diff --git a/.gitignore b/.gitignore index bc4b198..18dd698 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,53 @@ *.exe *.o *.a +gcc_arm/Makefile +agbcc +agbcc_arm +old_agbcc +*/genattr +*/genattrtab +*/gencheck +*/gencodes +*/genconfig +*/genemit +*/genextract +*/genflags +*/gengenrtl +*/genopinit +*/genoutput +*/genpeep +*/genrecog +*/config.log +gcc_arm/auto-host.h +gcc_arm/config.cache +gcc_arm/config.log +gcc_arm/config.status +gcc_arm/genrtl.c +gcc_arm/genrtl.h +gcc_arm/insn-attr.h +gcc_arm/insn-attrtab.c +gcc_arm/insn-codes.h +gcc_arm/insn-config.h +gcc_arm/insn-emit.c +gcc_arm/insn-extract.c +gcc_arm/insn-flags.h +gcc_arm/insn-opinit.c +gcc_arm/insn-output.c +gcc_arm/insn-peep.c +gcc_arm/insn-recog.c +gcc_arm/s-attr +gcc_arm/s-attrtab +gcc_arm/s-check +gcc_arm/s-codes +gcc_arm/s-config +gcc_arm/s-emit +gcc_arm/s-extract +gcc_arm/s-flags +gcc_arm/s-genrtl +gcc_arm/s-opinit +gcc_arm/s-output +gcc_arm/s-peep +gcc_arm/s-recog +gcc_arm/tree-check.h + diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..7118749 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,26 @@ +language: generic +dist: bionic +sudo: false +env: + global: + - DEVKITPRO=$HOME + - DEVKITARM=$DEVKITPRO/devkitARM +addons: + apt: + packages: + - gcc-multilib + - linux-libc-dev + - zlib-dev +cache: + apt: true +install: + - pushd $HOME + - travis_retry wget https://github.com/devkitPro/buildscripts/releases/download/devkitARM_r50/devkitARM_r50-linux.tar.xz + - tar xJf devkitARM*.tar.xz + - popd +matrix: + include: + - os: linux + env: _="Build" + script: + - sh build.sh diff --git a/build.sh b/build.sh index ca1785c..63a5d32 100755 --- a/build.sh +++ b/build.sh @@ -2,6 +2,7 @@ set -e CCOPT= CXXOPT= + if [ ! -z "$CC" ]; then CCOPT=CC=$CC; fi if [ ! -z "$CXX" ]; then CXXOPT=CXX=$CXX; fi make -C gcc clean @@ -10,6 +11,10 @@ mv gcc/old_agbcc . make -C gcc clean make -C gcc $CCOPT $CXXOPT mv gcc/agbcc . +# not sure if the ARM compiler is the old one or the new one (-DOLD_COMPILER) +rm -f gcc_arm/config.status gcc_arm/config.cache +cd gcc_arm && ./configure --target=arm-elf --host=i386-linux-gnu && make cc1 && cd .. +mv gcc_arm/cc1 agbcc_arm make -C libgcc clean make -C libgcc $CCOPT $CXXOPT mv libgcc/libgcc.a . diff --git a/config.if b/config.if new file mode 100755 index 0000000..bcc0269 --- /dev/null +++ b/config.if @@ -0,0 +1,87 @@ +#! /dev/null +# Don't call it directly. This shell script fragment is called to +# determine: +# +# 1. libstcxx_interface: the interface name for libstdc++. +# 2. cxx_interface: the interface name for c++. +# 3. libc_interface: the interface name for libc. +# + +# Get the top level src dir. +if [ -z "${topsrcdir}" -a -z "${top_srcdir}" ] +then + echo "Undefined top level src dir: topsrcdir and top_srcdir are empty" >&2 + exit 1 +fi + +if [ -n "${topsrcdir}" ] +then + if_topsrcdir=${topsrcdir} +else + if_topsrcdir=${top_srcdir} +fi + +if [ -f ${if_topsrcdir}/libstdc++/Makefile.in ]; then +# We check libstdc++ for libstdcxx_interface. +libstdcxx_interface=`grep "^INTERFACE" ${if_topsrcdir}/libstdc++/Makefile.in | sed 's/INTERFACE[ ]*=[ ]*\(.*\)/\1/'` +else +libstdcxx_interface= +fi + +if [ -f ${if_topsrcdir}/gcc/cp/Makefile.in ]; then +# We check gcc/cp for cxx_interface. +cxx_interface=`grep "^INTERFACE" ${if_topsrcdir}/gcc/cp/Makefile.in | sed 's/INTERFACE[ ]*=[ ]*\(.*\)/\1/'` +else +cxx_interface= +fi + +# The trickiest part is libc_interface. +if [ -z "${libc_interface}" ] +then + case ${target_os} in + *linux*libc1*|*linux*libc5*) + case ${target_alias} in + *alpha*|*powerpc*) + libc_interface=-libc5.9- + ;; + *) + libc_interface=-libc5- + ;; + esac + ;; + *linux*gnu*) + # We have to work harder to figure it out. + if [ ${target_alias} = ${build_alias} ] + then + dummy=if$$ + cat >$dummy.c < +main(argc, argv) + int argc; + char *argv[]; +{ + printf("%d\n", __GLIBC_MINOR__); + return 0; +} +EOF + ${CC-cc} $dummy.c -o $dummy 2>/dev/null + if [ "$?" = 0 ] + then + libc_interface=-libc6.`./$dummy`- + rm -f $dummy.c $dummy + else + # It should never happen. + echo "Cannot find the GNU C library minor version number." >&2 + rm -f $dummy.c $dummy + exit 1 + fi + else + # Cross compiling. Assume glibc 2.1. + libc_interface=-libc6.1- + fi + ;; + *) + libc_interface=- + ;; + esac +fi diff --git a/config.sub b/config.sub new file mode 100755 index 0000000..4dc4b6b --- /dev/null +++ b/config.sub @@ -0,0 +1,1274 @@ +#! /bin/sh +# Configuration validation subroutine script, version 1.1. +# Copyright (C) 1991, 92-97, 1998 Free Software Foundation, Inc. +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file 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 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +if [ x$1 = x ] +then + echo Configuration name missing. 1>&2 + echo "Usage: $0 CPU-MFR-OPSYS" 1>&2 + echo "or $0 ALIAS" 1>&2 + echo where ALIAS is a recognized configuration type. 1>&2 + exit 1 +fi + +# First pass through any local machine types. +case $1 in + *local*) + echo $1 + exit 0 + ;; + *) + ;; +esac + +# CYGNUS LOCAL marketing-names +# Here we handle any "marketing" names - translating them to +# standard triplets +case $1 in + mips-tx39-elf) + set mipstx39-unknown-elf + ;; + mips64vr5xxx-elf) + set mips64vr5000-elf + ;; + mips64vr5xxxel-elf) + set mips64vr5000el-elf + ;; + *) + ;; +esac +# END CYGNUS LOCAL marketing-names + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + linux-gnu*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond ) # CYGNUS LOCAL + os= + basic_machine=$1 + ;; + -scout) # CYGNUS LOCAL + ;; + -wrs) # CYGNUS LOCAL + os=vxworks + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ + | arme[lb] | pyramid | mn10200 | mn10300 \ + | tron | a29k | 580 | i960 | h8300 \ + | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \ + | alpha | alphaev5 | alphaev56 | alphapca56 | alphaev6 \ + | we32k | ns16k | clipper | i370 | sh | powerpc | powerpcle \ + | 1750a | dsp16xx | pdp11 \ + | mips64 | mipsel | mips64el | mips64orion | mips64orionel \ + | mipstx39 | mipstx39el \ + | sparc | sparclet | sparclite | sparc64 | sparc86x | v850 \ + | c4x) + basic_machine=$basic_machine-unknown + ;; + m88110 | m680[012346]0 | m683?2 | m68360 | m5200 | z8k | v70 \ + | h8500 | w65 | fr30) # CYGNUS LOCAL + basic_machine=$basic_machine-unknown + ;; + thumb) + basic_machine=$basic_machine-unknown + ;; + mips64vr4300 | mips64vr4300el) # CYGNUS LOCAL jsmith/vr4300 + basic_machine=$basic_machine-unknown + ;; + mips64vr4100 | mips64vr4100el) # CYGNUS LOCAL jsmith/vr4100 + basic_machine=$basic_machine-unknown + ;; + mips64vr5000 | mips64vr5000el) # CYGNUS LOCAL ian/vr5000 + basic_machine=$basic_machine-unknown + ;; + mips64vr5400) # CYGNUS LOCAL cagney/vr5400 + basic_machine=$basic_machine-unknown + ;; + mips16) + basic_machine=$basic_machine-unknown + ;; + tic30) # CYGNUS LOCAL ian/tic30 + basic_machine=$basic_machine-unknown + ;; + c30) # CYGNUS LOCAL ian/tic30 + basic_machine=tic30-unknown + ;; + + v850e) # CYGNUS LOCAL jtc/v850 + basic_machine=$basic_machine-unknown + ;; + v850ea) # CYGNUS LOCAL jtc/v850 + basic_machine=$basic_machine-unknown + ;; + d10v) + basic_machine=$basic_machine-unknown + ;; + d30v) # CYGNUS LOCAL hunt/d30v + basic_machine=$basic_machine-unknown + ;; + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i[34567]86) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + vax-* | tahoe-* | i[34567]86-* | i860-* | m32r-* | m68k-* | m68000-* \ + | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ + | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \ + | xmp-* | ymp-* \ + | hppa-* | hppa1.0-* | hppa1.1-* \ + | hppa2.0-* | hppa2.0w-* | hppa2.0n-* \ + | alpha-* | alphaev5-* | alphaev56-* | alphapca56-* \ + | alphaev6-* | we32k-* | cydra-* | ns16k-* | pn-* | np1-* \ + | xps100-* | clipper-* | orion-* \ + | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ + | sparc64-* | sparcv9-* | sparc86x-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* \ + | mipstx39-* | mipstx39el-* \ + | f301-* \ + | fr30-*) # CYGNUS LOCAL + ;; + m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | h8500-* | d10v-*) # CYGNUS LOCAL + ;; + thumb-*) # CYGNUS LOCAL angela/thumb + ;; + v850-*) # CYGNUS LOCAL + ;; + v850e-*) # CYGNUS LOCAL + ;; + v850ea-*) # CYGNUS LOCAL + ;; + d30v-*) # CYGNUS LOCAL + ;; + mips64vr4300-* | mips64vr4300el-*) # CYGNUS LOCAL jsmith/vr4300 + ;; + mips64vr4100-* | mips64vr4100el-*) # CYGNUS LOCAL jsmith/vr4100 + ;; + mips16-*) # CYGNUS LOCAL krk/mips16 + ;; + tic30-*) # CYGNUS LOCAL ian/tic30 + ;; + c30-*) # CYGNUS LOCAL ian/tic30 + basic_machine=tic30-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) # CYGNUS LOCAL + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) # CYGNUS LOCAL + basic_machine=a29k-amd + os=-udi + ;; + adobe68k) # CYGNUS LOCAL + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-cbm + ;; + amigaos | amigados) + basic_machine=m68k-cbm + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-cbm + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) # CYGNUS LOCAL + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + [ctj]90-cray) + basic_machine=c90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) # CYGNUS LOCAL + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) # CYGNUS LOCAL + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) # CYGNUS LOCAL + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + w89k-*) # CYGNUS LOCAL + basic_machine=hppa1.1-winbond + os=-proelf + ;; + op50n-*) # CYGNUS LOCAL + basic_machine=hppa1.1-oki + os=-proelf + ;; + op60c-*) # CYGNUS LOCAL + basic_machine=hppa1.1-oki + os=-proelf + ;; + hppro) # CYGNUS LOCAL + basic_machine=hppa1.1-hp + os=-proelf + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9] ) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9] ) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9] ) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | \ + hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893 ) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679] ) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) # CYGNUS LOCAL + basic_machine=hppa1.1-hp + os=-osf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + os=-mvs + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i[34567]86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i[34567]86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i[34567]86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i[34567]86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) # CYGNUS LOCAL + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) # CYGNUS LOCAL + basic_machine=i386-unknown + os=-vsta + ;; + i386-go32 | go32) # CYGNUS LOCAL + basic_machine=i386-unknown + os=-go32 + ;; + i386-mingw32 | mingw32) + basic_machine=i386-unknown + os=-mingw32 + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + miniframe) + basic_machine=m68000-convergent + ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + os=-linux-gnu + ;; + mips*-linux*) + basic_machine=mips-unknown + os=-linux-gnu + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) # CYGNUS LOCAL + basic_machine=m68k-rom68k + os=-coff + ;; + msdos) # CYGNUS LOCAL + basic_machine=i386-unknown + os=-msdos + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown # CYGNUS LOCAL + os=-netbsd + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) # CYGNUS LOCAL + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) # CYGNUS LOCAL + basic_machine=i960-intel + os=-mon960 + ;; + np1) + basic_machine=np1-gould + ;; + OSE68000 | ose68000) # CYGNUS LOCAL + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) # CYGNUS LOCAL + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | nexen) + basic_machine=i586-pc + ;; + pentiumpro | p6 | k6 | 6x86) + basic_machine=i686-pc + ;; + pentiumii | pentium2) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | nexen-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | k6-* | 6x86-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=rs6000-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + rom68k) # CYGNUS LOCAL + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sa29200) # CYGNUS LOCAL + basic_machine=a29k-amd + os=-udi + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sparclite-wrs) # CYGNUS LOCAL + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) # CYGNUS LOCAL + basic_machine=m68k-tandem + ;; + stratus) # CYGNUS LOCAL + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) # CYGNUS LOCAL + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) # CYGNUS LOCAL + basic_machine=w65-wdc + os=-none + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + z8k-*-coff) # CYGNUS LOCAL + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) # CYGNUS LOCAL + basic_machine=hppa1.1-winbond + ;; + op50n) # CYGNUS LOCAL + basic_machine=hppa1.1-oki + ;; + op60c) # CYGNUS LOCAL + basic_machine=hppa1.1-oki + ;; + mips) + if [ x$os = x-linux-gnu ]; then + basic_machine=mips-unknown + else + basic_machine=mips-mips + fi + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sparc | sparcv9) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) # CYGNUS LOCAL + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) # CYGNUS LOCAL + basic_machine=powerpc-apple + ;; + c4x*) + basic_machine=c4x-none + os=-coff + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + # CYGNUS LOCAL + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ + | -macos* | -mpw* | -magic* | -mon960* | -lnews* ) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + # END CYGNUS LOCAL + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -386bsd) # CYGNUS LOCAL + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) # CYGNUS LOCAL + os=-ose + ;; + -es1800*) # CYGNUS LOCAL + os=-ose + ;; + -xenix) + os=-xenix + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-semi) + os=-aout + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) # CYGNUS LOCAL + os=-aout + ;; + mips*-cisco) # CYGNUS LOCAL + os=-elf + ;; + mips*-*) # CYGNUS LOCAL + os=-elf + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-wec) # CYGNUS LOCAL + os=-proelf + ;; + *-winbond) # CYGNUS LOCAL + os=-proelf + ;; + *-oki) # CYGNUS LOCAL + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f301-fujitsu) + os=-uxpv + ;; + *-rom68k) # CYGNUS LOCAL + os=-coff + ;; + *-*bug) # CYGNUS LOCAL + os=-coff + ;; + *-apple) # CYGNUS LOCAL + os=-macos + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) # CYGNUS LOCAL + vendor=hitachi + ;; + -mpw* | -macos*) # CYGNUS LOCAL + vendor=apple + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os diff --git a/gcc_arm/COPYING b/gcc_arm/COPYING new file mode 100755 index 0000000..60549be --- /dev/null +++ b/gcc_arm/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/gcc_arm/COPYING.LIB b/gcc_arm/COPYING.LIB new file mode 100755 index 0000000..161a3d1 --- /dev/null +++ b/gcc_arm/COPYING.LIB @@ -0,0 +1,482 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library 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. + + This library 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 this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/gcc_arm/ChangeLog b/gcc_arm/ChangeLog new file mode 100755 index 0000000..7b8f481 --- /dev/null +++ b/gcc_arm/ChangeLog @@ -0,0 +1,10905 @@ +2000-05-11 Nick Clifton + + * config/arm/thumb.h (ASM_OUTPUT_ALIGN): Do not emit a 0 + alignment, the assembler treats it as a word alignment. + +Thu Oct 14 20:09:17 1999 Jonathan Larmour + + * config/arm/telf.h (ASM_OUTPUT_SECTION_NAME): Add %nobits option + to .section when outputting a .bss section to deal with multiple + .bss input sections (as happens with -fdata-sections) + Also output %progbits, not @progbits so the assembler doesn't treat as + a comment. + * config/arm/unknown-elf.h (ASM_OUTPUT_SECTION_NAME): Likewise + + * config/arm/t-arm-elf (MULTILIB_OPTIONS): Add -mcpu=arm7 multilib... + (MULTILIB_DIRNAMES): ...in directory nofmult... + (MULTILIB_EXCEPTIONS): ...but don't need to build it with thumb-interwork + (MULTILIB_MATCHES): And make sure it matches all the relevant CPUs + + * config/arm/lib1funcs.asm (_call_via_rX): Allow compilation of + thumb parts even when building with non-thumb CPUs, by forcing + thumb mode. + + * config/arm/elf.h (MULTILIB_DEFAULTS): include -fno-leading-underscore + to prevent unnecessary multilib + +Fri Oct 8 14:44:16 1999 Jonathan Larmour + + * configure.in (arm*-*-*): bracket arm core versions correctly + * configure: regenerate + +Tue Oct 5 17:12:26 MDT 1999 Diego Novillo + + * config/rs6000/rs6000.c (secondary_reload_class): For + TARGET_ELF make sure that HIGH instructions are copied + into BASE_REGS. + +Wed Feb 10 11:03:22 1999 Richard Henderson + + * configure.in (alphaev6*): Fix typo in target_cpu_default2. + +Wed Apr 7 14:07:34 1999 Jeffrey A Law (law@cygnus.com) + + * unroll.c (copy_loop_body): Always ensure at least two insns + are in the copied loop. + +Thu Aug 26 16:05:39 1999 Jason Merrill + + * configure.in (sparc86x-aout): Set use_collect2. + +Fri Aug 27 15:19:48 1999 Jason Merrill + + * rs6000.md: Add missing arg to rs6000_output_load_toc_table. + +Fri Aug 27 09:53:14 1999 Brendan Kehoe + + * sparc.md: For DF splits for reg/mem and mem/reg, Do gen_rtx_REGs + explicitly if we're dealing with a REG to circumvent gen_highpart and + gen_lowpart doing word swapping. (For sparc86x-elf + -mlittle-endian-data support.) + +1999-08-31 Brendan Kehoe + + * real.c (GET_REAL, PUT_REAL): Honor aliasing rules for the byte + order changes for these, using memcpy instead of trying + assignment. Fixes problems emitting float values in some + situations. + +Sat Sep 25 14:03:53 1999 Nick Clifton + + * varasm.c (asm_emit_uninitialised): If flag_data_sections is + true, then attempt to use ASM_OUTPUT_UNIQUE_BSS or + ASM_OUTPUT_UNIQUE_LOCAL to emit the variable. + + * tm.texi (ASM_OUTPUT_UNIQUE_BSS): Document new target macro. + (ASM_OUTPUT_UNIQUE_LOCAL): Document new target macro. + +Sat Sep 25 13:42:15 1999 Nick Clifton + + * varasm.c (asm_emit_uninitialised): New function: Generate + the assembler statements necessary to declare an uninitialised + variable. + (ASM_EMIT_LOCAL): New macro: Emit a local, uninitialised + variable. + (ASM_EMIT_BSS): New macro: Emit an entry in the bss section. + (ASM_EMIT_COMMON): New macro: Emit an entry in the common + section. + (assemble_variable): Use asm_emit_uninitialised to emit an + uninitialised variable. + +Thu Sep 2 22:00:08 1999 J"orn Rennecke + + * final.c (shorten_branches): Make value passed to LABEL_ALIGN + conform to documentation. + * sh.h (LABEL_ALIGN): If aligning loops, call sh_label_align + to check for special cases. + (sh_label_align): Declare. + * sh.c (sh_label_align): Define. + +Wed Sep 8 10:56:38 1999 Nick Clifton + + Patch supplied by Bernd Schmidt : + + * reload.c (MODE_BASE_REG_CLASS): Provide default definition and + replace all uses of BASE_REG_CLASS with this macro. + +Wed Aug 25 09:38:17 1999 Nick Clifton + + * dwarf2out.c (mem_loc_descriptor): Accept LABEL_REFs along + with SYMBOL_REFs. + +Tue Aug 24 20:16:55 1999 Nick Clifton + + * config/arm/telf.h (ASM_WEAKEN_LABEL): Define. + (TYPE_ASM_OP, SIZE_ASM_OP, TYPE_OPERAND_FORMAT, + ASM_DECLARE_RESULT, ASM_DECLARE_FUNCTION_NAME, + ASM_DECLARE_OBJECT_NAME, AS_FINISH_DECLARE_OBJECT_NAME, + ASM_DECLARE_FUNCTION_SIZE): Define. + +Mon Aug 23 15:59:32 1999 Jonathan Larmour + + * config/mips/mips.c (mips_move_2words): Only split 64-bit loads for + floating-point registers + +Thu Jun 24 03:00:01 1999 Jorn Rennecke + + * mips.h (CLASS_CANNOT_CHANGE_SIZE): Define. + +Wed Aug 11 18:28:07 EDT 1999 Diego Novillo + + * config/mips/mips.c (mips_move_2words): Emit two li insns for + 32-bit targets. + +1999-04-16 Angela Marie Thomas + + * config/mips/elfb4300.h: Support for dwarf2 debugging. + * config/mips/elfl4300.h: Likewise. + +Thu May 13 13:44:58 EDT 1999 Andrew MacLeod + + * config/rs6000/rs6000.md (nonlocal_goto_receiver): Add check for + constant_pool_size () before restoring the TOC register. + +Thu Jul 29 14:47:23 1999 Vladimir Makarov + + * config/sparc/sparc.h (ASM_CPU32_DEFAULT_SPEC): Change -Av8 onto + -Asparclite for sparc86x. + (CPP_CPU32_DEFAULT_SPEC, CPP_CPU_SPEC): Remove -D__sparc_v8__ for + sparc86x. + (ASM_CPU_SPEC): Use -Asparclite for sparc86x. + +Fri Jun 4 03:20:40 1999 J"orn Rennecke + + * sh.c (fixup_addr_diff_vecs): Emit braf reference label. + (braf_label_ref_operand): Delete. + * sh.h (PREDICATE_CODES): Remove braf_label_ref_operand. + * sh.md (casesi_jump_2): Operand1 is now the inside of a + label_ref, and has no predicate. + The patten has a predicate to guard against invalid substitutions. + (dummy_jump): Delete. + (casesi): Update use of casesi_jump_2. + +Wed Jun 2 21:53:05 1999 J"orn Rennecke + + * sh.h (CONST_OK_FOR_I, CONST_OK_FOR_L): Cast VALUE to HOST_WIDE_INT. + +Fri Jul 23 21:14:57 1999 J"orn Rennecke + + * dwarfout.c (ASM_OUTPUT_DWARF_DATA2): Cast VALUe to unsigned short. + +Wed Mar 10 18:56:31 1999 J"orn Rennecke + + * reload1.c (choose_reload_regs): When inheriting from the frame + pointer, don't clobber it. + +Mon Jul 19 14:23:42 1999 Vladimir Makarov + + * config/sparc/sparc.c (sparc_override_options): Enable SPARCLITE + instead of V8 for sparclite86x in cpu_table. + +Thu Jul 15 14:53:54 1999 Vladimir Makarov + + * config/sparc/lite.h (TARGET_DEFAULT): Enable sparclite. + + * config/sparc/liteelf.h (TARGET_DEFAULT): Ditto. + + * config/sparc/sp86x-aout.h (TARGET_DEFAULT): Ditto. + + * config/sparc/sp86x-elf.h (TARGET_DEFAULT): Ditto. + + +Tue Jun 15 12:57:44 1999 Vladimir Makarov + + * config/mips/elf.h (BSS_SECTION_ASM_OP, ASM_OUTPUT_ALIGNED_BSS): + Add the macros. + + * config/d10v/d10v.h (BSS_SECTION_ASM_OP, ASM_OUTPUT_ALIGNED_BSS): + Ditto. + + * config/i386/i386elf.h (BSS_SECTION_ASM_OP, ASM_OUTPUT_ALIGNED_BSS): + Ditto. + + * config/m68k/m68kelf.h (BSS_SECTION_ASM_OP, ASM_OUTPUT_ALIGNED_BSS): + Ditto. + + * config/sh/sh.h (BSS_SECTION_ASM_OP, ASM_OUTPUT_ALIGNED_BSS): + Ditto. + + * config/arm/telf.h (BSS_SECTION_ASM_OP, ASM_OUTPUT_ALIGNED_BSS): + Ditto. + +Mon Jul 12 10:13:25 1999 Vladimir Makarov + + * config/arm/thumb.c (thumb_reorg): Call replace_symbols_in_block + always unless NO_DEBUG is used. Compile this code + unconditionally. + (replace_symbols_in_block): Compile it unconditionally. + +Fri Jun 11 21:00:45 1999 Jim Wilson + + * config/mips/mips.c (mips_secondary_reload_class): Check for + (PLUS (SP) (REG)) and return appropriate register class. + * config/mips/mips.md (reload_insi): Delete predicate for operand 1. + Handle (PLUS (SP) (REG)). + +1999-06-16 Nick Clifton + + * config/tc-arm.c (thumb_set): New pseudo op. + (text, data, section): Override these pseudo ops with ARM + specific versions. + (s_thumb_set): New function: Perform the same as a .set pseudo + op, but also mark the alias'ed symbol as being a Thumb + function. + (arm_s_text): New function: Perform the same as the .text + pseudo op, but dump the literal pool before changing + sections. + (arm_s_data): New function: Perform the same as the .data + pseudo op, but dump the literal pool before changing + sections. + (arm_s_section): New function: Perform the same as the + .section pseudo op, but dump the literal pool before changing + sections. + (arm_cleanup): Do not reset the current section before dumping + the literal pool. + +1999-06-16 Nick Clifton + + * varasm.c (assemble_alias): Use the macro + ASM_OUTPUT_DEF_FROM_DECLS, if defined, in preference to + ASM_OUTPUT_DEF. + + * tm.texi: Document new macro ASM_OUTPUT_DEF_FROM_DECLS. + + * config/arm/telf.h (ASM_OUTPUT_DEF_FROM_DECLS): New macro. + + +Thu Jun 10 10:02:30 1999 Nick Clifton + + * config/tc-arm.c (ARM_8, ARM_9): Define. + (md_parse_option): Parse ARM8 and ARM9 cpu types. + +Thu Jun 10 10:02:30 1999 Nick Clifton + + * config/arm/arm.h (TARGET_CPU_arm9, TARGET_CPU_arm9tdmi): + Define. + (TARGET_OPTIONS): Add 'tune=' and 'fp=' options. + (arm_is_strong): New exported variable. + (arm_is_6_or_7): New exported variable. + (USE_RETURN_INS): Add parameter to macro. + + * config/arm/arm.md (is_strongarm): New attribute. + (model_wbuf): New attribute. + (write_buf, write_blockage, core): Amend models. + + * config/arm/arm.c (MAX_INSNS_SKIPPED): Replace with a + variable called 'max_insns_skipped'. + (insn_flags, tune_flags): New variables. + (arm_is_strong, arm_is_6_or_7): New variable. + (struct all_cores): Add arm8 and arm9 cores. + (arm_override_options): Rewrite to allow tuning of processor + selection. + (bit_count): New function: Count the number of bits set in a + word. + (use_return_insn): Add parameter. Disable conditional returns + if they are inefficient. + (arm_rtx_costs): Examien tuning parameter to determine + multiply costs. + (load_multiple_sequence): Add arm9 tuneing. + (final_prescan_insn): Add arm9 tuneing. +Thu Jul 8 16:07:26 1999 Jason Merrill + + * sparc/liteelf.h: Handle ctors like sparc86x. + +Wed Jun 2 10:03:01 1999 Catherine Moore + + * config/arm/thumb.c (thumb_print_operand): Process 'c' type + operands for selective linking support. + * config/arm/telf.h (MAKE_DECL_ONE_ONLY): Define. + (UNIQUE_SECTION_P): Define. + (UNIQUE_SECTION): Define. + +1999-05-27 Felix Lee + + * fixinc.x86-linux-gnu (FD_ZERO): missing patch from drepper: + remove memory output operands. + * fixinc/fixinc.x86-linux-gnu (FD_ZERO): sync with above. + +Sat May 22 18:18:43 1999 Jason Merrill + + * sparc/liteelf.h: Handle ctors like MIPS crosses. + * sparc/lite.h (STARTFILE_SPEC, LIB_SPEC): Define to "". + * configure.in: Don't use libgloss.h on sparclite-elf. + Use collect2 on sparclite-aout. + +Mon Mar 1 16:36:18 1999 Jeffrey A Law (law@cygnus.com) + + * mips.md (div_trap_normal, div_trap_mips16): Require the dependent + insn to be an INSN before looking at its pattern. + +Thu Feb 4 10:46:30 1999 Gavin Romig-Koch + + * config/mips/mips.md ([u]divmodsi4,[u]divmoddi4,[u]divsi3,[u]divdi3, + [u]modsi3,[u]moddi3) : Don't copy the "zero" argument to a register + before calling gen_div_trap. + +Wed Feb 3 15:51:04 1999 Gavin Romig-Koch + + * config/mips/mips.c (true_reg_or_0_operand) : New function. + * config/mips/mips.h (PREDICATE_CODES): Add true_reg_or_0_operand. + * config/mips/mips.md (div_trap,div_trap_normal,div_trap_mips16): + Use true_reg_or_0_operand for div_trap. + +Wed Feb 3 15:26:58 1999 Gavin Romig-Koch + + * config/mips/mips.md (div_trap_mips16): Remove nop's after branches. + +Mon Jan 18 12:03:08 1999 Gavin Romig-Koch + + * config/mips/mips.md (div_trap): Split div_trap_mips16 + from div_trap. + (div_trap_normal,div_trap_mips16): Correct the length attributes. + +Sat May 22 18:19:10 1999 Jason Merrill + + * configure.in: Don't use libgloss.h on mips64vr4100-elf, + mips64vr4300-elf, or mips64vr5xxx-elf. + +1999-05-21 Ulrich Drepper + + * new1.cc: Use __GCC_THROW and __GCC_nothing instead of __THROW + and __nothing. + * new2.cc: Likewise. + +1999-05-21 Ulrich Drepper + + * inc/new: Use __GCC_THROW and __GCC_nothing instead of __THROW + and __nothing. + +Sat May 15 11:59:47 1999 Jim Wilson + + * configure: Rebuild. + +Sat May 15 13:05:41 1999 Jim Wilson + + * arm.md (zeroextractqi_compare0_scratch): Disable. + +Fri May 14 21:18:48 1999 Jim Wilson + + * reload1.c (choose_reload_regs): New locals check_regnum, nr, + cant_inherit. When calling reload_reg_free_for_value_p, loop over + each reg in check_reg in case it is a multi-word hard register. + +Fri May 14 13:57:03 1999 Stan Cox + + * range.c (range_inner): Pick up devo change to set all_label_ref + from LABEL_NUSES instead of using LABEL_REFS. + +1999-05-14 Ulrich Drepper + + * fixinc/fixinc.x86-linux-gnu (FD_ZERO): Fix operand numbers in + asm input operands. + +Fri May 7 12:31:21 1999 Jim Wilson + + * mips/mips.c (mips_select_rtx_section): When TARGET_MIPS16, use + function_section instead of text_section. + * mips/mips.h (ENCODE_SECTION_INFO): Add check for UNIQUE_SECTION_P + in TARGET_MIPS16 STRING_CST handling. + +Wed Sep 23 00:16:41 1998 Ken Raeburn + + * cse.c (cse_insn): Don't substitute inside a libcall if we would + need to update the RETVAL insn's notes, and if the new value is a + hard reg register changed between the current insn and the RETVAL + insn. + +Fri May 7 12:31:21 1999 Jim Wilson + + * mips/elf64.h (MAKE_DECL_ONE_ONLY, UNIQUE_SECTION_P): Define. + +Fri May 7 18:12:55 1999 Vladimir Makarov + + * sparc.h (GO_IF_LEGITIMATE_ADDRESS): Prohibit REG+REG addressing + for TFmode when there are no instructions which accept REG+REG + instructions. + +Thu Apr 15 15:00:47 1999 Vladimir Makarov + + * expmed.c (extract_bit_field): Extract field smaller than a word + when unsignedp not assuming that the field is an integer. + +Thu Apr 29 07:40:21 1999 Vladimir Makarov + + * config/d10v/d10v.c (d10v_output_addr_const): Use parentheses + around SYMBOL_REF. + (print_operand_memory_reference): Remove output of parentheses + around symbols. This is Nick Clifton's patch dated Nov 16, 1998. + +Sat Apr 10 13:09:18 1999 Nick Clifton + + * config/arm/arm.c (di_operand): Allow SUBREGs as well. + (soft_df_operand): Allow SUBREGs as well. + +Sun Apr 25 03:17:33 1999 J"orn Rennecke + + * final.c (insn_lengths_max_uid): New variable. + (init_insn_lengths, shorten_branches): Set it. + (get_attr_lengths): Test insn uid against insn_lengths_max_uid. + +Mon Apr 26 13:30:31 EDT 1999 Andrew MacLeod + + * optabs.c (emit_libcall_block): Add a REG_EH_REGION reg note to all + calls within a libcall block to indicate no throws are possible. + * flow.c (find_basic_blocks, find_basic_blocks_1): Don't look for + libcall blocks. Don't add edges to exception handlers if we see + a REG_EH_REGION note with a value of 0. + (make_edges): Override active_eh_region vector if the call has a note + indicating the call does not throw. + +Mon Apr 26 13:56:17 EDT 1999 Andrew MacLeod + + * config/alpha/alpha.md (builtin_setjmp_receiver): Use a label_ref. + +1999-04-13 Jason Merrill + + * decl2.c (setup_initp): Compare DECL_ASSEMBLER_NAME instead + of the decls themselves. + +1999-04-09 Jason Merrill + + * decl.c (start_decl): Pass attributes to grokdeclarator. + (grokdeclarator): Handle attributes on constructor-syntax + initializers. + +Fri Apr 9 11:18:55 1999 Jason Merrill + + * c-common.c (decl_attributes, A_INIT_PRIORITY): Allow arrays + of classes, too. + +Mon Apr 5 12:58:03 1999 Catherine Moore + + * config/mips/elf.h, config/mips/elf64.h + (CTORS_SECTION_ASM_OP): Define. + (DTORS_SECTION_ASM_OP): Define. + (EXTRA_SECTIONS): Define. + (INVOKE__main): Define. + (NAME__MAIN): Define. + (SYMBOL__MAIN): Define. + (EXTRA_SECTIONS_FUNCTIONS): Define. + (SECTION_FUNCTION_TEMPLATE): Define. + (ASM_OUTPUT_CONSTRUCTOR): Define. + (ASM_OUTPUT_DESTRUCTOR): Define. + (CTOR_LIST_BEGIN): Define. + (CTOR_LIST_END): Define. + (DTOR_LIST_BEGIN): Define. + (DTOR_LIST_END): Define. + (LIB_SPEC): Define. + (STARTFILE_SPEC): Define. + (ENDFILE_SPEC): Define. + * config/mips/linux.h: Undefine all of the above. + * config/mips/rtems64.h: Likewise. + * config/mips/t-biendian (EXTRA_MULTILIB_PARTS): Define. + (CRTSTUFF_T_CFLAGS): Define. + * config/mips/t-lsi: Likewise. + * config/mips/t-r3900: Likewise. + * config/mips/t-vr4100: Likewise. + * config/mips/t-vr4300: Likewise. + * config/mips/t-vr5000: Likewise. + * config/mips/t-elf: New file. + * config/mips/vxworks.h: New file. + * configure.in (mips-wrs-vxworks): Use mips/vxworks.h. + (mips*-*-*elf*): Use t-elf instead of t-ecoff. + * configure: Regenerate. + +Tue Apr 6 15:58:28 1999 Catherine Moore + + * gcc/config/mips/elf.h (MAKE_DECL_ONE_ONLY): Define. + (UNIQUE_SECTION_P): Define. + +1999-03-24 Jim Blandy + + * libgcc2.c (__CTOR_LIST__, __DTOR_LIST__): Initialize on all + platforms. + +Wed Mar 31 16:13:42 1999 Jim Wilson + + * loop.c (find_and_verify_loops): Don't move a block between a + tablejump and its immediately following jump table. + +Tue Mar 30 13:19:36 1999 Jason Merrill + + * libgcc2.c (throw_helper): Just return the SP offset, rather than + a whole udata. Include args_size in the offset. + (__throw, __rethrow): Adjust. + +Mon Mar 29 18:10:31 1999 Richard Henderson + + * flow.c (add_edge): Don't add duplicate edges. + +Fri Mar 26 11:38:01 1999 Nick Clifton + + * config/arm/t-arm-elf (EXTRA_MULTILIB_PARTS): Define. + +Sat Mar 27 16:13:50 1999 Jeffrey A Law (law@cygnus.com) + + * flow.c (mark_used_regs): Improve handling of ASMs. + +Mon Mar 29 15:48:39 1999 Jason Merrill + + * invoke.texi (Invoking G++, C++ Dialect Options): Update. + +Fri Feb 12 16:56:10 1999 J"orn Rennecke + + * loop.c (load_mems): Don't guess how to do a load / store, use + gen_move_insn. + +Fri Mar 5 23:08:01 1999 J"orn Rennecke + + * reload.c (find_reloads_subreg_address): Actually create the USE + for the register, not the new memory location. + +Fri Feb 12 21:09:51 1999 J"orn Rennecke + + * reload.c (find_reloads_subreg_address): New function, broken out of + find_reloads_toplev. + (find_reloads_toplev, find_reloads_address_1): Use it. + +Fri Mar 5 21:41:07 1999 J"orn Rennecke + + * reload1.c (emit_reload_insns): If pseudo that can't be replaced + with its equivalent constant, fall back to reload_in. + +Mon Mar 8 18:47:11 1999 J"orn Rennecke + + * regmove.c (copy_src_to_dest): New argument max_old_uid. + +Tue Mar 2 16:45:31 1999 J"orn Rennecke + + * unroll.c (copy_loop_body): Don't make extra copies of + NOTE_INSN_LOOP_CONT notes. + +1999-02-11 Nick Clifton + + * lib/remote.exp (proc remote_exec): Display timeout in log + message. + + * lib/target.exp (proc default_target_compile): Add support for + timeout option. + + * baseboards/arm-sim.exp: Set gcc,timeout to 500. + +1999-02-11 Nick Clifton + + * lib/gcc.exp (proc gcc_target_compile): Add support for timeout + specified by target. + + * lib/consistency.exp (proc gcc_target_compile): Add support for + timeout specified by target. + +Mon Mar 15 12:39:38 1999 Nick Clifton + + * config/m32r/m32r.c (init_idents): New function. Initialise + static tree nodes for m32r specific attribute identifiers. Remove + leading and trailing double underscores from the attribute names. + (m32r_valid_machine_decl_attribute): Call init_idents. + (m32r_encode_section_info): Call init_idents. + +Mon Mar 15 15:27:44 1999 Vladimir N. Makarov + + * config/sparc/sparc.h (CONDITIONAL_REGISTER_USAGE): Don't use + PIC_OFFSET_TABLE_REGNUM for register allocation when -fPIC. + +Thu Mar 11 11:00:34 1999 Vladimir N. Makarov + + * global.c (build_insn_chain): Add code for processing + explicitly case when n_basic_blocks == 0. + +1999-03-11 Jim Wilson + + * reload1.c (calculate_needs_all_insns): When ignore equivalence + setting insn, clear need_elim, need_reload, and need_operand_change. + +Wed Mar 10 00:01:24 1999 J"orn Rennecke + + * reload1.c (reload_combine_note_store): Fix calculation of number + of affected registers. + +1999-03-04 Martin Hunt + + * gdbtk-hooks.c (gdbtk_load_hash): Change download_hash() + to Download::download_hash(). + +1999-03-01 Martin Hunt + + * gdbtk.c (TclDebug): Increase buffer size to 10000, in case + backtraces are very long. + +1999-02-26 James Ingham + + * gdbtk-cmds.c (gdb_search): Add a -filename switch, which returns + the file in which the function or type was defined, along with the + function... + + * gdbtk.c (gdbtk_find_main): The external editor stuff was getting + set twice... + +1999-02-18 Martin Hunt + + * gdbtk-cmds.c (gdb_disassemble): When debugging native threads, + set disassemble_from_exec to 0. This fixes bugs where disassembly + of threaded programs failed. + +1999-02-16 James Ingham + + * gdbtk.c (gdbtk_init): Remove redundant setting of the external + editor variables. + +1999-02-11 Martin Hunt + + * gdbtk-variable.c (variable_format): Enable binary format. + +1999-02-11 Martin Hunt + + * gdbtk-hooks.c: Change ALL Tcl_Eval calls in hooks to + call report_error() if there are errors. + +1999-02-11 Martin Hunt + + * gdbtk.c, gdbtk-cmds.c, gdbtk-hooks.c: Removed old IDE stuff. + +1999-02-09 Martin Hunt + + * gdbtk-hooks.c: Remove gdbtk_ignorable_warning prototype. + It is in gdbtk.h. + (report_error): New function. Displays debugging information + if a hook function fails. All hook functions should probably + call this. + (gdbtk_warning): Call report_error() if there is a problem. + (gdbtk_register_changed): Call report_error() if there is a problem. + (gdbtk_memory_changed): Call report_error() if there is a problem. + (gdbtk_ignorable_warning): Pass along class argument. If there + is a problem, call report_error(). + + * gdbtk-cmds.c: Remove TclDebug prototype. It is in gdbtk.h. + (gdb_loadfile): Add class name to gdbtk_ignorable_warning call. + + * gdbtk.c (TclDebug): Add "priority" argument. Calls "dbug" + instead of "debug". Removed non-ANSI ifdefs. + + * gdbtk.h: Fixed protos for gdbtk_ignorable_warning and TclDebug. + +1999-03-03 James Ingham + + * i386-tdep.c (_initialize_i386_tdep): Set the inital value for + disassembly flavor at startup, rather than hardcoding it. + + +1999-03-04 Martin Hunt + + * download.ith: New file. + * download.itb: New file. Implements itcl3 class and replaces + download.tcl. + + * srcbar.tcl (create_menu_items): Call create_run_menu + without arguments. + (create_run_menu): Add Disconnect and Connect to Run menu + instead of file menu. Change download_it to Download::download_it. + + * srctextwin.itb (do_key): Change binding to call + Download::download_it. + + * debugwin.itb (DebugWinDOpts::build_win): Add ProcessWIn to list + of classes for filter. + + * interface.tcl (set_target): No need to set window title. + (run_executable): Change download_it to Download::download_it + +1999-03-04 James Ingham + + * modal.tcl (ModalDialog): Handle WM_DELETE_WINDOW by calling the + cancel method. Also set unpost_notification to different values + in unpost & the destructor, so if the object dies irregularly, you + know not to try to double destruct it. + +1999-03-03 James Ingham + + * warning.tcl (WarningDlg::constructor):Destroy with unpost. + + * util.tcl (get_disassembly_flavor, set_disassembly_flavor, + init_disassembly_flavor): Added these functions for the Intel P2 + disassembly flavors. + (list_element_strcmp): New function for lsort -command on lists. + + * tracedlg.tcl (TraceDlg): Change combobox callback to reflect new + after behavior. + + * targetselction.itb (TargetSelection::save): If the target + is not valid, tell the user rather than simple refusing to go + away. + Also move stuff around to isolate the instance dependant stuff as + much as possible + Also replace delete with unpost. + + * targetselection.ith (TargetSelection): Make as much of the + initialization stuff Class functions as possible. Then only + initialize it once. + + * srcwin.ith (_update_title): initialize need_files. + + * srcwin.itb (SrcWin::_build_win): I changed the combobox so it + ran its code in an idle handler, so we can take out all the after + idle... cruft here. + + * srctextwin.ith (SrcTextWin): Added textheight variable so you + can adjust the height of the text display. + + * srctextwin.itb (SrcTextWin::build_win): Don't hardcode the size + of the text window, set it with the textheight option instead. + Also replace childsite with "component text" wherever required. + + * srcpref.itb (SrcPref::build_win, set_flavor): Added the Intel + disassembly flavor combobox. Added set_flavor method to support + this. + * srcpref.ith: Added declaration for set_flavor, and + disassembly_flavor instance variable. + + * modal.tcl (ModalDialog::post, unpost): Added unpost method to + provide a more regular way to dismiss the dialogs. Just + destroying them was leading to funny destruction order bugs. + Added cancel method, which is what client code should call to + "force close" the dialog, so child classes can override, and do + some cleanup. + + * memwin.itb (MemWin::destructor): Call the cancel method of the + Preferences dialog (if it is posted) rather than just destroying + it. + + * mempref.itb (MemPref::ok): call unpost, since this is a modal + dialog. + + * managedwin.itb (ManagedWin::reveal): Used to be called raise. + Don't reuse Tcl or Tk commands unless there is a really good + reason to... + (ManagedWin::destroy_toplevel): renamed from delete, which + conflicts both with the Itcl1.5 delete method, and the Itcl3.0 + delete command... Also, don't use this as the way to destroy + ManagedWins, rather destroy the object and let the object take + care of removing its toplevel. + (ManagedWin::_create): Group all the windows with + . for WindowManagers that properly handle this. + (ManagedWin::_create): Use dont_remember_size + rather than the instance variable. Also, windows which don't + remember size are not necessarily transient. + (ManagedWin::_create): Only call post if the + ManagedWin also isa ModalDialog. It is clearer what is going on. + * managedwin.ith: Carry through the name changes. + + * main.tcl: call init_disassembly_flavor for Intel assembly + flavors. + + *main.tcl: Group . with . This is half of the work required to + play nice with WindowMaker. The other half waits till we can get + gdb to pass the command-line arguments to Tcl. + + * interface.tcl: Add file_changed_hook to the hooks. The browser + window watches this and refreshes the file box if it changes. + + * globalpref.ith (GlobalPref): This should be a modal dialog. + * globalpref.itb (GlobalPref::build_win): call update idletasks, + not update. Since we are calling update, there is no reason to + delay calling resize_font_item_height. + * globalpref.itb: Replace destroy toplevel with unpost. + + * debugwin.itb (DebugWin::build_win): Replace childsite with + "component text" + + * console.itb (Console::_build_win): Replace childsite with + "component text" + + * browserwin.itb: Rewritten pretty completely. + * prefs.tcl (pref_set_defaults): add the browser preferences. + + * prefs.tcl (pref_set_defaults): add the intel disassembly flavor + preference. + + * about.tcl (About): This should be a modal dialog. + +1999-03-02 James Ingham + + * globalpref.itb (GlobalPref::make_font_item): Don't do the + resize_font_item_height here, since an update can cause the resize + before all the windows are built. Delay to the end of build_win + instead. + +1999-02-24 James Ingham + + * toolbar.tcl (remove_button): Specify the row in the toolbar from + which you are removing the item. On Windows, there are two rows + in the standard toolbar... + +1999-02-22 Martin Hunt + + * warning.tcl (WarningDlg::constructor): Remove extra quote + that was causing loading of this module to fail. + + * managedwin.itb (ManagedWin::_create): If the pack fails + (for example because the warning dialog reliazed it should + ignore the warning) print a warning debug message and return. + Also, while testing, tell the window manager to position + the window without asking the user for the position. + +1999-02-18 Martin Hunt + + * srctextwin.itb (SrcTextWin::FillAssembly): As a last resort, + if the disassembly fails for some reason, switch to the scratch + pane and write in a message about not being able to disassemble. + +1999-02-18 Martin Hunt + + * helpviewer.ith (HtmlViewer): Add thread and function + browser windows to help index. + + * help/index.toc: Removed. + +1999-02-18 Martin Hunt + + * help/thread.html: New file. Thread window online help. + * help/index.html: Add thread.html, and alphabetize list. + * help/source.html: Add index for thread_bp. + +1999-02-17 Martin Hunt + + * globalpref.itb (GlobalPref::build_win): Add a checkbutton to + allow use of an internet browser to read help files. + + * prefs.tcl (pref_set_defaults): Add preference gdb/help/browser. + Default is to use builtin html help. + + * helpviewer.itb (HtmlViewer::open_help): New public proc. + Depending on preferences, opens help in external browser or + internal htmlviewer. + + * toolbar.tcl (create_help_menu): Use HtmlViewer::open_help. + +1999-02-17 Martin Hunt + + * managedwin.itb (ManagedWin::_create): Restore some lines that + were accidently checked in commented out. + +1999-02-17 Keith Seitz + + * help/index.html: Add function browser. + * help/browser.html: New help file. + +1999-02-12 Martin Hunt + + * managedwin.itb (ManagedWin::_create): If a window class defines a + public variable "nosize" the size will not be set, only the position. + * browserwin.ith (toggle_all_bp): Add public variable "nosize". + +1999-02-12 Martin Hunt + + * process.ith: New file. + * process.itb: New file. Converted process.tcl to new itcl class. + * process.tcl: Deleted. + + * warning.tcl (WarningDlg::constructor): Set the window name. + +1999-02-11 Martin Hunt + + * variables.tcl (editEntry): Check that $variable is not empty. + + * warning.tcl (WarningDlg::constructor): Put focus on the + "OK" button and bind it to . + + * watch.tcl (add): If the user attempts to add a non-existent + variable to the watch-window, display an ignorable warning. + + * interface.tcl (gdbtk_tcl_ignorable_warning): -transient + should not take an argument. + (set_target_name): Ditto. + * srcbar.tcl (create_menu_items): Ditto. + * memwin.itb (MemWin::create_prefs): Ditto. + * managedwin.itb (ManagedWin::_create): Ditto. + +1999-02-11 James Ingham + + Move the Intel disassembly mode changes into devo. + + * main.tcl: Init the disassembly flavor bits. + * prefs.tcl: Define disassembly-flavor + * srcpref.ith: Add current_disassembly_flavor instance variable + and set_flavor method. + * srcpref.itb (build_win): Add the disassembly_flavor combobox. + (apply): set the flavor, if applicable. + (set_flavor): New method. + * util.tcl: Add 3 new functions - get_disassembly_flavor, + list_disassembly_flavor and init_disassembly_flavor. + +1999-02-10 Martin Hunt + + * srcwin.itb, download.tcl, main.tcl, srcbar.tcl: Removed old + IDE stuff. + + * toolbar.tcl (create_help_menu): Updated Cygnus URL and + removed old IDE stuff. + (create_ide_buttons): Removed. + +1999-02-10 Martin Hunt + + * managedwin.itb (ManagedWin::_create): Bind Alt-F4 to + always close the window. + +1999-02-10 Martin Hunt + + * main.tcl: Removed old debugging preferences. + * prefs.tcl (pref_set_defaults): Ditto. + +1999-02-09 Martin Hunt + + * managedwin.itb (ManagedWin::_create): Simplify raise + and post now that all windows use new manager. + + * warning.tcl (WarningDlg): Rewrite of entire class to use + new itcl 3.0 class. Also now uses a "class name" to keep + track of which messages should be ignored. Uses tk_messageBox + of the message doesn't have -ignorable set. + + * interface.tcl: Removed IDE stuff. + (gdbtk_tcl_ignorable_warning): Accept "class" argument and + use it when creating a WarningDlg. Use new ManagedWin::open. + + * srctextwin.itb (SrcTextWin::set_tp_at_line): Fix TraceDlg + open command to use ManagedWin::open. + + * srcpref.itb (SrcPref::build_win): Comment out line number + option. It wasn't very useful and did not become effective + until GDBtk was restarted. + +1999-02-09 James Ingham + + * srctextwin.itb (build_win): Set the paned window background to + white so it looks better when you switch windows. + + * mempref.itb (build_win): Use the libgui combobox for the bytes per + line field. + + * mempref.itb: remove some global declarations that I missed when + I converted all the variables to instance data. + + * variables.tcl (change_value): Catch one more place where $this + was being passed as a window name. + + * TODO: Added some more items, and removed some that had been fixed. + +Mon Feb 8 12:27:16 1999 Keith Seitz + + * interface.tcl (set_target_name): Fix switch syntax + error and getd the options preference in case it's not set. + + +1999-03-03 James Ingham + + * browser.test: Fixed up to match the new function browser. + This is not done yet... + + * srcwin.test: Check for errors when the bbox is called for a text + item that is not on screen (so bbox is ""). Return something more + useful. + +1999-03-01 James Ingham + + * Changelog entries merged over from gdb development branch. + + 1999-01-12 Martin Hunt + + * gdb.gdbtk/srcwin.test: Add a bunch of tests for the source + window filename and function comboboxes. Add in stack tests. + + 1999-01-11 Martin Hunt + + * gdb.gdbtk/srcwin.test: New file. Source Window tests. + * gdb.gdbtk/srcwin.exp: New file. Source Window tests. + + Wed Jan 6 09:22:52 1999 Keith Seitz + + * gdb.gdbtk/c_variable.test (c_variable-1.9): Add new + test to check for creation of a variable that is really a type. + (c_variable-7.81): Use "output" instead of "print" to get PC. + Include missing bits of test. + + * gdb.gdbtk/cpp_variable.test (cpp_variable-1.6): Default format + is now "natural", not "hexadecimal" + (cpp_variable-2.22): Ditto. + (cpp_variable-2.24): Force format to hex before getting value. + + * gdb.gdbtk/cpp_variable.exp: Supply missing arg to gdbtk_analyze_results. + + Tue Jan 5 12:40:52 1999 Keith Seitz + + * gdb.gdbtk/c_variable.c, c_variable.test, c_variable.exp: New C + language tests for variable object interface. + + * gdb.gdbtk/cpp_variable.h, cpp_variable.cc, cpp_variable.test, + cpp_variable.exp: New C++ language tests for variable object + interface. + + * gdb.gdbtk/Makefile.in (EXECUTABLES): Add c_variable and cpp_variable. + + Tue Jan 5 12:33:47 1999 Keith Seitz + + * lib/gdb.exp (gdbtk_analyze_results): Generic function + for outputting results of test run. + + * gdb.gdbtk/defs (gdbtk_test): Handle xpass and xfail. + (gdbtk_test_error): New proc which handles error aborts. + + * gdb.gdbtk/console.exp: Use gdbtk_analyze_results. + Check if we have a valid DISPLAY before running. + * gdb.gdbtk/browser.exp: Ditto. + + 1998-12-07 Martin M. Hunt + + * lib/gdb.exp (gdbtk_start): Fix path for itcl library. + * gdb.gdbtk/browser.test: Change "manage open" to ManagedWin::open. + * gdb.gdbtk/console.test: Same. + * gdb.gdbtk/*: Update from devo. + + Fri Jul 24 14:57:19 1998 Keith Seitz + + * gdb.gdbtk/Makefile.in: Add new example program "stack". + * gdb.gdbtk/browser.test,browser.exp: Add browser window + tests. + * gdb.gdbtk/stack1.c,stack2.c: Test case for browser window. + +end-sanitize-gdbtk +Thu Feb 25 13:21:58 1999 Michael Meissner + + * flags.h (flag_optimize_comparisons): Add new flag. + + * toplev.c (flag_optimize_comparisons): Add new global. + (f_options): Add -foptimize-comparisons. + + * fold-const.c (fold_truthop): Add optimizing sequence of comparsions + opreations. + (simple2_operand_p): New function like simple_operand_p, but + allows some simple arithmetic as well. + + * jump.c (jump_optimize): Don't do branch elimination on single + insns setting ints larger than the word size. + + * invoke.texi: Update documentation. + +Wed Mar 3 19:09:11 1999 Jim Wilson + + * sparc/elf.h (MULDI3_LIBCALL, DIVDI3_LIBCALL, UDIVDI3_LIBCALL, + MODDI3_LIBCALL, UMODDI3_LIBCALL, STDC_0_IN_SYSTEM_HEADERS): Undef. + (INIT_SUBTARGET_OPTABS): Define to empty. + * sparc/liteelf.h (LONG_DOUBLE_TYPE_SIZE, WIDEST_HARDWARE_FP_SIZE, + STDC_0_IN_SYSTEM_HEADERS, MULDI3_LIBCALL, DIVDI3_LIBCALL, + UDIV3_LIBCALL, MODDI3_LIBCALL, UMODDI3_LIBCALL): Delete. + * sparc/sp86x-elf.h: Likewise. + +Mon Mar 1 19:09:32 1999 Jim Wilson + + * Makefile.in (CROSS_FLOAT_H): Delete. + (FLOAT_H): Use float_h_file. + (rest.cross, stmp-int-hdrs): Delete gfloat.h dependency. + (gfloat.h): Delete. + (stmp-int-hdrs): Use FLOAT_H instead of gfloat.h. + (mostlyclean): Delete gloat.h reference. + (install-cross-rest, install-float-h-cross, stmp-headers): Update + comments. + * configure.in (sparcv9-*-solaris2*): Set float_format to none. + (sparc-*-solaris2*): Set float_format to none for 2.5 and higher. + (float_h_file): Set from float_format. Substitute into Makefile.in. + (float_format): No longer substitute into Makefile.in. + * cross-make (FLOAT_H): Delete. + * config/mips/t-cross64 (FLOAT_H): Delete. + * configure: Rebuilt. + +Wed Mar 3 20:02:21 1999 Jim Wilson + + * m68k/m68020-elf.h (INIT_SECTION_ASM_OP, FINI_SECTION_ASM_OP): Undef. + (STARTFILE_SPEC, ENDFILE_SPEC): Define to empty string. + +Fri Feb 26 12:53:00 1999 Jim Wilson + + * config/misp/mips.h (REGISTER_MOVE_COST): Make the cost of moving + from HI/LO/HILO/MD into general registers the same as for one + of moving general registers to HI/LO/HILO/MD. + +Tue Mar 2 09:24:10 1999 Nick Clifton + + * configure.in (gxx_include_dir): Rename to + gcc_gxx_include_dir in order to prevent it being overridden by + a top level Makefile. + (gcc_tooldir): If $exec_prefix != $prefix then use the + difference between the two as the basis for gcc_tooldir. + (dollar): Define. + + * configure: Rebuild. + + * Makefile.in: Rename gxx_include_dir to gcc_gxx_include_dir. + Add subsitution for dollar. + +Mon Mar 1 15:03:51 1999 Jim Wilson + + * config/m68k/lb1sf68.asm (udivsi3): Change jmi to jcs. Fix comments. + * config/m68k/m68k.h (LEGITIMATE_INDEX_REG_P): Reject SIGN_EXTEND of + HImode reg when TARGET_5200. + +Fri Feb 26 14:52:21 1999 Catherine Moore + + * toplev.c (compile_file): Disable -ffunction-sections and + debugging warning if the object format is elf. + +Sat Feb 20 16:19:55 1999 Andrew Cagney + + * config/mips/mips.c (mips_debugger_offset): When TARGET_MIPS16 && + frame_pointer_needed adjust frame size. + (function_prologue): Don't MIPS16 .mask GPOFFSET. Already adjusted + in .frame pseudo-op. + Frm Jim Wilson : + * mips.c (function_prologue): Adjust frame size in .frame pseudo-op + when TARGET_MIPS16 && frame_pointer_needed. + +1999-03-01 Brendan Kehoe + + Sat Jan 30 08:27:23 1999 Jeffrey A Law (law@cygnus.com) + + * alias.c (fixed_scalar_and_varying_struct_p): Add "static" to + function definition. + (aliases_everything_p, write_dependence_p):Likewise. + +1999-02-25 Jason Merrill + + * tree.c: Check ANSI_PROTOTYPES instead of __STDC__. + +1999-02-23 Jason Merrill + + * errfn.c: Change varargs code to look like toplev.c. + +Thu Feb 23 15:20:49 1999 J"orn Rennecke + + * sh.md (is_sfunc): New attribute. + * sh.h (INSN_SETS_ARE_DELAYED, INSN_REFERENCES_ARE_DELAYED): Use it. + +Thu Feb 11 17:51:24 1999 Michael Meissner + + * rs6000.md (movdf_hardfloat32): Add support for non-offsetable + LO_SUMs in addition to register+register addresses. + +1999-02-18 Vladimir Makarov + + * configure.in (i[34567]86-*-linux-gnu*, + i[34567]86-*-linux-gnulibc1, i[34567]86-*-linux-gnuaout*, + i[34567]86-*-linux-gnuoldld*): Use fixinc.x86-linux-gnu as + fixincludes. + + * configure: Rebuilt. + + * fixinc.x86-linux-gnu: New script for fixing asm-statements bug + on x86 linux. + + * fixinc/fixinc.x86-linux-gnu: Copy of the previous one. + + * fixinc/mkfixinc.sh (i[34567]86-*-linux-gnu*, + i[34567]86-*-linux-gnulibc1, i[34567]86-*-linux-gnuaout*, + i[34567]86-*-linux-gnuoldld*): Use fixinc.x86-linux-gnu as + fixincludes. + +Wed Feb 17 13:27:24 1999 Jim Wilson + + * m68k/crt0.S (start): Use jpbl not jmi in coldfire code. + +Thu Feb 18 15:52:49 1999 Jim Wilson + + * m68kelf.h (ASM_RETURN_CASE_JUMP): Add 5200 support. + +Fri Feb 12 13:06:28 1999 Jim Wilson + + * stmt.c (expand_return): Return if optimize_tail_recursion succeeded. + (optimize_tail_recursion): Change return type from void to int. + Add return statements. + * tree.h (optimize_tail_recursion): Change prototype to match. + +Sun Feb 14 09:24:27 1999 Michael Meissner + + * rs6000.md (iorsi3_internal3): Emit `#' for case where operand3 + is not CR0 so it is properly split. + +Fri Feb 12 13:20:52 1999 Jeffrey A Law (law@cygnus.com) + + * reload.c (find_reloads_address_1): Fix handling of an autoincremented + pseudo which is homed in the stack. + +Tue Feb 16 23:57:17 1999 Jeffrey A Law (law@cygnus.com) + + * mn10300.igen (retf): Fix return address computation and store + the new pc value into nia. + +Wed Feb 10 10:09:41 1999 Jeffrey A Law (law@cygnus.com) + + * mn10200.md (bset, bclr): Operand 0 is a read/write operand. + +Fri Feb 12 00:51:26 1999 Jeffrey A Law (law@cygnus.com) + + * mips.c (save_restore_insns): Fix loop to save/restore FP registers. + (compute_frame_size): Change loop over FP regs to be consistent + with the loop in save_restore_insns. + +Fri Feb 12 13:20:52 1999 Jeffrey A Law (law@cygnus.com) + + * h8300.md (zero_extendhisi2 H8/300 variant): Correctly handle + extending a CONST_INT. + + * h8300.md (peephole for combining memrefs): Delete incorrect peephole. + +Fri Feb 12 13:20:52 1999 Jeffrey A Law (law@cygnus.com) + + * m68k.md (ashldi_const): Disable for !TARGET_5200. Fix indention. + (ashldi3 expander): Similarly. Update comments. + +Fri Feb 12 13:20:52 1999 Jeffrey A Law (law@cygnus.com) + + * calls.c (store_one_arg): Mark any slots used for the argument + as in-use immediately after we're done saving any slots which + will be overwritten by this argument. + + +Wed Feb 10 13:30:18 1999 Dave Brolley + + * mbchar.c (local_mb_cur_max): Handle the case where MB_CUR_MAX is 0. + +Fri Feb 12 18:29:11 1999 J"orn Rennecke + + * loop.c (loop_insn_first_p, biv_elimination_giv_has_0_offset): + New functions. + (maybe_eliminate_biv_1): Use biv_elimination_giv_has_0_offset. + +Fri Feb 12 19:22:41 1999 Vladimir N. Makarov + + * loop.c (strength_reduce): Disable the latest loop optimizations. + + * loop.c (find_life_end): Wrap parameters in forward definition by + missed PROTO. + +1999-02-08 Nick Clifton + + * config/v850/v850.md: Enforce TARGET_LONG_CALLS option. + * config/v850/v850.c (construct_restore_jr, construct_save_jarl): + Enforce TARGET_LONG_CALLS option. + +Sat Feb 6 11:04:08 1999 Jim Wilson + + * unroll.c (find_splittable_givs): After express_from, call replace_rtx + to convert dest_reg to new_reg. + +Wed Feb 10 10:09:41 1999 Jeffrey A Law (law@cygnus.com) + + * reload1.c (reload_combine_note_store): Second argument is no + longer unused/ignored. Handle multi-register hard regs. + (move2add_note_store): Simplify. + +Sat Feb 6 10:31:35 1999 Jeffrey A Law (law@cygnus.com) + + * reload1.c (reload_combine_note_store): Be more careful with + STRICT_LOW_PART, ZERO_EXTRACT and SIGN_EXTRACT. + (move2add_note_store): Likewise. + + +Sat Feb 6 18:14:46 1999 Jeffrey A Law (law@cygnus.com) + + * mn10300.md (reload_insi): Do not earlyclobber the output operand. + +1999-02-05 Michael Meissner + + * loop.c (check_dbra_loop): A store using an address giv for which + we have no life information is not reversible. + +Fri Feb 5 17:08:01 1999 Dave Brolley + + * function.c (fixup_var_refs): Scan catch_clauses too. + +Fri Feb 5 11:33:49 1999 Benjamin Kosnik + + * c-common.c (decl_attributes): Fix reserved space for init_priority. + * tree.h (MAX_RESERVED_INIT_PRIORITY): New macro. + +Fri Feb 5 12:37:05 1999 Jeffrey A Law (law@cygnus.com) + + * loop.c (strength_reduce): Clear not_every_iteration when + passing the NOTE_INSN_LOOP_CONT note. + + * haifa-sched.c (add_dependence): Do not add a dependency on a + note. + +Fri Feb 5 10:52:58 1999 Nick Clifton + + * recog.c (split_block_insns): Only call update_flow_info if + instruction scheduling is enabled. + +Fri Feb 5 07:09:29 1999 J"orn Rennecke + + * loop.c (first_loop_store_insn): New file-scope variable. + (prescan_loop): Set it. + (check_dbra_loop): Check if a store depends on a register + that is set after the store. + +Fri Feb 5 06:55:15 1999 J"orn Rennecke + + * unroll.c (entire file): Remove tabs / spaces at end of lines. + Replace spaces with tabs where appropriate. + +Thu Feb 4 15:12:41 1999 J"orn Rennecke + + * loop.c (scan_loop): New argument loop_cont. Changed caller. + (strength_reduce): New argument loop_cont. Changed caller. + Before clearing not_every_iteration after a label, check if + we are not already past LOOP_CONT. + +Wed Feb 3 20:44:59 1999 J"orn Rennecke + + * loop.h (express_from): Declare. + (struct induction): Replace derived flag with derived_from pointer. + * loop.c (strength_reduce, record_giv, recombine_givs): Likewise. + (express_from): No longer static. + * unroll.c (find_splittable_givs): Replace derived with derived_from. + When processing an address giv with which another giv has been + combined that has also been derived from a third giv, handle like + having combined with the third giv. + Set splittable_regs_updates appropriately for derived givs. + +Wed Feb 3 11:56:23 1999 Jeffrey A Law (law@cygnus.com) + + * pa.c (insn_sets_and_refs_are_delayed): New function. + * pa.h (INSN_SETS_ARE_DELAYED): Use it. + (INSN_REFERENCES_ARE_DELAYED): Likewise. + +Tue Feb 2 22:42:51 1999 Jim Wilson + + * Makefile.in: Change all uses of AR to AR_FOR_TARGET. Change all uses + of HOST_AR to AR. Likewise for AR_FLAGS, RANLIB, and RANLIB_TEST. + (RANLIB_TEST): Test to see if ranlib exists. Only test absolute file + names if host == target. + (HOST_AR, HOST_AR_FLAGS, HOST_RANLIB, HOST_RANLIB_TEST): Delete. + (AR_FLAGS_FOR_TARGET): Renamed from AR_FOR_TARGET_FLAGS. + (AR, AR_FLAGS, OLDAR, OLDAR_FLAGS, RANLIB, RANLIB_TEST): Delete rules + setting them to *_FOR_TARGET. + * cross-make (AR, AR_FLAGS, OLDAR, OLDAR_FLAGS, RANLIB, RANLIB_TEST): + Delete. + +Fri Jan 29 21:00:56 1999 Bob Manson + + * resource.c, resource.h: New files. + * Makefile.in (OBJS): Add it. + + * haifa-sched.c (regno_use_in): Moved to rtlanal.c. + (split_block_insns): Moved to recog.c. + (update_flow_info): Make public. + * rtl.h: Declare them. + + * reorg.c: Moved the functions dealing with computing resource + usage to resource.c. + + * sched.c (regno_use_in): Moved to rtlanal.c. + (update_flow_info): Make public. + (schedule_insns): Use split_block_insns. + + * recog.c (split_block_insns): New function. + +Tue Feb 2 20:26:23 1999 Stan Cox + + * sparc.h (TARGET_CPU_sparc86x): Added. TARGET_CPU_sparclite86x synonym. + +Tue Feb 2 20:24:11 1999 J"orn Rennecke + + * loop.c (loop_optimize): Fix value max_uid_for_loop is reset + to after find_and_verify_loops call. + +Tue Feb 2 19:48:29 1999 J"orn Rennecke + + * (recombine_givs): Don't use a giv that's likely to be dead to + derive others. + + * loop.c (recombine_givs): Fix test for lifetime overlaps / loop + wrap around when deriving givs. + +Mon Feb 1 11:29:49 1999 Nick Clifton + + * config/arm/tpe.h (WCHAR_TYPE): Define to 'unsigend short'. + (WCHAR_TYPE_SIZE): Define to 16. + +1999-01-30 Jim Blandy + + * configure: For PowerPC configurations, accept "401", "ec603e", + "740", and "750" as valid arguments to --with-cpu. They're + supported in config/rs6000/rs6000.c, but were missing from this + list. + +Sat Jan 30 08:27:23 1999 Jeffrey A Law (law@cygnus.com) + + * pa.md (parallel shift and shiftadd): Mark output of shift as an + earlyclobber. + +Sat Jan 30 03:24:37 1999 J"orn Rennecke + + * loop.c (strength_reduce): Size reg_map according to reg_iv_type. + +Fri Jan 29 22:34:41 1999 J"orn Rennecke + + * loop.c (recombine_givs): Don't try to derive givs that have combined. + +Fri Jan 29 15:52:07 1999 Dave Brolley + + * emit-rtl.c (remove_insn): New function. + * rtl.h (remove_insn): Add prototype. + * function.c (reposition_prologue_and_epilogue_notes): Call remove_insn. + +Fri Jan 29 15:44:13 1999 J"orn Rennecke + + * loop.c (strength_reduce): Fix HAVE_cc0 handling when scanning + forward from cont dominator. + +Fri Jan 29 00:14:55 1999 J"orn Rennecke + + * loop.c (strength_reduce): Grow set_in_loop / n_times_set / + may_not_optimize to proper size when converting biv increments + into givs. + If necessary, reallocate reg_iv_type / reg_iv_info before calling + recombine_givs. + +Thu Jan 28 23:24:08 1999 J"orn Rennecke + + * loop.c (recombine_givs): New parameter unroll_p. If set, don't + generate complex adds. Changed caller. + Don't generate adds that cost more than the original one. + (strength_reduce): Warning fixes. + +Wed Jan 27 23:39:53 1999 J"orn Rennecke + + * rtl.h (insn_first_p): Declare. + * rtlanal.c (insn_first_p): New function. + * loop.h (varray.h): Include. + (struct induction): Change combined_with to unsigned. + New members derived, ix and last_use. + (reg_iv_type, reg_iv_info): Now varray_type. All references changed. + (REG_IV_TYPE, REG_IV_INFO): Define. + (first_increment_giv, last_increment_giv): Declare. + * loop.c (loop_number_loop_cont): New static variable. + (loop_number_cont_dominator): Likewise. + (reg_iv_type, reg_iv_info): Now varray_type. + (first_increment_giv, last_increment_giv): New variables. + (compute_luids, verify_dominator, find_life_end): New functions. + (cmp_recombine_givs_stats, recombine_givs): Likewise. + (loop_optimize): Allocate loop_number_loop_cont and + loop_number_cont_dominator. Use compute_luids. + (find_and_verify_loops): Initialize loop_number_loop_cont and + loop_number_cont_dominator. + (strength_reduce): Try to find bivs that can be expressed as givs + of another biv, and to convert biv increments into givs. + Call recombine_givs. Handle derived givs. + (record_biv): New argument location. All callers changed. + (record_giv): Initialize derived and last_use fields. + (basic_induction_var): New argument location. All callers changed. + (combine_givs): Don't combine a DEST_REG giv with a DEST_ADDR giv. + Increment combined_with instead of setting to 1. + * unroll.c (derived_regs): New static variable. + (unroll_loop): Initialize it. + Allocate local_regno according to max_reg_num. + (copy_loop_body): Cope with derived givs. + (find_splittable_givs): Check for Givs made from biv increments. + Set derived_regs for givs. + * Makefile.in (stmt.o, loop.o, unroll.o): Depend on loop.h . + +Wed Jan 27 19:31:36 1999 J"orn Rennecke + + * function.c (purge_addressof_1): Handle case when a register + has been used in a wider mode. + +Tue Jan 26 12:45:55 1999 Jim Wilson + + * function.c (expand_function_end): Pass arg_pointer_save_area to + validize_mem before using it. Emit code into a sequence. + +Sun Jan 24 20:13:45 1999 David Edelsohn + + * rs6000.md (left shift + set cr patterns): Add missing '#' to + split patterns. + (move register + set cr pattern): Ditto. + (movdi, !TARGET_POWERPC64 splitters): Add back in Jan. 15th patch, + inadvertently deleted. + +Sun Jan 24 08:07:59 1999 Jeffrey A Law (law@cygnus.com) + + * stmt.c (stmt_loop_nest_empty): New function. + * tree.h (stmt_loop_nest_empty): Declare it. + * rtl.def (CALL_PLACEHOLDER): New rtx code. + +Sat Jan 23 01:37:36 1999 Jeffrey A Law (law@cygnus.com) + + * configure.in (gcc_tooldir): Handle case where exec_prefix has + not been explicitly set. + * configure: Rebuilt. + + * configure.in (gcc_tooldir): When not making a relative gcc_tooldir, + use $exec_prefix/$target_alias for gcc_tooldir. + * configure: Rebuilt. + +Fri Jan 22 11:48:56 1999 Richard Henderson + + * cppp.c (xrealloc): Fix typo last change. + * cppalloc.c, gcc.c, genattr.c, genattrtab.c, gencodes.c: Likewise. + * genconfig.c, genemit.c, genextract.c, genflags.c: Likewise. + * genopinit.c, genoutput.c, genpeep.c, genrecog.c: Likewise. + +1999-01-22 Michael Meissner + + * rs6000.h (CR0_REGNO_P): New macro to test if cr0. + (CR_REGNO_NOT_CR0_P): New macro to test if cr, but not cr0. + (PREDICATE_CODES): Add cc_reg_not_cr0_operand. + (cc_reg_not_cr0_operand): Add declaration. + + * rs6000.c (cc_reg_not_cr0_operand): Return true if register is a + pseudo register, or a control register that is not CR0. + + * rs6000.md (all combiner patterns building . instructions): For + all `.' instructions that do something and set cr0, add an + alternative that does the operation, and then sets a different + flag, in order to avoid using the costly mcrf instruction and also + allow cr0 to be clobbered in asm statements. Also fix a few + patterns that used the wrong register. + +Fri Jan 22 10:42:06 1999 Vladimir N. Makarov + + * tm.texi (ROUND_TYPE_{SIZE,ALIGN}): More accurate descriptions of + the macros. + +Fri Jan 22 07:43:01 1999 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (gcc_tooldir): Move before first reference. + Let autoconf substitute in a value. + * configure.in (gcc_tooldir): Only use a relative path to the + tool directory if $exec_prefix == $prefix. + * configure: Rebuilt. + + * Makefile.in (tooldir): Replace with gcc_tooldir. + +Thu Jan 21 21:53:36 1999 Richard Henderson + + * emit-rtl.c (try_split): Don't try to split non-instructions. + +Thu Jan 21 20:24:02 1999 Richard Henderson + + * rs6000.h (LEGITIMIZE_RELOAD_ADDRESS): Recognize and accept + transformations that we have performed earlier. + * alpha.h (LEGITIMIZE_RELOAD_ADDRESS): Likewise. + + * alpha.md (prologue_stack_probe_loop): Don't do our own label + handling, call gen_label_rtx instead. + +Thu Jan 21 17:45:18 1999 Richard Henderson + + * cccp.c (xrealloc): Call malloc given a NULL old pointer. + * collect2.c, cppalloc.c, gcc.c, genattr.c, genattrtab.c: Likewise. + * gencodes.c, genconfig.c, genemit.c, genextract.c: Likewise. + * genflags.c, genopinit.c, genoutput.c, genpeep.c: Likewise. + * genrecog.c, mips-tfile.c, protoize.c: Likewise. + +Thu Jan 21 15:48:03 1999 Dave Brolley + + * cppexp.c (cpp_lex): Allocate token_buffer dynamically. + +1999-01-21 Vladimir N. Makarov + + * config/i960/i960.h (LONG_DOUBLE_TYPE_SIZE): Remove labels + `CYGNUS LOCAL i960-80bit'. + * emit-rtl.c (operand_subword) : Ditto + * stor-layout.c (layout_type): Ditto. + * varasm.c (output_constant_pool): Ditto. + +Thu Jan 21 14:18:04 EST 1999 Andrew MacLeod + + * expr.c (MOVE_BY_PIECES_P): Define condition for deciding to use + move_by_pieces. + (MOVE_MAX_PIECES): Define maximum number of bytes to move at once. + (USE_LOAD_POST_INCREMENT, USE_LOAD_PRE_DECREMENT): Define defaults. + (USE_STORE_POST_INCREMENT, USE_STORE_PRE_DECREMENT): Define defaults. + (move_by_pieces): Use new macros. + (emit_block_move): Use new macros. + (clear_by_pieces): Use new macros. + (clear_storage): Use new macros. + (emit_push_insn): Use new macros. + (expand_expr): Use new macros. + * config/sh/sh.h (USE_LOAD_POST_INCREMENT, USE_LOAD_PRE_DECREMENT): + Define. + (USE_STORE_POST_INCREMENT, USE_STORE_PRE_DECREMENT): Define. + (MOVE_BY_PIECES_P): Define based on alignment and TARGET_SMALLCODE. + (MOVE_MAX_PIECES): move 8 bytes on SH4. + * tm.texi(MOVE_BY_PIECES_P, MOVE_MAX_PIECES, USE_LOAD_POST_INCREMENT, + USE_LOAD_PRE_DECREMENT, USE_STORE_POST_INCREMENT, + USE_STORE_PRE_DECREMENT): Describe new macros. + +Thu Jan 21 09:38:04 1999 Nick Clifton + + * config/arm/arm.c (arm_gen_store_multiple): Fix typo in recent + update. + +Wed Jan 20 18:15:08 1999 Dave Brolley + + * function.c (assign_parms): Save and restore setting of + TREE_USED (parm). + +Wed Jan 20 12:51:42 1999 Mark Mitchell + + * arm.md: Use MEM_COPY_ATTRIBUTES where appropriate throughout. + Pass MEM_SCALAR_P to arm_gen_store_multiple where appropriate. + +Tue Jan 19 21:20:52 1999 Richard Henderson + + * recog.c (pop_operand): New function. + * recog.h (pop_operand): Declare it. + * genrecog.c (preds): Define it. + + * expr.c (do_jump_for_compare): Handle conditional branch expanders + emitting multiple jump instructions. + * jump.c (condjump_label): New function. + * rtl.h (condjump_label): Declare it. + +Tue Jan 19 21:08:20 1999 Richard Henderson + + * expr.c (emit_move_insn_1): Revert 17 Dec change. Don't emit + clobber during or after reload. + +Tue Jan 19 16:56:03 1999 Richard Henderson + + * genoutput.c (name_for_index): New function. + (scan_operands, validate_insn_alternatives): Use it. + * genrecog.c (insn_name_ptr_size): New variable. + (make_insn_sequence): Fill in insn_name_ptr. + (merge_trees): Use it. + +Tue Jan 19 16:37:36 1999 Richard Henderson + + * i386/isc.h (TARGET_DEFAULT): Define symbolicly. + * i386/isccoff.h, i386/next.h, i386/sco.h, i386/sco5.h: Likewise. + * i386/scodbx.h, i386/sequent.h, i386.unix.h: Likewise. + +Tue Jan 19 15:00:10 1999 Jeffrey A Law (law@cygnus.com) + + * loop.c (NUM_STORES): Delete. + (loop_store_mems): Turn into an EXPR_LIST of MEMs. + (prescan_loop): Properly initialize loop_mems_idx. + (note_addr_stored): Simplify using list structure instead of + fixed sized array. + (invariant_p, check_dbra_loop, load_mems): Similarly. + + * flow.c (invalidate_from_autoinc): New function. + (mark_set_1, mark_used_regs): Use it. + + * Makefile.in (protoize.o, unprotoize.o): Depend on Makefile. + +Tue Jan 19 11:54:04 1999 Jason Merrill + + * calls.c (expand_call): Strip a TARGET_EXPR if we're passing by + invisible reference. + +1999-01-19 Vladimir N. Makarov + + * invoke.texi (-mlong-double-64): New option description. + +1999-01-19 Jim Wilson + + * libgcc2.c: Change all uses of LONG_DOUBLE_TYPE_SIZE to + LIBGCC2_LONG_DOUBLE_TYPE_SIZE. + (LIBGCC2_LONG_DOUBLE_TYPE_SIZE): New. Set to LONG_DOUBLE_TYPE_SIZE + if not defined. + * i960/i960.h (MULTILIB_DEFAULTS): Define to mnumerics. + (CPP_SPECS): Add -mlong-double-64 support. + (TARGET_FLAG_LONG_DOUBLE_64, TARGET_LONG_DOUBLE_64): New. + (TARGET_SWITCHES): Add -mlong-double-64 support. + (LONG_DOUBLE_TYPE_SIZE): Likewise. + (LIBGCC2_LONG_DOUBLE_TYPE_SIZE): Define. + * i960/vx960-coff.h (MULTILIB_DEFAULTS): Define to msoft-float. + (CPP_SPECS): Add -mlong-double-64 support. + * i960/t-960bare (MULTILIB_OPTIONS): Add mlong-double-64. + (MULTILIB_DIRNAMES): Add ld64. + * i960/t-vxworks960 (MULTILIB_OPTIONS, MULTILIB_DIRNAMES): Likewise. + +Tue Jan 19 10:24:53 1999 Mark Mitchell + + * rtl.h (rtx_def): Update documentation. + (MEM_IN_STRUCT_P): Likewise. + (MEM_SCALAR_P): New macro. + (MEM_COPY_ATTRIBUTES): Likewise. + (MEM_SET_IN_STRUCT_P): Likewise. + * rtl.texi (MEM_SCALAR_P): Document. + * alias.c (canon_rtx): Use MEM_COPY_ATTRIBUTES. + (fixed_scalar_and_varying_struct_p): New function. Use + MEM_SCALAR_P rather than !MEM_IN_STRUCT_P. + (aliases_everything_p): Likewise. + (true_dependence): Use them. + (write_dependence_p): New function, containing code common to + anti_dependence and output_dependence. + (anti_dependence): Use it. + (output_dependence): Likewise. + * calls.c (save_fixed_argument_area): Don't clear + MEM_IN_STRUCT_P. + (expand_call): Use MEM_SET_IN_STRUCT_P. + (emit_library_call): Don't clear MEM_IN_STRUCT_P. + (emit_library_call_value): Likewise. + (store_one_arg): Use MEM_SET_IN_STRUCT_P. + * combine.c (simplify_rtx): Use MEM_COPY_ATTRIBUTES. + (make_extraction): Likewise. + (simplify_shift_const): Likewise. + (gen_lowpart_for_combine): Likewise. + * cse.c (gen_lowpart_if_possible): Use MEM_COPY_ATTRIBUTES. + * emit-rtl.c (operand_subword): Likewise. + (change_address): Likewise. + * explow.c (stabilize): Use MEM_COPY_ATTRIBUTES. + * expr.c (protect_from_queue): Use MEM_COPY_ATTRIBUTES. + (emit_group_store): Use MEM_SET_IN_STRUCT_P. + (copy_blkmode_from_reg): Likewise. + (store_field): Likewise. + (expand_expr): Remove bogus guesswork setting MEM_IN_STRUCT_P + heuristically. Use MEM_SET_IN_STRUCT_P. + (get_memory_rtx): Likewise. + * final.c (alter_subreg): Use MEM_COPY_ATTRIBUTES. + * function.c (assign_stack_temp): Clear MEM_SCALAR_P and + MEM_ALIAS_SET on newly returned MEMs. + (assign_temp): Use MEM_SET_IN_STRUCT_P. + (put_reg_into_stack): Likewise. + (fixup_var_refs1): Use MEM_COPY_ATTRIBUTES. + (gen_mem_addressof): Use MEM_SET_IN_STRUCT_P. + (assign_parms): Likewise. + (expand_function): Likewise. + * integrate.c (expand_inline_function): Likewise. + (copy_rtx_and_substitute): Use MEM_COPY_ATTRIBUTES. + * loop.c (note_addr_stored): Remove check on MEM_IN_STRUCT_P. + * optabs.c (gen_move_insn): Use MEM_COPY_ATTRIBUTES. + * print-rtl.c (print_rtx): Print /f for frame_related. + * recog.c (validate_replace_rtx_1): Use MEM_COPY_ATTRIBUTES. + * reload1.c (reload): Copy MEM_SCALAR_P as well. + * stmt.c (expand_decl): Use MEM_SET_IN_STRUCT_P. + (expand_anon_union_decl): Use MEM_COPY_ATTRIBUTES. + * varasm.c (make_decl_rtl): Use MEM_SET_IN_STRUCT_P. + (output_constant_def): Likewise. + * a29k.c (a29k_set_memflags_1): Take scalar_p. + Set MEM_SCALAR_P. + (a29k_set_memflags): Use it. + * alpha.c (get_aligned_mem): Use MEM_COPY_ATTRIBUTES. + * c4x.c (c4x_scan_for_ld): Likewise. + * h8300.c (fix_bit_operand): Likewise. + * m88k.c (legitimize_address): Likewise. + (block_move_loop): Likewise. + (block_move_no_loop): Likewise. + (block_move_sequence): Likewise. + (m88k_builtin_saveregs): Use MEM_SET_IN_STRUCT_P. + * mips/abi64.h (SETUP_INCOMING_VARARGS): Likewise. + * rs6000.c (expand_block_move_insn): Use MEM_COPY_ATTRIBUTES. + * sh.c (sh_builtin_saveregs): Use MEM_SET_IN_STRUCT_P. + * arm.h (arm_gen_load_multiple): Take scalar_p. + (arm_store_load_multiple): Likewise. + * arm.c (arm_gen_load_multiple): Likewise. + (arm_gen_store_multiple): Likewise. + (arm_gen_movstrqi): Treat MEM_SCALAR_P like MEM_IN_STRUCT_P. +Tue Jan 19 06:26:30 1999 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (cccp.o, cpplib.o): Depend on Makefile. + +Mon Jan 18 03:52:56 1999 Christian Bruel + Jeffrey A Law (law@cygnus.com) + + * flow.c (last_mem_set): Delete variable. References removed. + (mem_set_list): New variable. + (life_analysis): Initialize and finalize alias analysis. + (propagate_block); Initialize mem_set_list. Clear for CALL_INSNs. + (insn_dead_p): For a store to memory, search the entire mem_set_list + for a match. + (mark_set_1): Kill entries on the mem_set_list for aliased writes or + changes to their addresses. Add new entries to the mem_set_list for + memory writes writes. + (mark_used_regs): Kill entries on the mem_set_list which may be + referenced by a load operation. + +Mon Jan 18 01:01:02 1999 Jeffrey A Law (law@cygnus.com) + + * alias.c (base_alias_check): Add missing return for differing + symbols case. + +Sun Jan 17 19:23:20 1999 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (cppulp.o): Add dependencies. + + * i386.md (integer conditional moves): Add missing earlyclobbers. + + * regmove.c (optimize_reg_copy_1): Undo Aug 18 change. Update + REG_N_CALLS_CROSSED and REG_LIVE_LENGH if and only if we change + where a register is live. + +Sat Jan 16 15:13:46 1999 Jeffrey A Law (law@cygnus.com) + + * pa.md (shadd): Create shadd insns, even if the result of the shift is + needed without the addition. + +Sat Jan 16 10:48:16 1999 J"orn Rennecke + + * sh.md (movdf, movsf): Temporary workaround for no_new_pseudos lossage. + +Fri Jan 15 17:43:59 1999 Jeffrey A. Law + + * sparc.h (LEGITIMIZE_RELOAD_ADDRESS): Do not create + (mem (lo_sum (...)) for TFmode unless TARGET_V9. + +Thu Jan 14 22:38:41 1999 Jeffrey A Law (law@cygnus.com) + + * h8300.h (ASM_OUTPUT_LABELREF): Use asm_fprintf, not fprintf. + + * stmt.c (expand_end_case): Use emit_cmp_and_jump_insns to avoid + generating non-canonical rtl. + +1999-01-14 Vladimir N. Makarov + + * config/i960/i960.c (i960_output_move_double_zero, + i960_output_move_quad_zero): New functions for moving zeros. + (i960_output_move_double, i960_output_move_quad): Additional code + for situation when moving unaligned register group. + + * config/i960/i960.h (i960_output_move_double_zero, + i960_output_move_quad_zero): The function definitions. + + * config/i960/i960.md (movdi+1, movti+1): Usage of the functions. + +1999-01-13 Vladimir N. Makarov + + * config/i960/i960.c (i960_function_prologue): New code (optimal + solution) for saving global registers in local registers. + (form_reg_groups, reg_group_compare, split_reg_group): New + functions used by the code. + (reg_group): New structure definition for the new code. + +Wed Jan 13 13:28:22 1999 Catherine Moore + + * config/arm.c (output_func_epilogue): Check TARGET_ABORT_NORETURN + before generating a call to abort for volatile functions. + * config/arm.h (ARM_FLAG_ABORT_NORETURN): Define. + (TARGET_ABORT_NORETURN): Define. + (abort-on-noreturn): New option. + +Wed Jan 13 00:59:04 1999 Jeffrey A Law (law@cygnus.com) + + * mips.h (LOAD_EXTEND_OP): Correct for SImode and CCmode moves when + generating code for TARGET_64BIT. + +Tue Jan 12 10:23:24 1999 Stan Cox + + * mips.md (call_value_internal3c): New pattern for -mips16 -mlong-calls. + +Tue Jan 12 02:36:10 PST 1999 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Tue Jan 12 01:30:19 1999 Richard Henderson + + * rtl.c (rtx_alloc): Use memset instead of inline loop. + + * recog.h (recog_op_alt): Declare extern. + +Tue Jan 12 00:23:31 1999 Richard Henderson + + * function.c (purge_addressof_1): If the note accesses a mem+addressof + in a wider mode than any replacement, adjust the cached replacement. + Cache trivial substitutions as well. + +Tue Jan 12 00:06:00 1999 Richard Henderson + + * Makefile.in (OBJECTS): Add sbitmap.o. + (BASIC_BLOCK_H): Add sbitmap.h. + * basic-block.h: Move simple bitmap code to sbitmap.h. + * flow.c: Move simple bitmap code to sbitmap.c + * sbitmap.h, sbitmap.c: New files. + +Mon Jan 11 23:51:50 1999 Richard Henderson + + * alpha.h (TARGET_SWITCHES): Document switches. + (TARGET_OPTIONS): Likewise. + + * alpha/elf.h (ASM_FINISH_DECLARE_OBJECT): Use HOST_WIDE_INT_PRINT_DEC. + +Mon Jan 11 22:54:14 1999 Richard Henderson + + * tree.c (new_alias_set): Return zero if !flag_strict_aliasing. + +Mon Jan 11 22:36:01 1999 Richard Henderson + + * basic-block.h (basic_block_head): Rename to x_basic_block_head. + (basic_block_end): Rename to x_basic_block_end. + (BLOCK_HEAD, BLOCK_END): Update. + + * caller-save.c: Change basic_block_head/end references to + BLOCK_HEAD/END. + * combine.c, flow.c, function.c, gcse.c, global.c: Likewise. + * graph.c, haifa-sched.c, local-alloc.c, regclass.c: Likewise. + * regmove.c, reload1.c, reorg.c, sched.c: Likewise. + +Thu Jan 11 18:37:50 1999 Vladimir N. Makarov + + * invoke.texi (-mcpu=740, -mcpu=750): New options. + (-m(no-)multiple, -m(no-)string): Describe cases for PPC740 & + PPC750. + +1999-01-11 Michael Meissner + + * config/rs6000/rs6000.h ({ASM,CPP}_CPU_SPEC): Add support for all + machines supported with -mcpu=xxx. + (processor_type): Add PROCESSOR_PPC750. + (ADJUST_PRIORITY): Call rs6000_adjust_priority. + (RTX_COSTS): Supply costs for 750 multiply/divide operations. + (rs6000_adjust_priority): Add declaration. + + * config/rs6000/rs6000.c (rs6000_override_options): + -mcpu={750,740} now sets the processor type as 750, not 603. + Allow -mmultiple and -mstring on little endian 750 systems. + (rs6000_adjust_priority): Stub for now. + (get_issue_rate): The PowerPC 750 can issue 2 instructions/cycle. + + * config/rs6000/rs6000.md (function/cpu attributes): Add initial + ppc750 support. + + * config/rs6000/sysv4.h (STRICT_ALIGNMENT): Don't force strict + alignment if little endian. + (CC1_SPEC): Pass -mstrict-align if little endian, and not + overridden. + (CC1_ENDIAN_{LITTLE,BIG,DEFAULT}_SPEC): Endian specific configs. + (SUBTARGET_EXTRA_SPECS): Add cc1 endian specs. + + * config/rs6000/{sysv4,eabi}le.h (CC1_ENDIAN_DEFAULT_SPEC): + Override, default is little endian. + + * config/rs6000/t-ppcgas (MULTILIB_*): Delete obsolete Solaris + multilibs. + +Sat Jan 9 23:54:09 1999 Kaveh R. Ghazi + + * gcc.c (xstrerror): Renamed from my_strerror. All callers + changed. Remove prototype since we get that from libiberty.h. + + * protoize.c (xstrerror): Likewise. + +Sat Jan 9 23:22:04 1999 Kaveh R. Ghazi + + * gcc.c (read_specs): Ensure format specifiers match their arguments. + +Sat Jan 9 20:04:24 1999 Richard Henderson + + * tree.c (copy_node): Oops. That would be copy not zero + in that last change. + +Sun Jan 10 15:35:41 1999 Michael Hayes + + * config/c4x/c4x.c: Include system.h. + (c4x_caller_save_map): Disable caller save for RC. + (c4x_optimization_options): Disable scheduling before reload. + (valid_parallel_load_store) : Define return type as int. + Remove unused variable regs. + * config/c4x/c4x.h (REGISTER_MOVE_COST): Make independent of register + class. + * config/c4x/c4x.md (rotlqi3, rotrqi3): Fix up emitted RTL to + handle rotations. + (*db, decrement_and_branch_until_zero): Fix up constraints + to keep reload happy. + +Sat Jan 9 18:35:29 1999 Richard Henderson + + * tree.c (make_node): Call bzero instead of inline clear. + (copy_node, make_tree_vec, build1): Likewise. + (get_identifier): Call strlen instead of inline count. + (maybe_get_identifier): Likewise. + +Sun Jan 10 14:04:51 1999 Michael Hayes + + * config/c4x/c4x.md: (in_annul_slot_3): Allow unarycc and binarycc + operations in 3rd annulled delay slot. + (*lshrqi3_const_set): Disallow c constraint for operand0. + (modhi3+1, modhi3+2): Set attribute type to multi. + * config/c4x/c4x.c (c4x_S_constraint): Removed space in middle of + != operator. + +Sat Jan 9 11:44:55 1999 Kaveh R. Ghazi + + * gansidecl.h: Allow attribute unused on labels only when we are + version 2.93 or higher. Not all versions of 2.92 have this feature. + + * version.c: Bump minor number to 93. + +Fri Jan 8 10:51:13 1999 Andreas Schwab + + * config/m68k/m68k.h: Declare output_function_epilogue. + * recog.h: Declare next_insn_tests_no_inequality. + +Fri Jan 8 01:43:53 1999 Jeffrey A Law (law@cygnus.com) + + * stmt.c (optimize_tail_recursion): New function, extracted from ... + (expand_return): Use optimize_tail_recursion. + * tree.h (optimize_tail_recursion): Declare. + + * toplev.c (compile_file): Move call to output_func_start_profiler + to after the loop to emit deferred functions. + +Thu Jan 7 19:52:53 1999 Gerald Pfeifer + + * system.h (abort): Supply more detailed information on how to + report an Internal Compiler Error. + +Thu Jan 7 11:26:17 1999 Mark Mitchell + + * calls.c (store_unaligned_arguments_into_pseudos): Use xmalloc to + allocate memory that will live beyond this function. + (expand_call): Free it here. + +Thu Jan 7 03:08:17 1999 Richard Henderson + + * sparc.h (PREFERRED_RELOAD_CLASS): Select GENERAL_REGS for + integer data not destined for fp regs. + (LEGITIMIZE_RELOAD_ADDRESS): New. + +Thu Jan 7 03:03:42 1999 Stan Cox + Richard Henderson + + Support for Hypersparc and Sparclite86x: + * sparc.h (TARGET_CPU_hypersparc, TARGET_CPU_sparclite86x): New. + (CPP_CPU32_DEFAULT_SPEC): Fix up for the new targets. + (ASM_CPU32_DEFAULT_SPEC): Likewise. + (TARGET_CPU_DEFAULT): Likewise. + (enum processor_type): Likewise. + (CPP_ENDIAN_SPEC): Handle little endian data. + (LIBGCC2_WORDS_BIG_ENDIAN): Likewise. + (ADJUST_COST): Call sparc_adjust_cost. + * sparc.c (sparc_override_options): Fix up for the new targets. + (supersparc_adjust_cost): Make static. + (hypersparc_adjust_cost): New. + (ultrasparc_adjust_cost): Make static. + (sparc_adjust_cost): New. + * sparc.md (attr cpu): Add hypersparc and sparclite86x. + (function_unit): Add hypersparc scheduling rules. + + * configure.in (with_cpu handler): Recognize hypersparc. + +Thu Jan 7 23:54:05 1999 Michael Hayes + + * config/c4x/c4x.c: Added space after negation operator. + * config/c4x/c4x.h: Likewise. + * config/c4x/c4x.md: Likewise. + +Thu Jan 7 23:39:27 1999 Michael Hayes + + * config/c4x/c4x.c (c4x_preferred_reload_class): Always return class. + +Thu Jan 7 00:29:25 199 Bernd Schmidt + + * combine.c (num_sign_bit_copies): In NEG, MULT, DIV and MOD cases, + when a test can't be performed due to limited width of + HOST_BITS_PER_WIDE_INT, use the more conservative approximation. + Fix UDIV case for cases where the first operand has the highest bit + set. + +Thu Jan 7 00:01:38 1999 Lutz Vieweg + + * pa.h (reg_class): Add FPUPPER_REGS. + (REG_CLASS_NAMES): Similarly. + (REG_CLASS_CONTENTS): Similarly + (REGNO_REG_CLASS): Handle FPUPPER_REGS. + (FP_REG_CLASS_P): Likewise. + (REG_CLASS_FROM_LETTER): Similarly. + (CLASS_MAX_NREGS): Similarly. + +1999-01-06 Brendan Kehoe + + * fixincludes: For HP/UX 10.20, also look in curses_colr/curses.h + for a typedef of bool. Make sure to have a copy of the file is + in place before we look to fix it. Fix typo in variable name to + FILE. + +Wed Jan 6 07:51:05 1999 Richard Henderson + + * expr.c (expand_builtin) [case BUILT_IN_CONSTANT_P]: Use + value_mode for the return mode. + +Wed Jan 6 17:55:19 1999 Robert Lipe + + * configure.in: New flag --with-dwarf2. If set, enables DWARF-2 + debugging as default. + + * config/tm-dwarf2.h: New file. + +Wed Jan 6 16:08:54 1999 Jeffrey A Law (law@cygnus.com) + + * h8300.h (ASM_OUTPUT_LABELREF): Define. + + * pa.h (DONT_RECORD_EQUIVALENCE): Kill. + * local-alloc.c (update_equiv_regs): Corresponding changes. + * tm.texi (DONT_RECORD_EQUIVALENCE): Kill. + + * calls.c (special_function_p): Push alloca test inside the large + conditional which excludes functions not at file scope or not + extern. + + * calls.c (special_function_p): New function broken out of + expand_call. + (precompute_register_parameters): Likewise. + (store_one_arg): Likewise. + (store_unaligned_argumetns_into_pseudos): Likewise. + (save_fixed_argument_area): Likewise. + (restore_fixed_argument_area): Likewise. + (expand_call): Corresponding changes. + +Wed Jan 6 10:43:29 1999 Andreas Schwab + + * config/m68k/m68k.c (const_uint32_operand): Remove CONSTANT_P_RTX + handling. + (const_sint32_operand): Likewise. + +Wed Jan 6 09:44:51 1999 Kaveh R. Ghazi + + * toplev.h: In addition to checking _JBLEN, also check if `setjmp' + is a macro when deciding if we can use `jmp_buf' in prototypes. + +Thu Jan 7 00:12:24 1999 Michael Hayes + + * config/c4x/c4x.md (addqi3): If the destination operand is + a hard register other than an extended precision register, + emit addqi3_noclobber. + (*addqi3_noclobber_reload): New pattern added so that reload + will recognise a store of a pseudo, equivalent to the sum + of the frame pointer and a constant, as an add insn. + +Wed Jan 6 03:18:53 1999 Mark Elbrecht + + * expr.c (store_expr): If the lhs is a memory location pointed + to be a postincremented (or postdecremented) pointer, always + force the rhs to be evaluated into a pseudo. + +Wed Jan 6 00:54:21 1999 Geoff Keating + + * real.c (mtherr): Print more reasonable warning messages. + +Tue Jan 5 21:57:42 1999 Kaveh R. Ghazi + + * Makefile.in (gcc.o, prefix.o, cccp.o, cpplib.o): Depend on prefix.h. + + * cccp.c: Include prefix.h, don't prototype prefix.c functions. + (new_include_prefix): Constify char* parameters. + + * cppfiles.c (read_name_map): Likewise. + (append_include_chain): Likewise. Also, use a writable char* copy + of parameter `dir' which we then modify, rather than using the + parameter itself to store the new writable string. + (remap_filename): Constify some variables. Also, use a writable + char* to store an allocated string which we will be modifying. + + * cpplib.c: Include prefix.h, don't prototype prefix.c functions. + (cpp_start_read): Constify variable `str'. + + * cpplib.h (append_include_chain): Constify a char* parameter. + + * gcc.c Include prefix.h, don't prototype prefix.c functions. + (add_prefix, save_string): Constify char* parameters. + (fatal, error): Add ATTRIBUTE_PRINTF_1 to prototypes. + + * prefix.c: Include prefix.h. + (get_key_value, translate_name, save_string, update_path, + set_std_prefix): Constify various char* parameters and variables. + (save_string): Use xmalloc, not malloc. + (translate_name): Use a writable temporary variable to create and + modify a string before setting it to a const char*. + + * prefix.h: New file to prototype functions exported from prefix.c. + +Mon Jan 4 15:37:30 1999 Zack Weinberg + + * cpplib.c (skip_if_group): Split out the logic that handles + directive recognition to its own function. Don't use + parse markers; use a bare pointer into the buffer. Use + copy/skip_rest_of_line instead of doing it by hand. Remove + `return on any directive' mode which was never used, and take + only one argument. + (consider_directive_while_skipping): New function, subroutine + of skip_if_group. Logic streamlined a bit. + (conditional_skip, do_elif, do_else): Call skip_if_group with + only one argument. + +Mon Jan 4 15:27:30 1999 Zack Weinberg + + * cpplib.c (do_undef): EOF immediately after '#undef FOO' is not an + error. + +Mon Jan 4 11:55:51 1999 Jason Merrill + + * extend.texi (Bound member functions): Document. + +Mon Jan 4 11:01:48 1999 Kaveh R. Ghazi + + * mips-tdump.c (st_to_string, sc_to_string, glevel_to_string, + lang_to_string, type_to_string): Make return type const char*. + (print_symbol): Apply `const' keyword to a char*. + (print_file_desc): Cast structure member `crfd' to ulong when + comparing against one. + + * mips-tfile.c (pfatal_with_name): Apply `const' keyword to char*. + (fatal, error): Add ATTRIBUTE_PRINTF_1 to prototypes. + (progname, input_name): Apply `const' keyword to a char*. + Don't redundantly include sys/stat.h. + (alloc_info): Apply `const' keyword to a char*. + (st_to_string, sc_to_string): Likewise. + (hash_string): Cast variable `hash_string' to a symint_t when + comparing against one. + (add_string): Cast PAGE_USIZE to Ptrdiff_t when comparing against one. + Likewise cast it to long when comparing against one. + (add_local_symbol): Apply `const' keyword to a char*. + (add_ext_symbol): Likewise. + (add_unknown_tag): Likewise. + (add_procedure): Cast a printf-style field width to an int. + (add_file): Cast PAGE_USIZE to long when comparing against one + (parse_begin): Cast a printf-style field width to an int. + (parse_bend): Likewise. + (parse_def): Likewise. + (parse_end): Likewise. + (mark_stabs): Mark parameter `start' with ATTRIBUTE_UNUSED. + (parse_stabs_common): Fix format specifier. + (parse_input): Change type of variable `i' to Size_t. + (write_object): Fix arguments to match format specifiers. + Cast variable `num_write' to long when comparing against one. + (read_seek): Cast variable `sys_read' to symint_t when comparing + against one. Fix arguments to match format specifiers. Cast + variable `size' to long when comparing against one. + (copy_object): Cast result of `sizeof' to int when comparing + against one. Fix arguments to match format specifiers. Cast + variable `ifd' to long when comparing against a signed value. + Likewise, likewise. + +Mon Jan 4 10:30:33 1999 Kaveh R. Ghazi + + * c-common.c (decl_attributes): Allow applying attribute `unused' + on a LABEL_DECL. + + * c-parse.in (label): Parse attributes after a label, and call + `decl_attributes' to handle them. + + * gansidecl.h (ATTRIBUTE_UNUSED_LABEL): Define. + + * genrecog.c (OUTPUT_LABEL, write_tree_1, write_tree): When + generating labels, mark them with ATTRIBUTE_UNUSED_LABEL. + + * invoke.texi: Note that labels can be marked `unused'. + +Sun Jan 3 23:32:18 PST 1999 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sun Jan 3 23:00:42 1999 Jeffrey A Law (law@cygnus.com) + + * optabs.c (emit_cmp_and_jump_insns): Use CONSTANT_P canonicalizing + RTL for a compare/jump sequence. + +Sun Jan 3 22:58:15 1999 Michael Hayes + + * optabs.c (emit_cmp_insn): Abort if asked to emit non-canonical RTL + for a target with HAVE_cc0 defined. + (emit_cmp_and_jump_insns): New function. + * expr.h (emit_cmp_and_jump_insns): Prototype it. + * loop.c (check_dbra_loop): Use it to replace calls + to emit_cmp_insn and emit_jump_insn and to canonicalise + the comparison if necessary. + * unroll.c (unroll_loop): Likewise. + +Sun Jan 3 21:01:04 1999 Rainer Orth + + * fixincludes (sys/utsname.h): Provide forward declaration of + struct utsname on Ultrix V4.[35]. + + * mips.md (div_trap): Use local labels instead of dot-relative + branches. + +Sun Jan 3 20:40:34 1999 Jeffrey A Law (law@cygnus.com) + + * pa.md (branch, negated branch): Handle (const_int 0) as first + source operand. + * pa.c (output_cbranch): Likewise. + +Sun Jan 3 03:20:38 1999 David Edelsohn + + * rs6000.c (rs6000_stack_info): Undo spurious part of last + change. + +1999-01-01 Manfred Hollstein + + * extend.texi (__builtin_constant_p): Add missing @smallexample. + +Fri Jan 1 11:48:20 1999 Jeffrey A Law (law@cygnus.com) + + * i386.md (doubleword shifts): Fix dumb mistakes in previous change. + +Wed Dec 30 23:38:55 1998 Jeffrey A Law (law@cygnus.com) + + * m68k.md (adddi_dilshr32): Allow all operands to be registers too. + (adddi_dishl32): Similarly. + + * cse.c (invalidate_skipped_block): Call invalidate_from_clobbers + for each insn in the skipped block. + + * reload1.c (reload_as_needed): Verify that the insn satisfies its + constraints after replacing a register address with an autoincrement + address for reload inheritance purposes. + + * i386.md (doubleword shifts): Avoid namespace pollution. + +Wed Dec 30 23:00:28 1998 David O'Brien + + * configure.in (FreeBSD ELF): Needs special crt files. + +Wed Dec 30 22:50:13 1998 Geoffrey Noer + + * i386/xm-cygwin.h: change DIR_SEPARATOR to forward slash. + +1998-12-30 Andreas Schwab + + * loop.c (check_dbra_loop): While reversing the loop, if the + comparison value has a VOID mode use the mode of the other operand + to compute the mask. + +Wed Dec 30 22:24:00 1998 Michael Meissner + + * rs6000.md ({save,restore}_stack_function): Take 2 operands to + avoid warnings in compiling explow.c. + + (patch from Ken Raeburn, raeburn@cygnus.com) + * rs6000.c (rs6000_stack_info): Force 8-byte alignment of + fpmem_offset. Compute total size after that, and then + rs6000_fpmem_offset using both values. + +Mon Dec 28 19:26:32 1998 Gerald Pfeifer + + * gcc.texi (Non-bugs): ``Empty'' loops will be optimized away in + the future; indeed that already happens in some cases. + +Tue Dec 29 11:58:53 1998 Richard Henderson + + * sparc.c (input_operand): Recognize (const (constant_p_rtx)). + (arith_operand): Remove constant_p_rtx handling. + (const64_operand, const64_high_operand): Likewise. + (arith11_operand, arith10_operand, arith_double_operand): Likewise. + (arith11_double_operand, arith10_double_operand, small_int): Likewise. + (small_int_or_double, uns_small_int, zero_operand): Likewise. + * sparc.h (PREDICATE_CODES): Likewise. + + * rtl.h (CONSTANT_P): Remove CONSTANT_P_RTX. + +Tue Dec 29 11:32:54 1998 Richard Kenner : + + * rtl.def (CONSTANT_P_RTX): Clarify commentary. + * expr.c (expand_builtin, case BUILT_IN_CONSTANT_P): Rework to + consider constant CONSTRUCTOR constant and to defer some cases + to cse. + * cse.c (fold_rtx, case CONST): Add handling for CONSTANT_P_RTX. + * regclass.c (reg_scan_mark_refs, case CONST): Likewise. + +Tue Dec 29 11:30:10 1998 Richard Henderson + + * expr.c (init_expr_once): Kill can_handle_constant_p recognition. + * cse.c (fold_rtx, case 'x'): Remove standalone CONSTANT_P_RTX code. + + * alpha.c (reg_or_6bit_operand): Remove CONSTANT_P_RTX handling. + (reg_or_8bit_operand, cint8_operand, add_operand): Likewise. + (sext_add_operand, and_operand, or_operand): Likewise. + (reg_or_cint_operand, some_operand, input_operand): Likewise. + * alpha.h (PREDICATE_CODES): Likewise. + +Sat Dec 26 23:26:26 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sat Dec 26 09:17:04 1998 Jeffrey A Law (law@cygnus.com) + + * gengenrtl.c (gencode): Always use bzero to clear memory instead + of dangerous casts and stores. + + * Makefile.in (compare, gnucompare): Add missing else true clauses. + +Fri Dec 25 23:00:56 1998 Jeffrey A Law (law@cygnus.com) + + * alpha.md (builtin_longjmp): Add missing "DONE". + +Thu Dec 24 10:39:57 1998 Stan Cox + + * gcc.c (execute): Enable -pipe with win32. + +Wed Dec 23 10:27:44 1998 Nick Clifton + + * config/arm/t-arm-elf: Add multiplib option for leading + underscores. + + * config/arm/thumb.h (ASM_OUTPUT_LABELREF): Use variable + 'user_label_prefix' rather than macro USER_LABEL_PREFIX. + + (thumb_shiftable_const): Use macro 'BASE_REG_CLASS' rather + than variable 'reload_address_base_reg_class'. [Note this + change is unrelated to the others in this patch]. + + * config/arm/unknown-elf.h (USER_LABEL_PREFIX): Default to no + leading underscore. + +Wed Dec 23 09:51:32 1998 Kaveh R. Ghazi + + * alias.c (record_alias_subset): Remove ignored `&'. + (init_alias_once): Likewise. + + * c-lex.c (UNGETC): Cast first argument of comma expression to void. + + * config/mips/mips.c (mips_asm_file_end): Cast the result of + fwrite to `int' when comparing against one. + + * config/mips/mips.h (CAN_ELIMINATE): Add parens around && within ||. + (INITIAL_ELIMINATION_OFFSET): Add braces to avoid ambiguous `else'. + + * cse.c (rehash_using_reg): Change type of variable `i' to + unsigned int. + + * dwarf2out.c (initial_return_save): Cast -1 to unsigned before + assigning it to one. + + * except.c (duplicate_eh_handlers): Remove unused variable `tmp'. + + * final.c (final_scan_insn): Likewise for variable `i'. + (output_asm_insn): Cast a char to unsigned char when used as an + array index. + + * gcse.c (compute_pre_ppinout): Cast -1 to SBITMAP_ELT_TYPE when + assigning it to one. + + * loop.c (strength_reduce): Remove unused variables `count' and `temp'. + + * recog.c (preprocess_constraints): Cast a char to unsigned char + when used as an array index. + + * regmove.c (find_matches): Likewise. + + * reload1.c (calculate_needs): Add default case in switch. + (eliminate_regs_in_insn): Initialize variable `offset'. + (set_offsets_for_label): Change type of variable `i' to unsigned. + (reload_as_needed): Wrap variable `i' in macro check on + AUTO_INC_DEC || INSN_CLOBBERS_REGNO_P. + + * scan-decls.c (scan_decls): Mark parameters `argc' and `argv' + with ATTRIBUTE_UNUSED. Cast variable `start_written' to size_t + when comparing against one. + + * stor-layout.c (layout_decl): Cast maximum_field_alignment to + unsigned when comparing against one. Likewise for + GET_MODE_ALIGNMENT(). + (layout_record): Cast record_align to int when comparing against a + signed value. + (layout_type): Cast TYPE_ALIGN() to int when comparing against a + signed value. + + * tree.c (get_identifier): Cast variable `len' to unsigned when + comparing against one. + (maybe_get_identifier): Likewise + +Wed Dec 23 00:10:01 1998 Jeffrey A Law (law@cygnus.com) + + * toplev.c (rest_of_compilation): Do not set reload_completed. + * reload1.c (reload): Set reload_completed before calling + cleanup_subreg_operands. + +Tue Dec 22 23:58:31 1998 Richard Henderson + + * reload1.c (emit_reload_insns): Check `set' not null before use. + +Tue Dec 22 15:15:45 1998 Nick Clifton + + * rtlanal.c (multiple_sets): Change type of 'found' from 'rtx' to + 'int'. + +Tue Dec 22 13:55:44 1998 Theodore Papadopoulo + + * halfpic.c (half_pic_encode): Delete redundant code. + +Tue Dec 22 13:02:22 1998 Michael Meissner + + * toplev.c (main): Delete handling of -dM as a preprocessor + option. + +Mon Dec 21 17:39:38 1998 Michael Meissner + + * toplev.c (main): Don't emit any warnings when using -dD, -dM, or + -dI, which are handled by the preprocessor. + +Sun Dec 20 16:13:44 1998 John F. Carr + + * configure.in: Handle Digital UNIX 5.x the same as 4.x. + * i386/sol2.h: Define LOCAL_LABEL_PREFIX as ".". + +Sun Dec 20 07:39:52 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sat Dec 19 22:24:22 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sat Dec 19 21:41:32 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sat Dec 19 09:52:27 1998 Kaveh R. Ghazi + + * genattr.c (fatal): Qualify a char* with the `const' keyword. + + * genattrtab.c (fatal, attr_printf, attr_string, write_attr_set, + write_unit_name, write_eligible_delay, expand_units, + make_length_attrs, write_attr_case, find_attr, + make_internal_attr): Likewise. + * gencheck.c (tree_codes): Likewise. + * gencodes.c (fatal): Likewise. + * genconfig.c (fatal): Likewise. + * genemit.c (fatal): Likewise. + * genextract.c (fatal, walk_rtx, copystr): Likewise. + * genflags.c (fatal): Likewise. + * genopinit.c (fatal, optabs, gen_insn): Likewise. + * genoutput.c (fatal, error, predicates): Likewise. + * genpeep.c (fatal): Likewise. + * genrecog.c (fatal, decision, pred_table, add_to_sequence, + write_tree_1, write_tree, change_state, copystr, indents): Likewise. + +Thu Dec 17 18:21:49 1998 Rainer Orth + + * configure.in (with-fast-fixincludes): Fix whitespace. + * configure: Rebuilt. + + * fixincludes (c_asm.h): Wrap Digital UNIX V4.0B DEC C specific + asm() etc. function declarations in __DECC. + +Thu Dec 17 13:57:23 1998 Nick Clifton + + * expr.c (emit_move_insn_1): Only emit a clobber if the target + is a pseudo register. + +Thu Dec 17 13:50:29 1998 Nick Clifton + + * gcse.c: Include expr.h in order to get the prototype for + get_condition() which is used in delete_null_pointer_checks(). + +Thu Dec 17 15:58:26 1998 Kaveh R. Ghazi + + * hwint.h: New file to consolidate HOST_WIDE_INT (etc) macros. + +Thu Dec 17 12:31:12 1998 Jim Wilson + + * Makefile.in (INTERNAL_CFLAGS): Add SCHED_CFLAGS. + (ALL_CFLAGS): Delete SCHED_CFLAGS. + +1998-12-17 Vladimir N. Makarov + + * config/i60/i960.md (extendqihi2): Fix typo (usage ',' instead of + ';'). + +1998-12-17 Michael Tiemann + + * i960.md (extend*, zero_extend*): Don't generate rtl that looks + like (subreg:SI (reg:SI N) 0), because it's wrong, and it hides + optimizations from the combiner. + +Thu Dec 17 08:27:03 1998 J"orn Rennecke + + * loop.c (combine_givs_used_by_other): Don't depend on n_times_set. + +Wed Dec 16 17:30:35 1998 Nick Clifton + + * toplev.c (main): Disable optimize_size if a specific + optimization level is requested. Always set optimization + level to 2 if -Os is specified. + +Wed Dec 16 16:33:04 1998 Dave Brolley + + * objc/lang-specs.h: Pass -MD, -MMD and -MG to cc1obj if configured with + cpplib. + * cpplib.c (cpp_start_read): If in_fname is not initialized, try to + initialize it using fname. + +1998-12-16 Zack Weinberg + + * cpplib.c (do_include): Treat #include_next in the + primary source file as #include plus warning. Treat + #include_next in a file included by absolute path as an + error. fp == CPP_NULL_BUFFER is a fatal inconsistency. + +Wed Dec 16 12:28:54 1998 Kaveh R. Ghazi + + * cccp.c: Don't define MIN/MAX anymore. + * cpplib.c: Likewise. + * machmode.h: Likewise. + * system.h: Provide definitions for MIN/MAX. + +Tue Dec 15 23:47:42 1998 Zack Weinberg + + * fix-header.c: Don't define xstrdup here. + +Wed Dec 16 05:11:04 1998 J"orn Rennecke + + * loop.c (consec_sets_giv): New argument last_consec_insn. + (strength_reduce): Provide / use it. + +Wed Dec 16 17:24:07 1998 Michael Hayes + + * loop.h (loop_info): New field 'vtop'. + * loop.c (check_dbra_loop): Use loop_info->vtop rather than + scanning loop for vtop. + * unroll.c (subtract_reg_term, find_common_reg_term): New functions. + (loop_iterations): Use them to determine if loop has a constant + number of iterations. Set loop_info->vtop. Don't subtract + common reg term from initial_value and final_value if have a + do-while loop. + +Tue Dec 15 13:49:55 1998 Jeffrey A Law (law@cygnus.com) + + * mn10200.md (addsi3 expander): Use "nonmemory_operand" for operand 2. + + * mn10300.md (bset, bclr): Operand 0 is a read/write operand. + + * mn10200.md (abssf2, negsf2): New expanders. + + * mn10300.md (absdf2, abssf2, negdf2, negsf2): New expanders. + +Tue Dec 15 11:55:30 1998 Nick Clifton + + * integrate.c (copy_rtx_and_substitute): If a SUBREG is + replaced by a CONCAT whoes components do not have the same + mode as the original SUBREG, use a new SUBREG to restore the + mode. + + * emit-rtl.c (subreg_realpart_p): Cope with subregs containing + multiword complex values. + +1998-12-15 Zack Weinberg + + * cppalloc.c: Add xstrdup here. + * cpplib.h: Remove savestring prototype. + * cpplib.c: Remove savestring function. s/savestring/xstrdup/ + throughout. + * cppfiles.c: s/savestring/xstrdup/ throughout. + +1998-12-15 Zack Weinberg + + * cpplib.c: Make all directive handlers read their own + arguments. + (struct directive): Remove last two arguments from FUNC + member prototype. Remove `command_reads_line' member + entirely. + (directive_table): Remove initializations of + command_reads_line flag. Pretty-print. + (eval_if_expression, do_define, do_line, do_include, + do_undef, do_error, do_pragma, do_ident, do_if, do_xifdef, + do_else, do_elif, do_sccs, do_assert, do_unassert, + do_warning): Take only two args. + + (cpp_define): Call do_define with two args and the text to + define stuffed into a buffer. + (make_assertion): Call do_assert with two args. + (handle_directive): Call do_line with two args. Call + kt->func with two args. Remove command_reads_line + processing. + (do_define, do_undef, do_error, do_warning, do_pragma, + do_sccs): Read the rest of the line here. + (do_ident): Gobble rest of line, as cccp does. + (cpp_undef): New function. + (cpp_start_read): Call cpp_undef instead of do_undef. + +1998-12-15 Zack Weinberg + + * cpphash.h (union hash_value): Remove `keydef' member, add a + `struct hashnode *aschain' member for #assert. + + * cpplib.c (struct tokenlist_list, struct + assertion_hashnode): Delete structure definitions. + (assertion_install, assertion_lookup, delete_assertion, + check_assertion, compare_token_lists, reverse_token_list, + read_token_list, free_token_list): Delete functions. + (parse_assertion): New function. + (cpp_cleanup): Don't destroy the assertion_hashtable. + + (do_assert): Gut and rewrite. #assert foo (bar) places + entries for `#foo' and `#foo(bar)' in the macro hash table, + type T_ASSERT. The value union's `aschain' member is used + to chain all answers for a given predicate together. + (do_unassert): Also rewritten. Take an un-asserted + answer off the chain from its predicate and call + delete_macro on the hashnode, or walk a predicate chain + calling delete_macro on all the entries. + (cpp_read_check_assertion): Simply call parse_assertion to + get the canonical assertion name, and look that up in the + hash table. + + * cpplib.h (ASSERTION_HASHNODE,ASSERTION_HASHSIZE,assertion_hashtab): + Removed. + + * cpphash.c (install): Use bcopy instead of an explicit loop + to copy the macro name. + + * cppexp.c (cpp_lex): Convert the result of + cpp_read_check_assertion to a `struct operation' directly; + don't go through parse_number. + +Tue Dec 15 18:27:39 1998 J"orn Rennecke + + * loop.h (struct induction): Delete times_used member. + * loop.c (n_times_set): Rename to set_in_loop. Changed all users. + (n_times_used): Rename to n_times_set. Changed all users. + (scan_loop): Free reg_single_usage before strength reduction. + (record_giv, combine_givs): Remove handling of times_used member. + (combine_givs_used_once): Rename to: + (combine_givs_used_by_other) . Changed all callers. + +Tue Dec 15 01:45:26 1998 Jason Merrill + + * dwarf2out.c (gen_struct_or_union_type_die): Check AGGREGATE_TYPE_P + instead of TREE_CODE_CLASS == 't'. + (gen_type_die): Likewise. + (scope_die_for): Ignore FUNCTION_TYPE "scopes". + +Mon Dec 14 16:23:27 1998 Jim Wilson + + * real.c (endian): Disable last change unless + HOST_BITS_PER_WIDE_INT is greater than 32. + +Mon Dec 14 17:13:36 EST 1998 Andrew MacLeod + + * output.h (force_data_section): New prototype. + * varasm.c (force_data_section): New function to force the + data section, regardless of what in_section thinks. + * dwarf2out.c (output_call_frame_info): Call force_data_section + since varasm may not realize we've changes sections. + +Mon Dec 14 14:09:34 1998 Nick Clifton + + * reload1.c (reload): Delete REG_RETVAL and REG_LIBCALL notes + after completeing reload. + + * rtl.texi: Document that REG_RETVAL and REG_LIBCALL are + deleted after reload. + +Mon Dec 14 01:39:28 1998 Jeffrey A Law (law@cygnus.com) + + * rtl.h (multiple_sets): Fix prototype. + * rtlanal.c (multiple_sets): Fix return type. + +Sun Dec 13 12:43:58 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sun Dec 13 01:05:22 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +1998-12-13 Manfred Hollstein + + * protoize.c (fputs): Wrap extern declaration in #ifndef fputs. + +Sun Dec 13 00:24:14 1998 J"orn Rennecke + + * rtl.h (recompute_reg_usage): Add second argument. + * flow.c (recompute_reg_usage): Likewise. + * toplev.c (rest_of_compilation): Supply second argument to + recompute_reg_usage. + + * reload1.c (compute_use_by_pseudos): Allow reg_renumber[regno] < 0 + after reload. + +Sat Dec 12 23:39:10 1998 Jeffrey A Law (law@cygnus.com) + + * m68k/t-m68kelf (MULTILIB_OPTIONS): Add mcpu32. + (MULTILIB_MATCHES): -m68332 now uses mcpu32 libraries, not m68000. + (MULTILIB_EXCEPTIONS): Don't build 68881 libraries for m68000, + mcpu32 or m5200. + + * i386/next.h (ASM_OUTPUT_ALIGN): Use 0x90 for fill character. + + * rtlanal.c (multiple_sets): New function. + * rtl.h (multiple_sets): Declare it. + * local-alloc.c (wipe_dead_reg): Use it. + * global.c (global_conflicts): Likewise. + +Sat Dec 12 22:13:02 1998 Mark Mitchell + + * global.c (record_conflicts): Don't use an array of shorts to + store an array of ints. + (global_conflicts): Likewise. + +Sat Dec 12 16:49:24 1998 Richard Henderson + + * alpha.c (alpha_expand_block_move): mode_for_size expects + bits, not bytes. Infer extra alignment from addressof. + +1998-12-11 Michael Meissner + + * rs6000/sysv4.h (ASM_OUTPUT_ALIGNED_LOCAL): Put small data in the + .sbss section, not .sdata. + +1998-12-11 Manfred Hollstein + + * cccp.c: Do not #include here; this is already done + by "system.h". + * collect2.c: Likewise. + * cpplib.h: Likewise. + * gcc.c: Likewise. + * gcov.c: Likewise. + * getpwd.c: Likewise. + * protoize.c: Likewise. + * toplev.c: Likewise. + + * cpplib.h (HOST_WIDE_INT): Get definition from "machmode.h" + and don't try to define it here. + * Makefile.in (cppmain.o): Depend on machmode.h. + (cpplib.o): Likewise. + (cpperror.o): Likewise. + (cppexp.o): Likewise. + (cppfiles.o): Likewise. + (cpphash.o): Likewise. + (cppalloc.o): Likewise. + (fix-header.o): Likewise. + (scan-decls.o): Likewise. + +Fri Dec 11 11:02:49 1998 Stan Cox + + * sh.c (print_operand): lookup interrupt_handler attribute instead + of relying on static variable. + * (calc_live_regs): Likewise. + * (sh_pragma_insert_attributes): Create interrupt_handler + attribute if a pragma was specified + * (sh_valid_machine_decl_attribute): Don't set static flag. + * sh.h (PRAGMA_INSERT_ATTRIBUTES): New. + +Fri Dec 11 12:56:07 1998 J"orn Rennecke + + * reload1.c (reload_combine): Use BASIC_BLOCK_LIVE_AT_START + to determine if a register is live at a jump destination. + Everything is dead at a BARRIER. + +Thu Dec 10 16:02:06 1998 Jim Wilson + + * cse.c (simplify_unary_operation): Sign-extend constants when + they have the most significant bit set for the target. + * real.c (endian): Sign-extend 32 bit output values on a 64 bit + host. + * m32r/m32r.c (m32r_expand_prologue): Store pretend_size in + HOST_WIDE_INT temporary before negating it. + * m32r/m32r.md (movsi_insn+1): Use ~0xffff instead of 0xffff0000. + +Thu Dec 10 15:05:59 1998 Dave Brolley + + * objc/objc-act.c (lang_init_options): Enclose cpplib related code in + #if USE_CPPLIB. + +Thu Dec 10 13:39:46 1998 Kaveh R. Ghazi + + * collect2.h: New header file for prototypes. + + * Makefile.in (collect2.o, tlink.o): Depend on collect2.h. + +Wed Dec 9 17:40:26 1998 Dave Brolley + + * collect2.c: Include collect2.h. + * tlink.c: Likewise. + +Wed Dec 9 23:55:11 1998 Jeffrey A Law (law@cygnus.com) + + * flow.c: Update some comments. + +Wed Dec 9 15:29:26 1998 Dave Brolley + + * objc/objc-act.c (cpp_initialized): Removed. + (lang_init_options): Initialize cpplib. + (lang_decode_option): Move initialization of cpplib to + lang_init_options. + * c-lang.c: (parse_options,parse_in): Added. + (lang_init_options): Initialized cpplib here. + * c-decl.c (parse_options,cpp_initialized): Removed. + (c_decode_option): Move initialization of cpplib to + lang_init_options. + +Wed Dec 9 19:36:57 1998 J"orn Rennecke + + * reload1.c (reload_combine, reload_combine_note_store): + Make STORE_RUID always valid. + (reload_combine): Check if BASE is clobbered too early. + +Wed Dec 9 09:53:58 1998 Nick Clifton + + * reload.c (find_reloads): Display the insn that cannot be + reloaded. + +Wed Dec 9 12:15:26 1998 Dave Brolley + + * cccp.c (create_definition): Fix end of bufer logic. + +Wed Dec 9 10:15:45 1998 Kaveh R. Ghazi + + * except.c (duplicate_eh_handlers, rethrow_symbol_map): Function + pointer parameters changed to use the PARAMS() macro. + +Wed Dec 9 09:12:40 EST 1998 Andrew MacLeod + + * except.h (struct handler_info): Add handler_number field. + * except.c (gen_exception_label): EH labels no longer need to be + on the permanent obstack. + (get_new_handler): Set the label number field. + (output_exception_table_entry): Regenerate handler label reference + from the label number field. + (init_eh): Remove a blank line. + * integrate.c (get_label_from_map): Labels no longer need to be + on the permanent obstack. + +Tue Dec 8 22:04:33 1998 Jim Wilson + + * i960/i960.h (CONST_COSTS, case CONST_INT): Accept power2_operand + only when OUTER_CODE is SET. + +Tue Dec 8 22:47:15 1998 J"orn Rennecke + + * loop.c (strength_reduce): If scan_start points to the loop exit + test, be wary of subversive use of gotos inside expression statements. + Don't set maybe_multiple for a backward jump that does not + include the label under consideration into its range. + * unroll.c (biv_total_increment): Make use of maybe_multiple field. + +Tue Dec 8 22:33:18 1998 J"orn Rennecke + + * explow.c (plus_constant_wide): Don't immediately return with + result of recursive call. + +Tue Dec 8 15:32:56 EST 1998 Andrew MacLeod + + * eh-common.h (struct eh_context): Add table_index for rethrows. + + * rtl.h (enum reg_note): Add REG_EH_REGION and REG_EH_RETHROW reg notes. + (SYMBOL_REF_NEED_ADJUST): New flag indicating symbol needs to be + processed when inlined or unrolled (ie duplicated in some way). + + * rtl.c (reg_note_name): Add strings for new reg_note enums. + + * expr.h (rethrow_libfunc): New library decl. + + * optabs.c (rethrow_libfunc): Initialize. + + * except.h (struct eh_entry): Add new field 'rethrow_label'. + (new_eh_region_entry): No longer exported from except.c. + (duplicate_handlers): Renamed to duplicate_eh_handlers and + different prototype. + (rethrow_symbol_map, rethrow_used): New exported functions. + (eh_region_from_symbol): New exported function. + + * except.c (create_rethrow_ref): New function to create a single + SYMBOL_REF for a rethrow region. + (push_eh_entry): Initialize a rethrow ref. + (func_eh_entry): Add a rethrow_label field. + (new_eh_region_entry): Make static, and initialize the rethrow entry. + (duplicate_eh_handlers): Create a new region, and remap labels/symbols. + (eh_region_from_symbol): Find an EH region based on its rethrow symbol. + (rethrow_symbol_map): Given a label map, maps a rethrow symbol for + a region into an appropriate new symbol. + (rethrow_used): Indicate whether a rethrow symbol has been referenced. + (expand_eh_region_end): Don't issue jump around code for new-exceptions. + (end_catch_handler): Emit a barrier for new-exceptions since + control can never drop through the end of a catch block. + (expand_end_all_catch): new-exceptions never fall through a catch + block. + (expand_rethrow): use __rethrow routine for new exceptions. + (output_exception_table_entry): Generate rethrow labels, if needed. + (output_exception_table): Generate start and end rethrow labels. + (init_eh): Create rethrow symbols for beginning and end of table. + (scan_region): Don't eliminate EH regions which are the targets of + rethrows. + + * flow.c (make_edges): Add different edges for rethrow calls, + identified by having the REG_EH_RETHROW reg label. + (delete_unreachable_blocks): Don't delete regions markers which are + the target of a rethrow. + + * integrate.c (save_for_inline_eh_labelmap): New callback routine to + allow save_for_inline_copying to call duplicate_eh_handlers. + (save_for_inline_copying): Call duplicate_eh_handlers instead of + exposing internal details of exception regions. + (copy_for_inline): Check if SYMBOL_REFs need adjustment. + (expand_inline_function_eh_labelmap): New callback routine to + allow expand_inline_function to call duplicate_eh_handlers. + (expand_inline_function): Call duplicate_eh_handlers instead of + exposing internal details of exception regions. + (copy_rtx_and_substitute): Adjust SYMBOL_REFS if SYMBOL_REF_NEED_ADJUST + flag is set. + + * libgcc2.c (find_exception_handler): Generalize to enable it to + pick up processing where it left off last time for a rethrow. + (__unwinding_cleanup): New function. debug hook which is called before + unwinding when __throw finds there is nothing but cleanups left. + (throw_helper): Common parts of __throw extracted out for reuse. + (__throw): Common parts moved to throw_helper. + (__rethrow): New function for performing rethrows. + +Tue Dec 8 13:11:04 1998 Jeffrey A Law (law@cygnus.com) + + * reload1.c (current_function_decl): Tweak declaration. + +Tue Dec 8 10:23:52 1998 Richard Henderson + + * c-decl.c (flag_isoc9x): Default off. + (c_decode_option): Kill -std=gnu, add -std=gnu89 and -std=gnu9x. + * cccp.c (print_help, main): Likewise. + * gcc.c (default_compilers): Update for -std=gnu*. + +Tue Dec 8 01:14:46 1998 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (DEMANGLE_H): Change location to shared demangle.h. + * demangle.h: Deleted. + + * reload1.c (current_function_decl): Declare. + +Tue Dec 8 11:58:51 1998 Kaveh R. Ghazi + + * cpplib.c (convert_string): Use `0x00ff', not `0x00ffU'. + +Tue Dec 8 09:28:36 1998 Kaveh R. Ghazi + + * dbxout.c: If USG is defined use gstab.h, even if HAVE_STAB_H is set. + +1998-12-08 Ulrich Drepper + + * configure.in: Test for availability of putc_unlocked, fputc_unlocked, + and fputs_unlocked. + * configure: Rebuilt. + * system.h: If the *_unlocked functions are available use them + instead of the locked counterparts by defining macros. + * config.in: Regenerated. + +Tue Dec 8 00:34:05 1998 Mike Stump + + * i386/bsd.h (ASM_FILE_START): Don't use dump_base_name, it is + wrong and should only be used for dump related things, not + debugging information, instead main_input_filename should be used. + Also, reuse output_file_directive if possible. + * i386/aix386ng.h (ASM_FILE_START): Likewise. + * i386/isc.h (ASM_FILE_START): Likewise. + * i386/win-nt.h (ASM_FILE_START): Likewise. + * i386/sun386.h (ASM_FILE_START): Likewise. + +Mon Dec 7 23:56:28 1998 Robert Lipe + + * configure.in (mips*-*-linux*): Handle big and little endian + systems. + * configure: Rebuilt. + +Mon Dec 7 23:14:51 1998 Mike Stump + + * emit-rtl.c: Fix typo. + +Mon Dec 7 23:07:38 1998 Nathan Sidwell + + * reload1.c (eliminate_regs): Don't do anything, if we're not + generating code. + +Mon Dec 7 15:27:09 1998 DJ Delorie + + * mips/mips.h (ENCODE_SECTION_INFO): Handle TARGET_EMBEDDED_DATA. + Add comment. + * mips/mips.c (mips_select_section): Add comment. + +Mon Dec 7 17:55:06 1998 Mike Stump + + * cccp.c (ignore_escape_flag): Add support for \ as `natural' + characters in file names in #line to be consistent with #include + handling. We support escape prcessing in the # 1 "..." version of + the command. See also support in cp/lex.c. + (handle_directive): Likewise. + (do_line): Likewise. + +1998-12-07 Zack Weinberg + + * cpplib.c (initialize_char_syntax): Use ISALPHA and ISALNUM + so it'll work on non-ASCII platforms. Always consider $ an + identifier character. Take no arguments. + (cpp_reader_init): Call initialize_char_syntax with no + arguments. + (cpp_start_read): Don't call initialize_char_syntax again. + Clear is_idchar['$'] and is_idstart['$'] if not + opts->dollars_in_ident. + + * cpplib.h (struct cpp_reader): Replace void *data element by + cpp_options *opts. Rearrange elements to make gdb printout + less annoying (put buffer stack at end). + (CPP_OPTIONS): Get rid of now-unnecessary cast. + + * cppmain.c: s/data/opts/ when initializing cpp_reader + structure. + * c-decl.c: Likewise. + * objc/objc-act.c: Likewise. + * fix-header.c: Likewise. + +1998-12-07 Zack Weinberg + + * cpplib.h (struct cpp_buffer): Replace dir and dlen members + with a struct file_name_list pointer. + (struct cpp_reader): Add pointer to chain of `actual + directory' include searchpath entries. + (struct file_name_list): Add *alloc pointer for the sake of + the actual-directory chain. + + Move definition of HOST_WIDE_INT here. + (cpp_parse_escape): Change prototype to match changes in + cppexp.c. + + * cppfiles.c (actual_directory): New function. + (finclude): Use it to initialize the buffer's actual_dir + entry. + (find_include_file): We don't need to fix up max_include_len + here. + + * cpplib.c (do_include): Don't allocate a file_name_list on + the fly for current directory "" includes, use the one that's + been preallocated in pfile->buffer->actual_dir. Hoist out + duplicate code from the search_start selection logic. + (cpp_reader_init): Initialize pfile->actual_dirs. + + Remove definition of HOST_WIDE_INT. Change calls + to cpp_parse_escape to match changes in cppexp.c (note + hardcoded MASK, which is safe since this is the source + character set). + + * cppexp.c: Bring over changes to cpp_parse_escape from cccp.c + to handle wide character constants in #if directives. The + function now returns a HOST_WIDE_INT, and takes a third + argument which is a binary mask for all legal values (0x00ff + for 8-bit `char', 0xffff for 16-bit `wchar_t', etc.) Define + MAX_CHAR_TYPE_MASK and MAX_WCHAR_TYPE_MASK. Change callers of + cpp_parse_escape to match. [Fixes c-torture/execute/widechar-1.c] + +Mon Dec 7 15:38:25 1998 Dave Brolley + + * gcc.c (default_compilers): Fix typo in USE_CPPLIB spec for cc1. + +Mon Dec 7 15:38:25 1998 Kaveh R. Ghazi + + * c-aux-info.c (concat): Wrap function definition in !USE_CPPLIB. + * cppalloc.c: Move function `xcalloc' from cpplib.c to here. + * cpplib.c: Move function `xcalloc' from here to cppalloc.c. + +Mon Dec 7 11:30:49 1998 Nick Clifton + + * final.c (output_asm_name): Use tabs to seperate comments from + assembly text. + + Include instruction lengths (if defined) in output. + +Mon Dec 7 10:53:38 1998 Michael Hayes + + * loop.c (check_dbra_loop): Fix initial_value and initial_equiv_value + in the loop_info structure. + +Mon Dec 7 11:04:40 1998 Catherine Moore + + * configure.in: (arm*-*-ecos-elf): New target. + * configure: Regenerated. + * config/arm/elf.h (ASM_WEAKEN_LABEL): Define. + * config/arm/ecos-elf.h: New file. + * config/arm/unknown-elf.h (TARGET_VERSION): Check + for redefinition. + +Mon Dec 7 16:15:51 1998 J"orn Rennecke + + * sh.c (output_far_jump): Emit braf only for TARGET_SH2. + +Sun Dec 6 04:19:45 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sun Dec 6 05:16:16 1998 Michael Hayes + + * loop.c (check_dbra_loop): New argument loop_info. Update fields + as needed. + +Sun Dec 6 03:40:13 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sun Dec 6 07:49:29 1998 Alexandre Oliva + + * gcc.texi (Bug Reporting): 40Kb is a soft limit, larger + compressed reports are ok and preferred over URLs + +Sun Dec 6 07:45:33 1998 Alexandre Oliva + + * invoke.texi (Warning Options): Soften the tone of -pedantic + +Sun Dec 6 00:20:44 1998 H.J. Lu (hjl@gnu.org) + + * print-rtl.c (print_rtx): Add prototype. + + * unroll.c (iteration_info): Make it static. + +Sun Dec 6 01:19:46 1998 Richard Henderson + + * alias.c (memrefs_conflict_p): A second ANDed address + disables the aligned address optimization. + +Sat Dec 5 18:48:25 1998 Richard Henderson + + * alpha.c (alpha_emit_set_const_1): Fix parenthesis error + in -c << n case. + +Sat Dec 5 15:14:52 1998 Jason Merrill + + * i960.h (BOOL_TYPE_SIZE): Define. + +Sun Dec 6 00:28:16 1998 Michael Hayes + + * config/c4x/c4x.c (valid_parallel_load_store): Flog functionality + from old valid_parallel_operands_4. + (valid_parallel_operands_4): Check that operands for 4 operand + parallel insns are valid, excluding load/store insns. + * config/c4x/c4x.h (valid_parallel_load_store): Add prototype. + * config/c4x/c4x.md (*movqf_parallel, *movqi_parallel): Use + valid_parallel_load_store instead of valid_parallel_operands_4. + (*absqf2_movqf_clobber, *floatqiqf2_movqf_clobber, + *negqf2_movqf_clobber, *absqi2_movqi_clobber, + *fixqfqi2_movqi_clobber, *negqi2_movqi_clobber, + *notqi_movqi_clobber): Use valid_parallel_operands_4. + (*subqf3_movqf_clobber, *ashlqi3_movqi_clobber, + *ashrqi3_movqi_clobber, *lshrqi3_movqi_clobber, + *subqi3_movqi_clobber): Use valid_parallel_operands_5. + +Sat Dec 5 23:52:01 1998 Michael Hayes + + * config/c4x/c4x.c (iteration_info): Delete extern. + +Fri Dec 4 20:15:57 1998 Bernd Schmidt + + * tm.texi (SMALL_REGISTER_CLASSES): Make description match reality. + + * final.c (cleanup_subreg_operands): Delete some unused code. + + * recog.h (MAX_RECOG_ALTERNATIVES): New macro. + (struct insn_alternative): New structure definition. + (recog_op_alt): Declare variable. + (preprocess_constraints): Declare function. + * recog.c (recog_op_alt): New variable. + (extract_insn): Verify number of alternatives is in range. + (preprocess_constraints): New function. + * reg-stack.c: Include recog.h. + (constrain_asm_operands): Delete. + (get_asm_operand_lengths): Delete. + (get_asm_operand_n_inputs): New function. + (record_asm_reg_life): Delete OPERANDS, CONSTRAINTS, N_INPUTS and + N_OUTPUTS args. All callers changed. + Compute number of inputs and outputs here by calling + get_asm_operand_n_inputs. + Instead of constrain_asm_operands, call extract_insn, + constrain_operands and preprocess_constaints. Use information + computed by these functions throughout. + (record_reg_life): Delete code that is unused due to changes in + record_asm_reg_life. + (subst_asm_stack_regs): Delete OPERANDS, OPERAND_LOC, CONSTRAINTS, + N_INPUTS and N_OUTPUTS args. All callers changed. + Similar changes as in record_asm_reg_life. + (subst_stack_regs): Move n_operands declaration into the if statement + where it's used. + Delete code that is unused due to changes in subst_asm_stack_regs. + * stmt.c (expand_asm_operands): Verify number of alternatives is in + range. + * Makefile.in (reg-stack.o): Depend on recog.h. + +Fri Dec 4 02:23:24 1998 Jeffrey A Law (law@cygnus.com) + + * except.c (set_exception_version_code): Argument is an "int". + +Fri Dec 4 01:29:28 1998 Jeffrey A Law (law@cygnus.com) + + * configure.in (hppa2*-*-*): Handle like hppa1.1-*-* for now. + * configure: Rebuilt. + +Fri Dec 4 01:29:28 1998 Robert Lipe + + * configure.in (mipsel-*-linux*): New target. + * mips/linux.h: New file, based on other Linux targets. + +Thu Dec 3 11:19:50 1998 Mike Stump + + * gthr-vxworks.h (__ehdtor): Fix memory leak. The delete hook + runs in the context of the deleter, not the deletee, so we must + use taskVarGet to find the correct memory to free. + (__gthread_key_create): Initialize the task + variable subsystem so that the task variable is still active when + the delete hook is run. + +1998-12-03 Joseph S. Myers + + * pdp11.h: Use optimize_size for space optimizations. + * pdp11.c: Likewise. + * pdp11.md: Likewise. + + * pdp11.h (TARGET_40_PLUS): Fix typo. + +Thu Dec 3 11:48:32 1998 Jeffrey A Law (law@cygnus.com) + + * local-alloc.c (block_alloc): Slightly retune heuristic to widen + qty lifetimes. + +Thu Dec 3 22:30:18 1998 Michael Hayes + + * alias.c (addr_side_effect_eval): New function. + (memrefs_conflict_p): Use it. + * rtl.h (addr_side_effect_eval): Prototype it. + +1998-12-02 Joseph S. Myers + + * pdp11.md (extendsfdf2): Fix mode mismatch in SET. + +Wed Dec 2 11:23:07 1998 Jim Wilson + + * reload.c (find_reloads): When force const to memory, put result + in substed_operand not *recog_operand_loc. + +1998-12-02 Ulrich Drepper + + * c-lex.c: Fix indentation from last patch. + Remove trailing whitespace. + * real.c: Likewise. + +Wed Dec 2 10:11:12 1998 Jeffrey A Law (law@cygnus.com) + + * flow.c (delete_block): Call set_last_insn after we have reset + NEXT_INSN (kept_tail). + +Wed Dec 2 00:47:31 1998 Jeffrey A Law (law@cygnus.com) + + * mips.md (trap_if): Use "$0" for the value zero. + +Tue Dec 1 20:49:49 1998 Ulrich Drepper + Stephen L Moshier + Richard Henderson + + * c-common.c (declare_function_name): Declare predefinied variable + `__func__'. + + * c-decl.c (flag_isoc9x): Set to 1 by default. + (c_decode_option): Handle -std= option. Remove -flang-isoc9x. + (grokdeclarator): Always emit warning about implicit int for ISO C 9x. + + * c-parse.in: Allow constructors in ISO C 9x. + Rewrite designator list handling. + Allow [*] parameters. + Don't warn about comma at end of enum definition for ISO C 9x. + + * cccp.c (c9x): New variable. + (rest_extension): New variable. + (print_help): Document new -std= option. + (main): Recognize -std= option. Set c9x appropriately. + (create_definition): Recognize ISO C 9x vararg macros. + + * gcc.c (default_compilers): Adjust specs for -std options. + (option_map): Add --std. + (display_help): Document -std. + + * toplev.c (documented_lang_options): Add -std and remove + -flang-isoc9x. + + * c-lex.c (yylex): Recognize hex FP constants and call REAL_VALUE_ATOF + or REAL_VALUE_HTOF based on base of the constants. + * fold-const.c (real_hex_to_f): New function. Replacement function + for hex FP conversion if REAL_ARITHMETIC is not defined. + * real.c (asctoeg): Add handling of hex FP constants. + * real.h: Define REAL_VALUE_HTOF if necessary using ereal_atof or + real_hex_to_f. + +Tue Dec 1 16:45:49 1998 Stan Cox + + * mips.md (divmodsi4*, divmoddi4*, udivmodsi4*, udivmoddi4): Add + -mcheck-range-division/-mcheck-zero-division checking. Avoid as macro + expansion. Use hi/lo as destination register. + (div_trap): New. + (divsi3*, divdi3*, modsi3*, moddi3*, udivsi3*, udivdi3*, umodsi3*, + umoddi3*): Add -mcheck-range-division/-mcheck-zero-division checking. + Avoid as macro expansion. Use hi/lo as destination register. + + * mips.h (MASK_CHECK_RANGE_DIV): New. + (MASK_NO_CHECK_ZERO_DIV): New. + (ELIMINABLE_REGS): Added GP_REG_FIRST + 31. + (CAN_ELIMINATE, INITIAL_ELIMINATION_OFFSET): Allow for getting + return address for leaf functions out of r31 to support + builtin_return_address. + +Tue Dec 1 15:03:30 1998 Herman A.J. ten Brugge + + * jump.c (jump_optimize): Call regs_set_between_p with PREV_INSN(x), + NEXT_INSN(x) to check insn x. + +Tue Dec 1 15:20:44 1998 Jeffrey A Law (law@cygnus.com) + + * flow.c (delete_block): Call set_last_insn if we end up deleting the + last insn in the rtl chain. + + * reload1.c (reload): Do not set reload_completed or split insns + here. Instead... + * toplev.c (rest_of_compilation): Set reload_completed after + reload returns. Split insns after reload_cse has run. + +Tue Dec 1 11:55:04 1998 Richard Henderson + + * final.c (final_scan_insn): Abort if block_depth falls below 0. + +Tue Dec 1 10:23:16 1998 Nick Clifton + + * config/arm/t-arm-elf (LIBGCC2_CFLAGS): Define inhibit_libc. + +Tue Dec 1 10:22:18 1998 Nick Clifton + + * config/arm/unknown-elf.h (ASM_OUTPUT_DWARF2_ADDR_CONST): Remove + use of user-label_prefix. + +Tue Dec 1 17:58:26 1998 J"orn Rennecke + + * reload1.c (emit_reload_insns): Clear spill_reg_store + when doing a new non-inherited reload from the same pseudo. + + * local-alloc.c (function_invariant_p): New function. + (update_equiv_regs): Use function_invariant_p instead of CONSTANT_P + to decide if an equivalence should be recorded. + * reload1.c (num_eliminable_invariants): New static variable. + (reload): Set it. Use function_invariant_p instead of CONSTANT_P + to decide if an equivalence should be recorded. + Unshare PLUS. + (calculate_needs_all_insns): Skip insns that only set an equivalence. + Take num_eliminable_invariants into account when deciding + if register elimination should be done. + (reload_as_needed): Take num_eliminable_invariants into account + when deciding if register elimination should be done. + (eliminate_regs): Handle non-constant reg_equiv_constant. + * rtl.h (function_invariant_p): Declare. + +Mon Nov 30 02:00:08 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Mon Nov 30 00:42:59 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sun Nov 29 22:59:40 1998 Jason Merrill + + * except.c (add_new_handler): Complain about additional handlers + after one that catches everything. + +Sat Nov 28 10:56:32 1998 Jeffrey A Law (law@cygnus.com) + + * configure.in (alpha*-*-netbsd): Fix typo. + * configure: Rebuilt. + +Fri Nov 27 12:28:56 1998 Kaveh R. Ghazi + + * system.h: Include libiberty.h. + + * c-aux-info.c: Remove prototypes for concat/concat3. Change + function `concat' from fixed parameters to variable parameters, + as is done in libiberty. All callers of concat/concat3 + changed to use the new `concat' with variable args. + + * cccp.c: Remove things made redundant by libiberty.h and/or + conform to libiberty standards. + * cexp.y: Likewise. + * collect2.c: Likewise. + * config/1750a/1750a.h: Likewise. + * cppalloc.c: Likewise. + * cppexp.c: Likewise. + * cppfiles.c: Likewise. + * cpphash.c: Likewise. + * cpplib.c: Likewise. + * dyn-string.c: Likewise. + * fix-header.c: Likewise. + * gcc.c: Likewise. + * gcov.c: Likewise. + * genattr.c: Likewise. + * genattrtab.c: Likewise. + * gencheck.c: Likewise. + * gencodes.c: Likewise. + * genconfig.c: Likewise. + * genemit.c: Likewise. + * genextract.c: Likewise. + * genflags.c: Likewise. + * gengenrtl.c: Likewise. + * genopinit.c: Likewise. + * genoutput.c: Likewise. + * genpeep.c: Likewise. + * genrecog.c: Likewise. + * getpwd.c: Likewise. + * halfpic.c: Likewise. + * hash.c: Likewise. + * mips-tdump.c: Likewise. Wrap malloc/realloc/calloc prototypes + in NEED_DECLARATION_* macros. + + * mips-tfile.c: Remove things made redundant by libiberty.h and/or + conform to libiberty standards. + (fatal): Fix const-ification of variable `format' in + !ANSI_PROTOTYPES case. + + * prefix.c: Remove things made redundant by libiberty.h and/or + conform to libiberty standards. + + * print-rtl.c: Rename variable `spaces' to `xspaces' to avoid + conflicting with function `spaces' from libiberty. + + * profile.c: Remove things made redundant by libiberty.h and/or + conform to libiberty standards. + * protoize.c: Likewise. + * rtl.h: Likewise. + * scan.h: Likewise. + * tlink.c: Likewise. + * toplev.c: Likewise. + * toplev.h: Likewise. + * tree.h: Likewise. + +Thu Nov 26 08:38:06 1998 Kaveh R. Ghazi + + * cppfiles.c (simplify_pathname): Un-ANSI-fy function definition. + +Thu Nov 26 23:45:37 1998 Michael Hayes + + * README.C4X: Updated URLs. + * config/c4x/c4x.c (c4x_address_conflict): Fix typo. + (valid_parallel_operands_5): Remove unused variable. + +Thu Nov 26 23:40:03 1998 Michael Hayes + + * config/c4x/c4x.h (TARGET_DEFAULT): Fix typo. + +1998-11-26 Manfred Hollstein + + * Makefile.in (CONFIG_LANGUAGES): New macro taking all languages + which can be configured. + (LANGUAGES): Use $(CONFIG_LANGUAGES) instead of @all_languages@ + (Makefile): Pass actual LANGUAGES through the environment when + re-configuring. + (cstamp-h): Likewise. + (config.status): Likewise. + + * configure.in (enable_languages): Add new configuration parameter + "--enable-languages=lang1,lang2,...". + (${srcdir}/*/config-lang.in): Change handling to configure only + those directories, that the user might have enabled; default to + "all" existing languages. + * configure: Regenerate. + +Thu Nov 26 00:19:19 1998 Richard Henderson + + * rtlanal.c (regs_set_between_p): New function. + * rtl.h (regs_set_between_p): Prototype it. + * jump.c (jump_optimize): Use it instead of modified_between_p + in the Sep 2 change. + +Wed Nov 25 23:32:02 1998 Ian Dall + Matthias Pfaller + + * invoke.texi (Option Summary, NS32K Options): add description + of NS32K specific options. + + * ns32k.md (tstdf, cmpdf, movdf, truncdfsf2, fixdfqi2, fixdfhi2, + fixdfsi2, fixunsdfqi2, fixunsdfhi2, fixunsdfsi2, fix_truncdfqi2, + fix_truncdfhi2, fix_truncdfsi2, adddf3, subdf3, muldf3, divdf3, + negdf2, absdf2): Use l instead of f since the double class and + float class are no longer the same. + (cmpsi, truncsiqi2, truncsihi2, addsi3, subsi3, mulsi3, umulsidi3, + divsi3, modsi3, andsi3, iorsi3, xorsi3, negsi2, one_cmplsi2, + ashlsi3, ashlhi3, ashlqi3, rotlsi3, rotlhi3, rotlqi3, abssi2,...): + use "g" instead of "rmn" since LEGITIMATE_PIC_OPERAND has been + fixed. + (cmpsi, cmphi, cmpqi): use general_operand instead of + non_immediate_operand. Removes erroneous assumption that can't + compare constants. + (movsf, movsi, movhi, movqi,...): New register numbering scheme. + (movsi, addsi3): Use NS32K_DISPLACEMENT_P instead of hard coded + constants. + (movstrsi, movstrsi1, movstrsi2): completely new block move + scheme. + (...): Patterns to exploit multiply-add instructions. + (udivmodsi4, udivmodsi_internal4, udivmodhi4, + udivmoddihi4_internal, udivmodqi4, udivmoddiqi4_internal): new + patterns to exploit extended divide insns. + (udivsi3, udivhi3, udivqi3): remove since superceded by udivmodsi + etc patterns. + + * ns32k.h (FUNCTION_VALUE, LIBCALL_VALUE): Use f0 for complex + float return values as well as simple scalar floats. + (TARGET_32381, TARGET_MULT_ADD, TARGET_SWITCHES): + support new flag to denote 32381 fpu. + (OVERRIDE_OPTIONS): 32381 is a strict superset of 32081. + (CONDITIONAL_REGISTER_USAGE): disable extra 32381 registers if not + compling for 32381. + (FIRST_PSEUDO_REGISTER, FIXED_REGISTERS, CALL_USED_REGISTERS, + REGISTER_NAMES, ADDITIONAL_REGISTER_NAMES, OUTPUT_REGISTER_NAMES, + REG_ALLOC_ORDER, DBX_REGISTER_NUMBER, R0_REGNUM, F0_REGNUM, + L1_REGNUM, STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM, + LONG_FP_REGS_P, ARG_POINTER_REGNUM, reg_class, REG_CLASS_NAMES, + REG_CLASS_CONTENTS, SUBSET_P,REGNO_REG_CLASS, + REG_CLASS_FROM_LETTER, FUNCTION_PROLOGUE, FUNCTION_EPILOGUE, + REGNO_OK_FOR_INDEX_P, FP_REG_P, REG_OK_FOR_INDEX_P, + REG_OK_FOR_BASE_P, MEM_REG): new register scheme to include 32381 + fpu registers and special register classes for new 32381 + instructions dotf and polyf. + (MODES_TIEABLE_P): Allow all integer modes, notably DI and SI, to + be tieable. + (INCOMING_RETURN_ADDR_RTX, RETURN_ADDR_RTX, + INCOMING_FRAME_SP_OFFSET): New macros in case DWARF support is + required. + (SMALL_REGISTER_CLASSES): Make dependant on -mmult-add option. + (MOVE_RATIO): Set to zero because of smart movstrsi implimentation. + (REGISTER_MOVE_COST): move code to register_move_cost function for + ease of coding and debugging. + (CLASS_LIKELY_SPILLED_P): Under new register scheme class + LONG_FLOAT_REGO is likely spilled but not caught by default + definition. + (CONSTANT_ADDRESS_P, CONSTANT_ADDRESS_NO_LABEL_P): use macro + instead of hard coded numbers in range check. + (ASM_OUTPUT_LABELREF_AS_INT): delete since unused. + (...): Add prototypes for functions in ns32k.c but disable because + of problems when ns32k.h is included in machine independant files. + + * ns32k.c: include "system.h", "tree.h", "expr.h", "flags.h". + (ns32k_reg_class_contents, regcass_map, ns32k_out_reg_names, + hard_regno_mode_ok, secondary_reload_class, + print_operand, print_operand_address): new register scheme to + include 32381 fpu registers and special register classes for new + 32381 instructions dotf and polyf. + (gen_indexed_expr): Make static to keep namespace clean. + (check_reg): remove since never called. + (move_tail, expand_block_move): helper functions for "movstrsi" + block move insn. + (register_move_cost): Helper function for REGISTER_MOVE_COST macro. + Increase cost of moves which go via memory. + * netbsd.h (TARGET_DEFAULT): Set (new) 32381 fpu flag. + (CPP_PREDEFINES): nolonger predefine "unix". + + * ns32k.md (movsi, movsi, adddi3, subdi3, subsi3, subhi3, subqi3,...): + Remove erroneous %$. print_operand() can work out from the rtx is + an immediate prefix is required. + + * ns32k.h (RETURN_POPS_ARGS, VALID_MACHINE_DECL_ATTRIBUTE, + VALID_MACHINE_TYPE_ATTRIBUTE, COMP_TYPE_ATTRIBUTES, + SET_DEFAULT_TYPE_ATTRIBUTES): Support for -mrtd calling + convention. + (LEGITIMATE_PIC_OPERAND_P, SYMBOLIC_CONST): Correct handling of + pic operands. + + * ns32k.c (symbolic_reference_mentioned_p, print_operand): + Correct handling of pic operands. + (ns32k_valid_decl_attribute_p, ns32k_valid_type_attribute_p, + ns32k_comp_type_attributes, ns32k_return_pops_args): Support for + -mrtd calling convention. + +Wed Nov 25 23:42:20 1998 Tom Tromey + + * gcc.c (option_map): Recognize --output-class-directory. + +Thu Nov 26 18:26:21 1998 Michael Hayes + + * loop.h (precondition_loop_p): Added new mode argument. + * unroll.c (precondition_loop_p): Likewise. + (approx_final_value): Function deleted and subsumed + into loop_iterations. + (loop_find_equiv_value): New function. + (loop_iterations): Use loop_find_equiv_value to find increments + too large to be immediate constants. Also use it to find terms + common to initial and final iteration values that can be removed. + +Thu Nov 26 18:05:04 1998 Michael Hayes + + * loop.h (struct loop_info): Define new structure. + (precondition_loop_p): Added prototype. + (unroll_loop): Added new argument loop_info to prototype. + (final_biv_value, final_giv_value): Added new argument n_iterations + to prototype. + * loop.c (strength_reduce): Declare new structure loop_iteration_info + and new pointer loop_info. + (loop_n_iterations): Replace global variable by element in + loop_info structure. + (check_final_value): New argument n_iterations. + (insert_bct): New argument loop_info. + (loop_unroll_factor): Replace global array by element in + loop_info structure. + (loop_optimize): Remove code to allocate and initialise + loop_unroll_factor_array. + * unroll.c (precondition_loop_p): No longer static since + used by branch on count optimization. + (precondition_loop_p, unroll_loop): New argument loop_info. + (final_biv_value, final_giv_value, find_splittable_regs): New + argument n_iterations. + (loop_iteration_var, loop_initial_value, loop_increment, + loop_final_value, loop_comparison_code, loop_unroll_factor): + Replaced global variables by loop_info structure. + (loop_unroll_factor): Replace global array by element in + loop_info structure. + +Thu Nov 26 17:49:29 1998 Michael Hayes + + * loop.c (check_dbra_loop): Update JUMP_LABEL field of jump insn + when loop reversed. + + * unroll.c (precondition_loop_p): Return loop_initial_value + for initial_value instead of loop_iteration_var. + +Thu Nov 26 17:15:38 1998 Michael Hayes + + * config/c4x/c4x.md: Fix minor formatting problems. Update docs. + (*b, *b_rev, *b_noov, *b_noov_rev, *db, + decrement_and_branch_until_zero, rptb_end): Use c4x_output_cbranch + to output the instruction sequences. + (rpts): Delete. + (rptb_top): Provide alternatives to use any register or memory + for loop counter. + (rptb_end): Emit use of operands rather than assigning them + explicitly to the RS and RE registers. + +Thu Nov 26 16:37:59 1998 Michael Hayes + + * config/c4x/c4x.c (c4x_modified_between_p, c4x_mem_set_p, + c4x_mem_set_p, c4x_mem_modified_between_p, c4x_insn_moveable_p, + c4x_parallel_pack, c4x_parallel_find, c4x_update_info_reg, + c4x_update_info_regs, c4x_copy_insn_after, c4x_copy_insns_after, + c4x_merge_notes, c4x_parallel_process, + c4x_combine_parallel_independent, c4x_combine_parallel_dependent, + c4x_combine_parallel): Delete. + +Thu Nov 26 15:16:05 1998 Michael Hayes + + * config/c4x/c4x.c: (c4x_override_options): For compatibility + with old target options clear flag_branch_on_count_reg if + -mno-rptb specified and set flag_argument_alias is -mno-aliases + specified. + (c4x_output_cbranch): Handle a sequence of insns rather than a + single insn. + (c4x_rptb_insert): Do not emit a RPTB insn if the RC register + has not been allocated as the loop counter. + (c4x_address_conflict): Do not allow two volatile memory references. + (valid_parallel_operands_4, valid_parallel_operands_5, + valid_parallel_operands_6): Reject pattern if the register destination + of the first set is used as part of an address in the second set. + +Thu Nov 26 14:56:32 1998 Michael Hayes + + * config/c4x/c4x.h (TARGET_DEFAULT): Add PARALEL_MPY_FLAG. + (TARGET_SMALL_REG_CLASS): Set to 0 so that SMALL_REGISTER_CLASSES + is no longer enabled if PARALLEL_MPY_FLAG set. + (HARD_REGNO_CALL_CLOBBERED): Add parentheses to remove ambiguity. + (REG_CLASS_CONTENTS): Add braces around initializers. + (HAVE_MULTIPLE_PACK): Define. + (ASM_OUTPUT_BYTE_FLOAT): Use %lf format specifier with + REAL_VALUE_TO_DECIMAL. + (ASM_OUTPUT_SHORT_FLOAT): Use %lf format specifier with + REAL_VALUE_TO_DECIMAL. + (ar0_reg_operand): Add prototype. + (ar0_mem_operand): Likewise. + (ar1_reg_operand): Likewise. + (ar1_mem_operand): Likewise. + (ar2_reg_operand): Likewise. + (ar2_mem_operand): Likewise. + (ar3_reg_operand): Likewise. + (ar3_mem_operand): Likewise. + (ar4_reg_operand): Likewise. + (ar4_mem_operand): Likewise. + (ar5_reg_operand): Likewise. + (ar5_mem_operand): Likewise. + (ar6_reg_operand): Likewise. + (ar6_mem_operand): Likewise. + (ar7_reg_operand): Likewise. + (ar7_mem_operand): Likewise. + (ir0_reg_operand): Likewise. + (ir0_mem_operand): Likewise. + (ir1_reg_operand): Likewise. + (ir1_mem_operand): Likewise. + (group1_reg_operand): Likewise. + (group1_mem_operand): Likewise. + (ir1_reg_operand): Likewise. + (arx_reg_operand): Likewise. + (not_rc_reg): Likewise. + (not_modify_reg): Likewise. + (c4x_group1_reg_operand): Remove prototype. + (c4x_group1_mem_operand): Likewise. + (c4x_arx_reg_operand): Likewise. + +Wed Nov 25 19:02:55 1998 (Stephen L Moshier) + + * emit-rtl.c (gen_lowpart_common): Remove earlier change. + * real.c (make_nan): Make SIGN arg actually specify the sign bit. + +Thu Nov 26 14:12:05 1998 Michael Hayes + + * config/c4x/c4x.md (addqi3): Emit addqi3_noclobber pattern + during reload. + +Wed Nov 25 22:05:28 1998 J"orn Rennecke + + * config/sh/lib1funcs.asm (___udivsi3_i4): Don't switch to sz == 1 + unless FMOVD_WORKS is defined. + +Wed Nov 25 20:11:04 1998 J"orn Rennecke + + * regclass.c (init_reg_sets): Move code that calculates tables + dependent on reg_class_contents from here... + (init_reg_sets_1): To here. + +Wed Nov 25 14:54:46 1998 Zack Weinberg + + * cpplib.h: Delete struct import_file. Add ihash element to + struct cpp_buffer. Delete dont_repeat_files and + import_hash_table elements from cpp_reader; change + all_include_files to a hash table. Delete all foobar_include + / last_foobar_include elements from struct cpp_options; put + back four such: quote_include, bracket_include, + system_include, after_include. Redo struct file_name_list + completely. Add new structure type include_hash. Add + prototypes for merge_include_chains and include_hash. Change + prototypes for finclude, find_include_file, and + append_include_chain to match changes below. + + * cppfiles.c (simplify_pathname, include_hash, + remap_filename, merge_include_chains): New functions. + (add_import, lookup_import, open_include_file): Removed. + (INO_T_EQ): Define this (copied from cccp.c). + (hack_vms_include_specification): Remove all calls and #if 0 + out the definition. It was being called incorrectly and at + the wrong times. Until a VMSie can look at this, it's better + to not pretend to support it. + (append_include_chain): Change calling convention; now takes + only one directory at a time, and sets up the data structure + itself. + (redundant_include_p): Rewritten - this is now used for all + include redundancy, whether by #ifndef, #import, or #pragma + once. Looks up things in the include hash table. + (file_cleanup): Decrement pfile->system_include_depth here if + it's >0. + (find_include_file): Calling convention changed; now passes + around a struct include_hash instead of 3 separate parameters. + Guts ripped out and replaced with new include_hash mechanism. + (finclude): Calling convention changed as for + find_include_file. Error exits pulled out-of-line. Reformat. + (safe_read): Return a long, not an int. + (deps_output): Don't recurse. + + * cpplib.c (is_system_include): Deleted. + (path_include): Fix up call to append_include_chain. + (do_include): Fix up calls to find_include_file and finclude. + Clean up dependency output a bit. Shorten obnoxiously lengthy + #import warning message. Don't decrement + pfile->system_include_depth here. + (do_pragma): Understand the include_hash structure. Reformat. + (do_endif): Correct handling of control macros. Understand + the include_hash. + (cpp_start_read): Fix up calls to finclude. Call + merge_include_chains. + (cpp_handle_option): Fix up calls to append_include_chain. + Understand the four partial include chains. + (cpp_finish): Add debugging code (#if 0-ed out) for the + include_hash. + (cpp_cleanup): Free the include_hash, not the import hash and + the all_include and dont_repeat lists which no longer exist. + +Wed Nov 25 11:26:19 1998 Jeffrey A Law (law@cygnus.com) + + * toplev.c (no_new_pseudos): Define. + (rest_of_compilation): Set no_new_pseudos as needed. + * emit-rtl.c (gen_reg_rtx): Abort if we try to create a new pseudo + if no_new_pseudos is set. + * rtl.h (no_new_pseudos): Declare it. + * reload1.c (reload): Update comments. + * md.texi: Corresponding changes. + +Wed Nov 25 11:26:17 1998 Bernd Schmidt + + * reload1.c (reg_used_in_insn): Renamed from reg_used_by_pseudo. + (choose_reload_regs): Rename it here as well. When computing it, + also merge in used hardregs. + +1998-11-25 07:51 -0500 Zack Weinberg + + * gcc.c: Split out Objective-C specs to... + * objc/lang-specs.h: here. (New file.) Make the specs cpplib + aware. + + * c-lex.c (init_parse): Always initialize the filename global. + * objc/objc-act.c (lang_init): Always call check_newline at + beginning of file. + +Wed Nov 25 00:48:29 1998 Graham + + * reload1.c (reload): Remove unused variable. + (reload_reg_free_for_value_p): Add missing parameter definition. + + * jump.c (jump_optimize): Remove unused variable. + +Wed Nov 25 00:07:11 1998 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (graph.o): Depend on $(RTL_H), not rtl.h. + + * cse.c (fold_rtx): Make autoincrement addressing mode tests be + runtime selectable. + * expr.c (move_by_pieces): Similarly. + (move_by_pieces_1, clear_by_pieces, clear_by_pieces_1): Similarly. + * flow.c (find_auto_inc): Similarly. + (try_pre_increment): Similarly. + * loop.c (strength_reduce): Similarly. + * regclass.c (auto_inc_dec_reg_p): Similarly. + * regmove.c (try_auto_increment): Similarly. + (fixup_match_1): Similarly. + * rtl.h (HAVE_PRE_INCREMENT): Define if not already defined. + (HAVE_PRE_DECREMENT): Similarly. + (HAVE_POST_INCREMENT, HAVE_POST_DECREMENT): Similarly. + * Corresponding changes to all target header files. + * tm.texi: Update docs for autoinc addressing modes. + +Tue Nov 24 20:24:59 1998 Jim Wilson + + * configure.in (m68020-*-elf*, m68k-*-elf*): New targets. + * configure: Rebuild. + * config/elfos.h: New file. + * config/m68k/m68020-elf.h, config/m68k/m68kelf.h, + config/m68k/t-m68kelf: New file. + +Tue Nov 24 13:40:06 1998 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (HOST_AR): Define. + (HOST_AR_FLAGS, HOST_RANLIB, HOST_RANLIB_TEST): Similarly. + (libcpp.a): Use the host tools explicitly. + (STAGESTUFF): Add libcpp.a. + +Tue Nov 24 09:33:49 1998 Nick Clifton + + * config/m32r/m32r.md (movstrsi_internal): Describe changes made + to source and destination registers. + +Mon Nov 23 20:28:02 1998 Mike Stump + + * libgcc2.c (top_elt): Remove top_elt, it isn't thread safe. + The strategy we now use is to pre allocate the top_elt along + with the EH context so that each thread has its own top_elt. + This is necessary as the dynmanic cleanup chain is used on the + top element of the stack and each thread MUST have its own. + (eh_context_static): Likewise. + (new_eh_context): Likewise. + (__sjthrow): Likewise. + +Mon Nov 23 20:25:03 1998 Jason Merrill + + * i386/linux.h (ASM_OUTPUT_MAX_SKIP_ALIGN): Wrap in do...while. + * i386.md (prologue_get_pc): Remove unused variable. + +Mon Nov 23 17:05:40 1998 Geoffrey Noer + + * i386/xm-cygwin.h: Rename cygwin_ path funcs back to cygwin32_. + +Mon Nov 23 16:40:00 1998 Ulrich Drepper + + * Makefile.in (OBJS): Add graph.o + (graph.o): New dependency list. + * flags.h: Declare dump_for_graph and define graph_dump_types type. + * print-rtl.c (dump_for_graph): Define new variable. + (print_rtx): Rewrite to allow use in graph dumping functions. + * toplev.c: Declare print_rtl_graph_with_bb, clean_graph_dump_file, + finish_graph_dump_file. + Define graph_dump_format. + (compile_file): If graph dumping is enabled also clear these files. + Finish graph dump files. + (rest_of_compilation): Also dump graph information if enabled. + (main): Recognize -dv to enabled VCG based graph dumping. + * graph.c: New file. Graph dumping functions. + +Mon Nov 23 16:39:04 1998 Richard Henderson + + * configure.in: Look for . + * system.h: Include it before substitute S_ISREG definitions. + +Mon Nov 23 17:40:37 1998 Gavin Romig-Koch + + * config/mips/abi.h: Use ABI_O64, duplicating ABI_32 usage. + * config/mips/iris6.h: Same. + * config/mips/mips.md: Same. + * config/mips/mips.c: Same; also add "-mabi=o64" option. + * config/mips/mips.h: Same; also define ABI_O64. + +Mon Nov 23 17:02:27 1998 Kaveh R. Ghazi + + * configure.in: Use AC_PREREQ(2.12.1). + +Mon Nov 23 10:16:38 1998 "Melissa O'Neill" + + * cccp.c (S_ISREG, S_ISDIR): Delete defines. + * cpplib.c, gcc.c: Likewise. + * system.h (S_ISREG, S_ISDIR): Define if not already defined. + +Mon Nov 23 09:53:44 1998 Richard Henderson + + * local-alloc.c (local_alloc): Use malloc not alloca for + reg_qty, reg_offset, ref_next_in_qty. + +Mon Nov 23 16:46:46 1998 J"orn Rennecke + + * caller-save.c (insert_one_insn): Initialize the live_before and + live_after register sets. + + Add SH4 support: + + * config/sh/lib1funcs.asm (___movstr_i4_even, ___movstr_i4_odd): Define. + (___movstrSI12_i4, ___sdivsi3_i4, ___udivsi3_i4): Define. + * sh.c (reg_class_from_letter, regno_reg_class): Add DF_REGS. + (fp_reg_names, assembler_dialect): New variables. + (print_operand_address): Handle SUBREGs. + (print_operand): Added 'o' case. + Don't use adj_offsettable_operand on PRE_DEC / POST_INC. + Name of FP registers depends on mode. + (expand_block_move): Emit different code for SH4 hardware. + (prepare_scc_operands): Use emit_sf_insn / emit_df_insn as appropriate. + (from_compare): Likewise. + (add_constant): New argument last_value. Changed all callers. + (find_barrier): Don't try HImode load for FPUL_REG. + (machine_dependent_reorg): Likewise. + (sfunc_uses_reg): A CLOBBER cannot be the address register use. + (gen_far_branch): Emit a barrier after the new jump. + (barrier_align): Don't trust instruction lengths before + fixing up pcloads. + (machine_dependent_reorg): Add support for FIRST_XD_REG .. LAST_XD_REG. + Use auto-inc addressing for fp registers if doubles need to + be loaded in two steps. + Set sh_flag_remove_dead_before_cse. + (push): Support for TARGET_FMOVD. Use gen_push_fpul for fpul. + (pop): Support for TARGET_FMOVD. Use gen_pop_fpul for fpul. + (calc_live_regs): Support for TARGET_FMOVD. Don't save FPSCR. + Support for FIRST_XD_REG .. LAST_XD_REG. + (sh_expand_prologue): Support for FIRST_XD_REG .. LAST_XD_REG. + (sh_expand_epilogue): Likewise. + (sh_builtin_saveregs): Use DFmode moves for fp regs on SH4. + (initial_elimination_offset): Take TARGET_ALIGN_DOUBLE into account. + (arith_reg_operand): FPUL_REG is OK for SH4. + (fp_arith_reg_operand, fp_extended_operand) New functions. + (tertiary_reload_operand, fpscr_operand): Likewise. + (commutative_float_operator, noncommutative_float_operator): Likewise. + (binary_float_operator, get_fpscr_rtx, emit_sf_insn): Likewise. + (emit_df_insn, expand_sf_unop, expand_sf_binop): Likewise. + (expand_df_unop, expand_df_binop, expand_fp_branch): Likewise. + (emit_fpscr_use, mark_use, remove_dead_before_cse): Likewise. + * sh.h (CPP_SPEC): Add support for -m4, m4-single, m4-single-only. + (CONDITIONAL_REGISTER_USAGE): Likewise. + (HARD_SH4_BIT, FPU_SINGLE_BIT, SH4_BIT, FMOVD_BIT): Define. + (TARGET_CACHE32, TARGET_SUPERSCALAR, TARGET_HARWARD): Define. + (TARGET_HARD_SH4, TARGET_FPU_SINGLE, TARGET_SH4, TARGET_FMOVD): Define. + (target_flag): Add -m4, m4-single, m4-single-only, -mfmovd. + (OPTIMIZATION_OPTIONS): If optimizing, set flag_omit_frame_pointer + to -1 and sh_flag_remove_dead_before_cse to 1. + (ASSEMBLER_DIALECT): Define to assembler_dialect. + (assembler_dialect, fp_reg_names): Declare. + (OVERRIDE_OPTIONS): Add code for TARGET_SH4. + Hide names of registers that are not accessible. + (CACHE_LOG): Take TARGET_CACHE32 into account. + (LOOP_ALIGN): Take TARGET_HARWARD into account. + (FIRST_XD_REG, LAST_XD_REG, FPSCR_REG): Define. + (FIRST_PSEUDO_REGISTER: Now 49. + (FIXED_REGISTERS, CALL_USED_REGISTERS): Include values for registers. + (HARD_REGNO_NREGS): Special treatment of FIRST_XD_REG .. LAST_XD_REG. + (HARD_REGNO_MODE_OK): Update. + (enum reg_class): Add DF_REGS and FPSCR_REGS. + (REG_CLASS_NAMES, REG_CLASS_CONTENTS, REG_ALLOC_ORDER): Likewise. + (SECONDARY_OUTPUT_RELOAD_CLASS, SECONDARY_INPUT_RELOAD_CLASS): Update. + (CLASS_CANNOT_CHANGE_SIZE, DEBUG_REGISTER_NAMES): Define. + (NPARM_REGS): Eight floating point parameter registers on SH4. + (BASE_RETURN_VALUE_REG): SH4 also passes double values + in floating point registers. + (GET_SH_ARG_CLASS) Likewise. + Complex float types are also returned in float registers. + (BASE_ARG_REG): Complex float types are also passes in float registers. + (FUNCTION_VALUE): Change mode like PROMOTE_MODE does. + (LIBCALL_VALUE): Remove trailing semicolon. + (ROUND_REG): Round when double precision value is passed in floating + point register(s). + (FUNCTION_ARG_ADVANCE): No change wanted for SH4 when things are + passed on the stack. + (FUNCTION_ARG): Little endian adjustment for SH4 SFmode. + (FUNCTION_ARG_PARTIAL_NREGS): Zero for SH4. + (TRAMPOLINE_ALIGNMENT): Take TARGET_HARWARD into account. + (INITIALIZE_TRAMPOLINE): Emit ic_invalidate_line for TARGET_HARWARD. + (MODE_DISP_OK_8): Not for SH4 DFmode. + (GO_IF_LEGITIMATE_ADDRESS): No base reg + index reg for SH4 DFmode. + Allow indexed addressing for PSImode after reload. + (LEGITIMIZE_ADDRESS): Not for SH4 DFmode. + (LEGITIMIZE_RELOAD_ADDRESS): Handle SH3E SFmode. + Don't change SH4 DFmode nor PSImode RELOAD_FOR_INPUT_ADDRESS. + (DOUBLE_TYPE_SIZE): 64 for SH4. + (RTX_COSTS): Add PLUS case. + Increae cost of ASHIFT, ASHIFTRT, LSHIFTRT case. + (REGISTER_MOVE_COST): Add handling of R0_REGS, FPUL_REGS, T_REGS, + MAC_REGS, PR_REGS, DF_REGS. + (REGISTER_NAMES): Use fp_reg_names. + (enum processor_type): Add PROCESSOR_SH4. + (sh_flag_remove_dead_before_cse): Declare. + (rtx_equal_function_value_matters, fpscr_rtx, get_fpscr_rtx): Declare. + (PREDICATE_CODES): Add binary_float_operator, + commutative_float_operator, fp_arith_reg_operand, fp_extended_operand, + fpscr_operand, noncommutative_float_operator. + (ADJUST_COST): Use different scale for TARGET_SUPERSCALAR. + (SH_DYNAMIC_SHIFT_COST): Cheaper for SH4. + * sh.md (attribute cpu): Add value sh4. + (attrbutes fmovd, issues): Define. + (attribute type): Add values dfp_arith, dfp_cmp, dfp_conv, dfdiv. + (function units memory, int, mpy, fp): Make dependent on issue rate. + (function units issue, single_issue, load_si, load): Define. + (function units load_store, fdiv, gp_fpul): Define. + (attribute hit_stack): Provide proper default. + (use_sfunc_addr+1, udivsi3): Predicated on ! TARGET_SH4. + (udivsi3_i4, udivsi3_i4_single, divsi3_i4, divsi3_i4_single): New insns. + (udivsi3, divsi3): Emit special patterns for SH4 hardware, + (mulsi3_call): Now uses match_operand for function address. + (mulsi3): Also emit code for SH1 case. Wrap result in REG_LIBCALL / + REG_RETVAL notes. + (push, pop, push_e, pop_e): Now define_expands. + (push_fpul, push_4, pop_fpul, pop_4, ic_invalidate_line): New expanders. + (movsi_ie): Added y/i alternative. + (ic_invalidate_line_i, movdf_i4): New insns. + (movdf_i4+[123], reload_outdf+[12345], movsi_y+[12]): New splitters. + (reload_indf, reload_outdf, reload_outsf, reload_insi): New expanders. + (movdf): Add special code for SH4. + (movsf_ie, movsf_ie+1, reload_insf, calli): Make use of fpscr visible. + (call_valuei, calli, call_value): Likewise. + (movsf): Emit no-op move. + (mov_nop, movsi_y): New insns. + (blt, sge): generalize to handle DFmode. + (return predicate): Call emit_fpscr_use and remove_dead_before_cse. + (block_move_real, block_lump_real): Predicate on ! TARGET_HARD_SH4. + (block_move_real_i4, block_lump_real_i4, fpu_switch): New insns. + (fpu_switch0, fpu_switch1, movpsi): New expanders. + (fpu_switch+[12], fix_truncsfsi2_i4_2+1): New splitters. + (toggle_sz): New insn. + (addsf3, subsf3, mulsf3, divsf3): Now define_expands. + (addsf3_i, subsf3_i, mulsf3_i4, mulsf3_ie, divsf3_i): New insns. + (macsf3): Make use of fpscr visible. Disable for SH4. + (floatsisf2): Make use of fpscr visible. + (floatsisf2_i4): New insn. + (floatsisf2_ie, fixsfsi, cmpgtsf_t, cmpeqsf_t): Disable for SH4. + (ieee_ccmpeqsf_t): Likewise. + (fix_truncsfsi2): Emit different code for SH4. + (fix_truncsfsi2_i4, fix_truncsfsi2_i4_2, cmpgtsf_t_i4): New insns. + (cmpeqsf_t_i4, ieee_ccmpeqsf_t_4): New insns. + (negsf2, sqrtsf2, abssf2): Now expanders. + (adddf3, subdf3i, muldf2, divdf3, floatsidf2): New expanders. + (negsf2_i, sqrtsf2_i, abssf2_i, adddf3_i, subdf3_i): New insns. + (muldf3_i, divdf3_i, floatsidf2_i, fix_truncdfsi2_i): New insns. + (fix_truncdfsi2, cmpdf, negdf2, sqrtdf2, absdf2): New expanders. + (fix_truncdfsi2_i4, cmpgtdf_t, cmpeqdf_t, ieee_ccmpeqdf_t): New insns. + (fix_truncdfsi2_i4_2+1): New splitters. + (negdf2_i, sqrtdf2_i, absdf2_i, extendsfdf2_i4): New insns. + (extendsfdf2, truncdfsf2): New expanders. + (truncdfsf2_i4): New insn. + * t-sh (LIB1ASMFUNCS): Add _movstr_i4, _sdivsi3_i4, _udivsi3_i4. + (MULTILIB_OPTIONS): Add m4-single-only/m4-single/m4. + * float-sh.h: When testing for __SH3E__, also test for + __SH4_SINGLE_ONLY__ . + * va-sh.h (__va_freg): Define to float. + (__va_greg, __fa_freg, __gnuc_va_list, va_start): + Define for __SH4_SINGLE_ONLY__ like for __SH3E__ . + (__PASS_AS_FLOAT, __TARGET_SH4_P): Likewise. + (__PASS_AS_FLOAT): Use different definition for __SH4__ and + __SH4_SINGLE__. + (TARGET_SH4_P): Define. + (va_arg): Use it. + + * sh.md (movdf_k, movsf_i): Tweak the condition so that + init_expr_once is satisfied about the existence of load / store insns. + + * sh.md (movsi_i, movsi_ie, movsi_i_lowpart, movsf_i, movsf_ie): + change m constraint in source operand to mr / mf . + + * va-sh.h (__va_arg_sh1): Use __asm instead of asm. + + * (__VA_REEF): Define. + (__va_arg_sh1): Use it. + + * va-sh.h (va_start, va_arg, va_copy): Add parenteses. + +Sun Nov 22 21:34:02 1998 Jeffrey A Law (law@cygnus.com) + + * i386/dgux.c (struct option): Add new "description field". + * m88k/m88k.c (struct option): Likewise. + +Sun Nov 22 16:07:57 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sun Nov 22 13:40:02 1998 Bernd Schmidt + + * regmove.c (regmove_profitable_p): Use return value of find_matches + properly. + +Sun Nov 22 02:47:37 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sat Nov 21 22:12:09 1998 Jeffrey A Law (law@cygnus.com) + + * reload1.c (eliminate_regs): Do not lose if eliminate_regs is called + without reload having been called earlier. + + * v850.c (ep_memory_operand): Offsets < 0 are not valid for EP + addressing modes. + (v850_reorg): Similarly. + + * loop.c (check_dbra_loop): Avoid using gen_add2_insn. + +Sat Nov 21 02:18:38 1998 J"orn Rennecke + + * loop.c (move_movables): Start of libcall might be new loop start. + +Fri Nov 20 12:14:16 1998 Kaveh R. Ghazi + + * hash.c (hash_table_init_n): Wrap prototype arguments in PARAMS(). + +Fri Nov 20 08:34:00 1998 Bernd Schmidt + + * function.c (nonlocal_goto_handler_slots): Renamed from + nonlocal_goto_handler_slot; now an EXPR_LIST chain. + (push_function_context_to): Adjust for this change. + (pop_function_context_from): Likewise. + (init_function_start): Likewise. + (expand_function_end): Likewise. + * function.h (struct function): Likewise. + * calls.c (expand_call): Likewise. + * explow.c (allocate_dynamic_stack_space): Likewise. + * expr.h (nonlocal_goto_handler_slots): Rename its declaration. + * stmt.c (declare_nonlocal_label): Make a new handler slot for each + label. + (expand_goto): When doing a nonlocal goto, find corresponding handler + slot for it. Don't put the label address in the static chain register. + (expand_end_bindings): Break out nonlocal goto handling code into + three new functions. + (expand_nl_handler_label, expand_nl_goto_receiver, + expand_nl_goto_receivers): New static functions, broken out of + expand_end_bindings and adapted to create one handler per nonlocal + label. + * function.c (delete_handlers): Delete insn if it references any of + the nonlocal goto handler slots. + * i960.md (nonlocal_goto): Comment out code that modifies + static_chain_rtx. + * sparc.md (nonlocal_goto): Likewise. + (goto_handler_and_restore_v9): Comment out. + (goto_handler_and_restore_v9_sp64): Comment out. + +Thu Nov 19 23:44:38 1998 Bernd Schmidt + + * expr.c (STACK_BYTES): Delete unused macro. + * calls.c: Provide default for PREFERRED_STACK_BOUNDARY. + (STACK_BYTES): Use PREFERRED_STACK_BOUNDARY, not STACK_BOUNDARY. + (expand_call): Likewise. + (emit_library_call): Likewise. + (emit_library_call_value): Likewise. + * function.c: Provide default for PREFERRED_STACK_BOUNDARY. + (STACK_BYTES): Use PREFERRED_STACK_BOUNDARY, not STACK_BOUNDARY. + * explow.c: Provide default for PREFERRED_STACK_BOUNDARY. + (round_push): Use PREFERRED_STACK_BOUNDARY, not STACK_BOUNDARY. + (allocate_dynamic_stack_space): Likewise. + * tm.texi (PREFERRED_STACK_BOUNDARY): Document new macro. + (STACK_BOUNDARY): Update description to reflect the new situation. + +Thu Nov 19 22:20:51 1998 Jeffrey A Law (law@cygnus.com) + + * reorg.c (relax_delay_slots): When optimizing for code size, if a + return with a filled delay slot is followed by a return with an + unfilled delay slot, delete the first return and reemit the insn + that was previously in its delay slot. + + * i860.c (single_insn_src_p): Add missing parens. + * ginclude/math-3300.h: Likewise. + +Thu Nov 19 20:55:59 1998 H.J. Lu (hjl@gnu.org) + + * regclass.c (init_reg_sets_1): Add prototype. + (init_reg_modes): Likewise. + +1998-11-19 Zack Weinberg + + * c-common.c: Change warning messages to say `comparison is + always true' or `comparison is always false' instead of the + confusing `is always 0', `is always 1'. + +Thu Nov 19 19:05:49 1998 Per Bothner + + * print-tree.c (print_node): After printing BLOCK or BIND_EXPR, + break instead of return (which loses closing '>'). + +Thu Nov 19 19:34:13 1998 Jeffrey A Law (law@cygnus.com) + + * i386.h (LEGITIMATE_CONSTANT_P): Reject CONST_DOUBLEs that are not + standard 387 constants. + + * i386.md (jump): Explicitly set "memory" attribute. + (indirect_jump, prologue_set_stack_ptr): Likewise. + (prologue_get_pc_and_set_got, pop): Likewise. + (allocate_stack_worder, blockage, return_internal): Likewise. + (return_pop_internal, nop): Likewise. + (epilogue_set_stack_ptr, leave): Likewise. + +Thu Nov 19 15:42:54 1998 Nick Clifton + + * config/arm/coff.h: Set USER_LABEL_PREFIX to "_". + +Thu Nov 19 23:20:59 1998 J"orn Rennecke + + * reload1.c (reload_reg_free_for_value_p): + Early auto_inc reloads don't conflict with outputs. + +Thu Nov 19 12:58:55 1998 Kaveh R. Ghazi + + * configure.in: Don't do AC_CHECK_HEADERS(wait.h sys/wait.h). + Instead call AC_HEADER_SYS_WAIT. + + * collect2.c: Don't provide defaults for sys/wait.h macros. + * gcc.c: Likewise. + * protoize.c: Likewise. Also, don't include sys/wait.h. + + * system.h: Include sys/wait.h and provide macro defaults. + +1998-11-19 Andreas Schwab + + * Makefile.in (mandir): Set to @mandir@. + (man1dir): New variable to hold the former value of $(mandir). + Replace all uses of $(mandir) by $(man1dir). + +Wed Nov 18 16:31:28 1998 Jim Wilson + + * reload.c (find_reloads_address_part): If have a CONST_INT, create + a new one before passing it to force_const_mem. + + * reload.c (find_reloads_toplev): Pass &x instead of NULL_PTR in + find_reloads_address call. + +Wed Nov 18 22:13:00 1998 J"orn Rennecke + + * expr.c (store_expr): Don't generate load-store pair + if TEMP is identical (according to ==) with TARGET. + +Tue Nov 17 22:25:16 1998 J"orn Rennecke + + * reload1.c (reload_reg_free_for_value_p): When considered reload + has an output, matching inputs are not sufficient to avoid conflict. + +Tue Nov 17 11:51:16 1998 Mark Mitchell + + * hash.h (hash_table_key): New type. + (hash_entry): Change `string' field to generic `key'. + (hash_table): Add `comp' and `hash' functions. + (hash_table_init): Take them as input. + (hash_table_init_n): Likewise. + (hash_lookup): Modify for generic keys. + (hash_newfunc): Likewise. + (hash_traverse): Likewise. + (string_hash): New function. + (string_compare): Likewise. + (string_copy): Likewise. + * hash.c (hash_table_init_n): Modify for generic keys. + (hash_table_init): Likewise. + (hash_lookup): Likewise. + (hash_newfunc): Likewise. + (hash_traverse): Likewise. + (string_hash): Split out from hash_lookup. + (string_compare): New function. + (string_copy): Split out from hash_lookup. + * tlink.c (symbol_hash_newfunc): Modify for new interfaces to hash + tables. + (symbol_hash_lookup): Likewise. + (file_hash_newfunc): Likewise. + (file_hash_lookup): Likewise. + (demangled_hash_newfunc): Likewise. + (demangled_hash_lookup): Likewise. + (tlink_int): Likewise. + (read_repo_file): Likewise. + (recompile_files): Likewise. + (demangle_new_symbols): Likewise. + (scan_linker_output): Likewise. + +Tue Nov 17 17:13:53 1998 J"orn Rennecke + + * flow.c (insn_dead_p): New argument NOTES. Changed all callers. + +Mon Nov 16 17:56:07 1998 David Edelsohn + + * rs6000.c (output_mi_thunk): Improve test for local branch. + +Mon Nov 16 17:56:07 1998 Franz Sirl + + * rs6000.c (output_mi_thunk): Correct test for aggregate values. + +Mon Nov 16 21:02:52 1998 J"orn Rennecke + + * reload1.c (reload_reg_free_before_p): Delete. + Changed all callers to use reload_reg_free_for_value_p instead. + (reload_reg_free_for_value_p): Handle more reload types. + A RELOAD_FOR_INPUT doesn't conflict with its + RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_INPADDR_ADDRESS. + Add special case for OUT == const0_rtx. + Added ignore_address_reloads argument. Changed all callers. + +Mon Nov 16 02:22:29 1998 Jason Merrill + + * toplev.c (compile_file): Don't pedwarn about undefined static + functions just because we passed -Wunused. + +Mon Nov 16 04:41:41 1998 J"orn Rennecke + + * function.c (purge_addressof_1): Unshare rtl created by + store_bit_field. + +Mon Nov 16 04:23:06 1998 J"orn Rennecke + + * regmove.c (regmove_optimize): Don't do anything but + optimize_reg_copy[123] when flag_regmove is not set. + +Sat Nov 14 15:05:07 1998 Richard Henderson + + * alpha.md (addsi3, subsi3): Revise 5 Nov change to store DImode + value in paradoxical SImode result, rather than truncating midpoint. + +Fri Nov 13 22:19:23 1998 Richard Henderson + + * alpha.c (reg_not_elim_operand): New. + * alpha.h (PREDICATE_CODES): Add it. + * alpha.md (s48addq, s48subq patterns): Use it as the predicate + for the multiplicand. + +Fri Nov 13 22:50:37 1998 David Edelsohn + + * rs6000.md (movsf): Remove explicit secondary-reload-like + functionality. Only truncate SFmode store if in FPR. + (movsf splitters): Combine const_double splitters. + (movsf_hardfloat): Add GPR support. + +Fri Nov 13 11:02:11 1998 Stan Cox + + * splet.h (SUBTARGET_OVERRIDE_OPTIONS): New to + deprecate -mlive-g0 and -mbroken-saverestore. + * t-splet (MULTILIB_OPTIONS): Likewise. + + * sparc.c (sparc_flat_compute_frame_size): Correctly calc args_size + in a leaf function. Clarify total_size/extra_size relationship. + +Thu Nov 12 19:20:57 1998 Geoffrey Noer + + * i386/cygwin32.asm: Delete. + * i386/cygwin.asm: New file, renamed from cygwin32.asm. + * i386/cygwin32.h: Delete. + * i386/cygwin.h: New file, renamed from cygwin32.h. + * i386/t-cygwin32: Delete. + * i386/t-cygwin: New file, renamed from t-cygwin32. Include + cygwin.asm instead of cygwin32.asm. Remove "32" from comment. + * i386/x-cygwin32: Delete. + * i386/x-cygwin: New file, renamed from x-cygwin32. + * i386/xm-cygwin32: Delete. + * i386/xm-cygwin: New file, renamed from xm-cygwin32. Use newly + renamed cygwin_ funcs for path translations. + * i386/win32.h: Define __CYGWIN__ when -mcygwin given. + * i386/winnt.c: Remove "32" from comment about cygwin. + * i386/mingw32.h: Fix references to cygwin32.h in light of above. + * rs6000/cygwin32.h: Delete. + * rs6000/cygwin.h: New file, renamed from cygwin32.h. Add + -D__CYGWIN__ to CPP_PREDEFINES. + * rs6000/x-cygwin32: Delete. + * rs6000/x-cygwin: New file, renamed from x-cygwin32. + * rs6000/xm-cygwin32: Delete. + * rs6000/xm-cygwin: New file, renamed from xm-cygwin32. + + * configure.in: Check for cygwin* instead of cygwin32. Account + for the rename of cygwin-related config files to lose the "32"s. + * configure: Regenerate. + + * cccp.c, collect2.c, gcc.c, getpwd.c, libgcc2.c, protoize.c, + toplev.c: Change all refs to __CYGWIN32__ to __CYGWIN__. + +Wed Nov 11 12:25:19 1998 Tom Tromey + + * Makefile.in (JAVAGC): New macro. + * configure: Rebuilt. + * configure.in: Recognize --enable-java-gc argument. Subst + `JAVAGC' variable. + +Thu Nov 12 03:32:16 1998 J"orn Rennecke + + Handle equivalences that have been obscured by gcse: + + * reload1.c (reload): Handle equivalences set up in multiple places. + * local-alloc.c (reg_equiv_init_insns): New variable. + (no_equiv): New function. + (update_equiv_regs): Handle equivalences set up in multiple places. + Don't ignore an insn just because its destination is likely to be + spilled. + +Wed Nov 11 13:46:13 1998 Jim Wilson + + * except.c (expand_eh_return): Readd force_operand call lost in + Sept 15 change. + +Tue Nov 10 17:04:11 1998 David Edelsohn + + * rs6000.h (LEGITIMIZE_ADDRESS): Add missing goto on last case. + +1998-11-09 Andreas Schwab + + * dbxout.c: Check HAVE_STAB_H instead of HAVE_STABS_H. + +Mon Nov 9 20:15:19 1998 Bernd Schmidt + + * regmove.c (regmove_optimize): Fix error in last change. + +Mon Nov 9 16:37:52 1998 Andrew Cagney + + * mips.c (function_prologue): When TARGET_MIPS16, adjust the register + offset in the .mask pseudo to compensate for frame pointer adjustments. + (mips16_fp_args, build_mips16_call_stub): For little endian, do not + word swap arguments moved to/from FP registers. + * mips16.S (DFREVCMP): Reverse arguments to OPCODE. + +Mon Nov 9 09:47:06 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Mon Nov 9 02:14:14 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Mon Nov 9 03:06:24 1998 Jeffrey A Law (law@cygnus.com) + + * reload1.c (delete_output_reload_insn): If a pseudo is set multiple + times, then it can not be completely replaced. + +Mon Nov 9 00:39:02 1998 Richard Henderson + + * alpha.md (call, call_value) [OSF]: Correct alt 3 insn length. + +Sun Nov 8 17:50:30 1998 Kaveh R. Ghazi + + * gansidecl.h: Prepend a "G" to the macro wrapping this file + (to distinguish it from the macro wrapping ansidecl.h.) + Include libiberty's ansidecl.h. Remove all redundant definitions. + Define the PROTO() style macros in terms of the PARAMS() ones. + + + * calls.c (emit_library_call): Switch on ANSI_PROTOTYPES, not + __STDC__, when deciding whether to use ANSI variable args. + (emit_library_call_value): Likewise. + + * cccp.c (error): Likewise. + (warning): Likewise. + (error_with_line): Likewise. + (warning_with_line): Likewise. + (pedwarn): Likewise. + (pedwarn_with_line): Likewise. + (pedwarn_with_file_and_line): Likewise. + (fatal): Likewise. + + * cexp.y (error): Likewise. + (pedwarn): Likewise. + (warning): Likewise. + + * collect2.c (fatal_perror): Likewise. + (fatal): Likewise. + (error): Likewise. + + * combine.c (gen_rtx_combine): Likewise. + + * cpperror.c (cpp_message): Likewise. + (cpp_fatal): Likewise. + + * cpplib.c (cpp_error): Likewise. + (cpp_warning): Likewise. + (cpp_pedwarn): Likewise. + (cpp_error_with_line): Likewise. + (cpp_warning_with_line): Likewise. + (cpp_pedwarn_with_line): Likewise. + (cpp_pedwarn_with_file_and_line): Likewise. + + * cpplib.h: Don't define PARAMS() macro. + + * demangle.h: Likewise. + + * doprint.c (checkit): Switch on ANSI_PROTOTYPES, not __STDC__, + when deciding whether to use ANSI variable args. + + * emit-rtl.c (gen_rtx): Likewise. + (gen_rtvec): Likewise. + + * final.c (asm_fprintf): Likewise. + + * fix-header.c (cpp_message): Likewise. + (fatal): Likewise. + (cpp_fatal): Likewise. + + * gcc.c (concat): Likewise. + (fatal): Likewise. + (error): Likewise. + + * genattr.c (fatal): Likewise. + + * genattrtab.c (attr_rtx): Likewise. + (attr_printf): Likewise. + (fatal): Likewise. + + * gencodes.c (fatal): Likewise. + + * genconfig.c (fatal): Likewise. + + * genemit.c (fatal): Likewise. + + * genextract.c (fatal): Likewise. + + * genflags.c (fatal): Likewise. + + * genopinit.c (fatal): Likewise. + + * genoutput.c (fatal): Likewise. + (error): Likewise. + + * genpeep.c (fatal): Likewise. + + * genrecog.c (fatal): Likewise. + + * halfpic.h: Switch on ANSI_PROTOTYPES, not __STDC__, when + deciding whether to declare `tree_node' and `rtx_def'. + + * hash.h: Don't define stuff we get from gansidecl.h. + + * mips-tfile.c: Likewise. Define __proto() in terms of PARAMS(). + (fatal): Switch on ANSI_PROTOTYPES, not __STDC__, when deciding + whether to use ANSI variable args. + (error): Likewise. + + * prefix.c (concat): Likewise. + + * scan.h: Likewise. + + * system.h: Likewise. + + * toplev.c (error_with_file_and_line): Likewise. + (error_with_decl): Likewise. + (error_for_asm): Likewise. + (error): Likewise. + (fatal): Likewise. + (warning_with_file_and_line): Likewise. + (warning_with_decl): Likewise. + (warning_for_asm): Likewise. + (warning): Likewise. + (pedwarn): Likewise. + (pedwarn_with_decl): Likewise. + (pedwarn_with_file_and_line): Likewise. + (sorry): Likewise. + (really_sorry): Likewise. + + * toplev.h: Switch on ANSI_PROTOTYPES, not __STDC__, when deciding + whether to declare `tree_node' and `rtx_def'. + + * tree.c (build): Switch on ANSI_PROTOTYPES, not __STDC__, when + deciding whether to use ANSI variable args. + (build_nt): Likewise. + (build_parse_node): Likewise. + +Sun Nov 8 13:10:55 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sat Nov 7 23:34:01 1998 Kaveh R. Ghazi + + * Makefile.in (libcpp.a): Check RANLIB_TEST before runing RANLIB. + +Sat Nov 7 22:26:19 1998 David Edelsohn + + * collect2.c (main, case 'b'): Use else if. + +Sat Nov 7 15:35:25 1998 Kaveh R. Ghazi + + * configure.in (host_xm_file, build_xm_file, xm_file, tm_file): + Arrange to include gansidecl.h in {ht}config.h & tm.h just + before the config/ directory headers. + (tm_file_list, host_xm_file_list, build_xm_file_list): Handle + gansidecl.h in the list of dependencies. + + * Makefile.in (RTL_BASE_H): Don't depend on gansidecl.h. + (TREE_H, DEMANGLE_H, RECOG_H, REGS_H, libgcc2.a, stmp-multilib, + mbchar.o, collect2.o, pexecute.o, vfprintf.o, splay-tree.o, gcc.o, + gencheck.o, choose-temp.o, mkstemp.o, mkstemp.o, prefix.o, + dyn-string.o, cexp.o, cccp.o, cppmain.o, cpplib.o, cpperror.o, + cppexp.o, cppfiles.o, cpphash.o, cppalloc.o, scan-decls.o): + Likewise. + + * cccp.c: Don't include gansidecl.h. + * cexp.y: Likewise. + * collect2.c: Likewise. + * config/c4x/c4x.c: Likewise. + * config/v850/v850.h: Likewise. + * cppalloc.c: Likewise. + * cpperror.c: Likewise. + * cppexp.c: Likewise. + * cppfiles.c: Likewise. + * cpphash.c: Likewise. + * cpplib.c: Likewise. + * cppmain.c: Likewise. + * cppulp.c: Likewise. + * demangle.h: Likewise. + * doprint.c: Likewise. + * dyn-string.c: Likewise. + * eh-common.h: Likewise. + * fix-header.c: Likewise. + * frame.c: Likewise. + * gcc.c: Likewise. + * gcov.c: Likewise. + * gen-protos.c: Likewise. + * gencheck.c: Likewise. + * halfpic.h: Likewise. + * hash.c: Likewise. + * machmode.h: Likewise. + * mbchar.c: Likewise. + * prefix.c: Likewise. + * protoize.c: Likewise. + * recog.h: Likewise. + * rtl.h: Likewise. + * scan-decls.c: Likewise. + * tree.h: Likewise. + * varray.h: Likewise. + +Sat Nov 7 11:37:53 1998 Richard Henderson + + * i386.md (call_value_pop): If we're not popping anything, + defer to call_value. + (call_pop): Likewise defer to call. + +Sat Nov 7 02:49:56 1998 Richard Henderson + + * function.c (purge_addressof): Clear purge_addressof_replacements + only after processing the whole function. + +Sat Nov 7 00:54:55 1998 Jeffrey A Law (law@cygnus.com) + + * reload1.c (reload): If we can not perform a particular elimination + when we thought we could earlier, then we must always iterate through + the loop at least one more time. + +Fri Nov 6 19:37:33 1998 Richard Henderson + + * alpha.c (add_operand): Simplify the CONST_INT match. + (sext_add_operand): Correct typo in comparison by using + CONST_OK_FOR_LETTER_P. + * alpha.md (s?addq): Use sext_add_operand to allow the negative + constant alternatives to be generated. + (mulsi3, muldi3, umuldi3_highpart): Loosen constraints to allow + small constants, since the hw instructions do. + +Fri Nov 6 20:15:19 1998 Bernd Schmidt + + * reload1.c (emit_reload_insns): When rewriting the SET_DEST of a + previous insn to store directly into our reload register, make sure + that if the source of the previous insn is a reload register, its + spill_reg_store and spill_reg_stored_to values are cleared. + +Fri Nov 6 16:35:10 1998 David Edelsohn + + * rs6000.md (floatunssidf2_internal splitter): Use base register + operand, not hard-coded SP. + +Fri Nov 6 04:07:53 1998 David S. Miller + + * jump.c (calculate_can_reach_end): Fix thinko. + +Fri Nov 6 00:16:04 1998 Jeffrey A Law (law@cygnus.com) + + * reorg.c (fill_simple_delay_slots): Fix typo. + + * romp.h (LEGITIMIZE_ADDRESS): Fix typo. + +Fri Nov 6 00:10:00 1998 Jan Hubicka (hubicka@freesoft.cz) + + * i386.md (extendsidi2): Use # in the output template. + (extendsidi splitters): New splitters. + +Thu Nov 5 11:13:27 1998 Nick Clifton + + * configure.in: Use unknown-elf.h as tm_file for arm-elf + configuarions. + * configure: Regenerate. + +Thu Nov 5 07:59:05 1998 David S. Miller + + * jump.c (init_label_info, delete_barrier_successors, + mark_all_labels, delete_unreferenced_labels, + delete_noop_moves, calculate_can_reach_end): New functions broken + out of jump_optimize. + (jump_optimize): Use them. + +Thu Nov 5 07:57:45 EST 1998 Andrew MacLeod + + * except.c (expand_fixup_region_end): Make sure outer context labels + are not issued in an inner context during cleanups. + +Thu Nov 5 04:03:06 1998 Richard Henderson + + * alpha.md (addsi3, subsi3): No new temporaries once cse is + no longer expected. + +Thu Nov 5 03:29:19 1998 Richard Henderson + + * alpha.md (addsi3, subsi3): Expand to a DImode temporary so as + to expose this midpoint to CSE. + +Thu Nov 5 03:42:54 1998 David S. Miller + + * config/sparc/sparc.md (movdf_const_intreg_sp64): Enable again. + +Thu Nov 5 10:53:01 1998 Andreas Schwab + + * configure.in: Bring over gcc2 change of Nov 19 1997. + +Wed Nov 4 23:43:08 1998 Graham + + * toplev.c (output_lang_identify): Make definition dependent on + ASM_IDENTIFY_LANGUAGE. + + * print-rtl.c (spaces): Make static. + +Wed Nov 4 22:16:36 1998 Hans-Peter Nilsson + + * extend.texi: Clarify proper uses for register clobbers in asms. + +Wed Nov 4 22:16:36 1998 Bernd Schmidt + + * recog.h (enum op_type): Define. + (constrain_operands): Adjust prototype. + (recog_op_type): Declare new variable. + * recog.c (recog_op_type): New variable. + (insn_invalid_p): Allow modifying an asm statement after reload. + (extract_insn): Set up recog_op_type. + (constrain_operands): Lose INSN_CODE_NUM arg. All callers changed. + Don't compute operand types, use recog_op_type. + Use the information computed by extract_insn instead of the previous + method of finding it by insn code number. + * caller-save.c (init_caller_save): Use extract_insn, not insn_extract. + * reorg.c (fill_slots_from_thread): Likewise. + * reload1.c (reload_as_needed): Likewise. + (gen_reload): Likewise. + (inc_for_reload): Likewise. + (reload_cse_simplify_operands): Likewise. + Use the information computed by extract_insn instead of the previous + method of finding it by insn code number. + * genattrtab.c (write_attr_case): Generate call to extract_insn, not + insn_extract. + * final.c (final_scan_insn): Use extract_insn, not insn_extract. + (cleanup_operand_subregs): Use extract_insn, not insn_extract. + Use the information computed by extract_insn instead of the previous + method of finding it by insn code number. + * regmove.c (find_matches): Likewise. Change meaning of the return + value to be nonzero if the optimization can be performed, zero if + not. All callers changed. + Shorten some variable names to fix formatting problems. + (regmove_optimize): Shorten some variable names to fix formatting + problems. + Use the information computed by extract_insn instead of the previous + method of finding it by insn code number. + * regclass.c (scan_one_insn): Likewise. + (record_reg_classes): Don't compute operand types, use recog_op_type. + * reload.c (find_reloads): Lose CONSTRAINTS1 variable; use + recog_constraints instead. + +Wed Nov 4 21:37:46 1998 Jeffrey A Law (law@cygnus.com) + + * rtl.h (flow2_completed): Declare. + * flow.c (flow2_completed): Definition. + * toplev.c (rest_of_compilation): Set and clear flow2_completed + as necessary. + +Wed Nov 4 19:15:37 1998 "Melissa O'Neill" + + * Makefile.in (libcpp.a): Ranlib libcpp.a + + * cppulp.c (user_label_prefix): Initialize. + +Wed Nov 4 19:07:08 1998 John Wehle (john@feith.com) + + * flow.c (mark_regs_live_at_end): Mark the stack pointer as live + at a RETURN if current_function_sp_is_unchanging is set. + +Wed Nov 4 18:16:29 1998 Herman A.J. ten Brugge + + * emit-rtl.c (try_split): Fixed error in Oct 10 patch. + +Wed Nov 4 15:11:15 1998 Geoffrey Noer + + * i386/cygwin32.h (MASK_WIN32, MASK_CYGWIN, MASK_WINDOWS, MASK_DLL, + TARGET_WIN32, TARGET_CYGWIN, TARGET_WINDOWS, TARGET_DLL): New. + (SUBTARGET_SWITCHES): Add -mno-cygwin, -mcygwin, and -mdll options. + (CPP_PREDEFINES): Don't define __CYGWIN32__ here. + (STARTFILE_SPEC): Handle -mdll, -mno-cygwin options. + (CPP_SPEC): Handle -mno-cygwin option. Define __CYWIN__ in addition + to __CYGWIN32__. + (LIB_SPEC): Handle -mno-cyginw option. + (LINK_SPEC): Handle -mdll. + +Wed Nov 4 22:56:14 1998 J"orn Rennecke + + * reload.c (find_reloads): Fix test for usage by other reload + to handle secondary reloads properly. + +Wed Nov 4 17:25:10 1998 Kaveh R. Ghazi + + * reload1.c (ELIMINABLE_REGS, NUM_ELIMINABLE_REGS): Introduce an + intermediate structure which has exactly the members provided by + ELIMINABLE_REGS. Define NUM_ELIMINABLE_REGS in terms of the + static intermediate structure. + + (init_elim_table): Xmalloc() `reg_eliminate', and initialize it + from the intermediate structure. Do the same analogous fix in + the case where ELIMINABLE_REGS is not defined. + +Tue Nov 3 20:50:03 1998 Jeffrey A Law (law@cygnus.com) + + * pa.h (SELECT_SECTION): Fix thinko. + +Tue Nov 3 17:51:36 1998 Jim Wilson + + * dwarf2out.c (output_call_frame_info): Comments on last change. + +Tue Nov 3 07:51:43 1998 Richard Earnshaw (rearnsha@arm.com) + + * arm.c (add_constant): When taking the address of an item in the + pool, get the mode of the item addressed. + + * arm.c (final_prescan_insn case INSN): If an insn doesn't + contain a SET or a PARALLEL, don't consider it for conditional + execution. + + Restore ABI compatibility for NetBSD. + * arm/netbsd.h (DEFAULT_PCC_STRUCT_RETURN): Override setting in + arm.h + (RETURN_IN_MEMORY): Likewise. + +Mon Nov 2 11:46:17 1998 Doug Evans + + * m32r/m32r.c (m32r_expand_block_move): Fix byte count computations. + (m32r_output_block_move): Rewrite bytes < 4 handling. + +Mon Nov 2 10:10:35 1998 Kaveh R. Ghazi + + * configure.in: Call AC_FUNC_VFORK. + + * collect2.c: Define VFORK_STRING as a printable string for + error messages (either "vfork" or "fork".) If HAVE_VFORK_H is + defined, include vfork.h. If VMS is defined, define vfork() + appropriately. Remove vfork check on USG, we're using autoconf. + (collect_execute): Pass VFORK_STRING to fatal_perror instead of + checking locally what string to pass. + (scan_prog_file): Likewise. + (scan_libraries): Likewise. + + * gcc.c: Remove vfork check on USG, we're using autoconf. + Besides, no calls to vfork/fork occur in this file. + + * protoize.c: Likewise. + +Mon Nov 2 07:52:28 1998 Alexandre Oliva + + * configure.in (DEFAULT_LINKER): renamed from LD + (DEFAULT_ASSEMBLER): renamed from AS; reverted Schwab's patch + (gcc_cv_as): try $DEFAULT_ASSEMBLER before $AS + * configure: rebuilt + +Mon Nov 2 01:48:10 1998 Alexandre Oliva + + * BUGS: fix the regexp for `more' to find the appropriate node. + Reported by Joerg Pietschmann + + * BUGS: added link to the WWW FAQ + +Sun Nov 1 18:27:15 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sun Nov 1 11:04:32 1998 Jeffrey A Law (law@cygnus.com) + + * From Christian Gafton: + * i386/linux.h (CPP_PREDEFINES): Add -D__i386__. + * sparc/linux.h (CPP_PREDEFINES): Add -D__sparc__. + * sparc/linux64.h (CPP_PREDEFINES): Add -D__sparc__. + +Sat Oct 31 21:42:39 1998 Mark Mitchell + + * c-common.c (c_get_alias_set): Allow all type-punning through + unions. Don't get confused about the type of a bit-field, despite + the antics of build_modify_expr. + +Sat Oct 31 22:35:29 1998 Jean-Pierre Radley + + * fixinc.sco: Paramaterize #include_next values. + * fixinc/fixinc.sco: Likewise. + +Sat Oct 31 20:39:35 1998 Jeffrey A Law (law@cygnus.com) + + * toplev.c (rest_of_compilation): No longer set reload_completed. + * reload1.c (reload): Set it here. Perform instruction splitting + after reload has completed if we will be running the scheduler + again. + +Sat Oct 31 12:30:02 1998 Jeffrey A Law (law@cygnus.com) + + * jump.c (jump_optimize): Initialize mappings from INSN_UID to + EH region if exceptions are enabled and we're performing cross + jump optimizations. + (find_cross_jump): Exit loop if the insns are in different EH regions. + +Sat Oct 31 10:02:48 1998 Mark Mitchell + + * dwarf2out.c (output_call_frame_info): Use + ASM_OUTPUT_DWARF_DELTA4 for the CIE offset to match frame.c. + +Sat Oct 31 10:23:14 1998 Kaveh R. Ghazi + + Reinstall Apr 24th fix, lost during May 6th gcc2 merge: + * c-common.c (check_format_info): Don't check for the 'x' + format character twice, instead check for 'x' and 'X' + +Fri Oct 30 14:50:25 1998 Jeffrey A Law (law@cygnus.com) + + * configure.in (assembler features): Also make gas is configured if + we find it in the souce tree. + +Fri Oct 30 13:23:20 1998 Richard Henderson + + * i386.c (i386_comp_type_attributes): Compare whether the + attributes are defined, not their tree nodes. + +Fri Oct 30 11:39:47 1998 Alexandre Oliva + + * configure.in (gxx_include_dir): bitten by autoconf quoting + characters :-( + * configure: rebuilt + +Fri Oct 30 10:43:29 1998 Andreas Schwab + + * configure.in: Ignore non-absolute value in $AS. + +Fri Oct 30 00:54:25 1998 Peter Jakubek + + * m68k.h (INDIRECTABLE_1_ADDRESS_P): Fix thinko. + +Fri Oct 30 00:42:34 1998 Mark Elbrecht + + * configure.in (msdosdjgpp): Set exeext and target_alias. + +Thu Oct 29 23:55:43 1998 Bernd Schmidt + + * flow.c (XNMALLOC): New macro. + (flow_int_list_blocks, basic_block_succ, basic_block_pred): New + static variables. + (add_edge, add_edge_to_label): New static functions. + (free_bb_memory): New function. + (flow_delete_insn): Delete function. + (basic_block_drops_in): Delete variable. + (find_basic_blocks): Allocate and initialize basic_block_head, + basic_block_succ. Don't allocate basic_block_drops_in. + Call free_bb_memory at the beginning. + (find_basic_blocks_1): Don't do multiple passes. + Delete code to compute basic_block_drops_in. + After calling make_edges, mark blocks reached by current block live. + Update test for unreachable live blocks. + (mark_label_ref): Delete args X, CHECKDUP. Add PRED arg. All callers + changed. + Simplify to call add_edge_to_label when a LABEL_REF is found. + (make_edges): Simplify to call add_edge_to_label instead of + mark_label_ref most of the time. + Compute here whether control drops into the next block. + (delete_unreachable_blocks): Return void. All callers changed. + Delete unreachable blocks in reverse order. + After deleting all unreachable blocks, renumber the remaining ones + and update n_basic_blocks. + (delete_block): Speed up deletion a bit. + Don't set basic_block_drops_in for deleted blocks. + (free_basic_block_vars): Don't free basic_block_drops_in. + (life_analysis_1): Update to use new edge representation. + (dump_flow_info): Delete code to print basic block info; call + dump_bb_data instead. + (compute_preds_succs): Delete code to recompute basic_block_drops_in + and uid_block_number. + Simply copy the previously computed cfg. + (dump_bb_data): New arg LIVE_INFO. All callers changed. + Print register lifetime information if LIVE_INFO is nonzero. + * basic-block.h (dump_bb_data): Adjust prototype. + * gcse.c (gcse_main): Update call to dump_bb_data. + * rtl.h (free_bb_memory): Declare. + * toplev.c (rest_of_compilation): Call free_bb_memory. + + * reload1.c (struct elim_table): Delete MAX_OFFSET member. + (update_eliminable_offsets): Don't compute it. + (set_initial_elim_offsets): Don't initialize it. + Break out some code into set_initial_label_offsets so the rest of + this function can be called from reload_as_needed. + Assume that INITIAL_FRAME_POINTER_OFFSET is defeined when + ELIMINABLE_REGS isn't. + (set_initial_label_offsets): New function, broken out of + set_initial_elim_offsets. + (set_offsets_for_label): New function, broken out of set_label_offsets + and reload_as_needed. + (reload): Call the two new functions. + (reload_as_needed): Call set_initial_elim_offsets instead of + duplicating the code. Likewise for set_offsets_for_label. + + * reload1.c (choose_reload_regs): Fix typo in Oct 17 change. + (emit_reload_insns): Ensure that when we set reg_reloaded_valid for + any hard reg, reg_reloaded_dead contains valid data. + +Thu Oct 29 22:30:54 1998 Marcus Meissner + + * i386.c (i386_comp_type_attributes): Return nonzero for mismatched + "stdcall" and "cdecl" attributes. + +Thu Oct 29 23:55:43 1998 Bernd Schmidt + + * reload1.c (choose_reload_regs): Fix typo in Oct 17 change. + +Thu Oct 29 19:05:17 1998 Jim Wilson + + * sched.c (update_flow_info): Add code to ! found_orig_dest case to + handle deleted no-op moves of hard registers. + * haifa-sched.c (update_flow_info): Likewise. + +Thu Oct 29 18:07:47 1998 Jeffrey A Law (law@cygnus.com) + + * mips.md (reload_{in,out}{si,di}): Emit a USE of HILO at the end + of the sequences to reload the HILO register which do not actually + reference HILO. + +Thu Oct 29 12:39:35 1998 Jim Wilson + + * c-common.c (c_get_alias_set): Handle ARRAY_REF of union field. + +Thu Oct 29 14:10:22 EST 1998 Andrew MacLeod + + * except.c (emit_eh_context): Make the EH context register stay alive + at -O0 so stupid.c doesn't get confused. + +1998-10-29 Herman A.J. ten Brugge + + * emit-rtl.c (try_split): Do not try to split a BARRIER. + +Thu Oct 29 01:33:54 1998 Jan Hubicka + Jeffrey A Law (law@cygnus.com) + + * i386.md: Change ix86_cpu == PROCESSOR_PENTIUM to TARGET_PENTIUM + (zero_extendsidi2): Use # in output template and handle completely by + splits. + (zero_extend splitters): New define_splits. + (ashiftrt_32): New pattern. + +Wed Oct 28 22:58:35 1998 Jason Merrill + + * tree.c (append_random_chars): New fn. + (get_file_function_name_long): Use it. + +Wed Oct 28 22:27:05 1998 Richard Henderson + + * Makefile.in (cc1): Put C_OBJS, and thence @extra_c_objs@ last. + (LIBCPP_OBJS): New. Add cppulp.o. + (cppmain, fix-header): Depend on and use libcpp.a. + * configure.in (extra_c_objs, extra_cxx_objs): Use libcpp.a instead + of the individual object files. + * objc/Make-lang.in (cc1obj): Put OBJC_OBJS, and thence @extra_c_objs@, + last. + + * cccp.c (user_label_prefix): New. + (main): Set it off -f*leading-underscore. + (special_symbol): Use it. + * cpplib.c (special_symbol): Likewise. + (cpp_handle_option): Handle -f*leading-underscore. + * cppulp.c: New file. + + * output.h (user_label_prefix): Declare it. + * dwarf2out.c (ASM_NAME_TO_STRING): Prepend user_label_prefix. + * toplev.c (f_options, main): Handle -f*leading-underscore. + + * defaults.h (ASM_OUTPUT_LABELREF): Use asm_fprintf instead of + referencing USER_LABEL_PREFIX directly. + * config/nextstep.h (ASM_OUTPUT_LABELREF): Likewise. + * m32r/m32r.h (ASM_OUTPUT_LABELREF): Likewise. + * final.c (asm_fprintf): Use user_label_prefix instead. + * arm/thumb.c (thumb_print_operand): Likewise. + + * gcc.c (default_compilers): Pass -f*leading-underscore on to + cpp wherever appropriate. + +Wed Oct 28 23:09:25 1998 Robert Lipe + + * sco5.h (SUBTARGET_SWITCHES): Add documentation for OpenServer- + specific compiler switches. + +Wed Oct 28 21:05:53 1998 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (c-common.o): Depend on c-pragma.h. Use $(RTL_H) instead + of rtl.h. + +Wed Oct 28 20:52:47 1998 Kaveh R. Ghazi + + * gcc.c (EXTRA_SPECS, extra_specs): Introduce an intermediate + structure which has exactly the members provided by EXTRA_SPECS. + Xmalloc() the real `extra_specs', and initialize it from this + intermediate structure. + + * alpha.h (EXTRA_SPECS): Revert change for missing initializers. + + * mips.h (EXTRA_SPECS): Likewise. + + * sparc.h (EXTRA_SPECS): Likewise. + +Wed Oct 28 16:46:07 1998 Andreas Schwab + + * function.c (purge_addressof_1): Instead of aborting when a + bitfield insertion as a replacement for (MEM (ADDRESSOF)) does not + work just put the ADDRESSOF on stack. Otherwise remember all such + successfull replacements, so that exactly the same replacements + can be made on the REG_NOTEs. Remove the special case for CALL + insns again. + (purge_addressof_replacements): New variable. + (purge_addressof): Clear it at end. + +1998-10-28 16:10 -0500 Zack Weinberg + + * c-lang.c: Declare extern char *yy_cur if USE_CPPLIB. + (lang_init): Call check_newline always. + * c-lex.c (init_parse) [USE_CPPLIB=1]: After calling + cpp_start_read, set yy_cur and yy_lim to read from + parse_in.token_buffer, so that we'll see the first #line + directive. + * cpplib.c (cpp_start_read): finclude the main input file + before processing -include/-imacros. Process -imacros and + -include separately, and handle -include by stacking a + buffer for the file in question as if it'd been #included. + * toplev.c (documented_lang_options) Recognize -H when + USE_CPPLIB is on. + +1998-10-28 16:09 -0500 Zack Weinberg + + * cpplib.c: Merge do_once into do_pragma. Break file handling + code out of do_include. + Move append_include_chain, deps_output, + file_cleanup, redundant_include_p, import_hash, + lookup_import, add_import, read_filename_string, read_name_map, + open_include_file, finclude, safe_read to cppfiles.c. + Move prototypes for deps_output, append_include_chain, + finclude to cpplib.h. Move definition of struct + file_name_list there also. + + * cppfiles.c: New file. Contains all the above functions + broken out of cpplib.c; also hack_vms_include_specification + from cccp.c and find_include_file, a new function broken out of + do_include. + + * Makefile.in (cppmain): Depend on cppfiles.o. + (fix-header): Likewise. + (cppfiles.o): New target. + * configure.in (--enable-c-cpplib): Add cppfiles.o to + extra_c_objs. Add ../cppfiles.o to extra_cxx_objs. + +Wed Oct 28 14:06:49 1998 Jim Wilson + + * dwarfout.c (dwarfout_file_scope_decl): If DECL_CONTEXT, don't abort + if pending_types is non-zero. + (dwarfout_finish): Verify pending_types is zero before finishing. + +Wed Oct 28 10:29:09 1998 Nick Clifton + + * expr.c (convert_move): Use shifts to perform the move if a + suitable extend pattern cannot be found. Code written by + Richard Henderson . + +Wed Oct 28 03:59:29 1998 Bernd Schmidt + + * regclass.c (renumber, regno_allocated): New static variables, moved + out of allocate_reg_info. + (allocate_reg_info): Move these two variables outside the function. + Move code to free memory into new function free_reg_info. + (free_reg_info): New function, broken out of allocate_reg_info. + * toplev.c (compile_file): Call free_reg_info, not allocate_reg_info. + * rtl.h (allocate_reg_info): Don't declare. + (free_reg_info): Declare. + + * final.c (cleanup_subreg_operands): ASM_INPUTs need no treatment. + +Wed Oct 28 02:38:12 1998 Jason Merrill + + * toplev.c (compile_file): Temporarily revert last change. + +Wed Oct 28 00:00:35 1998 Jason Merrill + + * c-typeck.c (convert_for_assignment): Parenthesize. + +1998-10-28 Andreas Schwab + + * reload1.c (delete_output_reload): Avoid ambigous else. + +Wed Oct 28 00:10:35 1998 Jeffrey A Law (law@cygnus.com) + + * toplev.c (compile_file): Call allocate_reg_info to free register + table memory. + * rtl.h (allocate_reg_info): Declare. + + * PROJECTS: Remove entry for local spilling. + + * final.c (cleanup_subreg_operands): New function. + (final_scan_insn): Use it. + (alter_subreg): Clear the "used" field when we turn a SUBREG into + a REG. + * reload1.c (reload): Delete CLOBBER insns and also cleanup SUBREG + operands when reload has finished. + * reload.h (cleanup_subreg_operands): Declare.. + * flow.c (life_analysis_1): No longer delete CLOBBER insns after + reload. Handled in reload itself. + +Tue Oct 27 23:32:34 1998 Bernd Schmidt + + * reload1.c (verify_initial_offsets): New function. + (reload): Call it after reload_as_needed. Also verify that the frame + size stays constant during reload_as_needed. + * i386.h (CONST_DOUBLE_OK_FOR_LETTER_P): Undo Jul 26 change. + + * reload.h (struct insn_chain): Add need_operand_change element. + * reload1.c (new_insn_chain): Clear it. + (calculate_needs_all_insns): Set it; don't overload need_reload. + (reload_as_needed): Use it. + + * reload.c (find_reloads_address): Use BASE_REG_CLASS instead of + reload_address_base_reg_class throughout. Similar for INDEX_REG_CLASS + and reload_address_index_reg_class. + (find_reloads_address_1): Likewise. + * reload.h (reload_address_base_reg_class, + reload_address_index_reg_class): Don't declare. + * reload1.c (reg_old_renumber, pseudo_previous_regs, + pseudo_forbidden_regs, bad_spill_regs_global): New static variables. + (used_spill_regs): Now static. + (reload_address_base_reg_class, reload_address_index_reg_class, + regs_explicitly_used, counted_for_groups, counted_for_nongroups, + basic_block_needs, max_needs, group_size, group_mode, max_groups, + max_nongroups, max_needs_insn, max_groups_insn, max_nongroups_insn, + forbidden_regs): + Deleted variables. + (init_reload): Delete code to compute base/index reg classes. + (reload): Delete variable J. + Delete code to manage basic_block_needs. + Don't compute regs_explicitly_used. + Allocate, initialize and free reg_old_renumber, pseudo_forbidden_regs, + pseudo_previous_regs. + Initialize bad_spill_regs_global. + Don't call order_regs_for_reload here. + Don't initialize spill_reg_order and n_spills. + Don't forbid explicitly used regs to be used for spill regs. + Change main loop to infinite loop, with explicit break statements. + Make SOMETHING_CHANGED variable local to that loop. + Don't initialize max_needs, max_groups, max_nongroups, max_needs_insn, + max_groups_insn, max_nongroups_insn, group_size, group_mode. + Make sure spilled_speudos is cleared before calling spill_hard_reg or + new_spill_reg. + Don't call dump_needs. + Delete code to reset potential_reload_regs. + Delete code to terminate loop conditional on the global needs variables + showing no further needs. + (calculate_needs_all_insns): Return void. All callers changed. + Initialize somehing_needs_elimination here, not in reload. + Delete avoid_return_reg kludge. + (calculate_needs): Lose AVOID_RETURN_REG and GLOBAL args, return void. + All callers changed. + Initialize the group_mode and group_size elements of the arg CHAIN. + Delete code to manage basic_block_needs. + Operate on elements of CHAIN instead of global variables. + Delete avoid_return_reg kludge. + (find_tworeg_group): Lose GLOBAL arg, take CHAIN arg, return void. + All callers changed. + Operate on elements of CHAIN instead of global variables. + Delete special SMALL_REGISTER_CLASSES code. + Delete spill_failure code; now in new_spill_reg. + (find_group): Lose GLOBAL arg, take CHAIN arg, return void. + All callers changed. + Operate on elements of CHAIN instead of global variables. + (maybe_mark_pseudo_spilled): New static function. + (find_reload_regs): Lose GLOBAL arg, take CHAIN arg, return void. + All callers changed. + Operate on elements of CHAIN instead of global variables. + Call order_regs_for_reload here, not in reload. + Initialize spill_reg_order and n_spills. + Simplify test whether an asm insn is involved. + Delete spill_failure code; now in new_spill_reg. + Call maybe_mark_pseudo_spilled for everything marked as live in + CHAIN. Merge CHAIN's used_spill_regs into the global variable + used_spill_regs. + (dump_needs): Take CHAIN arg. No longer static, to prevent the + compiler from optimizing this function (now unused) away. + Operate on elements of CHAIN instead of global variables. + (possible_group_p): Lose MAX_GROUPS arg, take CHAIN arg. All callers + changed. + Operate on elements of CHAIN instead of global variables. + (count_possible_groups): Lose GROUP_SIZE, GROUP_MODE, MAX_GROUPS args, + take CHAIN arg. All callers changed. + Operate on elements of CHAIN instead of global variables. + (new_spill_reg): Lose MAX_NEEDS, MAX_NONGROUPS, GLOBAL args, take + CHAIN, NONGROUP args. Return void. All callers changed. + Verify caller isn't trying to spill a pseudo. + Simplify test for illegal reg, just use bad_spill_regs. + Generate better error messages. + Operate on elements of CHAIN instead of global variables. + Mark spilled register in CHAIN's used_spill_regs element. + Don't call spill_hard_reg. + (spill_hard_reg): Lose GLOBAL arg, return void. All callers changed. + Mark spilled hard regs in bad_spill_regs_global. + Mark affected pseudos in spilled_pseudos, but don't spill them. + (ior_hard_reg_set): New static function. + (finish_spills): Return int. All callers changed. + Compute spill_reg_order, n_spills and spill_regs here. Also update + regs_ever_live for regs used as spills. + For every pseudo in spilled_pseudos, spill it and mark the previous + hard reg it had in pseudo_previous_regs. Compute which hard regs + arseudo): New static function. + (order_regs_for_reload): Take CHAIN arg. All callers changed. + Initialize bad_spill_regs from bad_spill_regs_global, then merge any + hard registers explicitly used across the current insn into the set. + Compute hard_reg_n_uses taking only pseudos live across this insn + into account. + Tweak sorting of potential_reload_regs. + (compare_spill_regs): Delete function. + (reload_as_needed): Don't sort the spill_regs array, it's computed + in proper order in finish_spills. + Delete avoid_return_reg kludge. + Delete code to manage basic_block_needs. + (allocate_reload_reg): Minor speed/readability tweaks. + Operate on elements of CHAIN instead of global variables. + (choose_reload_regs): Lose AVOID_RETURN_REG arg. All callers changed. + Delete avoid_return_reg kludge. + Initialize reload_reg_used from CHAIN's used_spill_regs element. + Delete unused label FAIL. + (reload_combine): Replce reload_address_index_reg_class with + INDEX_REGS. + Don't use used_spill_regs to determine information about lifetime of + hard regs. + +Tue Oct 27 13:15:02 1998 Nick Clifton + + * toplev.c (display_help): Ignore empty target specific + options, and if -W is also specified on the command line then + display undocumented options. + + * config/arm/arm.c: Updated with changes in devo sources. + * config/arm/arm.h: Updated with changes in devo sources. + * config/arm/lib1funcs.asm: Updated with changes in devo sources. + * config/arm/lib1thumb.asm: Add ELF support. + +Tue Oct 27 16:11:43 1998 David Edelsohn + + * collect2.c (aix64_flag): New variable. + (main, case 'b'): Parse it. + (GCC_CHECK_HDR): object magic number must match mode. + (scan_prog_file): Only check for shared object if valid header. + Print debugging if header/mode mismatch. + +Tue Oct 27 10:15:02 1998 Nick Clifton + + Added support for arm-elf-linux configuration, submitted by Philip + Blundell , and integrated this with the arm-elf + code developed by Catherine Moore . The following + files are affected: + + * configure.in: Add arm-*-linux-gnu, armv2-*-linux and arm-*-elf + targets. + + * configure: Regenerated. + + * config/arm/aout.h: Add default definitions of REGISTER_PREFIX, + USER_LABEL_PREFIX and LOCAL_LABEL_PREFIX. Make other macro + definitions conditional on their not having been already defined. + + * config/arm/lin1funcs.asm: Add ELF only macros to generate .size + and .type directives, and add "(PLT)" qualification to function + calls. + + * config/arm/linux.h: Deleted. This file is now superceeded by + either linux-elf.h or linux-aout.h. + + * config/arm/linux-gas.h: Define `inhibit_libc' if cross-compiling. + (CLEAR_INSN_CACHE): New macro, currently disabled (awaiting kernel + support). + Move definitions from old linux.h file here. + + * config/arm/elf.h: New file. Generic ARM/ELF support. + + * config/arm/linux-aout.h: New file. Support for Linux with a.out. + + * config/arm/linux-elf.h: New file. Support for Linux with ELF. + + * config/arm/linux-elf26.h: New file. Support for Linux with ELF + using the 26bit APCS. + + * config/arm/unknown-elf.h: New file. Support for OS'es other + than Linux with ELF. + + * config/arm/t-arm-elf: New file. makefile fragment for arm-elf + builds. + + * config/arm/coff.h: Include aout.h for basic assembler macros. + Add support for -mstructure_size_boundary= command line option. + + * config/arm/arm.h: Add support for -mstructure_size_boundary= + command line option. Make macro definitions conditional on their + not having been already defined. + + * config/arm/arm.c: Add support for -mstructure_size_boundary= + command line option. + + +Tue Oct 27 08:56:46 1998 Andrew MacLeod + + * dwarfout.c (ASM_OUTPUT_DWARF_STRING_NEWLINE): ASM_OUTPUT_DWARF_STRING + has been changed to not include a newline. Use this macro instead. + (output_enumeral_list, const_value_attribute, name_attribute, + comp_dir_attribute, prototyped_attribute, producer_attribute, + inline_attribute, pure_or_virtual_attribute, output_inheritance_die, + dwarfout_file_scope_decl, generate_new_sfname_entry, + generate_macinfo_entry, dwarfout_init, dwarfout_finish): Use + ASM_OUTPUT_DWARF_STRING_NEWLINE macro. + +Mon Oct 26 13:35:02 1998 Richard Henderson + + * combine.c (subst): Process the inputs to a parallel asm_operands + only once. + +Mon Oct 26 13:32:31 1998 Richard Henderson + + * stmt.c (expand_asm_operands): Accept `=' or `+' at any position. + +Mon Oct 26 12:53:14 1998 Jeffrey A Law (law@cygnus.com) + + * tm.texi (ASM_OUTPUT_MAX_SKIP_ALIGN): Document. + +Mon Oct 26 00:36:58 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sun Oct 25 23:36:52 1998 Jason Merrill + + * stmt.c (expand_fixup): Set fixup->before_jump to a + NOTE_INSN_DELETED instead of a NOTE_INSN_BLOCK_BEG. + +Sun Oct 25 15:49:57 1998 Kaveh R. Ghazi + + * Makefile.in (recog.o): Depend on toplev.h. + (insn-emit.o): Depend on recog.h. + (insn-peep.o): Depend on recog.h and insn-config.h. + + * combine.c (simplify_set): Remove unused variable `scratches'. + + * final.c (final_scan_insn): Wrap declaration of variables `vlen' + and `idx' in macro conditional controlling their use. + + * genemit.c (main): Make the generated output file include + recog.h. Don't have it declare `insn_operand_constraint', since + we get it from recog.h. + + * genpeep.c (main): Make the generated output file include + insn-config.h and recog.h. + + * recog.c: Include toplev.h. + (extract_insn): Remove unused variable `p'. + + * regclass.c (fix_register): Add missing braces around initializer + for `what_option'. + (allocate_reg_info): Move variable `i' into the scope where it is + used. Change its type to `size_t'. + +Sun Oct 25 13:10:15 1998 Bernd Schmidt + + * reload.c (push_reload): When merging reloads, make sure + that reload_in_reg and reload_in are from the same reload in + all cases. + +Sun Oct 25 12:07:00 1998 Mumit Khan + + * i386/crtdll.h (CPP_PREDEFINES): Fix typo. + * i386/mingw32.h (CPP_PREDEFINES): Likewise. + +Fri Oct 23 23:42:03 1998 David Edelsohn + + * loop.c (loop_has_tablejump): New variable. + (prescan_loop): Scan for it. + (insert_bct): Replace explicit scan with use of it. + * regclass.c (regclass): Restore loop variable j. + (record_reg_classes): Deterine op_types modifiers and initialize + classes[i] before matching constraints. Handle matching + constraints 5-9. + +Fri Oct 23 13:55:48 1998 Jim Wilson + + * m32r/m32r.c (gen_split_move_double): Call alter_subreg. Delete + subreg support. + +Fri Oct 23 16:19:24 1998 Kaveh R. Ghazi + + * mips.h (EXTRA_SPECS): Add missing initializers. + +Fri Oct 23 16:08:39 1998 Kaveh R. Ghazi + + * sparc.h (EXTRA_SPECS): Add missing initializers. + (sparc_defer_case_vector): Provide a prototype. + + * svr4.h (ASM_OUTPUT_ASCII): Cast STRING_LIMIT to (long) when + comparing it to the result of a pointer subtraction. + +Fri Oct 23 15:34:14 1998 Kaveh R. Ghazi + + * alpha.c (override_options): Use ISDIGIT(), not isdigit(). Cast + the argument to (unsigned char). + + * alpha.h (EXTRA_SPECS): Add missing initializers. + (ASM_GENERATE_INTERNAL_LABEL): Ensure the argument matches the + format specifier. + +Fri Oct 23 13:12:35 1998 Jeffrey A Law (law@cygnus.com) + + * flow.c (life_analysis_1): Enable "rescan" code after reload. + (propagate_block): Delete dead code after reload. + + * sched.c (update_flow_info): Revert Oct 19, 1998 change. Brings + back Oct 15, 1998 change. + * haifa-sched.c (update_flow_info): Likewise. + * flow.c (life_analysis_1): Delete CLOBBER insns after reload. + + * mn10200.md (truncated shift): Accept constant inputs too. + +Fri Oct 23 04:06:57 1998 Richard Earnshaw (rearnsha@arm.com) + + * machmode.h (mode_mask_array): No longer const. + * rtl.c (init_rtl): Fully initialize it if EXTRA_CC_MODES defined. + +Fri Oct 23 11:19:06 1998 Martin v. Löwis + + * frame.c: Somewhat explain `FDE'. + Suggested by Brendan Kehoe + +Fri Oct 23 00:56:11 1998 Jason Merrill + + * expr.c (pending_chain): Move up. + (save_expr_status): Do save pending_chain. + (restore_expr_status): And restore it. + * function.h (struct function): Add pending_chain. + +1998-10-23 Herman A.J. ten Brugge + + * reorg.c (relax_delay_slots): Fixed test for mostly_true_jump. The + did not match the code. + +Fri Oct 23 00:07:01 1998 Bernd Schmidt + + * regclass.c (regclass): Break out some code into new function + scan_one_insn, and into regclass_init. + (init_cost): New static variable, moved out of regclass. + (regclass_init): Initialize it here, not in . + (scan_one_insn): New static function, broken out of regclass. + * recog.c (apply_change_group): Break out some code into new + function insn_invalid_p. + (insn_invalid_p): New static fn, broken out of apply_change_group. + +Thu Oct 22 22:34:42 1998 Jim Wilson + + * reload1.c (reload_as_needed): When rewrite POST_INC, verify + reg_reloaded_contents matches incremented pseudo. + + * v850/v850.c (v850_reorg): Call alter_subreg. Delete subreg support. + +Fri Oct 23 11:11:56 1998 Michael Hayes + + * rtl.def (POST_MODIFY, PRE_MODIFY): New generalized operators for + addressing modes with side effects. These are currently + placeholders for the C4x target. + +Thu Oct 22 16:46:35 1998 Bernd Schmidt + + * loop.c (express_from): Make sure that when generating a PLUS of + a PLUS, any constant expression appears on the outermost PLUS. + +Thu Oct 22 15:46:23 1998 Per Bothner (bothner@cygnus.com) + + * Makefile.in (distdir-cvs, distdir-start): Clean up so it + works if "$(srcdir)" != ".". + +Wed Oct 21 19:23:59 1998 Jim Wilson + + * expmed.c (store_bit_field): If need to add a SUBREG, then remove + existing SUBREG if we can, otherwise abort. + +Wed Oct 21 09:58:51 1998 Mark Mitchell + + * c-common.c (c_apply_type_quals_to_decl): Don't crash when + `restrict' is applied to a non-pointer variable. + +Wed Oct 21 09:18:58 1998 Mark Mitchell + + * invoke.texi: Document -flang-isoc9x. + + * tree.h (TYPE_RESTRICT): New macro. + (TYPE_UNQUALIFIED): New manifest constant. + (TYPE_QUAL_CONST): Likewise + (TYPE_QUAL_VOLATILE): Likewise. + (TYPE_QUAL_RESTRICT): Likewise. + (tree_type): Add restrict_flag. Reduce count of free bits. + (tree_decl): Add pointer_alias_set. + (build_qualified_type): New function. + (build_type_variant): Define in terms of build_qualified_type. + * tree.c (set_type_quals): New function. + (make_node): Initializae DECL_POINTER_ALIAS_SET. + (build_type_attribute_variant): Use build_qualified_type and + set_type_quals. + (build_type_variant): Rename, and modify, to become... + (build_qualified_type): New function. + (build_complex_type): Use set_type_quals. + + * c-tree.h (C_TYPE_OBJECT_P): New macro. + (C_TYPE_FUNCTION_P): Likewise. + (C_TYPE_INCOMPLETE_P): Likewise. + (C_TYPE_OBJECT_OR_INCOMPLETE_P): Likewise. + (c_apply_type_quals_to_decl): New function. + (c_build_qualified_type): New function. + (c_build_type_variant): Define in terms of c_build_qualified_type. + (flag_isoc9x): Declare. + * c-typeck.c (qualify_type): Use c_build_qualified_type. + (common_type): Change to use TYPE_QUALS. + (comptypes): Likewise. + (convert_for_assignment): Likewise. + * c-aux-info.c (gen_type): Likewise. Deal with `restrict'. + * c-decl.c (flag_isoc9x): Define. + (c_decode_option): Handle -flang-isoc9x. + (grokdeclarator): Update to handle restrict. Use TYPE_QUALS, + c_build_qualified_type, etc. Use c_apply_type_quals_to_decl. + * c-lex.c (init_lex): Deal with restrict. + (init_lex): Don't treat restrict as a reserved word in + -traditional mode, or without -flang-isoc9x. + * c-lex.h (rid): Add RID_RESTRICT. + * c-parse.gperf (restrict, __restrict, __restrict__): Make + equivalent to RID_RESTRICT. + * c-parse.in (TYPE_QUAL): Update comment. + * c-common.c: Include rtl.h. + (c_find_base_decl): New function. + (c_build_type_variant): Rename, and modify, to become ... + (c_build_qualified_type): New function. + (c_apply_type_quals_to_decl): Likewise. + * toplev.c (documented_lang_options): Add -flang-isoc9x. + +Wed Oct 21 09:15:06 1998 Nick Clifton + + * config/arm/arm.h (TARGET_SWITCHES): Document arm specific + command line switches. + +Tue Oct 20 10:04:51 1998 Graham + + * reload.c (loc_mentioned_in_p): Add missing braces to bind + else to correct if. + +Mon Oct 19 16:34:05 1998 Tom Tromey + + * gcc.c (option_map): Added --classpath and --CLASSPATH. + +Tue Oct 20 10:59:02 1998 Gavin Romig-Koch + + * regclass.c (fix_register): Add error message. + * invoke.texi (-fcall-used-REG,-fcall-saved-REG): Note the + new error message. + +Tue Oct 20 10:12:17 1998 Kaveh R. Ghazi + + * c-decl.c (warn_missing_noreturn): New global variable. + (c_decode_option): Check for new flags -W{no-}missing-noreturn. + (finish_function): Implement missing noreturn warning. + + * c-tree.h (warn_missing_noreturn): Declare extern. + + * invoke.texi: Document new flags. + + * toplev.c (documented_lang_options): Add description. + +Tue Oct 20 22:16:11 1998 Michael Hayes + + * config/c4x/c4x.c (c4x_parallel_process): Disable until BCT + loop optimization stable for the C4x. + (c4x_rptb_info_t, c4x_dump, c4x_rptb_in_range, c4x_rptb_unjumped_loop, + c4x_rptb_find_comp_and_jump, c4x_rptb_loop_info_get, + c4x_rptb_emit_init, c4x_rptb_process): Deleted (superceded by BCT + loop optimization). + (c4x_address_conflict): Be more paranoid when packing a volatile + memref in a parallel load/store. + +Tue Oct 20 21:56:05 1998 Michael Hayes + + * config/c4x/c4x.md (repeat_block_top, repeat_block_end, + repeat_block_filler): Deleted. + (*ashlqi3_set, *ashrqi3_const_set, *ashrqi3_nonconst_clobber): + Condition code not set if destination register from 'c' class. + (*subbqi3_carry_clobber): Fix typo. + +1998-10-18 Herman A.J. ten Brugge + + * reorg.c (steal_delay_list_from_target) Check for insns that + modify the condition codes and effect the direction of the jump + in the sequence. + +Sat Oct 17 13:09:09 1998 Graham + + * function.c (purge_addressof_1): Replace call to + emit_insns_before() with emit_insn_before(). + +Mon Oct 19 19:34:03 1998 Mike Stump + + * libgcc2.c (__pure_virtual): Call __terminate instead of _exit. + +Mon Oct 19 13:26:24 1998 Bernd Schmidt + + * jump.c (sets_cc0_p): Compile only if HAVE_cc0. + +Mon Oct 19 11:40:56 1998 Jeffrey A Law (law@cygnus.com) + + * gcse.c (compute_hash_table): Correctly identify hard regs which are + clobbered across calls. + + * loop.c (scan_loop): Be more selective about what invariants are + moved out of a loop. + +Mon Oct 19 10:46:58 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Mon Oct 19 11:40:56 1998 Jeffrey A Law (law@cygnus.com) + + * libgcc2.c (eh_context_static): Do not call malloc to allocate the + static eh_context structure. + +Mon Oct 19 10:45:40 1998 Bernd Schmidt + + * combine.c (recog_for_combine): Lose PADDED_SCRATCHES arg. All + callers changed. + (try_combine): Don't update max_scratch. + * flow.c (max_scratch, num_scratch): Delete variables. + (life_analysis_1): Don't initialize max_scratch. + (propagate_block): Don't update max_scratch. + (mark_set_1): Don't increment num_scratch. + * regs.h (max_scratch): Delete declaration. + +Mon Oct 19 10:28:15 1998 Jeffrey A Law (law@cygnus.com) + + * reload1.c (reload_reg_free_before_p): Hack. Return 0 if EQUIV + is nonzero. This is temporary! + + * sched.c (update_flow_info): Handle death notes made invalid by + instruction splitting. Partially reverts Oct 15, 1998 patch. + * haifa-sched.c (update_flow_info): Likewise. + +Sun Oct 18 17:31:26 1998 Jeffrey A Law (law@cygnus.com) + + * function.c (uninitialized_vars_warning): Do not warn for a VAR_DECL + if it has a nonzero DECL_INITIAL. + +Sat Oct 17 23:18:08 1998 Kaveh R. Ghazi + + * Makefile.in (flow.o): Depend on recog.h. + + * cpplib.h (directive_table): Add missing initializiers. + (finclude): Change type of variable `bsize' to size_t. + + * cse.c (rtx_cost): Mark parameter `outer_code' with ATTRIBUTE_UNUSED. + + * dwarfout.h (dwarfout_label): Wrap prototype in macro RTX_CODE. + + * fix-header.c (lookup_std_proto): Cast the result of `strlen' to + `int' when comparing against one. + (cpp_file_line_for_message): Mark parameter `pfile' with + ATTRIBUTE_UNUSED. + (cpp_fatal): Mark parameter `pfile' with ATTRIBUTE_UNUSED. + + * flow.c: Include recog.h. + (sbitmap_copy): Cast arguments 1 & 2 of `bcopy' to (PTR). + + * function.c (thread_prologue_and_epilogue_insns): Mark parameter + `f' with ATTRIBUTE_UNUSED. + (reposition_prologue_and_epilogue_notes): Likewise. + + * genopinit.c (gen_insn): Cast argument of ctype functions to + `unsigned char'. + + * haifa-sched.c: Include recog.h. + (blockage_range): Cast result of UNIT_BLOCKED macro to (int) when + comparing against one. + + * libgcc2.a (__throw): Revert ATTRIBUTE_UNUSED change for now. + + * mips-tfile.c (parse_end): Cast the argument of ctype function to + `unsigned char'. + (parse_ent): Likewise. + (parse_input): Likewise. + + * optabs.c (init_libfuncs): Likewise. + + * protoize.c (find_rightmost_formals_list): Likewise. + + * recog.h (const_double_operand): Fix typo in prototype. + + * tlink.c (scan_linker_output): Cast the argument of ctype + function to `unsigned char'. + + * toplev.c (check_lang_option): Cast the result of `strlen' to + `int' when comparing against one. + +Sat Oct 17 13:09:09 1998 Graham + + * gcse.c (dump_cuid_table): Correct typo. + +Sat Oct 17 11:02:47 1998 Nick Clifton + + * toplev.c (display_help): Prepend '-m' to target specific + options. + (check_lang_option): Ignore text after end of first word of a + language specific option. + (display_help): Ignore empty target specific options, and if -W is + also specified on the command line then display undocumented + options. + + * invoke.texi: Document --help option. + +Sat Oct 17 02:26:03 1998 Bernd Schmidt + + * reload1.c (reg_used_by_pseudo): New static variable. + (choose_reload_regs): Initialize it. + Use it instead of testing spill_reg_order to determine whether a + pseudo is live in a hard register across the current insn. + Fix a typo in a reference to reload_reg_rtx. + + * flow.c (propagate_block): Replace code that computes and uses + regs_sometimes_live with simpler code that just walks the set of + currently live registers. + + * Makefile.in (insn-extract.o): Fix dependencies. + * genextract.c (main): Generate includes for insn-config.h and + recog.h. + Delete generation of declarations which are now in recog.h. + * genrecog.c (main): Delete generation of definitions which are + now in recog.c. + * local-alloc.c (block_alloc): Use extract_insn and the variables + it sets up instead of looking up values by insn_code. + * recog.c (recog_operand, recog_operand_loc, recog_dup_loc, + recog_dup_num): Define here instead of generating the definition in + genrecog.c. + (recog_n_operands, recog_n_dups, recog_n_alternatives, + recog_operand_mode, recog_constraints, recog_operand_address_p): + New variables. + (extract_insn): New function. + * recog.h (extract_insn): Declare function. + (which_alternative, recog_n_operands, recog_n_dups, + recog_n_alternatives, recog_operand_mode, recog_constraints, + recog_operand_address_p): Declare variables. + * regclass.c (n_occurrences): New static function. + * reload.c (n_occurrences): Delete function. + (find_reloads): Use extract_insn. + * reload.h (n_occurrences): Delete declaration. + +Sat Oct 17 01:17:51 1998 Jeffrey A Law (law@cygnus.com) + + * reload1.c (reload_as_needed): Fix test for when to call + update_eliminable_offsets. + +Fri Oct 16 20:40:50 1998 J"orn Rennecke + + Fix consistency problems with reg_equiv_{mem,address}; + Improve reload inheritance; + + * reload.c (reload_out_reg): New variable. + (loc_mentioned_in_p, remove_address_replacements): New functions. + (remove_replacements): Deleted. + (push_reload): Set reload_out_reg[i]. + When merging, also set reload_{in,out}_reg[i], and remove + duplicate address reloads. + (combine_reloads): Copy reload_out_reg[i]. + (find_reloads): Do make_memloc substitution also when + reg_equiv_memory_loc[regno] and num_not_at_initial_offset + are both nonzero. + Include *recog_operand_loc in commutativity operand changes. + Generate optional output reloads. + Delete reference to n_memlocs. Don't set *recog_operand_loc before + processing operands. Call make_memloc in reg_equiv_address code. + Set *recog_operand_loc only after processing operands, and only + if replace is true. Return a value. + When changing address reload types for operands that didn't get + reloaded, use RELOAD_FOR_OPADDR_ADDRESS for + RELOAD_FOR_INPADDR_ADDRESS / RELOAD_FOR_OUTADDR_ADDRESS reloads. + Don't emit USEs for pseudo SUBREGs when not replacing. + (find_reloads_address): Do make_memloc substitution also when + reg_equiv_memory_loc[regno] and num_not_at_initial_offset + are both nonzero. + (find_reloads_toplev): Likewise. + Call make_memloc in reg_equiv_address code. + (debug_reload_to_stream): Add code to output reload_out_reg. + (make_memloc): Delete local variable i, ifdefed out code, and + references to memlocs and n_memlocs. + (memlocs, n_memlocs): Delete. + (push_secondary_reload): Clear reload_out_reg. + (find_reloads_address_1): Provide memrefloc argument to all calls + to find_reloads_address. + In AUTO_INC code, handle non-directly addressable equivalences properly. + * reload.h (reload_out_reg, num_not_at_initial_offset): Declare. + (find_reloads): Add return type. + (remove_address_replacements, deallocate_reload_reg): Declare. + * reload1.c (num_not_at_initial_offset): No longer static. + (delete_address_reloads, delete_address_reloads_1): Likewise. + (deallocate_reload_reg): New function. + (spill_reg_stored_to): New array. + (eliminate_regs): Don't substitute from reg_equiv_memory_loc. + (eliminate_regs_in_insn): Move assignments of previous_offset and + max_offset fields, and recalculation of num_not_at_initial_offset + into new static function: + (update_eliminable_offsets) . + (reload_as_needed): Call update_eliminable_offsetss after calling + find_reloads. + Call forget_old_reloads_1 with contents of reloaded auto_inc + expressions if the actual addressing can't be changed to match the + auto_inc. + (choose_reload_regs): For inheritance, replace + reload_reg_free_before_p test with reload_reg_used_at_all test, and + remove stand-alone reload_reg_used_at_all test. + Use reload_out_reg to determine which reload regs have output reloads. + Treat reload_override_in more similar to inherited reloads. + Handle (subreg (reg... for inheritance. + For flag_expensive_optimizations, add an extra pass to remove + unnecessary reloads from known working inheritance. + Delete obsolete code for pseudos replaced with MEMs. + Handle inheritance from auto_inc expressions. + (emit_reload_insns): If reload_in is a MEM, set OLD to + reload_in_reg[j]. + Don't reload directly from oldequiv; if it's a pseudo with a + stack slot, use reload_in[j]. + Check that reload_in_reg[j] is a MEM before replacing reload_in + from reg_reloaded_contents. + Include non-spill registers in reload inheritance processing. + Also try to use reload_out_reg to set spill_reg_store / + reg_last_reload_reg. + In code to set new_spill_reg_store, use single_set to find out if + there is a single set. + Add code that allows to delete optional output reloads. + Add code to allow deletion of output reloads that use no spill reg. + At the end, set reload_override_in to oldequiv. + Also call delete_output_reload if reload_out_reg is equal to old + in oldequiv code. + Add code to call delete_output_reload for stores with no matching load. + Set / use spill_reg_stored_to. + Handle case where secondary output reload uses a temporary, but + actual store isn't found. + When looking for a store of a value not loaded in order to call + delete_output_reload, count_occurences should return 0 for no + loads; but discount inherited input reloadill_reg_stored_to. + Do checks for extra uses of REG. Changed all + callers. + Use delete_address_reloads. + (reload): Take return value of find_reloads into account. + If a no-op set needs more than one reload, delete it. + (reload_reg_free_before_p): RELOAD_FOR_INPUT + can ignore RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_INPADDR_ADDRESS + for the same operand. + (clear_reload_reg_in_use): Check for other reloads that keep a + register in use. + (reload_reg_free_for_value_p): handle RELOAD_FOR_OPERAND_ADDRESS / + RELOAD_FOR_OPADDR_ADDR. + Take into account when an address address reload is only needed + for the address reload we are considering. + (count_occurrences): Use rtx_equal_p for MEMs. + (inc_for_reload): Return instruction that stores into RELOADREG. + New argument two, IN, and rtx. Changed all callers. + (calculate_needs_all_insns, reload_as_needed): + Don't clear after_call for a CLOBBER. + Keep track of how many hard registers need to be copied from + after_call, and don't clear after_call before we have seen + that much copies, or we see a different instruction. + +Fri Oct 16 10:58:23 1998 Jeffrey A Law (law@cygnus.com) + + * flow.c (find_basic_blocks_1): Do not delete unreachable blocks + after reload has completed. + +Fri Oct 16 17:26:10 1998 Dave Brolley + + * cpplib.c (cpp_get_token): Replace whitespace that occurs between + a macro name and the next token with a single blank if that whitespace + is in a macro buffer and the next token is not '('. + +Fri Oct 16 15:44:02 1998 Dave Brolley + + * cccp.c (rescan): Handle multibyte chartacters ending in backslash. + (rescan): Ditto. + (skip_if_group): Ditto. + (skip_to_end_of_comment): Ditto. + (macarg1): Ditto. + (discard_comments): Ditto. + (change_newlines): Ditto. + +Fri Oct 16 15:26:24 1998 Dave Brolley + + * c-lex.c (yylex): Fix unaligned access of wchar_t. + +Fri Oct 16 10:47:53 1998 Nick Clifton + + * config/arm/arm.h (TARGET_SWITCHES): Add --help documentation. + (TARGET_OPTIONS): Add --help documentation. + +Fri Oct 16 11:49:01 1998 Kaveh R. Ghazi + + * rtl.h (sets_cc0_p): Revert Oct 14 ATTRIBUTE_NORETURN change. + +Fri Oct 16 07:08:46 1998 Bruce Korb + + * fixinc/* Moved in from ../contrib directory in preparation + for integrating it into the normal build process. In particular, + fixinc/Makefile.in must be config-ed into the build directory + as fixinc/Makefile. Proposed patches to ./Makefile.in and + ./configure.in will be "in the mail" momentarily. + +Fri Oct 16 08:13:46 1998 David S. Miller + + * cse.c (cse_basic_block): Fixup hash flushing loop so we do not + accidently walk into the free list. Comment how that can happen. + (invalidate): Fix indentation. + +Thu Oct 15 23:53:29 1998 Bernd Schmidt + Jeffrey A Law (law@cygnus.com) + + * flow.c (life_analysis_1): Do not clobber regs_ever_live after + reload. Never perform rescans of the insn chain after reload. + (propagate_block): Do not delete insn or create new autoinc addressing + modes after reload. + + * jump.c (jump_optimize): Unconditionally use the code that was + previously conditional on PRESERVE_DEATH_INFO_REGNO_P. + * reload1.c (reload): When reloading is finished, delete all + REG_DEAD and REG_UNUSED notes. + (emit_reload_insns): Delete all code that was conditional on + PRESERVE_DEATH_INFO_REGNO_P. + (no_longer_dead_regs): Delete variable. + (reload_cse_delete_death_notes): Delete function. + (reload_cse_no_longer_dead): Delete function. + (reload_cse_regs_1): Delete all code to handle deletion of death + notes. + (reload_cse_noop_set_p): Likewise. + (reload_cse_simplify_set): Likewise. + (reload_cse_simplify_operands): Likewise. + (reload_cse_move2add): Likewise. + * reorg.c (used_spill_regs): Delete declaration. + (max_label_num_after_reload): Delete declaration. + (find_dead_or_set_registers): Don't assume that spill regs are + dead at a CODE_LABEL. + * rtlanal.c (dead_or_set_regno_p): Death notes are always accurate, + even after reload. + * sched.c (sched_analyze_insn): Likewise. + (update_flow_info): Likewise. + * haifa-sched.c (sched_analyze_insn): Likewise. + (update_flow_info): Likewise. + * tm.texi (PRESERVE_DEATH_INFO_REGNO_P): Delete documentation. + * toplev.c (max_label_num_after_reload): Delete variable. + (rest_of_compilation): Don't set max_label_num_after_reload. + Call life_analysis after reload_cse_regs if optimizing. + * config/gmicro/gmicro.h: Delete comment referring to + PRESERVE_DEATH_INFO_REGNO_P. + * config/i386/i386.h: Likewise. + * config/m88k/m88k.h: Likewise. + * config/m32r/m32r.h (PRESERVE_DEATH_INFO_REGNO_P): Delete definition. + * config/sh/sh.h: Likewise. + +Thu Oct 15 19:48:41 1998 David Edelsohn + + * loop.c (strength_reduce): Restore marking bct_p as + ATTRIBUTE_UNUSED. + * rs6000.c (optimization_options): Change #ifdef HAIFA to + HAVE_decrement_and_branch_on_count. + (small_data_operand): Remove TARGET_ELF condition for marking + parameters ATTRIBUTE_UNUSED. + +Thu Oct 15 11:45:51 1998 Robert Lipe + + * config/i386/sco5.h (MAX_OFILE_ALIGNMENT): Define. + (SELECT_SECTION): Resync with svr4.h. + +Thu Oct 15 12:42:13 1998 David Edelsohn + + * loop.c (strength_reduce): Undo Oct 14 change marking bct_p + ATTRIBUTE_UNUSED. + +Thu Oct 15 00:57:55 1998 Robert Lipe + + * c-pragma.c (handle_pragma_token): Test for null tree before + dereferencing TREE_CODE. + +Thu Oct 15 17:36:48 1998 Michael Hayes + + * config/c4x/c4x.c: Convert to use GEN_INT. + (c4x_parallel_process): Rework to handle new repeat loop structure. + + * config/c4x/c4x.md: Convert to use GEN_INT. + (rptb_end): Convert to use GE test. Replace uses with clobbers. + (decrement_and_branch_on_count): Likewise. + + * config/c4x/c4x.h (REPEAT_BLOCK_PROCESS): Deleted hook now that + loop.c has the desired functionality. + (rc_reg_operand): New prototype. + + * config/c4x/t-c4x: Can now build all front ends. + +Wed Oct 14 23:27:08 1998 Didier FORT (didier.fort@fedex.com) + + * fixincludes: Fix up rpc/{clnt,svr,xdr}.h for SunOS. + +Wed Oct 14 22:13:28 1998 Joel Sherrill (joel@OARcorp.com) + + * Makefile.in (stmp-fixinc): Do not install assert.h if not desired. + * config/t-rtems: Do not install assert.h -- use newlib's. + +Wed Oct 14 21:57:08 1998 J"orn Rennecke + + * combine.c (combine_instructions): When finished, call init_recog. + * regmove.c (optimize_reg_copy_3): Reject volatile MEMs. + +Wed Oct 14 16:10:22 1998 Per Bothner + + * toplev.c: If flag_syntax_only, don't open or write assembler file. + +Wed Oct 14 13:26:05 1998 Kaveh R. Ghazi + + * cppalloc.c (memory_full): Mark function prototype with + ATTRIBUTE_NORETURN. + + * demangle.h (collect_exit): Likewise. + + * fix-header.c (v_fatal, fatal): Likewise. + + * gcc.c (pfatal_with_name, pfatal_pexecute, fatal, fancy_abort): + Likewise. + + * gcov.c (print_usage): Likewise. + + * genattr.c (fatal, fancy_abort): Likewise. + + * genattrtab.c (fatal, fancy_abort): Likewise. + + * gencodes.c (fatal, fancy_abort): Likewise. + + * genconfig.c (fatal, fancy_abort): Likewise. + + * genemit.c (fatal, fancy_abort): Likewise. + + * genextract.c (fatal, fancy_abort): Likewise. + + * genflags.c (fatal, fancy_abort): Likewise. + + * genopinit.c (fatal, fancy_abort): Likewise. + + * genoutput.c (fatal, fancy_abort): Likewise. + + * genpeep.c (fatal, fancy_abort): Likewise. + + * genrecog.c (fatal, fancy_abort): Likewise. + + * libgcc2.c (__eprintf, __default_terminate, __sjthrow, + __sjpopnthrow, __throw): Likewise. + + * objc/objc-act.c (objc_fatal): Likewise. + + * protoize.c (usage, aux_info_corrupted, + declare_source_confusing): Likewise. + + * rtl.c (dump_and_abort): Likewise. + + * rtl.h (sets_cc0_p): Likewise. + + * toplev.c (float_signal, pipe_closed): Likewise. + +1998-10-14 Andreas Schwab + + * dwarf2out.c (expand_builtin_dwarf_reg_size): Look at all ranges + when generating the decision tree for the general case. + + * config/m68k/m68k.h (HARD_REGNO_MODE_OK): Don't accept modes + wider that 12 bytes in fpu regs or wider than 8 byte in fpa regs. + +Wed Oct 14 11:14:02 1998 Kaveh R. Ghazi + + * Makefile.in (sched.o): Depend on recog.h. + + * alias.c (REG_BASE_VALUE): Cast the result of REGNO() macro to + (unsigned) when comparing against one. + (find_base_value): Likewise. + (record_base_value): Cast variable `regno' to (unsigned) when + comparing against one. Cast the result of REGNO() macro to + (unsigned) when comparing against one. + (memrefs_conflict_p): Change type of variables `r_x' and `r_y' to + unsigned. + (init_alias_analysis): Add unsigned variable `ui'. Use it as loop + variable where an unsigned index is needed. + + * caller-save.c (init_caller_save): Cast `-1' to (enum insn_code) + before comparing against one. + + * collect2.c: Add prototypes for functions `error', `fatal' and + `fatal_perror'. Make these functions take variable arguments + instead of faking it with a fixed number of args. + (write_c_file_stat): Cast the argument of ctype macro to (unsigned + char). + + * combine.c (can_combine_p): Mark parameter `pred' with + ATTRIBUTE_UNUSED. + (find_split_point): Cast variable `src' to (unsigned + HOST_WIDE_INT) when comparing against one. + (simplify_rtx): Cast 1 to (unsigned HOST_WIDE_INT) in shift. + (simplify_logical): Likewise. + (force_to_mode): Cast result of INTVAL() macro to (unsigned + HOST_WIDE_INT) when comparing against one. Cast 1 to (unsigned + HOST_WIDE_INT) in shift. + (simplify_and_const_int): Cast result of INTVAL() macro to + `unsigned HOST_WIDE_INT' when comparing against one. + (merge_outer_ops): Cast variable const0 to `unsigned + HOST_WIDE_INT' when comparing against the result of + GET_MODE_MASK() macro. + (simplify_comparison): Likewise for variable `c0'. Cast variable + `const_op' to `unsigned HOST_WIDE_INT' when comparing against + one. Cast `1' to `unsigned HOST_WIDE_INT' in shift. Cast the + result of `GET_MODE_MASK()/2' to `HOST_WIDE_INT' when comparing + against one. Cast `1' to `unsigned HOST_WIDE_INT' in shift. Cast + result of INTVAL() macro to `unsigned HOST_WIDE_INT' when + comparing against one. + (distribute_notes): Wrap variable `cc0_setter' in macro `HAVE_cc0'. + + config/mips/mips.c (gen_int_relational): Cast result of INTVAL() + macro to `unsigned HOST_WIDE_INT' when comparing against one. + (output_block_move): Cast `sizeof' expression to (int) when + comparing against one. + (function_arg): Cast BITS_PER_WORD to `unsigned' when comparing + against one. + (save_restore_insns): Cast `base_offset' to `long' to match format + specifier in fprintf. + + * config/mips/mips.h (Pmode): Cast the result of `Pmode' macro + to `enum machine_mode'. + + * flow.c (life_analysis_1): Remove unused variable `insn'. + + * gcc.c (translate_options): Move variables `j' and `k' into the + scope in which they are used. Change their types to `size_t'. + (set_spec): Cast the argument of ctype macro to `unsigned char'. + (read_specs): Likewise. + (process_command): Cast `sizeof' to (int) when comparing against one. + (do_spec_1): Cast the argument of ctype macro to `unsigned char'. + (handle_braces): Cast both sides of `==' expression to `long' to + ensure sign matching. + (main): Cast variable `i' to `int' when comparing against one. + + * gcov-io.h (__fetch_long): Change type of parameter `bytes' from + int to size_t. Cast variable `i' to size_t when comparing against + one. + + * genattrtab.c (convert_set_attr_alternative): Remove unused + parameter `insn_code'. All callers changed. + (convert_set_attr): Likewise. + + * genrecog.c (add_to_sequence): Cast result of XVECLEN() macro to + size_t when comparing against one. Likewise for variable `len'. + + * global.c (global_alloc): Cast variable `max_regno' to size_t + when comparing against one. Likewise for variable `max_allocno'. + + * jump.c (sets_cc0_p): Mark parameter `x' with ATTRIBUTE_UNUSED. + + * local-alloc.c (validate_equiv_mem_from_store): Mark parameter + `set' with ATTRIBUTE_UNUSED. + (find_free_reg): Cast `sizeof' expression to (int) when comparing + against one. + + * loop.c (count_loop_regs_set): Remove unused variable `dest'. + (strength_reduce): Mark parameter `bct_p' with ATTRIBUTE_UNUSED. + (get_condition): Cast variable `const_val' to `unsigned + HOST_WIDE_INT' when comparing against one. Cast unsigned + expression to HOST_WIDE_INT when comparing against one. + (insert_loop_mem): Mark parameter `data' with ATTRIBUTE_UNUSED. + (load_mems_and_recount_loop_regs_set): Cast variable `nregs' to + `unsigned' when comparing against one. + + * protoize.c (is_id_char): Change type of parameter `ch' to + unsigned char. + (munge_compile_params): Cast argument of ctype macro to (const + unsigned char). + (process_aux_info_file): Cast variable `aux_info_size' to int when + comparing against one. + (forward_to_next_token_char): Cast argument of ctype macro to + `const unsigned char'. + (edit_formals_lists): Likewise. + (find_rightmost_formals_list): Likewise. + (add_local_decl): Likewise. + (add_global_decls): Likewise. + (edit_fn_definition): Likewise. + (do_cleaning): Likewise. + (scan_for_missed_items): Likewise. + (edit_file): Cast variable `orig_size' to (int) when comparing + against one. + (main): Cast argument of ctype macro to `const unsigned char'. + + * recog.c (const_int_operand): Mark parameter `mode' with + ATTRIBUTE_UNUSED. + + * regclass.c (record_reg_classes): Change type of variable `c' to + `unsigned char'. Cast `char' array index to `unsigned char'. + + * reload.c (push_secondary_reload): Cast argument to + REG_CLASS_FROM_LETTER() macro to `unsigned char'. + + * reload1.c (calculate_needs): Cast `char' array index to + `unsigned char'. + (set_label_offsets): Change type of variable `i' to unsigned int. + Cast result of XVECLEN() macro to unsigned when comparing against + one. + (mark_not_eliminable): Change type of variable `i' to unsigned. + (order_regs_for_reload): Likewise. Cast `max_regno' to unsigned + when comparing against one. + (reload_as_needed): Cast macro NUM_ELIMINABLE_REGS to (int) when + comparing against one. + (choose_reload_regs): Hide unused label `fail'. + (reload_cse_simplify_operands): Cast `char' array index to + `unsigned char'. + (reload_combine_note_store): Mark parameter `set' with + ATTRIBUTE_UNUSED. Cast UNITS_PER_WORD to unsigned when comparing + against one. + (reload_cse_move2add): Remove unused variable `src2'. + + * sched.c: Include recog.h. + (sched_note_set): Remove unused parameter `b'. All callers + changed. + (split_hard_reg_notes): Likewise for parameter `orig_insn'. + (blockage_range): Cast result of UNIT_BLOCKED() macro to (int) + when comparing against one. + + * stupid.c (stupid_find_reg): Mark parameter `changes_size' with + ATTRIBUTE_UNUSED. Cast `sizeof' expression to (int) when + comparing against one. + + * unroll.c (precondition_loop_p): Remove unused parameter + `loop_end'. All callers changed. + +Tue Oct 13 22:12:11 1998 Bernd Schmidt + + * reload1.c (maybe_fix_stack_asms): New static function. + (reload): Call it. + + * reload.h (compute_use_by_pseudos): Declare. + + * reload1.c (spilled_pseudos, insns_need_reload): New variables. + (something_needs_reloads): Delete variable. + (finish_spills): New function. + (compute_use_by_pseudos): New function. + + (delete_caller_save_insns): Lose argument FIRST. All callers changed. + Use the reload_insn_chain instead of walking the rtl directly. + + (reload): Allocate and free spilled_pseudos. + Ensure that all calls of spill_hard_reg are followed by a call to + finish_spills. + Use the insns_need_reload list instead of something_needs_reloads + to find out if reload_as_needed must be called. + Clear unused_insn_chains at the end. + + (calculate_needs_all_insns): Lose FIRST parameter. All callers + changed. + Delete code to keep track of current basic block. + Walk reload_insn_chain instead of the rtl structure. Build the + insns_need_reload chain. + Remember which insns need reloading/elimination by setting the + appropriate fields in struct insn_chain, not by putting modes on the + insn. + + (calculate_needs): Lose THIS_BLOCK arg. Accept arg CHAIN instead of + arg INSN. All callers changed. + Delete declaration of struct needs. + Don't set something_needs_reloads. + Record insn needs in the CHAIN argument. + + (spill_hard_reg): Record the affected pseudos in spilled_pseudos. + + (reload_as_needed): Lose FIRST arg. All callers changed. + Walk the reload_insn_chain instead of the rtx structure. + Delete code to keep track of current basic block. + Rename one of the NEXT variables to OLD_NEXT. + + (allocate_reload_reg): Accept arg CHAIN instead of arg INSN. All + callers changed. + (choose_reload_regs): Likewise. + + (emit_reload_insns): Replace INSN and BB args with arg CHAIN. All + callers changed. + + * caller-save.c (MOVE_MAX_WORDS): New macro. Use it throughout + instead of (MOVE_MAX / UNITS_PER_WORD) computation. + (hard_regs_live, hard_regs_need_restore): Delete variables. + (n_regs_saved): Now static. + (referenced_regs, this_insn_sets): New variables. + + (setup_save_areas): Restructure the code a bit. + + (restore_referenced_regs): Delete function. + (mark_referenced_regs): New function, similar to the old + restore_referenced_regs, but mark registers in referenced_regs. + + (clear_reg_live): Delete function. + (mark_set_regs): Renamed from set_reg_live. All callers changed. + Only mark registers in this_insn_sets. + + (save_call_clobbered_regs): Rework this function to walk the + reload_insn_chain instead of using the list of instructions directly. + Delete code to keep track of register lives, compute live regs on the + fly from information in the chain. + Instead of calling restore_referenced_regs, use mark_referenced_regs, + then walk the set it computes and call insert_restore as appropriate. + + (insert_restore): Lose INSN and BLOCK args. Add CHAIN arg. All + callers changed. + Restructure the code a bit. Test hard_regs_saved instead of + hard_regs_need_restore. + (insert_save): Lose INSN and BLOCK args. Add CHAIN and TO_SAVE + args. All callers changed. + Restructure the code a bit. Use TO_SAVE to determine which regs to + save instead of more complicated test. + (insert_one_arg): Lose INSN and BLOCK args. Add CHAIN arg. All + callers changed. + Create a new insn_chain structure for the new insn and place it + into the chain. + + * rtl.texi: Update documentation to reflect that reload no longer + puts modes on the insns. + +1998-10-14 Andreas Schwab + + * function.c (purge_addressof_1): Force the first argument of a + CALL insn to memory. + +Wed Oct 14 00:38:40 1998 Jeffrey A Law (law@cygnus.com) + + * rtl.h: Delete duplicate prototypes. Add some missing + prototypes. + * rtlanal.c: (for_each_rtx): Formatting tweak. + +1998-10-13 Herman A.J. ten Brugge + + * real.c (emdnorm and etoasc): Disable round to even for c4x target + to be compatible with TI compiler. + + * Makefile.in (USER_H): Add va-c4x.h to definition. + +Tue Oct 13 23:03:37 1998 Richard Henderson + + * function.c (purge_addressof_1): Fix typo in inequality: do + bitfield optimization for equal mode sizes. + * expmed.c (store_bit_field): Don't take subregs of subregs in + the movstrict case. Tidy a potential problem in the multi-word case. + (extract_bit_field): Likewise. + +Tue Oct 13 22:12:11 1998 Bernd Schmidt + + * flow.c (find_basic_blocks): Emit NOPs after normal calls in this + function. + Compute max_uid_for_flow by calling get_max_uid after the scan. + (find_basic_blocks_1): Don't emit NOPs here. + +Tue Oct 13 22:05:49 1998 Richard Henderson + + * alias.c (base_alias_check): Accept new args for the modes of the + two references. Use them to determine if an AND can overlap. Update + all callers. + (memrefs_conflict_p): Assume sizes are aligned, and uses them + to determine if an AND can overlap. + +Tue Oct 13 17:51:04 1998 Jim Wilson + + * config/m68k/m68k.h (HARD_REGNO_MODE_OK): For FP regs, add REGNO >= 16 + check. Add comment to document problems with TARGET_SUN_FPA version + of this macro. + * config/m68k/m68k.md (movxf+1): Support 'r'/'r' moves. + +Tue Oct 13 17:46:18 1998 Kaveh R. Ghazi + + * Makefile.in (gencheck.o): Depend on gansidecl.h. + + * c-common.c (print_char_table): Add missing initializers. + (scan_char_table): Likewise. + (time_char_table): Likewise. + + * c-decl.c (c_decode_option): Mark parameter `argc' with + ATTRIBUTE_UNUSED. + (declare_parm_level): Mark parameter `definition_flag' with + ATTRIBUTE_UNUSED. + + * c-lex.c (readescape): Use `(unsigned)1' in shift. + (yylex): Likewise. Cast `sizeof' to an (int) when comparing + against one. + + * calls.c (store_one_arg): Remove unused parameter `fndecl'. All + callers changed. + (emit_call_1): Mark parameters `fndecl' and `funtype' with + ATTRIBUTE_UNUSED. + (expand_call): Cast result of MIN() to (unsigned int) when + comparing against an unsigned value. + + * cccp.c (pcfinclude): Remove unused parameter `limit'. All + callers changed. + (make_definition): Remove unused parameter `op'. All callers + changed. + (create_definition): Cast REST_EXTENSION_LENGTH to (long) when + comparing against the result of pointer arithmetic. + + * config/mips/mips.h (FUNCTION_ARG_BOUNDARY): Cast to (unsigned) + when comparing against one. + + * dwarf2out.c (dwarf2out_frame_debug): Cast REGNO() and + HARD_FRAME_POINTER_REGNUM to (unsigned) when comparing against + one. + (output_die): Move variable `i' into the scope in which it is + used. Change its type to `unsigned'. + (output_die): Cast the result of `strlen' to (int) when passing it + to ASM_OUTPUT_ASCII(). + (output_pubnames): Likewise. + (output_line_info): Likewise. + + * emit-rtl.c (global_rtl): Add missing initializers. + + * explow.c (promote_mode): Mark parameter `for_call' with + ATTRIBUTE_UNUSED. + + * expmed.c (expand_shift): Cast the result of GET_MODE_BITSIZE to + `unsigned HOST_WIDE_INT' when comparing against one. + (synth_mult): Change type of variable `cost' to int. + (emit_store_flag): Use `(unsigned HOST_WIDE_INT) 1' in shift. + + * expr.c (copy_blkmode_from_reg): Cast BITS_PER_WORD to (unsigned) + when comparing against one. + (get_inner_reference): Change variable `alignment' to unsigned. + (expand_expr): Cast the result of GET_MODE_ALIGNMENT to (unsigned + int) when comparing against one. + (expand_builtin_setjmp): Change type of variable `i' to size_t. + + * fold-const.c (div_and_round_double): Cast BASE to + (HOST_WIDE_INT) when comparing against one. + + * gencheck.c: Include gansidecl.h. + (main): Mark parameter `argv' with ATTRIBUTE_UNUSED. + + * optabs.c (gen_cond_trap): Mark parameters `code', `op2' and + `tcode' with ATTRIBUTE_UNUSED. + + * real.c (edivm): Cast constant value to (unsigned long) in + expression compared against an unsigned value. + + * stmt.c (expand_return): Cast BITS_PER_WORD to (unsigned) when + comparing against one. + (expand_end_case): Cast CASE_VALUES_THRESHOLD to (unsigned int) + when comparing against one. + + * stor-layout.c (mode_for_size): Cast MAX_FIXED_MODE_SIZE to + (unsigned int) when comparing against one. Likewise for + GET_MODE_BITSIZE. + (smallest_mode_for_size): Likewise. + (save_storage_status): Mark parameter `p' with ATTRIBUTE_UNUSED. + (restore_storage_status): Likewise. + + * toplev.c (debug_args): Add missing initializer. + (f_options): Spelling correction. Add missing initializers. + (documented_lang_options): Likewise. + (debug_end_source_file): Mark parameter `lineno' with + ATTRIBUTE_UNUSED. + + * tree.c (valid_machine_attribute): Mark parameters `attr_args', + `decl' and `type' with ATTRIBUTE_UNUSED. + + * varasm.c (decode_reg_name): Cast `sizeof' expression to (int) + when comparing against one. + (assemble_variable): Mark parameter `top_level' with + ATTRIBUTE_UNUSED. + (assemble_external_libcall): Mark parameter `fun' with + ATTRIBUTE_UNUSED. + (output_constant_pool): Mark parameters `fnname' and `fndecl' with + ATTRIBUTE_UNUSED. + +Tue Oct 13 12:51:04 1998 Nick Clifton + + * config/v850/lib1funcs.asm (_udivsi3): Add .type declaration. + Replace use of r5 with use of r19. + + * config/v850/v850.h (LINK_POINTER_REGNUM): Define. + + * config/v850/v850.c (compute_register_save_size): Allow for the + fact that helper functions save all registers, not just those used + by the function. + + Replace constant 31 with macro LINK_POINTER_REGNUM. + + * config/v850/v850.md: Use 'indirect_operand' rather than + 'memory_operand' for bit test/set/clear patterns. + +Tue Oct 13 11:49:14 1998 Jason Merrill + + * mips/iris6.h (ASM_OUTPUT_WEAK_ALIAS): Call ASM_GLOBALIZE_LABEL. + * varasm.c (assemble_start_function et al): Don't call + ASM_GLOBALIZE_LABEL for weak symbols. + +Tue Oct 13 11:37:45 1998 Nick Clifton + + * cse.c (equiv_constant): Check for NULL return from + gen_lowpart_if_possible(). + +Tue Oct 13 11:24:51 1998 Jeffrey A Law (law@cygnus.com) + + * mn10200.md (addsi3, subsi3, negsi2): Only allow register operands. + + * collect2.c (main): Pass -EL/-EB through to the compiler. + +1998-10-12 Herman A.J. ten Brugge + + * expr.c (push_block): Handle targets where the stack grows + to higher addresses, but args grow to lower addresses and + ACCUMULATE_OUTGOING_ARGS is not defined. + +Tue Oct 13 08:00:52 1998 Catherine Moore + + * config/v850/v850.c (print_operand): Extend meaning + of 'c' operands to support .vtinherit. + +Tue Oct 13 21:38:35 1998 Michael Hayes + + * config/c4x/c4x.c: Convert to gen_rtx_FOO. + Added ATTRIBUTE_UNUSED to unused function arguments. + (rc_reg_operand): New predicate. + (c4x_rptb_insert): New function. + (c4x_rptb_nop_p): Recognize modified rptb_top pattern. + (c4x_optimization_options): New function. + + * config/c4x/c4x.md: Convert to gen_rtx_FOO. + (decrement_and_branch_on_count): New pattern. + (rptb_top): Modified pattern to work with BCT optimization. + + * config/c4x/c4x.h (RC_REG): New register class. + (rc_reg_operand): Define prototype. + (IS_RC_REG): New macro. + (IS_RC_OR_PSEUDO_REG): New macro. + (IS_RC_OR_PSEUDO_REGNO): New macro. + (OPTIMIZATION_OPTIONS): Define. + +Mon Oct 12 19:57:34 1998 Jason Merrill + + * collect2.c (extract_init_priority): No priority is 65535. + +Mon Oct 12 12:10:37 1998 Alexandre Oliva + + * Makefile.in (build_tooldir): new variable, same as old + $(tooldir), but without depending on $(libdir)/$(unlibsubdir) + (GCC_FOR_TARGET): add -B$(build_tooldir)/bin/ + (bootstrap, bootstrap2, bootstrap3, bootstrap4): ditto + + * configure.in (gxx_include_dir): set default based on unlibsubdir + * Makefile.in (tooldir): ditto + (cccp.o, cpplib.o): use unlibsubdir implicitly through + gxx_include_dir, includedir and tooldir + (protoize.o, unprotoize.o): ditto + +Mon Oct 12 10:50:44 1998 Nick Clifton + + * config/arm/arm.md: Replace (reg 24) with (reg:CC 24). + + * config/arm/thumb.c (thumb_override_options): Add warning about + PIC code not being supported just yet. + +Sun Oct 11 16:49:15 EDT 1998 John Wehle (john@feith.com) + + * flow.c: Update comment. + (notice_stack_pointer_modification): New static function. + (record_volatile_insns): Use it. + (mark_regs_live_at_end): Mark the stack pointer as alive + at the end of the function if current_function_sp_is_unchanging + is set. + (life_analysis_1): Set current_function_sp_is_unchanging. + * function.c: Define it. + (init_function_start): Initialize it. + * output.h: Declare it. + * reorg.c (fill_simple_delay_slots, dbr_schedule): Mark + the stack pointer as alive at the end of the function if + current_function_sp_is_unchanging is set. + * i386.c (ix86_epilogue): Optimize the restoring + of the stack pointer. + +Mon Oct 12 01:22:53 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sun Oct 11 23:04:30 1998 Robert Lipe + + * c-pragma.c (handle_pragma_token): If passed a token instead + of a tree, use that as the pack value. + +Sun Oct 11 14:21:14 1998 Mark Mitchell + + * flow.c (find_basic_blocks_1): Fix prototype. + +Sun Oct 11 05:03:41 1998 Ken Raeburn + + * tree.h (DECL_NO_CHECK_MEMORY_USAGE): New macros. + (struct tree_decl): New fields no_check_memory_usage. + * c-common.c (enum attrs): Add A_NO_CHECK_MEMORY_USAGE. + (init_attributes): Register it as a new attribute. + (decl_attributes): Set flags on functions given that attribute. + * c-decl.c (duplicate_decls): Merge new attribute. + * expr.h (current_function_check_memory_usage): Declare new var. + * calls.c, expr.c, function.c, stmt.c, alpha.c, clipper.c, m88k.c, + pa.c, sparc.c: Replace uses of flag_check_memory_usage with + current_function_check_memory_usage. + * function.h: Add field to struct function. + * function.c (current_function_check_memory_usage): Define it. + (push_function_context_to, pop_function_context_from): Save and + restore it. + (expand_function_start): Set it, based on global flag and function + attribute. + + * expr.c (expand_expr, case VAR_DECL): In memory-checking code, do + check non-automatic variables, to permit detection of writes to + read-only locations in embedded systems without memory management. + * calls.c (store_one_arg): Use ARGS_SIZE_RTX to get size of argument + when emitting chkr_set_right_libfunc call, even if the argument is + BLKmode or variable-sized; don't abort. + + * optabs.c (init_optabs): Create Checker and __cyg_profile_* + symbols in Pmode, not VOIDmode. + +Sun Oct 11 01:03:05 1998 Zack Weinberg + + * cppexp.c: When forcing unsigned comparisons, cast both sides + of the operation. + + * cpphash.h: Move static declaration of hashtab[]... + * cpphash.c: ...here. + + * cpplib.c: Cast difference of two pointers to size_t before + comparing it to size_t. Cast signed to unsigned + before comparing to size_t. (FIXME: struct argdata should use + unsigned buffer sizes.) + * cpplib.h (struct cpp_reader): Declare token_buffer_size as + unsigned int. (CPP_WRITTEN): Cast return value to size_t. + (CPP_RESERVE): Parenthesize N for evaluation order, cast to + size_t before comparison. + +Sun Oct 11 00:15:29 1998 Jeffrey A Law (law@cygnus.com) + + * flow.c (find_basic_blocks): Delete "live_reachable_p" argument. + (find_basic_blocks_1): Similarly. + * output.h (find_basic_blocks): Fix prototype. + * gcse.c, toplev.c: Don't pass "live_reachable_p" argument to + find_basic_blocks anymore. + +Sat Oct 10 22:00:34 1998 Richard Henderson + + * basic-block.h (EXECUTE_IF_SET_IN_SBITMAP): New macro. + (sbitmap_free, sbitmap_vector_free): New macros. + * output.h (rtl_dump_file): Declare. + +Sat Oct 10 17:01:42 1998 Jeffrey A Law (law@cygnus.com) + + * regmove.c (optimize_reg_copy_3): Honor TRULY_NOOP_TRUNCATION. + +Fri Oct 9 22:08:05 1998 Kaveh R. Ghazi + + * fp-bit.c (SFtype): Don't implicitly use int in declaration. + (DFtype): Likewise. + (_fpdiv_parts): Remove unused parameter `tmp', all callers changed. + (divide): Remove unused variable `tmp'. + (si_to_float): Cast numeric constant to (SItype) before comparing + it against one. + +Fri Oct 9 16:03:19 1998 Graham + + * flow.c (print_rtl_with_bb): Changed type of in_bb_p to match use. + * gcc.c (add_preprocessor_option): Correct typo when allocating + memory, sizeof() argument had one too many `*'. + (add_assembler_option): Likewise. + (add_linker_option): Likewise. + * gcov.c (output_data): Likewise. + * local-alloc.c (memref_used_between_p): Likewise. + (update_equiv_regs): Likewise. + * loop.c (strength_reduce): Likewise. + * reg-stack.c (record_asm_reg_life): Likewise. + (subst_asm_stack_reg): Likewise. + * reorg.c (dbr_schedule): Likewise. + +Fri Oct 9 15:57:51 1998 Bernd Schmidt + + * flow.c (life_analysis_1): Break out some functions. + (find_basic_blocks_1): Likewise. Also move some variables out and + make them static. + Rename NONLOCAL_LABEL_LIST arg to NONLOCAL_LABELS and initialize + new static var nonlocal_label_list with it. + (active_eh_region, nested_eh_region, label_value_list, + nonlocal_label_list): New static variables. + (make_edges, delete_unreachable_blocks, delete_block): New static + functions, broken out of find_basic_blocks_1. + (record_volatile_insns, mark_regs_live_at_end, set_noop_p, + noop_move_p): New static functions, broken out of life_analysis_1. + +Fri Oct 9 15:49:29 1998 Richard Henderson + + * expmed.c (store_bit_field): Pun non-integral str_rtx modes. + Take extra care for op0 now possibly being a subreg. + (extract_bit_field): Likewise. + * function.c (purge_addressof_1): Revert Oct 4 change. Drop + the reg to memory if there is no equal sized integral mode. + * stor-layout.c (int_mode_for_mode): New function. + * machmode.h: Prototype it. + +Fri Oct 9 14:26:44 1998 Jeffrey A Law (law@cygnus.com) + + * global.c (build_insn_chain): Verify no real insns exist past the + end of the last basic block, then exit the loop. + +Fri Oct 9 11:44:47 1998 David Edelsohn + + * loop.c (insert_bct): Ensure loop_iteration_var non-zero before use. + +Thu Oct 8 21:59:47 1998 Dave Brolley + + * emit-rtl.c (init_emit_once): Call INIT_EXPANDERS. + +Thu Oct 8 22:03:45 1998 David Edelsohn + + * rs6000.h (RTX_COSTS): Add PROCESSOR_PPC604e cases. + +Thu Oct 8 17:00:18 1998 Richard Henderson + + * flow.c (find_basic_blocks): Correctly determine when a call + is within an exception region. + +Thu Oct 8 17:15:04 1998 Jeffrey A Law (law@cygnus.com) + + * toplev.c (output_file_directive): Use DIR_SEPARATOR, not '/'. + + * cpplib.h: Protect from multiple inclusions. + * cpplib.c: Fix minor formatting problems. + + * i386/xm-cygwin32.h: Only define POSIX if it is not already defined. + + * jump.c (jump_optimize): Revert accidental patch. + + * Makefile.in (cpplib.o): Use unlibsubdir. + +Thu Oct 8 12:50:47 1998 Jim Wilson + + * loop.c (get_condition): Allow combine when either compare is + VOIDmode. + +Thu Oct 8 11:31:01 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Thu Oct 8 12:21:14 1998 Richard Frith-Macdonald + + * c-lex.c (remember_protocol_qualifiers): Handle RID_BYREF. + (init_lex): Initialize ridpointers[RID_BYREF]. + * c-lex.h (enum rid): Add RID_BYREF. + * c-parse.gperf: Add RID_BYREF as a type qualifier. + * objc/objc-act.c (is_objc_type_qualifiers): Handle RID_BYREF. + (encode_type_qualifiers): Similarly + * c-gperf.h: Rebuilt. + +Thu Oct 8 05:56:00 1998 Jeffrey A Law (law@cygnus.com) + + * c-common.c (type_for_mode): Only return TItype nodes when + HOST_BITS_PER_WIDE_INT is >= 64 bits. + * c-decl.c (intTI_type_node, unsigned_intTI_type_node): Only declare + when HOST_BITS_PER_WIDE_INT is >= 64 bits. + (init_decl_processing): Only create TItype nodes when + HOST_BITS_PER_WIDE_INT is >= 64 bits. + * c-tree.h (intTI_type_node, unsigned_intTI_type_node): Only declare + when HOST_BITS_PER_WIDE_INT is >= 64 bits. + +Thu Oct 8 05:05:34 1998 Bernd Schmidt + + * stmt.c (n_occurrences): New static function. + (expand_asm_operands): Verify that all constrains match in the + number of alternatives. + Verify that '+' or '=' are at the beginning of an output constraint. + Don't allow '&' for input operands. + Verify that '%' isn't written for the last operand. + * reload.c (find_reloads): Abort if an asm is found with invalid + constraints; all possible problems ought to be checked for earlier. + +Thu Oct 8 04:26:20 1998 Michael Hayes + + * flags.h (flag_branch_on_count_reg): Always declare + * toplev.c (flag_branch_on_count_reg): Likewise. + * toplev.c: Fix typos. + + * real.c (c4xtoe): Remove unused variables. Add some missing parens. + (toc4x): Similarly. + +Thu Oct 8 01:25:22 1998 Richard Henderson + + * flow.c (find_basic_blocks): Calc upper bound for extra nops in + max_uids_for_flow. + (find_basic_blocks_1): Add a nop to the end of a basic block when + a trailing call insn does not have abnormal control flow. + * gcse.c (pre_transpout): New variable. + (alloc_pre_mem, free_pre_mem, dump_pre_data): Bookkeeping for it. + (compute_pre_transpout): Calculate it. + (compute_pre_ppinout): Use it to eliminate impossible placements + due to abnormal control flow through calls. + (compute_pre_data): Call compute_pre_transpout. + +Wed Oct 7 21:40:24 1998 David S. Miller + + * config/sparc/sol2-sld-64.h (ASM_CPU_SPEC): Fix typo. + +Wed Oct 7 21:19:46 1998 Ken Raeburn + + * config/mips/mips.md (tablejump_internal3, tablejump_internal4 + and matching define_insns): Tack on a `use' of the table label, so + flow analysis will recognize a tablejump. + +Wed Oct 7 17:33:39 1998 Richard Henderson + + * gcse.c (pre_insert_insn): Tweek to notice that calls do not + always end basic blocks for abnormal edge reasons. + +Wed Oct 7 14:40:43 1998 Nick Clifton + + * config/i386/i386.h: Remove definition of + HANDLE_PRAGMA_PACK_PUSH_POP. + + * config/i386/go32.h: Add definition of + HANDLE_PRAGMA_PACK_PUSH_POP. + + * config/i386/win32.h: Add definition of + HANDLE_PRAGMA_PACK_PUSH_POP. + + * config/i386/cygwin32.h: Add definition of + HANDLE_PRAGMA_PACK_PUSH_POP. + + * c-pragma.c (insert_pack_attributes): Do not insert + attributes unless #pragma pack(push,) is in effect. + +Wed Oct 7 12:10:46 1998 Jim Wilson + + * expr.c (emit_group_store): Handle a PARALLEL destination. + +Wed Oct 7 10:07:29 1998 Richard Henderson + + * gcse.c (pre_insert_insn): When a call ends a bb, insert + the new insns before the argument regs are loaded. + +Wed Oct 7 12:55:26 1998 Kaveh R. Ghazi + + * Makefile.in (c-gperf.h): Add -L KR-C -F ', 0, 0' flags to gperf. + (c-parse.gperf): Update comments describing invocation flags. + (c-gperf.h): Regenerate using gperf 2.7.1 (19981006 egcs). + +1998-10-07 Manfred Hollstein + + * reload1.c (reload): Call free before clobbering the memory + locations or constants pointers. + +Wed Oct 7 02:05:20 1998 David S. Miller + + * config/sparc/sol2-sld-64.h (TRANSFER_FROM_TRAMPOLINE): Rework + for efficiency by checking whether we need to modify the current + stack permission at all. + (ASM_OUTPUT_CONSTRUCTOR, ASM_OUTPUT_DESTRUCTOR): Define. + * config/sparc/sparc.c (sparc_initialize_trampoline): Emit + __enable_execute_stack libcall here too if + TRANSFER_FROM_TRAMPOLINE is defined. + * config/sparc/sparc.h: Set TARGET_ARCH32 to a constant if + IN_LIBGCC2. + +Wed Oct 7 02:27:52 1998 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (DRIVER_DEFINES): Remove last change. + +Wed Oct 7 01:08:43 1998 Bernd Schmidt + + * jump.c (duplicate_loop_exit_test): Strip REG_WAS_0 notes off all + insns we're going to copy. + * regclass.c (reg_scan_mark_refs): Don't test X for NULL_RTX. + + * loop.c (count_one_set): Add prototype. + + * caller-save.c (restore_referenced_regs): Lose mode argument. + (insert_save): Lose mode argument. + (insert_restore): Lose mode argument. + (insert_one_insn): Lose mode argument. + (save_call_clobbered_regs): Lose mode argument. + (setup_save_areas): Take no argument and return void. All callers + changed. + Don't verify validity of memory addresses. + * reload.h (setup_save_ares): Adjust prototype. + (save_call_clobbered_regs): Likewise. + * reload1.c (delete_caller_save_insns): New function. + (caller_save_spill_class): Delete variable. + (caller_save_group_size): Delete variable. + (reload): Call setup_save_areas and save_call_clobbered_regs + in the main loop, before calling calculate_needs_all_insns. + Don't call save_call_clobbered_regs after the loop. + Call delete_caller_save_insns at the end of an iteration if + something changed. + Delete code to manage caller_save_spill_class. + Emit the final note before setting reload_first_uid. + Simplify test that determines whether reload_as_needed gets run. + (calculate_needs): Delete code to manage caller_save_spill_class. + +Tue Oct 6 15:42:27 1998 Richard Henderson + + * collect2.c (main): Initialize ld_file_name. + +Tue Oct 6 15:45:15 1998 Catherine Moore + + * config/sparc/sysv4.h (ASM_OUTPUT_SECTION_NAME): Don't + check for flag_function_sections. + +Tue Oct 6 20:02:31 1998 J"orn Rennecke + + * cse.c (insert_regs): Fix bug in Sep 24 change. + +Tue Oct 6 17:00:42 1998 J"orn Rennecke + + * flags.h (flag_dump_unnumbered): Declare. + * toplev.c (flag_dump_unnumbered): Don't declare. + * print-rtl.c (flags.h): Include. + (print_rtl_single): Add return value. + * rtl.h (print_rtl_single): Update declaration. + * flow.c (flag_dump_unnumbered): Don't declare. + (print_rtl_with_bb): Use return value of print_rtl_single. + +Tue Oct 6 01:36:00 1998 Bernd Schmidt + + * loop.c (count_one_set): New static function, broken out of + count_loop_regs_set + (count_loop_regs_set): Call it. + * global.c (mark_reg_store): Handle clobbers here by not calling + set_preference. + (mark_reg_clobber): Just call mark_reg_store after ensuring SETTER + is in fact a clobber. + * integrate.c (process_reg_param): New function, broken out of + expand_inline_function. + (expand_inline_function): Call it. + + + * i386.md (addsidi3_1): Delete unused variable temp. + (addsidi3_2): Likewise. + (clstrstrsi): Delete unused variable addr1. + + * rtl.h: Don't declare any functions also declared in recog.h. + + * Makefile.in (stupid.o): Update dependencies. + (global.o): Likewise. + + * global.c: Include reload.h + (reg_becomes_live): New function. + (reg_dies): New function. + (build_insn_chain): New function. + (global_alloc): Call build_insn_chain before calling reload. + + * reload.h (struct needs): New structure definition. + (struct insn_chain): Likewise. + (reload_insn_chain): Declare variable. + (new_insn_chain): Declare function. + + + * reload1.c (reload_startobj): New variable. + (reload_insn_chain): New variable. + (unused_insn_chains): New variable. + (new_insn_chain): New function. + (init_reload): Initialize reload_startobj, not reload_firstobj. + (reload): Initialize reload_firstobj. + Before returning, free everything on the reload_obstack. + + * stupid.c: Include insn-config.h, reload.h and basic-block.h. + (reg_where_dead_chain, reg_where_born_exact, reg_where_born_clobber, + current_chain): New variables. + (reg_where_born): Delete variable. + (REG_WHERE_BORN): New macro. + (find_clobbered_regs): New function. + (stupid_life_analysis): Don't allocate/free reg_where_born. + Allocate and free reg_where_born_exact, reg_where_born_clobber, + reg_where_dead_chain. + Use REG_WHERE_BORN instead of reg_where_born. + While processing the insns, build the reload_insn_chain with + information about register lifetimes. + (stupid_reg_compare): Use REG_WHERE_BORN instead of reg_where_born. + (stupid_mark_refs): Replace arg INSN with arg CHAIN. All callers + changed. + Compute and information about birth and death of pseudo registers in + reg_where_dead_chain, reg_where_born_exact and reg_where_born_clobber. + Delete code to set elements of reg_where_born. + +Mon Oct 5 22:34:30 1998 Alexandre Petit-Bianco + + * tree.def (GOTO_EXPR): Modified documentation. + * expr.c (expand_expr): Expand GOTO_EXPR into a goto or a computed + goto. + +Mon Oct 5 22:43:36 1998 David Edelsohn + + * unroll.c (loop_iteration_var, loop_initial_value, loop_increment + loop_final_value, loop_comparison_code): No longer static. + (unroll_loop): Delete loop_start_value update. + * loop.h (loop_iteration_var, loop_initial_value, loop_increment, + loop_final_value, loop_comparison_code): Extern. + (loop_start_value): Delete extern. + * loop.c (loop_can_insert_bct, loop_increment, loop_start_value, + loop_comparison_value, loop_comparison_code): Delete. + (loop_optimize): Remove initialization for deleted variables. + (strength_reduce): Delete analyze_loop_iterations call. Only call + insert_bct if flag_branch_count_on_reg set. + (analyze_loop_iterations): Delete. + (insert_bct): Remove iteration count calculation. Move checks for + viable BCT optimization to here. Obtain iteration count from + loop_iterations and correct for unrolling. Check for enough + iteration to be beneficial. Comment out runtime iteration count + case. + (insert_bct): Print iteration count in dump file. Remove + loop_var_mode and use word_mode directly. + + * rs6000.h (processor_type): Add PROCESSOR_PPC604e. + * rs6000.c (rs6000_override_options): Use it. + (optimization_options): Enable use of flag_branch_on_count_reg. + * rs6000.md (define_function_unit): Describe 604e. + +1998-10-05 Herman A.J. ten Brugge + + * loop.c (move_movables): Corrected threshold calculation for + moved_once registers. + +Mon Oct 5 21:18:45 1998 Bernd Schmidt + + * loop.c (combine_givs_p): Fix test for identical givs. + +Mon Oct 5 10:11:28 1998 Nick Clifton + + * dwarf2out.c (gen_subprogram_die): If errorcount nonzero, don't + call abort if the function is already defined. + +Mon Oct 5 10:02:36 1998 Jeffrey A Law (law@cygnus.com) + + * combine.c (simplify_rtx): Do not replace TRUNCATE with a SUBREG if + truncation is not a no-op. + +Mon Oct 5 09:02:04 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Mon Oct 5 08:19:55 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Mon Oct 5 01:07:23 1998 Torbjorn Granlund + + * expmed.c (expand_divmod): Don't widen for computing remainder + if we seem to have a divmod pattern for needed mode. + +Mon Oct 5 01:01:42 1998 Zack Weinberg + + * cpplib.c (macroexpand): Correct off-by-one error in handling + of escapes. + +Sun Oct 4 23:58:30 1998 Richard Henderson + + * combine.c (expand_field_assignment): Don't do bitwise operations + on MODE_FLOAT; pun to MODE_INT if possible. + +Sun Oct 4 18:33:24 1998 Jason Merrill + scott snyder + + * tlink.c (scan_linker_output): Recognize errors from irix 6.2 + linker. Recognize mangled names in quotes. + +Sun Oct 4 02:58:20 1998 Jakub Jelinek + + * config/sparc/sparc.md (ashldi3+1): Name it ashldi3_sp64. + (ashlsi3_const1, ashldi3_const1): New combiner patterns. + (ashrsi3_extend, ashrsi3_extend2): New combiner patterns. + (lshrsi3_extend, lshrsi3_extend2): Ditto. + +Sun Oct 4 00:23:00 1998 David S. Miller + + * function.c (purge_addressof_1): If trying to take a sub-word + integral piece of a floating point mode, put it on the stack. + +Sat Oct 3 19:01:03 1998 Richard Henderson + + * alpha/linux.h (CPP_PREDEFINES): Define __alpha__ for imake. + +Sat Oct 3 14:42:19 1998 Jason Merrill + + * PROJECTS: Remove template friends. + + * collect2.c (sort_ids): Remove unused variable. + + * tm.texi (MATH_LIBRARY): Document. + (NEED_MATH_LIBRARY): Remove. + + * varasm.c (assemble_start_function, assemble_variable, weak_finish, + assemble_alias): Do ASM_GLOBALIZE_LABEL for weak symbols, too. + +Sat Oct 3 16:14:44 1998 John Carr + + * dwarf2out.c (expand_builtin_dwarf_reg_size): Initialize + last_end to 0x7fffffff. + +Fri Oct 2 19:14:20 1998 David S. Miller + + * function.c (purge_addressof_1): Do not perform endianness + corrections on bitpos, who we call will do it for us. + +Fri Oct 2 11:52:35 1998 Jeffrey A Law (law@cygnus.com) + + * h8300.c (WORD_REG_USED): Fix typo. + (initial_offset): Use WORD_REG_USED. + + * h8300.c (handle_pragma): Fix typo. + +Fri Oct 2 10:51:35 1998 Bernd Schmidt + + * caller-save.c (insert_save_restore): Break this function up + into new functions insert_restore, insert_save and insert_one_insn. + All callers changed. + (insert_restore): New function, mostly broken out of + insert_save_restore. + (insert_save): Likewise. + (insert_one_insn): Likewise. + (restore_referenced_regs): New argument BLOCK. All callers changed. + (save_call_clobbered_regs): Don't keep track of basic block boundaries + in this function, do it in insert_one_insn instead. + + * reload1.c (reload): Break out some more pieces into separate + functions. + (dump_needs): New function, broken out of reload. + (set_initial_elim_offsets): Likewise. + (init_elim_table): Likewise. + (update_eliminables): Likewise. + + * global.c (global_alloc): Delete code to manage the scratch_list. + * local-alloc.c (qty_scratch_rtx): Delete. + (scratch_block): Delete. + (scratch_list): Delete. + (scratch_list_length): Delete. + (scratch_index): Delete. + (alloc_qty_for_scratch): Delete. + (local-alloc): Update initialization of max_qty. + Delete code to manage the scratch list. + Delete code to allocate/initialize qty_scratch_rtx. + (block_alloc): Don't allocate quantities for scratches. + Delete code to manage the scratch list. + * regs.h (scratch_list): Delete declaration. + (scratch_block): Delete declaration. + (scratch_list_length): Delete declaration. + * reload1.c (reload): Delete code to manage the scratch list. + (spill_hard_reg): Likewise. + (mark_scratch_live): Delete. + + * recog.c (alter_subreg): Delete declaration. + +1998-10-02 Andreas Jaeger + + * Makefile.in (cccp.o): Fix typo in last patch. + +Fri Oct 2 16:13:12 1998 J"orn Rennecke + + * t-sh (LIB1ASMFUNCS): Add _set_fpscr . + * config/sh/lib1funcs.asm (___set_fpscr): Add. + +Fri Oct 2 02:01:59 1998 Jeffrey A Law (law@cygnus.com) + + * regclass.c (reg_scan_mark_refs): Return immediately if passed a + NULL_RTX as an argument. + + * Makefile.in (unlibsubdir): Define. + (DRIVER_DEFINES): Use unlibsubdir. + (cccp.o, cpplib.o, protoize.o, unprotoize.o): Similarly. + (stmp-fixinc): Similarly. + +Thu Oct 1 19:58:30 1998 Bernd Schmidt + + * regmove.c (regmove_optimize): Add variable old_max_uid. + At the end of the function, update basic_block_end. + +Thu Oct 1 17:58:25 1998 David S. Miller + + * dwarf2out.c (expand_builtin_dwarf_reg_size): Use + FIRST_PSEUDO_REGISTER as upper bound for last_end, not an + arbitrary constant. + +Thu Oct 1 17:57:14 1998 Nick Clifton + + * config/arm/arm.c: Improve interworking support. + +Thu Oct 1 18:43:35 1998 J"orn Rennecke + + * reload1.c (choose_reload_regs): Fix test if reload_reg_rtx[r] was + copied from reload_out[r] . + +Thu Oct 1 19:20:09 1998 John Carr + + * dwarf2out.c (expand_builtin_dwarf_reg_size): Fix to work + with more than three size ranges. + + * flow.c (sbitmap_copy): Use bcopy to copy bitmap. + + * rtl.c (mode_name): Add a null string at the end of the array. + (mode_wider_mode): Change type to unsigned char. + (mode_mask_array): New variable. + (init_rtl): Update for mode_wider_mode type change. + + * rtl.h (mode_wider_mode): Change type to unsigned char. + (mode_mask_array): Declare. + (GET_MODE_MASK): Use mode_mask_array. + +Thu Oct 1 15:56:01 1998 Gavin Romig-Koch + + * calls.c (expand_call) : Encapsulate code into + copy_blkmode_from_reg. + * expr.c (copy_blkmode_from_reg): New function. + * expr.h (copy_blkmode_from_reg): New function. + * integrate.c (function_cannot_inline_p): We can inline + these now. + (expand_inline_function): Use copy_blkmode_from_reg + if needed. Avoid creating BLKmode REGs. + (copy_rtx_and_substitute): Don't try to SUBREG a BLKmode + object. + +Thu Oct 1 10:42:27 1998 Nick Clifton + + * config/v850/v850.c: Add function prototypes. + Add support for v850 special data areas. + + * config/v850/v850.h: Add support for v850 special data areas. + + * c-pragma.c: Add support for HANDLE_PRAGMA_PACK and + HANDLE_PRAGMA_PACK_PUSH_POP. + (push_alignment): New function: Cache an alignment requested + by a #pragma pack(push,). + (pop_alignment): New function: Pop an alignment from the + alignment stack. + (insert_pack_attributes): New function: Generate __packed__ + and __aligned__ attributes for new decls whilst a #pragma pack + is in effect. + (add_weak): New function: Cache a #pragma weak directive. + (handle_pragma_token): Document calling conventions. Add + support for #pragma pack(push,) and #pragma pack (pop). + + * c-pragma.h: If HANDLE_SYSV_PRAGMA or HANDLE_PRAGMA_PACK_PUSH_POP + are defined enable HANDLE_PRAGMA_PACK. + Move 'struct weak_syms' here (from varasm.c). + Add pragma states for push and pop pragmas. + + * c-common.c (decl_attributes): Call PRAGMA_INSERT_ATTRIBUTES + if it is defined. + + * c-lex.c: Replace occurances of HANDLE_SYSV_PRAGMA with + HANDLE_GENERIC_PRAGMAS. + + * varasm.c: Move definition of 'struct weak_syms' into + c-pragma.h. + (handle_pragma_weak): Deleted. + + * config/i386/i386.h: Define HANDLE_PRAGMA_PACK_PUSH_POP. + + * config/winnt/win-nt.h: Define HANDLE_PRAGMA_PACK_PUSH_POP. + + * c-decl.c (start_function): Add invocation of + SET_DEFAULT_DECL_ATTRIBUTES, if defined. + + * tm.texi: Remove description of non-existant macro + SET_DEFAULT_SECTION_NAME. + + (HANDLE_SYSV_PRAGMA): Document. + (HANDLE_PRAGMA_PACK_PUSH_POP): Document. + +Wed Sep 30 22:27:53 1998 Robert Lipe + + * config.sub: Recognize i[34567]86-pc-udk as new target. + * configure.in: Likewise. + * config/i386/t-udk: New file. + * config/i386/udk.h: New file. + +Wed Sep 30 19:33:07 1998 Jeffrey A Law (law@cygnus.com) + + * reorg.c (check_annul_list_true_false): Remove unused variables. + (steal_delay_list_from_target): Add missing "used_annul" variable. + (try_merge_delay_insns): Close out half formed comment. + +Wed Sep 30 19:13:20 1998 Zack Weinberg + + * cpplib.c (macroexpand): If arg->raw_before or + arg->raw_after, remove any no-reexpansion escape at the + beginning of the pasted token. Correct handling of whitespace + markers and no-reexpand markers at the end if arg->raw_after. + + * toplev.c (documented_lang_options): Recognize -include, + -imacros, -iwithprefix, -iwithprefixbefore. + * cpplib.c (cpp_start_read): Process -imacros and -include + switches at the same time and in command-line order, after + initializing the dependency-output code. Emit properly nested + #line directives for them. Emit a #line for the main file + before processing these switches, and don't do it again + afterward. + +Wed Sep 30 18:03:22 1998 Richard Henderson + + * function.c (purge_addressof_1): Use bitfield manipulation + routines to handle mem mode < reg mode. + +Wed Sep 30 18:43:32 1998 Herman ten Brugge + + * reorg.c (try_merge_delay_insns): Account for resources referenced + in each instruction in INSN's delay list before trying to eliminate + useless instructions. Similarly when looking at a trial insn's delay + slots. + + * reorg.c (check_annul_list_true_false): New function. + (steal_delay_list_from_{target,fallthrough}): Call it and also + refine tests for when we may annul if already filled a slot. + (fill_slots_from_thread): Likewise. + (delete_from_delay_slot): Return newly-created thread. + (try_merge_delay_isns): Use its new return value. + +Wed Sep 30 18:29:26 1998 Jeffrey A Law (law@cygnus.com) + + * loop.c (check_dbra_loop): Use a vanilla loop reversal if the biv is + used to compute a giv or as some other non-counting use. + +Wed Sep 30 18:19:27 1998 Michael Hayes + + * regs.h (HARD_REGNO_CALL_PART_CLOBBERED): New macro. + * local-alloc.c (find_free_reg): Use it. + * global.c (find_reg): Likewise. + * tm.texi: Document HARD_REGNO_CALL_PART_CLOBBERED. + + * regs.h (HARD_REGNO_CALLER_SAVE_MODE): New macro. + * caller-save.c (init_caller_save): Use it. + * tm.texi: Document HARD_REGNO_CALLER_SAVE_MODE. + +Wed Sep 30 12:57:30 1998 Zack Weinberg + + * configure.in: Add --enable-cpplib option which uses cpplib + for cpp, but doesn't link cpplib into cc1. Make help text + capitalization consistent. + * configure: Rebuilt. + +Wed Sep 30 10:09:39 1998 Mark Mitchell + + * function.c (gen_mem_addressof): If the address REG is + REG_USERVAR_P make the new REG be so also. + * loop.c (scan_loop): Apply DeMorgan's laws and add documentation + in an attempt to clarify slightly. + +Wed Sep 30 09:57:40 1998 Jeffrey A Law (law@cygnus.com) + + * expr.c (expand_expr): Handle COMPONENT_REF, BIT_FIELD_REF ARRAY_REF + and INDIRECT_REF in code to check MAX_INTEGER_COMPUTATION_MODE. + +Wed Sep 30 10:13:39 1998 Catherine Moore + + * toplev.c: Fix last patch. + +Tue Sep 29 20:03:18 1998 Jim Wilson + + * loop.c (get_condition): Fix typo in May 9 change. + +Tue Sep 29 11:11:38 EDT 1998 Andrew MacLeod + + * invoke.texi (-fexceptions): Merge 2 different descriptions. + +Mon Sep 28 22:08:52 1998 Kaveh R. Ghazi + + * toplev.c (documented_lang_options): Spelling corrections. + +Mon Sep 28 19:41:24 1998 Alexandre Oliva + + * configure.in: new flags --with-ld and --with-as, equivalent + to setting LD and AS environment variables. Test whether + specified arguments are GNU commands, and report them with + checking messages. Use the specified AS for configure + tests too. + * configure: ditto + * acconfig.h: add DEFAULT_ASSEMBLER and DEFAULT_LINKER + * config.in: ditto + * gcc.c (find_a_file): when looking for `as' and `ld', return + the DEFAULT program if it exists + * collect2.c (main): use DEFAULT_LINKER if it exists + + * gcc.c (find_a_file): the test for existence of a full + pathname was reversed + +Mon Sep 28 17:34:35 1998 Michael Meissner + + * rs6000.h (ASM_OUTPUT_MI_THUNK): Only define on ELF systems. + * rs6000.c (output_mi_thunk): Always use a raw jump for now. + +Mon Sep 28 14:24:03 1998 Mark Mitchell + + * tree.h (TYPE_BINFO): Document. + +Mon Sep 28 12:55:49 1998 Stan Cox + + * i386-coff.h (dbxcoff.h): Added. + +Mon Sep 28 12:51:00 1998 Catherine Moore + + * toplev.c: fix bad patch around flag_data_sections. + +Mon Sep 28 10:32:28 1998 Nick Clifton + + * reload1.c (reload): Use reload_address_index_reg_class and + reload_address_base_reg_class when setting + caller_save_spill_class. (Patch generated by Jim Wilson: + wilson@cygnus.com). + +Mon Sep 28 07:43:34 1998 Mark Mitchell + + * c-common.c (c_get_alias_set): Tighten slightly for FUNCTION_TYPEs + and ARRAY_TYPEs. Tidy up. Improve support for type-punning. + * expr.c (store_field): Add alias_set parameter. Set the + MEM_ALIAS_SET accordingly, if the target is a MEM. + (expand_assignment): Use it. + (store_constructor_field): Pass 0. + (expand_expr): Likewise. + +Mon Sep 28 07:54:03 1998 Catherine Moore + + * flags.h: Add flag_data_sections. + * toplev.c: Add option -fdata-sections. Add flag_data_sections. + (compile_file): Error if flag_data_sections not supported. + * varasm.c (assemble_variable): Handle flag_data_sections. + * config/svr4.h: Modify prefixes for UNIQUE_SECTION_NAME. + * config/mips/elf.h: Likewise. + * config/mips/elf64.h: Likewise. + * invoke.texi: Describe -fdata-sections. + +Mon Sep 28 04:15:44 1998 Craig Burley + + * invoke.texi (-ffloat-store): Clarify that this option + does not affect intermediate results -- only variables. + +Mon Sep 28 04:11:35 1998 Jeffrey A Law (law@cygnus.com) + + * cpp.texi: Update for Fortran usage from Craig. + +Fri Sep 25 22:09:47 1998 David Edelsohn + + * rs6000.c (function_arg_boundary): Revert accidental change on + September 18. + +Fri Sep 25 20:30:00 1998 Michael Meissner + + * rs6000.h (ASM_OUTPUT_MI_THUNK): Declare, call output_mi_thunk. + (output_mi_thunk): Declare. + + * rs6000.c (output_mi_thunk): Function to create thunks for MI. + (output_function_profiler): Use r12 for temp, instead of r11 so + that we preserve the static chain register. + +Fri Sep 25 14:18:33 1998 Jim Wilson + + * sdbout.c (sdbout_one_type): Don't look at TYPE_BINFO field of enums. + +Fri Sep 25 19:30:19 1998 J"orn Rennecke + + * sh.c (gen_shl_sext): Fix case 5. + +Fri Sep 25 17:35:23 1998 J"orn Rennecke + + * reload1.c (reload_combine): Re-add line that got accidentally lost. + +Fri Sep 25 10:43:47 1998 Kaveh R. Ghazi + + * cccp.c (pedwarn_with_file_and_line): For !__STDC__ case, avoid + accessing variables until they are initialized via va_arg(). + +Thu Sep 24 22:12:16 1998 David S. Miller + + * reload1.c (reload_combine): Initialize set before using. + +Thu Sep 24 18:53:20 1998 Jason Merrill + + * sdbout.c (sdbout_field_types): Don't emit the types of fields we + won't be emitting. + +Thu Sep 24 17:05:30 1998 Nick Clifton + + * config/arm/arm.md (insv): Add comment. In CONST_INT case, and + operand3 with mask before using it. Patch provided by Jim Wilson. + +Thu Sep 24 15:08:08 1998 Jakub Jelinek + + * config/sparc/sparc.c (function_value): Perform the equivalent of + PROMOTE_MODE for ARCH64. + (eligible_for_epilogue_delay): Allow DImode operations in delay + slot of a return for ARCH64. + +Thu Sep 24 22:17:54 1998 J"orn Rennecke + + * sh.md (sqrtsf2): Fix mode of sqrt. + +Thu Sep 24 21:48:51 1998 J"orn Rennecke + + * reload1.c (choose_reload_regs): Also try inheritance when + reload_in is a stack slot of a pseudo, even if we already got a + reload reg. + +Thu Sep 24 21:22:39 1998 J"orn Rennecke + + * reload1.c (reload_cse_regs_1): Renamed from reload_cse_regs. + (reload_cse_regs): New function body: call reload_cse_regs_1, + reload_combine, reload_cse_move2add. + When doing expensive_optimizations, call reload_cse_regs_1 a + second time after reload_cse_move2add. + (reload_combine, reload_combine_note_store): New functions. + (reload_combine_note_use): New function. + (reload_cse_move2add, move2add_note_store): New functions. + +Thu Sep 24 18:48:43 1998 J"orn Rennecke + + * reload.c (find_reloads): In code to promote RELOAD_FOR_X_ADDR_ADDR + reloads to RELOAD_FOR_X_ADDRESS reloads, test for reload sharing. + + Properly keep track of first RELOAD_FOR_X_ADDRESS also for + more than 3 such reloads. + + If there is not more than one RELOAD_FOR_X_ADDRESS, don't change + RELOAD_FOR_X_ADDR_ADDR reload. + +Thu Sep 24 17:45:55 1998 J"orn Rennecke + + * expr.c (store_constructor): When initializing a field that is smaller + than a word, at the start of a word, try to widen it to a full word. + + * cse.c (cse_insn): When we are about to change a register, + remove any invalid references to it. + + (remove_invalid_subreg_refs): New function. + (mention_regs): Special treatment for SUBREGs. + (insert_regs): Don't strip SUBREG for call to mention_regs. + Check if reg_tick needs to be bumped up before that call. + (lookup_as_function): Try to match known word_mode constants when + looking for a norrower constant. + (canon_hash): Special treatment for SUBREGs. + +Thu Sep 24 01:35:34 1998 David S. Miller + + * config/sparc/sol2-sld-64.h (TRANSFER_FROM_TRAMPOLINE): Define. + * config/sparc/sparc.c (sparc64_initialize_trampoline): If that is + defined, emit libcall to __enable_execute_stack. Also fix opcodes + and offsets in actual stack trampoline code so they match the + commentary and actually work. + +Thu Sep 24 01:19:02 1998 Jakub Jelinek + + * configure.in (sparcv9-*-solaris): Use t-sol2 and t-sol2-64 for + tmake_file. + (sparc64-*-linux): Use t-linux and sparc/t-linux64 for + tmake_file. Set extra_parts to needed crt objects. + * configure: Rebuilt. + * config/sparc/linux64.h (SPARC_BI_ARCH): Define. + (TARGET_DEFAULT): Set if default is v9 or ultra. + (STARTFILE_SPEC32, STARTFILE_SPEC64): New macros. + (STARTFILE_SPEC): Set to those upon SPARC_BI_ARCH. + (ENDFILE_SPEC32, ENDFILE_SPEC64, ENDFILE_SPEC): Likewise. + (SUBTARGET_EXTRA_SPECS, LINK_ARCH32_SPEC, LINK_ARCH64_SPEC, + LINK_SPEC, LINK_ARCH_SPEC): Likewise. + (TARGET_VERSION): Define. + (MULTILIB_DEFAULT): Define. + * config/sparc/sparc.h (CPP_CPU_DEFAULT_SPEC): Rearrange so that + mixed 32/64 bit compilers based upon SPARC_BI_ARCH work. + (CPP_CPU64_DEFAULT_SPEC, CPP_CPU32_DEFAULT_SEC): Define + appropriately. + (TARGET_SWITCHES): Allow ptr32/ptr64 options once more. + * config/sparc/sparc.c (sparc_override_options): If arch and + pointer size disagree, emit diagnostic and fix it up. If + SPARC_BI_ARCH and TARGET_ARCH32, set cmodel to CM_32. Turn off + V8PLUS in 64-bit mode. + * config/sparc/t-linux64: New file. + * config/sparc/t-sol2-64: New file. + * config/sparc/t-sol2: Adjust build rules to use MULTILIB_CFLAGS. + * config/sparc/sol2-sld-64.h (SPARC_BI_ARCH): Define. + (ASM_CPU32_DEFAULT_SPEC, ASM_CPU64_DEFAULT_SPEC, + CPP_CPU32_DEFAULT_SPEC, CPP_CPU64_DEFAULT_SPEC): Define. + (ASM_SPEC, CPP_CPU_SPEC): Set appropriately based upon those. + (STARTFILE_SPEC32, STARTFILE_SPEC32, STARTFILE_ARCH_SPEC): + Define. + (STARTFILE_SPEC): Set approriately based upon those. + (CPP_CPU_DEFAULT_SPEC, ASM_CPU_DEFAULT_SPEC): Set based upon + disposition of DEFAULT_ARCH32_P. + (LINK_ARCH32_SPEC, LINK_ARCH64_SPEC): Define. + (LINK_ARCH_SPEC, LINK_ARCH_DEFAULT_SPEC): Set based upon those. + (CC1_SPEC, MULTILIB_DEFAULTS): Set based upon DEFAULT_ARCH32_P. + (MD_STARTFILE_PREFIX): Set correctly based upon SPARC_BI_ARCH. + * config/sparc/xm-sysv4-64.h (HOST_BITS_PER_LONG): Only set on + arch64/v9. + * config/sparc/xm-sp64.h (HOST_BITS_PER_LONG): Likewise. + +Wed Sep 23 22:32:31 1998 Mark Mitchell + + * rtl.h (init_virtual_regs): New function. + * emit-rtl.c (init_virtual_regs): Define. + (insn_emit): Use it. + * integrate.c (save_for_inline_copying): Likewise. + +Wed Sep 23 16:22:01 1998 Nick Clifton + + * config/arm/thumb.h: The following patches were made by Jim Wilson: + (enum reg_class): Add NONARG_LO_REGS support. + (REG_CLASS_NAMES, REG_CLASS_CONTENTS, REGNO_REG_CLASS, + PREFERRED_RELOAD_CLASS, SECONDARY_RELOAD_CLASS): Likewise. + (GO_IF_LEGITIMATE_ADDRESS): Disable REG+REG addresses before reload + completes. Re-enable HImode REG+OFFSET addresses. + (LEGITIMIZE_RELOAD_ADDRESS): Define. + + * expmed.c (extract_bit_field): Add comment from Jim Wilson. + +Wed Sep 23 13:26:02 1998 Richard Henderson + + * alpha.c (get_aligned_mem): Revert Sep 20 change. + (alpha_set_memflags, alpha_set_memflags_1): Likewise. + (alpha_align_insns): Properly calculate initial offset wrt max_align. + +Wed Sep 23 10:45:44 1998 Richard Earnshaw (rearnsha@arm.com) + + * arm.c (find_barrier): Revert change of Apr 23. Handle table + jumps as a single entity, taking into account the size of the + table. + +Tue Sep 22 15:13:34 1998 Alexandre Petit-Bianco + + * tree.def (SWITCH_EXPR): New tree node definition. + +Mon Sep 21 23:40:38 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Mon Sep 21 22:31:14 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Mon Sep 21 22:48:09 1998 Jeffrey A Law (law@cygnus.com) + + * configure.in: Recognize i[34567]86-*-openbsd* and handle it like + NetBSD. + +Mon Sep 21 22:05:28 1998 Jeffrey A Law (law@cygnus.com) + + * Revert this patch. + * reload.c (find_reloads): Do not replace a pseudo with + (MEM (reg_equiv_addr)) in the initializing insn for the + pseudo. + +Mon Sep 21 20:19:41 1998 John Carr + + * final.c (final_scan_insn): Disable tracking CC across branches. + +Mon Sep 21 17:15:26 EDT 1998 Andrew MacLeod + + * expr.h (eh_rtime_match_libfunc): New extern declaration. + * optabs.c (init_optabs): Set eh_rtime_match_libfunc. + * except.c (start_catch_handler): Use eh_rtime_match_libfunc. + * libgcc2.c (__eh_rtime_match): Always return 0 if the matcher is + NULL. Only include if inhibit_libc is not defined. + +Mon Sep 21 14:10:51 1998 Jason Merrill + + * toplev.c (rest_of_compilation): Skip compiling anything with + DECL_EXTERNAL set, not just if it has DECL_INLINE as well. + +Mon Sep 21 13:51:05 1998 Jim Wilson + + * flow.c (find_basic_blocks): Delete check for in_libcall_block when + prev_code is a CALL_INSN. Change check for REG_RETVAL note to + use in_libcall_block. + (find_basic_blocks_1): Delete check for in_libcall_block when prev_code + is a CALL_INSN. If CALL_INSN and in_libcall_block, then change code + to INSN. + +Mon Sep 21 14:02:23 1998 + + * i386.h: (TARGET_SWITCHES) Improve doc for align-double. Fix + typo in no-fancy-math-387 description. + +Mon Sep 21 09:27:18 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Mon Sep 21 09:24:49 1998 Stan Cox + + * i386-coff.h (DBX_DEBUGGING_INFO): Added. + +Mon Sep 21 09:14:49 1998 Robert Lipe + + * i386.h: (TARGET_SWITCHES) Add description fields for flags + documented in install.texi. + (TARGET_OPTIONS) Likewise. + +Mon Sep 21 01:39:03 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Mon Sep 21 01:53:05 1998 Felix Lee + + * c-lex.c (init_lex): Use getenv ("LANG"), not GET_ENVIRONMENT (). + * cccp.c (main): Likewise. + + * cccp.c, collect2.c, cpplib.c, gcc.c, config/i386/xm-cygwin32.h: + Rename GET_ENVIRONMENT to GET_ENV_PATH_LIST, and fix some + macro-use bugs. + +Mon Sep 21 00:52:12 1998 Per Bothner + + * Makefile.in (LIBS): Link in libiberty.a. + * c-common.c, gcc.c, toplev.c: Replace (some) bcopy calls by memcpy. + +Sun Sep 20 23:28:11 1998 Richard Henderson + + * reload1.c (emit_reload_insns): Accept a new arg for the bb. Use + it to update bb boundaries. Update caller. + * function.c (reposition_prologue_and_epilogue_notes): Update + bb boundaries wrt the moved note. + +Sun Sep 20 20:57:02 1998 Robert Lipe + + * configure.in (i*86-*-sysv5*): Use fixinc.svr4 to patch byteorder + problems. + * configure: Regenerate. + +Sun Sep 20 19:01:51 1998 Richard Henderson + + * alpha.c (alpha_sr_alias_set): New variable. + (override_options): Set it. + (alpha_expand_prologue, alpha_expand_epilogue): Use it. + (mode_mask_operand): Fix signed-unsigned comparision warning. + (alpha_expand_block_move): Likewise. + (print_operand): Likewise. + (get_aligned_mem): Use change_address. + (alpha_set_memflags, alpha_set_memflags_1): Set the alias set. + (alphaev4_insn_pipe, alphaev4_next_group): New functions. + (alphaev4_next_nop, alphaev5_next_nop): New functions. + (alpha_align_insns): Remade from old alphaev5_align_insns + to handle multiple processors. + (alpha_reorg): Call alpha_align_insns for both ev4 and ev5. + * output.h (label_to_alignment): Prototype. + + * tree.c (new_alias_set): New function. + * tree.h (new_alias_set): Declare it. + * c-common.c (c_get_alias_set): Use it. + +Sun Sep 20 12:35:55 1998 Richard Henderson + + * fold-const.c (fold): Yet another COND_EXPR bug: when folding + to an ABS expr, convert an unsigned input to signed. + +Sun Sep 20 12:14:45 1998 Jeffrey A Law (law@cygnus.com) + + * fold-const.c (fold): Fix another type in COND_EXPR handling code. + +1998-09-20 Michael Hayes + + * configure.in: Add support for c4x targets. + * configure: Rebuilt. + +Sun Sep 20 00:00:51 1998 Richard Henderson + + * combine.c (distribute_notes): If an insn is a cc0 user, only + delete it if we can also delete the cc0 setter. + +Sun Sep 20 00:22:23 1998 Michael Tiemann + + * fold-const.c (fold): Fix typo in COND_EXPR handling code. + (invert_truthvalue): Enable truthvalue inversion for + floating-point operands if -ffast-math. + +Sat Sep 19 23:58:07 1998 Melissa O'Neill + + * configure.in: Disable collect2 for nextstep. Instead use + crtbegin/crtend. + * configure: Rebuilt. + * config/nextstep.h (STARTFILE_SPEC): Add crtbegin. + (ENDFILE_SPEC): Define. + (OBJECT_FORMAT_MACHO): Define. + (EH_FRAME_SECTION_ASM_OP): Define. + * crtstuff.c: Handle MACHO. + +Sun Sep 20 00:24:24 1998 Robert Lipe + + * config/i386/sco5.h (TARGET_MEM_FUNCTIONS): Define. + +1998-09-19 Torbjorn Granlund + + * fp-bit.c (pack_d): Do not clear SIGN when fraction is 0. + (_fpadd_parts): Get sign right for 0. + +1998-09-19 Michael Hayes + + * ginclude/varargs.h: Add support for C4x target. + * ginclude/stdargs.h: Likewise. + +Sat Sep 19 12:05:09 1998 Richard Henderson + + * alpha.c (alpha_return_addr): SET should be VOIDmode. + (alpha_emit_set_long_const): Rewrite to be callable from reload + and 32-bit hosts. + (alpha_expand_epilogue): Update for alpha_emit_set_long_const. + * alpha.md (movdi): Likewise. + +Sat Sep 19 07:33:36 1998 Richard Earnshaw (rearnsha@arm.com) + + * arm.c (add_constant): New parameter address_only, change caller. + Set it non-zero if taking the address of an item in the pool. + (arm_reorg): Handle cases where we need the address of an item in + the pool. + + * arm.c (bad_signed_byte_operand): Check both arms of a sum in + a memory address. + * arm.md (splits for *extendqihi_insn and *extendqisi_insn): Handle + memory addresses that are not in standard canonical form. + +Sat Sep 19 01:00:32 1998 Michael Hayes (mph@elec.canterbury.ac.nz) + + * README.C4X: New file with information about the c4x ports. + * ginclude/va-c4x.h: New file for c4x varargs support. + * config/c4x: New directory with c4x port files. + +Fri Sep 18 22:52:05 1998 Jeffrey A Law (law@cygnus.com) + + * reload.c (find_reloads): Do not replace a pseudo with + (MEM (reg_equiv_addr)) in the initializing insn for the + pseudo. + +Fri Sep 18 23:50:56 1998 David Edelsohn + + * toplev.c (rest_of_compilation): Set bct_p on second call to + loop_optimize. + * loop.c (loop_optimize, scan_loop, strength_reduce): New argument + bct_p. + (strength_reduce): Only call analyze_loop_iterations and + insert_bct if bct_p set. + (check_dbra_loop): Fix typo. + (insert_bct): Use word_mode instead of SImode. + (instrument_loop_bct): Likewise. Do not delete iteration count + condition code generation insn. Initialize iteration count before + loop start. + * rtl.h (loop_optimize): Update prototype. + + * ginclude/va-ppc.h (va_arg): longlong types in overflow area are + not doubleword aligned. + + * rs6000.c (optimization_options): New function. + (secondary_reload_class): Only call true_regnum for PSEUDO_REGs. + * rs6000.h (OPTIMIZATION_OPTIONS): Define. + (REG_ALLOC_ORDER): Allocate highest numbered condition regsiters + first; cr1 can be used for FP record condition insns. + +Fri Sep 18 09:44:55 1998 Nick Clifton + + * config/m32r/m32r.h (m32r_block_immediate_operand): Add to + PREDICATE_CODES. + + * config/m32r/m32r.md: Add "movstrsi" and "movstrsi_internal" + patterns. + + * config/m32r/m32r.c (m32r_print_operand): Add 's' and 'p' + operators. + (block_move_call): New function: Call a library routine to copy a + block of memory. + (m32r_expand_block_move): New function: Expand a "movstrsi" + pattern into a sequence of insns. + (m32r_output_block_move): New function: Expand a + "movstrsi_internal" pattern into a sequence of assembler opcodes. + (m32r_block_immediate_operand): New function: Return true if the + RTL is an integer constant, less than or equal to MAX_MOVE_BYTES. + +Thu Sep 17 16:42:16 EDT 1998 Andrew MacLeod + + * except.c (start_catch_handler): Issue 'fatal' instead of 'error' and + re-align some code. + * libgcc2.c (__eh_rtime_match): fprintf a runtime error. Use . + +Thu Sep 17 12:24:33 1998 J"orn Rennecke + + * regmove.c (copy_src_to_dest): Check that modes match. + +Wed Sep 16 22:10:42 1998 Robert Lipe + + * config/i386/sco5.h (SUPPORTS_WEAK): True only if targeting ELF. + +Wed Sep 16 15:24:54 1998 Richard Henderson + + * i386.h (PREFERRED_RELOAD_CLASS): Respect an existing class + narrower than FLOAT_REGS. + +Wed Sep 16 17:51:00 1998 Alexandre Oliva + + * cpplib.c: removed OLD_GPLUSPLUS_INCLUDE_DIR + * cccp.c: ditto + * Makefile.in (old_gxx_include_dir): removed + +Wed Sep 16 12:29:22 1998 Nick Clifton + + * config/sh/sh.h: Update definition of HANDLE_PRAGMA to match + new specification. + + * config/sh/sh.c (handle_pragma): Rename to sh_handle_pragma(). + (sh_handle_pragma): Change function arguments to match new + specification for HANDLE_PRAGMA. + +Wed Sep 16 12:43:19 1998 Kaveh R. Ghazi + + * gen-protos.c (parse_fn_proto): Cast argument of ISALNUM to + `unsigned char'. + (main): Mark parameter `argc' with ATTRIBUTE_UNUSED. + When generating output, initialize missing struct member to zero. + +Wed Sep 16 14:47:43 1998 J"orn Rennecke + + * regmove.c (copy_src_to_dest): Don't copy if that requires + (a) new register(s). + +Wed Sep 16 01:29:12 1998 Bernd Schmidt + + * global.c (reg_allocno): Now static. + * reload1.c (reg_allocno): Delete declaration. + (order_regs_for_reload): Take no arguments. Don't treat regs + allocated by global differently than those allocated by local-alloc. + +Wed Sep 16 01:09:01 1998 Kamil Iskra + + * m68k/m68k.c (output_function_prologue): Reverse NO_ADDSUB_Q + condition, fix format strings. + (output_function_epilogue): Likewise. + + * m68k/m68k.c: Don't include directly. + +Wed Sep 16 00:30:56 1998 Geoff Keating + + * gcse.c: New definition NEVER_SET for reg_first_set, reg_last_set, + mem_first_set, mem_last_set; because 0 can be a CUID. + (oprs_unchanged_p): Use new definition. + (record_last_reg_set_info): Likewise. + (record_last_mem_set_info): Likewise. + (compute_hash_table): Likewise. + +Tue Sep 15 22:59:52 1998 Jeffrey A Law (law@cygnus.com) + + * rs6000.c (output_epilogue): Handle Chill. + + * mn10200.h (ASM_OUTPUT_DWARF2_ADDR_CONST): Define. + * mn10300.h (ASM_OUTPUT_DWARF2_ADDR_CONST): Define. + + * combine.c (make_extraction): If no mode is specified for + an operand of insv, extv, or extzv, default it to word_mode. + (simplify_comparison): Similarly. + * expmed.c (store_bit_field): Similarly. + (extract_bit_field): Similarly. + * function.c (fixup_var_regs_1): Similarly. + * recog.c (validate_replace_rtx_1): Similarly. + * mips.md (extv, extzv, insv expanders): Default modes for most + operands. Handle TARGET_64BIT. + (movdi_uld, movdi_usd): New patterns. + + * pa.c (emit_move_sequence): Do not replace a pseudo with its + equivalent memory location unless we have been provided a scratch + register. Similarly do not call find_replacement unless a + scratch register has been provided. + +Tue Sep 15 19:23:01 1998 Bernd Schmidt + + * i386.h (PREFERRED_RELOAD_CLASS): For standard 387 constants, + return FLOAT_REGS. + +Tue Sep 15 19:09:06 1998 Richard Henderson + + * tree.h (BUILT_IN_CALLER_RETURN_ADDRESS): Unused. Kill. + (BUILT_IN_FP, BUILT_IN_SP, BUILT_IN_SET_RETURN_ADDR_REG): Kill. + (BUILT_IN_EH_STUB_OLD, BUILT_IN_EH_STUB, BUILT_IN_SET_EH_REGS): Kill. + (BUILT_IN_EH_RETURN, BUILT_IN_DWARF_CFA): New. + * c-decl.c (init_decl_processing): Update accordingly. + * expr.c (expand_builtin): Likewise. + + * rtl.h (global_rtl): Add cfa entry. + (virtual_cfa_rtx, VIRTUAL_CFA_REGNUM): New. + (LAST_VIRTUAL_REGISTER): Update. + * emit-rtl.c (global_rtl): Add cfa entry. + (init_emit): Initialize it. + * function.c (cfa_offset): New. + (instantiate_virtual_regs): Initialize it. + (instantiate_virtual_regs_1): Instantiate virtual_cfa_rtx. + (expand_function_end): Call expand_eh_return. + * tm.texi (ARG_POINTER_CFA_OFFSET): New. + + * except.c (current_function_eh_stub_label): Kill. + (current_function_eh_old_stub_label): Likwise; update all references. + (expand_builtin_set_return_addr_reg): Kill. + (expand_builtin_eh_stub_old, expand_builtin_eh_stub): Kill. + (expand_builtin_set_eh_regs): Kill. + (eh_regs): Produce a third reg for the actual handler address. + (eh_return_context, eh_return_stack_adjust): New. + (eh_return_handler, eh_return_stub_label): New. + (init_eh_for_function): Initialize them. + (expand_builtin_eh_return, expand_eh_return): New. + * except.h: Update prototypes. + * flow.c (find_basic_blocks_1): Update references to the stub label. + * function.h (struct function): Kill stub label elements. + + * libgcc2.c (in_reg_window): For REG_SAVED_REG, check that the + register number is one that would be in the previous window. + Provide a dummy definition for non-windowed targets. + (get_reg_addr): New function. + (get_reg, put_reg, copy_reg): Use it. + (__throw): Rely on in_reg_window, not INCOMING_REGNO. Kill stub + generating code and use __builtin_eh_return. Use __builtin_dwarf_cfa. + + * alpha.c (alpha_eh_epilogue_sp_ofs): New. + (alpha_init_expanders): Initialize it. + (alpha_expand_epilogue): Use it. + * alpha.h: Declare it. + * alpha.md (eh_epilogue): New. + + * m68h.h (ARG_POINTER_CFA_OFFSET): New. + * sparc.h (ARG_POINTER_CFA_OFFSET): New. + +Tue Sep 15 19:31:58 1998 Michael Meissner + + * i960.h (CONST_COSTS): Fix thinko. Test flag, not the constant + flag bit mask. + +Tue Sep 15 14:10:54 EDT 1998 Andrew MacLeod + + * except.h (struct eh_entry): Add false_label field. + (end_catch_handler): Add prototype. + * except.c (push_eh_entry): Set false_label field to NULL_RTX. + (start_catch_handler): When using old style exceptions, issue + runtime typematch code before continuing with the handler. + (end_catch_handler): New function, generates label after handler + if needed by older style exceptions. + (expand_start_all_catch): No need to check for new style exceptions. + (output_exception_table_entry): Only output the first handler label + for old style exceptions. + * libgcc2.c (__eh_rtime_match): New routine to lump runtime matching + mechanism into one function, if a runtime matcher is provided. + +Tue Sep 15 13:53:59 EDT 1998 Andrew MacLeod + + * config/i960/i960.h (SLOW_BYTE_ACCESS): Change definition to 1. + +Tue Sep 15 09:59:01 1998 Mark Mitchell + + * integrate.c (copy_decl_list): Fix typo. + +Tue Sep 15 04:18:52 1998 David S. Miller + + * config/sparc/sparc.md (movdf_const_intreg_sp32): Fix length + attribute. + +Mon Sep 14 14:02:53 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Mon Sep 14 10:33:56 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Mon Sep 14 09:51:05 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sun Sep 13 22:10:18 1998 David S. Miller + + * invoke.texi (C Dialect Options): Put back missing @end itemize. + +Mon Sep 14 02:33:46 1998 Alexandre Oliva + + * configure.in: remove usage of `!' to negate the result of a + command; some common shells do not support it + +Sun Sep 13 19:17:35 1998 David S. Miller + + * configure.in: in sparc9-sol2 config, use 'if test' not + brackets. + * configure: Rebuilt. + + * config/sparc/sol2-sld-64.h (SPARC_DEFAULT_CMODEL): Change to + CM_MEDANY. + (CPP_CPU_SPEC): Do not define _LP64, header files do this. + (CPP_CPU_DEFAULT_SPEC): Likewise. + * config/sparc/sol2.h (INIT_SUBTARGET_OPTABS): Get the names right + for arch64 libfuncs. + + * config/sparc/sparc.md (goto_handler_and_restore): Allow any mode + for operand zero. + +Sun Sep 13 09:11:59 1998 Kaveh R. Ghazi + + * acconfig.h (NEED_DECLARATION_STRSIGNAL): Provide a stub. + + * collect2.c: Don't declare `sys_siglist' here. + (my_strsignal): Prototype and define new function. Use it in + place of `sys_siglist' hacks. + + * mips_tfile.c: Likewise. + + * configure.in (AC_CHECK_FUNCS): Check for strsignal. + (GCC_NEED_DECLARATIONS): Likewise. + + * system.h (strsignal): Prototype it, if necessary. + (sys_siglist): Declare it, if necessary. + +Sun Sep 13 04:37:28 1998 David S. Miller + + * loop.c (move_movables): While removing insn sequences, preserve + the next pointer of the most recently deleted insn when we skip + over a NOTE. + +Sun Sep 13 08:13:39 1998 Ben Elliston + + * objc/config-lang.in: Do not output the name of the selected + thread file when building the front-end. The Makefile for the + runtime library will do this. + + * objc/Make-lang.in: Do not build the runtime library or install + the Objective C header files. The Makefile for the runtime + library will do this. + + * objc/Makefile.in (all.indirect): Only build the front-end. + (compiler): Rename to `frontend'. + (obj-runtime): Remove target. + (copy-headers): Likewise. + (clean): No need to remove `libobjc.a' any longer. + +Sat Sep 12 11:37:19 1998 Michael Meissner + + * rs6000.h ({ASM,CPP}_CPU_SPEC): Add support for all machines + supported with -mcpu=xxx. + +Fri Sep 11 23:55:54 1998 David S. Miller + + * flow.c (mark_set_1): Recognize multi-register structure return + values in CALL insns. + (mark_used_regs): Likewise. + (count_reg_sets_1): Likewise. + (count_reg_references): Likewise. + * rtlanal.c (note_stores): Likewise. + (reg_overlap_mentioned_p): Likewise. + * haifa-sched.c (check_live_1): Likewise. + (update_live_1): Likewise. + (sched_analyze_1): Likewise. + (sched_note_set): Likewise. + (birthing_insn_p): Likewise. + (attach_deaths): Likewise. + + * config/sparc/sparc.md (movdf_const_intreg_sp64): Disable. + + +Fri Sep 11 22:57:55 1998 Eric Dumazet + + * config/i386/sco5.h (ASM_WEAKEN_LABEL): Defined as in svr4.h. + +Thu Sep 10 22:02:04 1998 David S. Miller + + * glimits.h (__LONG_MAX__): Recognize __sparcv9 too. + +Thu Sep 10 21:19:10 1998 Jakub Jelinek + + * configure.in: Add check for GAS subsection -1 support. + * acconfig.h (HAVE_GAS_SUBSECTION_ORDERING): Add. + * configure config.in: Rebuilt. + * config/sparc/sparc.h (CASE_VECTOR_MODE): For V9 flag_pic, use + SImode is subsection -1 works, else use DImode. + (ASM_OUTPUT_ADDR_VEC_START, ASM_OUTPUT_ADDR_VEC_END): Define if + subsection -1 works. + * config/sparc/sparc.c (sparc_output_addr_vec, + sparc_output_addr_diff_vec): Use them if defined. + +Thu Sep 10 10:46:01 1998 Mark Mitchell + + * tree.h (DECL_ORIGIN): New macro. + * integrate.c (copy_and_set_decl_abstract_origin): New function. + (copy_decl_list): Use it. + (integrate_parm_decls): Likewise. + (integrate_decl_tree): Likewise. + * dwarf2out.c (decl_ultimate_origin): Simplify. + * dwarfout.c (decl_ultimate_origin): Likewise. + * c-decl.c (duplicate_decls): Use DECL_ORIGIN. + (pushdecl): Likewise. + +Thu Sep 10 08:01:31 1998 Anthony Green + + * config/rs6000/rs6000.c (output_epilog): Add Java support. + +Thu Sep 10 14:48:59 1998 Martin von Löwis + + * invoke.texi (C++ Dialect Options): Document -fhonor-std. + +Thu Sep 10 01:38:05 1998 Jeffrey A Law (law@cygnus.com) + + * reg-stack.c (straighten_stack): Do nothing if the virtual stack is + empty or has a single entry. + + * toplev.c (rest_of_compilation): Open up the dump file for reg-stack + before calling reg_to_stack. + +Thu Sep 10 00:03:34 1998 Richard Henderson + + * alpha.c (alphaev5_insn_pipe): Abort on default case. + (alphaev5_next_group): Swallow CLOBBERs and USEs. + + * c-tree.h (warn_long_long): Declare it. + +Wed Sep 9 23:31:36 1998 (Stephen L Moshier) + + * emit-rtl.c (gen_lowpart_common): Disable optimization of + initialized float-int union if the value is a NaN. + +Wed Sep 9 23:00:48 1998 Nathan Sidwell + + * c-lex.c (real_yylex): Don't warn about long long constants if + we're allowing long long + +Wed Sep 9 21:58:41 1998 Bernd Schmidt + + * except.h (current_function_eh_stub_label): Declare. + (current_function_eh_old_stub_label): Declare. + * function.h (struct function): New members eh_stub_label and + eh_old_stub_label. + * except.c (current_function_eh_stub_label): New variable. + (current_function_eh_old_stub_label): New variable. + (init_eh_for_function): Clear them. + (save_eh_status): Save them. + (restore_eh_status): Restore them. + (expand_builtin_eh_stub): Set current_function_eh_stub_label. + (expand_builtin_eh_stub_old): Set current_function_eh_old_stub_label. + * flow.c (find_basic_blocks_1): When handling a REG_LABEL note, don't + make an edge from the block that contains it to the block starting + with the label if this label is one of the eh stub labels. + If eh stub labels exist, show they are reachable from the last block + in the function. + + * reload1.c (reload): Break out several subroutines and make some + variables global. + (calculate_needs_all_insns): New function, broken out of reload. + (calculate_needs): Likewise. + (find_reload_regs): Likewise. + (find_group): Likewise. + (find_tworeg_group): Likewise. + (something_needs_reloads): New global variable, formerly in reload. + (something_needs_elimination): Likewise. + (caller_save_spill_class): Likewise. + (caller_save_group_size): Likewise. + (max_needs): Likewise. + (group_size): Likewise. + (max_groups): Likewise. + (max_nongroups): Likewise. + (group_mode): Likewise. + (max_needs_insn): Likewise. + (max_groups_insn): Likewise. + (max_nongroups_insn): Likewise. + (failure): Likewise. + + * print-rtl.c (print_rtx): For MEMs, print MEM_ALIAS_SET. + +Wed Sep 9 13:14:41 1998 Richard Henderson + + * loop.c (load_mems): Copy rtx for output mem. + +Wed Sep 9 15:16:58 1998 Gavin Romig-Koch + + * mips/abi64.h (LONG_MAX_SPEC): Don't set LONG_MAX for + mips1 or mips2 either. + +Wed Sep 9 12:31:35 1998 Jeffrey A Law (law@cygnus.com) + + * pa.c (pa_reorg): New marking scheme for jumps inside switch + tables. + (pa_adjust_insn_length): Update to work with new marking scheme + for jumps inside switch tables. + * pa.md (switch_jump): Remove pattern. + (jump): Handle jumps inside jump tables. + + * Makefile.in (profile.o): Depend on insn-config.h + +Wed Sep 9 09:36:51 1998 Jim Wilson + + * iris6.h (DWARF2_UNWIND_INFO): Undef. + +Wed Sep 9 01:32:01 1998 David S. Miller + + Add preliminary native sparcv9 Solaris support. + * configure.in: Recognize sparv9-*-solaris2* + * configure: rebuilt + * config.sub: Recognize sparcv9 just like sparc64. + * config/sparc/sol2-c1.asm config/sparc/sol2-ci.asm + config/sparc/sol2-cn.asm: Macroize so it can be shared between + 32-bit and 64-bit Solaris systems. + * config/sparc/t-sol2: Assemble those with cpp. + * config/sparc/sparc.h (TARGET_CPU_sparcv9): New alias for v9. + (*TF*_LIBCALL): If ARCH64 use V9 names. + * config/sparc/{xm-sysv4-64,sol2-sld-64}.h: New files. + +Wed Sep 9 01:07:30 1998 Jakub Jelinek + + * config/sparc/sparc.h (TARGET_CM_MEDMID): Fix documentation. + (CASE_VECTOR_MODE): Set to SImode even if PTR64, when MEDLOW and + not doing pic. + (ASM_OUTPUT_ADDR_{VEC,DIFF}_ELT): Check CASE_VECTOR_MODE not + Pmode. + * config/sparc/sparc.md (tablejump): Likewise, and sign extend op0 + to Pmode if CASE_VECTOR_MODE is something else. + +Wed Sep 9 00:10:31 1998 Jeffrey A Law (law@cygnus.com) + + * prefix.c (update_path): Correctly handle cases where PATH is + a substring of the builtin prefix, but specifies a different + directory location. + +Tue Sep 8 23:46:04 1998 Hans-Peter Nilsson + + * expr.c: Corrected comment about what MOVE_RATIO does. + * config/alpha/alpha.h: Ditto. + * config/1750a/1750a.h: Ditto. + * config/clipper/clipper.h: Ditto. + * config/i386/i386.h: Ditto. + +Tue Sep 8 22:56:12 1998 Jeffrey A Law (law@cygnus.com) + + * configure.in (m68k-next-nextstep3*): Use collect2. + Similarly for x86 NeXT configurations. + * configure: Rebuilt. + +Tue Sep 8 01:38:57 1998 Nathan Sidwell + + * configure.in: Don't assume srcdir is .../gcc + * configure: Rebuilt. + +Sat Sep 5 16:34:34 EDT 1998 John Wehle (john@feith.com) + + * global.c: Update comments. + (global_alloc): Assign allocation-numbers + even for registers allocated by local_alloc in case + they are later spilled and retry_global_alloc is called. + (mark_reg_store, mark_reg_clobber, + mark_reg_conflicts, mark_reg_death): Always record a + conflict with a pseudo register even if it has been + assigned to a hard register. + (dump_conflicts): Don't list pseudo registers already assigned to + a hard register as needing to be allocated, but do list their + conflicts. + * local-alloc.c: Update comment. + +Mon Sep 7 23:38:01 1998 Jeffrey A Law (law@cygnus.com) + + * configure.in: Check for bogus GCC_EXEC_PREFIX and LIBRARY_PATH. + * configure: Rebuilt. + +Mon Sep 7 22:41:46 1998 Michael Meissner + + * rs6000.c (rs6000_override_options): Fix name for ec603e, to add + missing 'c'. + * t-ppccomm (MULTILIB_MATCHES_FLOAT): Add support for -mcpu=xxx + for all targets that set -msoft-float. + +Mon Sep 7 23:30:07 1998 Kaveh R. Ghazi + + * toplev.c (print_switch_values): Make static to match prototype. + +Mon Sep 7 19:13:59 1998 Jeffrey A Law (law@cygnus.com) + + * configure.in: If we are unable to find the "gnatbind" program, + then do not configure the ada subdir. + * configure: Rebuilt. + +Sun Sep 6 14:03:58 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sun Sep 6 13:28:07 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sun Sep 6 08:54:14 1998 Kaveh R. Ghazi + + * Makefile.in (toplev.o): Depend on $(EXPR_H). + (insn-extract.o, insn-attrtab.o): Depend on toplev.h. + + * gansidecl.h: Define ATTRIBUTE_NORETURN. + + * genattrtab.c: Have insn-attrtab.c include toplev.h. + + * genextract.c: Have insn-extract.c include toplev.h. + + * rtl.h: Don't prototype `fatal_insn_not_found' and `fatal_insn'. + + * toplev.c: Include expr.h. + (really_sorry, fancy_abort): Remove prototypes. + (set_target_switch): Add argument in prototype. + (vfatal): Mark prototype with ATTRIBUTE_NORETURN. + (v_really_sorry): Likewise. + (print_version, print_single_switch, print_switch_values): Make + static and add prototype arguments. + (decl_printable_name): Add prototype arguments. + (lang_expand_expr_t): New typedef. + (lang_expand_expr): Declare as a lang_expand_expr_t. + (incomplete_decl_finalize_hook): Add prototype argument. + (decl_name): Mark variable `verbosity' with ATTRIBUTE_UNUSED. + (botch): Likewise for variable `s'. + (rest_of_type_compilation): Mark variables `type' and `toplev' + with ATTRIBUTE_UNUSED if none of DBX_DEBUGGING_INFO, + XCOFF_DEBUGGING_INFO or SDB_DEBUGGING_INFO are defined. + (display_help): Make variable `i' an `unsigned long'. + (main): Remove unused parameter `envp'. + Cast assignment to `lang_expand_expr' to a `lang_expand_expr_t'. + Cast -1 when comparing it with a `size_t'. + + * toplev.h (fatal, fatal_io_error, pfatal_with_name): Mark + prototype with ATTRIBUTE_NORETURN. + (fatal_insn_not_found, fatal_insn, really_sorry, + push_float_handler, pop_float_handler): Add prototypes. + (fancy_abort): Mark prototype with ATTRIBUTE_NORETURN. + (do_abort, botch): Add prototypes. + +Sat Sep 6 12:05:18 1998 John Carr + + * final.c (final): If a label is reached only from a single jump, + call NOTICE_UPDATE_CC on the jump and its predecessor before + emitting the insn after the label. + + * i386.h: Add AMD K6 support. + Change TARGET_* macros to use table lookup. + (INITIALIZE_TRAMPOLINE): Improve trampoline code. + (ADJUST_COST): Change definition to call function in i386.c. + (ISSUE_RATE): Define as 2 for anything newer than an 80486. + * i386.c: Add AMD K6 support. + Add constants for feature tests used by TARGET_* macros. + (split_di): If before reload, call gen_lowpart and gen_highpart. + (x86_adjust_cost): New function. + (put_jump_code): New function. + (print_operand): New codes 'D' and 'd'. + * i386.md: New insn types. New insn attribute "memory". + Redefine scheduling parameters to use new types and add AMD K6 + support. Explicitly set type of most insns. + (move insns): K6 prefers movl $0,reg to xorl reg,reg. Pentium + Pro and K6 prefer movl $1,reg to incl reg. + (adddi3, subdi3): Set cc_status. + (DImode shift patterns): Change label counters from HOST_WIDE_INT + to int; x86 can't have more than 2^31 DImode shifts per file. + (setcc): Combine all setcc patterns. Allow writing memory. + Combine all jump patterns using match_operator. + (*bzero): Name pattern. Emit mutliple stos instructions when that + is faster than rep stos. + (xordi3, anddi3, iordi3): Simplify DImode logical patterns and + add define_split. + +Sun Sep 6 11:17:20 1998 Dave Love + + * config/m68k/x-next (BOOT_LDFLAGS): Define suitably for f771 + linking. + +Sat Sep 5 22:05:25 1998 Richard Henderson + + * alpha.c (alpha_ra_ever_killed): Inspect the topmost sequence, + not whatever we're generating now. + + * alpha.c (set_frame_related_p, FRP): New. + (alpha_expand_prologue): Mark frame related insns. + (alpha_expand_epilogue): Likewise, but with a null FRP. + * alpha.h (INCOMING_RETURN_ADDR_RTX): New. + * alpha.md (exception_receiver): New. + * alpha/crtbegin.asm (.eh_frame): New beginning. + (__do_frame_setup, __do_frame_takedown): New. + * alpha/crtend.asm (.eh_frame): New ending. + * alpha/elf.h (DWARF2_DEBUGGING_INFO): Define. + (ASM_SPEC): Don't emit both dwarf2 and mdebug. + (ASM_FILE_START): Don't emit .file for dwarf2. + + * rtl.h (enum reg_note): Add REG_FRAME_RELATED_EXPR. + * rtl.c (reg_note_name): Likewise. + * rtl.texi (REG_NOTES): Likewise. + * dwarf2out.c (dwarf2out_frame_debug): Use it. Recognize a store + without an offset. + +Sat Sep 5 14:47:17 1998 Richard Henderson + + * i386.h (PREFERRED_RELOAD_CLASS): Standard fp constants load to TOS. + * i386.md (movsf, movdf, movxf): Validate memory address returned + from force_const_mem. Kill useless REG_EQUAL setting code. + +Sat Sep 5 14:23:31 1998 Torbjorn Granlund + + * m68k.md (zero_extendsidi2): Fix typo. + +Sat Sep 5 13:40:24 1998 Krister Walfridsson + + * configure.in: Removed references to the removed file + * config/xm-netbsd.h. Use ${cpu_type}/xm-netbsd.h for + * arm*-*-netbsd* and ns32k-*-netbsd*. + * config/i386/xm-netbsd.h: Removed unnecessary file. + * config/m68k/xm-netbsd.h: Likewise. + * config/sparc/xm-netbsd.h: Likewise. + * config/mips/xm-netbsd.h: Likewise. + +Sat Aug 29 13:32:58 1998 Mumit Khan + + * i386/cygwin32.h (BIGGEST_ALIGNMENT): Define. + (PCC_BITFIELD_TYPE_MATTERS): Define to be 0. + + * i386/cygwin32.h (ASM_OUTPUT_SECTION_NAME): Don't check for + for exact section attributions. + + * i386/mingw32.h (CPP_PREDEFINES): Add __MSVCRT__ for msvc + runtime. + * i386/crtdll.h (CPP_PREDEFINES): Define. + +Sat Sep 5 03:23:05 1998 Jeffrey A Law (law@cygnus.com) + + * m68k.md (5200 movqi): Do not allow byte sized memory references + using address regs. + * m68k.c (output_move_qimode): Do not use byte sized operations on + address registers. + + * Makefile.in (pexecute.o): Use pexecute.c from libiberty. Provide + explicit rules for building. Similarly for alloca, vfprintf, + choose-temp and mkstemp, getopt, getopt1, and obstack. + (INCLUDES): Add $(srcdir)/../include. + * pexecute.c, alloca.c, vfprintf.c, choose-temp.c, mkstemp.c: Delete. + * getopt.h, getopt.c getopt1.c, obstack.c, obstack.h: Likewise. + +Fri Sep 4 11:57:50 1998 Tom Tromey + + * gcc.c (do_spec_1): [case 'o'] Account for + lang_specific_extra_outfiles. + (main): Correctly clear all slots in outfiles for + lang_specific_extra_outfiles. Set input_file_number before + calling lang_specific_pre_link. + +Fri Sep 4 10:37:07 1998 Jim Wilson + + * loop.c (load_mems): Fix JUMP_LABEL field after for_each_rtx call. + +Fri Sep 4 02:01:05 1998 David S. Miller + + * config/sparc/sparc.c (output_double_int): In all V9 symbolic + cases, use xword. + (sparc_output_deferred_case_vectors): If no work to do, return. + Fix thinko in Sept 1 change. + +1998-09-03 SL Baur + + * Makefile.in: add semicolon in BISON definition for portability. + +Thu Sep 3 13:34:41 1998 Toon Moene + + * config/nextstep.c (handle_pragma): Correct name of third + argument. + +Tue Sep 1 11:30:33 1998 Nick Clifton + + * config/m32r/m32r.md: Change (reg:CC 17) to (reg:SI 17). + * config/m32r/m32r.h: Make register 17 be fixed. + * config/m32r/m32r.c: Use SImode for cc operations. + +Thu Sep 3 18:17:34 1998 Benjamin Kosnik + + * invoke.texi (Warning Options): Add -Wnon-template-friend + documentation. + +Thu Sep 3 18:16:16 1998 Michael Meissner + + * rs6000.c (rs6000_override_options): Add -mcpu={401,e603e}. + +Thu Sep 3 18:05:16 1998 David Edelsohn + + * rs6000.md (movsf): Disable explicit secondary-reload-like + functionality if TARGET_POWERPC64. + (movdf): Remove TARGET_POWERPC64 explicit secondary-reload-like + functionality. + +Thu Sep 3 11:41:40 1998 Robert Lipe + + * fixinc.sco: Borrow code to wrap 'bool' typedefs from tinfo.h + and term.h from fixinc.wrap. + +Thu Sep 3 09:47:31 1998 Kaveh R. Ghazi + + * aclocal.m4 (GCC_HEADER_STRING): New macro to detect if it is + safe to include both string.h and strings.h together. + (GCC_NEED_DECLARATION): Test STRING_WITH_STRINGS when deciding + which headers to search for function declarations. Continue to + prefer string.h over strings.h when both are not acceptable. + + * acconfig.h (STRING_WITH_STRINGS): Add stub. + + * configure.in: Call GCC_HEADER_STRING. + + * system.h: Test STRING_WITH_STRINGS when deciding which headers + to include. Continue to prefer string.h over strings.h when both + are not acceptable. + +Wed Sep 2 23:56:29 1998 David S. Miller + + * config/sparc/sparc.c (output_double_int): If V9 and MEDLOW, do + not assume top 32-bits of symbolic addresses are zero if + flag_pic. + +Thu Sep 3 00:23:21 1998 Richard Henderson + + * ginclude/va-alpha.h: Protect entire second portion of the + file against double inclusion. + +Thu Sep 3 00:37:55 1998 Ovidiu Predescu + + Added support for the Boehm's garbage collector. + * configure.in: Handle --enable-objc-gc. + * configure: Rebuilt. + * Makefile.in (CHECK_TARGETS): Add check-objc. + (check-objc): New rule. + * objc/Make-lang.in: Build a different Objective-C library that + runs with the Boehm's collector. + * objc/encoding.c (objc_round_acc_size_for_types): New function. + * objc/encoding.c: Correctly compute the size of compound types in + the presence of bitfields. Skip the variable name of the type if + any. Added support for long long. + * objc/encoding.h (_C_GCINVISIBLE): New specifier. + (_F_GCINVISIBLE): New mask. + * objc/gc.c: New file. Compute the type memory mask associated with + a class based on the runtime information. + * objc/misc.c: Added the hooks that use the Boehm's collector + allocation functions. + * objc/objc-act.c (build_class_template): Generate a new class + member (gc_object_type) to hold the class' type memory mask. + (build_shared_structure_initializer): Initialize the new member to + NULL. + (encode_complete_bitfield): New function. Generate the new + encoding. + (encode_field_decl): Generate the new encoding only for the GNU + runtime. + * objc/objc-api.h (_C_LNG_LNG, _C_ULNG_LNG): New specifiers for the + long long types. + (class_get_gc_object_type): New function to mark a pointer instance + variable as a weak pointer. + * objc/objc-features.texi: New file. + * objc/objc.h (gc_object_type): New class member. + * objc/objects.c (class_create_instance): Create a typed memory + object when compiled with Boehm's collector support. + * objc/sendmsg.c (__objc_init_install_dtable): Call + __objc_send_initialize instead of setting the initialize flag. + (__objc_send_initialize): Call __objc_generate_gc_type_description + to generate the class type memory mask. Rewrite the code that + sends the +initialize so that it is called only once (bug report + and fix from Ronald Pijnacker ). + * testsuite/objc: New testsuite for Objective-C type encoding. + * testsuite/lib/objc-torture.exp: New file. + * testsuite/lib/objc.exp: New file. + +Wed Sep 2 14:47:36 1998 Jim Wilson + + * jump.c (jump_optimize): In if/then/else transformations, add + another call to modified_between_p for the jump insn. + +Wed Sep 2 14:16:49 1998 Jeffrey A Law (law@cygnus.com) + + * fix-header.c (symlink): Treat like readlink. + +Wed Sep 2 19:30:06 1998 J"orn Rennecke + + * dwarfout.c (fundamental_type_code): Encode 32 bit floats/doubles + as FT_float. + +Wed Sep 2 10:06:07 1998 Nick Clifton + + * config/nextstep.h: Update HANDLE_PRAGMA macro. + * config/h8300/h8300.h: Update HANDLE_PRAGMA macro. + * config/i960/i960.h: Update HANDLE_PRAGMA macro. + + * config/nextstep.c (handle_pragma): Take three arguments, as per + the new HANDLE_PRAGMA macro specification. + * config/h8300/h8300.c (handle_pragma): Take three arguments, as + per the new HANDLE_PRAGMA macro specification. + * config/i960/i960.c (process_pragma): Take three arguments, as + per the new HANDLE_PRAGMA macro specification. + +Wed Sep 2 09:25:29 1998 Nick Clifton + + * c-lex.c (check_newline): Call HANDLE_PRAGMA before + HANDLE_SYSV_PRAGMA if both are defined. Generate warning messages + if unknown pragmas are encountered. + (handle_sysv_pragma): Interpret return code from + handle_pragma_token (). Return success/failure indication rather + than next unprocessed character. + (pragma_getc): New function: retrieves characters from the + input stream. Defined when HANDLE_PRAGMA is enabled. + (pragma_ungetc): New function: replaces characters back into the + input stream. Defined when HANDLE_PRAGMA is enabled. + + * c-pragma.c (handle_pragma_token): Return success/failure status + of the parse. + + * c-pragma.h: Change prototype of handle_pragma_token(). + + * varasm.c: (handle_pragma_weak): Only create this function if + HANDLE_PRAGMA_WEAK is defined. + + * c-common,c (decl_attributes): If defined call the expression + contained within the INSERT_ATTRIBUTES macro before adding + attributes to a decl. + + * tm.texi (HANDLE_PRAGMA): Document the new verion of + HANDLE_PRAGMA, which takes three arguments. + (INSERT_ATTRIBUTES): Document this new macro. + + * LANGUAGES: Document the new version of HANDLE_PRAGMA and the + new INSERT_ATTRIBUTES macro. + +Wed Sep 2 02:03:23 1998 David S. Miller + + * config/sparc/sparc.md (movdf): Only generate special RTL for + LABEL_REFs when PIC. + (move_label_di): Remove + (movdi_pic_label_ref, movdi_high_pic_label_ref, + movdi_lo_sum_pic_label_ref): New patterns for 64-bit label + references when PIC. + * config/sparc/sparc.h (ASM_OUTPUT_ADDR_VEC_ELT, + ASM_OUTPUT_ADDR_DIFF_ELT): Don't do anything special for MEDLOW, + output an .xword for all 64-bit cases. + +Tue Sep 1 15:55:17 1998 David S. Miller + + * config/sparc/sparc.c (finalize_pic): Don't output arbitrary + alignment, use FUNCTION_BOUNDARY instead. + (sparc_output_deferred_case_vectors): Likewise. + +Mon Aug 31 17:25:41 1998 David S. Miller + + * config/sparc/sparc.md (movsf_const_intreg): Kill warning. + (movtf_insn_sp64, movtf_no_e_insn_sp64): Reorder alternatives. + +Mon Aug 31 13:57:55 1998 Richard Henderson + + * alpha/va_list.h: New file. + * alpha/x-alpha (EXTRA_HEADERS): New. Add va_list.h. + +Mon Aug 31 14:55:02 1998 Jeffrey A Law (law@cygnus.com) + + * NEWS: Add SCO Openserver and Unixware 7 notes. + + * NEWS: Fix typos. + +Mon Aug 31 15:42:18 1998 Dave Brolley + + * varasm.c (compare_constant_1): Handle RANGE_EXPR. + (record_constant_1): Handle RANGE_EXPR. + +Mon Aug 31 10:54:03 1998 Richard Henderson + + * print-rtl.c (print_rtx): NOTE_INSN_LIVE has an rtx not a bitmap. + * haifa-sched.c (sched_analyze): Handle NOTE_INSN_RANGE_START + and NOTE_INSN_RANGE_END specially. + (reemit_notes): Likewise. + +Mon Aug 31 10:18:52 1998 Kaveh R. Ghazi + + * sparc.c (TMASK, UMASK): Use `(unsigned)1' not `1U'. + (ultrasparc_sched_init): Remove unneeded &. + +Mon Aug 31 10:47:16 1998 Andreas Schwab + + * config/m68k/m68k.h (TARGET_SWITCHES): Don't remove MASK_68040 + for m68020-60, to prevent the use of fintrz. + +Sun Aug 30 22:17:20 1998 Mark Mitchell + + * configure.in: If the native compiler is GCC use $(WARN_CFLAGS) + even in stage1. + * Makefile.in: Likewise. + * configure: Regenerated. + +Sun Aug 30 22:15:41 1998 H.J. Lu (hjl@gnu.org) + + * configure.in (gxx_include_dir): Changed to + '${prefix}/include/g++'-${libstdcxx_interface}. + * configure: Rebuilt. + +Sun Aug 30 20:19:43 1998 Hans-Peter Nilsson + + * expr.c (expand_expr): Change ">" to ">=" making MOVE_RATIO use + consistent. + * tm.texi (Costs): Say MOVE_RATIO is number of mem-mem move + *sequences* *below* which scalar moves will be used. + +Sun Aug 30 17:18:43 1998 Jeffrey A Law (law@cygnus.com) + + * collect2.c (mktemp): Delete unused declaration. + + * config/xm-netbsd.h: Remove unnecessary file. + * config/*/xm-netbsd.h: Do not include the generic xm-netbsd.h + file anymore, it is not needed. + +Sun Aug 30 16:05:45 1998 Mark Mitchell + + * convert.c (convert_to_integer): Issue an error on conversions to + incomplete types. + +Sun Aug 30 16:47:20 1998 Martin von Lvwis + + * Makefile.in: Add lang_tree_files and gencheck.h. + * configure.in: Generate them. + * gencheck.c: Include gencheck.h. + +Sat Aug 29 21:38:24 1998 David S. Miller + + * config/sparc/sparc.md (pic_lo_sum_di, pic_sethi_di): Rename to + movdi_lo_sum_pic and movdi_high_pic and make visible. + * config/sparc/sparc.c (legitimize_pic_address): For -fPIC, + emit these when Pmode is not SImode. + * config/sparc/linux64.h (SPARC_DEFAULT_CMODEL): Make CM_MEDLOW. + +Sat Aug 29 14:59:32 1998 Mumit Khan + + * i386/cygwin32.h (ASM_OUTPUT_SECTION_NAME): Don't emit + .linkonce directive after the first time. + +Sat Aug 29 12:39:56 1998 Jeffrey A Law (law@cygnus.com) + + * m68k.md (beq0_di): Generate correct (and more efficient) code when + the clobbered operand overlaps with an input. + (bne0_di): Similarly. + + * Makefile.in (INSTALL): Remove "--no-header" argument. + + * NEWS: Various updates. + +Fri Aug 28 19:00:44 1998 David S. Miller + + * config/sparc/sparc.c (arith_operand, const64_operand, + const64_high_operand, arith_double_4096_operand): Mark mode as + unused. + (create_simple_focus_bits): Remove unused arg highest_bit_set, all + callers changed. + (sparc_emit_set_const64): Remove unused variable i. + (sparc_splitdi_legitimate): Likewise for addr_part. + (ultra_code_from_mask): Likewise for mask. + (ultra_cmove_results_ready_p): Fixup entry modulo calc. and + reverse return values so it matches usage and comments. + (ultra_flush_pipeline): Likewise. + (ultra_fpmode_conflict_exists): Likewise, remove unused variable + this_type, and allow loads and stores of differing FP modes as + they do not create a conflict. + (ultra_find_type): Initialize fpmode to SFmode, fix + parenthesization thinkos in large conditional. + (ultrasparc_sched_init): Mark dump and sched_verbose as unused. + Init free_slot_mask after ultra_cur_hist is reset, not before. + (ultrasparc_rescan_pipeline_state): Remove unused variable ucode. + (ultrasparc_sched_reorder): Don't bzero current pipeline state, + use ultra_flush_pipeline instead, then re-init group pointer. + Fix statement with no effect. If no progress made in, and no + instructions scheduled at all, advance to new pipeline cycle else + we get into an endless loop. + (ultrasparc_adjust_cost): Remove previous arg. + * config/sparc/sparc.h (ADJUST_COST): Update to reflect that. + +Fri Aug 28 13:52:35 1998 Jim Wilson + + * sparc.md (DImode, DFmode, TFmode splits): Delete self_reference + code. Use reg_overlap_mentioned_p to detect when source and + destination overlap. + (negtf2_notv9+1): Use DFmode instead of SFmode in last two operands. + +1998-08-28 Brendan Kehoe + + * loop.c (check_dbra_loop): Pass COMPARISON_VALUE, not + COMPARISON_VAL, into invariant_p. + +Fri Aug 28 15:13:25 1998 J"orn Rennecke + + * regmove.c (regclass_compatible_p): New function. + (regmove_optimize): Use it. + + Use NREGS parameter insted of calling max_reg_num. + + (fixup_match_1): Don't use code = MINUS when later tieing with + a hard register is likely. + +Fri Aug 28 14:54:07 1998 J"orn Rennecke + + * loop.c (check_dbra_loop): Fix calculation of FINAL_VALUE when + COMPARISON_VAL was normalized. + +Thu Aug 27 20:10:46 1998 Jeffrey A Law (law@cygnus.com) + + * loop.c (check_dbra_loop): The loop ending comparison value + must be an invariant or we can not reverse the loop. + + * loop.c (scan_loop): Count down from max_reg_num - 1 to + FIRST_PSEUDO_REGISTER to avoid calling max_reg_num each iteration + of the loop. + (load_mems_and_recount_loop_regs_set): Likewise. + + * i386.c (print_operand): Remove obsolete 'c' docs. + +Wed Aug 26 17:13:37 1998 Tom Tromey + + * gthr.h: Document __GTHREAD_MUTEX_INIT_FUNCTION. + * frame.c (init_object_mutex): New function. + (init_object_mutex_once): Likewise. + (find_fde): Call it. + (__register_frame_info): Likewise. + (__register_frame_info_table): Likewise. + (__deregister_frame_info): Likewise. + +Thu Aug 27 15:14:18 1998 Jeffrey A Law (law@cygnus.com) + + * haifa-sched.c (sched_analyze_insn): Fix thinko in last change. + +Thu Aug 27 16:34:51 1998 J"orn Rennecke + + * loop.c (check_dbra_loop): Enable code for reversal + of some loops without a known constant loop end. + +Wed Aug 26 18:38:15 1998 Richard Henderson + + * haifa-sched.c (last_clock_var): New. + (schedule_block): Initialize it. + (schedule_insn): Use it to fill insn modes with issue information. + + * alpha.c (alpha_handle_trap_shadows): Remove do-nothing exit. + Tag trapb and next insn with TImode. + (alphaev5_insn_pipe, alphaev5_next_group, alphaev5_align_insns): New. + (alpha_reorg): Add conditional for alpha_handle_trap_shadows. + Invoke alphaev5_align_insns as appropriate. + * alpha.h (LABEL_ALIGN_AFTER_BARRIER): Was ALIGN_LABEL_AFTER_BARRIER. + (MD_SCHED_VARIABLE_ISSUE): New. + * alpha.md (attr type): Add multi. + (define_asm_attributes): New. + (prologue_stack_probe_loop, builtin_setjmp_receiver): Set type multi. + (arg_home): Likewise. + (fnop, unop, realign): New. + +Wed Aug 26 15:55:41 1998 Jim Wilson + + * iris5.h (PREFERRED_DEBUGGING_TYPE): Undef. + * iris5gas.h (PREFERRED_DEBUGGING_TYPE): Define. + + * configure.in (powerpc-ibm-aix4.[12]*): Change from 4.[12].*. + (rs6000-ibm-aix4.[12]*): Likewise. + * configure: Regnerate. + +Wed Aug 26 09:30:59 1998 Nick Clifton + + * config/arm/thumb.c (thumb_exit): Do not move a4 into lr if it + already contains the return address. + +Wed Aug 26 12:57:09 1998 Jeffrey A Law (law@cygnus.com) + + * calls.c (expand_call): Use bitfield instructions to extract/deposit + word sized hunks when loading unaligned args into registers. + + * haifa-sched.c (sched_analyze_insn): Only create scheduling + barriers for LOOP, EH and SETJMP notes on the loop_notes list. + + * mn10300.h (RTX_COSTS): Handle UDIV and UMOD too. + +Wed Aug 26 16:35:37 1998 J"orn Rennecke + + * loop.c (check_dbra_loop): Add some code that would allow reversal + of some loops without a known constant loop end if it were enabled. + +Wed Aug 26 11:08:44 1998 Gavin Romig-Koch + + * mips.md (lshrsi3_internal2+2): Fix type-o. + +Wed Aug 26 10:53:03 1998 Kaveh R. Ghazi + + * system.h: Include stdarg.h/varargs.h, make sure they are ordered + correctly with regards to stdio.h. + + * calls.c: Remove stdarg.h/varargs.h. + * cccp.c: Likewise. + * cexp.y: Likewise. + * combine.c: Likewise. + * cpperror.c: Likewise. + * cpplib.c: Likewise. + * cpplib.h: Likewise. + * doprint.c: Likewise. + * emit-rtl.c: Likewise. + * final.c: Likewise. + * fix-header.c: Likewise. + * gcc.c: Likewise. + * genattr.c: Likewise. + * genattrtab.c: Likewise. + * gencodes.c: Likewise. + * genconfig.c: Likewise. + * genemit.c: Likewise. + * genextract.c: Likewise. + * genflags.c: Likewise. + * genopinit.c: Likewise. + * genoutput.c: Likewise. + * genpeep.c: Likewise. + * genrecog.c: Likewise. + * mips-tfile.c: Likewise. + * prefix.c: Likewise. + * protoize.c: Likewise. + * regmove.c: Likewise. + * toplev.c: Likewise. + * tree.c: Likewise. + +Wed Aug 26 05:09:27 1998 Jakub Jelinek + + * config/sparc/sparc.c (sparc_override_options): If not + TARGET_FPU, turn off TARGET_VIS. + * config/sparc/sparc.h (TARGET_SWITCHES): Add no-vis. + (LEGITIMATE_CONSTANT_P): Allow SF/DF mode zero when TARGET_VIS. + * config/sparc/sparc.md (movsi_insn): Use fzeros not fzero. + (movdi_insn_sp64): Add VIS fzero alternative. + (clear_sf, clear_df): New VIS patterns. + (movsf, movdf expanders): Allow fp_zero_operand flat out when + TARGET_VIS. + (one_cmpldi2_sp64): Provide new fnot1 VIS alternative. + +Tue Aug 25 10:57:41 1998 Mark Mitchell + + * loop.c (n_times_set, n_times_used, may_not_optimize, + reg_single_usage): Convert to varrays. All uses changed. + (insert_loop_mem): Return a value. + (scan_loop): Tweak AVOID_CC_MODE_COPIES code. + (load_mems_and_recount_loop_regs_set): Likewise. Grow the arrays, if + necessary. + +Tue Aug 25 23:57:12 1998 Jeffrey A Law (law@cygnus.com) + + * From Alexandre: + * configure.in: Do not set thread_file to "irix" since no such + support exists yet. + + * sparc.md (float abs/neg splits): Check reload_completed before + calling alter_subreg. + +Tue Aug 25 19:17:59 1998 David S. Miller + + * config/sparc/sparc.c (sparc_absnegfloat_split_legitimate): New + function. + * config/sparc/sparc.h: Declare it. + * config/sparc/sparc.md (float abs/neg splits): Use it. + (all other splits): Handle SUBREGs properly where necessary. + (unnamed (1< + + * config/v850/v850.c (movsi_source_operand): Treat CONSTANT_P_RTX + as an ordinary operand. + +Tue Aug 25 12:54:57 1998 Jason Merrill + + * tree.c (valid_machine_attribute): Don't apply attributes to both + decl and type. + +Tue Aug 25 12:23:20 PDT 1998 Richard Henderson + + * reload.c (operands_match_p): Handle rtvecs. + + * i386.c (legitimate_pic_address_disp_p): New. + (legitimate_address_p): Use it. + (legitimize_pic_address): Use unspecs to represent @GOT and @GOTOFF. + Handle constant pool symbols just like statics. + (emit_pic_move): Use Pmode not SImode for clarity. + (output_pic_addr_const) [SYMBOL_REF]: Remove @GOT and @GOTOFF hacks. + [UNSPEC]: New, handling what we killed above. + [PLUS]: Detect and abort on invalid symbol arithmetic. + * i386.h (CONSTANT_ADDRESS_P): Remove HIGH. + +Tue Aug 25 12:02:23 1998 Mark Mitchell + + * alias.c: Include output.h. + (DIFFERENT_ALIAS_SETS_P): Don't treat alias sets as + different if we're in a varargs function. + * Makefile.in (alias.o): Depend on output.h + +Tue Aug 25 19:20:12 1998 J"orn Rennecke + + * sh.h (GIV_SORT_CRITERION): Delete. + +Tue Aug 25 13:19:46 1998 Dave Brolley + + * regclass.c (regclass): Use xmalloc/free instead of alloca. + * stupid.c (stupid_life_analysis): Ditto. + * reload1.c (reload): Ditto. + +Tue Aug 25 05:48:18 1998 Jakub Jelinek + + * config/sparc/sparc.c (arith_4096_operand, arith_add_operand, + arith_double_4096_operand, arith_double_add_operand): New + predicates. + * config/sparc/sparc.h (PREDICATE_CODES): Add them, declare them. + * config/sparc/sparc.md (adddi3, addsi3, subdi3, subsi3): Use + them to transform add/sub 4096 into add/sub -4096. + +Mon Aug 24 23:31:03 1998 David S. Miller + + * loop.c (scan_loop): Allocate some slop to handle pseudos + generated by move_movables. + (load_mems_and_recount_loop_regs_set): Honor AVOID_CC_MODE_COPIES + here too. + +Mon Aug 24 19:45:40 1998 Jim Wilson + + * tree.def (DECL_RESULT): Correct documentation. + +Tue Aug 25 01:15:27 1998 J"orn Rennecke + + * reload1.c (reload_reg_free_before_p): New argument EQUIV; Changed + all callers. Abort for RELOAD_FOR_INSN. RELOAD_FOR_OUTADDR_ADDR: + conflicts will all RELOAD_FOR_OUTPUT reloads. + + * reload1.c (reload_cse_regs_1): When deleting a no-op move that + loads the function result, substitute with a USE. + +Mon Aug 24 15:20:19 1998 David Edelsohn + + * rs6000.h (GO_IF_LEGITIMATE_ADDRESS): Use TARGET_POWERPC64 + when testing LEGITIMATE_INDEXED_ADDRESS_P DFmode and DImode. + (LEGITIMIZE_ADDRESS): Use TARGET_POWERPC64 for INDEXED fixup. + * rs6000.c (print_operand, case 'L'): Add UNITS_PER_WORD, not 4. + (print_operand, cases 'O' and 'T'): Fix typos in lossage strings. + * rs6000.md (fix_truncdfsi2_store): Remove %w from non-CONST_INT + operand. + (movdf_softfloat32, movdf_hardfloat64, movdf_softfloat64): Change + 'o' to 'm' for GPR variant constraints. + +Mon Aug 24 10:25:46 1998 Jeffrey A Law (law@cygnus.com) + + * loop.c (scan_loop): Honor AVOID_CC_MODE_COPIES. + + * h8300.h (STRIP_NAME_ENCODING): Fix typo. + + * sparc.md (TFmode splits): Use reg_overlap_mentioned_p to detect + when the source and destination overlap. + + * stmt.c (emit_case_nodes): Change rtx_function to rtx_fn to avoid + clash with global type. + +Mon Aug 24 00:53:53 1998 Jason Merrill + + * fixinc.irix: Add curses.h handling from fixinc.wrap. + + * c-common.c (combine_strings): Also set TREE_READONLY. + Change warn_write_strings to flag_const_strings. + * c-decl.c, c-tree.h: Likewise. + +Sun Aug 23 18:39:11 1998 David S. Miller + + * config/sparc/sparc.c (sparc_emit_set_const32): If outputting a + CONST_INT, not a symbolic reference, don't use a HIGH/LO_SUM + sequence, use SET/IOR instead so CSE can see it. + * config/sparc/sparc.md (movhi_const64_special, + movsi_const64_special): New patterns necessitated by that change. + (movhi_high): Remove. + (movhi_lo_sum): Change to match an IOR. + (movdf_insn_sp32): Test TARGET_V9 not TARGET_ARCH64. + (movdf_insn_v9only): New pattern for when V9 but not ARCH64. + (movdf_insn_sp64): Test both TARGET_V9 and TARGET_ARCH64. + (movdf splits): Allow when not V9 or when not ARCH64 and integer + registers are involved. + (snesi_zero_extend split): Remove reload_completed test. + (unnamed plus and minus zero_extend sidi splits): Add it. + +Sun Aug 23 11:56:08 1998 Mark Mitchell + + * extend.texi: Remove description of extension to explicit + instantiation that is now endorsed by standard C++. + +Sun Aug 23 09:39:09 1998 David S. Miller + + * config/arc/arc.c (arc_initialize_pic): Remove. + * config/arc/arc.h (INITIALIZE_PIC): Similarly, this routine does + nothing on any platform and is invoked by no-one, it does not even + appear in the documentation. + * config/sparc/sparc.h (INITIALIZE_PIC): Likewise. + * config/sparc/sparc.c (initialize_pic): Likewise. + (find_addr_reg): Remove this as well, no longer referenced after + my rewrite. + +Sun Aug 23 00:17:14 1998 Jeffrey A Law (law@cygnus.com) + + * recog.c (validate_replace_rtx_group): New function. + * recog.h (validate_replace_rtx_group): Declare it. + * regmove.c (optimize_reg_copy_3): If any substitution fails, then undo + the entire group of substitutions. + +Sat Aug 22 23:31:00 1998 Klaus-Georg Adams (Klaus-Georg.Adams@chemie.uni-karlsruhe.de) + + * loop.c (load_mems): Fix initializers. + +Fri Aug 21 23:07:46 1998 David S. Miller + + * config/sparc/sparc.md (TFmode splits): Handle destination + registers being referenced in the address correctly. + + * expmed.c (make_tree) [CONST_INT]: Sign extend even if + TREE_UNSIGNED, when bitsize of type's mode is larger than + HOST_BITS_PER_WIDE_INT. + +Fri Aug 21 19:31:31 1998 Alexandre Petit-Bianco + + * tree.def (LABELED_BLOCK_EXPR, EXIT_BLOCK_EXPR): New tree nodes. + * tree.h (LABELED_BLOCK_LABEL, LABELED_BLOCK_BODY, + EXIT_BLOCK_LABELED_BLOCK, EXIT_BLOCK_RETURN, LOOP_EXPR_BODY): New + macros. + * expr.c (expand_expr): Handle LABELED_BLOCK_EXPR and + EXIT_BLOCK_EXPR. + +Thu Aug 20 19:43:44 1998 Jeffrey A Law (law@cygnus.com) + + * h8300.c (h8300_encode_label): Use '&' for tiny data items. + * h8300.h (TINY_DATA_NAME_P): Likewise. + (STRIP_NAME_ENCODING): Handle '&'. + + * mn10200.h (REG_OK_FOR_INDEX_P): Do not check the mode of the + register (it could be accessed via an outer SUBREG). + (REG_OK_FOR_BASE_P): Likewwise. + (GO_IF_LEGITIMATE_ADDRESS): Consistently use REGNO_OK_FOR_BASE_P. + + * remove.c (optimize_reg_copy_3): Abort instead of silently generating + bogus rtl. + + * jump.c (rtx_renumbered_equal_p): Do not consider PLUS commutative. + +Thu Aug 20 17:35:20 1998 David S. Miller + + * config/sparc/sparc.md (movtf_insn_sp32): All memory operands + must be offsettable so the splits can be made. + +Thu Aug 20 13:56:53 1998 Michael Meissner + + * config/i386/winnt.c: Include system.h, not stdio.h to get + sys/param.h pulled in before rtl.h in case the system defines MIN + and MAX. + +Thu Aug 20 13:44:20 1998 David Edelsohn + + * rs6000.md (movqi, movhi): Add CONSTANT_P_RTX. + +Thu Aug 20 13:15:11 1998 Dave Brolley + + * stor-layout.c (layout_type): Compute TYPE_SIZE_UNIT correctly for + arrays of bits. + * cpplib.c (cpp_define): Handle macros with parameters. + +Wed Aug 19 21:33:19 1998 David Edelsohn + + * rs6000.c (rs6000_output_load_toc_table): Use ld for 64-bit. + (output_toc): Use single TOC slot or llong minimal-toc for DFmode + and DImode 64-bit. Use llong for minimal-toc SFmode and + SYMBOL_REF / LABEL_REF 64-bit. + (output_function_profiler): Use llong for profiler label and ld to + load 64-bit label address. + +Wed Aug 19 17:52:27 1998 Nick Clifton (nickc@cygnus.com) + + * config/arm/thumb.md (extendqisi2_insn): Cope with REG + + OFFSET addressing. + +Wed Aug 19 14:13:31 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Wed Aug 19 13:10:30 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Wed Aug 19 13:06:47 1998 Jason Merrill + + * collect2.c (extract_init_priority): Use atoi instead of strtoul. + +Wed Aug 19 13:51:35 1998 Hans-Peter Nilsson + + * tm.texi (Misc): Fix typo "teh". + + * tm.texi (PIC): Fix typo "PPIC". + + * tm.texi (Caller Saves): Say that DEFAULT_CALLER_SAVES has no + effect when -O2 and higher. + * invoke.texi (Optimize Options): Likewise for -fcaller-saves. + +1998-08-19 Michael Hayes + + * regclass.c: Changed register set documentation to be consistent + with GCC behaviour. + + * final.c (final_start_function) Removed redundant test for + call_fixed_regs. + +Wed Aug 19 13:28:41 1998 Mark Mitchell + + * rtl.h (rtx_function): New type. + (for_each_rtx): New function. + * rtlanal.c (for_each_rtx): Define it. + + * recog.c (change_t): New type. + (change_objects, change_old_codes, change_locs, change_olds): + Replace with ... + (changes): New variable. + (validate_change): Dynamically allocate room for more changes, if + necessary. Uses changes array instead of change_objects, etc. + (apply_change_group): Use changes array instead of + change_objects, etc. + + * loop.c (loop_mem_info): New type. + (loop_mems): New variable. + (loop_mems_idx): Likewise. + (looop_mems_allocated): Likewise. + (scan_loop): Remove nregs parameter. + (next_insn_in_loop): New function. + (load_mems_and_recount_loop_regs_set): Likewise. + (load_mems): Likewise. + (insert_loop_mem): Likewise. + (replace_loop_mem): Likewise. + (replace_label): Likewise. + (INSN_IN_RANGE_P): New macro. + (loop_optimize): Don't pass max_reg_num() to scan_loop. + (scan_loop): Remove nregs parameter, compute it after any new + registers are created by load_mems. Use INSN_IN_RANGE_P and + next_insn_in_loop rather than expanding them inline. Call + load_mems to load memory into pseudos, if appropriate. + (prescan_loop): Figure out whether or not there are jumps from the + loop to targets other than the label immediately following the + loop. Call insert_loop_mem to notice all the MEMs used in the + loop, if it could be safe to pull MEMs into REGs for the duration + of the loop. + (strength_reduce): Use next_insn_in_loop. Tweak comments. + +Wed Aug 19 08:29:44 1998 Richard Earnshaw (rearnsha@arm.com) + + * arm.c (arm_override_options): Remove lie about ignoring PIC flag. + +Wed Aug 19 07:08:15 1998 David S. Miller + + * config/sparc/sparc.c (finalize_pic): Check for the correct + nonlocal_goto_receiver UNSPEC number. + * config/sparc/sparc.md (nonlocal_goto_receiver): Add comment + making note of this dependency existing in sparc.c + (negtf2_notv9 split): Give NEG SFmode. + (negsf2): Fix insn output string. + +Tue Aug 18 12:40:27 1998 Richard Henderson + + * c-common.c (decl_attributes): Issue an error if the argument + to alias is not a string. + +Tue Aug 18 10:33:30 1998 Jeffrey A Law (law@cygnus.com) + + * haifa-sched.c (sched_analyze): Put all JUMP_INSNs on the last + pending memory flush list. + + * combine.c (can_combine_p): Allow combining insns with REG_RETVAL + notes. + (try_combine): Allow combining insns with REG_LIBCALL notes. + + * expr.c (emit_block_move): Do not call memcpy as a libcall + instead build up a CALL_EXPR and call it like any other + function. + (clear_storage): Similarly for memset. + + * regmove.c (fixup_match_2): Do not call reg_overlap_mentioned_p + on notes. + + * Makefile.in (cplus-dem.o): Provide explicit rules for building + cplus-dem.o + + * regmove.c (optimize_reg_copy_1): Update REG_N_CALLS_CROSSED + and REG_LIVE_LENGTH as successful substitutions are made. + +Tue Aug 18 07:15:27 1998 Kaveh R. Ghazi + + * config/sparc/sparc.c (ultra_find_type): Add empty semicolon + statement after end of loop label. + +Tue Aug 18 07:13:27 1998 David S. Miller + + * config/sparc/sparc.c (ultra_types_avail): New variable. + (ultra_build_types_avail): New function to record mask of insn + types in ready list at this cycle. + (ultrasparc_sched_reorder): Call it. + (ultra_find_type): Use it to quicken the search. Also simplif + dependency check, don't use rtx_equal_p because we know exactly + what we are looking for. + +Tue Aug 18 03:20:53 1998 Richard Earnshaw (rearnsha@arm.com) + + * arm.h (SECONDARY_INPUT_RELOAD_CLASS): Return NO_REGS if compiling + for architecture v4. + +Mon Aug 17 21:26:38 1998 David S. Miller + + * config/sparc/sparc.md (sltu, sgeu): Don't FAIL, call + gen_compare_reg. + (movsf_const_intreg, movsf_const_high, movsf_const_lo, + movdf_const_intreg and helper splits): New patterns to move float + constants into integer registers. + (negtf2, negdf2, abstf2, absdf2): Rework using new patterns and + splits. + +Mon Aug 17 11:46:19 1998 Jeffrey A Law (law@cygnus.com) + + * From Graham + * tree.c (build_index_type): Copy TYPE_SIZE_UNIT from sizetype + to itype. + * c-decl.c (finish_enum): Copy TYPE_SIZ_UNIT from enumtype to tem. + + * rs6000.c (secondary_reload_class): For TARGET_ELF, indicate that + a BASE_REGS register is needed as an intermediate when copying + a symbolic value into any register class other than BASE_REGS. + + * expr.c (move_by_pieces): No longer static. Remove prototype. + * rtl.h (move_by_pieces): Add extern prototype. + * mips.c (expand_block_move): Handle aligned straight line copy by + calling move_by_pieces. + + * expr.c (expand_expr): Allow assignments from TImode PARM_DECLs + and VAR_DECLs. + +Mon Aug 17 10:28:52 1998 Mark Mitchell + + * stmt.c (expand_end_loop): Tidy. Allow unconditional + jumps out of the loop to be treated as part of the exit test. + +Mon Aug 17 10:06:11 1998 Kaveh R. Ghazi + Jeff Law + + * Makefile.in (cplus-dep.o): Use cplus-dem.c from libiberty. + * cplus-dem.c: Delete. + + * Makefile.in (fold-const.o): depend on $(RTL_H). + + * fold-const.c: Include rtl.h to get the prototype for + `set_identifier_local_value'. + + * loop.c (express_from_1): Remove unused variable `tmp'. + (combine_givs): cast the first argument of bzero to char *. + + * toplev.c (display_help): Remove unused variable `looking_for_start'. + + * c-decl.c (init_decl_processing): Remove unneeded &. + + * alpha.h (alpha_initialize_trampoline): Provide prototype. + + * except.c (set_exception_lang_code, set_exception_version_code): + Change parameter from `short' to `int' to avoid using a gcc + extension. + + * except.h (set_exception_lang_code, set_exception_version_code): + Likewise for prototypes. + + * flow.c (count_reg_references): Remove unused variables `regno' + and `i'. + + * gcse.c (hash_scan_insn): Declare parameter `in_libcall_block'. + + * prefix.c (translate_name): Cast the result of `alloca'. + + * varray.h (VARRAY_FREE): Reimplement as a `do-while(0)' statement. + +Mon Aug 17 09:23:42 1998 Andreas Schwab + + * config/m68k/m68k.c: Include "system.h" instead of . + Include "toplev.h". + (valid_dbcc_comparison_p): Mark mode argument as unused. + (symbolic_operand): Likewise. + (legitimize_pic_address): Likewise. + (const_uint32_operand): Likewise. + (const_sint32_operand): Likewise. + * sched.c [!INSN_SCHEDULING]: Define only dummy function + schedule_insns and comment out rest of file. + + * m68k.c (output_move_simode_const): Use subl to move a zero into an + address register. + (output_move_[hq]imode): Likewise. + +Mon Aug 17 09:15:47 1998 Jeffrey A Law (law@cygnus.com) + + * toplev.c (main): Enable -fstrict-aliasing for -O2 and above. + * invoke.texi: Corresponding changes. + +Mon Aug 17 02:03:55 1998 Richard Henderson + + * regclass.c (allocate_reg_info): Respect MIN when clearing data. + +Sun Aug 16 17:37:06 1998 David S. Miller + + * config/sparc/sparc.c (ultra_code_from_mask, + ultra_cmove_results_ready_p, ultra_fpmode_conflict_exists, + ultra_find_type, ultra_schedule_insn, ultra_flush_pipeline, + ultrasparc_sched_init, ultrasparc_variable_issue, + ultra_rescan_pipeline_state, ultrasparc_sched_reorder): New + functions to describe UltraSPARC pipeline exactly to Haifa. + (ultrasparc_adjust_cost): Indicate IMUL type insns have zero cost, + as there is nothing the scheduler can do about it. Indicate that + REG_DEP_OUTPUT's collide. Fixup formatting. + * config/sparc/sparc.h (RTX_COSTS): Fixup integer multiply and + divide costs on Ultra for DImode. + (MD_SCHED_INIT, MD_SCHED_REORDER, MD_SCHED_VARIABLE_ISSUE): + Define. + * config/sparc/sparc.md (ieu_unnamed function unit): Rename to + ieuN and add call_no_delay_slot to type list. + (cti function unit): New unit for branches on UltraSPARC. + (subx/addx insns): Set type to misc. + (sidi zero/sign extension insns on arch64): Set type to shift. + (sign_extendhidi2_insn): Set type to sload. + +Sun Aug 16 13:52:00 1998 David Edelsohn + + * rs6000.c (rs6000_stack_info): Use if == 0 for sizes. + (output_epilog): Use if != 0 for offset. + (rs6000_fatal_bad_address): Prepare for Intl. + * rs6000.h (rs6000_fatal_bad_address): Declare. + * rs6000.md (movsfcc, movdfcc): Use else if. + (elf_high): Use {liu|lis}. + (elf_low): Use {cal|la}. Remove %a template from old mnemonics. + (movsi): Use rs6000_fatal_bad_address. + +Sun Aug 16 01:53:21 1998 Richard Henderson + + * reload.c (find_equiv_reg): Reject equivalences separated + by a volatile instruction. + +Sun Aug 16 00:21:44 1998 Franz Sirl + + * rs6000/linux.h (CPP_OS_DEFAULT_SPEC): Define. + +Sat Aug 15 20:51:35 1998 Richard Henderson + + * alpha.md (movsicc): Fix mode mismatch. + +Sat Aug 15 20:22:33 1998 H.J. Lu (hjl@gnu.org) + + * config/alpha/alpha.h (ASM_OUTPUT_MI_THUNK): Handle aggregated + return type. + * config/alpha/win-nt.h (ASM_OUTPUT_MI_THUNK): Likewise. + +Sat Aug 15 08:39:49 1998 David S. Miller + + * config/sparc/sparc.md (movsi_lo_sum_pic_label_reg): Remove + write-only modifier from operand 1 constraint. + +Sat Aug 15 06:28:19 1998 David S. Miller + + * config/sparc/sparc.c (sparc_emit_set_const64_quick1): If + emitting a XOR of -1 at the end, emit a NOT instead for combine's + sake. + (sparc_emit_set_const64): Likewise, also when computing trailing + bits do not negate low_bits and make fast_int an int. + +Fri Aug 14 21:07:03 1998 Jeffrey A Law (law@cygnus.com) + + * loop.c (add_label_notes): Do not ignore references to labels + before dispatch tables. Mirrors Apr 8 change to mark_jump_label. + * gcse.c (add_label_notes): Similarly. + + * pa.h (ASM_OUTPUT_MI_THUNK): Strip name encoding. + + * m68k.md (adddi_dilshr32): One of the operands must be a register. + (adddi_dishl32): Similarly. + +Fri Aug 14 14:12:59 1998 Jason Merrill + + * i386.h (MODES_TIEABLE_P): Reorganize to shut up warnings. + * alias.c (memrefs_conflict_p): Add braces to shut up warnings. + * cse.c (cse_basic_block): Add parens to shut up warnings. + +Fri Aug 14 12:58:21 1998 David S. Miller + + * config/sparc/sparc.c (sparc_emit_set_const64_quick2, + sparc_emit_set_const64_longway, const64_is_2insns, + create_simple_focus_bits, sparc_emit_set_const64): Fix more bugs + in 64-bit constant formation. + * config/sparc/sparc.md (snesi_zero_extend split): Generate + rtl for addx not subx. + (define_insn movdi_const64_special): Make available even when + HOST_BITS_PER_WIDE_INT is not 64. + (movdi_lo_sum_sp64_cint, movdi_high_sp64_cint): Remove. + (losum_di_medlow, sethm, setlo): Make op2 symbolic_operand. + (cmp_siqi_trunc_set, cmp_diqi_trunc_set): Encapsulate both + instances of operand 1 inside a QI subreg. + (xordi3_sp64_dbl): Remove '%' constraint for op1. + (one_cmpldi2_sp64): Fix output string. + (one_cmplsi2_not_liveg0): Rewrite to remove unneeded extra + alternative case. + (unnamed arch64 ashift DI): Truncate shift count if greater than + 63, not 31. + +Fri Aug 14 21:52:53 1998 J"orn Rennecke + + * expr.c (store_expr): Don't optimize away load-store pair + when either source or destination have a side effect. + +Fri Aug 14 16:50:10 1998 John Carr + + * genrecog.c (add_to_sequence): Fatal error if the modes of the + operands of SET are incompatible. + + * alpha.md: Fix max and min patterns so modes of SET operands match. + +Fri Aug 14 12:22:55 1998 Ian Lance Taylor + + * configure.in: Avoid [[ by using test and changequote. + * configure: Rebuild. + +Fri Aug 14 01:22:31 1998 David S. Miller + + * rtl.def (CONSTANT_P_RTX): Fix typo in string name. + + * config/sparc/sparc.md (seqdi_special_trunc, snedi_special_trunc, + seqsi_special_extend, snesi_special_extend, snesi_zero_extend and + split, snedi_zero_trunc and split, seqsi_zero_extend and split, + seqdi_zero_trunc and split, pic_lo_sum_di, pic_sethi_di, + movdi_cc_sp64_trunc, movdi_cc_reg_sp64_trunc, addx_extend_sp32 and + split, addx_extend_sp64, subx_extend_sp64, subx_extend and split): + Fix mismatching modes in SET operands. + (conditional move patterns): Fix formatting. + (unnamed subx arch64 pattern): Remove duplicate insn. + +Fri Aug 14 00:34:34 1998 David S. Miller + + * config/sparc/sparc.c (const64_operand, const64_high_operand): + Get it right when HOST_BITS_PER_WIDE_INT is not 64. + (input_operand): Fixup test for what we accept for constant + integers. + (sparc_emit_set_const32, sparc_emit_set_symbolic_const64): Give + set VOIDmode. + (safe_constDI): Remove. + (sparc_emit_set_safe_HIGH64, gen_safe_SET64, gen_safe_OR64, + gen_safe_XOR64): New functions. + (sparc_emit_set_const64_quick1, sparc_emit_set_const64_quick2, + sparc_emit_set_const64_longway, sparc_emit_set_const64): Use + them. + * config/sparc/sparc.md (define_insn xordi3_sp64_dbl): Only make + available when HOST_BITS_PER_WIDE_INT is not 64. + (define_insn movdi_sp64_dbl, movdi_const64_special): Likewise and + move before movdi_insn_sp64 pattern. + (define_insn movdi_lo_sum_sp64_dbl, movdi_high_sp64_dbl): Remove. + (define_insn sethi_di_medlow, seth44, setm44, sethh): Use + symbolic_operand as predicate for second operand. + (DImode minus split on arch32, negsi2 expander, one_cmplsi2 + expander): Give set VOIDmode. + +Fri Aug 14 01:45:06 1998 Mumit Khan + + * i386/cygwin32 (DEFAULT_PCC_STRUCT_RETURN): Define. + +Fri Aug 14 01:40:21 1998 Geoffrey Keating + + * rs6000/linux.h (LINK_SPEC): Pass -G args to the linker. + +Fri Aug 14 01:23:23 1998 Richard Earnshaw (rearnsha@arm.com) + + * arm/netbsd.h (TARGET_DEFAULT): Default includes software floating + point. + (CPP_FLOAT_DEFAULT_SPEC): Re-define accordingly. + +Fri Aug 14 01:19:08 1998 Robert Lipe + + * install.texi: Various SCO OpenServer tweaks. + +Thu Aug 13 20:14:40 1998 Jim Wilson + + * reload1.c (eliminate_regs_in_insn): Handle another case when + eliminating the frame pointer to the hard frame pointer. Add + missing ep->to_rtx check to one existing case. + + * mips/mips.md (movhi_internal2+2): Fix typo mem:SI -> mem:HI. + +Thu Aug 13 17:08:11 1998 Jason Merrill + + * tree.h: De-conditionalize init_priority code. + + * mips.h (NM_FLAGS): Change from -Bp to -Bn. + * collect2.c (NM_FLAGS): Change from -p to -n. + + * configure.in: Turn on collect2 for mipstx39-elf. + Handle use_collect2=no properly. + + * c-common.c: De-conditionalize init_priority code. + * collect2.c (extract_init_priority, sort_ids): New fns. + (main): Call sort_ids. + Move sequence_number to file scope. + + * configure.in: Handle --enable-init-priority. + * c-common.c (attrs): Add A_INIT_PRIORITY. + (init_attributes, decl_attributes): Likewise. + * tree.h (DEFAULT_INIT_PRIORITY, MAX_INIT_PRIORITY): New macros. + * tree.c (get_file_function_name_long): Split out... + (get_file_function_name): ...from here. + +Thu Aug 13 16:09:53 1998 Martin von Loewis + + * expr.c (safe_from_p): Change code to ERROR_MARK only when not + accessing nodes. + +Thu Aug 13 15:24:48 1998 Jason Merrill + + * toplev.c (display_help): Add braces to shut up warnings. + * tree.c (simple_cst_equal): Likewise. + + * fold-const.c (non_lvalue): Don't deal with null pointer + constants here. + (fold, case COMPOUND_EXPR): Wrap a constant 0 in a NOP_EXPR. + + * c-typeck.c (initializer_constant_valid_p): Allow conversion of 0 + of any size to a pointer. + +Thu Aug 13 12:53:13 1998 Jim Wilson + + * i386/winnt.c (i386_pe_asm_file_end): Check TREE_SYMBOL_REFERENCED. + +Wed Aug 12 17:25:18 1998 Jeffrey A Law (law@cygnus.com) + + * mn10300.c (REG_SAVE_BYTES): Only reserve space for registers + which will be saved. + * mn10300.md (prologue insn): Only save registers which need saving. + (epilogue insn): Similarly. + + * mn10300.c, mn10300.h, mn10300.md: Remove "global zero register" + optimizations. + +Wed Aug 12 12:39:16 1998 Gavin Romig-Koch + + * mips/mips.h (ENCODE_SECTION_INFO): Set SYMBOL_REF_FLAG for + VAR_DECL's in gp addressable sections. + +Tue Aug 11 23:02:31 1998 John Carr + + * sparc.c: Change return to ; return; in functions + returning void. + * sparc.md: Add empty semicolon statement after final label in + move expanders. + +Tue Aug 11 22:42:01 1998 David S. Miller + + * config/sparc/sparc.md (define_insn addx_extend): Rename to + addx_extend_sp64, only allow when TARGET_ARCH64. + (define_insn addx_extend_sp32 and split): Version that works when + not TARGET_ARCH64. + (define_insn subx_extend): Likewise. + (define_split adddi3 and subdi3 with zero extension): Fixup and + correct bugs when not TARGET_ARCH64. + +Tue Aug 11 16:04:34 1998 John Carr + + * except.c (set_exception_lang_code, set_exception_version_code): + Use prototype-style definition if __STDC__, to match declaration + in except.h. + + * genemit.c: Change FAIL and DONE macros not to use loops. + +Tue Aug 11 12:27:03 1998 Jim Wilson + + * dwarf2out.c (ASM_OUTPUT_DWARF_ADDR_CONST): Use + ASM_OUTPUT_DWARF2_ADDR_CONST if defined. + + * mips/mips.md (reload_outsi): Use M16_REG_P when TARGET_MIPS16. + +Tue Aug 11 18:12:53 1998 Dave Love + + * README.g77: Update from Craig. + +Tue Aug 11 04:46:01 1998 David S. Miller + + * config/sparc/sparc.c (sparc_emit_set_const32): INTVAL is of + type HOST_WIDE_INT. + (safe_constDI sparc_emit_set_const64_quick1, + sparc_emit_set_const64_quick2, sparc_emit_set_const64_longway, + analyze_64bit_constant, const64_is_2insns, + create_simple_focus_bits): Fix some bugs when compiled on real + 64-bit hosts. + (function_arg_record_value_3, function_arg_record_value_2, + function_arg_record_value): Add fully prototyped forward decls. + * config/sparc/sparc.md (define_insn cmpsi_insn_sp32): Rename back + to cmpsi_insn and use on both 64 and 32 bit targets. + (define_insn cmpsi_insn_sp64): Remove. + (define_expand zero_extendsidi2): Allow for 32-bit target too. + (define_insn zero_extendsidi2_insn): Rename to + zero_extendsidi2_insn_sp64. + (define_insn zero_extendsidi2_insn_sp32): New pattern and + assosciated forced split for it. + + * config/sparc/sparc.c (const64_operand, const64_high_operand): + New predicates. + * config/sparc/sparc.h: Declare them. + (PREDICATE_CODES): Add them. + * config/sparc/sparc.md (movdi_lo_sum_sp64_dbl, + movdi_high_sp64_dbl, xordi3_sp64_dbl): Use them. + +Mon Aug 10 22:57:24 1998 John Carr + + * config/sparc/sparc.md (define_insn jump): Output ba,pt not b,pt + in v9 case as the latter makes the Solaris assembler crash. + +Mon Aug 10 22:39:09 1998 David S. Miller + + * config/sparc/sparc.c (input_operand): Do not accept a LO_SUM MEM + for TFmode when !v9. We require offsettable memory addresses. + * config/sparc/sparc.h (ALTER_HARD_SUBREG): Handle TFmode to + DFmode register number conversions. + * config/sparc/sparc.md (define_split DFmode moves): If register + is a SUBREG do alter_subreg on it before using. + (define_expand movtf): Fixup comment about alignment on v9. + (define_split TFmode moves): Don't use gen_{high,low}part, create + explicit SUBREGs instead. + +Mon Aug 10 19:02:55 1998 John Carr + + * Makefile.in (mbchar.o): Depend on mbchar.c. + +Mon Aug 10 04:28:13 1998 David S. Miller + Richard Henderson + + Rewrite Sparc backend for better code generation and + improved sparc64 support. + * config/sparc/sp64-elf.h: Set JUMP_TABLES_IN_TEXT_SECTION to + zero. + * config/sparc/sysv4.h: Likewise. + * config/sparc/sparc.c (v8plus_regcmp_p, sparc_operand, + move_operand, v8plus_regcmp_op, emit_move_sequence, + singlemove_string, doublemove_string, mem_aligned_8, + output_move_double, output_move_quad, output_fp_move_double, + move_quad_direction, output_fp_move_quad, output_scc_insn): + Remove. + (small_int_or_double): New predicate. + (gen_compare_reg): Remove TARGET_V8PLUS cmpdi_v8plus emission. + (legitimize_pic_address): Emit movsi_{high,lo_sum}_pic instead of + old pic_{sethi,lo_sum}_si patterns. + (mem_min_alignment): New generic function to replace + mem_aligned_8, which uses REGNO_POINTER_ALIGN information when + available and can test for arbitrary alignments. All callers + changed. + (save_regs, restore_regs, build_big_number, + output_function_prologue, output_cbranch, output_return, + sparc_flat_save_restore, sparc_flat_output_function_prologue, + sparc_flat_output_function_epilogue): Prettify + insn output. + (output_function_epilogue): Likewise and add code to output + deferred case vectors. + (output_v9branch): Likewise, add new arg INSN and use it to tack + on branch prediction settings. All callers changed. + (print_operand): Likewise and output %l44 for LO_SUMs when + TARGET_CM_MEDMID. + (sparc_splitdi_legitimate): New function to make sure DImode + splits can be run properly when !arch64. + (sparc_initialize_trampoline, sparc64_initialize_trampoline): + Reformat example code in comments. + (set_extends): Remove UNSPEC/v8plus_clear_high case. + (sparc_addr_diff_list, sparc_addr_list): New statics to keep track + of deferred case vectors we need to output. + (sparc_defer_case_vector): Record a case vector. + (sparc_output_addr_vec, sparc_output_addr_diff_vec, + sparc_output_deferred_case_vectors): New functions to output them. + (sparc_emit_set_const32): New function to form 32-bit constants in + registers when that requires more than one instruction. + (safe_constDI, sparc_emit_set_const64_quick1, + sparc_emit_set_const64_quick2, sparc_emit_set_const64_longway, + analyze_64bit_constant, const64_is_2insns, + create_simple_focus_bits, sparc_emit_set_const64): New functions + which do the same for 64-bit constants when arch64. + (sparc_emit_set_symbolic_const64): New function to emit address + loading for all code models on v9. + * config/sparc/sparc.h (CONDITIONAL_REGISTER_USAGE): Do not make + %g1 fixed when arch64, unfix %g0 when TARGET_LIVE_G0. + (ALTER_HARD_SUBREG): Fix thinko, return REGNO + 1 not 1. + (SECONDARY_INPUT_RELOAD_CLASS, SECONDARY_OUTPUT_RELOAD_CLASS): Fix + inaccuracies in comments, add symbolic and text_segment operands + when TARGET_CM_MEDANY and TARGET_CM_EMBMEDANY respectively. Use + GENERAL_REGS in these cases as a temp REG is needed to load these + addresses into a register properly. + (EXTRA_CONSTRAINT): Document more accurately, remove Q case as it + is no longer used. + (GO_IF_LEGITIMATE_ADDRESS): Allow TFmode for LO_SUM on v9 since fp + quads are guarenteed to have 16-byte alignment. + (LEGITIMIZE_ADDRESS): For SYMBOL_REF, CONST, and LABEL_REF use + copy_to_suggested_reg instead of explicit LO_SUM and HIGH. + (ASM_OUTPUT_ADDR_VEC, ASM_OUTPUT_ADDR_DIFF_VEC): New macros for + deferred case vector implementation. + (ASM_OUTPUT_ADDR_VEC_ELT): Use fputc to output newline. + (ASM_OUTPUT_ADDR_DIFF_ELT): Parenthesize LABEL in macro calls. + Generate "internal label - label" instead of "label - 1b". + (PRINT_OPERAND_ADDRESS): For LO_SUM use %l44 on TARGET_CM_MEDMID. + (PREDICATE_CODES): Remove sparc_operand, move_operand, + v8plus_regcmp_op. Add small_int_or_double, input_operand, and + zero_operand. + (doublemove_string, output_block_move, output_fp_move_double, + output_fp_move_quad, output_move_double, output_move_quad, + output_scc_insn, singlemove_string, mem_aligned_8, move_operand, + sparc_operand, v8plus_regcmp_op, v8plus_regcmp_p): Remove externs. + (sparc_emit_set_const32, sparc_emit_set_const64, + sparc_emit_set_symbolic_const64, input_operand, zero_operand, + mem_min_alignment, small_int_or_double): Add externs. + * config/sparc/sparc.md: Document the many uses of UNSPEC and + UNSPEC_VOLATILE in this backend. + (define_function_unit ieu): Rename to ieu_unnamed. Add move and + unary to types which execute in it. + (define_function_unit ieu_shift): Rename to ieu0. + (define_function_unit ieu1): New, executes compare, call, and + uncond_branch type insns. + (define_function_units for type fdivs, fdivd, fsqrt): These + execute in the fpu multiply unit not the adder on UltraSparc. + (define_expand cmpdi): Disallow TARGET_V8PLUS. + (define_insn cmpsi_insn): Rename to cmpsi_insn_sp32. + (define_insn cmpsi_insn_sp64): New, same as sp32 variant except it + allows the arith_double_operand predicate and rHI constraint when + TARGET_ARCH64. + (define_insn cmpdi_sp64, cmpsf_fpe, cmpdf_fpe, cmptf_fpe, + cmpsf_fp, cmpdf_fp, cmptf_fp, sltu_insn, neg_sltu_insn, + neg_sltu_minux_x, neg_sltu_plus_x, sgeu_insn, neg_sgeu_insn, + sltu_plus_x, sltu_plus_x, sltu_plus_x_plus_y, x_minus_sltu, + sgeu_plus_x, x_minus_sgeu, movqi_cc_sp64, movhi_cc_sp64, + movsi_cc_sp64, movdi_cc_sp64, movsf_cc_sp64, movdf_cc_sp64, + movtf_cc_sp64, movqi_cc_reg_sp64, movhi_cc_reg_sp64, + movsi_cc_reg_sp64, movdi_cc_reg_sp64, movsf_cc_reg_sp64, + movdf_cc_reg_sp64, movtf_cc_reg_sp64, zero_extendhisi2_insn, + cmp_siqi_trunc, cmp_siqi_trunc_set, sign_extendhisi2_insn, + sign_extendqihi2_insn, sign_extendqisi2_insn, + sign_extendqidi2_insn, sign_extendhidi2_insn, + extendsfdf2, extendsftf2, extenddftf2, truncdfsf2, trunctfsf2, + trunctfdf2, floatsisf2, floatsidf2, floatsitf2, floatdisf2, + floatdidf2, floatditf2, fix_truncsfsi2, fix_truncdfsi2, + fix_trunctfsi2, fix_truncsfdi2, fix_truncdfdi2, fix_trunctfdi2, + adddi3_sp64, addsi3, cmp_ccx_plus, cmp_cc_plus_set, subdi_sp64, + subsi3, cmp_minus_ccx, cmp_minus_ccx_set, mulsi3, muldi3, + muldi3_v8plus, cmp_mul_set, mulsidi3, mulsidi3_v8plus, + const_mulsidi3_v8plus, mulsidi3_sp32, const_mulsidi3, + smulsi3_highpart_v8plus, unnamed subreg mult, + const_smulsi3_highpart_v8plus, smulsi3_highpart_sp32, + const_smulsi3_highpart, umulsidi3_v8plus, umulsidi3_sp32, + const_umulsidi3, const_umulsidi3_v8plus, umulsi3_highpart_v8plus, + const_umulsi3_highpart_v8plus, umulsi3_highpart_sp32, + const_umulsi3_highpart, divsi3, divdi3, cmp_sdiv_cc_set, udivsi3, + udivdi3, cmp_udiv_cc_set, smacsi, smacdi, umacdi, anddi3_sp64, + andsi3, and_not_di_sp64, and_not_si, iordi3_sp64, iorsi3, + or_not_di_sp64, or_not_si, xordi3_sp64, xorsi3, xor_not_di_sp64, + xor_not_si, cmp_cc_arith_op, cmp_ccx_arith_op, + cmp_cc_arith_op_set, cmp_ccx_arith_op_set, cmp_ccx_xor_not, + cmp_cc_xor_not_set, cmp_ccx_xor_not_set, cmp_cc_arith_op_not, + cmp_ccx_arith_op_not, cmp_cc_arith_op_not_set, + cmp_ccx_arith_op_not_set, negdi2_sp64, cmp_cc_neg, cmp_ccx_neg, + cmp_cc_set_neg, cmp_ccx_set_neg, one_cmpldi2_sp64, cmp_cc_not, + cmp_ccx_not, cmp_cc_set_not, cmp_ccx_set_not, addtf3, adddf3, + addsf3, subtf3, subdf3, subsf3, multf3, muldf3, mulsf3, + muldf3_extend, multf3_extend, divtf3, divdf3, divsf3, negtf2, + negdf2, negsf2, abstf2, absdf2, abssf2, sqrttf2, sqrtdf2, sqrtsf2, + ashlsi3, ashldi3, unnamed DI ashift, cmp_cc_ashift_1, + cmp_cc_set_ashift_1, ashrsi3, ashrdi3, unnamed DI ashiftrt, + ashrdi3_v8plus, lshrsi3, lshrdi3, unnamed DI lshiftrt, + lshrdi3_v8plus, tablejump_sp32, tablejump_sp64, call_address_sp32, + call_symbolic_sp32, call_address_sp64, call_symbolic_sp64, + call_address_struct_value_sp32, call_symbolic_struct_value_sp32, + call_address_untyped_struct_value_sp32, + call_symbolic_untyped_struct_value_sp32, call_value_address_sp32, + call_value_symbolic_sp32, call_value_address_sp64, + call_value_symbolic_sp64, branch_sp32, branch_sp64, + flush_register_windows, goto_handler_and_restore, + goto_handler_and_restore_v9, goto_handler_and_restore_v9_sp64, + flush, all ldd/std peepholes, return_qi, return_hi, return_si, + return_addsi, return_di, return_adddi, return_sf, all call+jump + peepholes, trap, unnamed trap insns): Prettify output strings. + (define_insn anddi3_sp32, and_not_di_sp32, iordi3_sp32, + or_not_di_sp32, xordi3_sp32, xor_not_di_sp32, one_cmpldi2): + Likewise and force + implement splits for integer cases. + (define_insn return_sf_no_fpu): Likewise and allow to match when + no-fpu because of our subreg SFmode splits. + (define_insn zero_extendqihi2, zero_extendqisi2_insn, + zero_extendqidi2_insn, zero_extendhidi2_insn, + zero_extendsidi2_insn, sign_extendsidi2_insn): Likewise and use + input_operand for second operand. + (cmp_minus_cc, cmp_minus_cc_set): Likewise and use + reg_or_0_operand for operand 2 so new splits can use it. + (cmp_zero_extendqisi2, cmp_zero_extendqisi2_set, cmp_cc_plus, + cmp_cc_xor_not): Likewise and don't forget to check TARGET_LIVE_G0 + too. + (cmp_zero_extract, cmp_zero_extract_sp64): Likewise and allow + CONST_DOUBLEs for operand 2. + (define_insn move_label_di): Likewise and label distance + optimization because it no longer works with new deferred case + vector scheme. To be revisited. + (define_insn x_minus_y_minus_sltu, x_minus_sltu_plus_y): Likewise + and allow reg_or_0_operand and J constraint for second operand. + (define_insn jump): Set branch predict taken on V9. + (define_insn tablejump): Emit LABEL_REF + PLUS memory address for + new deferred case vector scheme. + (define_insn pic_tablejump_32, pic_tablejump_64): Remove. + (define_insn negdi2_sp32): Force + implement splits. + (define_insn negsi2, one_cmplsi2): Rename to negsi2_not_liveg0 and + one_cmplsi2_not_liveg0 respectively, and create expander of original + names which emit special rtl for TARGET_LIVE_G0. + (define_insn cmpdi_v8plus, scc_si, scc_di): Remove. + (define_insn seq, sne, slt, sge, sle, sltu, sgeu): Don't do + gen_compare_reg, FAIL instead. + (define_insn sgtu, sleu): Likewise and check gen_s*() return + values when trying to reverse condition codes, if they FAIL then + do likewise. + (define_insn snesi_zero, neg_snesi_zero, snesi_zero_extend, + snedi_zero, neg_snedi_zero, snedi_zero_trunc, seqsi_zero, + neg_seqsi_zero, seqsi_zero_extend, seqdi_zero, neg_seqdi_zero, + seqdi_zero_trunc, x_plus_i_ne_0, x_minus_i_ne_0, x_plus_i_eq_0, + x_minus_i_eq_0): Add new splits to perform these multi-insn cases, + set output string to # to indicate they are mandatory splits. + (define_insn pic_lo_sum_si, pic_sethi_si, pic_lo_sum_di, + pic_sethi_di, move_pic_label_si): Remove. + (define_insn movsi_low_sum, movsi_high, movsi_lo_sum_pic, + movsi_high_pic, movsi_pic_label_reg): New patterns to take their + place. + (define_expand movsi_pic_label_ref, define_insn + movsi_high_pic_label_ref, movsi_lo_sum_pic_label_ref): New + expander and insns to handle PIC label references and deferred + case vectors. + (define_insn get_pc_via_rdpc): Comment out as it is no longer + used. + (define_expand movqi, movhi, movsi, movdi, movsf, movdf, movtf): + Rewrite to not use emit_move_sequence, make use of new constant + formation code, and new splits for all multi-insn cases. + (define_insn movqi_insn): Remove sethi case, it can never happen. + Use reg_or_zero_operand instead of const0_rtx explicit test, + use input_operand instead of move_operand for source, and use + general_operand now for dest. + (define_insn movhi_insn): Similar but leave sethi case. + (define_insn lo_sum_qi, store_qi, store_hi): Remove. + (define_insn sethi_hi lo_sum_hi): Rename to movhi_high and + movhi_lo_sum respectively, prettify output string. + (define_insn movsi_zero_liveg0): New pattern to put zero into a + register when needed on TARGET_LIVE_G0. + (define_insn movsi_insn): Use general_operand and input_operand + for dest and src respectively. Simplify applicability test. + Prettify output strings, and add clr alternative for J + constraint. + (define_insn movdi_sp32_v9, movdi_sp32, define_splits for + deprecated std and reg-reg DI moves): Remove and... + (define_insn movdi_insn_sp32, movdi_insn_sp64): Replace with new + implementation which uses forced splits for all non-single insn + cases. + (define_split DI move cases on !arch64): New splits to handle all + situations of 64-bit double register DImode on 32bit, and + unaligned registers and memory addresses for all subtargets. + (define_insn movsf_const_insn, movdf_const_insn, store_sf): + Remove. + (define_insn movsf_insn, movsf_no_f_insn): Use general_operand and + input_operand for dest and src respectively, prettify output + strings. + (define_insn movdf_insn, movdf_no_e_insn, store_df, + movtf_const_insn, movtf_insn, movtf_no_e_insn, store_tf): Remove + and... + (define_insn movdf_insn_sp32, movdf_no_e_insn_sp32, + movdf_insn_sp64, movdf_no_e_insn_sp64, movtf_insn, + movtf_no_e_insn_sp32, movtf_insn_hq_sp64, movtf_insn_sp64, + movtf_no_e_insn_sp64) Replace with new + implementation which uses forced splits for all non-single insn + cases. + (define_split DF move cases): New splits in similar vein to DI + move counterparts. + (define_insn sethi_di_medlow, sethi_di_medium_pic, + sethi_di_embmedany_data, sethi_di_embmedany_text, sethi_di_sp64, + movdi_sp64_insn): Remove old v9 code model and constant loading + support insns and.. + (define_insn pic_lo_sum_di, pic_sethi_di, + sethi_di_medlow_embmedany_pic, sethi_di_medlow, losum_di_medlow, + seth44, setm44, setl44, sethh, setlm, sethm, setlo, + embmedany_sethi, embmedany_losum, embmedany_brsum, + embmedany_textuhi, embmedany_texthi, embmedany_textulo, + embmedany_textlo, movdi_lo_sum_sp64_cint, movdi_lo_sum_sp64_dbl, + movdi_high_sp64_cint, movdi_high_sp64_dbl): Replace with new + scheme, using unspecs, secondary reloads, and one to one sparc + insn to rtl insn mapping for better scheduling and code gen. + (define_expand reload_indi, reload_outdi): Reload helpers for + MEDANY and EMBMEDANY symbol address loading cases which require a + temporary register. + (define_expand movsicc): Remove v8plus_regcmp cases. + (define_insn movdi_cc_sp64_trunc, movdi_cc_reg_sp64_trunc, + cmp_zero_extendqidi2, cmp_zero_extendqidi2_set, cmp_qidi_trunc, + cmp_diqi_trunc_set): New patterns used by some of the new scc + splits on arch64. + (define_insn xordi3_sp64_dbl): New pattern used for constant + formation when crossing from 32-bit targets. + (define_insn movsi_cc_reg_v8plus, v8plus_clear_high, and helper + split): Remove. + (define_insn addx, subx): Make visible and prettify. + (define_insn adddi3_insn_sp32): Likewise and force split. + (define_insn addx_extend, subx_extend, unnamed): New patterns for + 64bit scc split usage. + (define_insn unnamed plusDI zero_extend, unnamed minusDI + zero_extend, subdi3): Force and implement splits. + + * final.c (final_scan_insn): Don't output labels if target + specifies ASM_OUTPUT_ADDR_{DIFF}_VEC. Do these macro operations + instead. + + * reorg.c (dbr_schedule): When taking on BR_PRED notes at the end, + don't forget to walk inside SEQUENCESs too as these are what the + delay slot scheduler will create. + +Mon Aug 10 01:21:01 1998 Richard Henderson + + * alpha.md (extxl+1,+2): New patterns to work around + combine lossage. + +Sat Aug 8 19:20:22 1998 Gary Thomas (gdt@linuxppc.org) + + * rs6000.c (rs6000_allocate_stack_space) Fix typo which + caused bad assembly code to be generated. + +Sat Aug 8 18:53:28 1998 Jeffrey A Law (law@cygnus.com) + + * netbsd.h: Fix typo. + +Mon Aug 3 00:06:42 1998 Robert Lipe + + * config.sub: Fix typo. + +Sun Aug 2 22:39:08 1998 Hans-Peter Nilsson + + * invoke.texi (Environment Variables): Typo: Change "ascpects" + into "aspects". + (Running Protoize): Typo: Change "ther" into "other". + +Sun Aug 2 00:42:50 1998 Jeffrey A Law (law@cygnus.com) + + * i386/netbsd.h: Undo previous change to DWARF2_UNWIND_INFO. + * m68k/netbsd.h: Likewise. + * ns32k/netbsd.h: Likewise. + * sparc/netbsd.h: Likewise. + +Sat Aug 1 17:59:30 1998 Richard Henderson + + * ginclude/va-alpha.h (va_list): Use a typedef, not a define. + * ginclude/va-clipper.h (va_list): Likewise. + +Fri Jul 31 20:22:02 1998 Michael Meissner + + * rs6000.c (rs6000_override_options): If big endian and -Os, use + load/store multiple instructions unless user overrides. + +Fri Jul 31 17:08:59 1998 Jeffrey A Law (law@cygnus.com) + + * ns32k/netbsd.h: Fix typo. + +Fri Jul 31 10:23:55 1998 Doug Evans + + * m32r/m32r.h (ASM_OUTPUT_SOURCE_LINE): Always output line number + labels with .debugsym if no parallel insns. + +Thu Jul 30 19:15:53 1998 Richard Henderson + + * alpha.md (fp cmp): Replicate patterns for ALPHA_TP_INSN. + (fcmov): Remove ALPHA_TP_INSN patterns -- fcmov doesn't trap. + +Thu Jul 30 19:50:15 1998 David Edelsohn + + * rs6000/x-aix43 (AR_FOR_TARGET_FLAGS): Delete. + (AR_FOR_TARGET): Define. + +Thu Jul 30 12:29:12 1998 Mark Mitchell + + * dyn-string.h: New file. + * dyn-string.c: Likewise. + * Makefile.in (OBJS): Add dyn-string.o. + (dwarf2out.o): Add dyn-string.h dependency. + (dyn-string.o): List dependencies. + * dwarf2out.c: Include dyn-string.h. + (ASM_NAME_TO_STRING): Use dyn_string_append, rather than strcpy. + (addr_const_to_string): Take a dyn_string_t, not a char* as a + prototype. Use dyn_string_append rather than strcat, throughout. + (addr_to_string): Use dyn_string_t. + +Thu Jul 30 13:08:07 1998 Ken Raeburn + + Function entry/exit profiling instrumentation: + * expr.h (profile_function_entry_libfunc, + profile_function_exit_libfunc): Declare new variables. + * optabs.c: Define them here. + (init_optabs): Initialize them. + * tree.h (struct tree_decl): New flag + no_instrument_function_entry_exit. + (DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT): New accessor macro. + * c-decl.c (duplicate_decls): Merge it. + * c-common.c (enum attrs): New value A_NO_INSTRUMENT_FUNCTION. + (init_attributes): Use it for "no_instrument_function". + (decl_attributes): Handle it, for functions that have not yet been + compiled. Set decl flag. + * flags.h (flag_instrument_function_entry_exit): Declare new + variable. + * toplev.c (flag_instrument_function_entry_exit): Define it here. + (f_options): New option "instrument-functions". + * function.h (struct function): New field instrument_entry_exit. + * function.c (current_function_instrument_entry_exit): New + variable. + (push_function_context_to, pop_function_context_from): Save and + restore. + (expand_function_start): Set current_ variable, maybe emit return + label and entry profile call. + (expand_function_end): Maybe emit exit profile call. + +Thu Jul 30 00:58:34 1998 Jeffrey A Law (law@cygnus.com) + + * i386.md (movqi): When optimizing a load of (const_int 1) into a + NON_QI_REG_P, pretend the register is SImode. + +Wed Jul 29 23:49:23 1998 Todd Vierling + + * configure.in: Use xm-netbsd.h as the NetBSD xm file (not xm-siglist). + Accept arm32 as arm, m68k4k as m68k, mipsle as mips-dec, and any + manufacturer id for ns32k. + * configure: Regenerated. + * config/netbsd.h: When using ASM_WEAKEN_LABEL, make it global too. + * config/t-netbsd: Don't compile libgcc1-test as the fns are in libc. + * config/i386/netbsd.h: Undefine DWARF2_UNWIND_INFO, not define as 0. + * config/m68k/netbsd.h: Same. + * config/ns32k/netbsd.h: Same. + * config/sparc/netbsd.h: Same. + +Wed Jul 29 22:39:21 1998 Jeffrey A Law (law@cygnus.com) + + * unroll.c (unroll_loop): Do not abort for an UNROLL_MODULO + or UNROLL_COMPLETELY loop that starts with a jump to its + exit code. + +Wed Jul 29 22:18:14 1998 David Edelsohn + + * rs6000/rs6000.md (absdi2 define_split): Swap operands of MINUS. + * rs6000/rs6000.c (mask64_operand): Use HOST_BITS_PER_WIDE_INT. + (print_operand, case 'B'): Don't fall through. + (print_operand, case 'S'): Correct mask begin/end computation. + Use HOST_BITS_PER_WIDE_INT. + * rs6000/rs6000.h (CPP_PREDEFINES): Define _LONG_LONG. + (CONDITIONAL_REGISTER_USAGE): GPR13 fixed if TARGET_64BIT. + * rs6000/aix41.h (CPP_PREDEFINES): Same. + * rs6000/aix43.h (CPP_PREDEFINES): Same. + +Wed Jul 29 11:47:10 1998 Nick Clifton + + * config/arm/thumb.md (extendqisi2_insn): Remove earlyclobber + constraint from second alternative. + +Tue Jul 28 23:29:04 1998 Jason Merrill + + * configure.in: Fix --without/--disable cases for local-prefix, + gxx-include-dir and checking. + +Tue Jul 28 22:01:23 1998 David S. Miller + + * configure.in (enable_haifa): Set by default for sparc64 too. + configure: Rebuilt. + +Tue Jul 28 23:29:04 1998 Jason Merrill + + * i386/cygwin32.h (VALID_MACHINE_TYPE_ATTRIBUTE): New macro. + * i386/winnt.c (associated_type): New fn. + (i386_pe_valid_type_attribute_p): New fn. + (i386_pe_check_vtable_importexport): Remove. + (i386_pe_dllexport_p): Use associated_type. + (i386_pe_dllimport_p): Likewise. + + From Antonio M. O. Neto : + * i386.c (i386_valid_type_attribute_p): Also accept + attributes for METHOD_TYPEs. + +Tue Jul 28 23:17:39 1998 Peter Gerwinski + + * tree.c (build_range_type): Copy TYPE_SIZE_UNIT. + +Tue Jul 28 22:31:12 1998 Craig Burley + + * gcc.c: Fix commentary describing %g, %u, %U, and %O. + + * gcc.c (do_spec_1): Fix handling of %g%O and %U%O to prevent + them from generating a new base name for each occurence of + a specific suffix. + +1998-07-28 Vladimir N. Makarov + + * cse.c (cse_insn): Enable subsitution inside libcall only for REG, + SUBREG, MEM. + * rtlanal.c (replace_rtx): Prohibit replaces in CONST_DOUBLE. + + + + * cplus-dem.c (type_kind_t): New type. + (demangle_template_value_parm): Add type_kind_t parameter. Rely + on this paramter, rather than demangling the type again. + (demangle_integral_value): Pass tk_integral. + (demangle_template_: Pass the value returned from do_type. + (do_type): Return a type_kind_t. Pass tk_integral to + demangle_template_value_parm for array bounds. + (demangle_fund_type): Likewise. + +Mon Jul 27 00:54:41 1998 Jason Merrill + + * tree.c (simple_cst_equal, case CONSTRUCTOR): OK if the elts are + identical. + +Mon Jul 27 22:18:36 1998 Jeffrey A Law (law@cygnus.com) + + * pa.c (move_operand): Accept CONSTANT_P_RTX. + +Mon Jul 27 17:18:52 1998 Dave Brolley + + * stor-layout.c (layout_type): Handle arrays of bits, for Chill. + + * expr.c (get_inner_reference): Handle zero-based, unsigned, array + index conversion. + +Mon Jul 27 14:51:33 1998 Jeffrey A Law (law@cygnus.com) + + * mn10300.h (DEBUGGER_AUTO_OFFSET): Define. + (DEBUGGER_ARG_OFFSET): Likewise. + + * mn10300.md (movsf): Remove last change. Not needed. + +Mon Jul 27 14:22:36 1998 Dave Brolley + + * c-lex.c (yylex): Fix boundary conditions in character literal and + string literal loops. + +Mon Jul 27 11:43:54 1998 Stan Cox + + * longlong.h (count_leading_zeros): Sparclite scan instruction was + being invoked incorrectly. + + * i386.c (ix86_prologue): Added SUBTARGET_PROLOGUE invocation. + * i386/cygwin32.h (STARTFILE_SPEC, LIB_SPEC, SUBTARGET_PROLOGUE): + Add -pg support. + * i386/win32.h: New file. Hybrid mingw32.h/cygwin32.h configuration. + * configure.in: Added i[34567]86-*-win32 + * config.sub: Ditto. + * configure: Rebuilt. + +Sun Jul 26 01:11:12 1998 H.J. Lu (hjl@gnu.org) + + * i386.h (CONST_DOUBLE_OK_FOR_LETTER_P): Return 0 when eliminating + the frame pointer and compiling PIC code and reload has not completed. + + * i386.c (output_to_reg): Add code to emulate non-popping DImode + case. + +Sun Jul 26 01:01:32 1998 Jeffrey A Law (law@cygnus.com) + + * regmove.c (regmove_optimize): Fix typo initializing regmove_bb_head. + +Sat Jul 25 23:29:23 1998 Gerald Pfeifer + + * Makefile.in (install-info): Only try to update the info + directory file if it exists in the first place. + +Fri Jul 24 18:58:37 1998 Klaus Espenlaub + + * rs6000.h (ASM_OUTPUT_CONSTRUCTOR, ASM_OUTPUT_DESTRUCTOR): Delete. + +Fri Jul 24 14:20:26 1998 Jeffrey A Law (law@cygnus.com) + + * mn10300.md (movqi, movhi, movsi, movsf): Correctly handle + CONST_DOUBLE source. + +Fri Jul 24 11:17:04 1998 Nick Clifton + + * config/arm/thumb.c (thumb_print_operand): Decode %_ in asm + strings as the insertion of USER_LABEL_PREFIX. + * config/arm/thumb.h (PRINT_OPERAND_PUNCT_VALID_P): Accept _ as a + valid code. + * config/arm/thumb.md: Use %_ as a prefix to gcc library function + calls. + +Thu Jul 23 18:53:20 1998 Jim Wilson + + * dbxout.c (dbxout_range_type): Only call dbxout_type_index for + already defined type. + +Thu Jul 23 13:49:41 1998 Jeffrey A Law (law@cygnus.com) + + * expr.c (check_max_integer_computation_mode): Allow conversions + of constant integers to MAX_INTEGER_COMPUTATION_MODE. + (expand_expr): Likewise. + +Thu Jul 23 11:12:06 1998 Alexandre Petit-Bianco + + * expr.c (expand_expr): Expand RETURN_EXPR. + +Thu Jul 23 11:00:29 1998 Jim Wilson + + * dwarf2out.c (dwarf2out_finish): Call stripattributes on TEXT_SECTION. + +Wed Jul 22 19:10:00 1998 Catherine Moore + + * dwarf2out.c (output_aranges): Call stripattributes + for TEXT_SECTION references. + (output_line_info): Likewise. + +Wed Jul 22 14:08:54 1998 David S. Miller + + * profile.c (branch_prob): Call allocate_reg_info after outputting + profile rtl in instrument_arcs. + +Wed Jul 22 12:47:49 1998 Jim Wilson + + * fixinc.irix (math.h): Install wrapper instead of copying. + +Wed Jul 22 12:37:14 1998 Alexandre Petit-Bianco + + * tree.def (EXPR_WITH_FILE_LOCATION): Defined as an 'e' expression + so WFL are expanded correctly when contained in a COMPOUND_EXPR. + * tree.h (EXPR_WFL_EMIT_LINE_NOTE): Change macro not to use + lang_flag_0. Added documentation in the flag table. + +Tue Jul 21 23:28:35 1998 Klaus Kaempf + + * cccp.c (do_include): Fix vax c style include handling. + +Tue Jul 21 13:28:19 1998 Jason Merrill + + * cplus-dem.c (do_type): Use demangle_template_value_parm for arrays. + +Sun Jul 12 01:27:05 1998 Jason Merrill + + * fold-const.c (non_lvalue): Don't deal with null pointer + constants here. + (fold, case COMPOUND_EXPR): Wrap a constant 0 in a NOP_EXPR. + +Tue Jul 21 15:49:31 1998 David Edelsohn + + * rs6000.h (PREDICATE_CODES): Add CONSTANT_P_RTX. + * rs6000.md (movsi, movdi): Add CONSTANT_P_RTX. + * rs6000.c (short_cint_operand): Add CONSTANT_P_RTX. + (u_short_cint_operand): Same. + (reg_or_cint_operand): Same. + (logical_operand): Same. + (input_operand): Same. + (reg_or_short_operand): Use u_short_cint_operand. + +Tue Jul 21 08:56:42 1998 Richard Henderson + + * alpha.md (fix_truncdfsi2, fix_truncsfsi2): Remove the define_expands, + but keep the insns and splits. Adjust so when the ultimate destination + is memory, use cvtql. + +Tue Jul 21 08:55:09 1998 Richard Henderson + + * flow.c (regno_uninitialized): Fixed regs are never uninitialized. + +Tue Jul 21 00:31:01 1998 Jeffrey A Law (law@cygnus.com) + + * gcc.c (do_spec): Call "error" not "warning". + + * configure.in: Fix minor problems with gas feature detection code. + * configure: Rebuilt. + + * gcc.c (do_spec): Issue a warning for '%[]' usage. + + * Undo this change. + * gcc.c: Delete %[spec] support. + (do_spec_1, case '('): Likewise. + (do_spec_1, case '['): Call error. + +Mon Jul 20 22:34:17 1998 Richard Henderson + + * alpha.h (CPP_SPEC): Tidy. Hook to cpp_cpu and cpp_subtarget. + (CPP_SUBTARGET_SPEC): Default to empty string. + (CPP_AM_*, CPP_IM_*, CPP_CPU_*, CPP_CPU_SPEC): New. + (EXTRA_SPECS, SUBTARGET_EXTRA_SPECS): New. + * alpha/elf.h (LD_SPEC): Use %(elf_dynamic_linker). + * alpha/linux-elf.h (SUBTARGET_EXTRA_SPECS): New. + (LIB_SPEC): Tidy. + * alpha/linux.h (CPP_PREDEFINES): Tidy. + * alpha/netbsd-elf.h (SUBTARGET_EXTRA_SPECS): New. + * alpha/netbsd.h (CPP_PREDEFINES): Tidy. + * alpha/osf.h (CPP_PREDEFINES): Remove bits subsumed by CPP_CPU_SPEC. + * alpha/win-nt.h (CPP_PREDEFINES): Likewise. + * alpha/vsf.h (CPP_PREDEFINES): Likewise. + (CPP_SUBTARGET_SPEC): New. Do this instead of overriding CPP_SPEC. + * alpha/vxworks.h: Likewise. + +Mon Jul 20 22:51:57 1998 Ken Raeburn + + * mips.md (reload_outsi): Added missing REGNO call. + (smulsi3_highpart, umulsi3_highpart): Provide prototype for + function pointer. + (mul_acc_di, mul_acc_64bit_di): Don't use match_op_dup, use + another match_operator and compare the codes. + + * mips.h (MASK_DEBUG_E, MASK_DEBUG_I): Set to zero. + + * MIPS multiply pattern fixes: + * mips.h (enum reg_class, REG_CLASS_NAMES, REG_CLASS_CONTENTS): + Add union classes for HI, LO, or HILO plus general registers. + (GENERATE_MADD): Deleted. + * mips.md (mulsi3_mult3): Don't disparage output-LO alternative. + Add TARGET_MAD to condition. + (mulsi3): Test HAVE_mulsi3_mult3, not specific flags. + (mul_acc_si): Expand GENERATE_MADD here; it's the only use. Use + "*d" for accumulator, to give preference to LO initially but not + during reload. + +Mon Jul 20 16:16:38 1998 Dave Brolley + + * configure.in (enable_c_mbchar): New configure option. + (extra_cpp_objs): Always available now. + + * cexp.y (mbchar.h): #include it. + (yylex): Handle Multibyte characters in character literals. + + * cccp.c (mbchar.h): #include it. + (main): Set character set based on LANG environment variable. + (rescan): Handle multibyte characters in comments. + (skip_if_group): See above. + (validate_else): See above. + (skip_to_end_of_comment): See above. + (macarg1): See above. + (discard_comments): See above. + (rescan): Handle multibyte characters in string and character literals. + (collect_expansion): See above. + (skip_quoted_string): See above. + (macroexpand): See above. + (macarg1): See above. + (discard_comments): See above. + (change_newlines): See above. + + * c-lex.c (mbchar.h): #include it. + (GET_ENVIRONMENT): New macro. + (init_lex): Set character set based on LANG environment variable. + (yylex): Handle multibyte characters in character literals. + (yylex): Handle multibyte characters in string literals. + + * Makefile.in (mbchar.o): New target. + (cccp$(exeext)): @extra_cpp_objs@ is always available. + (cppmain$(exeext)): @extra_cpp_objs@ is always available. + + * mbchar.[ch]: New files for multibyte character handling. + +Mon Jul 20 01:11:11 1998 David S. Miller + + * jump.c (jump_optimize): When simplifying noop moves and + PUSH_ROUNDING, fix thinko so we use same criterion for identifying + the PUSHes to rewrite in second loop as we did in the first. + +Sun Jul 19 08:23:53 1998 Kaveh R. Ghazi + + * cplus-dem.c (demangle_nested_args): Make function definition + static to match the prototype. + +Fri Jul 17 14:58:44 1998 Richard Henderson + + * alloca.c: Respect USE_C_ALLOCA. + * gencheck.c (xmalloc): Ignore __GNUC__ for definition. + * gengenrtl.c (xmalloc): Likewise. + +Fri Jul 17 14:18:14 1998 Richard Henderson + + * loop.h (struct induction): Add no_const_addval. + * loop.c (the_movables, reg_address_cost): New variables. + (init_loop): Init reg_address_cost. + (loop_optimize): Call end_alias_analysis. + (scan_loop): Init the_movables. + (record_giv): Init induction->no_const_addval. + (basic_induction_var) [PLUS]: Use rtx_equal_p instead of ==. + [REG]: Rearrange loop search test to catch more cases. + (general_induction_var): Return success not benefit; take an extra + argument for that. Change all callers. + (simplify_giv_expr) [PLUS]: Always combine invariants. Use sge_plus. + [MULT]: Use rtx_equal_p instead of ==. Combine simple invariants. + [default]: Search the_movables for additional combinations. + (sge_plus_constant, sge_plus): New functions. + (express_from_1): New function. + (express_from): Always define. Rewrite using express_from_1. + (combine_givs_p): Handle more cases. Ignore address cost. + (cmp_combine_givs_stats): New function. + (combine_givs_used_once, combine_givs_benefit_from): New functions. + (combine_givs): Rewrite to do best-fit combination. + + * fold-const.c (operand_equal_p): Handle RTL_EXPR. + (fold): Do a complete (A*C)+(B*C) association check. + +Fri Jul 17 11:21:55 1998 Jim Wilson + + * function.c (fixup_var_refs_insns): Handle CLOBBER of a CONCAT. + +Fri Jul 17 11:48:55 1998 Jeffrey A Law (law@cygnus.com) + + * mn10300.c (MODES_TIEABLE_P): Fix typo. + +Fri Jul 17 03:26:12 1998 Rihcard Earnshaw (rearnsha@arm.com) + + * tree.c (valid_machine_attribute): Only create a new type variant if + there is a decl to use it. + +Thu Jul 16 14:48:04 1998 Nick Clifton + + * gcc.c (do_spec_1): Cope with %g/%u/%U options which do not have + a suffix. + +Fri Jul 17 03:24:40 1998 Hans-Peter Nilsson + + * extend.texi (Explicit Reg Vars): Typo: change "may deleted" into "may + be deleted" + +Thu Jul 16 14:48:47 1998 Jeffrey A Law (law@cygnus.com) + + * mn10300.c (count_tst_insns): New arg oreg_countp. Callers changed. + Simplify tests for clearing an address register. + (expand_prologue): Corresponding changes. + + * mn10300.md (movXX patterns): Make sure the destination is an + ADDRESS_REG when substituting "zero_areg" for (const_int 0). + (logical patterns): Split into expanders + patterns + (zero and sign extension patterns): Similarly. + (shift patterns): Similarly. + +Thu Jul 16 01:17:44 1998 Richard Henderson + + * loop.c (emit_iv_add_mult): Scan the entire insn list generated + for the sequence, recording base values. + +Wed Jul 15 10:49:55 1998 Richard Henderson + + * i386.h (CPP_CPU_SPEC): Remove -Asystem(unix). + +Tue Jul 14 14:15:30 1998 Nick Clifton + + * gcc.c: Remove ANSI-C ism from --help code. + + * toplev.c: Support --help with USE_CPPLIB. + +Tue Jul 14 14:46:08 1998 Jeffrey A Law (law@cygnus.com) + + * configure.in: Rework gas feature code to work with symlink based + source trees. + + * extend.texi: Clarify some issues related to local variables + assigned to explicit registers. + + * mn10300.md (mulsi): Turn into expander + pattern. + + * mn10300.md (movsi, movsf, movdi, movdf): Remove "x" from I -> a + alternative. + +Tue Jul 14 07:41:59 1998 Richard Earnshaw (rearnsha@arm.com) + + * arm/tcoff.h (USER_LABEL_PREFIX): Make it empty to match coff.h. + +Tue Jul 14 03:02:44 1998 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump again to distinguish mainline tree from the + egcs-1.1 branch. + +See ChangeLog.0 for earlier changes. + +Local Variables: +add-log-time-format: current-time-string +End: diff --git a/gcc_arm/ChangeLog.0 b/gcc_arm/ChangeLog.0 new file mode 100755 index 0000000..f2982a5 --- /dev/null +++ b/gcc_arm/ChangeLog.0 @@ -0,0 +1,13017 @@ +Tue Jul 14 02:20:38 1998 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump to avoid problems with old spec files during + bootstrap. + +Mon Jul 13 23:11:44 1998 David S. Miller + + * config/sparc/sparc.c (output_scc_insn): Enclose || conditions in + parens while walking over notes. + * config/sparc/sparc.md (reg movdi split): Clean up matching + conditions. + (all DI arithop splits on 32-bit): Handle immediate arguments + correctly when they are CONST_INTs. + +Mon Jul 13 23:57:21 1998 Kamil Iskra + + * m68k/m68k.h (TARGET_SWITCHES): Clear MASK_68040_ONLY for + -m68020-40, -m68020-60 and -m5200. + +Mon Jul 13 23:52:05 1998 Weiwen Liu + + * gcc.c (do_spec_1): Fix %O handling for secure temporary file + creation. + +Mon Jul 13 23:42:36 1998 Ralf Corsepius + + * sh/elf.h (MAX_OFILE_ALIGNMENT): Undefine before including svr4.h. + +Mon Jul 13 23:36:08 1998 Jim Wilson + + * i386/i386.h (CPP_486_SPEC, CPP_586_SPEC, CPP_686_SPEC): New specs. + (CPP_CPU_DEFAULT_SPEC, CPP_CPU_SPEC): Use them. + (EXTRA_SPECS): Support them. + * gcc.c: Delete %[spec] support. + (do_spec_1, case '('): Likewise. + (do_spec_1, case '['): Call error. + * i386/aix386ng.h, cygwin32.h, freebsd-elf.h, gas.h, isc.h, + linux-aout.h, linux-oldld.h, linux.h, osfelf.h, osfrose.h, sco.h, + sco4.h, sco4dbx.h, sco5.h, sol2.h, sysv3.h (CPP_SPEC): Delete + %[cpp_cpu]. + +Mon Jul 13 23:31:04 1998 Andreas Schwab + + * m68k.c (output_scc_di): Use cmpw #0 only for address registers. + +Mon Jul 13 23:26:43 1998 Jeffrey A Law (law@cygnus.com) + + * tree.h (tree_common): Note front-end dependencies on layout of + this structure. + +Mon Jul 13 23:18:39 1998 Craig Burley + + * stmt.c (expand_expr_stmt): If not assigning fresh + value to last_expr_value, zero it, so old garbage + doesn't get dereferenced. + +Mon Jul 13 23:06:55 1998 Henning.Petersen@t-online.de (Henning Petersen) + + * gcse.c (hash_scan_insn): Add missing argument declaration. + +Mon Jul 13 18:59:13 1998 Jim Wilson + + * configure.in (mips-sgi-irix5cross64, mips-sgi-irix5*): Remove + HAVE_INTTYPES_H from xm_defines. Define xm_file to mips/xm-iris5.h. + * mips/xm-iris5.h (USG): Delete. + +Mon Jul 13 17:18:47 1998 Nick Clifton + + * cccp.c (main): Add support for parsing --help. + (display_help): New function: display command line switches. + + * cpplib.c (cpp_handle_option): Add support for parsing --help. + (display_help): New function: display command line switches. + + * gcc.c (main): Add support for parsing --help, and passing it on + to the sub-processes invoked by gcc. + (display_help): New function: display comman line switches. + + * tm.texi (TARGET_SWITCHES and TARGET_OPTIONS): Document + 'description' field added to structure. + + * toplev.c: Add support for parsing --help. + Add documentation strings to command line option tables. + (display_help): New function: display comman line switches. + +Mon Jul 13 16:15:10 1998 John Carr + + * sparc.c, sparc.h, sparc.md: New trampoline code. + Allow integer operand 1 to V8+ DImode shift instructions. + Fix bugs in V8+ wide multiply patterns. + In 32 bit mode, split DImode register moves and logical instructions. + Write V9 branch prediction flag. + Use V9 conditional move more often for scc. + +Mon Jul 13 15:10:09 1998 Philippe De Muyter + + * invoke.texi(-fno-builtin): Explain that the names of built-in + functions begin with `__builtin_', not `__'. + +Mon Jul 13 19:01:52 1998 J"orn Rennecke + + * reload1.c (reload_reg_free_before_p): Abort for RELOAD_FOR_OUTPUT. + +Mon Jul 13 10:50:17 1998 Mark Mitchell + + * cplus-dem.c (SCOPE_STRING): Remove DMGL_JAVA stuff. + (cplus_demangle_opname): Initialize work. + (demangle_template): Remove is_java_array. + (do_type): Remove DMGL_JAVA stuff. + (long_options): Remove "java". + (main): Remove 'j' option. + +Mon Jul 13 10:19:00 1998 Jeffrey A Law (law@cygnus.com) + + * mn10300.h (REG_CLASS_FROM_LETTER): Map 'y' to SP_REGS. + Handle 'x' as NO_REGS for this cpu. + (REGNO_OK_FOR_BIT_BASE_P): Define. + (REG_OK_FOR_BIT_BASE_P): Define. + (GO_IF_LEGITIMATE_ADDRESS): Use them. + (REG_OK_FOR_INDEX_P): Tweak. + * mn13000.c (REG_SAVE_BYTES): Define. + (expand_epilogue, initial_offset): Use it. + (secondary_reload_class): Slightly reformat. + (output_tst): Tweak comments. + * mn10300.md: Change 'x' to 'y' for SP_REGS. Then add 'x' to many + patterns. + (addsi3): Turn into a define_expand/define_insn pair. Rework code for + three operand addition case to be more efficient. + (subsi3): Turn into a define_expand/define_insn pair. + + * expr.c (expand_expr): Only set MEM_IN_STRUCT_P if the memory address + is not varying for REFERENCE_TYPE or when we think we might have found + an optimized access to the first element in an array. + +Mon Jul 13 02:24:08 1998 David S. Miller + + * regclass.c (reg_scan_mark_refs): New arg min_regno. Only update + regscan information for REGs with numbers greater than or equal to + this. All callers changed. + (reg_scan_update): New function to efficiently update regscan + information on the fly. + * rtl.h: Add prototype. + * jump.c (jump_optimize): Call it when we make a transformation + which generates new pseudo-REGs. + +Sun Jul 12 13:08:14 1998 Jeffrey A Law (law@cygnus.com) + + * collect2.c (main): Use "-x c" instead of "-lang-c" for force the + compiler into C mode. + +Sun Jul 12 01:27:05 1998 Jason Merrill + + * cplus-dem.c (demangle_nested_args): Return a value. + + * tree.h (TYPE_P): New macro. + +Sat Jul 11 16:19:48 1998 Mark Mitchell + + * cplus-dem.c (string): Move definition before work_stuff. + (work_stuff): Add volatile_type, forgetting_types, + previous_argument, and nrepeats fields. + (SCOPE_STRING): New macro. + (demangle_template): Add `remember' parameter. Add comment. + Register the `B' code type here, if remembering. Tidy. Fix crash + on NULL tmpl_argvec. Be consistent with use of tname/trawname. + (demangle_nested_args): New function. + (internal_cplus_demangle): Handle volatile-qualified member + functions. + (mop_up): Delete the previous_argument string if present. + (demangle_signature): Tidy. Handle volatile-qualified member + functions. Handle back-references using the `B' code. Use extra + parameter to demangle_template and SCOPE_STRING where appropriate. + (demangle_template_value_parm): Fix thinko; 'B' is not an integral + code. + (demangle_class): Use SCOPE_STRING. + (gnu_special): Pass additional argument to demangle_template. + Use SCOPE_STRING. + (demangle_qualified): Save qualified types for later + back-references. Handle constructors and destructors for template + types correctly. + (do_type): Tidy. Use SCOPE_STRING. Pass extra argument to + demangle_template. Use demangled_nested_args. Don't remember + qualified types here; that's now done in demangle_qualified. + Similarly for templates. + (do_arg): Improve commment. Handle 'n' repeat code. + (remember_type): Check forgetting_types. + (demangle_args): Deal with 'n' repeat codes. Tidy. + +Sat Jul 11 02:59:08 1998 Richard Earnshaw + + * arm.md (extendhisi2_mem, movhi, movhi_bytes): Propagate the volatile + and structure attribute flags to MEMs generated. + (splits for sign-extended HI & QI mode from memory): Also propagate + the volatile flag. + + * configure.in (thumb-*-coff*): Don't cause fixincludes to be run. + +Fri Jul 10 19:06:59 1998 Michael Meissner + + * varray.h: Include system.h if it hasn't already been included + before to get size_t declared. + +Fri Jul 10 12:53:58 1998 David S. Miller + + * jump.c (jump_optimize): If after_regscan and our transformations + generate new REGs, rerun reg_scan. + +Fri Jul 10 11:50:43 EDT 1998 Andrew MacLeod + + * config/i960/i960.c (i960_address_cost): MEMA operands with + positive offsets < 4096 are free. + +Fri Jul 10 12:34:37 1998 Andreas Schwab + + * config/m68k/m68k.c (const_uint32_operand): Recognize + CONSTANT_P_RTX. + (const_sint32_operand): Likewise. + +Thu Jul 9 22:58:59 1998 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (alias.o): Depend on $(EXPR_H). + +Thu Jul 9 18:24:56 1998 J"orn Rennecke + + * reload1.c (choose_reload_regs): If using an equivalence from + find_equiv_reg and reg_reloaded_valid is not set for this register, + clear the associated spill_reg_store. + +Thu Jul 9 18:12:49 1998 J"orn Rennecke + + * reload1.c (emit_reload_insns): If an output reload copies only + to a secondary reload register, indicate that the secondary reload + does the actual store. + +Thu Jul 9 18:01:05 1998 J"orn Rennecke + + * reload.c (find_equiv_reg): If need_stable_sp is set, + check if stack pointer is changed directly in a PARALLEL. + +Thu Jul 9 10:38:14 1998 Jeffrey A Law (law@cygnus.com) + + * jump.c (duplicate_loop_exit_test): Fix thinko. + +Thu Jul 9 01:30:37 1998 Joel Sherrill + Ralf Corsepius + + * config/i386/rtemself.h: Updated to keep in sync with + config/i386/linux.h. + + * configure.in: Added sh-rtemself. + * configure: Rebuilt. + * config/sh/rtems.h: Removed -D__ELF__ since it is now COFF. + * config/sh/rtemself.h: New file. + + * config/rs6000/rtems.h: Defined STARTFILE_DEFAULT_SPEC. + +Wed Jul 8 21:43:14 1998 Jeffrey A Law (law@cygnus.com) + + * configure.in: Check if the assembler supports ".balign" and + ".p2align" and define HAVE_GAS_BALIGN_AND_P2ALIGN appropriately. + * acconfig.h (HAVE_GAS_BALIGN_AND_P2ALIGN): New tag. + * i386/gas.h (ASM_OUTPUT_ALIGN): If the assembler has support for + ".balign" then use it. + + * print-rtl.c (print_rtx): Revert previous patch. + + * jump.c (duplicate_loop_exit_test): Do not duplicate the loop exit + test if the exit code has an insn with ASM_OPERANDS. + + * i386/cygwin32.h (STDIO_PROTO): Fix typo. + * m32r.h (STDIO_PROTO): Fix typo. + + * pa.h (LEGITIMIZE_RELOAD_ADDRESS): Handle addresses created by + LEGITIMIZE_RELOAD_ADDRESS. + * tm.texi (LEGITIMIZE_RELOAD_ADDRESS): Note that this macro must be + able to handle addresses created by previous invocations of the macro. + + * flow.c (find_auto_inc): Remove most recent change. Real bug was + elsewhere. + + * cse.c (count_reg_usage): Count registers used in addresses of + CLOBBERs. + +Wed Jul 8 15:08:29 1998 Jim Wilson + + * Makefile.in (STAGESTUFF): Readd line lost during June 9 FSF merge. + + * configure.in (mips64orion-*-rtems*): Use elf64.h not elfl64.h. + +1998-07-08 Vladimir N. Makarov + + * config/fp-bit.c (__gexf2, __fixxfsi, __floatsixf): Add function + stubs. + + * toplev.c (lang_options): Add -Wlong-long, -Wno-long-long + options. + * c-decl.c (warn_long_long): Define. + (c_decode_option): Parse -Wlong-long, -Wno-long-long options. + (grokdeclarator): Add flag `warn_long_long' as guard for + warning "ANSI C does not support `long long'". + * invoke.texi: Add description of options -Wlong-long, + -Wno-long-long. + * gcc.1: The same as above. + +Wed Jul 8 02:43:34 1998 Jeffrey A Law (law@cygnus.com) + + * rtlanal.c (reg_overlap_mentioned_p): Handle STRICT_LOW_PART. If + either argument is CONSTANT_P, then return zero. + * reload.c (reg_overlap_mentioned_for_reload_p): Similarly. + + * configure.in: Also look at $srcdir/gas/configure to find a + gas version #. + +Wed Jul 8 00:28:22 1998 Carlo Wood + + * dsp16xx.h : Clean up of macro OPTIMIZATION_OPTIONS + +Tue Jul 7 21:18:14 1998 Mumit Khan + + * i386/cygwin32.h (ASM_DECLARE_FUNCTION_NAME): Merge duplicate + definitions from last two patches. + +Tue Jul 7 23:03:34 1998 J"orn Rennecke + + * reload1.c (choose_reload_regs): Don't set reload_override_in + if EQUIV is clobbered in INSN and the reload is done after INSN. + +Tue Jul 7 21:23:36 1998 J"orn Rennecke + + * expr.c (emit_queue): If emitting a SEQUENCE, set QUEUED_INSN + to the first insn of the sequence. + +Tue Jul 7 21:05:25 1998 J"orn Rennecke + + * cse.c (cse_insn): Don't make change without validation. + +Tue Jul 7 11:40:05 1998 Jeffrey A Law (law@cygnus.com) + + * mn10200.md (various zero/sign extension patterns): zero and sign + extensions which use "sub" clobber cc0. + +Tue Jul 7 09:12:08 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Tue Jul 7 10:07:20 1998 Jeffrey A Law (law@cygnus.com) + + * print-rtl.c (print_rtx): Use REAL_VALUE_TYPE instead of "double". + +Tue Jul 7 08:41:27 1998 Richard Henderson (rth@cygnus.com) + + * print-rtl.c (print_rtx): Only print fp values when REAL_VALUE_TYPE + is a double. + +Tue Jul 7 00:31:58 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Tue Jul 7 01:03:03 1998 Mumit Khan + + Support for dllimport and dllexport attributes for i386-pe. + + * tree.h (DECL_NON_ADDR_CONST_P): New accessor macro. + (struct tree_decl): Add non_addr_const_p field. + * tree.c (staticp): Use. + + * i386/cygwin32.h (CPP_PREDEFINES): Map __declspec(x) to GCC + attributes. + (SUBTARGET_SWITCHES): Switches to turn on/off dllimport|export + attributes. Also accept -mwindows option. + (VALID_MACHINE_DECL_ATTRIBUTE): New macro. + (MERGE_MACHINE_DECL_ATTRIBUTE): New macro. + (REDO_SECTION_INFO_P): New macro. + (DRECTVE_SECTION_FUNCTION): New macro. + (drectve_section): Cover function to implement above. + (SWITCH_TO_SECTION_FUNCTION): New macro. + (switch_to_section): Covert function to implement above. + (EXTRA_SECTIONS): Add in_drectve. + (EXTRA_SECTION_FUNCTIONS): Add in_drectve and switch_to_section. + (ENCODE_SECTION_INFO): Delete old macro and redefine as a function. + (STRIP_NAME_ENCODING): Handle new attributes. + (ASM_OUTPUT_LABELREF): New macro. + (ASM_OUTPUT_FUNCTION_NAME): New macro. + (ASM_OUTPUT_COMMON): New macro. + (ASM_OUTPUT_DECLARE_OBJECT_NAME): New macro. + + * i386/mingw32.h (CPP_PREDEFINES): Map __declspec(x) to GCC + attributes. + + * i386/winnt.c (i386_pe_valid_decl_attribute_p): New function. + (i386_pe_merge_decl_attributes): New function. + (i386_pe_check_vtable_importexport): New function. + (i386_pe_dllexport_p): New function. + (i386_pe_dllimport_p): New function. + (i386_pe_dllexport_name_p): New function. + (i386_pe_dllimport_name_p): New function. + (i386_pe_mark_dllexport): New function. + (i386_pe_mark_dllimport): New function. + (i386_pe_encode_section_info): New function. + (i386_pe_unique_section): Strip encoding from name first. + +Tue Jul 7 00:50:17 1998 Manfred Hollstein (manfred@s-direktnet.de) + + * libgcc2.c (L_exit): Provide a fake for atexit on systems which + define ON_EXIT but not HAVE_ATEXIT. + +Tue Jul 7 00:44:35 1998 Franz Sirl + + * m68k.md (zero_extend QI to HI): Correctly handle TARGET_5200. + +Tue Jul 7 00:36:41 1998 Ulrich Drepper + + * i386.c: Remove random whitespace at end of lines. + + * i386.c (ix86_epilogue): For pentium processors, try to deallocate + 4 or 8 byte stacks with pop instructions instead of an add instruction. + +Tue Jul 7 00:30:08 1998 Klaus Kaempf + + * alpha.c: Include tree.h before expr.h. + +Mon Jul 6 22:50:48 1998 Jason Merrill + + * c-parse.in (struct_head, union_head, enum_head): New nonterminals. + (structsp): Use them. Update files generated from c-parse.in. + * extend.texi (Type Attributes): Document it. + + * c-decl.c: Add warn_multichar. + (c_decode_option): Handle -Wno-multichar. + * c-lex.c (yylex): Check it. + * c-tree.h: Declare it. + * toplev.c (lang_options): Add it. + * invoke.texi: Document it. + +Mon Jul 6 22:47:55 1998 J"orn Rennecke + + * reload.c (find_equiv_reg): When looking for stack pointer + const, + make sure we don't use a stack adjust. + + * reload.c (find_equiv_reg): If need_stable_sp is set, + check if stack pointer is changed directly. + + * reload1.c (delete_dead_insn): Don't delete feeding insn + if that insn has side effects. + + * flow.c (find_auto_inc): Clear UNCHANGING bit of register that is + changed. + + * reload1.c (reload_reg_free_before_p): RELOAD_FOR_OPADDR_ADDR + precedes RELOAD_FOR_OUTADDR_ADDRESS. + + * gcse.c (hash_scan_insn): New argument IN_LIBCALL_BLOCK. Changed + caller. + +Mon Jul 6 22:21:56 1998 Kamil Iskra + + * m68k.c (output_scc_di): Use cmpw #0 instead of tstl when + testing address registers on the 68000. + +Mon Jul 6 22:17:19 1998 Alasdair Baird + + * i386.c (is_fp_test): Fix thinko. + + * jump.c (jump_optimize) Check for CONST_INT before using INTVAL. + +Mon Jul 6 22:14:31 1998 Richard Henderson (rth@cygnus.com) + + * print-rtl.c (print_rtx): Display the real-value equivalent of + a const_double when easy. + + * real.h (REAL_VALUE_TO_TARGET_SINGLE): Use a union to pun types. + Zero memory first for predictability. + (REAL_VALUE_TO_TARGET_DOUBLE): Likewise. + * varasm.c (immed_real_const_1): Notice width of H_W_I == double. + + * regclass.c (allocate_reg_info): Initialize the entire reg_data + virtual array. + +Mon Jul 6 22:09:32 1998 Ian Lance Taylor + Jeff Law + + + * i386/cygwin32.h: Add some declaration of external functions. + (ASM_DECLARE_FUNCTION_NAME): Define. + (ASM_OUTPUT_EXTERNAL, ASM_OUTPUT_EXTERNAL_LIBCALL): Define. + (ASM_FILE_END): Define. + * i386/winnt.c (i386_pe_declare_function_type): New function. + (struct extern_list, extern_head): Define. + (i386_pe_record_external_function): New function. + (i386_pe_asm_file_end): New function. + + * cpplib.c (cpp_options_init): Initialize cplusplus_comments to 1, + matching July 18, 1995 change to cccp.c. If -traditional then + disable cplusplus_comments. + +Mon Jul 6 21:28:14 1998 Jeffrey A Law (law@cygnus.com) + + * combine.c (expand_compound_operation): Fix thinko in code to optimize + (zero_extend:DI (subreg:SI (foo:DI) 0)) to foo:DI. + + * Disable the following change from gcc2. Not appropriate for egcs: + + Sun Jun 7 09:30:31 1998 Richard Kenner + * reload.c (find_reloads): Give preference to pseudo that was the + reloaded output of previous insn. + +Mon Jul 6 21:07:14 1998 Kaveh R. Ghazi + + * aclocal.m4 (GCC_FUNC_PRINTF_PTR): Don't define HOST_PTR_PRINTF. + Instead, define a new macro HAVE_PRINTF_PTR which only signifies + whether we have the %p format specifier or not. + + * acconfig.h: Delete stub for HOST_PTR_PRINTF, add HAVE_PRINTF_PTR. + + * machmode.h (HOST_PTR_PRINTF): When determining the definition, + check HAVE_PRINTF_PTR to see whether "%p" is okay. + + * mips-tfile.c: Include machmode.h to get HOST_PTR_PRINTF. + + * Makefile.in (mips-tfile.o): Depend on machmode.h. + +Mon Jul 6 10:42:05 1998 Mark Mitchell + + * jump.c (duplicate_loop_exit_test): Don't refuse to copy a + section of code just because it contains + NOTE_INSN_BLOCK_{BEG,END}. + * stmt.c (expand_end_loop): Likewise. Also, don't refuse to + move CALL_INSNs or CODE_LABELs. When moving code, don't move + NOTE_INSN_BLOCK_{BEG,END}. + +Mon Jul 6 09:38:15 1998 Mark Mitchell + + * cse.c (CSE_ADDRESS_COST): New macro, based on ADDRESS_COST, but + dealing with ADDRESSOF. + (find_best_addr): Use it. + +Mon Jul 6 09:27:08 1998 Richard Henderson + + * alpha/vms.h (TRAMPOLINE_TEMPLATE): Revert last change. + +Mon Jul 6 09:25:06 1998 Dave Love + + * libgcc2.c (__eprintf): Make args consistent with prototype in + assert.h. + +Mon Jul 6 00:28:43 1998 Mark Mitchell + + * cse.c (cse_insn): When SETting (MEM (ADDRESSOF (X))) to Y, + don't claim that the former is equivalent to the latter. + +Sun Jul 5 23:58:19 1998 Jeffrey A Law (law@cygnus.com) + + * cse.c (cse_insn): Second arg is an RTX now. Update all callers. + (cse_basic_block): Keep track of the current RETVAL insn for a + libcall instead of just noting that we're in a libcall. + + * combine.c (simplify_comparison): Do not commute a AND into + a paradoxical SUBREG if not WORD_REGISTER_OPERATIONS. + + * i386/freebsd-elf.h (ASM_OUTPUT_MAX_SKIP_ALIGN): Protect with + HAVE_GAS_MAX_SKIP_P2ALIGN. + * i386/linux.h: Likewise. + +Fri Jul 3 02:33:35 1998 David S. Miller + + * sparc.c (sparc_operand, move_operand, arith_operand, + arith11_operand, arith10_operand, arith_double_operand, + arith11_double_operand, arith10_double_operand, small_int, + uns_small_int): Recognize CONSTANT_P_RTX. + (output_sized_memop, output_move_with_extension, + output_load_address, output_size_for_block_move, + output_block_move, delay_operand): Remove, has not been + enabled or referenced for years. + * sparc.md (movstrsi, block_move_insn): Likewise. + * sparc.h (PREDICATE_CODES): Define. + * linux-aout.h (MACHINE_STATE_{SAVE,RESTORE}): Override with + version which uses getcc/setcc traps to save/restore condition + codes. + * linux64.h: Likewise. + * sunos4.h: Likewise. + * linux.h: Likewise. + * sol2.h: Likewise. + * sun4o3.h: Likewise. + +Fri Jul 3 02:28:05 1998 Richard Henderson + + * alpha.c (alpha_initialize_trampoline): Hack around Pmode/ptr_mode + lossage on VMS. Reported by kkaempf@rmi.de. + * alpha/vms.h (TRAMPOLINE_TEMPLATE): Add missing 0. + +Thu Jul 2 17:41:14 1998 Nick Clifton + + * config/m32r/m32r.h (MUST_PASS_IN_STACK): Override default + version. + +Thu Jul 2 14:34:48 1998 David Edelsohn + + * expr.h (STACK_SIZE_MODE): New macro. + * explow.c (allocate_dynamic_stack_space): Use it for + mode of allocate_stack pattern increment operand. + * tm.texi (STACK_SAVEAREA_MODE, STACK_SIZE_MODE): Document. + * md.texi (stack_save_block, ...): Reflect use of macro. + + * rs6000.h (PROMOTE_MODE): Always promote to word_mode. + (PROMOTE_FUNCTION_ARGS): Define. + (PROMOTE_FUNCTION_RETURN): Define. + (FUNCTION_VALUE): Promote to word_mode if smaller. + Convert to gen_rtx_FOO. + * rs6000.md (call_indirect): Store doubleword in 64-bit mode. + Convert to gen_rtx_FOO. + * rs6000.c: Convert to gen_rtx_FOO. + +Thu Jul 2 14:16:11 1998 Michael Meissner + + * varray.{c,h}: New files to provide virtual array support. + + * Makefile.in (OBJS): Add varray.o. + (varray.o): Add new file. + (REGS_H): New variable for dependencies for files including + regs.h. Add varray.h and files it includes. Change all regs.h + dependencies to $(REGS_H). + + * toplev.c (x{m,re}alloc): If size is 0, allocate 1 byte. + (xcalloc): Provide frontend for calloc. + * {tree,rtl}.h (xcalloc): Add declaration. + + * basic-block.h (REG_BASIC_BLOCK): Convert reg_n_info to be a + varray. + + * regs.h (toplevel): Include varray.h. + (reg_n_info): Switch to use a varray. + (REG_*): Ditto. + (allocate_reg_info): Change num_regs argument to be size_t. + + * regclass.c (reg_info_data): New structure to remember groups of + reg_info structures allocated that are to be zeroed. + ({pref,alt}class_buffer): New statics to hold buffers + allocate_reg_info allocates for {pref,alt}class_buffer. + (regclass): Use {pref,alt}class_buffer to initialize + {pref,alt}class. + (allocate_reg_info): Switch to make reg_n_info use varrays. + Allocate buffers for the preferred and alter register class + information. Change num_regs argument to be size_t, not int. + + * flow.c (reg_n_info): Switch to use varrays. + +Thu Jul 2 10:11:47 1998 Robert Lipe + + * install.texi (sco3.2v5): Document new --with-gnu-as flag. + * config/i386/sco5.h (JUMP_TABLES_IN_TEXT_SECTION): Defined as + in other targets. + (USE_GAS): Conditionalize away native assembler usage. + * config/i386/sco5gas.h: New file. + * config/i386/t-sco5gas: New file. + * configure.in (ix86-sco3.2v5*): Use new files if --with-gnu-as + +Thu Jul 2 08:20:00 1998 Catherine Moore + + * haifa-sched.c (alloc_EXPR_LIST): Change to use + unused_expr_list. + +Thu Jul 2 14:13:28 1998 Dave Love + + * Makefile.in (install-info): Don't use $realfile. Ignore + possible errors from the install-info program. + +Thu Jul 2 01:53:32 1998 Alasdair Baird + + * combine.c (simplify_comparison): Apply SUBREG_REG to SUBREGs. + +Wed Jul 1 23:06:03 1998 Richard Henderson + + * i386.h (HARD_REGNO_MODE_OK): Kill spurrious test. + (MODES_TIEABLE_P): Tie SImode and HImode. + +1998-07-01 Andreas Jaeger + + * invoke.texi (Optimize Options): Fix typo. + +Wed Jul 1 22:25:43 1998 Jim Wilson + + * xcoffout.c (xcoffout_begin_function): Call xcoffout_block for + the zero'th block. + +Wed Jul 1 23:12:58 1998 Ken Raeburn + + * h8300.c (print_operand): Delete %L support. + * h8300.md (branch_true, branch_false): Use %= with a prefix + instead of %L for local branch labels. + +Wed Jul 1 21:27:13 1998 J"orn Rennecke + + * reload1.c (emit_reload_insns): Use proper register classes for + SECONDARY_INPUT_RELOAD_CLASS / SECONDARY_MEMORY_NEEDED code. + +Wed Jul 1 21:17:36 1998 J"orn Rennecke + + * reload.c (find_reloads): If there are multiple + RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_OUTPUT_ADDRESS reloads for + one operand, change RELOAD_FOR_INPADDR_ADDRESS / + RELOAD_FOR_OUTADDR_ADDRESS for all but the first + RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_OUTPUT_ADDRESS reloads. + +Wed Jul 1 17:23:23 1998 J"orn Rennecke + + * regmove.c (fixup_match_2): Check that P has RTX_CLASS 'i' before + using its PATTERN. + +Wed Jul 1 05:04:41 1998 Richard Henderson + + * expr.c (emit_group_load, emit_group_store): Rewrite considering + the size and alignment of the structure being manipulated. + * expr.c, calls.c, function.c: Update all callers. + * expr.h: Update prototypes. + * cse.c (invalidate): Cope with parallels. + +Wed Jul 1 04:22:23 1998 Richard Henderson + + * sparc.c (function_arg_record_value): Take a MODE arg with which to + create the PARALLEL. Update all callers. + +Wed Jul 1 04:10:35 1998 Richard Henderson + + * expr.c (expand_assignment, store_constructor, expand_expr): Use + convert_memory_address instead of convert_to_mode when possible. + +Wed Jul 1 03:48:00 1998 Richard Henderson + + * alpha.c (alpha_initialize_trampoline): Take arguments describing + the layout. Use ptr_mode. Disable hint generation. Use gen_imb. + * alpha.h (INITIALIZE_TRAMPOLINE): Pass extra args to the init func. + (TRANSFER_FROM_TRAMPOLINE): Move ... + * alpha/osf.h: ... here. + * alpha/vms.h (INITIALIZE_TRAMPOLINE): Use alpha_initialize_trampoline. + (TRANSFER_FROM_TRAMPOLINE): Remove undef. + * alpha/win-nt.h: Likewise. + * alpha/vxworks.h: Likewise. + + * alpha/linux.h: Revert gcc2 merge lossage. + +Wed Jul 1 10:56:55 1998 Andreas Schwab + + * c-decl.c (grokdeclarator): Don't warn about implicit int in + `typedef foo = bar'. + +Wed Jul 1 02:12:33 1998 Robert Lipe + + * i386.c (asm_output_function_prefix): Make 686 function + prologues not issue .types for non-global lables. + +Tue Jun 30 23:46:53 1998 Dmitrij Tejblum + + * i386/freebsd.h (WCHAR_TYPE): Chagne to an "int". + (WCHAR_TYPE_SIZE): Update appropriately. + +Tue Jun 30 23:16:39 1998 Jeffrey A Law (law@cygnus.com) + + * flow.c (recompute_reg_usage): Does not return a value. + * rtl.h (recompute_reg_usage): Update prototype. + + * jump.c (jump_optimize): Show that the jump chain is not + valid when not optimizing. + +Tue Jun 30 16:01:01 1998 Richard Henderson + + * rtl.def (CONSTANT_P_RTX): New. + * rtl.h (CONSTANT_P): Recognize it. + * cse.c (fold_rtx): Eliminate it. + * expr.c (can_handle_constant_p): New variable. + (init_expr_once): Initialize it. + (expand_builtin): Generate CONSTANT_P_RTX if the expression is not + immediately recognizable as a constant. + + * alpha.c (reg_or_6bit_operand): Recognize CONSTANT_P_RTX. + (reg_or_8bit_operand, cint8_operand, add_operand): Likewise. + (sext_add_operand, and_operand, or_operand): Likewise. + (reg_or_cint_operand, some_operand, input_operand): Likewise. + * alpha.h (PREDICATE_CODES): Add CONSTANT_P_RTX where needed. + +1998-06-30 Benjamin Kosnik + + * dbxout.c (dbxout_type_methods): Remove warn_template_debugging. + +Tue Jun 30 14:03:34 1998 Kaveh R. Ghazi + + * aclocal.m4 (GCC_NEED_DECLARATION): Accept an optional second + argument, which is typically preprocessor code used to draw in + additional header files when looking for a function declaration. + (GCC_NEED_DECLARATIONS): Likewise. + + * configure.in (GCC_NEED_DECLARATIONS): Add checks for getrlimit + and setrlimit, search for them in sys/resource.h. + + * acconfig.h: Add stubs for NEED_DECLARATION_GETRLIMIT and + NEED_DECLARATION_SETRLIMIT. + + * system.h: Prototype getrlimit/setrlimit if necessary. + +Tue Jun 30 10:54:48 1998 Mark Mitchell + + * rtl.texi: Don't say that RTX_INTEGRATED_P is not depended + upon. + +Tue Jun 30 13:11:42 1998 Franz Sirl + + * rs6000/sysv4.h (asm output): add tabs for asm directives. + +Tue Jun 30 13:11:42 1998 David Edelsohn + + * Makefile.in (FLAGS_TO_PASS): Set AR_FLAGS to AR_FOR_TARGET_FLAGS. + +Tue Jun 30 08:59:15 1998 Kaveh R. Ghazi + + * gansidecl.h (ATTRIBUTE_UNUSED): Use __unused__ not `unused'. + Don't define NULL here. Also, remove all vestiges of autoconf + based checks for bcmp/bcopy/bzero/index/rindex. + + * system.h: Immediately after including stdio.h, check for and if + necessary provide a default definition of NULL. + +Tue Jun 30 08:22:05 1998 Michael Meissner + + * reload1.c (reload_cse_simplify_operands): Call + fatal_insn_not_found, not abort. + +Tue Jun 30 02:34:02 1998 Jeffrey A Law (law@cygnus.com) + + * choose-temp.c (make_temp_file): Accept new argument for the + file suffix to use. Allocate space for it and add it to the + template. + * mkstemp.c (mkstemps): Renamed from mkstemp. Accept new argument + for the length of the suffix. Update template struture checks + to handle optinal suffix. + * collect2.c (make_temp_file): Update prototype. + (main): Put proper suffixes on temporary files. + * gcc.c (make_temp_file): Update prototype. + (do_spec_1): Put proper suffixes on temporary files. + +Tue Jun 30 00:56:19 1998 Bruno Haible + + * invoke.texi: Document new implicit structure initialization + warning. + +Mon Jun 29 21:40:15 1998 J"orn Rennecke + + * toplev.c (flag_dump_unnumbered): Declare. + (f_options): Add dump-unnumbered. + * print-rtl.c (flag_dump_unnumbered): Define. + (print_rtx): Print only '#' for insn numbers if flag_dump_unnumbered + is nonzero. + (print_rtl): Don't output line number notes if flag_dump_unnumbered + is nonzero. + * flow.c (print_rtl_with_bb): Don't output newline after line + numbers note if flag_dump_unnumbered is nonzero. + +Mon Jun 29 22:12:06 1998 Jeffrey A Law (law@cygnus.com) + + * Merge from gcc2 June 9, 1998 snapshot. See ChangeLog.13 for + details. + + * pa.c, pa.h, pa.md: Convert to gen_rtx_FOO. + +Mon Jun 29 20:12:41 1998 Kaveh R. Ghazi + + * Makefile.in (fix-header): Don't needlessly depend on cpperror.o. + + * alias.c (CHECK_ALIAS_SETS_FOR_CONSISTENCY): Cast expansion to + void since it is evaluated in a comma list. + + * mips.h (ASM_GENERATE_INTERNAL_LABEL): Always sprintf `NUM' + argument as a long and cast `NUM' to long to ensure it is of the + proper width. Wrap macro arguments in parens when they appear in + the expansion. + + * sol2.h (ASM_GENERATE_INTERNAL_LABEL): Likewise. + + * sparc.h (ASM_GENERATE_INTERNAL_LABEL): Likewise. + (ASM_DECLARE_RESULT): Fix fprintf format specifier to match + function argument return type. + (REGNO_OK_FOR_INDEX_P, REGNO_OK_FOR_BASE_P, REGNO_OK_FOR_FP_P, + REGNO_OK_FOR_CCFP_P): Use `(unsigned)' not `U'. + + * cpplib.c (cpp_message_from_errno): Remove unneeded argument to + cpp_message. + + * dbxout.c: Fix the comments after an #endif to reflect the actual + condition tested in the preceding #if. + + * except.c (find_all_handler_type_matches): Switch to old-style + function definition. + + * expr.c (expand_builtin): Remove unused variable `type' twice. + + * gbl-ctors.h (DO_GLOBAL_CTORS_BODY): Cast -1 before comparing it + to an unsigned long. + + * haifa-sched.c (print_insn_chain): Remove unused function. + + * objc/objc-act.c (build_msg_pool_reference): Hide prototype and + definition. + + * toplev.c: When testing whether to include dbxout.h, also include + it when XCOFF_DEBUGGING_INFO is defined. + + * unroll.c (unroll_loop): Add parentheses around assignment used + as truth value. + +Mon Jun 29 12:18:00 1998 Catherine Moore + + * config/lb1spc.asm (.div, .udiv): Replace routines. + +Mon Jun 29 09:44:24 1998 Mark Mitchell + + * rtl.h: Update comment about special gen_rtx variants. + * emit-rtl.c (gen_rtx): Handle MEMs using gen_rtx_MEM. + +Sun Jun 28 20:58:51 1998 Jeffrey A Law (law@cygnus.com) + + * choose-temp.c (choose_temp_base): Restore original variant of + this function for compatibility. + (make_temp_file): This is the new, preferred interface to create + temporary files. + * collect2.c (choose_temp_base): Delete declaration. + (make_temp_file): Declare. + (temp_filename_length, temp_filename): Delete. + (main): Use make_temp_file to get temporary files. Use --lang-c + to force the resulting ctort/dtor file to be compiled with the C + compiler. Make sure to remove temporary files on all exit paths. + * gcc.c (make_temp_file): Provide prototype if MKTEMP_EACH_FILE is + defined. + (choose_temp_base): Only provide prototype if MKTEMP_EACH_FILE is + not defined. + (do_spec): Use make_temp_file if MKTEMP_EACH_FILE is defined. + +Sun Jun 28 08:57:09 1998 Kaveh R. Ghazi + + * configure.in (GCC_NEED_DECLARATIONS): Add strerror, getcwd and + getwd. + + * acconfig.m4: Add stubs for NEED_DECLARATION_STRERROR, + NEED_DECLARATION_GETCWD and NEED_DECLARATION_GETWD. + + * cccp.c: Remove strerror()/sys_nerr/sys_errlist decls. + (my_strerror): Add prototype and make it static. + + * collect2.c: Likewise. + + * cpplib.c: Likewise. + + * gcc.c: Likewise, but keep `my_strerror' extern. + + * protoize.c: Likewise. + + * pexecute.c (my_strerror): Add argument to prototype. + + * system.h: Add prototypes for getcwd, getwd and strerror. Add + extern decls for sys_nerr and sys_errlist. Make abort decl + explicitly extern. + + * getpwd.c: Remove decls for getwd and getcwd. + +Sun Jun 28 02:11:16 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sat Jun 27 23:32:25 1998 Richard Henderson + + * jump.c (jump_optimize): Use side_effects_p & may_trap_p instead + of rtx_unsafe_p. Use modified_between_p instead of reg_set_between_p. + Allow FP moves to be optimized. + (rtx_unsafe_p): Delete. + +Sat Jun 27 23:02:04 1998 Richard Henderson + + * objc/archive.c: Remove prototypes. + +Sat Jun 27 22:37:05 1998 Jeffrey A Law (law@cygnus.com) + + * tm.texi (NEED_MATH_LIBRARY): Document new target macro. + + * Makefile.in (gencheck): Remove $(TREE_H) dependency. + +Sat Jun 27 20:20:00 1998 John Carr + + * dsp16xx.h (FIRST_PSEUDO_REGISTER): Add parentheses to definition. + * dsp16xx.c (next_cc_user_unsigned): New function. + Remove save_next_cc_user_code. + (print_operand): Use HOST_WIDE_INT_PRINT_* macros. + * dsp16xx.md: Call next_cc_user_unsigned instead of using + save_next_cc_user_code. + Use gen_rtx_* functions instead of gen_rtx. + +Sat Jun 27 20:18:34 1998 Franz Sirl + + * rs6000.h: Add trap_comparison_operator to PREDICATE_CODES. + +Sat Jun 27 16:45:42 1998 Jeffrey A Law (law@cygnus.com) + + * flow.c (count_reg_sets): New function. + (count_reg_sets_1, count_ref_references): Likewise. + (recompute_reg_usage): Likewise. + * rtl.h (recompute_reg_usage): Add prototype. + * toplev.c (rest_of_compilation): Call recompute_reg_usage just + before local register allocation. + +Sat Jun 27 13:15:30 1998 Richard Henderson + + * alpha.md (negsf, negdf): Revert Jan 22 change. + +Sat Jun 27 07:35:21 1998 Kaveh R. Ghazi + + * mkstemp.c: Include gansidecl.h. Rename uint64_t to gcc_uint64_t. + (mkstemp): Remove size specifier for variable `letters'. Call + gettimeofday, not __gettimeofday. + + * Makefile.in (EXPR_H): New dependency variable. + (c-typeck.o): Depend on $(EXPR_H) instead of expr.h. + (c-iterate.o): Likewise. + (gencheck): Depend on $(TREE_H) instead of tree.h, etc. + (stor-layout.o): Depend on $(EXPR_H) instead of expr.h. + (toplev.o): Likewise. Also depend on $(RECOG_H) instead of recog.h. + (varasm.o): Depend on $(EXPR_H) instead of expr.h. + (function.o): Likewise. + (stmt.o): Likewise. + (except.o): Likewise. + (expr.o): Likewise. + (calls.o): Likewise. + (expmed.o): Likewise. + (explow.o): Likewise. + (optabs.o): Likewise. + (sdbout.o): Likewise. + (dwarf2out.o): Likewise. + (emit-rtl.o): Likewise. + (integrate.o): Likewise. + (jump.o): Likewise. + (cse.o): Likewise. + (gcse.o): Likewise. Also depend on $(BASIC_BLOCK_H) instead of + basic-block.h. + (loop.o): Depend on $(EXPR_H) instead of expr.h. + (unroll.o): Likewise. + (combine.o): Likewise. + (reload.o): Likewise. + (reload1.o): Likewise. + (caller-save.o): Likewise. + (reorg.o): Likewise. + (alias.o): Don't depend on insn-codes.h. + (regmove.o): Depend on $(RECOG_H)/$(EXPR_H) instead of recog.h/expr.h. + (insn-emit.o): Depend on $(EXPR_H) instead of expr.h. + (insn-opinit.o): Likewise. + +Sat Jun 27 01:35:14 1998 Jeffrey A Law (law@cygnus.com) + + * choose-temp.c (choose_temp_base): Remove MPW bits. Use mkstemp + instead of mktemp. + * gcc.c (MKTEMP_EACH_FILE): Define. + (main): No need to call choose_temp_base if we are going to + use choose_temp_base to create each file later. + * mkstemp.c: New file. Adapted from glibc. + * Makefile.in (xgcc, colect2, protoize, unprotoize): Link in mkstemp.o + (mkstemp.o): Add dependencies. + + * configure.in (gettimeofday): Check for its existance. + * config.in (HAVE_GETTIMEOFDAY): Define. + * configure: Rebuilt. + +1998-06-26 Michael Meissner + + * rs6000.md (ne 0, non power case): Add missing & constraint. + Name pattern ne0. + (negative abs insns): Add pattern names. + +Fri Jun 26 17:36:42 1998 Dave Love + + * Makefile.in (install-info): Run install-info program in separate + loop. + +Fri Jun 26 16:03:15 1998 Michael Meissner + + * haifa-sched.c (schedule_block): Add hooks for the machine + description to reorder the ready list, and update how many more + instructions can be issued this cycle. + * tm.texi (MD_SCHED_{INIT,REORDER,VARIABLE_ISSUE}): Document. + +Fri Jun 26 11:54:11 1998 David S. Miller + + * config/sparc/sparc.h (REGNO_OK_FOR_{INDEX,BASE,FP,CCFP}_P): + Explicitly mark the constant being compared against as unsigned. + * config/sparc/sparc.c (sparc_select, cpu_default, cpu_table): + Fully initialize final members. + (mem_aligned_8): Explicit init of offset to zero. + (output_function_prologue): Explicit init of n_regs to zero. + (output_function_epilogue): Likewise, and mark arg size as + unused. + (init_cumulative_args): Mark libname and indirect as unused. + (function_arg_pass_by_reference): Likewise for cum and named. + (sparc_builtin_saveregs): Likewise for arglist. + (sparc_flat_eligible_for_epilogue_delay): Likewise for slot. + +Fri Jun 26 06:58:54 1998 Richard Earnshaw (rearnsha@arm.com) + + * arm.h (SECONDARY_INPUT_RELOAD_CLASS): Only need a secondary reload + if reloading a MEM. + + * arm.h (arm_adjust_cost): Renamed bogus prototype from + arm_adjust_code. + (bad_signed_byte_operand): Add prototype. + * arm.c (arm_override_options): Make I unsigned. + (const_ok_for_arm): Add casts to the constants. + (load_multiple_operation): Don't redeclare elt in sub-block. + (arm_gen_movstrqi): Delete external declaration of optimize. + (gen_compare_reg): Declare parameter fp. + + * arm.c (final_prescan_insn): Only initialize scanbody if the insn + has a pattern. + +Fri Jun 26 09:31:24 1998 Kaveh R. Ghazi + + * alpha.c: Include system.h and toplev.h. + (cint8_operand): Mark parameter `mode' with ATTRIBUTE_UNUSED. + (const48_operand): Likewise. + (mode_width_operand): Likewise. + (mode_mask_operand): Likewise. + (mul8_operand): Likewise. + (current_file_function_operand): Likewise. + (signed_comparison_operator): Likewise. + (divmod_operator): Likewise. + (any_memory_operand): Likewise. + (alpha_return_addr): Likewise for parameter `frame'. + (alpha_builtin_saveregs): Likewise for parameter `arglist'. + (vms_valid_decl_attribute_p): Likewise for parameters `decl' and + `attributes'. + (alpha_start_function): Likewise for parameter `decl'. Use + HOST_WIDE_INT_PRINT_DEC in call to fprintf. Fix various format + specifiers. Remove unused variables `lab' and `name'. + (alpha_end_function): Mark parameter `decl' with ATTRIBUTE_UNUSED. + (check_float_value): Likewise for parameter `overflow'. + (alpha_need_linkage): Likewise for parameters `name' and `is_local'. + + * alpha.h (ASM_IDENTIFY_GCC, ASM_IDENTIFY_LANGUAGE): Define as + taking an argument. + (ASM_OUTPUT_SHORT): Cast argument to `int' in call to fprintf. + (ASM_OUTPUT_CHAR): Likewise. + (ASM_OUTPUT_BYTE): Likewise. + (PRINT_OPERAND_ADDRESS): Use HOST_WIDE_INT_PRINT_DEC in call to + fprintf. + (PUT_SDB_EPILOGUE_END): Mention argument `NAME' in definition. + Add prototypes for functions in alpha.c. + + * alpha.md (ashldi3): Add default case in switch. + +1998-06-26 Manfred Hollstein + + * Makefile.in (gcc_version, gcc_version_trigger): New macros. + (version): Initialize from $(gcc_version). + + * configure.in (version): Rename to gcc_version. + (gcc_version_trigger): New variable; call AC_SUBST for it and + emit it into the generated config.status. + * configure: Regenerate. + +Thu Jun 25 12:47:41 1998 Mark Mitchell + + * fold-const.c (make_range): Don't go looking at TREE_OPERANDs of + nodes that are not expressions. + +Thu Jun 25 15:08:16 1998 Mark Mitchell + + * invoke.texi (-fstrict-aliasing): Document. + * rtl.texi (MEM_ALIAS_SET): Document. + + * flags.h (flag_strict_aliasing): Declare. + * toplev.c (flag_strict_aliasing): Define. + (f_options): Add -strict-aliasing. + (main): Set flag_strict_aliasing if -O2 or higher. + + * tree.h (tree_type): Add alias_set field. + (TYPE_ALIAS_SET): New macro. + (TYPE_ALIAS_SET_KNOWN_P): Likewise. + (get_alias_set): Declare. + * tree.c (lang_get_alias_set): Define. + (make_node): Initialize TYPE_ALIAS_SET. + (get_alias_set): New function. + * print-tree.c (print_node): Dump the alias set for a type. + + * c-tree.h (c_get_alias_set): Declare. + * c-common.c (c_get_alias_set): New function. + * c-decl.c (init_decl_processing): Set lang_get_alias_set. + + * expr.c (protect_from_queue): Propogage alias sets. + (expand_assignment): Calculate alias set for new MEMs. + (expand_expr): Likewise. + * function.c (put_var_into_stack): Likewise. + (put_reg_into_stack): Likewise. + (gen_mem_addressof): Likewise. + (assign_parms): Likewise. + * stmt.c (expand_decl): Likewise. + * varasm.c (make_decl_rtl): Eliminate redundant clearing of + DECL_RTL. Calculate alias set for new MEMs. + + * rtl.def (REG): Add dummy operand. + (MEM): Add extra operand to store the MEM_ALIAS_SET. + * rtl.h (MEM_ALIAS_SET): New macro. + (gen_rtx_MEM): Declare. + * emit-rtl.c (gen_rtx_MEM): New function. + * gengenrtl.c (sepcial_rtx): Make MEMs special. + + * alias.c (CHECK_ALIAS_SETS_FOR_CONSISTENCY): New macro. + (DIFFERENT_ALIAS_SETS_P): Likewise. + (canon_rtx): Propogate the alias set to the new MEM. + (true_dependence): Check the alias sets. + (anti_dependence): Likewise. + (output_dependence): Likewise. + * explow.c (stabilize): Progoate alias sets. + * integrate.c (copy_rtx_and_substitute): Likewise. + * final.c (alter_subreg): Make sure not to leave MEM_IN_STRUCT_P + in an unpredictable state. Propogate alias sets. + * reload1.c (reload): Clear MEM_ALIAS_SET for new MEMs about which + we have no alias information. + +Thu Jun 25 16:59:18 EDT 1998 Andrew MacLeod + + * except.h (CATCH_ALL_TYPE): Definition moved to eh-common.h. + (find_all_handler_type_matches): Add function prototype. + * eh-common.h (CATCH_ALL_TYPE): Definition added. + * except.c (find_all_handler_type_matches): Add function to find all + runtime type info in the exception table. + (output_exception_table_entry): Special case for CATCH_ALL_TYPE. + +Thu Jun 25 15:47:55 1998 Kaveh R. Ghazi + + * Makefile.in (xcoffout.o): Depend on toplev.h, output.h and dbxout.h. + + * config/fp-bit.c (_fpmul_parts): Move variables `x', `ylow', + `yhigh' and `bit' into the scope in which they are used. + (_fpdiv_parts): Remove unused variables `low', `high', `r0', `r1', + `y0', `y1', `q', `remainder', `carry', `d0' and `d1'. + + * rs6000.c: Move include of output.h below tree.h. Include toplev.h. + (any_operand): Mark unused parameters `op' and `mode' with + ATTRIBUTE_UNUSED. + (count_register_operand): Likewise for parameter `mode'. + (fpmem_operand): Likewise. + (short_cint_operand): Likewise. + (u_short_cint_operand): Likewise. + (non_short_cint_operand): Likewise. + (got_operand): Likewise. + (got_no_const_operand): Likewise. + (non_add_cint_operand): Likewise. + (non_logical_cint_operand): Likewise. + (mask_operand): Likewise. + (current_file_function_operand): Likewise. + (small_data_operand): Likewise for parameters `op' and `mode' but + only when !TARGET_ELF. + (init_cumulative_args): Mark parameters `libname' with + ATTRIBUTE_UNUSED. + (function_arg_pass_by_reference): Likewise for parameters `cum', + `mode' and `named'. + (expand_builtin_saveregs): Likewise for parameter `args'. + (load_multiple_operation): Likewise for parameter `mode'. + (store_multiple_operation): Likewise. + (branch_comparison_operator): Likewise. + (secondary_reload_class): Likewise. + (print_operand): Add parentheses around & operation. + (output_prolog): Mark parameter `size' with ATTRIBUTE_UNUSED. + (output_epilog): Likewise. Cast argument to fprintf to int. + (rs6000_adjust_cost): Mark parameter `dep_insn' with ATTRIBUTE_UNUSED. + (rs6000_valid_decl_attribute_p): Likewise for parameters `decl', + `attributes', `identifier' and `args'. + (rs6000_valid_type_attribute_p): Likewise for parameter `attributes'. + (rs6000_comp_type_attributes): Likewise for parameters `type1' and + `type2'. + (rs6000_set_default_type_attributes): Likewise for parameter `type'. + + * rs6000.h (RTX_COSTS): Add parentheses around & operation. + (toc_section, private_data_section, trap_comparison_operator): Add + prototypes. + + * dbxout.h (dbxout_parms, dbxout_reg_parms, dbxout_syms): Add + prototypes. + + * xcoffout.c: Include toplev.h, outout.h and dbxout.h. + + * xcoffout.h (stab_to_sclass, xcoffout_begin_function, + xcoffout_begin_block, xcoffout_end_epilogue, + xcoffout_end_function, xcoffout_end_block, + xcoff_output_standard_types, xcoffout_declare_function, + xcoffout_source_line): Add prototypes. + +Thu Jun 25 09:54:55 1998 Nick Clifton + + * config/arm/arm.h (REG_ALLOC_ORDER): Add ARG_POINTER_REGNUM, + noticed by grahams@rcp.co.uk. + +Thu Jun 25 11:12:29 1998 Dave Brolley + + * gcc.c (default_compilers): Use new | syntax to eliminate + string concatenation. + +Thu Jun 25 01:00:48 1998 Richard Henderson + + * alpha.c (alpha_function_name): Delete. + (alpha_ra_ever_killed): Notice current_function_is_thunk. + (alpha_sa_mask, alpha_sa_size, alpha_does_function_need_gp): Likewise. + (alpha_start_function): Reorg from output_prologue. + (alpha_end_function): Reorg from output_epilogue. + * alpha.h (ASM_DECLARE_FUNCTION_NAME): Call alpha_start_function. + (ASM_DECLARE_FUNCTION_SIZE): New. + (FUNCTION_PROLOGUE, FUNCTION_EPILOGUE): Delete. + (PROFILE_BEFORE_PROLOGUE): Set. + (ASM_OUTPUT_MI_THUNK): Remove bits now output by start/end_function. + * alpha/win-nt.h (ASM_OUTPUT_MI_THUNK): Likewise. + +Thu Jun 25 01:18:47 1998 John Wehle (john@feith.com) + + * i386/freebsd-elf.h (ASM_OUTPUT_MAX_SKIP_ALIGN): Define. + +1998-06-25 Herman A.J. ten Brugge + + * expr.c (expand_assignment): Rework address calculation for structure + field members to expose more invariant computations to the loop + optimizer. + (expand_expr): Likewise. + +Wed Jun 24 22:44:22 1998 Jeffrey A Law (law@cygnus.com) + + * local-alloc.c (block_alloc): Do not try to avoid false dependencies + when SMALL_REGISTER_CLASSES is nonzero. + +Wed Jun 24 17:55:15 1998 Klaus Kaempf + + * alpha.md (call_vms, call_value_vms): Strip leading * from symbol. + +Wed Jun 24 16:27:23 1998 John Carr + + * expr.c (get_memory_rtx): New function. + (expand_builtin): Call get_memory_rtx for MEM arguments to builtin + string functions. + + * expmed.c (init_expmed): Initialize all elements of *_cost arrays. + + * optabs.c: Use gen_rtx_FOO (...) instead of gen_rtx (FOO, ...). + * expr.c: Likewise. + * explow.c: Likewise. + * combine.c: Likewise. + * reload1.c: Likewise. + * gcse.c: Likewise. + +Wed Jun 24 15:13:01 1998 Dave Brolley + + * README.gnat: Add patch for new lang_decode_options interface. + +Wed Jun 24 09:14:04 EDT 1998 Andrew MacLeod + + * except.c (start_catch_handler): Do nothing if EH is not on. + +1998-06-24 Manfred Hollstein + + * configure.in (gxx_include_dir): Initialize default value depending on + new flag --enable-version-specific-runtime-libs; remove superfluous + default initialization afterwards. + * configure: Regenerate. + +Wed Jun 24 01:32:12 1998 David S. Miller + + * toplev.c (rest_of_compilation): Revert May 15 change. + +Tue Jun 23 21:27:27 1998 Ken Raeburn + + * reload.c (find_reloads): Fix check for failure to match any + alternative, to account for Mar 26 change in initial "best" cost. + +Tue Jun 23 16:44:21 1998 Dave Brolley + + * cpplib.c (do_line): Typo broke #line directive. + (cpp_message_from_errno): New function. + (cpp_error_from_errno): Call cpp_message_from_errno. + * cpplib.h (cpp_message_from_errno): New function. + +Tue Jun 23 13:38:18 EDT 1998 Andrew MacLeod + + * libgcc2.c (__get_eh_table_version, __get_eh_table_language): New + functions to return exception descriptor information. + (find_exception_handler): Pass match_info field to runtime matcher, + not a descriptor table entry. + +Tue Jun 23 09:30:58 1998 Dave Love + + * cpp.texi, gcc.texi: Add @dircategory, @direntry meant to + accompany previous Makefile.in (install-info) change. + +Tue Jun 23 10:06:07 EDT 1998 Andrew MacLeod + + * eh-common.h (struct __eh_info): Remove coerced value field. + * libgcc2.c (find_exception_handler): Don't set coerced_value field. + * except.c (get_dynamic_handler_chain, get_dynamic_cleanup_chain): Use + POINTER_SIZE instead of Pmode. + (expand_start_all_catch): Call start_catch_handler() if we are not + using new style exceptions. + +Tue Jun 23 06:45:00 1998 Catherine Moore + + * varasm.c (assemble_variable): Remove reference to warn_bss_align. + +Mon Jun 22 23:57:31 1998 David S. Miller + + * config/sparc/sparc.md (zero_extendhidi2, extendhisi2, + extendqihi2, extendqisi2, extendqidi2, extendhidi2, adddi3, + subdi3, negdi2, call, call_value, untyped_return, nonlocal_goto, + splits and peepholes): Change remaining generic gen_rtx calls to + specific genrtl ones. + * config/sparc/sparc.c: Likewise. + +Mon Jun 22 22:21:46 1998 Richard Henderson + + * gcc.c (handle_braces): Recognize | between options as an or. + +Mon Jun 22 23:13:47 1998 John Wehle (john@feith.com) + + * i386/freebsd-elf.h (JUMP_TABLES_IN_TEXT_SECTION): Define as flag_pic. + * i386/sysv4.h (JUMP_TABLES_IN_TEXT_SECTION): Define as flag_pic. + + * i386.md (exception_receiver): Define. + +Mon Jun 22 12:01:48 1998 Jim Wilson + + * Makefile.in (PROTOIZE_INSTALL_NAME, UNPROTOIZE_INSTALL_NAME, + PROTOIZE_CROSS_NAME, UNPROTOIZE_CROSS_NAME): New variables. + (install-common): Use them. + + * gcse.c (add_label_notes): New function. + (pre_insert_insn): Call it. + * unroll.c (unroll_loop): Look for insns with a REG_LABEL note, and + pass the label to set_label_in_map. + +Mon Jun 22 19:01:14 1998 Dave Love + + * Makefile.in (install-info): Fix typpo in previous change. + +Mon Jun 22 11:10:00 1998 Catherine Moore + + * varasm.c (assemble_variable): Emit alignment warning. + +Mon Jun 22 08:18:46 1998 Kaveh R. Ghazi + + * Makefile.in (varasm.o): Depend on sdbout.h. + (sdbout.o): Depend on toplev.h. + + * collect2.c (scan_prog_file): Cast fprintf argument to `long' and + use %ld specifier. + + * final.c (shorten_branches): Cast first arg of `bzero' to char *. + + * genextract.c (main): When creating insn-extract.c, mark variable + `i' with ATTRIBUTE_UNUSED. + + * genpeep.c (main): When creating insn-peep.c, mark variables + `insn', `x' and `pat' with ATTRIBUTE_UNUSED. + + * objc/init.c (__objc_tree_print): Wrap function definition in + macro `DEBUG'. + + * objc/objc-act.c (encode_array): Cast sprintf argument to `long' + and use %ld specifier. + (adorn_decl): Likewise, twice. + + * reload1.c (reload_cse_regs): Cast first arg of `bzero' to char *. + + * sdbout.c: Include output.h and toplev.h. + (PUT_SDB_INT_VAL): Use HOST_WIDE_INT_PRINT_DEV to print argument + `a'. Cast `a' to HOST_WIDE_INT to force it to always be so. + (PUT_SDB_SIZE): Likewise. + + * sdbout.h (sdbout_mark_begin_function): Add prototype. + + * stmt.c (check_for_full_enumeration_handling): Cast argument of + `warning' to long and use %ld specifier. + + * toplev.c (main): Likewise for `fprintf'. + + * toplev.h (output_file_directive): Add prototype. + + * unroll.c (unroll_loop): Use HOST_WIDE_INT_PRINT_DEC specifier in + call to `fprintf'. + (precondition_loop_p): Likewise. + + * varasm.c Include sdbout.h. + (assemble_static_space): Move sometimes-unused variable `rounded' + into the scope in which it is used. + + * mips.c (gpr_mode): Don't say `static' twice. + + * cpplib.c (cpp_handle_option): Don't pass unneeded NULL to cpp_fatal. + + * objc/objc-act.c (init_selector): Hide prototype and definition. + + * optabs.c (gen_cond_trap): Remove unused variable `icode'. + + * regmove.c (copy_src_to_dest): Likewise for `i'. + + * mips-tfile.c (add_local_symbol): Cast width format specifier to int. + (add_ext_symbol): Likewise. + (add_file): Likewise. + (parse_def): Likewise. + (write_varray): Use HOST_PTR_PRINTF to print a pointer. Fix + remaining format specifiers and arguments. + (write_object): Likewise, several times. + (read_seek): Likewise. + (out_of_bounds): Likewise. + (allocate_cluster): Likewise. + (xmalloc): Likewise. + (xcalloc): Likewise. + (xrealloc): Likewise. + (xfree): Likewise. + + * mips-tdump.c (print_symbol): Likewise. + +Sun Jun 21 17:05:34 1998 Dave Love + + * Makefile.in (install-info): Use install-info program if + available, per GNU standard. + +Sun Jun 21 18:56:44 1998 Jeffrey A Law (law@cygnus.com) + + * invoke.texi: Document -mrelax for the mn10300 and mn10200. + + * basic-block.h (init_regset_vector): Delete declaration. + * flow.c (init_regset_vector): Make it static and add a prototype. + + * bitmap.h (debug_bitmap): Declare. + + * haifa-sched.c (debug_ready_list): Make static. + + * toplev.h (fancy_abort): Declare. + +Sun Jun 21 18:30:13 1998 H.J. Lu (hjl@gnu.org) + + * basic-block.h (init_regset_vector): New declaration. + + * Makefile.in (sdbout.o): Add insn-codes.h to dependency. + + * global.c: Include machmode.h amd move hard-reg-set.h before + rtl.h. + + * haifa-sched.c (insn_issue_delay, birthing_insn_p, + adjust_priority, print_insn_chaino): New declaration. + (schedule_insns): Remove declaration. + (init_target_units, get_visual_tbl_length, + init_block_visualization): Add prototype. + + * integrate.c (pushdecl, poplevel): Remove declaration. + + * rtl.h (expand_expr): Remove declaration. + + * loop.c (oballoc): Remove declaration. + (replace_call_address): Add prototype. + +Sun Jun 21 01:08:17 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sun Jun 21 01:16:38 1998 John Wehle (john@feith.com) + + * i386.c (output_fp_conditional_move): Don't bother handling + (cc_prev_status.flags && CC_NO_OVERFLOW) since the INSN patterns + prevent this from happening. + + * i386.md (nonlocal_goto_receiver): Delete. + +Sun Jun 21 00:42:20 1998 H.J. Lu (hjl@gnu.org) + + * Makefile.in (crtbeginS.o, crtendS.o): Add -fno-exceptions and + -DCRTSTUFFS_O. + (INSTALL): cd $(srcdir) before make. + + * flow.c (allocate_for_life_analysis, init_regset_vector): + Remove declaration. + + * function.h (get_first_block_beg): New declaration. + + * gbl-ctors.h (__do_global_dtors): Add prototype. + + * gcov-io.h (__fetch_long): New declaration. + (__store_long): Likewise. + (__read_long): Likewise. + (__write_long): Likewise. + + * gcov.c (print_usage): New declaration. + + * Makefile.in (c-iterate.o): Depend on insn-codes.h too. + +Sat Jun 20 00:36:16 1998 Jeffrey A Law (law@cygnus.com) + + * calls.c (expand_call): Initialize "src" and "dest". + * stmt.c (expand_return): Likewise. + * expmed.c (extract_split_bit_field): Similarly for "result" + * gcse.c (compute_hash_table): Mark first arg as unused. + * jump.c (jump_optimize): Initialize reversep. + * tree.c (make_node): Initialize length. + + * c-common.c (check_format_info): Initialize length_char and + fci to keep -Wall quiet. + + * except.c (jumpif_rtx): Put declaration and definition + inside a suitable #ifdef. + (jumpifnot_rtx): Delete dead function. + + * i386.h (output_int_conditional_move): Declare. + (output_fp_conditional_move): Likewise. + (ix86_can_use_return_insn_p): Likewise. + + * optabs.c (init_traps): Put prototype inside a suitable #ifdef. + +Sat Jun 20 00:27:40 1998 Graham + + * alias.c: Include toplev.h + * caller-save.c: Include toplev.h + * combine.c: Include toplev.h + * flow.c Include toplev.h + * global.c: Include toplev.h + * jump.c: Include toplev.h + * local-alloc.c: Include toplev.h + * loop.c: Include toplev.h + * regmove.c: Include toplev.h + * stupid.c: Include toplev.h + * unroll.c: Include toplev.h + * Makefile.in: Add toplev.h dependencies. + +Fri Jun 19 22:40:25 1998 Jason Merrill + + * regmove.c (copy_src_to_dest): Add decl for loop_depth. + + * svr4.h (ASM_GENERATE_INTERNAL_LABEL): Cast arg to unsigned. + * dwarf2out.c (ASM_OUTPUT_DWARF_DATA1): Likewise. + Add parens to various macros. + +Fri Jun 19 23:22:42 1998 Bruno Haible + + * c-typeck.c (pop_init_level): Warn about implicit zero initialization + of struct members. + +Fri Jun 19 23:06:33 1998 Jason Merrill + + * varasm.c (assemble_start_function): Add weak_global_object_name. + * tree.c (get_file_function_name): Use it. + +Fri Jun 19 22:55:14 1998 Jeffrey A Law (law@cygnus.com) + + * except.c (jumpif_rtx): Make static and add prototype. + (jumpifnot_rtx): Likewise. + + * README.gnat: Add a build patch from Fred Fish. + + * c-lang.c (GNU_xref_begin, GNU_xref_end): Deleted. + + * Makefile.in (c-iterate.o): Depend on expr.h. + +Fri Jun 19 20:38:34 1998 H.J. Lu (hjl@gnu.org) + + * except.h (emit_unwinder, end_eh_unwinder): Removed. + + * dwarfout.c (getpwd): Add prototype. + (is_pseudo_reg, type_main_variant, is_tagged_type, + is_redundant_typedef): New declaration. + (output_decl): Add prototype for FUNC. + (type_main_variant): Make it static. + (is_tagged_type): Likewise. + (is_redundant_typedef): Likewise. + + * expr.c (do_jump_by_parts_greater_rtx): Removed. + (truthvalue_conversion): Likewise. + + * c-iterate.c: Include "expr.h". + (expand_expr): Use proper values when calling the function. + + * explow.c (emit_stack_save): Add prototype for FCN. + (emit_stack_restore): Likewise. + + * dwarf2out.c (getpwd): Add prototype. + + * dwarf2out.h (debug_dwarf, debug_dwarf_die): New declarations. + + * c-typeck.c (c_expand_asm_operands): Use proper values when calling + expand_expr. + + * c-lex.c (yyprint): Add prototype. + (check_newline, build_objc_string): Remove declaration. + + * c-tree.h (comptypes_record_hook): Removed. + (finish_incomplete_decl): New prototype. + + * alias.c (find_base_value): Add prototype. + (true_dependence): Add prototype for function argument. + + * c-aux-info.c (xmalloc): Remove declaration. + +Fri Jun 19 20:23:05 1998 Robert Lipe + + * i386.c: Include system.h. Remove redundant includes. + (optimization_options): Mark param 'size' with ATTRIBUTE_UNUSED. + (i386_cc_probably_useless_p): Likewise for 'decl', 'attributes', + 'identifier', 'args'. + (i386_valid_type_attribute_p): Likewise for 'attributes'. + (i386_comp_type_attribute_p): Likewise for 'type1', 'type2'. + (function_arg_partial_nregs): Likewise for 'cum', 'mode', 'type', + and 'named'. + (symbolic_operand): Likewise for 'mode'. + (call_insn_operand): Likewise. + (expander_call_insn_operand): Likewise. + (ix86_logical_operator): Likewise. + (ix86_binary_operator_ok): Likewise. + (emit_pic_move): Likewise. + (VOIDmode_compare_op): Likewise. + (is_mul): Likewise. + (str_immediate_operand): Likewise. + (ix86_uary_operator_ok): Likewise for 'code', 'mode', and 'operands'.yy + (asm_output_function_prefix): Likewise for 'name'. + (function_prologue): Likewise for 'file', and 'size'. + (function_epilogue): Likewise. + +1998-06-19 Jim Wilson + + * loop.h (struct induction): Clarify comment for unrolled field. + * unroll.c (find_splittable_givs): Move set of unrolled field + after address validity check. + +Fri Jun 19 18:38:04 1998 Michael Meissner + + * config/fp-bit.c (INLINE): Only define if not already defined. + +1998-06-19 Manfred Hollstein + + * Makefile.in (installdirs): Loop over directories in $(libsubdir) + creating probably missing ones, instead of single if statements. + +Fri Jun 19 10:43:52 1998 Andreas Schwab + + * c-common.c (truthvalue_conversion): Protect side effects in the + expression when splitting a complex value. + * fold-const.c (fold): Likewise. + +Fri Jun 19 02:31:16 1998 Klaus Kaempf (kkaempf@progis.de) + + * cccp.c (hack_vms_include_specification): rewrite to handle + '#include ' correctly. + +Fri Jun 19 02:24:11 1998 H.J. Lu (hjl@gnu.org) + + * config/i386/linux.h (ASM_OUTPUT_MAX_SKIP_ALIGN): Defined. + +Fri Jun 19 02:10:10 1998 John Wehle (john@feith.com) + + * i386.c (notice_update_cc): Integer conditional moves don't + affect cc0. + + * i386.md (movsfcc, movdfcc, movxfcc): Use emit_store_flag + to support LT, LE, GE, and GT signed integer comparisons. + (movsfcc+1, movsfcc+2, movdfcc+1, movdfcc+2, + movxfcc+1, movxfcc+2): Pattern doesn't match if the comparison + is LT, LE, GE, or GT. + (movdicc): Remove code resulting from an earlier patch which + didn't apply correctly. + +Fri Jun 19 02:00:19 1998 Richard Kenner + + * reload1.c (reload_cse_regno_equal_p): If -ffloat-store, don't + consider a MEM in FP mode as equal. + +Fri Jun 19 01:02:17 1998 Jeffrey A Law (law@cygnus.com) + + * c-decl.c (duplicate_decls): Avoid setting TREE_ASM_WRITTEN for + duplicate declarations of a function. + +Fri Jun 19 00:33:33 1998 H.J. Lu (hjl@gnu.org) + + * config/float-i386.h: New. + + * configure.in (i[34567]86-*-linux-*): Set float_format to i386. + +Thu Jun 18 20:11:00 1998 Jim Wilson + + * sched.c (schedule_insns): Use xmalloc not alloca for max_uid + indexed arrays. Call free at the end of the function for them. + * haifa-sched.c (schedule_insns): Likewise. + +Thu Jun 18 18:16:01 1998 Jim Wilson + + * dwarf2out.c (size_of_string): Do count backslashes. + +Thu Jun 18 11:43:54 1998 Nick Clifton + + * config/arm/thumb.h (GO_IF_LEGITIMATE_ADDRESS): Disallow REG+REG + addressing when one register is the frame pointer or stack + pointer. Disallow REG+CONST addressing in HI mode. + +Thu Jun 18 17:30:39 1998 J"orn Rennecke + + * reload.c (find_reloads): Don't narrow scope of RELOAD_OTHER to + RELOAD_FOR_INSN. + +Thu Jun 18 09:36:50 1998 Kaveh R. Ghazi + + * Makefile.in (c-lang.o): Depend on output.h. + + * c-lang.c: Include output.h. + + * sparc.c (sparc_builtin_saveregs): Remove unused variable `fntype'. + + * except.c (expand_builtin_eh_stub): Likewise for variable `jump_to'. + + * genrecog.c (write_subroutine): When writing insn-recog.c, mark + variables `insn', `pnum_clobbers', `x[0 .. max_depth]' and `tem' + with ATTRIBUTE_UNUSED. + + * regmove.c (copy_src_to_dest): Make function static to match its + prototype. + + * reload1.c Include hard-reg-set.h before rtl.h to get macro + HARD_CONST. Include machmode.h before hard-reg-set.h. + + * rtl.h: Prototype `retry_global_alloc' and wrap with macro + HARD_CONST to protect usage of typedef HARD_REG_SET. + + * tree.c: Prototype `_obstack_allocated_p'. + + * varasm.c: Wrap prototype of `asm_output_aligned_bss' in macro + BSS_SECTION_ASM_OP. + +Thu Jun 18 09:20:47 1998 Kaveh R. Ghazi + + * pa.c: Include system.h and toplev.h. Remove redundant code. + (call_operand_address): Mark parameter `mode' with ATTRIBUTE_UNUSED. + (symbolic_operand): Likewise. + (symbolic_memory_operand): Likewise. + (pic_label_operand): Likewise. + (fp_reg_operand): Likewise. + (pre_cint_operand): Likewise. + (post_cint_operand): Likewise. + (ireg_or_int5_operand): Likewise. + (int5_operand): Likewise. + (uint5_operand): Likewise. + (int11_operand): Likewise. + (uint32_operand): Likewise. + (ior_operand): Likewise. + (lhs_lshift_cint_operand): Likewise. + (pc_or_label_operand): Likewise. + (legitimize_pic_address): Likewise. + (hppa_legitimize_address): Likewise for parameter `old'. + (output_block_move): Likewise for parameter `size_is_constant'. + (output_function_prologue): Likewise for parameter `size'. + (output_function_epilogue): Likewise. + (return_addr_rtx): Likewise for parameter `count'. + (output_mul_insn): Likewise for parameter `unsignedp'. + (hppa_builtin_saveregs): Likewise for parameter `arglist'. + (output_bb): Likewise for parameter `operands'. + (output_bvb): Likewise. + (function_label_operand): Likewise for parameter `mode'. + (plus_xor_ior_operator): Likewise. + (shadd_operand): Likewise. + (non_hard_reg_operand): Likewise. + (eq_neq_comparison_operator): Likewise. + (movb_comparison_operator): Likewise. + (pa_combine_instructions): Likewise for parameter `insns'. + + * pa.h: Add prototypes for functions `output_deferred_plabels', + `override_options', `output_ascii', `output_function_prologue', + `output_function_epilogue', `print_operand', + `symbolic_expression_p', `reloc_needed', `compute_frame_size', + `hppa_address_cost', `and_mask_p', `symbolic_memory_operand', + `pa_adjust_cost', `pa_adjust_insn_length' and + `secondary_reload_class'. + +Wed Jun 17 22:28:48 1998 Jason Merrill + + * configure.in: Don't turn on collect2 unconditionally. + +Wed Jun 17 20:20:48 1998 Mark Mitchell + + * cse.c (cse_basic_block): Don't include NOTE insns in the count + that is used to decide whether or not it is time to erase the + equivalence table. + +Wed Jun 17 18:30:43 1998 Franz Sirl + + * rs6000/linux.h (JUMP_TABLES_IN_TEXT_SECTION): Define to zero. + +Wed Jun 17 19:05:03 1998 John Carr + + * haifa-sched.c (haifa_classify_insn): TRAP_IF is risky. + (sched_analyze_2): Allow scheduling TRAP_IF. + + * reorg.c (mark_referenced_resources): Examine operands of TRAP_IF. + + * rtl.h (TRAP_CODE): New macro. + + * rtl.def (TRAP_IF): Change second operand type to rtx. + + * optabs.c (gen_cond_trap): New function. + (init_traps): New function. + (init_optabs): Call init_traps. + * expr.h: Declare gen_cond_trap. + + * jump.c (jump_optimize): Optimize jumps to and around traps. + + * sparc.md: Define trap instructions. + + * rs6000.md: Define trap instructions. + * rs6000.c (print_operand): New code 'V' for trap condition. + (trap_comparison_operator): New function. + + * m88k.md: Update use of TRAP_IF. + + * tree.h (enum built_in_function): New function code BUILT_IN_TRAP. + * c-decl.c (init_decl_processing): New builtin __builtin_trap. + * expr.c (expand_builtin): Handle BUILT_IN_TRAP. + + * expr.c (expand_builtin): Error if __builtin_longjmp second argument + is not 1. + +Wed Jun 17 15:20:00 PDT 1998 Catherine Moore + + * reload1.c (spill_hard_reg): Check mode of register when + spilling from scratch_list. + +Wed Jun 17 16:25:38 EDT 1998 Andrew MacLeod (amacleod@cygnus.com) + + * except.c (add_new_handler): fix bug in finding last region handler. + * libgcc2.c (find_exception_handler): Pass exception table pointer + to runtime type matcher, not the match info field. + +Wed Jun 17 15:57:48 EDT 1998 Andrew MacLeod (amacleod@cygnus.com) + + * eh-common.h (struct eh_context): Add comment for hidden use of + field dynamic_handler_chain. + * except.c (get_dynamic_handler_chain): Comment on, and use the + correct offset of the dynamic_handler_chain field. + +1998-06-17 12:46:56 1998 Jim Wilson + + * mips/iris6.h (LINK_SPEC): Add -woff 131. + +1998-06-17 Jason Merrill + + * dwarf2out.c: Disable EH_FRAME_SECTION if we don't have .init. + + * configure.in: Don't disable collect2 when we have GNU ld. + +Wed Jun 17 08:38:13 1998 Jeffrey A Law (law@cygnus.com) + + * fold-const.c (make_range): Do not widen the type of the expression. + + * expr.c (check_max_integer_computation_mode): New function. + (expand_expr): Avoid integer computations in modes wider than + MAX_INTEGER_COMPUTATION_MODE. + * fold-const.c (fold): Likewise. + * tree.h (check_max_integer_computation_mode): Declare. + * tm.texi (MAX_INTEGER_COMPUTATION_MODE): Document it. + + * configure.in (nm): Make a link to "nm" in the build tree too. + + * mn10300.md (andsi3): Fix typo. + +Tue Jun 16 22:58:40 1998 Richard Henderson + + * reload1.c (reload_cse_regs): Call bzero instead of looping. + +Tue Jun 16 18:30:35 1998 Jim Wilson + + * dwarf2out.c (stripattributes): Prepend '*' to the section name. + +Tue Jun 16 16:49:26 1998 Richard Henderson + + * alpha.c (alpha_expand_prologue, alpha_expand_epilogue): New fns. + (output_prologue, output_epilogue): Merge VMS and OSF versions; + Remove anything related to the actual code generation. + (output_end_prologue): New function. + (alpha_sa_mask, alpha_sa_size): Merge VMS and OSF versions. + (alpha_does_function_need_gp): Return false for VMS. + (alpha_function_needs_gp): Make static. + (add_long_const): Delete. + (summarize_insn): Don't assume a SUBREG is of a REG. + Prototype all static functions. Rename VMS-specific global + variables vms_*. + * alpha.h (TARGET_CAN_FAULT_IN_PROLOGUE): Default to 0. + (FUNCTION_BOUNDARY): Align to cache line. + (LOOP_ALIGN, ALIGN_LABEL_AFTER_BARRIER): Align to octaword. + (FUNCTION_END_PROLOGUE): New macro. + * alpha.md (attribute length): New. Mark all insns. + (return_internal, prologue_stack_probe_loop) New patterns. + (prologue, init_fp, epilogue): New patterns. + Disable peepholes. + * linux.h (TARGET_CAN_FAULT_IN_PROLOGUE): Define. + +Tue Jun 16 17:36:35 1998 Dave Brolley + + * toplev.c (lang_options): Add -trigraphs option for cpplib. + +Tue Jun 16 23:33:24 1998 J"orn Rennecke + + * reload1.c (reload_reg_free_before_p): RELOAD_FOR_OUTADDR_ADDRESS + is earlier than RELOAD_FOR_OUTPUT_ADDRESS; RELOAD_FOR_INPADDR_ADDRESS + is earlier than RELOAD_FOR_INPUT_ADDRESS. + +Tue Jun 16 13:15:16 1998 Jim Wilson + + * libgcc1-test.c (memcpy): Define. + +Tue Jun 16 13:44:02 1998 Michael Meissner + + * genattrtab.c (struct attr_desc): Change int flags to bit + fields. Add bit fields for this being function_units_used + or *_blockage_range attributes. + (write_unit_name): New function to print a function unit name + given unit #. + (expand_units): Indicate whether this is function_units_used or + *_blockage_range attributes. + (write_toplevel_expr): Print function_units_used and + *_blockage_range attributes in a more friendly fashion. + (make_internal_attr): Indicate whether this attribute is either + function_units_used or *_blockage_range. + +Mon Jun 15 17:06:43 1998 Michael Meissner + Jim Wilson + + * regmove.c (copy_src_to_dest): Do not copy src to dest if either + the source or destination is special. + +Mon Jun 15 13:20:33 1998 Jim Wilson + + * c-decl.c (shadow_tag_warned): Use specs not declspecs in for loop. + +Mon Jun 15 07:16:29 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sat Jun 13 13:10:40 1998 Krister Walfridsson + + * config/sparc/netbsd.h (DEFAULT_PCC_STRUCT_RETURN): Undefine before + redefining it. + +Fri Jun 12 18:06:45 1998 Doug Evans + + * m32r/m32r.h (STARTFILE_SPEC): Delete crtsysc.o. + (ENDFILE_SPEC): Add -lgloss. + +Fri Jun 12 14:57:59 1998 Kaveh R. Ghazi + + * mips.c (small_int): Mark parameter `mode' with ATTRIBUTE_UNUSED. + (large_int): Likewise. + (pc_or_label_operand): Likewise. + (call_insn_operand): Likewise. + (consttable_operand): Likewise. + (m16_uimm3_b): Likewise. + (m16_simm4_1): Likewise. + (m16_nsimm4_1): Likewise. + (m16_simm5_1): Likewise. + (m16_nsimm5_1): Likewise. + (m16_uimm5_4): Likewise. + (m16_nuimm5_4): Likewise. + (m16_simm8_1): Likewise. + (m16_nsimm8_1): Likewise. + (m16_uimm8_1): Likewise. + (m16_nuimm8_1): Likewise. + (m16_uimm8_m1_1): Likewise. + (m16_uimm8_4): Likewise. + (m16_nuimm8_4): Likewise. + (m16_simm8_8): Likewise. + (m16_nsimm8_8): Likewise. + (m16_usym8_4): Likewise. + (m16_usym5_4): Likewise. + (mips_move_1word): Change type of variable `i' from int to size_t. + (mips_move_2words): Likewise. + (output_block_move): Mark parameter `libname' with ATTRIBUTE_UNUSED. + (function_arg_advance): Use HOST_PTR_PRINTF to print an address. + (function_arg): Likewise. + (function_arg_partial_nregs): Mark parameter `named' with + ATTRIBUTE_UNUSED. + (override_options): Use ISDIGIT instead of isdigit. + (mips_output_external): Mark parameter `file' with ATTRIBUTE_UNUSED. + (final_prescan_insn): Likewise for parameters `opvec' and `noperands'. + (save_restore_insns): Cast HOST_WIDE_INT arguments passed to + function `fatal' to long before printing. Use + HOST_WIDE_INT_PRINT_DEC in fprintf. Both changes done several + times in this function. + (function_prologue): Mark parameter `size' with ATTRIBUTE_UNUSED. + (function_epilogue): Likewise for parameters `file' and `size'. + Print an int with "%d" not "%ld". + (mips_select_rtx_section): Mark parameter `x' with ATTRIBUTE_UNUSED. + (mips_function_value): Likewise for parameter `func'. + (function_arg_pass_by_reference): Likewise for parameters `cum' + and `named'. + (extend_operator): Likewise for parameter `mode' + (highpart_shift_operator): Likewise. + + * mips.md (mul_acc_si): Remove unused variable `macc'. + +Fri Jun 12 09:33:44 1998 Richard Henderson + + * fold-const.c (fold): Revert last change. It breaks constant + expressions somehow. + +Fri Jun 12 10:23:36 1998 Andreas Schwab + + * expr.c (do_jump, case EQ_EXPR, NE_EXPR): When comparing complex + prevent operands from being evaluated twice. + +Fri Jun 12 00:50:27 1998 Sergey Okhapkin + + * toplev.c (lang_options): Add -remap as a preprocessor option. + +Fri Jun 12 00:30:32 1998 John Wehle (john@feith.com) + + * i386.md (cmpsi_1, cmphi_1, cmpqi_1): Remove code + which set CC_REVERSED since reload should ensure that + the operands are already the correct type. + +Thu Jun 11 17:14:15 1998 Jim Wilson + + * except.c (expand_builtin_eh_stub): Call emit_move_insn rather than + calling gen_rtx_SET. + +Thu Jun 11 18:45:49 1998 David Edelsohn + + * config/rs6000/x-aix43 (AR): Delete. + (AR_FOR_TARGET_FLAGS): Add -X32_64 here. + +Thu Jun 11 16:19:17 1998 David W. Schuler + + * config/i386/aix386ng.h (CPP_SPEC): Remove extraneous quote. + +Thu Jun 11 12:40:27 1998 Jim Wilson + + * mips.c (override_options): Replace word_mode with explicit + TARGET_64BIT check. + +Thu Jun 11 14:50:02 1998 Michael Meissner + + * regmove.c (regmove_optimize): If we can't replace the + destination in an insn that sets the source, generate an explicit + move of the source to the destination. + (copy_src_to_dest): New function. + (toplevel): Include basic-block.h + + * Makefile.in (regmove.o): Add basic-block.h dependencies. + +Thu Jun 11 10:30:09 1998 Dave Brolley + + * toplev.c (lang_options): Add missing options (nostdinc, idirafter). + +Wed Jun 10 23:39:32 1998 Mark Mitchell + + * rtl.h (rtx_def): Improve documentation. + (MEM_IN_STRUCT_P): Likewise. + +Wed Jun 10 23:23:17 1998 Graham + + * c-decl.c (start_decl): Correct test for -Wmain. + + * c-decl.c (grokdeclarator): Remove unused variable "last". + +Wed Jun 10 14:52:27 1998 Jim Wilson + + * expr.c (expand_builtin_setjmp): Store const1_rtx in target. + (expand_builtin_longjmp): Abort if value isn't const1_rtx. + Delete code storing value in static_chain_rtx. + (expand_builtin, case BUILT_IN_LONGJMP): Pass NULL_RTX for target + to second expand_expr call. + +Wed Jun 10 13:08:41 1998 Mark Mitchell + + * mips/mips.c: Remove -mabi=o32 and -mabi=n64. + +Wed Jun 10 13:41:23 1998 Dave Brolley + + * cppmain.c (fatal): New function. + * configure.in (cpp_main): New configuration variable. + * configure: Regenerated. + * Makefile.in (CCCP): Use a configuration variable to select basex + for cccp. + (cppmain$(exeext)): Add @extra_cpp_objs@. + +Wed Jun 10 13:07:02 1998 Dave Brolley + + * objc/objc-act.c: Add cpplib declarations. + (lang_decode_option): Initialize cpplib if necessary. + (lang_decode_option): New argc/argv interface. + * tree.h (lang_decode_option): New argc/argv interface. + * toplev.c (lang_options): Add cpp options. + (main): New interface for lang_decode_option. + * gcc.c (default_compilers): Don't call cpp for a cpplib-enabled C compiler + unless -E, -M or -MM is specified. + * cpplib.h (cpp_handle_option): New function. + * cpplib.c (cpp_handle_option): New function. + (cpp_handle_options): Now calls cpp_handle_option. + * c-tree.h (c_decode_option): New argc/argv interface. + * c-lex.c (init_parse): cpplib now initialized in c_decode_option. + * c-lang.c (lang_decode_option): New argc/argv interface. + * c-decl.c: Add cpplib declarations. + (c_decode_option): New argc/argv interface. + (c_decode_option): Call cpp_handle_option. + (c_decode_option): Now returns number of strings processed. + +Wed Jun 10 09:47:13 1998 Richard Earnshaw (rearnsha@arm.com) + + * unroll.c (verify_addresses): Use validate_replace_rtx to undo the + changes. Abort if the undo fails. + +1998-06-10 Vladimir N. Makarov + + * config/rs6000/rs6000.c (output_prolog): Change locations and + directions of saving and restoring arguments of main on the stack. + +Wed Jun 10 08:56:27 1998 John Carr + + * reload1.c (reload_cse_simplify_operands): Do not call gen_rtx_REG + for each alternative. Do not replace a CONST_INT with a REG unless + the reg is cheaper. + +Wed Jun 10 02:11:55 1998 Jeffrey A Law (law@cygnus.com) + + * decl.c (init_decl_processing): Fix typo. + + * mips.c (gpr_mode): New variable. + (override_options): Initialize gpr_mode. + (compute_frame_size): Use "gpr_mode" instead of "word_mode" to + determine size and offset of general purpose registers save slots. + (save_restore_insns, mips_expand_prologue): Similarly. + + * reload.c (find_reloads_toplev): Use gen_lowpart common to convert + between constant representations when we have (SUBREG (REG)) with + REG equivalent to a constant. + +Wed Jun 10 01:39:00 1998 Juha Sarlin + + * h8300.c (get_shift_alg): Add special cases for shifts of 8 and 24. + +Tue Jun 9 22:05:34 1998 Richard Henderson + + * fold-const.c (fold): Even with otherwise constant trees, look for + opportunities to combine integer constants. + +Wed Jun 3 23:41:24 EDT 1998 John Wehle (john@feith.com) + + * i386.c (notice_update_cc): Clear cc_status.value2 in the + case of UNSPEC 5 (bsf). + + * i386.md (movsfcc, movdfcc, movxfcc): The floating point + conditional move instructions don't support signed integer + comparisons. + +Tue Jun 9 14:31:19 1998 Nick Clifton + + * config/v850/t-v850 (TCFLAGS): Add assembler options to warn of + overlfows. + + * config/v850/lib1funcs.asm (__return_interrupt): Use 'addi + 16,sp,sp' ratehr than 'add 16,sp'. Patch courtesy of Biomedin + . + +Tue Jun 9 16:23:13 EDT 1998 Andrew MacLeod + + * except.c (expand_start_catch): Rename to start_catch_handler. + (expand_end_catch): Delete function. + (expand_end_all_catch): Remove catch status that expand_end_catch + use to do. + * except.h (expand_start_catch): Rename prototype. + (expand_end_catch): Delete prototype. + +Tue Jun 9 12:57:32 1998 Mark Mitchell + + * invoke.texi: Add documentation for -mips4 and -mabi=*. + +Tue Jun 9 12:12:34 1998 Klaus Kaempf (kkaempf@progis.de) + + * alpha/vms.h (EXTRA_SECTIONS): Add in_ctors and in_dtors. + (EXTRA_SECTION_FUNCTIONS): Add ctors_section and dtors_section. + (ASM_OUTPUT_CONSTRUCTOR, ASM_OUTPUT_DESTRUCTOR): Define. + +Tue Jun 9 12:10:27 1998 John Carr + + * haifa-sched.c (update_flow_info): Use UNITS_PER_WORD, not MOVE_MAX, + as the threshold to permit splitting memory operations. + +Tue Jun 9 12:36:16 1998 Jeffrey A Law (law@cygnus.com) + + * mips.c (gpr_mode): New variable. + (override_options): Initialize gpr_mode. + (compute_frame_size): Use "gpr_mode" instead of "word_mode" to + determine size and offset of general purpose registers save slots. + (save_restore_insns, mips_expand_prologue): Similarly. + + * Makefile.in (LIB2FUNCS_EH): Define. Just "_eh" for now. + (LIBGCC2_CFLAGS): Remove -fexceptions. + (LIB2FUNCS): Remove "_eh". + (libgcc2.a): Iterate over LIB2FUNCS_EH and build everything in + it with -fexceptions. + + * Makefile.in (local-alloc.o): Depend on insn-attr.h. + * local-alloc.c (block_alloc): Avoid creating false + dependencies for targets which use instruction scheduling. + +Tue Jun 9 02:40:49 1998 Richard Henderson + + * mips/elf.h (ASM_DECLARE_OBJECT_NAME): Define. + (ASM_FINISH_DECLARE_OBJECT): Define; + * mips/elf64.h: Likewise. + +Tue Jun 9 01:08:47 1998 Richard Henderson + + * toplev.c (flag_new_exceptions): Remove extraneous `extern'. + +Mon Jun 8 23:24:48 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Mon Jun 8 23:24:58 1998 David Edelsohn + + * rs6000.md (mulsidi3): Add !TARGET_POWERPC64 constraint. + (mulsidi3_ppc64): Delete. + +Mon Jun 8 20:57:40 1998 Kaveh R. Ghazi + + * Makefile.in (varasm.o): Depend on dbxout.h. + (cse.o): Depend on toplev.h and output.h. + (gcse.o): Depend on output.h. + + * mips.c: Include system.h and toplev.h and remove redundant code. + Include output.h after tree.h so all its prototypes get activated. + * mips.md (table_jump): Remove unused variable `dest'. + + * sparc.h: Add prototype for `v8plus_regcmp_op'. + + * crtstuff.c (fini_dummy, init_dummy): Mark function definitions + with __attribute__ ((__unused__)). + (__frame_dummy): Provide prototype before use, wrap it with + EH_FRAME_SECTION_ASM_OP. + + * cse.c: Move inclusion of above local headers. + Include toplev.h and output.h. + + * dbxout.h: Add prototype for `dbxout_begin_function'. + + * final.c (final_scan_insn): Wrap variable `max_skip' in macro + ASM_OUTPUT_MAX_SKIP_ALIGN. + + * gcse.c: Include system.h and output.h. + (dump_cuid_table, dump_rd_table, dump_cprop_data, dump_pre_data): + Make extern instead of static. + (compute_can_copy): Only declare variables `reg' and `insn' when + AVOID_CCMODE_COPIES is not defined. + (record_set_info): Mark parameter `setter' with ATTRIBUTE_UNUSED. + (hash_scan_clobber): Likewise for `x' and `insn'. + (hash_scan_call): Likewise. + (record_last_set_info): Likewise for `setter'. + (mark_call): Likewise for `pat'. + (pre_insert_insn): Wrap variable `note' in macro HAVE_cc0. + + * libgcc2.c (__bb_init_prg): Replace bzero with memset and fix the + length parameter so that it multiplies the number of elements by + the sizeof(element). + + * output.h: Add prototype for `weak_finish'. + + * recog.h: Likewise for `validate_replace_src'. + + * rtl.h: Likewise for `optimize_save_area_alloca', + `fix_sched_param', `purge_addressof', `gcse_main', + `regmove_optimize', `dbr_schedule', `branch_prob' and + `end_branch_prob'. + + * toplev.h: Likewise for `set_float_handler' and + `output_quoted_string'. + + * varasm.c: Include dbxout.h. + +Mon Jun 8 18:12:06 1998 Jim Wilson + + * mips.c (mips_secondary_reload_class): Use gp_reg_p instead of + GP_REG_P. Use gr_regs instead of GR_REGS. + +Mon Jun 8 16:54:12 1998 Ken Raeburn + Jeff Law + + * Revamped multiply support for MIPS chips. + * mips.c (extend_operator): New function. + (highpart_shift_operator): Likewise. + * mips.h: Declare new functions. + (PREDICATE_CODES): Add support for new predicates. + * mips.md (mulsi3 expander): Simplify. + (mulsi_mult3): Add another constraint alternative. Support + 3 operand multiply instructions as found on various mips + parts. + (mulsi3_r4650): Delete pattern, now handled by mulsi_mult3. + (mul_acc_si): New pattern and associated splitters. + (mulsidi3 expander): Rework to use mulsidi3_64bit and + mulsidi3_internal. + (umulsidi3): New expander. + (mulsidi3_internal): Accept either sign or zero extended + operands and generate code as appropriate appropriately. + (mulsidi3_64bit): Similarly. + (smulsi3_highpart): Turn into an expander and generate code + to match new patterns. + (umulsi3_highpart): Likewise. + (xmulsi3_highpart_internal): New pattern. + (maddi patterns): Delete. Replace with: + (mul_acc_di, mul-acc_64bit_di): New patterns. + +Mon Jun 8 14:16:15 EDT 1998 Andrew MacLeod + + * eh-common.h: Remove NEW_EH_MODEL compile time flag, and replace with + flag_new_exceptions runtime flag. + (struct old_exception_table): New struct which represents what + the exception table looks like without the new model. + (NEW_EH_RUNTIME): New value used as a tag in the exception table to + flag that this is a new style table. + * except.h: Remove compile time flag NEW_EH_MODEL. + (expand_builtin_eh_stub_old): New prototype. + * tree.h (enum built_in_function): Add BUILT_IN_EH_STUB_OLD. + * expr.c (expand_builtin): New builtin func BUILT_IN_EH_STUB_OLD. + * c-decl.c (init_decl_processing): Add new builtin function + __builtin_eh_stub_old. + * final.c (final_scan_insn): Replace compile time flag NEW_EH_MODEL. + * flags.h (flag_new_exceptions): New runtime flag. + * toplev.c (flag_new_exceptions): Initialize default to 0, + -fnew-exceptions sets to 1. + * except.c (output_exception_table_entry): Output New style exception + identifier into table, and replace compile time flag NEW_EH_MODEL + with runtime flag flag_new_exceptions. + (output_exception_table): Replace compile time flag NEW_EH_MODEL. + (expand_builtin_eh_stub_old): Duplicates original functionality of + expand_builtin_eh_stub. + (expand_builtin_eh_stub): Replace compile time flag NEW_EH_MODEL. + * libgcc2.c (find_exception_handler): Remove NEW_EH_MODEL #ifdefs. + (old_find_exception_handler): New func, same as find_exception_handler + except it works on the old style exception table. + (__throw): Replace NEW_EH_MODEL. Detect new model based on presence + of identifier in the exception table, and call appropriate routines. + +Mon Jun 8 01:21:13 1998 Jason Merrill + + * function.c: Define current_function_cannot_inline. + (push_function_context_to): Save it. + (pop_function_context_from): Restore it. + * function.h (struct function): Provide it a home. + * output.h: Declare it. + * integrate.c (function_cannot_inline_p): Check it. + +Mon Jun 8 10:43:15 1998 Richard Henderson + + * expr.c (force_operand): Detect PIC address loads before + splitting arithmetic. + +Mon Jun 8 09:22:38 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Mon Jun 8 02:55:56 1998 Graham + + * tree.c (tree_class_check): Add braces to eliminate ambigious + else warning. + (tree_check): Likewise. + +Mon Jun 8 02:49:23 1998 H.J. Lu (hjl@gnu.org) + + * reg-stack.c (subst_stack_regs_pat): Make sure the top of + stack is the destination for conditional move insn. + +Mon Jun 8 01:21:13 1998 Jason Merrill + + * tree.h (TREE_VEC_END): Cast unused value to void. + + * i386.c (print_operand): Use %lx for long operand. + +Mon Jun 8 00:04:07 1998 Richard Henderson + + * alpha.c (summarize_insn): Ignore rtl slot format 'i'. + +Sun Jun 7 14:15:45 1998 John Carr + + * sol2.h (INIT_SUBTARGET_OPTABS): Use Solaris libc float/long long + conversion functions. + +Sun Jun 7 14:02:58 1998 Richard Henderson + + * toplev.c (flag_exceptions): Default to 0. + (compile_file): Remove flag_exceptions == 2 hack. + (main): Call lang_init_options. + * tree.h: Declare it. + * c-lang.c: Implement it. + * objc/objc-act.c: Likewise. + +Sun Jun 7 12:27:30 1998 David Edelsohn + + * rs6000.md (restore_stack_block): Generate MEM and specify mode. + * rs6000.h (STACK_SAVEAREA_MODE): SAVE_FUNCTION is VOIDmode. + * rs6000.c (rs6000_output_load_toc_table): Use fputs. + (output_function_profiler): Use asm_fprintf and fputs. + +Sat Jun 6 12:17:12 1998 Kaveh R. Ghazi + + * gencheck.c: Remove redundant stdio.h include. Add a definition + of xmalloc for when we are forced to link with alloca.o. + + * reload1.c (reload_reg_free_for_value_p): Use `(unsigned)1' + instead of `1U'. + + * fold-const.c (constant_boolean_node): Make definition static to + match the prototype. + +Fri Jun 5 15:53:17 1998 Per Bothner + + * gcc.c (lang_specific_pre_link): New LANG_SPECIFIC_DRIVER function. + (lang_specific_extra_outfiles): New LANG_SPECIFIC_DRIVER variable. + (do_spec, input_filename, input_filename_length): Make public. + (main): Adjust outfiles allocation by lang_specific_extra_outfiles. + Call lang_specific_pre_link befor elinking. + +Fri Jun 5 12:29:28 1998 Jeffrey A Law (law@cygnus.com) + + * haifa-sched.c (rank_for_schedule): For "equally good insns", prefer + the insn which has the most insns dependent on it. + +Fri Jun 5 09:03:22 1998 John Carr + + * alias.c (find_base_value): Avoid reading past end of reg_base_value. + +Fri Jun 5 03:05:34 1998 Richard Henderson + + * alpha.md (insxh-1): New insxl pattern for combine. + +Fri Jun 5 01:12:15 1998 H.J. Lu (hjl@gnu.org) + + * i386/i386.c (output_fp_conditional_move): New function + to output floating point conditional move. + (output_int_conditional_move): New function to output integer + conditional move. + + * i386/i386.md (movsicci+5, movhicc+5, movdicc+5): Call + output_int_conditional_move () to output int conditional move. + (movsfcc+5, movdfcc+5, movxfcc+5): Call + output_fp_conditional_move () to output floating point + conditional move. + + * i386/i386.c (put_condition_code): In INT mode, check + cc_prev_status.flags & CC_NO_OVERFLOW for GE and LT. + +Thu Jun 4 16:09:51 1998 Dave Brolley + + * dbxout.c (dbxout_type): Output arrays of bits as if + they were bitstrings for Chill + +Thu Jun 4 14:35:27 1998 David Edelsohn + + * tree.c (get_inner_array_type): New function. + * tree.h (get_inner_array_type): Prototype. + * expr.h (STACK_SAVEAREA_MODE): New macro. + * expr.c (expand_builtin_setjmp): Initialize sa_mode using + STACK_SAVEAREA_MODE. + (expand_builtin_longjmp): Likewise. + * explow.c (emit_stack_save): Likewise. + (allocate_dynamic_stack_space): Use Pmode not insn_operand_mode. + + * rs6000/aix41.h (ASM_CPU_SPEC): Define relative to ASM_DEFAULT_SPEC. + (CPP_CPU_SPEC): Define relative to CPU_DEFAULT_SPEC. + * rs6000/aix43.h: New file. + * rs6000/t-aix43: New file. + * rs6000/x-aix41: New file. + * rs6000/x-aix43: New file. + * configure.in (rs6000-ibm-aix*): Use them. + * rs6000/powerpc.h: Delete. + * rs6000/sysv4.h: Move necessary powerpc.h definitions to here. + * rs6000/netware.h: and here. + * rs6000/win-nt.h: and here. + + * rs6000/rs6000.c (processor_target_table, 620): Do not affect + MASK_POWERPC64. + (rs6000_override_options): Ignore flag_pic for AIX. + (rs6000_immed_double_const): Delete. + (u_short_cint_operand): Don't assume 32-bit CONST_INT. + (reg_or_u_short_operand): Don't assume 32-bit CONST_INT. + (num_insns_constant): mask64_operand() is 2 insns. + (logical_operand): Don't assume 32-bit CONST_INT. + (non_logical_cint_operand): Don't assume 32-bit CONST_INT. + (easy_fp_constant): Any CONST_DOUBLE_HIGH is okay for 64-bit. + (mask_constant): HOST_WIDE_INT parameter. + (non_and_cint_operand): Delete. + (mask64_operand): New function. + (and64_operand): New function. + (function_arg_advance): DImode arguments do not need special + alignment when 64-bit. + (function_arg): Likewise. + (setup_incoming_varargs): Reverse reg_size assignment. + (print_operand): HOST_WIDE_INT second parameter. + (print_operand, 'B'): New case. + (print_operand, 'M'): Fix typo in lossage string. + (print_operandm 'S'): New case. + (rs6000_stack_info): Reverse reg_size assignment. Use total_raw_size + to compute AIX push_p. Use reg_size to compute {cr,lr}_save_offset. + (rs6000_output_load_toc_table): Reverse init_ptr assignment. Use + TARGET_64BIT not TARGET_POWERPC64. Convert fprintf to fputs. + Load GOT highpart, don't add it. Add lowpart with {cal|la}. + (rs6000_allocate_stack_space): Use {cal|la}. + (output_epilog): Use {cal|la} + (output_function_profiler): Add call glue to mcount call. + Load GOT highpart, don't add it. Add lowpart with {cal|la}. + + * rs6000/rs6000.h (TARGET_SWITCHES): Add powerpc64. + (STACK_BOUNDARY): Depend on TARGET_32BIT. + (ADJUST_FIELD_ALIGN): Calculate array alignment using innermost type. + (CONST_OK_FOR_LETTER_P): Don't assume 32-bit CONST_INT. + (EXTRA_CONSTRAINTS): Remove NT 'S' and 'T'. Replace 'S' with + 64-bit mask operand. + (RS6000_SAVE_TOC): Depend on TARGET_32BIT. + (STACK_SAVEAREA_MODE): New macro. + (LEGITIMATE_CONSTANT_P): DImode okay for 64bit. + (LEGITIMIZE_RELOAD_ADDRESS): New macro. + (RTX_COSTS, AND/IOR/XOR): Reflect current machine description. + (ASM_FILE_START): Emit 64-bit ABI directive. + (ASM_DECLARE_FUNCTION_NAME): Align CSECT on doubleword in 64-bit mode. + (ASM_OUTPUT_SPECIAL_POOL_ENTRY): DImode okay for 64-bit. + (PREDICATE_CODES): Add "and64_operand" and "mask64_operand". + Delete "non_and_cint_operand". "input_operand" includes CONST_DOUBLE. + + * rs6000/rs6000.md (iorsi3, xorsi3): Use HOST_WIDE_INT for mask. + Restore define_splits. + (floatsidf2, floatunssidf2): Remove !TARGET_POWERPC64 final constraint. + (floatsidf2_internal, floatunssidf2_internal2): Likewise. + Do not specify base register operand mode. + (floatsidf2_loadaddr): Do not specify base register operand mode. + (floatsidf2_store1, floatsidf2_store2): Operand 1 must be base + register; do not specify mode. Remove !TARGET_POWERPC64 final + constraint. + (floatsidf2_load): Do not specify base register operand mode. Remove + !TARGET_POWERPC64 final constraint. + (fix_truncdfsi2_internal, fix_truncdfsi2_{store,load}): Do not specify + base register operand mode. + (adddi3): Split large constants early. + (absdi3): Shift by 63, not 31. + (*mulsidi3_ppc64): New pattern. + (rotldi3): Add masking combiner patterns. + (anddi3): Add rldic{r,l} masking. Remove split of large constants + because PPC insns zero-extend. + (iordi3, xordi3): Split large constants early. + (movsi matcher): Remove S and T constraints. + (movsf const_double): create SImode constant from TARGET_DOUBLE. + (movdf_hardfloat32): Add default abort() case. + (movdf easy_fp_const): create DImode constant from TARGET_DOUBLE. + (movdi): Remove 64-bit constant generator. Try to convert + CONST_DOUBLE to CONST_INT. Handle TOC memory constants. + (movdi_32): Add default abort() case. + (movdi_64): Add numerous ways to split 64-bit constants. + Make catch-all define_split more optimal and never FAIL. + (movti_ppc64): Add default abort() case. + (allocate_stack): Remove operand modes. Use Pmode. + (restore_stack_block): Remove operand modes. Generate Pmode + temporary. + (save_stack_nonlocal, restore_stack_nonlocal): Generate Pmode + temporary. Save area is double Pmode. + (call_indirect_aix64, call_value_indirect_aix64): New patterns. + (call, call_value): Do not specify address operand mode. Choose + appropriate AIX ABI. + (*call_local64, *ret_call_local64): New patterns. + (*call_nonlocal_aix64, *ret_call_nonlocal_aix64): New patterns. + (*ret_call_nonlocal_aix32): Use call_value_indirect for REG. + (compare): Materialize DImode truthvalues. + +Thu Jun 4 01:26:57 1998 Craig Burley + + * expr.c (safe_from_p): Avoid combinatorial explosion + over duplicate SAVE_EXPRs by ensuring we never recurse + on one that has already been visited. + +Thu Jun 4 00:54:21 1998 Graham + + * loop.c (check_dbra_loop): Initialise final_value before + normalizing the loop. + +Wed Jun 3 20:00:04 1998 J"orn Rennecke + + * reload1.c (reload_reg_free_for_value_p): New arguments out and + reloadnum. Changed all callers. + +1998-06-03 Ulrich Drepper + + * system.h: Add _() and N_() macros in preparation for gettext. + +Wed Jun 3 11:02:24 1998 Andreas Schwab + + * c-common.c (check_format_info): Put back check for C9x `hh' + length modifier. Warn about %n format writing into const. Remove + obsolete comment. + (format_char_info): Fix comments. + + * configure.in: Set float_format to m68k for all m68k targets that + do not override LONG_DOUBLE_TYPE_SIZE. + * config/float-m68k.h: New file. + +Tue Jun 2 23:14:01 1998 Richard Henderson + + * jump.c (jump_optimize): Remove debug messages accidentally left in + with the previous change. + +Tue Jun 2 22:46:08 1998 Richard Henderson + + * expr.c (store_expr): Revert stray patch associated with + 1998-05-23 commit. + +Tue Jun 2 21:59:01 1998 Richard Henderson + + * jump.c (rtx_unsafe_p): New function. + (jump_optimize): Use it on if/then/else transformations and + conditional move transformations. + +Tue Jun 2 22:50:10 1998 Andreas Schwab + + * fold-const.c (fold, case EQ_EXPR): When folding VAR++ == CONST + or VAR-- == CONST construct a proper mask if VAR is a bitfield. + Cope with CONST being out of range for the bitfield. + +Tue Jun 2 22:28:31 1998 Bernd Schmidt + + * expr.c (emit_move_insn_1): When moving complex values in several + steps, emit a CLOBBER to show the destination dies. + +Tue Jun 2 22:17:26 1998 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (site.exp): Use the object testsuite directory as + the temporary directory. + + * expr.c (expand_expr, case ADDR_EXPR): Handle taking the + address of an ADDRESSOF rtx. + +1998-06-02 Mike Stump + + * expr.c (expand_builtin_setjmp): Handle BUILTIN_SETJMP_FRAME_VALUE. + * i960.h (SETUP_FRAME_ADDRESSES, BUILTIN_SETJMP_FRAME_VALUE): Define. + * i960.md (ret, flush_register_windows): Define. + (nonlocal_goto): Likewise. Nested function nonlocal gotos don't + work yet. + * tm.texi (BUILTIN_SETJMP_FRAME_VALUE): Document new macro. + +Tue Jun 2 14:02:38 1998 Richard Henderson + + * alpha.md (divsi3, udivsi3, modsi3, umodsi3): Enable, and work + around an OSF/1 library bug wrt sign-extension of inputs. + +Tue Jun 2 13:02:44 1998 Richard Henderson + + * vax/netbsd.h (DWARF2_UNWIND_INFO): Must be undef, not defined 0. + +Mon Jun 1 03:44:03 1998 Catherine Moore + + * config/sh/sh.h (MAX_OFILE_ALIGNMENT): Define. + + * varasm.c (assemble_variable): Augment alignment warning. + +Mon Jun 1 12:14:28 1998 Michael Meissner + + * config/fp-bit.c (_fp{add,div}_parts): Return correct IEEE result + in the presence of IEEE negative 0's. + +Sun May 31 16:11:41 1998 John Wehle (john@feith.com) + + * reload.c (find_reloads): Record the existing mode if + operand_mode == VOIDmode before replacing a register with + a constant. + * i386.md (tstsi, tsthi, tstqi, tstsf, tstdf, tstxf): Set + i386_compare_op1 to const0_rtx for the benefit of the + conditional move patterns. + (movsicc, movhicc, movsfcc, movdfcc, movxfcc, movdicc): Rewrite + based on suggestions from Jim Wilson. + +Sun May 31 00:44:02 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sun May 31 00:34:17 1998 Bruce Korb + + * Makefile.in (fixinc.sh): Update rules again. + +Sun May 31 00:27:47 1998 Jeffrey A Law (law@cygnus.com) + + * extend.texi: Bring back reference to trampoline paper. + +Sun May 31 00:22:34 1998 Ulrich Drepper + + * Makefile.in (USER_H): Add stdbool.h. + * ginclude/stdbool.h: New file. + +Fri May 29 01:48:25 1998 Jeffrey A Law (law@cygnus.com) + + * jump.c (thread_jumps): Do not look at the NOTE_LINE_NUMBER + of a non-note insn. + + * gcse.c (pre_delete): Fix code to determine the mode of + the reaching pseudo register. + +Fri May 29 01:07:28 1998 Bernd Schmidt + + * Makefile.in (GEN): Add gencheck + (STAGESTUFF): Add tree-check.h and gencheck. + +Fri May 29 00:57:37 1998 Bruce Korb + + * Makefile.in (cstamp-h.in): Remove before trying to recreate. + (fixinc.sh): Set some additional environment variables before + calling mkfixinc.sh. + +Thu May 28 12:57:05 1998 Jeffrey A Law (law@cygnus.com) + + * reload.c (find_reloads): Do not force a reloads of match_operators. + +Thu May 28 10:22:22 EDT 1998 Andrew MacLeod + + * except.h (remove_handler): Add new prototype. + * except.c (remove_handler): New function to remove handlers + from an exception region. + * flow.c (find_basic_blocks_1): Remove handlers from regions when + handler label is deleted; remove exception regions with no handlers. + +Thu May 28 09:36:39 1998 Michael Meissner + + * except.h (rtx): Define rtx type correctly if needed. + * function.h (rtx): Ditto. + (tree): Define tree type correctly if needed. + + * c-pragma.c (toplevel): Include rtl.h. + + * stor-layout.c (toplevel): Move include of rtl.h before + except.h. + + * Makefile.in (c-pragma.o): Add except.h, rtl.h dependencies. + (tree.o): Add except.h dependency. + +Wed May 27 22:02:40 1998 Jeffrey A Law (law@cygnus.com) + + * reload1.c: Revert accidental checkin. + + * configure.lang: Fix thinko when adding a definition for + target_alias to the Makefile. + +Wed May 27 02:50:00 1998 Catherine Moore (clm@cygnus.com) + + * config/sparc/lb1spc.asm (.rem and .urem): Replace + routines. + +Wed May 27 02:48:31 1998 Richard Earnshaw (rearnsha@arm.com) + + * arm.c (arm_gen_constant): Rework to eliminate uninitialized + variable warnings. Don't generate scratch registers if only + counting insns. + (find_barrier): Eliminate unused variable SRC. + +1998-05-27 Manfred Hollstein + + * toplev.h (rtx_def): Provide global declaration to avoid + `limited scope' warnings. + +Tue May 26 23:47:52 1998 Mumit Khan + + * Makefile.in (gencheck.o): Use HOST_CC. + * i386/t-mingw32: New file. + * configure.in (i386-*-mingw32*): Use. + +Tue May 26 07:31:04 1998 Richard Earnshaw (rearnsha@arm.com) + + * arm.c (bad_signed_byte_operand): New predicate function. + * arm.h (PREDICATE_CODES): Add it to the list. + * arm.md (*extendqi[sh]i_insn): Split any addresses that ldrsb + can't handle. + (define_split): Two new splits for above insns. + + * arm.c: Include toplev.h. + (arm_override_options): Add parentheses around use of tune_flags. + (arm_split_constant): Remove unused variable. + (arm_gen_constant, arm_gen_movstrqi, add_constant): Likewise. + (output_func_prologue, arm_expand_prologue): Likewise. + (arm_canonicalize_comparison): Make I unsigned; rework constants + accordignly. Add missing paratheses around << operation. + (arm_rtx_costs): Correctly parenthesise MULT costs. Add a DEFAULT + clause. + ({load,store}_multiple_sequence): Initialize BASE_REG. + (select_dominance_cc_mode): Add DEFAULT clauses. + (broken_move): Return zero if the destination is not a register. + (arm_reorg): Move unused REGNO declaration into the dead code. + * arm.h (CANONICALIZE_COMPARISON): Ensure OP1 is updated. + +Mon May 25 22:49:56 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Mon May 25 11:56:24 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Mon May 25 14:00:13 1998 Dave Brolley + + * cpperror.c (v_cpp_message): Remove static prototype. + * cpplib.c (v_cpp_message): Move prototype to cpplib.h. + * cpplib.h (v_cpp_message): Add protoptype. + (stdarg.h,varargs.h): Needed for v_cpp_message prototype. + +Sun May 24 20:36:15 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sun May 24 02:08:57 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +1998-05-24 Andreas Schwab + + * m68k.h: Declare more functions used in macros. + (REG_CLASS_CONTENTS): Completely embrace initializer. + * m68k.md (adddi3, subdi3): Add abort call to avoid warning + about returning no value. + * cse.c (find_best_addr): Declare p and found_better only if + needed. + * dbxout.c (dbxout_continue): Define only if DBX_CONTIN_LENGTH > 0. + * dwarfout.c (string_length_attribute): #if 0 away. + * function.c (expand_function_end): Define varible blktramp only + if needed. + * jump.c (find_insert_position): Define only if !HAVE_cc0. + * loop.c (combine_givs_p): Define variable tem only if needed. + * real.c: Comment out unused functions eabs, eround, + e{24,53,64,113}toasc and eiinfin. + + +Sat May 23 23:44:53 1998 Alexandre Oliva + + * Makefile.in (boostrap2-lean, bootstrap3-lean, + bootstrap4-lean): New targets. + +Sat May 23 23:35:14 1998 Jeffrey A Law (law@cygnus.com) + + * warn_summary, test_summary: Moved into the contrib directory. + +1998-05-23 Manfred Hollstein + + * Makefile.in (ENQUIRE_CFLAGS, ENQUIRE_LDFLAGS): Move down to the end + of the Makefile. + (FLOAT_H_TEST): Likewise. + (ENQUIRE): Likewise. + (float.h-nat): Likewise. + (float.h-cross): Likewise. + (enquire): Likewise. + (enquire.o): Likewise. + (stmp-int-hdrs): Fix comment about enquire; depend upon gfloat.h. + (stmp-headers): Move actions to stmp-int-hdrs, retaining only a + no-op. + (FLOAT_H): Remove old float.h-nat version; move current definition + to CROSS_FLOAT_H location. + (all.cross): Remove comments about enquire stuff. + + * Makefile.in (all.cross): Swap $(LIBGCC) and $(STMP_FIXPROTO). + (rest.encap): Likewise. + (libgcc2.ready): Depend upon $(STMP_FIXPROTO) + + * toplev.h (tree_node): Provide global declaration to avoid + `limited scope' warnings. + +Sat May 23 23:23:35 1998 Robert Lipe + + * test_summary: Display section breaks for each entry + in a multilibbed target's output. + +1998-05-23 Richard Henderson + + * expr.c (expand_expr): For {BITFIELD,COMPONENT,ARRAY}_REF, if the + offset's mode is not ptr_mode, convert it. + +1998-05-22 Jason Merrill + + * fold-const.c (ssize_binop): New fn. + * tree.h: Declare it. + +Fri May 22 03:42:05 1998 Richard Earnshaw (rearnsha@arm.com) + + * genextract.c (print_path): Handle zero-length path as a special + case. + +Fri May 22 01:38:07 1998 Hans-Peter Nilsson + + * cplus-dem.c (MBUF_SIZE): Bumped from 512 to 32767. + +Fri May 22 00:57:00 1998 Bernd Schmidt (crux@pool.informatik.rwth-aachen.de> + + * final.c (JUMP_TABLES_IN_TEXT_SECTION): Provide a default value. + (shorten_branches, final_scan_insn): Test value of + JUMP_TABLES_IN_TEXT_SECTION instead of just testing whether it + is defined. + * tm.texi (JUMP_TABLES_IN_TEXT_SECTION): Corresponding changes. + * arm/coff.h: Define JUMP_TABLES_IN_TEXT_SECTION to 1. + * arm/tcoff.h: Likewise. + * i386/386bsd.h: Likewise. + * i386/freebsd-elf.h: Likewise. + * i386/freebsd.h: Likewise. + * i386/netbsd.h: Likewise. + * i386/ptx4-i.h: Likewise. + * i386/sysv4.h: Likewise. + * pa/pa.h: Likewise. + * rs6000/linux.h: Likewise. + * rs6000/rs6000.h: Likewise. + * sh/sh.h: Likewise. + * sparc/sp64-elf.h: Likewise. + * v850/v850.h: Likewise. + * rs6000/sysv4.h: Define JUMP_TABLES_IN_TEXT_SECTION to 0. + * i386/linux.h: Define JUMP_TABLES_IN_TEXT_SECTION to (flag_pic). + +Thu May 21 19:50:13 1998 J"orn Rennecke + + * regmove.c (gen_add3_insn): New function. + (fixup_match_2): Use it instead of calling gen_addsi3. + +Thu May 21 23:09:50 1998 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (gencheck): Depend on HOST_LIBDEPS. + + * alias.c (rtx_equal_for_memref_p): Handle SCRATCH as a memory + address. + +Thu May 21 20:18:13 1998 Martin von Loewis + + * Makefile.in (TREE_H): Add tree-check.h. + (tree-check.h, gencheck): New targets. + * gencheck.c: New file. + * tree.c (tree_check, tree_class_check): New functions. + * tree.h (TREE_CHECK, TREE_CLASS_CHECK): Define. + (TYPE_CHECK, DECL_CHECK): Define. + Modify all access macros to use generated checking macros. + +Wed May 20 23:44:28 EDT 1998 John Wehle (john@feith.com) + + * acconfig.h (HAVE_GAS_MAX_SKIP_P2ALIGN): New tag. + * configure.in: Check for it. + * i386/gas.h (ASM_OUTPUT_MAX_SKIP_ALIGN): Use it. + * final.c (uid_align, uid_shuid, label_align): Make static. + (label_align): Change type to struct label_alignment pointer. + (LABEL_TO_ALIGNMENT, shorten_branches): Update due to type change. + (LABEL_TO_MAX_SKIP): Define. + (LABEL_ALIGN_MAX_SKIP, LOOP_ALIGN_MAX_SKIP, + LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP): Provide defaults. + (shorten_branches): Record the maximum bytes to skip when + aligning a label. + (final_scan_insn): Use the maximum bytes to skip when aligning a label + if ASM_OUTPUT_MAX_SKIP_ALIGN is available. + * i386.h (LOOP_ALIGN_MAX_SKIP, + LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP): Define. + * i386.c (override_options): i386_align_jumps and i386_align_loops + default to 4 if ASM_OUTPUT_MAX_SKIP_ALIGN is available. + * invoke.texi: Document new i386 align-loops and align-jumps behavior. + +1998-05-21 Mark Mitchell + + * cplus-dem.c (do_type): Handle volatile qualification. + +Thu May 21 12:23:17 1998 Per Bothner + + * function.c (init_function_start): Don't call emit_line_note if + lineno is 0. (Can happen when compiling Java .class files.) + +Thu May 21 19:50:13 1998 J"orn Rennecke + + * reload1.c (reload_reg_free_for_value_p): Fix RELOAD_FOR_INPUT + end of lifetime and RELOAD_FOR_OUTPUT start of lifetime. + +Thu May 21 19:32:27 1998 J"orn Rennecke + + * combine.c (nonzero_bits): For paradoxical subregs, take + LOAD_EXTENDED_OP into account. + +Thu May 21 11:51:15 1998 Dave Brolley + + * configure.in (extra_c_objs): add prefix.o. + (extra_cxx_objs): extra objects for C++ with cpplib. + * configure: Regenerate. + + * c-tree.h: (get_directive_line): Different prototype for cpplib. + (GET_DIRECTIVE_LINE): Macro wrapper for get_directive_line. + + * c-lex.h: (get_directive_line): Not needed here for cpplib. + + * c-lex.c: (yy_cur,yy_lim,yy_get_token): Move to c-common.c. + (GET_DIRECTIVE_LINE): Move to c-common.c and rename to get_directive_line. + + * c-common.c (parse_in,parse_options,cpp_token): Declare for cpplib. + (yy_cur,yy_lim,yy_get_token,get_directive,line): Moved here from c-lex.c + +Thu May 21 09:04:42 1998 Kaveh R. Ghazi + + * gengenrtl.c (type_from_format, accessor_from_format): Change + type of parameter `c' from `char' to `int'. + +Wed May 20 22:28:34 1998 Jeffrey A Law (law@cygnus.com) + + * warn_summary, test_summary: New scripts from + Kaveh Ghazi and Alexandre Oliva respectively. + + * gcse.c (current_function_calls_longjmp): Declare. + +1998-05-20 Jason Merrill + + * dwarf2out.c (base_type_die): Use int_size_in_bytes. + +Wed May 20 01:11:02 1998 Doug Evans (devans@cygnus.com) + Jeff Law (law@cygnus.com) + + * Global CSE and constant/copy propagation. + * Makefile.in (OBJS): Add gcse.o + (STAGESTUFF): Add *.gcse. + (gcse.o): Add dependencies. + (mostlyclean): Remove *.gcse and */*.gcse. + * gcse.c: New file. + * loop.c (loop_optimize): Move call to init_alias_analysis. + * recog.c (validate_replace_src): New function. + * toplev.c (gcse_dump): New global variable. + (flag_gcse, gcse_time): Likewise. + (compile_file): Initialize gcse_time and clean out the gcse dump + file if necessary. + (rest_of_compilation): Call gcse_main as requested. Dump RTL + after gcse if requested. + (main): Enable gcse for -O2 and above. Handle -dG. Enable gcse + dumps for -da. + * gcc.texi: Add gcse related internal documentation. + * invoke.texi: Note new command line options for gcse. + * tm.texi: Document AVOID_CCMODE_COPIES. + * mips.h (AVOID_CCMODE_COPIES): Define. + +Tue May 19 22:31:20 1998 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (deduced.h): Only run scan-types if $(SYSTEM_HEADER_DIR) + exists. + (stmp-fixproto): Simlarly for running fixproto. + * cross-make (SYSTEM_HEADER_DIR): Now $(tooldir)/sys-include. + +Tue May 19 19:08:52 1998 Jim Wilson + + * config/mips/mips.c (double_memory_operand): Accept any MEM during + reload when TARGET_64BIT. + +Tue May 19 18:21:25 1998 Jim Wilson + + Finish incomplete change started by Kenner. + * configure.in (*-*-linux-gnu*): Delete NO_STAB_H from xm_defines. + (powerpcle-*-cygwin32): Delete xm_defines. + * final.c, mips-tfile.c, xcoffout.c, config/mips/mips.c: Use + HAVE_STAB_H instead of NO_STAB_H. + * config/xm-linux.h (NO_STAB_H): Delete. + (HAVE_STAB_H): Undefine. + * config/i386/xm-go32.h (NO_STAB_H): Delete. + +1998-05-19 Jim Wilson + + * dwarfout.c (dwarfout_file_scope_decl, case TYPE_DECL): Ignore + LANG_TYPE trees with DECL_SOURCE_LINE of 0. + +Tue May 19 15:07:54 1998 Todd Vierling + + * arm/netbsd.h: Ensure DWARF2_UNWIND_INFO is undefined. + +Tue May 19 17:19:16 1998 J"orn Rennecke + + * reload1.c (reload_reg_free_for_value_p): New function. + (allocate_reload_reg, choose_reload_regs): Use it. + +Tue May 19 11:51:00 EDT 1998 Andrew MacLeod (amacleod@cygnus.com) + + * except.c (expand_start_catch): Correct logic for when to + generate a new handler label, and when to use the old one. + +Tue May 19 11:08:52 1998 Kaveh R. Ghazi + + * Makefile.in (print-rtl.o): Depend on bitmap.h. + (dbxout.o): Depend on toplev.h. + ($(SCHED_PREFIX)sched.o): Likewise. + ($(out_object_file)): Likewise for system.h and toplev.h. + (cppmain.o): Depend on gansidecl.h. + (cpplib.o): Likewise. + (cpperror.o): Likewise. + (cppexp.o): Likewise. + (cpphash.o): Likewise. + (cppalloc.o): Likewise. + (fix-header.o): Depend on cpplib.h and cpphash.h. + (scan-decls.o): Depend on gansidecl.h. + + * basic-block.h (free_regset_vector): Add prototype. + + * cccp.c (check_precompiled): Mark parameter `fname' with + ATTRIBUTE_UNUSED. + (do_assert): Likewise for `op' and `keyword'. + (do_unassert): Likewise. + (do_line): Likewise for `keyword'. + (do_error): Likewise for `op' and `keyword'. + (do_warning): Likewise. + (do_ident): Likewise for `keyword'. + (do_pragma): Likewise for `limit', `op' and `keyword'. + (do_sccs): Likewise. + (do_if): Likewise for `keyword'. + (do_elif): Likewise. + (do_else): Likewise. + (do_endif): Likewise. + + * collect2.c (getenv): Remove redundant prototype. + (collect_exit, collect_execute, dump_file): Likewise. + (dump_list): Wrap prototype and definition in COLLECT_EXPORT_LIST. + (dump_prefix_list): Hide prototype and definition. + + * sparc.c: Include toplev.h. + (intreg_operand): Mark parameter `mode' with ATTRIBUTE_UNUSED. + (symbolic_memory_operand): Likewise. + (sp64_medium_pic_operand): Likewise. + (data_segment_operand): Likewise. + (text_segment_operand): Likewise. + (splittable_symbolic_memory_operand): Likewise. + (splittable_immediate_memory_operand): Likewise. + (eq_or_neq): Likewise. + (normal_comp_operator): Likewise. + (noov_compare_op): Likewise. + (v9_regcmp_op): Likewise. + (v8plus_regcmp_op): Likewise. + (extend_op): Likewise. + (cc_arithop): Likewise. + (cc_arithopn): Likewise. + (small_int): Likewise. + (uns_small_int): Likewise. + (clobbered_register): Likewise. + (legitimize_pic_address): Likewise. + (delay_operand): Likewise. + (sparc_builtin_saveregs): Remove unused variable `stdarg'. + + * sparc.h (order_regs_for_local_alloc, eligible_for_return_delay, + sparc_issue_rate, v8plus_regcmp_p): Add prototypes. + + * sparc.md (cmpdi_v8plus): Add abort for default case in switch. + + * cppalloc.c: Include gansidecl.h. + + * cpperror.c: Include stdarg.h/varargs.h and gansidecl.h. + (cpp_file_line_for_message): Mark parameter `pfile' with + ATTRIBUTE_UNUSED. + (v_cpp_message): New function. + (cpp_message): Use it. Also convert to variable arguments. + (cpp_fatal): Likewise. + (cpp_pfatal_with_name): Constify parameter `name'. + + * cppexp.c: Move gansidecl.h before cpplib.h. + * cpphash.c: Likewise. + * cpphash.h (hashf, delete_macro): Add prototypes. + + * cpplib.c: Include stdarg.h/varargs.h and move gansidecl.h before + cpplib.h. Don't include errno.h. + (update_path): Add arguments to prototype. + (cpp_fatal, cpp_file_line_for_message, cpp_message, delete_macro, + cpp_print_containing_files): Remove redundant prototypes. + (cpp_hash_cleanup, add_import, append_include_chain, + make_assertion, path_include, initialize_builtins, + initialize_char_syntax, finclude, validate_else, comp_def_part, + lookup_import, redundant_include_p, is_system_include, + read_name_map, read_filename_string, open_include_file, + check_macro_name, compare_defs, compare_token_lists, + eval_if_expression, change_newlines): Add prototype arguments. + (hashf): Remove redundant prototype. + (read_token_list, free_token_list, safe_read, xcalloc, savestring, + conditional_skip, skip_if_group): Add prototype arguments. + (fdopen): Remove redundant prototype. + (do_define, do_line, do_include, do_undef, do_error, do_pragma, + do_ident, do_if, do_xifdef, do_else, do_elif, do_endif, do_sccs, + do_once, do_assert, do_unassert, do_warning): Add prototype arguments. + (struct directive): Add prototype arguments to function pointer + member `func'. + (handle_directive): Add missing arguments to call to `do_line'. + (do_include): Mark parameters `unused1' and `unused2' with + ATTRIBUTE_UNUSED. + (do_line): Likewise for `keyword' and new parameters `unused1' and + `unused2'. + (do_error): Likewise for `keyword'. + (do_warning): Likewise. Also add missing argument `pfile' in call + to cpp_pedwarn. + (do_once): Mark parameter `keyword', `unused1' and `unused2' with + ATTRIBUTE_UNUSED. + (do_ident): Likewise for `keyword', `buf' and `limit'. + (do_pragma): Likewise. Also add missing arguments in call to do_once. + (do_sccs): Mark parameter `keyword', `buf' and `limit' with + ATTRIBUTE_UNUSED. + (do_if): Likewise for `keyword'. + (do_elif): Likewise. + (eval_if_expression): Likewise for `buf' and `length'. + (do_xifdef): Likewise for `unused1' and `unused2'. + (do_else): Likewise for `keyword', `buf' and `limit'. + (do_endif): Likewise. + (parse_name): Add missing argument `pfile' in call to cpp_pedwarn. + (cpp_handle_options): Remove superfluous NULL argument in call to + cpp_fatal. + (cpp_handle_options): Likewise. + (do_assert): Mark parameter `keyword', `buf' and `limit' with + ATTRIBUTE_UNUSED. + (do_unassert): Likewise. + (cpp_print_file_and_line): Add missing argument `pfile' in call to + cpp_file_line_for_message. + (v_cpp_error): New function. + (cpp_error): Use it. Also accept variable arguments. + (v_cpp_warning): New function. + (cpp_warning): Use it. Also accept variable arguments. + (cpp_pedwarn): Accept variable arguments. + (v_cpp_error_with_line): New function + (cpp_error_with_line): Use it. Accept variable arguments. + (v_cpp_warning_with_line): New function. + (cpp_warning_with_line): Use it. Accept variable arguments. Hide + definition. + (cpp_pedwarn_with_line): Accept variable arguments. + (cpp_pedwarn_with_file_and_line): Likewise. + (cpp_error_from_errno): Constify parameter `name'. Add missing + argument `pfile' in call to cpp_file_line_for_message. + (cpp_perror_with_name): Constify parameter `name'. + + * cpplib.h: Define PARAMS() in terms of PROTO(). + (fatal): Remove redundant prototype. + (cpp_error, cpp_warning, cpp_pedwarn, cpp_error_with_line, + cpp_pedwarn_with_line, cpp_pedwarn_with_file_and_line, + cpp_error_from_errno, cpp_perror_with_name, cpp_pfatal_with_name, + cpp_fatal, cpp_message, cpp_pfatal_with_name, + cpp_file_line_for_message, cpp_print_containing_files): Add + arguments to prototypes. + (scan_decls, cpp_finish): Add prototypes. + + * cppmain.c: Include gansidecl.h. + (main): Remove unused variable `i'. + + * dbxout.c: Include toplev.h. + + * demangle.h (do_tlink, collect_execute, collect_exit, + collect_wait, dump_file, file_exists): Add prototype. + + * dwarf2out.c (dwarf_type_encoding_name, decl_start_label): Hide + prototype and definition. + (gen_unspecified_parameters_die): Don't assign results of call to + function new_die() to unused variable `parm_die'. + (dwarf2out_line): Mark parameter `filename' with ATTRIBUTE_UNUSED. + (dwarf2out_define): Likewise for `lineno' and `buffer'. + + * dwarfout.c (output_unsigned_leb128, output_signed_leb128): Hide + prototype and definition. + (output_die): Add prototype arguments to function pointer arg. + (output_unspecified_parameters_die): Mark parameter `arg' with + ATTRIBUTE_UNUSED. + + * except.c (output_exception_table_entry): Remove unused variable + `eh_entry'. + + * except.h (expand_fixup_region_start, expand_fixup_region_end): + Add prototypes. + + * expr.c (do_jump_by_parts_equality_rtx): Remove prototype. + + * expr.h (do_jump_by_parts_equality_rtx): Add prototype. + + * fix-header.c: Include stdarg.h/varargs.h, move gansidecl.h + before cpplib.h, include cpphash.h, remove redundant prototype of + cpp_fatal, don't define `const', add a prototype for `fatal'. + (cpp_file_line_for_message): Add missing arguments `pfile'. + (v_cpp_message): New function. + (cpp_message): Use it. + (v_fatal): New function. + (fatal, cpp_fatal): Use it. + (cpp_pfatal_with_name): Constify parameter `name'. + + * flow.c (free_regset_vector): Remove redundant prototype. + + * function.c (round_down): Wrap prototype and definition with + macro ARGS_GROW_DOWNWARD. + (record_insns): Wrap prototype and definition with + defined (HAVE_prologue) || defined (HAVE_epilogue). + + * gansidecl.h (ATTRIBUTE_PRINTF_4, ATTRIBUTE_PRINTF_5): New macros. + + * gen-protos.c: Include gansidecl.h. + (hashf): Don't make it static, constify parameter `name'. + + * genattrtab.c (check_attr_test): Change XEXP() to XSTR() to match + specifier %s in calls to function `fatal'. + + * haifa-sched.c: Include toplev.h. + (find_rgns): Remove unused variable `j'. + + * integrate.c (note_modified_parmregs): Mark parameter `x' with + ATTRIBUTE_UNUSED. + (mark_stores): Likewise. + + * jump.c (mark_modified_reg): Likewise. + + * output.h (insn_current_reference_address): Add prototype. + (eh_frame_section): Likewise. + + * print-rtl.c: Include bitmap.h. + + * reload1.c (reload): Wrap variables `note' and `next' in macro + PRESERVE_DEATH_INFO_REGNO_P. + (forget_old_reloads_1): Mark parameter `ignored' with + ATTRIBUTE_UNUSED. + (choose_reload_regs): Remove unused variable `in'. + (reload_cse_invalidate_mem): Mark parameter `ignore' with + ATTRIBUTE_UNUSED. + (reload_cse_check_clobber): Likewise. + + * rtl.h (expand_null_return, reg_classes_intersect_p): Add prototype. + (mark_elimination): Fix typo in prototype. + + * scan-decls.c: Include gansidecl.h. + + * tree.h (using_eh_for_cleanups, supports_one_only): Add prototype. + +Mon May 18 22:37:33 1998 Jeffrey A Law (law@cygnus.com) + + * function.c (identify_blocks): Fix thinko when setting the + block number for NOTE_INSN_BLOCK_END. + +Mon May 18 15:30:42 1998 Nick Clifton + + * config/v850/lib1funcs.asm: Add .text pseudo op to start of + ___udivsi3. + + * config/v850/lib1funcs.asm: Fix .size pseudo ops to use three + underscores for the prefixes to the names of the maths functions. + + * dbxout.c (dbxout_parms): Revert to using DECL_ARG_TYPE. Add + comment explaining why. + +Mon May 18 13:20:23 1998 Richard Henderson + + * tree.h (TYPE_SIZE_UNIT): New. + (struct tree_type): Add size_unit member. + * stor-layout.c (layout_type): Initialize it. + * expr.c (get_inner_reference) [ARRAY_REF]: Use it. + * tree.c (size_in_bytes, int_size_in_bytes): Likewise. + +Mon May 18 12:07:37 1998 Richard Earnshaw (rearnsha@arm.com) + + * stor-layout.c (layout_record): Fix off-by-one error when checking + length of the TYPE_BINFO vector. + +Mon May 18 10:59:23 1998 Nick Clifton + + * dbxout.c (dbxout_parms): Use TREE_ARG to compute the type of a + function parameter passed in memory. + +Mon May 18 09:02:09 1998 Robert Lipe + + * dwarfout.h, dwarf2out.h, dbxout.h, sdbout.h: New files. + Prototypes for externally used functions in respective C files. + * dwarfout.c, dbxout.c, dwarf2out.c, sdbout.c, toplev,c, + final.c: Include above files. + * Makefile.in (toplev.o): Add dependency for above four headers. + (final.o): Likewise. + (dwarfout.o, dbxout.o, dwarf2out.o, sdbout.o): Depend on four + respective header files. + +Mon May 18 01:23:33 1998 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (TARGET_TOOLPREFIX): No longer define. + (AR_FOR_TARGET, RANLIB_FOR_TARGET): Define to use versions in + the build tree if they exist. + (AR, AR_FLAGS, OLDAR, OLDAR_FLAGS, RANLIB, RANLIB_TEST): Update + appropriately. + (objdir): Let configure substitute value. + (FLOAT_H): Let configure select a pre-built version from the + config subdir. + * build-make (INSTALL_TARGET, ALL): Disable, no longer needed. + * configure.in: Substitute for objdir. + + * Makefile.in (build_canonical, host_canonical): Let configure + substitute values for these variables. + * configure.in: Substitute for build_canonical, host_canonical + and target_subdir in generated Makefile. + + * output.h (find_basic_blocks): Declare. + (free_basic_block_vars, set_block_num, life_analysis): Likewise. + + * Makefile.in (BISON): Use bison from the build tree if it exists. + (FLEX): Similarly. + +Mon May 18 00:08:19 1998 Nick Clifton + + * gcc.c (SWITCH_CURTAILS_COMPILATION): Definition. + (DEFAULT_SWITCH_CURTAILS_COMPILATION): True for options -S and -c. + (process_command): If HAVE_EXECUTABLE_SUFFIX is defined then scan + command line arguments to see if an executable is not being + created, and if so - do not append the suffix. + + * tm.texi (SWITCH_CURTAILS_COMPILATION): Add description of new + driver macro. + +Sun May 17 23:59:45 1998 John Wehle (john@feith.com) + + * i386.h (ALIGN_DFmode): Delete. + (CONSTANT_ALIGNMENT): Define. + * varasm.c (force_const_mem): Use it. + +Sun May 17 19:31:05 1998 Richard Henderson + + * alpha.c (alpha_emit_conditional_branch): Clear cmp_code after + using it with swap_condition, not before. + +Sun May 17 13:44:32 1998 Jim Wilson + + * alias.c (mode_alias_check): Delete. + (true_dependence, anti_dependence, output_dependence): Revert April 21 + change. + +Sun May 17 08:45:21 1998 Krister Walfridsson + + * toplev.c (output_lang_identify): Enable prototype and definition. + +Sun May 17 01:12:27 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sat May 16 23:20:32 1998 Richard Henderson + + * alpha/osf.h (HAVE_STAMP_H): Define. + * alpha.c: Use it. + * alpha/netbsd.h, alpha/netbsd-elf.h: New files. + * configure.in (alpha*-*-netbsd*): New. + Based on patches from Paul H. Anderson . + + * configure.in (alpha*-*-linux-*): Kill xm_defines. + (alpha*-*-linux-gnulibc1*) [fixincludes]: Define. + * alpha/xm-linux.h: Remove file. + +Sat May 16 18:32:45 1998 Doug Evans + + * dbxout.c (dbxout_parms): If mode of type of parameter living + in memory doesn't match mode of DECL_RTL, make big endian correction. + +Fri May 15 21:40:06 1998 John Wehle (john@feith.com) + + * i386.md (movdi-1, movdi): Rewrite based on SI move patterns. + +Fri May 15 18:55:22 1998 Jason Merrill + + * tree.h (BINFO_SIZE, TYPE_BINFO_SIZE): New macros. + * stor-layout.c (layout_record): Set it. + +Fri May 15 18:49:30 1998 Mark Mitchell + + * toplev.c (rest_of_compilation): Don't defer nested functions. + +Fri May 15 17:42:52 1998 Bob Manson + + * config/rs6000/rs6000.c (rs6000_stack_info): Align the stack bottom + to an 8-byte boundary if info_ptr->fpmem_p. + +Fri May 15 17:36:11 1998 Bill Moyer + + * loop.c (basic_induction_var): Added test preventing + CCmode parameter passed to convert_modes(). + +Fri May 15 17:26:18 1998 Alexandre Petit-Bianco + + * expr.c (expand_expr, case EXPR_WITH_FILE_LOCATION): Save/restore + input_filename and lineno around expand_expr call. Set them to values + in WFL before expand_expr call. + +Fri May 15 12:44:57 1998 Benjamin Kosnik + + * stor-layout.c (set_sizetype): Set TYPE_NAME on bitsizetype. + +Fri May 15 07:20:03 1998 Mark Mitchell + + * fold-const.c (constant_boolean_node): New function. + (fold): Use it. + +Fri May 15 11:21:16 1998 J"orn Rennecke + + * sh.c (gen_shl_and): Don't sign extend constant for kind two. + Abort if trying to split kind 3 or 4 outside of combine. + +Fri May 15 01:47:37 1998 Jeffrey A Law (law@cygnus.com) + + * mips.c (print_operand, case 'x'): Use HOST_WIDE_INT_PRINT_HEX. + +Fri May 15 01:42:45 1998 Mumit Khan + + * objc/Make-lang.in (OBJC_O): Add missing exeext. + (libobjc.a, runtime-info.h): Likewise. + +Fri May 15 01:29:39 1998 John Wehle (john@feith.com) + + * i386.h (DATA_ALIGNMENT): Define. + +Fri May 15 05:35:37 1998 J"orn Rennecke + + * reload1.c (delete_output_reload): Ignore single USE that + was emitted for the pseudo use of this INSN. + If the no reference to REG between OUTPUT_RELOAD_INSN and INSN + remains, we can always delete OUTPUT_RELOAD_INSN. + +Thu May 14 18:38:50 1998 Jim Wilson + + * reload.c (find_reloads): Don't penalize SCRATCH output reload. + +Thu May 14 15:10:30 1998 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (expr.o): Remove dependency on deleted modemap.def file. + +Thu May 14 16:30:47 EDT 1998 Andrew MacLeod + + * eh-common.h: New file for basic EH data structures. + * except.h: Various prototypes and structures for NEW_EH_MODEL + * function.h (struct function): Add a struct eh_stack for the catch + clause stack. + * except.c (gen_exception_label): New function to generate an + exception label. + (push_eh_entry): Use gen_exception_label() and init 'label_used' field. + (push_entry): New function to push an existing entry onto a stack. + (receive_exception_label): New function to emit the code required + at the start of all catch blocks. + (struct func_eh_entry): New structure for maintaining handlers + associated with EH regions. + (new_eh_region_entry): New function to register an EH region. + (add_new_handler): New function to register a handler with a region. + (get_new_handler): Creates anew handler entry for registering. + (find_func_region): New function to convert a NOTE eh region number + to an Eh region index. + (get_first_handler): New function to get the first handler in a region. + (clear_function_eh_region): New function to release memory. + (duplicate_handlers): New function to duplicate a list of handlers. + (expand_eh_region_end): Create a new region entry node as well. + (expand_leftover_cleanups): Call receive_exception_label() and + register the cleanup as a handler to the current region. + (expand_start_catch): New function to start a catch clause. + (expand_end_catch): New function to end a catch clause. + (expand_start_all_catch): restructure to not do the equivilent of + what expand_start_catch() does now. Push the exception region being + handled onto the catch stack. + (output_exception_table_entry): Issue an entry for each handler + associated with a region. + (set_exception_lang_code): New function for setting the language code. + (set_exception_version_code): New function to set the version number. + (output_exception_table): Output version and language codes. + (find_exception_handler_labels): Find handler labels using new scheme. + (is_exception_handler_label): New function, returns 1 if label is + present as a handler in some exception region. + (check_exception_handler_labels): Use the new scheme. + (init_eh_for_function): Initialize the catch stack. + (save_eh_status): Save the catch stack. + (restore_eh_status): Restore the catch stack. + (scan_region): Don't remove unreferenced handler label. Flow does it. + (get_reg_for_handler): New function to get the eh_context pointer + passed by __throw. + (expand_builtin_eh_stub): Changes required for NEW_EH_MODEL only. + * final.c (final_scan_insn): With NEW_EH_MODEL, add EH table + entry when processing END region rather that START region. + * flow.c (find_basic_blocks_1): Find all potential handler regions + now that we don't automatically know what the labels might be. + Let scan_region() remove unreferenced EH BEGIN/END labels. + * integrate.c (get_label_from_map): Put inlined labels onto the + permanent obstack since we dont know which ones might be exception + labels. + (save_for_inline_copying): Make new copies of all the handlers. + (expand_inline_function): Make new copies of all the handlers. + * libgcc2.c: Remove local struct decls, and include eh-common.h. + (find_exception_handler): With NEW_EH_MODEL the first matching + region we find is the right one. Add eh_info as a new parameter. + (__throw): Pass eh_info to find_exception_handler. Set handler + and pass use different regs under NEW_EH_MODEL. + +Thu May 14 12:58:21 1998 Jim Wilson + + * i960.h (hard_regno_mode_ok): Changed to function from array of + unsigned. + (HARD_REGNO_MODE_OK): Call function instead of testing bit. + * i960.c (hard_regno_mode_ok): Changed to function from array of + unsigned. + +Thu May 14 08:41:46 1998 J"orn Rennecke + + * reload.c (remove_replacements): New function. + * reload.h (remove_replacements): Declare. + * reload1.c (choose_reload_regs): Disable some reloads that + belong to inherited reloads. + +Thu May 14 02:17:17 1998 J"orn Rennecke + + * loop.c (scan_loop): Don't call move_moveables for optimize_size. + + * reload1.c (merge_assigned_reloads): When merging, reset + reload_spill_index for the eliminated reload. + +Wed May 13 17:51:13 1998 Jeffrey A Law (law@cygnus.com) + + * haifa-sched.c (schedule_insns): Fix merge goof. + +1998-05-13 Jim Wilson + + * varasm.c (make_decl_rtl): Revert April 1 change. + * alpha/alpha.h, alpha/win-nt.h, arm/arm.h, i386/unix.h, i960/i960.h, + m68k/linux.h, pa/pa.h, sparc/sparc.h, vax/vax.h (ASM_OUTPUT_MI_THUNK): + Get function name from the SYMBOL_REF in the DECL_RTL, not from + DECL_ASSEMBLER_NAME. + * i386/winnt.c (gen_stdcall_suffix): Comment for questionable use of + DECL_ASSEMBLER_NAME. + +Wed May 13 13:09:19 1998 Jim Wilson + + * i386.c (notice_update_cc, output_float_compare): Disable + TARGET_CMOVE support. + +Wed May 13 15:28:59 1998 Michael Meissner + Jeff Law + + * rtlanal.c (find_reg_note): Ignore notes that are not on on + insns of class 'i'. + (find_regno_note): Likewise. + + * Makefile.in (stor-layout.o): Depend on except.h + (varasm.o, function.o): Likewise. + (expr.o): Depend on except.h, modemap.def and hard-reg-set.h. + + * Makefile.in (HOST_RTL): Add $(HOST_PREFIX)bitmap.o. + (rtl.o, emit-rtl.o): Add dependency on bitmap.h. + ($(HOST_PREFIX_1)rtl.o): Likewise. + ($(HOST_PREFIX_1)bitmap.o): New host object. + * emit-rtl.c (toplevel): Include bitmap.h. + (gen_rtx): Handle 't' and 'b' nodes. + * print-rtl.c (print_rtx): Handle printing NOTE_INSN_LIVE notes. + Print block number for block begin/end notes. Print 't' type + nodes as a pointer. Know that the 3rd argument of live range + start/stop notes is really a range_info rtx. If type is 'b', print + out argument as a bitmap. + * rtl.c: Include bitmap.c. + (copy_rtx): Copy tree nodes as is. Copy bitmaps if type is 'b'. + (note_insn_name): Add NOTE_INSN_RANGE_{START,END}, NOTE_INSN_LIVE. + * rtl.def (RANGE_LIVE): New node to hold live information while we + recalculate the basic blocks. + (RANGE_REG, RANGE_INFO): New rtl types for live range splitting. + (RANGE_VAR): New node, to hold information saved in symbol node for New + communicating live range information to the debug output functions. + * rtl.h (rtunion_def): Add rttree and rtbit fields. + (XBITMAP, XTREE): New accessor macros. + (NOTE_LIVE_INFO): Overload NOTE_SOURCE_FILE for NOTE_INSN_LIVE notes. + (NOTE_RANGE_INFO): Similarly for NOTE_INSN_RANGE_{START,END} notes. + (NOTE_BLOCK_LIVE_RANGE_BLOCK): Define. + (NOTE_INSN_RANGE_START, NOTE_INSN_RANGE_END, NOTE_INSN_LIVE): New notes. + (RANGE_LIVE_{BITMAP,ORIG_BLOCK}): New accessor macros. + (RANGE_REG_{SYMBOL,BLOCK}_NODE, RANGE_VAR_*): New accessor macros. + (RANGE_INFO_*): Likewise. + * sched.c (sched_analyze): Keep live range start/stop notes. + (unlink_other_notes): Likewise. + * haifa-sched.c (sched_analyze): Keep live range start/stop notes. + (unlink_other_notes): Likewise. + * tree.h (BLOCK_LIVE_RANGE_{START,END,VAR_FLAG}): New accessor macros. + (BLOCK_LIVE_RANGE_FLAG): Likewise. + (DECL_LIVE_RANGE_RTL): Likewise. + (struct tree_block): Add live_range_flag, live_range_var_flag, + live_range_start and live_range_end. + (struct tree_decl): Add live_range_rtl field. + * gengenrtl.c (type_from_format): Handle 'b' and 't'. + (accessor_from_format): Likewise. + + * haifa-sched.c (schedule_block): Make verbose output line up. + Also add a blank line in printing the individual ready lists. + +Wed May 13 15:43:44 1998 Kaveh R. Ghazi + + * Makefile.in (c-lang.o): Depend on c-tree.h, c-lex.h and toplev.h. + (c-lex.o): Depend on output.h. + (c-common.o): Likewise. + (stmt.o): Likewise. + (calls.o): Likewise. + (integrate.o): Depend on toplev.h. + (regclass.o): Depend on output.h. + (final.o): Depend on reload.h. + + * c-common.c: Include output.h. + (check_format_info): Remove unused variable `integral_format'. + + * c-decl.c (print_lang_decl): Mark parameters `file', `node' and + `indent' with ATTRIBUTE_UNUSED. + (print_lang_type): Likewise. + (maybe_build_cleanup): Likewise for parameter `decl'. + (copy_lang_decl): Likewise for parameter `node'. + + * c-lang.c: Include c-tree.h, c-lex.h and toplev.h. + (lang_print_xnode): Mark parameters `file', `node' and `indent' + with ATTRIBUTE_UNUSED. + (lookup_interface): Likewise for parameter `arg'. + (is_class_name): Likewise. + (maybe_objc_check_decl): Likewise for parameter `decl'. + (maybe_objc_comptypes): Likewise for parameters `lhs', `rhs' and + `reflexive'. + (maybe_objc_method_name): Likewise for parameter `decl'. + (build_objc_string): Likewise for parameters `len' and `str'. + + * c-lex.c: Include output.h. + + * c-lex.h (position_after_white_space): Correct typo in prototype. + + * c-tree.h (finish_file, c_expand_start_cond, c_expand_start_else, + c_expand_end_cond, init_iterators): Add prototypes. + + * caller-save.c (set_reg_live): Mark parameters `reg' and `setter' + with ATTRIBUTE_UNUSED. + + * calls.c: Include output.h. + + * cccp.c (pipe_closed): Mark parameter `signo' with + ATTRIBUTE_UNUSED. + + * combine.c: Move inclusion of expr.h to after insn-config.h. + + * iris6.h (ASM_IDENTIFY_GCC, ASM_IDENTIFY_LANGUAGE): Don't define + as empty, rather define as ((void)0). + + * sparc.c (sparc_check_64): Add braces around ambiguous `else'. + Add parentheses around assignment used as truth value. + + * cplus-dem.c (squangle_mop_up): Change return type to void. + (internal_cplus_demangle): Remove unused parameter `options'. + All callers changed. + (cplus_demangle_opname): Remove function wide variable `int i' and + replace with `size_t i' at each location where it is used. + (cplus_demangle_opname): change type of `i' from int to size_t. + + * cppexp.c (right_shift): Mark parameter `pfile' with + ATTRIBUTE_UNUSED. + + * cpphash.c (cpp_lookup): Likewise. + (cpp_hash_cleanup): Likewise. + + * cpplib.c (parse_name): Add a prototype and make it static. + (null_underflow): Mark parameter `pfile' with ATTRIBUTE_UNUSED. + (null_cleanup): Likewise for parameters `pbuf' and `pfile'. + (macro_cleanup): Likewise for parameter `pfile'. + (file_cleanup): Likewise. + + * cpplib.h (cpp_reader_init, cpp_options_init, cpp_start_read, + cpp_read_check_assertion, skip_rest_of_line): Add prototypes. + + * crtstuff.c (force_to_data, __CTOR_LIST__, force_to_data, + __DTOR_END__, __FRAME_END__): Mark with ATTRIBUTE_UNUSED. + + * cse.c (cse_check_loop_start): Mark parameter `set' with + ATTRIBUTE_UNUSED. + + * dbxout.c (flag_minimal_debug, have_used_extensions, + source_label_number): Move inside macro wrapper check against + defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO). + + * dwarf2out.c (gen_entry_point_die): Hide prototype and definition. + + * except.h (doing_eh): Provide prototype. + + * expr.c: Move inclusion of expr.h to after insn-config.h. + + * final.c: Include reload.h. + (shorten_branches): Cast the first argument of bzero to char *. + + * fix-header.c (cpp_print_containing_files): Mark parameter + `pfile' with ATTRIBUTE_UNUSED. + (cpp_fatal): Likewise. + + * flow.c (find_basic_blocks_1): Cast the first argument of bzero + to char *. + + * genattrtab.c (make_length_attrs): Change the type of variable + `i' from int to size_t. + (zero_fn): Mark parameter `exp' with ATTRIBUTE_UNUSED. + (one_fn): Likewise. + + * genextract.c (main): When generating insn-extract.c, mark + variable `junk' with ATTRIBUTE_UNUSED. + + * gengenrtl.c (gencode): When generating genrtl.c, cast the first + argument of bzero to char*. + + * integrate.c: Include toplev.h. + + * libgcc2.c: Wrap `struct exception_table' and + `find_exception_handler' in macro DWARF2_UNWIND_INFO. + + * objc/Make-lang.in (objc-act.o): Depend on toplev.h. + + * objc/objc-act.c: Include toplev.h. + (lang_print_xnode): Mark parameters `file', `node' and `indent' + with ATTRIBUTE_UNUSED. + (finish_protocol): Likewise for parameter `protocol'. + + * output.h (declare_weak): Add prototype. + (decode_reg_name): Don't wrap with TREE_CODE macro. + (assemble_alias): Add prototype. + + * regclass.c: Include output.h. + + * reload.h (reloads_conflict): Add prototype. + + * rtl.h (print_rtl_single, mark_elimiation, reg_class_subset_p, + output_func_start_profiler): Add prototypes. + + * rtlanal.c (reg_set_p_1): Mark parameters `x' and `pat' with + ATTRIBUTE_UNUSED. + + * scan-decls.c: Include scan.h. + + * scan.h (recognized_function, recognized_extern): Add prototypes. + + * stmt.c: Include output.h. + + * toplev.c (error_for_asm, warning_for_asm): Remove prototypes. + (output_lang_identify): Hide prototype and definition. + (float_signal): Mark parameter `signo' with ATTRIBUTE_UNUSED. + (pipe_closed): Likewise. + + * toplev.h (count_error, strip_off_ending, error_for_asm, + warning_for_asm): Add prototypes. + +Wed May 13 12:54:19 1998 Michael Meissner + + * toplev.c (rest_of_compilation): "Charge" final for any time + doing various cleanup operations after finishing compilation + of a function. + + * flow.c (dump_flow_info): Also print number of sets and + whether or not the pseudo is a user variable. + + * flow.c (reg_n_max): New global variable. + * regclass.c (allocate_reg_info): Keep reg_n_max up to date. + Delete regno_max variable. + * regs.h (REG_N_CHECK): Define. + (REG_N_REFS, REG_N_SETS, REG_N_DEATHS): Use REG_N_CHECK. + (REG_N_CHANGES_SIZE, REG_N_CALLS_CROSSED, REG_LIVE_LENGTH): Likewise. + (REGNO_FIRST_UID, REGNO_LAST_UID, REGNO_LAST_NOTE_UID): Likewise. + +Wed May 13 12:54:19 1998 Martin von Loewis + + * acconfig.h (ENABLE_CHECKING): Undefine. + * configure.in (--enable-checking): New option. + +Wed May 13 08:52:08 1998 J"orn Rennecke + + * reload1.c (merge_assigned_reloads): Can merge + RELOAD_FOR_INPUT_ADDRESS and RELOAD_FOR_OTHER_ADDRESS even + if RELOAD_FOR_INPUT with the same reload_reg_rtx is present. + +Tue May 12 20:05:57 1998 Jim Wilson + + * collect2.c (main): Ignore do_collecting when COLLECT_EXPORT_LIST. + +Wed May 13 03:23:45 1998 J"orn Rennecke + + * reload1.c (gen_reload): Create REG_EQUIV notes. + +Tue May 12 22:21:07 1998 J"orn Rennecke + + * reload1.c (reload): Fix check for USEs to use code of pattern. + (choose_reload_regs): Remove dead variable use_insn. + +Tue May 12 14:04:49 1998 Jeffrey A Law (law@cygnus.com) + + * pa.h (DBX_CONTIN_LENGTH): Reduce to 3000 bytes. + +Tue May 12 15:16:02 1998 Michael Meissner + + * haifa-sched.c (HAIFA_INLINE): Define to be __inline unless + already defined. + (find_insn_{,mem_}list): Use HAIFA_INLINE, not __inline. + (insn_{unit,issue_delay}): Ditto. + (blockage_range): Ditto. + (actual_hazard{,_this_instance}): Ditto. + (schedule_unit): Ditto. + (potential_hazard): Ditto. + (insn_cost): Ditto. + (swap_sort): Ditto. + (queue_insn): Ditto. + (birthing_insn_p): Ditto. + (adjust_priority): Ditto. + (get_block_head_tail): Ditto. + (init_rgn_data_dependences): Ditto. + +Tue May 12 10:27:54 1998 Klaus Kaempf + + * alpha/vms.h (COMMON_ASM_OP, ASM_OUTPUT_ALIGNED_COMMON): Define. + +Tue May 12 11:44:14 1998 Gavin Koch + + * config/mips/mips.h (ASM_OUTPUT_ALIGN): Remove trailing semi-colon. + +Tue May 12 11:38:31 1998 Gavin Koch + + * config/mips/mips.md (dslot): Move after definition of "cpu" + attribute. Handle r3900 case. + +Tue May 12 10:21:36 1998 Kaveh R. Ghazi + + * system.h: Define the STRINGIFY macro here. + * protoize.c: Not here. + * gengenrtl.c (DEF_RTL_EXPR): Use the STRINGIFY macro. + +Tue May 12 00:47:33 1998 John Wehle (john@feith.com) + + * varasm.c (assemble_variable): Compute the alignment of the data + earlier so that both initialized and uninitialized variables are + effected by DATA_ALIGNMENT. + * tm.texi (DATA_ALIGNMENT): Updated appropriately. + +Mon May 11 19:57:58 1998 Jeffrey A Law (law@cygnus.com) + + * mips.c: Prototype static functions. + +Mon May 11 17:43:03 1998 Jim Wilson + + * regmove.c (fixup_match_2, find_matches, regmove_profitable): + Add explanatory comments. + + * sparc.h (SPARC_INCOMING_INT_ARG_FIRST): Support TARGET_FLAT. + +Mon May 11 17:24:27 1998 Richard Henderson + + * sparc.md (ffsdi2): Disable. Simplify the expression as well. + +Mon May 11 13:30:44 1998 Jim Wilson + + * varasm.c (make_decl_rtl): Disable April 1 change. + +Mon May 11 09:14:41 1998 Richard Henderson + + * configure.in (alpha-*-linux-gnu): Undo lossage from gcc2 merge. + +Mon May 11 08:24:18 1998 Richard Henderson + + * alpha.h (PRINT_OPERAND_PUNCT_VALID_P): Add '`'. + * alpha.c (print_operand): Handle it. + * alpha.md (fix_truncdfsi2, fix_truncsfsi2): New patterns and + related define_splits. Also add peepholes for SImode reload + plus sign_extend lossage. + +Mon May 11 09:33:10 1998 Kaveh R. Ghazi + + * genattr.c: Include stdarg.h/varargs.h. Change function + `fatal' to use variable arguments instead of faking it with + integer parameters. Provide a prototype which also + checks the format specifiers using ATTRIBUTE_PRINTF_1. + + * genattrtab.c: Likewise. + * gencodes.c: Likewise. + * genconfig.c: Likewise. + * genemit.c: Likewise. + * genextract.c: Likewise. + * genflags.c: Likewise. + * genopinit.c: Likewise. + * genpeep.c: Likewise. + * genrecog.c: Likewise. + * genoutput.c: Likewise. Similarly for function `error'. + +Sun May 10 02:27:03 1998 Kaveh R. Ghazi + + * acconfig.h (HAVE_VOLATILE): Insert stub for autoconf. + * alocal.m4 (GCC_C_VOLATILE): New autoconf test. + * configure.in: Use GCC_C_VOLATILE. + * system.h (volatile): Define as empty if no volatile support is + available. + +Sun May 10 01:21:43 1998 Jeffrey A Law (law@cygnus.com) + + * genemit.c (output_add_clobbers): Removed unused variable 'i' from + generated fucntion. + +Sat May 9 02:02:15 1998 Richard Henderson + + * loop.c (get_condition): Don't combine when either compare is MODE_CC. + * alpha.c (alpha_emit_conditional_branch): New function. Taken from + the body of beq; additionally set the mode of the branch to CCmode for + FP compares and not fast_math. + (alpha_emit_conditional_move): Always use a compare insn for FP + when not fast_math, as well as setting CCmode on the cmov. + * alpha.md (beq, bne, blt, et al): Call alpha_emit_conditional_branch. + + * machmode.h (COMPLEX_MODE_P): New macro. + +Sat May 9 01:53:23 1998 Richard Henderson + + * haifa-sched.c (print_exp): Fix typo. + +Fri May 8 21:48:50 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Fri May 8 18:23:08 1998 Michael Meissner + + * final.c (final_scan_insn): Call fatal_insn instead of abort if + we could not split an insn when required to. + + * m32r.md ({add,sub}di3): Add define_splits and appropriate low + level insns. + (peepholes): Disable peepholes that call dead_or_set_p. + (movsi): Rewrite to handle addresses better after last change. + Add define_split to split load of addresses in large/medium modes. + (prologue): Call m32r_expand_prologue. + (movsi_{push,pop}): Generators for push/pop. + (movsi): Support PRE_{INC,DEC}, POST_INC. + (mov{di,df}): Rewrite. Always split the insns. + (movsf): Add define_split to get register load in correct mode. + (cmp_ne_small_const_insn): Use 'N' instead of 'S' constraint. + (attributes): Rewrite attributes so that type indicates both the + type and the length of the insn directly. + (all insns): Change to use new type attributes. + (debug): New attribute to convey whether -mdebug was used. + (opt_space): New attribute to convey whether -Os was used. + (function units): Loads are 3 cycles, not 2. Better classify all + insns into short/long. + (load/store/extend insns): Add separate case for load/store + indirect operations without an offset. + (divsi3): Division is a long operation, not short. + + * m32r.h (LEGITIMATE_LO_SUM_ADDRESS_P): Do not allow LO_SUM for + modes > 1 word. + (GO_IF_MODE_DEPENDENT_ADDRESS): LO_SUM is now mode dependent. + (CONST_OK_FOR_LETTER_P): Make 'N' handle reverse 8 bit compares. + (EXTRA_CONSTRAINT): Remove 'S' special support. Add 'U' for + operands with PRE_{INC,DEC}, POST_INC. + (FUNCTION_PROFILER): Call abort instead of doing nothing. + (GO_IF_LEGITIMATE_ADDRESS): Allow PRE_{INC,DEC}, POST_INC of + SImode variables. + (gen_split_move_double): Declare. + (EXTRA_CONSTRAINT): Add 'T' for memory reference with no offset. + + * m32r.c (gen_split_move_double): Fix typo. Also, don't call + emit_move_insn, build up SET's directly. + (toplevel): Include system.h, not stdio.h. + (move_double_src_operand): Allow any DF or DI mode constant. + (gen_split_move_double): Split moves of DI or DF values into the + appropriate moves, loads, or stores. Don't handle use of auto + inc/dec if using dead index. Do handle overlapping moves, etc. + (m32r_frame_info): Remove prologue_size field. + (m32r_compute_frame_size): Don't calculate prologue size. + (m32r_output_function_prologue): Change to pretty much a NOP. + (m32r_expand_prologue): Expand prologue as a series of INSNs. + (m32r_print_operand): Add support for PRE_{INC,DEC}, POST_INC. + (m32r_print_operand_address): Ditto. + +Fri May 8 14:13:21 1998 H.J. Lu (hjl@gnu.org) + + * reload1.c (emit_reload_insns): When performing expensive + optimizations, do not output the last reload insn if OLD is + not the dest of NSN and is in the src and is clobbered by INSN. + +Fri May 8 09:47:29 1998 Kaveh R. Ghazi + + * Makefile.in (genrtl.o): Depend on system.h. + * gengenrtl.c (gencode): When creating genrtl.c, have it + include system.h. + +Fri May 8 10:57:33 1998 Andreas Schwab + + * config/m68k/t-linux: Remove extra stuff already included in + config/t-linux. + +Fri May 8 09:53:24 Paul Eggert + + * fixinc.wrap: Renamed from fixinc.math. Put wrapper around + curses.h if it contains `typedef char bool;', as suggested by + Manfred Hollstein . + + * configure.in: Rename fixinc.math to fixinc.wrap. + +Thu May 7 19:26:34 1998 Jim Wilson + + * gcc.c (read_specs): Handle missing blank line at end of specs file. + + * i386.md (movsicc, movhicc, movsicc_1, movhicc_1, movsfcc_1, + movdfcc_1): Disable. + +Thu May 7 15:39:14 1998 Jim Wilson + + * configure.in (enable_threads): Rename to enable_threads_flag before + main loop. Set enable_threads to enable_threads_flag inside main + loop. + +Thu May 7 17:38:03 1998 Michael Meissner + + * r6000/eabi.asm (__eabi): Restore LR in case __eabi is called + multiple times. + +Thu May 7 14:26:05 1998 Kaveh R. Ghazi + + * aclocal.m4 (GCC_FUNC_VFPRINTF_DOPRNT): New macro. + + * configure.in: Add a call to GCC_FUNC_VFPRINTF_DOPRNT. + (AC_CHECK_HEADERS): Remove unused check for varargs.h,sys/varargs.h. + (AC_CHECK_FUNCS): Remove unused check for vprintf. + + * Makefile.in: Add support for linking in vfprintf.c and doprint.c. + (cccp.o): Depend on gansidecl.h. + (cexp.o): Likewise. + + * cccp.c: Convert from using PRINTF_ALIST/PRINTF_DCL to VPROTO as + per the rest of gcc source. + * cexp.y: Likewise. Include gansidecl.h and remove all code made + redundant. + + * cccp.c: Remove checks for HAVE_VPRINTF and the associated code + used when vfprintf is missing. + * cexp.y: Likewise. + * gcc.c: Likewise. + * genattrtab.c: Likewise. + * mips-tfile.c: Likewise. + * toplev.c: Likewise. + + * vfprintf.c: New file. + * doprint.c: New file. + +Thu May 7 10:18:41 1998 Jeffrey A Law (law@cygnus.com) + + * config/linux.h (ASM_COMMENT_START): Remove from here, + * config/linux-aout.h (ASM_COMMENT_START): and here, + * config/i386/linux.h (ASM_COMMENT_START): to here, + * config/i386/linux-aout.h (ASM_COMMENT_START): and here. + * config/i386/linux-oldld.h (ASM_COMMENT_START): Define + here as '#' too. + +Thu May 7 10:55:59 1998 Andreas Schwab + + * config/m68k/m68k.md (adddi3, subdi3): Properly negate the DImode + constant. + +Wed May 6 22:32:37 CDT 1998 Robert Lipe + + * Makefile.in (dwarfout.o) Add toplev.h dependency. + * dwarfout.c, i386.c: Include toplev.h + * toplev.h: (pfatal_with_name) Add prototype. + +Wed May 6 19:02:29 1998 Jason Merrill + + * Makefile.in: Fix .SUFFIXES. + +Wed May 6 19:31:32 1998 Alan Modra + + * config/linux.h (ASM_COMMENT_START): Define as "#". + * config/linux-aout.h (ASM_COMMENT_START): Likewise. + +Wed May 6 15:51:39 1998 Jim Wilson + + * objc/Make-lang.h (objc-parse.o): Add toplev.h dependency. + * objc/objc-parse.y, objc/objc-parse.c: Regenerate. + + * toplev.c: Include toplev.h. + * Makefile.in (c-common.o, c-convert.o, c-decl.o, c-iterate.o, + c-lex.o, c-parse.o, c-pragma.o, c-typeck.o, calls.o, convert.o, + dwarf2out.o, except.o, expr.o, final.o, fold-const.o, function.o, + hash.o, profile.o, real.o, reg-stack.o, regclass.o, reload.o, + reload1.o, stmt.o, stor-layout.o, tlink.o, tree.o, varasm.o): Add + toplev.h dependency. + + * mips/mips.c (save_restore_insns): Change FRAME_POINTER_REGNUM to + HARD_FRAME_POINTER_REGNUM. + + * expr.c (target_temp_slot_level): Delete duplicate definition. + +Wed May 6 16:46:01 1998 Jeffrey A Law (law@cygnus.com) + + * stmt.c (mark_seen_cases): Make it have external linkage again. + * expr.h (mark_seen_cases): Add declaration, but only when tree.h + has been included. + + * haifa-sched.c (print_value, case SUBREG): Fix typo. + + * i386.c (output_387_binary_op): Add some braces to avoid warnings. + * i386.h (REG_CLASS_CONTENTS): Similarly. + + * toplev.c (-fsched-max): Delete flag. + (-fsched-interblock-max-blocks,-fsched-interblock-max-insns): Likewise. + * haifa-sched.c: Remove -fsched-max-N, -fsched-interblock-max-blocks-N + and -fsched-interblock-max-insns-N support. Remove INTERBLOCK_DEBUG + conditionals. + + * haifa-sched.c (find_rgns): Correctly handle reducible loops with + inner loops which are not reducible. + + * loop.c (regs_match_p): Fix typo in prototype. + + * regmove.c (try_auto_increment): Wrap declaration inside an + #ifdef AUTO_INC_DEC. + +Wed May 6 17:07:47 1998 Michael Meissner + + * final.c (output_operand_lossage): Call fatal with the operand + lossage message instead of calling abort. + +Wed May 6 15:37:27 1998 Kaveh R. Ghazi + + * c-common.c: Convert to using ctype macros defined in system.h. + * c-lex.c: Likewise. + * cccp.c: Likewise. + * collect2.c: Likewise. + * rs6000.c: Likewise. + * cpplib.c: Likewise. + * fix-header.c: Likewise. + * gcc.c: Likewise. + * gen-protos.c: Likewise. + * pexecute.c: Likewise. + * protoize.c: Likewise. + * rtl.c: Likewise. + * scan.c: Likewise. + * stmt.c: Likewise. + * tlink.c: Likewise. + * toplev.c: Likewise. + +Wed May 6 14:44:14 1998 Gavin Koch + + * config/mips/r3900.h (SUBTARGET_ASM_DEBUGGING_SPEC) : + Replace -gdwarf-2 with -g0. + +Wed May 6 11:43:18 1998 Kaveh R. Ghazi + + * Makefile.in (mips-tfile.o, mips-tdump.o): Depend on system.h. + * mips-tdump.c: Include system.h, remove redundant headers. + * mips-tfile.c: Likewise. Also, convert all ctype function calls + to calls of the macro versions defined in system.h. + + * objc/Make-lang.in (objc-act.o): Depend on system.h. + * objc/objc-act.c: Include system.h, remove redundant headers. + +Wed May 6 11:21:06 1998 Kaveh R. Ghazi + + * configure.in (AC_CHECK_FUNCS): Add isascii. + (GCC_NEED_DECLARATIONS): Add atof. + + * system.h: Provide prototypes for abort, atof, atol and sbrk here. + * rtl.c, rtl.h, toplev.c, tree.h: Not here. + +Wed May 6 10:52:49 1998 Kaveh R. Ghazi + + * system.h: Wrap time.h and sys/file.h in autoconf checks. + Provide default definitions for O_RDONLY and O_WRONLY here. + + * cccp.c, cpplib.c, fix-header.c, gcc.c, protoize.c: Not here. + +1998-05-06 Mark Mitchell + + * tree.h (IS_EXPR_CODE_CLASS): Remove bogus '3'. + +Wed May 6 06:35:38 1998 Robert Lipe + + * toplev.h: New file. Protypes for functions in toplev.c. + * tree.h, rtl.h: Deleted protos for functions in toplev.c. + * c-common.c, c-convert.c, c-decl.c, c-iterate.c, c-lex.c, + c-parse.in, c-parse.y, c-pragma.c, c-typeck.c, calls.c, + convert.c, dwarf2out.c, except.c, expr.c, final.c, fold-const.c, + function.c, hash.c, profile.c, real.c, reg-stack.c, regclass.c, + reload.c, reload1.c, stmt.c, stor-layout.c, tlink.c, tree.c, + varasm.c: include it. + +Wed May 6 01:09:01 1998 Jeffrey A Law (law@cygnus.com) + Jim Wilson (wilson@cygnus.com) + + * haifa-sched.c (find_rgns): In no_loops case, fix test for leaf + blocks. Check for 1 successor which is the EXIT_BLOCK. + + * haifa-sched.c (find_rgns): Detect unreachable blocks, including + unreachable loops with more than one block. + +Wed May 6 08:22:24 1998 Manfred Hollstein + + * fix-header.c (write_rbrac): Add "abort" to functions which need to + be protected. + +Wed May 6 00:09:36 1998 Jeffrey A Law (law@cygnus.com) + + * Check in merge from gcc2. See ChangeLog.12 for details. + +Tue May 5 14:33:49 1998 Jim Wilson + + * c-common.c (scan_char_table): Separate 's' and 'c'. 'c' does not + accept 'a' flag. 'S' does accept 'a' flag. + (check_format_info): When pedantic, warn for m/C/S/a/A formats, + and `a' flag. + + * elf64.h (MULTILIB_DEFAULTS): Move definition after mips.h include. + +Tue May 5 10:50:39 1998 Andreas Schwab + + * config/m68k/m68k.h: Declare functions from m68k.c used in + macros and machine description. + (ASM_OUTPUT_LONG_DOUBLE): Always use `l' flag in print format for + long values. + (ASM_OUTPUT_FLOAT): Likewise. + (ASM_OUTPUT_FLOAT_OPERAND): Likewise. + +Tue May 5 01:28:12 1998 Jason Merrill + + * tree.def: Add NAMESPACE_DECL. + * dwarfout.c (type_ok_for_scope): Ignore NAMESPACE_DECLs for now. + * dwarf2out.c (push_decl_scope): Likewise. + (scope_die_for): Likewise. + * tree.c (decl_function_context): Use TREE_CODE_CLASS to determine + how to get next context level. + +Tue May 5 01:43:16 1998 Jim Wilson + + * i386.c (output_fix_trunc): Add code to emulate non-popping DImode + case. + +Tue May 5 01:15:06 1998 Jeffrey A Law (law@cygnus.com) + + * h8300.h (ADDITIONAL_REGISTER_NAMES): Add "er" registers. + + * reorg.c (fill_slots_from_thread): Update REG_DEAD/REG_UNUSED notes + for any insns skipped at the start of a block because they were + redundant. + +Mon May 4 20:23:51 1998 Jim Wilson + + * alpha.h (DBX_CONTIN_LENGTH): Decrease to 3000. + +1998-05-04 Ulrich Drepper + + * c-common.c (format_char_info): Add new field hhlen. + (print_char_table, scan_char_table, time_char_table): Initialize + hhlen field appropriately. + (char_format_info): Recognize hh modifier and lookup correct char + table entry. + +Mon May 4 19:15:29 1998 Jim Wilson + + * expr.c (expand_expr, case INDIRECT_REF): Don't optimize string + reference if this is a store. + +Mon May 4 17:25:17 1998 Richard Henderson + + * sparc.c (output_move_quad): Fix typo in mov_by_64 argument. + +Sun May 3 23:57:25 1998 Robert Lipe + + Make UnixWare 7 bootstrap support work with final shipping product. + * configure.in: (i[34567]86-*-sysv5): append, not overwrite, xm_file. + Pick up xm-siglist and xm-alloca. + (xm_defines): Add USG so dbxout will build. + * configure: Regenerate. + +Sun May 3 13:51:34 PDT 1998 Richard Henderson + + Support for official Sparc V9 ABI: + * sparc.c (sparc_override_options): Force stack bias off for !arch64. + Care for flag_pcc_struct_return default. + (output_move_quad): Rewrite to move by halves on v9 and in the + proper direction. + (move_quad_direction): New function. + (output_fp_move_quad): Use it to determine the direction of copy. + (function_arg_slotno): Return -1 for FP reg overflow as well. + (function_arg_record_value*): New functions. + (function_arg): Use them. Streamline unprototyped parameter passing. + (function_arg_pass_by_reference): Pass TCmode by reference. + (function_value): New function. + * sparc.h (PTRDIFF_TYPE, SIZE_TYPE): For -pedantic's sake, don't use + long long in 64-bit mode. + (RETURN_IN_MEMORY): v9 returns structs < 32-bytes in regs. + (DEFAULT_PCC_STRUCT_RETURN): Make the default detectable. + (BASE_RETURN_VALUE_REG): Consider complex float types for arch64. + (BASE_OUTGOING_VALUE_REG, BASE_PASSING_ARG_REG): Likewise. + (BASE_INCOMING_ARG_REG): Likewise. + (FUNCTION_VALUE): Call function_value. + (FUNCTION_OUTGOING_VALUE, LIBCALL_VALUE): Likewise. + * sparc.md (movdi_sp32_v9): Disable for arch64. + (movsf, movdf, movtf): Sort all ulternatives using fp regs first. + (call_value_address_sp64): Remove register class constraints. + (call_value_symbolic_sp64): Likewise. + (nonlocal_goto): Pass label reg directly to goto_handlers. Constrain + v9 case to 32-bit constants. + (goto_handler_and_restore_v9): Provide a version for arch64. + * sparc/linux64.h (SIZE_TYPE, PTRDIFF_TYPE): Remove private definition. + * sparc/sp64-aout.h (TARGET_DEFAULT): Turn on stack bias. + (CPP_PREDEFINES): New. + * sparc/sp64-elf.h: Likewise. + (PREFERRED_DEBUGGING_TYPE): Dwarf2. + (ASM_OUTPUT_DWARF2_ADDR_CONST): New. + * sparc/sysv4.h (SIZE_TYPE, PTRDIFF_TYPE): Undo svr4.h's changes. + +Sat May 2 17:47:17 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sat May 2 01:37:29 1998 J"orn Rennecke + + * reload.c (find_reloads): Emit USEs to mark where a pseudo + is reloaded with the MEM of its stack slot. + * reload1.c (cannot_omit_stores): Delete. + (reload): Don't initialize it. + Don't apply avoid_return_reg logic to USEs. + When done, remove USEs that have a REG_EQUAL note on them. + (emit_reload_insns): Handle case where we have inherited a MEM. + (choose_reload_regs): Likewise. + (delete_output_reload): Don't use cannot_omit_stores. + +Thu Apr 30 18:59:03 1998 Jim Wilson + + * Makefile.in (cpp.info, gcc.info): Put -o option before input file. + +Thu Apr 30 16:57:34 1998 Michael Meissner + + * haifa-sched.c (print_{exp,value}): Various changes to make the + debug output easier to read. Also, use only one buffer, and make + sure the buffer we are passed in doesn't overflow. + (safe_concat): Concatenate to a buffer without overflow. + +Thu Apr 30 16:57:34 1998 Kaveh R. Ghazi + + * haifa-sched.c (alloc_{INSN,EXPR}_LIST): Make static to agree + with the prototype. + +Wed Apr 29 21:45:16 1998 J"orn Rennecke + + * sched.c (new_insn_dead_notes): Check if the register was + used in the original instruction. + * haifa-sched.c (new_insn_dead_notes): Likewise. + +Wed Apr 29 13:46:03 1998 Jim Wilson + + * dwarf2out.c (scope_die_for): If could not find proper scope, + check for and handle tagged type with incorrect TYPE_CONTEXT. + +Wed Apr 29 15:34:40 1998 John Carr + + * calls.c (expand_call): Fix recognition of C++ operator new. + + * alias.c (mode_alias_check): Disable type based alias detection. + +Wed Apr 29 15:06:42 1998 Gavin Koch + + * config/mips/elf.h (ASM_OUTPUT_DEF,ASM_WEAKEN_LABEL, + ASM_OUTPUT_WEAK_ALIAS): Define. + * config/mips/elf64.h: Same. + * config/mips/r3900.h (ASM_OUTPUT_DEF,SUPPORTS_WEAK, + ASM_WEAKEN_LABEL): Removed. + +Wed Apr 29 10:53:29 1998 Andreas Schwab + + * calls.c (expand_call): Bump the length limit on the specially + recognized function names to 17. + +Tue Apr 28 17:53:33 1998 Jim Wilson + + * ginclude/stddef.h: Add check for _MACHINE_ANSI_H_ for BSD/OS + when undefining macros at the end. + + * expr.c (expand_builtin, case BUILT_IN_MEMSET): Break if either + val or len has TREE_SIDE_EFFECTS set. + + * sparc.md (mulsidi3): Call const v8plus and v8plus routines. + (mulsidi3_v8plus, const_mulsidi3_v8plus): Delete asterisk from name. + (smuldi3_highpart): Call const v8plus routine. + (smulsi3_highpart_v8plus): Renamed from smulsidi3_highpart_v8plus. + (const_smulsi3_highpart_v8plus): New pattern. + (smulsi3_highpart_sp32): Renamed from smulsidi3_highpart_sp32. + (umulsidi3): Call const v8plus routine. + (umulsi3_highpart): Handle const before v8plus. Call const v8plus + routine. + (umulsi3_highpart_v8plus): Renamed from umulsidi3_highpart_v8plus. + (umulsi3_highpart_sp32): Renamed from umulsidi3_highpart_sp32. + +Tue Apr 28 08:55:26 1998 Michael Meissner + + * m32r.c (*_oper{and|ator}): Change enum arguments and return + values to int, so they can be prototyped even in files that don't + include rtl.h. + ({small,large}_insn_p): Ditto. + (m32r_select_cc_mode): Ditto. + (gen_compare): Ditto. + (function_arg_partial_nregs): Ditto. + (m32r_setup_incoming_varargs): Ditto. + (init_reg_tables): Add prototype. + (m32r_frame_info): Add prolog_size field. + (m32r_compute_frame_size): Calculate the size of the prologue. + (m32r_first_insn_address): Return prologue size. + (m32r_output_function_prologue): Calculate frame size before + printing out information. Print out the prologue size. + + * m32r.h: Prototype all functions in m32r.c. + (FIRST_INSN_ADDRESS): Declare, returning prologue size. + + * m32r.md (bcc functions): Cast enum's to int. + + * m32r.c (conditional_move_operand): Silence a debug message. + ({small,long}_insn): New predicates. + + * m32r.h (TARGET_M32R): New macro. + (PREDICATE_CODES): Rearrange somewhat, add small_insn/long_insn. + (HAIFA_P): Define as 1/0 depending on whether the Haifa scheduler + was selected. + (ISSUE_RATE): Define as 2. + + * m32r.md (insn_size): New attribute. + ({,rev_}branch_insn): Add .s qualifier to branches believed to be + short. + (m32r): New attribute. + + * configure.in (enable_haifa): Switch m32r to Haifa by default. + * configure: Regenerate. + + (Changes from Nick Clifton ) + * m32r.h (EXTRA_CONSTRAINT): Implement 'S' constraint to perfoirm + the equivalent of a negated 'I' constraint. + (PRESERVE_DEATH_INFO_REGNO_P): Define in order to allow peephole + optimisation to work. + + * m32r.md (cmp_ne_small_const_insn): Use 'S' constriant rather + than 'I' since the value is negated. + (peephole): Add peephole optimisation to cope with optimization of + divide and subtracts of the same operands. + + * m32r.c zero_and_one, emit_cond_move): Add support for MVFC. + * m32r.h: Ditto. + * m32r.md: Ditto. + + * m32r.h (PREDICATE_CODES): Add declaration of machine specific + predicates. + +Tue Apr 28 07:25:53 1998 Manfred Hollstein + + * Makefile.in (libgcc2.ready): Revert last patch (Apr 24). + +Mon Apr 27 18:39:47 1998 Nick Clifton + + * config/arm/thumb.h (GO_IF_LEGITIMATE_ADDRESS): Check against + frame_pointer_rtx not FRAME_POINTER_REGNUM. + +Mon Apr 27 18:36:28 1998 Jim Wilson + + * reg-stack.c: Revert last patch (Apr 20). + (convert_regs): Set insn to PREV_INSN (next) after do while loop. + + * m68k/lb1sf68.asm (Laddsf$3): Fix typos in mcf5200 exg code. + + * loop.c (check_dbra_loop): New locals jump, first_compare, and + compare_and_branch. Call get_condition to set first_compare. + Set compare_and_branch to number of compare/branch instructions. + Replace PREV_INSN (PREV_INSN (loop_end)) with first_compare. + Replace '2' with compare_and_branch. + +Mon Apr 27 15:53:30 EDT 1998 Andrew MacLeod + + * cplus-dem.c (demangle_qualified): Replace missing else. + +Mon Apr 27 20:22:08 1998 J"orn Rennecke + + * sh.c (gen_ashift_hi): Don't make SUBREG of a SUBREG. + +Mon Apr 27 18:23:51 1998 J"orn Rennecke + + * sh.c (sh_expand_prologue, sh_expand_epilogue): + If TARGET_DOUBLE_ALIGN, preserve 64 bit stack alignment. + * sh.h (STACK_BOUNDARY): Likewise. + +Mon Apr 27 17:22:48 1998 J"orn Rennecke + + * sh.h (LEGITIMIZE_RELOAD_ADDRESS): Define. + +Mon Apr 27 08:55:23 1998 Michael Meissner + + * system.h (abort): If abort is not defined, and neither is + USE_SYSTEM_ABORT, redefine abort to call fprintf and exit, + reporting the line and filename of the error. + + * .gdbinit: Add breakpoints on exit and fancy_abort. + + * final.c (split_double): Avoid a compiler warning if + BITS_PER_WORD is less than or equal to HOST_BIT_PER_WIDE_INT. + + * rtl.h (JUMP_{CROSS_JUMP,NOOP_MOVES,AFTER_REGSCAN}): New macros + for calling jump_optimize. + + * toplev.c (rest_of_compilation): Call jump_optimize using JUMP_* + macros, rather than 0/1's. + +Sun Apr 26 23:19:10 1998 Richard Henderson + + * alpha.h (CONST_COSTS): Zero is always free. + (RTX_COSTS): Add EV6 costs. Abort if alpha_cpu is unknown. + +Sun Apr 26 15:38:50 1998 Andreas Schwab + + * cplus-dem.c (gnu_special): Fix off-by-one bug when checking the + length in the name of a virtual table. + +Sun Apr 26 01:21:06 1998 Richard Henderson + + * alpha.c (print_operand): Don't add 'v' suffix for ALPHA_FPTM_N. + +Sat Apr 25 22:11:38 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sat Apr 25 17:17:15 1998 Jeffrey A Law (law@cygnus.com) + + * fold-const.c (fold_convert): Fix typo. + +Sat Apr 25 17:55:54 1998 John Carr + + * alias.c (alias_invariant): New variable. + (record_base_value): New argument INVARIANT. + (memrefs_conflict_p): If a register has an entry in the alias_invariant + array, try substituting that value for the register. + + * rtl.h: Declare record_base_value. + + * loop.c, unroll.c: Update callers of record_base_value. + + * alias.c (find_base_value, find_base_term): SIGN_EXTEND and + ZERO_EXTEND do not affect base values. + +Fri Apr 24 15:57:02 1998 Jeffrey A Law (law@cygnus.com) + + * dbxout.c (dbxout_type): Fix typo. + (dbxout_range_type): Another HOST_WIDE_INT_PRINT_DEC fix. + + * configure.in: Use CC_FOR_BUILD, not BUILD_CC. + +Fri Apr 24 16:11:47 1998 John Carr + + * expr.c (expand_builtin, case MEMSET): Set MEM_IN_STRUCT_P + if the argument is the address of a structure or array. + + * configure.in: Enable Haifa scheduler by default for SPARC. + +Fri Apr 24 20:55:47 1998 J"orn Rennecke + + * cse.c (cse_set_around_loop): Don't do optimization when + new pseudos are created. + +Fri Apr 24 11:00:18 1998 Jeffrey A Law (law@cygnus.com) + + * dbxout.c (dbxout_type_fields): Use HOST_WIDE_INT_PRINT_DEC + appropriately. + (dbxout_type_method_1, dbxout_type): Likewise. + (print_int_cst_octal, print_octal, dbxout_symbol): Likewise. + (dbxout_type): Fix check for when to print a type range in + octal vs decimal. + +Fri Apr 24 16:45:03 1998 J"orn Rennecke + + * (gen_shl_and, in case 1): Fix comparison with mask. + +Fri Apr 24 06:46:40 1998 Nick Clifton + + * config/arm/thumb.h (GO_IF_LEGITIMATE_ADDRESS): Disallow frame + pointer as second register in REG+REG pair. + +Fri Apr 24 09:22:23 1998 Kaveh R. Ghazi + + * c-common.c (check_format_info): Don't check for the 'x' format + character twice, instead check for 'x' and 'X' + +Fri Apr 24 08:02:30 1998 Manfred Hollstein + + * Makefile.in (libgcc2.ready): Add explicit dependancy from + $(STMP_FIXPROTO) to ensure all necessary include files have + been created and to guarantee proper parallel builds. + +Fri Apr 24 04:42:35 1998 J"orn Rennecke + + * sh.c (sh_expand_prologue, in !SH3E code): Don't push an extra + register for stdarg functions. + * sh.h (current_function_varargs): Declare. + (FUNCTION_ARG): Ignore NAMED for stdarg functions. + +1998-04-23 Jim Wilson + + * frame.c, libgcc2.c (stdlib.h, unistd.h): Don't include when + inhibit_libc is defined. + + * c-aux-info.c (gen_type): Use DECL_NAME only for TYPE_DECL. + +Thu Apr 23 19:09:33 1998 Jim Wilson + + * profile.c (tablejump_entry_p): New function. + (branch_prob): Add code to recognize MIPS tablejump entry branch. + Use tablejump_entry_p in MIPS and HPPA tablejump checking code. + +Thu Apr 23 15:01:13 1998 Nick Clifton + + * config/arm/arm.c (find_barrier): Return as soon as a barrier is + found, rather than at end of the loop, after the insn has been + changed. + +Thu Apr 23 20:21:06 1997 J"orn Rennecke + + * sh.c (gen_ashift_hi): Implement right shifts via gen_ashift. + * sh.md (ashrhi3_k, lshrhi3_k, lshrhi3_m, lshrhi3, lshrhi3+1): Delete. + +Wed Apr 22 17:07:35 1998 Michael Meissner + + * loop.c (note_addr_stored): Correct function to take 2 arguments, + instead of 1. + + * rtl.def (MATCH_INSN2): Add new matching pattern. + * genrecog.c (add_to_sequence): Support MATCH_INSN2. + +Wed Apr 22 15:52:22 1998 John Carr + + * emit-rtl.c (gen_highpart): The high part of a CONST_INT is not zero + if HOST_BITS_PER_WIDE_INT is larger than BITS_PER_WORD. + + * final.c (split_double): Sign extend both halves of a split CONST_INT. + +Wed Apr 22 10:42:45 1998 Jeffrey A Law (law@cygnus.com) + + * mips.c (compute_frame_size): Change only argument to a HOST_WIDE_INT. + +Wed Apr 22 10:53:49 EDT 1998 Andrew MacLeod + + * cplus-dem.c (struct work stuff): Add field for B and K mangle codes. + (cplus_demangle_opname): Call mop_up_squangle. + (cplus_demangle): Initialize squangle info, then call + internal_cplus_demangle. (Most code moved there as well) + (internal_cplus_demangle): New function, performs most of what use + to be done in cplus_demangle, but is only called with this file. + (squangle_mop_up): New function to clean up B and K code data. + (mop_up): set pointers to NULL after freeing. + (demangle_signature, demangle_template, demangle_class): Add + switch elements to handle K and B codes. + (demangle_prefix, gnu_special, demangle_qualified): Add + code to handle K and B codes. + (do_type, demangle_fund_type): Handle B and K codes. + (remember_Ktype): New function to store K info. + (register_Btype, remember_Btype): New functions for B codes. + (forget_B_and_K_types): New function to destroy B and K info. + +1998-04-21 Jim Wilson + + * stmt.c (check_seenlabel): When search for line number note for + warning, handle case where there is no such note. + +Tue Apr 21 20:48:37 1998 John Carr + + * genemit.c (gen_exp): Allow machine description to set mode of + MATCH_OP_DUP. + +Tue Apr 21 16:36:01 1998 John Carr + + * alias.c (mode_alias_check): New function. + (true_dependence, anti_dependence, output_dependence): Call + mode_alias_check. + +Tue Apr 21 12:05:32 1998 Jeffrey A Law (law@cygnus.com) + + * mips.h (STACK_BOUNDARY): Allow specific targets to override. + (MIPS_STACK_ALIGN): Similarly. + + * c-common.c (type_for_mode): Handle TI types. + * c-decl.c (intTI_type_node, unsigned_int_TI_type_node): Define. + (init_decl_processing): Handle TI types. + * c-tree.h (intTI_type_node, unsigned_int_TI_type_node): Declare. + + * mips.c (block_move_loop): Test Pmode == DImode instead of + TARGET_MIPS64. + (expand_block_move, save_restore_insns): Likewise. + (function_prologue, mips_expand_prologue): Likewise. + (mips_expand_epilogue): Likewise. + * mips.h (POINTER_SIZE): Allow specific targets to override. + (Pmode): Allow specific targets to override. + (FUNCTION_PROFILER): Test Pmode == DImode instead of TARGET_MIPS64 + (POINTER_BOUNDARY, FUNCTION_MODE): Likewise. + (TRAMPOLINE_TEMPLATE, TRAMPOLINE_SIZE): Likewise. + (TRAMPOLINE_ALIGNMENT, INITIALIZE_TRAMPOLINE): Likewise. + (CASE_VECTOR_MODE, ASM_OUTPUT_ADDR_VEC_ELT): Likewise. + (ASM_OUTPUT_ADDR_DIFF_ELT, SIZE_TYPE, PTRDIFF_TYPE): Likewise. + * mips.md (indirect, tablejump & casesi support): Test for + Pmode == DImode instead of TARGET_MIPS64. + (call patterns): Likewise. + +Tue Apr 21 09:43:55 1998 Kaveh R. Ghazi + + * objc/sendmsg.c: Define gen_rtx_MEM() to 1, as is already done + for gen_rtx(MEM, ...). + +Tue Apr 21 02:15:36 1998 Richard Henderson + + * sparc.h (MACHINE_STATE_SAVE, MACHINE_STATE_RESTORE): Rewrite + to not be so gross, and to properly function with PIC. + +Mon Apr 20 20:44:25 1998 Jim Wilson + + * frame.c (heapsort): Rename to frame_heapsort. + + * gcc.c (do_spec_1, case '['): Move flag out of loop and initialize it. + +Mon Apr 20 12:43:09 1998 Doug Evans + + * flow.c (sbitmap_vector_alloc): Ensure sbitmaps properly aligned. + +Mon Apr 20 15:04:14 1998 John Wehle (john@feith.com) + + * i386.md (movsf_push, movdf_push, movxf_push): Allow memory + operands during and after reload. + +Mon Apr 20 22:37:50 1998 J"orn Rennecke + + * final.c (shorten_branches, init_insn_lengths): Move code + to free label_align, uid_shuid, insn_lengths, insn_addresses + and uid_align from the former function into the latter one; + Add code to clear these variables. + * sh.h (label_align): Remove declaration. + +Mon Apr 20 14:48:29 1998 Michael Meissner + + * gcc.c (lang_specific_driver): Declare prototype properly so + fatal can be passed to it without error. + + * configure.in (AC_CHECK_FUNCS): Check for strchr and strrchr. + * configure: Regenerate. + * config.in: Add #undef's for strchr and strrchr. + + * protoize.c (toplevel): If we have rindex, but not strrchr, map + rindex to strrchr. + (file_could_be_converted): Use strrchr, not rindex since rindex is + not defined on Linux systems when _POSIX_SOURCE is defined. + (file_normally_convertible): Ditto. + (process_aux_info_file): Ditto. + (main): Ditto. + + * rs6000.md (mov{sf,df} define_splits): When splitting a move of + a constant to an integer register, don't split the insns that do + the simple AND and OR operations, rather just split each word, and + let the normal movsi define split handle it further. + +Mon Apr 20 18:19:40 1998 J"orn Rennecke + + * sh.c (find_barrier): Fix bug in ADDR_DIFF_VEC handling. + (split_branches): Call init_insn_lengths. + +Mon Apr 20 07:37:49 1998 Michael Meissner + + * i386.c: Include expr.h to get the change_address prototype + declared. + +Mon Apr 20 01:00:05 1998 H.J. Lu (hjl@gnu.org) + + * reg-stack.c (subst_asm_stack_regs): Change to return the last + new insn generated by this function. + (subst_stack_regs): Likewise. + (convert_regs): Record the last newly generated insn and use + it for change_stack () instead of INSN. + +Sun Apr 19 15:41:24 1998 Manfred Hollstein + + * fix-header.c (enum special_file): Undefine enumerators if they + are already defined by include files. + * fixproto (rel_source_file in unistd.h stdlib.h): Prefix file protection + macro with '__' to not pollute user namespace. + +Sun Apr 19 02:42:06 1998 Richard Henderson + + * haifa-sched.c (queue_to_ready): Fix typo in prototype. + +Sat Apr 18 23:52:35 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sat Apr 18 18:30:22 1998 Jim Wilson + + * i386.md (fix_truncsfdi2+[123]): Add + to operand 1 constraints. + + * i386.h (CPP_CPU_DEFAULT): Renamed to CPP_CPU_DEFAULT_SPEC. + Add missing -Dpentium* options. + (CPP_CPU_SPEC): Delete redundant definition. Include cpp_cpu_default + instead of CPP_CPU_DEFAULT. + (EXTRA_SPECS): Add entry for cpp_cpu_default. + +Sat Apr 18 19:06:59 1998 David Edelsohn + + * rs6000.md (floatsidf2_loadaddr): rs6000_fpmem_offset will be + negative in a stackless frame. + * rs6000.c (rs6000_stack_info): Don't include fixed-size link area + in stackless frame size. Support 64-bit stackless frame size. + Combine fpmem offset calculations and don't add total_size to + offset if not pushing a stack frame. + +Sat Apr 18 15:41:16 1998 Jim Wilson + + * regmove.c (fixup_match_1): In three places, in flag_exceptions + check, change p to q. + +Sat Apr 18 15:30:49 1998 Jim Wilson + + * gcc.c (lang_specific_driver): Add new parm type to prototype. + (added_libraries): New file scope static variable. + (process_command): Initialize added_libraries. Pass it to + lang_specific_driver. + (main): Use added_libraries in check for no input files. + +Sat Apr 18 01:23:11 1998 John Carr + + * sparc.c, sparc.h, sparc.md, sol2.h: Many changes related to V9 + code generation. Use 64 bit instructions in 32 bit mode when + possible. Use V9 return instruction. UltraSPARC optimizations. + + * sparc.h: Change gen_rtx (CODE to gen_rtx_CODE (. + +Fri Apr 17 22:38:17 1998 Jeffrey A Law (law@cygnus.com) + + * global.c (global_alloc): Don't pass HARD_CONST (0) to find_reg, + just pass zero. That will work regardless of the size of HARD_REG_SET. + + * libgcc2.c (__floatdisf): Fix a couple typos. + +Fri Apr 17 17:28:26 1998 Jim Wilson + + * Makefile.in (mostlyclean): Delete *.mach and *.bp files. + +Fri Apr 17 16:35:35 1998 Greg McGary + + * emit-rtl.c (gen_highpart): initialize `word' properly for pseudo. + +Fri Apr 17 14:30:37 1998 John Carr + + * emit-rtl.c (operand_subword_force): If a register can not be + accessed by words, copy it to a pseudo register. + +Fri Apr 17 14:30:37 1998 Jim Wilson + + * rs6000/vxppc.h (CPP_SPEC): Add support for mrelocatable*. + +Fri Apr 17 17:01:25 1998 Michael Meissner + + * tree.h (mark_seen_cases): Delete declaration. + +Fri Apr 17 13:32:20 1998 Jeffrey A Law (law@cygnus.com) + + * stmt.c (mark_seen_cases): Make static and add prototype. + +Fri Apr 17 11:21:43 1998 Kaveh R. Ghazi + + * frame.c: Include stdlib.h and unistd.h to possibly get various + function prototypes. The fixproto script guarantees these header + files exist on the target system. + * libgcc2.c: Likewise. + + * gthr-single.h (__gthread_mutex_lock, __gthread_mutex_trylock, + __gthread_mutex_unlock): Add __attribute__ ((__unused__)) to the + function parameters. + * libgcc2.c (__udiv_w_sdiv): Likewise. + +Thu Apr 16 22:41:02 1998 Jeffrey A Law (law@cygnus.com) + + * varasm.c (asm_output_bss): Add prototype. + (asm_output_aligned_bss): Likewise. + + * unroll.c (verify_addresses): Add prototype. + + * toplev.c: Add many prototypes. Too many to mention here. + + * stmt.c (check_seenlabel): Add prototype. + + * rtlanal.c (reg_set_p_1): Add prototype. + (reg_set_last_1): Likewise. + + * reorg.c (find_dead_or_set_registers): Add prototype. + + * regmove (try_auto_increment): Add prototype. + + * reg-stack.c (pop_stack): Add prototype. + + * recog.c (validate_replace_rtx_1): Add prototype. + (find_cosntant_term_loc): Likewise. + + * loop.c (regs_patch_p): Add prototype. + (add_label_notes, count_nonfixed_reads): Likewise. + (find_single_use_in_loop): Likewise. + (express_from): Surround prototype with #ifdef. + (giv_sort): Similarly. + + * jump.c (mark_modified_reg): Add prototype. + + * haifa-sched.c (is_prisky): Add prototype. + (queue_to_ready): Likewise. + + * genextract.c (gen_insn): Add prototype. + + * genemit.c (max_operand_1): Add prototype. + (max_operand_vec, print_code, gen_exp, gen_insn): Likewise. + (gen_expand, gen_explit, output_add_clobbers): Likewise. + (output_init_mov_optab): Likewise. + + * genattrtab.c (attr_hash_add_rtx): Add prototype. + (attr_hash_add_string, write_length_unit_log): Likewise. + + * genattr.c (init_range): Add prototype. + + * combine.c (sets_function_arg_p): Add prototype. + + * expr.c (store_constructor_field): Add prototype. + (get_memory_usage_from_modifier): Likewise + + * expmed.c (synth_mult): Add prototype. + (choose_multiplier, invert_mod2n): Likewise. + + * except.c (push_eh_entry): Add prototype. + (pop_eh_entry, enqueue_eh_entry, dequeu_eh_entry): Likewise. + (call_get_eh_context, start_dynamic_cleanup): Likewise. + (start_dynamic_handler, can_throw): Likewise. + (output_exception_table_entry, scan_region): Likewise. + (eh_regs, set_insn_eh_region): Likewise. + + * dwarfout.c (decl_class_context): Add prototype. + (output_inheritance_die, type_ok_for_scope): Likewise. + + * c-lex.c (skip_white_space_on_line): Add prototype. + + * alias.c (record_set): Add prototype. + (find_base_term, base_alias_check): Likewise. + + * function.c (assign_outer_stack_local): Make static and add prototype. + + * haifa-sched.c (build_control_flow): Accept raw data as inputs + instead of computing it locally. Callers changed. + (find_rgns): Several new arguments. Callers changed. + Generally clean up and comment better. Use dominators to + identify reducible loops. Convert some flag arrays to bitmaps. + Convert most of the code to work on pred/succ lists instead of + an edge table. Add comments for future improvements. + (schedule_insns): Allocate temporary tables for flow data, call + routines to compute flow data and pass it along to children as + arguments. + (debug_control_flow): Delete. Use dump_bb_data instead. + + * basic-block.h (compute_dominators): Declare. + + * flow.c (dump_sbitmap, dump_sbitmap_vector): New debugging + functions. + * basic-block.h: Declare them. + +Thu Apr 16 13:45:51 1998 Jim Wilson + + * reg-stack.c (constrain_asm_operands): Set n_alternatives to zero if + no operands. + +Wed Apr 15 11:33:09 1998 Alexandre Petit-Bianco + + * tree.c (build_expr_wfl): Use NULL_TREE if the file name is NULL. + Propagate TREE_SIDE_EFFECTS and TREE_TYPE iff the encapsulated + node is non NULL. Cache last file name and file name identifier node. + +1998-04-15 Mark Mitchell + + * c-common.c (declare_hidden_char_array): Use TYPE_DOMAIN to get + the length of an array, not TREE_TYPE. + +Wed Apr 15 15:31:34 1998 Jeffrey A Law (law@cygnus.com) + + * flow.c (sbitmap_union_of_successors): New function. + * basic-block.h (sbitmap_union_of_successors): Declare it. + +Wed Apr 15 12:38:03 1998 Jim Wilson + + * configure.in (gnu_ld): Rename to gnu_ld_flag before main loop. + Set gnu_ld to gnu_ld_flag inside main loop. + (gas): Likewise. + +Wed Apr 15 14:50:05 1998 Dave Brolley + + * toplev.c (compile_file): Call init_parse using new interface. + (init_lex): Remove declaration. + + * c-lex.c (init_parse): Now returns char* containing filename. + +Wed Apr 15 12:37:10 1998 Jeffrey A Law (law@cygnus.com) + + * pa.h (LEGITIMIZE_RELOAD_ADDRESS): Do nothing if not optimizing. + +Wed Apr 15 12:10:18 1998 Michael Meissner + + * Makefile.in (gen{config,flags,codes,emit}): Link in host print-rtl.o. + (gen{extract,peep,opinit,output}): Ditto. + + * gen{attr,codes,config,emit,output}.c (insn_attr_name): Provide a + global definition so print-rtl.o can be linked in. + * gen{peep,recog}.c (insn_attr_name): Ditto. + +Tue Apr 14 07:30:57 1998 K. Richard Pixley + + * fixincludes: discard empty C++ comments, as found in sys/time.h + on hpux-11.0. + +Wed Apr 15 10:47:21 1998 Andreas Schwab + + * config/m68k/m68k.md (adddi3, subdi3): Optimize for constant + operand. + +Wed Apr 15 01:21:21 1998 Jeffrey A Law (law@cygnus.com) + + * emit-rtl.c (operand_subword): Rework slightly to avoid + bogus warning from previous change. + +Tue Apr 14 23:39:13 1998 Richard Henderson + + * alpha.md: Revert Oct 27 change, as it is superceeded by Kenner's + Nov 8 find_replacement change. Move decls of get_unaligned_address + * alpha.h: ... here. + +Tue Apr 14 22:00:39 1998 John Carr + + * function.c (assign_parms): Initialize unsignedp before passing + its pointer to promote_mode. + + * genattrtab.c (check_attr_test): Handle MATCH_INSN like MATCH_OPERAND. + (write_test_expr): Allow MATCH_INSN. + +Tue Apr 14 21:57:57 1998 Paul Eggert + + * install.texi: Update section on warnings that can be safely ignored. + +Tue Apr 14 14:55:16 1998 Jim Wilson + + * mips.md (reload_outdi): Change the scratch mode from DImode to + TImode. New variable scratch, used instead of operand[2] in template. + Add code for MIPS16 HILO_REGNUM case where output reg is not M16_REG_P. + +Tue Apr 14 16:19:03 1998 Michael Meissner + + * expr.c (MOVE_RATIO): Set to 3 if optimizing for space. + +Tue Apr 14 11:31:28 1998 Krister Walfridsson + + * i386/bsd386.h (ASM_OUTPUT_ALIGN): Redefine. + +Tue Apr 14 09:02:32 1998 Jeffrey A Law (law@cygnus.com) + + * svr4.h (ASM_DECLARE_OBJECT_NAME): Use HOST_WIDE_INT_PRINT_DEC. + (ASM_FINISH_DECLARE_OBJECT): Likewise. + + * Idea and part of the patch from HJ. + * Makefile.in: auto-host.h renamed from auto-config.h. All references + changed. + (distclean): Remove auto-build.h too. + * configure.in: Rename host autoconf generated file to auto-host.h. + If host != build, then run autoconf to generate auto-build.h for + the build machine and include it in build_xm_files. + Check for wait.h and sys/wait.h. + + * combine.c (simplify_rtx, case TRUNCATE): Respect value of + TRULY_NOOP_TRUNCATION. + +Mon Apr 13 11:31:49 1998 Jason Merrill + + * tree.h (BINFO_OFFSET_ZEROP): Use integer_zerop. + +Sun Apr 12 20:55:32 1998 Catherine Moore + + * invoke.texi (ld options) Include memset requirements + for options -nodstdlib and -nodefaultlibs. + +1998-04-12 Paul Eggert + + This change is from an idea suggested by Arthur David Olson. + + * c-common.c (decl_attributes, record_function_format, + check_format_info, init_function_format_info): + Add support for strftime format checking. + (enum format_type): New type. + (record_function_format): Now static, and takes value of type + enum format_type instead of int. + (time_char_table): New constant. + (struct function_format_info): format_type member renamed from is_scan. + (check_format_info): Use `warning' rather than sprintf followed by + `warning', to avoid mishandling `%' in warnings. + Change `pedwarn' to `warning', since these warnings do not necessarily + mean the program does not conform to the C Standard, as the code + need not be executed. + + * c-tree.h (record_function_format): Remove decl; no longer extern. + + * extend.texi: Add documentation for strftime format checking. + +Sun Apr 12 20:23:03 1998 Jeffrey A Law (law@cygnus.com) + + * mips/ecoffl.h: Do not include mips.h. + * mips/elf.h: Likewise. + + * configure.in (mips-*-ecoff): Do not mention mips/mips.h in tm_files. + * mips/ecoff.h: Include "mips/mips.h". + +Sat Apr 11 22:42:54 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sat Apr 11 01:24:28 1998 Jeffrey A Law (law@cygnus.com) + + * cse.c (count_reg_usage): Correctly handle REG_NONNEG notes. + (delete_trivially_dead_insns): Renamed from delete_dead_from_cse. + * toplev.c (rest_of_compilation): Call delete_trivially_dead_insns instead of delete_dead_from_cse. Also call delete_trivially_dead_insns + between loop optimization passes. + * rtl.h: Updated appropriately. + +Fri Apr 10 22:28:32 1998 Jeffrey A Law (law@cygnus.com) + + Reinstall this patch from Jason. + * function.c (push_function_context_to): Don't call init_emit. + +Fri Apr 10 13:40:20 1998 Nick Clifton + + * rtl.c (read_skip_spaces): Prevent infinite loops upon + encountering unterminated comments. + +Fri Apr 10 10:43:41 1998 Jeffrey A Law (law@cygnus.com) + + * emit-rtl.c (operand_subword): Properly handle CONST_INTs for + 64x32 cross builds. + + * configure.in: Handle --with-fast-fixincludes. + (fixincludes): If --with-fast-fixincludes, then use a different + fixincludes program by default. + * Makefile.in (fixinc.sh): New rule. + +Fri Apr 10 00:36:31 1998 H.J. Lu (hjl@gnu.org) + + * i386.md (movqi+1): Handle invalid QI register. + (movsf_push-1): Likewise. + +Thu Apr 9 16:53:59 1998 Nick Clifton + + * config/m32r/m32r.c: call_address_operand(): Only accept symbolic + addresses. + symbolic_memort_operand(), call32_operand(), int8_operand(), + int16_operand(), uint24_operand(), reg_or_int8_operand(): Removed. + Not used. + uint16_operand(): Made static. + +Thu Apr 9 01:43:04 1998 Jeffrey A Law (law@cygnus.com) + + * calls.c (expand_call): Fix typo. + +Thu Apr 9 00:18:44 1998 Dave Brolley (brolley@cygnus.com) + + * c-lex.c (finput): New global. + (init_parse): Always included. Handle !USE_CPPLIB using + code originally in compile_file. + (finish_parse): Update for CPPLIB. + * toplev.c (init_parse, finish_parse): Declare. + (finput): Delete variable. Now in front-ends. + (compile_file): Remove code which is now handled by init_parse + which is unconditionally called. Similarly for finish_parse. + +Wed Apr 8 23:13:50 1998 Gavin Koch + + * config/mips/r3900.h (ASM_OUTPUT_DEF,SUPPORTS_WEAK, + ASM_WEAKEN_LABEL): Add. + +Wed Apr 8 18:21:30 1998 Richard Henderson + + * alpha/crtbegin.asm, alpha/crtend.asm, alpha/t-crtb: New files. + * configure.in (alpha-*-linux*): Use them. + +Fri Apr 3 17:02:13 1998 Alexandre Petit-Bianco + + * tree.def (EXPR_WITH_FILE_LOCATION): New tree node definition. + * tree.h (EXPR_WFL_{NODE,FILENAME,FILENAME_NODE,LINENO, + COLNO,LINECOL,SET_LINECOL,EMIT_LINE_NOTE}): New macros. + (build_expr_wfl): New prototype declaration. + * tree.c (build_expr_wfl): New function, to build + EXPR_WITH_FILE_LOCATION nodes. + (copy_node): Don't zero TREE_CHAIN if copying a + EXPR_WITH_FILE_LOCATION node. + * print-tree.c (print_node): Handle EXPR_WITH_FILE_LOCATION. + * expr.c (expand_expr): Handle EXPR_WITH_FILE_LOCATION. + +Wed Apr 8 12:51:19 1998 Jeffrey A Law (law@cygnus.com) + + * configure.in (v850): Use t-v850. + (ix86-wrs-vxworks): Recognize 786 just like other x86 configurations. + + * protoize.c (creat, read, write): Do not declare. + + * jump.c (mark_jump_label): Record REG_LABEL notes for insns which + refer to the CODE_LABEL before a dispatch table. + + * invoke.texi: Add ARC options. + + * gcc.c (proces_command): Improve error message for -o with + either -c or -S. + + * i386/x-cygwin32 (CLIB): Link in advapi32. + + * alpha.h (ASM_IDENTIFY_GCC): Define to nothing. + (ASM_IDENTIFY_LANGUAGE): Likewise. + + * i386.md (movqi recognizer): Don't perfom byte increment into + a NON_QI_REG_P. + + * configure.in (x86-dg-dgux): Run fixinc.dgux. + + * i370.h: Fix typo in GEN_INT changes. + + * bitmap.c (bitmap_element_allocate): Use "void" for arglist instead + of an empty arglist in prototype. + + * Makefile.in: Remove bytecode crud that crept back in after the + gcc2 merge. + +1998-04-08 Brendan Kehoe + + * c-lex.h (is_class_name): Fix arg type to be tree, not void. + (make_pointer_declarator, reinit_parse_for_function): Fix typo. + +Wed Apr 8 06:16:45 1998 Richard Earnshaw (rearnsha@arm.com) + + * arm.h (LEGITIMIZE_RELOAD_ADDRESS): Define. + +Wed Apr 8 00:44:18 1998 Bernd Schmidt (crux@pool.informatik.rwth-aachen.de> + + * c-lex.c (is_class_name): Delete declaration. + (whitespace_cr): Make static and add prototype. + * c-lex.h (make_pointer_declarator, reinit_parse_for_function, + yylex, get_directive_line): Turn declarations into prototypes. + (position_after_whitespace, check_newline, yyerror,, is_class_name, + forget_protocol_qualifiers, remember_protocol_qualifiers): Add + prototypes. + * genattr.c (extend_range, write_upcase, gen_attr, write_units): Add + prototypes. + * gencodes.c (gen_insn): Add prototype. + * genconfig.c (walk_insn, gen_insn, gen_expand, gen_split, + gen_peephole): Add prototypes. + * genflags.c (num_operands, gen_proto, gen_nonproto, gen_insn): Add + prototypes. + * gengenrtl.c (type_from_format, accessor_from_format, special_rtx, + special_format, find_formats, gendecl, genmacro, gendef, genlegend, + genheader, gencode): Add prototypes. + * genopinit.c (gen_insn): Add prototype. + * genoutput.c (output_prologue, output_epilogue, scan_operands, + process_template, validate_insn_alternatives, gen_insn, gen_peephole, + gen_expand, gen_split, n_occurrences): Add prototypes. + * genpeep.c (gen_peephole): Add prototype. + * loop.c (find_and_verify_loops, mark_loop_jump, prescan_loop, + reg_in_basic_block_p, consec_sets_invariant_p, libcall_other_reg, + labels_in_range_p, count_loop_regs_set, note_addr_stored, + loop_reg_used_before_p, scan_loop, replace_call_address, + skip_consec_insns, libcall_benefit, ignore_some_movables, + force_movables, combine_movables, rtx_equal_for_loop_p, move_movables, + strength_reduce, valid_initial_value_p, find_mem_givs, record_biv, + check_final_value, record_giv, update_giv_derive, basic_induction_var, + simplify_giv_expr, general_induction_var, consec_sets_giv, + check_dbra_loop, express_from, combine_givs_p, combine_givs, + product_cheap_p, maybe_eliminate_biv, maybe_eliminate_biv_1, + last_use_this_basic_block, record_initial, update_reg_last_use, + iteration_info, analyze_loop_iterations, insert_bct, + instrument_loop_bct, indirect_jump_in_function_p): Turn declarations + into prototypes. + +Tue Apr 7 21:48:52 1998 Jeffrey A Law (law@cygnus.com) + + * pa.h (LEGITIMIZE_RELOAD_ADDRESS): Define. + +1998-04-07 Ken Raeburn + + * config/mips/mips.c (siginfo): Deleted. + (override_options): Don't install SIGINFO signal handler. + +Tue Apr 7 11:58:04 1998 Jim Wilson + + * loop.c (check_dbra_loop): When normalize comparison_val, add check + to verify it is non-negative. + +Tue Apr 7 02:01:47 1998 Richard Henderson + + * alpha.c (alpha_expand_block_move): Correctly collect block offsets. + (alpha_expand_block_clear): Likewise. + +Mon Apr 6 23:36:01 1998 Richard Henderson + + * tree.h (sizetype_tab): Fix previous change for K&R. + +Mon Apr 6 22:23:29 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Mon Apr 6 23:16:10 1998 Richard Earnshaw (rearnsha@arm.com) + + * configure.in (sparc-*-solaris2*): Add xm-siglist.h to xm_file. + Add USG and POSIX to xm_defines. + +Mon Apr 6 21:49:57 1998 Bob Manson + + * gcc.c: Add linker spec. + (link_command_spec): Use %(linker) instead of ld. + (main): If collect2 is requested as the linker, see if it exists; + if not, use ld instead. + + * Makefile.in (USE_COLLECT2): It's named collect2 now, not ld. + (ld:) Deleted. + (install-collect2): Install as collect2, not ld. + + * configure.in(will_use_collect2): It's named collect2 now. + + * collect2: Remove checks to see if we were invoked recursively. + (collect_execute): Use _spawnvp under cygwin32. + +Mon Apr 6 17:23:41 1998 Jim Wilson + + * haifa-sched.c (build_control_flow): Set unreachable for block whose + only predecessor is itself. + +Mon Apr 6 16:08:04 1998 Kaveh R. Ghazi + + * c-parse.in: Include system.h, and remove stuff now made redundant. + * cccp.c: Likewise. + * cexp.y: Likewise. + * protoize.c: Likewise. Properly check for cpp stringification. + + * Makefile.in (c-parse.o, cccp.o, cexp.o, protoize.o, unprotoize.o): + Depend on system.h. + + * objc/Make-lang.in (objc-parse.o): Likewise. + +Mon Apr 6 14:59:58 1998 Kaveh R. Ghazi + + * gansidecl.h: Check if compiler supports __attribute__. Provide + definitions for ATTRIBUTE_UNUSED and ATTRIBUTE_PRINTF using + __attribute__ when its available. Also provide definitions for + ATTRIBUTE_PRINTF_1, ATTRIBUTE_PRINTF_2 and ATTRIBUTE_PRINTF_3 in + terms of ATTRIBUTE_PRINTF. + + * genoutput.c (process_template): Use ATTRIBUTE_UNUSED in place + of __attribute__. + +Mon Apr 6 07:17:52 1998 Catherine Moore + + * combine.c (can_combine_p): Include successor in volatile test. + +Mon Apr 6 14:16:33 1998 J"orn Rennecke + + * sh.h (CASE_VECTOR_SHORTEN_MODE): Fix logic when to set + offset_unsigned. + +Mon Apr 6 02:03:29 1998 Jeffrey A Law (law@cygnus.com) + + * objc/objc-act.c (encode_aggregate_within): Avoid GNU extensions + in prototype and definition. + +Mon Apr 6 00:48:56 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Mon Apr 6 00:08:50 1998 Richard Henderson + + * alpha.c (alpha_expand_block_clear): Add missing offset arg to + alpha_expand_unaligned_store_words. + +Sun Apr 5 21:31:24 1998 John Wehle (john@feith.com) + + * i386.md (movsf_push, movsf_mem): Remove. + (movsf_push): Rename from movsf_push_nomove and move in front of + movsf. Use nonmemory_operand predicate and don't bother checking + TARGET_MOVE. + (movsf_push_memory): New pattern. + (movsf): Don't bother checking for push_operand. If TARGET_MOVE and + both operands refer to memory then force operand[1] into a register. + (movsf_normal): Change to unnamed pattern. + Likewise for movdf, movxf, and friends. + +Sun Apr 5 18:45:51 PDT 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sun Apr 5 16:31:10 1998 Richard Henderson + + * configure.in (alpha-dec-osf*): Match osf1.3 correctly. + +Sun Apr 5 16:53:37 1998 Don Bowman + + * configure.in (mips-wrs-vxworks): New target. + +Sat Apr 4 23:34:32 PST 1998 Jeff Law (law@cygnus.com) + + * expmed.c (synth_mult): The value -1, has no zeros, so it can + never have the form ...011. + + * version.c: Bump for snapshot. + +Sat Apr 4 20:16:46 1998 Richard Henderson + + * i386.c (asm_output_function_prefix, load_pic_register): + Use ASM_GENERATE_INTERNAL_LABEL properly. + (output_pic_addr_const): Recognize %X to supress any PIC sym suffix. + (print_operand): Ignore it. + (load_pic_register): Use it for the got load call. + * i386.md (prologue_set_got, prologue_get_pc): Likewise. + (prologue_get_pc_and_set_got): Likewise. + * i386.h: Update print_operand docs. + +Sat Apr 4 19:08:37 1998 Richard Henderson + + * i386.md (ffssi, ffshi): Rewrite as define_expands. + (ffssi_1, ffshi_1): New (unspec [] 5) support patterns. + * i386.c (notice_update_cc): Recognize unspec 5. + +Sat Apr 4 18:07:16 1998 David Mosberger-Tang (davidm@mostang.com) + + * alpha.h (PRINT_OPERAND_PUNCT_VALID_P): Accept '(' for s/sv/svi. + * alpha.c (print_operand): Handle it. + * alpha.md (fix_truncsfdi2): Use it. Add earlyclobber pattern + for ALPHA_TP_INSN. + (fix_truncdfdi2): Likewise. + +Sat Apr 4 17:42:05 1998 Richard Henderson + + * tree.h (sizetype_tab[2], sbitsizetype, ubitsizetype): Merge all + of these into a single struct, with additional [us]sizetype entries. + * stor-layout.c (set_sizetype): Initialize [us]sizetype. + * fold-const.c (size_int_wide): Don't rely on sizetype_tab being + an array. + +Sat Apr 4 17:04:41 1998 Richard Henderson + + * configure.in (alpha-*-linux-*): Undo tm_file changes from gcc2 merge. + +Sat Apr 4 13:50:01 1998 Richard Henderson + + * haifa-sched.c (split_block_insns): Don't supress insn splitting + on subsequent passes. + + * alpha.c (hard_fp_register_operand): New function. + * alpha.h (PREDICATE_CODES): Add it. + * alpha.md (extendsidi2): Kill bogus f<-f cvtql+cvtlq case. Add an + f<-m case and accompanying define_split. + (trapb): Use a unique unspec_volatile number. + +Sat Apr 4 13:32:08 1998 Richard Henderson + + * configure.in (alpha-*-linux-gnu*): Undo Feb 3 change brought in + from gcc2 merge. + +Sat Apr 4 10:23:41 1998 Jeffrey A Law (law@cygnus.com) + + * Check in merge from gcc2. See ChangeLog.11 and ChangeLog.12 + for details. + + * haifa-sched.c: Mirror recent changes from gcc2. + +Fri Apr 3 00:17:01 1998 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (insn*.o): Depend on system.h. + + * pa.c (output_global_address): Initialize base. + * pa.h (GO_IF_LEGITIMATE_ADDRESS): Initialize index. + +1998-04-03 Mike Stump + + * gthr.h: Support systems that don't have weak, but have threads. + * configure.in (*wrs-vxworks*): Use VxWorks threads by default. + * gthr-vxworks.h: New file. + * objc/thr-vxworks.h: Dummy file from thr-single.c for now. + +Thu Apr 2 18:00:52 1998 Jim Wilson + + * i386.md (movqi+1): Change alternative 1 from *r/r to *r/*rn. + +1998-04-02 Vladimir N. Makarov + + * ginclude/va-i960.h (va_end): Change void * to void. + +Thu Apr 2 13:51:10 1998 Kaveh R. Ghazi + + * Makefile.in (choose-temp.o): Depend on system.h. + + * choose-temp.c: Include system.h when IN_GCC. + +Thu Apr 2 02:37:07 1998 Joern Rennecke (amylaar@cygnus.co.uk) + Richard Henderson + + * reload.c (find_reloads_address): Try LEGITIMIZE_RELOAD_ADDRESS. + (move_replacements): New function. + * reload.h: Prototype it. + + * alpha.h (LEGITIMIZE_RELOAD_ADDRESS): New definition. + +Thu Apr 2 01:01:34 1998 Richard Henderson + + * configure (alpha-*-linuxecoff, alpha-*-linux-gnulibc1): + Run fixincludes. + + * emit-rtl.c (gen_lowpart_common): Skip count by HARD_REGNO_NREGS. + (gen_highpart): Likewise. + * final.c (alter_subreg): Allow the target to hook by-mode subreg + hard register number changes. + +Wed Apr 1 22:26:22 1998 Jeffrey A Law (law@cygnus.com) + + * fold-const.c optimze_bit_field_compare): Initialize rnbitpos, + rnbitsize, rnmode and rinner. + (make_range): Initialize type. + (fold): Initialize arg0, arg1 and varop. + + * function.c (instantiate_virtual_regs_1): Initialize offset, regnoi + and regnor. + (expand_function_start): Initialize last_ptr. + + * stor-layout.c (layout_record): Initialize desired_align. + (get_best_mode): Initialize unit. + + * tree.c (copy_node): Initialize length. + + * c-lex.c (yylex): Initialize traditional_type, ansi_type and type. + + * caller-save.c (insert_save_restore): Initialize pat, code and + numregs. + + * emit-rtl.c (push_to_sequence): Initialize top. + (push_topmost_sequence): Likewise. + + * genattrtab.c (simplify_by_exploding): Initialize defval. + + * profile.c (branch_prob): Initialize dest. + + * rtl.h (note_stores): Remove duplicate prototype. + (GEN_INT): Re-instate cast of second arg to HOST_WIDE_INT. + + * cplus-dem.c (gnu_special): Don't get confused by . + strings that are not actually lengths. + + * genattrtab.c: Make generated file use system.h, instead of + including stdio.h, etc directly. + * genextract.c, genopinit.c, genoutput.c: Likewise. + * genpeep.c, genrecog.c: Likewise + + * genoutput.c (process_template): Mark operands in the generated + function as potentially unused if compiling with GNU CC. + + * i386/freebsd-elf.h (CPP_PREDEFINES): Update from FreeBSD folks. + + * pa.md (reload peepholes): Remove unused variable "mode". + +Wed Apr 1 17:06:19 1998 Nick Clifton + + * config/arm/thumb.h: Add super interworking support. + * config/arm/thumb.c: Add super interworking support. + * config/arm/thumb.md: Add super interworking support. + * config/arm/lib1funcs.asm: Add interworking support. + * config/arm/lib1thumb.asm: Add super interworking support. + * config/arm/t-semi: Add interworking support. + * config/arm/t-thumb: Add interworking support. + * config/arm/README-interworking: New file. + +Wed Apr 1 14:38:10 1998 Jim Wilson + + * config/mips/iris6.h (MD_EXEC_PREFIX): Set to /usr/bin/. + (MD_STARTFILE_PREFIX): Unset. + +1998-04-01 Mark Mitchell + + * varasm.c (make_decl_rtl): Update the DECL_ASSEMBLER_NAME for a + entity in a local scope. + + * fold-const.c (fold): Call truthvalue_conversion for values which + are folded to boolean type. + +Wed Apr 1 06:09:53 1998 Jeffrey A Law (law@cygnus.com) + + * 1750a.md, arm.c, clipper.c, clipper.md: Use GEN_INT consistently. + * convex.h, dsp16xx.c, fx80.md, gmicro.c, gmicro.md: Likewise. + * i370.h, i370.md, i860.c, i860.h, i860.md, i960.c: Likewise. + * i960.h, i960.md, m32r.md, m68k.md, m68kv4.h, m88k.c: Likewise. + * m88k.md, ns32k.c, ns32k.md, pdp11.c, pdp11.h, pdp11.md: Likewise. + * pyr.c, pyr.h, pyr.md, romp.c, romp.h, romp.md: Likewise. + * rs6000.md, sparc.c, sparc.h, sparc.md, spur.c, spur.md: Likewise. + * tahoe.md, vax.h, vax.md, we32k.c, we32k.h, we32k.md: Likewise. + * md.texi: Likewise. + +Wed Apr 1 08:33:44 1998 Manfred Hollstein + + * fixincludes (limits.h): Fix nested comments in Motorola's + limits.h and sys/limits.h. + +Tue Mar 31 16:57:33 1998 Jim Wilson + + * alpha.c (alpha_expand_unaligned_load): Use tgt instead of addr + as dest of expand_binop call. + + * alpha.md (extzv): Correct check for valid operand[2] values. + + * profile.c (branch_prob): Add code to recognize HPPA tablejump entry + branch. + + * toplev.c (rest_of__compilation): Call init_recog_no_volatile at end. + +Mon Mar 30 13:11:05 1998 Stan Cox + + * libgcc2.c: (__main, __do_global_dtors, __do_global_ctors): + For __CYGWIN32__ use the versions in winsup/dcrt0.cc. + + * gcc.c, cccp.c, cpplib.c, collect2.c (GET_ENVIRONMENT): Added. + cygwin32 can override this to allow both unix and win32 style PATHs. + + * i386/xm-cygwin32.h (GET_ENVIRONMENT): Defined to allow win32 + style environment paths. + +Mon Mar 30 14:43:20 1998 Kaveh R. Ghazi + + * Makefile.in (cppalloc.o, cpperror.o, cppexp.o, cpphash.o, + cpplib.o, cppmain.o, fix-header.o, gcov.o, gen-protos.o, + gengenrtl.o, halfpic.o, hash.o, scan-decls.o, scan.o): Depend on + system.h. + + * cpphash.c: Include config.h. + * cppalloc.c: Include system.h. Add parameters to various + function prototypes. + * cpperror.c: Likewise. + * cppexp.c: Likewise. + * cpphash.c: Likewise. + * cpplib.c: Likewise. + * cppmain.c: Likewise. + * fix-header.c: Likewise. + * gcov.c: Likewise. + * gen-protos.c: Likewise. + * gengenrtl.c: Likewise. + * halfpic.c: Likewise. + * hash.c: Likewise. + * scan-decls.c: Likewise. + * scan.c: Likewise. + +Mon Mar 30 11:06:45 1998 Jim Wilson + + * README.gnat: Add lang_print_xnode definition. + +Mon Mar 30 11:12:24 1998 Andreas Schwab + + * config/m68k/m68k.c (standard_68881_constant_p): Don't use + fmovecr on the 68060. + +Mon Mar 30 00:21:03 1998 Jeffrey A Law (law@cygnus.com) + + * genemit.c (DONE): Rework so that it works in the true arm if + an if-else conditional. + (FAIL): Likewise. + +Sun Mar 29 12:45:23 1998 Jeffrey A Law (law@cygnus.com) + + * rs6000.c: Do not include stdioh or ctype.h anymore. + + * Makefile.in (c-typeck.o): Delete on expr.h, insn-codes.h and + $(RTL_H). + (stor-layout.o): Likewise. + * c-typeck.c: Include rtl.h and expr.h. + * stor-layout.c: Likewise. + + * cpplib.c (cpp_file_line_for_message): Delete unused parameter. + All callers changed. + (do_sccs): Wrap in an SCCS_DIRECTIVE ifdef. + * fix-header.c (cpp_file_line_for_message): Delete unused paramter. + All callers changed. + + * collect2.c (is_in_list): Wrap inside COLLECT_EXPORT_LIST ifdef. + + * local-alloc.c (reg_classes_overlap_p): Delete dead function. + + * tree.h (lang_print_xnode): Provide prototype. + +Sat Mar 28 23:50:44 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sun Mar 29 00:42:21 1998 Jeffrey A Law (law@cygnus.com) + + * objc/sendmsg.c (__objc_block_forward): Add braces for return + value if INVISIBLE_STRUCT_RETURN. + + * pa.c (arith_double_operand): Fix parens. + + * haifa-sched.c (print_pattern): Correct arg to sprintf. + + * Makefile.in (libgcc1.null): Make return type for __foo void. + +Sat Mar 28 14:37:20 1998 Jeffrey A Law (law@cygnus.com) + + * pa.h: Add declarations for many functions defined in pa.c. + + * genpeep.c (main): Remove unused variable 'i' from the generated + file. + + * genemit.c (gen_expand): Do not emit "_done" or "_fail" labels. + (gen_split): Likewise. + (main): Rework generated definitions of DONE and FAIL so that they + no longer use gotos. Avoids warnings about unused labels. + + * integrate.c (copy_rtx_and_substitute): Rework to avoid need for + unused "junk" variable. + + * genattrtab.c (write_complex_function): Add a default case in + generated switch statement to keep -W -Wall quiet. + +Sat Mar 28 10:47:21 1998 Nick Clifton + + * invoke.texi: Document more ARM and Thumb command line options. + + * config/arm/xm-thumb.h: New file. + +Sat Mar 28 01:37:33 1998 Craig Burley + + * stmt.c (expand_expr_stmt): Must generate code for + statements within an expression (gcc's `({ ... )}') + even if -fsyntax-only. + +Sat Mar 28 01:06:12 1998 Bernd Schmidt + Jeffrey A Law (law@cygnus.com) + + * basic-block.h (basic_block_computed_jump_target): Declare. + * flags.h: (current_function_has_computed_jump): Declare. + * flow.c: (basic_block_computed_jump_target): Define. + (flow_analysis): Allocate it. Set current_function_has_computed_jump + to 0. + (find_basic_blocks): Set current_function_has_computed_jump and + elements of basic_block_computed_jump_target to 1 as appropriate. + * function.c: (current_function_has_computed_jump): Define. + * global.c (global_conflicts): Don't allocate pseudos into stack regs + at the start of a block that is reachable by a computed jump. + * reg-stack.c (stack_reg_life_analysis): If must restart, do so + immediately. + (subst_stack_regs): Undo change from Sep 4 1997. + (uses_reg_or_mem): Now unused, deleted. + * stupid.c (stupid_life_analysis): Compute + current_function_has_computed_jump. + (stupid_find_reg): Don't allocate stack regs if the function has a + computed goto. + * haifa-sched.c (is_cfg_nonregular): Delete code to determine if + the current function has a computed jump. Use the global value + instead. + +Sat Mar 28 00:21:37 1998 Jeffrey A Law (law@cygnus.com) + + * i386/freebsd.h (CPP_PREDEFINES): Remove __386BSD__. + (DWARF2_UNWIND_INFO): Define to zero. + +Fri Mar 27 16:04:49 1998 Michael Meissner + + * gcc.c (set_std_prefix): Add declaration. + (process_command): If GCC_EXEC_PREFIX is set, remove /lib/gcc-lib/ + suffix, and update the standard prefix prefix.c uses. + + * prefix.c (std_prefix): New global to hold default prefix value. + (get_key_value): Change to use std_prefix instead of PREFIX. + (translate_name): Ditto. + (update_path): Ditto. + (get_key_value): Release allocated scratch storage. + (set_std_prefix): New function to reset the standard prefix. + +Fri Mar 27 18:08:21 1998 J"orn Rennecke + + * sh.c (find_barrier): Fix calculations for alignment increase. + +Fri Mar 27 08:56:52 1998 Manfred Hollstein + + * Makefile.in (stmp-fixinc): If we're actually fixing include + files, copy gcc's assert.h into the fixed include dir. + * fixincludes (assert.h): Avoid any attempts to fix a probably + broken system specific assert.h file. + * fixproto (stdlib.h): Make sure, it'll contain a definition of + size_t. + +Fri Mar 27 00:49:46 1998 Jeffrey A Law (law@cygnus.com) + + * regclass.c (reg_scan_mark_refs): Be more selective about + when we mark a register with REGNO_POINTER_FLAG. + +Thu Mar 26 23:00:11 1998 J"orn Rennecke + + reload inheritance improvement: + * reload1.c (reg_reloaded_contents, reg_reloaded_insn): + Change meaning: index is now hard reg number. + (reg_reloaded_valid, reg_reloaded_dead): New variables. + (reload_spill_index): Content is now a hard reg number. + (reload_as_needed): Change to fit new variable meaning. + (forget_old_reloads_1, allocate_reload_reg): Likewise. + (choose_reload_regs, emit_reload_insns): Likewise. + +Thu Mar 26 18:34:13 1998 J"orn Rennecke + + * regclass.c (record_reg_classes): '?' increases cost by two. + + * reload.c (find_reloads): Double previous costs. Output + reloads cost one unit extra. + + * reload1.c (eliminate_regs): Delete LOAD_EXTENDED_OP code that + boiled down to && ! 0. + + * reload.c (find_equiv_reg): Also consider a goal offset from the + frame pointer to be constant. + +Thu Mar 26 17:34:46 1998 J"orn Rennecke + + * sh.h (OPTIMIZATION_OPTIONS): Define. + +Thu Mar 26 00:19:47 1998 Richard Henderson + + * combine.c (make_compound_operation): Simplify (subreg (*_extend) 0). + +Wed Mar 25 23:53:11 1998 Jeffrey A Law (law@cygnus.com) + + * pa.c (pa_adjust_cost): Avoid redundant calls to get_attr_type. + +Wed Mar 25 13:40:48 1998 Jim Wilson + + * c-common.c (check_format_info): Initialize type, is_type. New local + integral_format. Don't warn for 'L' when pedantic. Do warn for 'L' + when pedantic if used with integral format specifier. + +Wed Mar 25 16:09:01 1998 Michael Meissner + + * rs6000.h (FUNCTION_ARG_PADDING): Cast result to be enum + direction. + (function_arg_padding): Declare. + + * rs6000.c: Include system.h. + (function_arg_padding): Change return type to int, cast enum's to + int. + + (From Kaveh R. Ghazi ) + * collect2.c (scan_prog_file): Add explicit braces to avoid + ambiguous `else'. + + * dbxout.c (dbxout_type_fields): Add braces around empty body in + an if-statement. + (dbxout_type): Likewise. + + * rs6000.c (rs6000_override_options): Change type of `i', `j' and + `ptt_size' from int to size_t. + (rs6000_file_start): Likewise for `i'. + (rs6000_replace_regno): Add default case in enumeration switch. + (output_epilog): Remove unused variable `i'. + (rs6000_longcall_ref): Remove unused variables `len', `p', `reg1' + and `reg2'. + + * rs6000.h (ADDITIONAL_REGISTER_NAMES): Add missing braces around + initializer. + (get_issue_rate, non_logical_cint_operand): Add prototype. + (rs6000_output_load_toc_table): Ditto. + + * rs6000.md (udivmodsi4): Add explicit braces to avoid ambiguous + `else'. + +Wed Mar 25 10:05:19 1998 Nick Clifton + + * config/arm/thumb.c: New File. Support for ARM's Thumb + instruction set. + * config/arm/thumb.h: New File. Thumb definitions. + * config/arm/thumb.md: New File. Thumb machine description. + * config/arm/tcoff.h: New File. Thumb COFF support. + * config/arm/t-thumb: New File. Thumb makefile fragment. + * config/arm/lib1thumb.asm: New File. Thumb libgcc support functions. + + * configure.in: Add Thumb-coff target. + * configure: Add Thumb-coff target. + * config.sub: Add Thumb-coff target. + +Wed Mar 25 10:30:32 1998 Jim Wilson + + * loop.c (scan_loop): Initialize move_insn_first to zero. + +Wed Mar 25 01:06:49 1998 Joel Sherrill (joel@OARcorp.com) + + * config/i386/go32-rtems.h: Defined TARGET_MEM_FUNCTIONS. + * config/i386/rtems.h: Likewise. + * config/i960/rtems.h: Likewise. + * config/m68k/rtems.h: Likewise. + * config/mips/rtems64.h: Likewise. + * config/pa/rtems.h: Likewise. + * config/rs6000/rtems.h: Likewise. + * config/sh/rtems.h: Likewise. + * config/sparc/rtems.h: Likewise. + +Wed Mar 25 00:57:26 1998 Richard Kenner + + * pa.c (emit_move_sequence): If in reload, call find_replacement. + +Tue Mar 24 10:44:11 1998 Nick Clifton + + * Makefile.in (gcov$(exeext)): Support .exe extension to gcov. + + * collect2.c (find_a_file): Add debugging. + (find_a_file): Test for win32 style absolute paths if + DIR_SERPARATOR is defined. + (prefix_from_string): Add debugging. + (main): Test for debug command line switch at start of program + execution. + (main): Use GET_ENVIRONMENT rather than getenv(). + (prefix_from_env): Use GET_ENVIRONMENT. + +1998-03-24 Mark Mitchell + + * cplus-dem.c (optable): Add sizeof. + (demangle_template_value_parm): New function containing code + previously found in demangle_template. + (demangle_integral_value): New function which handles complicated + integral expressions. + (demangle_template): Use them. + +Tue Mar 24 12:13:18 1998 Kaveh R. Ghazi + + * Makefile.in (genconfig.o, genflags.o, gencodes.o, genemit.o, + genopinit.o, genrecog.o, genextract.o, genpeep.o, genattr.o, + genattrtab.o, genoutput.o): Depend on system.h. + + * genattr.c: Include system.h. Add arguments to various function + prototypes. Remove redundant prototype of read_rtx(). + * genattrtab.c: Likewise. + * gencodes.c: Likewise. + * genconfig.c: Likewise. + * genemit.c: Likewise. + * genextract.c: Likewise. + * genflags.c: Likewise. + * genopinit.c: Likewise. + * genoutput.c: Likewise. + * genpeep.c: Likewise. + * genrecog.c: Likewise. + +1998-03-24 Martin von Loewis + + * c-lang.c (lang_print_xnode): New function. + * objc/objc-act.c (lang_print_xnode): Likewise. + * print-tree.c (print_node): Call it + +Mon Mar 23 23:59:11 1998 H.J. Lu (hjl@gnu.org) + + * c-parse.in: Recognize protocol qualifiers in class + definitions for objc. + Include "output.h". + (yyerror): Remove redundant decl. + (yyprint): Fix prototype. + +Mon Mar 23 23:49:47 1998 Jeffrey A Law (law@cygnus.com) + + * cse.c (rtx_cost): Only call CONST_COSTS if it is defined. + + * stmt.c (unroll_block_trees): Free block_vector if needed. + +Mon Mar 23 23:26:42 1998 Philippe De Muyter + + * m68k/m68k.md (zero_extendqidi2, zero_extendhidi2): New patterns. + (zero_extendsidi2): Avoid useless copy. + (iordi_zext): New pattern. + (iorsi_zexthi_ashl16): Pattern reworked to avoid "0" constraint for + operand 2. + (iorsi_zext): New name for old unnamed pattern; indentation fixes. + + * m68k/m68k.md (ashldi_const): Allow shift count in range ]32,63]. + (ashldi3): Allow constant shift count in range ]32,63]. + (ashrdi_const, ashrid3, lshrdi_const, lshrdi3): Likewise. + +1998-03-22 Mark Mitchell + + * tree.h (IS_EXPR_CODE_CLASS): New macro. + +Mon Mar 23 23:18:48 1998 Jeffrey A Law (law@cygnus.com) + + * h8300.h (CONST_COSTS): Remove definition. + (DEFAULT_RTX_COSTS): Define. + +Mon Mar 23 22:58:22 1998 Joel Sherrill (joel@OARcorp.com) + + * config/sh/rtems.h: Switched from ELF to COFF. + +Mon Mar 23 14:14:20 1998 J"orn Rennecke + + * freebsd.h (ASM_OUTPUT_ALIGN): Redefine. + +Sat Mar 21 23:52:56 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sun Mar 22 00:50:42 1998 Nick Clifton + Geoff Noer + + * Makefile.in: Various fixes for building cygwin32 native toolchains. + + * objc/Makefile.in: Various fixes for building cygwin32 native toolchains. + * objc/Make-lang.in: Likewise. + + * config/i386/xm-cygwin32.h (PATH_SEPARATOR): Set to a semi-colon. + +Sun Mar 22 00:21:46 1998 R. Ganesan + + * configure.in: Handle with-PACKAGE=no correctly + +Fri Mar 20 17:36:23 1998 Kaveh R. Ghazi + + * Makefile.in (alias.o, bitmap.o, c-aux-info.o, c-common.o, + c-decl.o, c-iterate.o, c-lang.o, c-lex.o, c-pragma.o, c-typeck.o, + caller-save.o, calls.o, collect2.o, combine.o, cse.o, dbxout.o, + dwarf2out.o, dwarfout.o, emit-rtl.o, except.o, explow.o, expmed.o, + expr.o, final.o, flow.o, function.o, getpwd.o, global.o, + integrate.o, jump.o, local-alloc.o, loop.o, optabs.o, pexecute.o, + prefix.o, print-rtl.o, print-tree.o, profile.o, real.o, recog.o, + reg-stack.o, regclass.o, regmove.o, reload.o, reload1.o, reorg.o, + rtl.o, rtlanal.o, sdbout.o, stmt.o, stor-layout.o, stupid.o, + tlink.o, toplev.o, tree.o, unroll.o, varasm.o, xcoffout.o): Depend + on system.h. + + * alias.c, bitmap.c, c-aux-info.c, c-common.c, c-decl.c, + c-iterate.c, c-lang.c, c-lex.c, c-pragma.c, c-typeck.c, + caller-save.c, calls.c, collect2.c, combine.c, cse.c, dbxout.c, + dwarf2out.c, dwarfout.c, emit-rtl.c, except.c, explow.c, expmed.c, + expr.c, final.c, flow.c, function.c, gcc.c, getpwd.c, global.c, + integrate.c, jump.c, local-alloc.c, loop.c, optabs.c, pexecute.c, + prefix.c, print-rtl.c, print-tree.c, profile.c, real.c, recog.c, + reg-stack.c, regclass.c, regmove.c, reload.c, reload1.c, reorg.c, + rtl.c, rtlanal.c, sched.c, sdbout.c, stmt.c, stor-layout.c, + stupid.c, tlink.c, toplev.c, tree.c, unroll.c, varasm.c, + xcoffout.c: Include system.h. Organize include ordering so + that stdarg/varargs comes before other system headers. Remove + spurious casts of functions assured of a prototype in system.h. + +Fri Mar 20 11:19:40 1998 Stan Cox + + * reg-stack.c (pop_stack): Define. Pops any register on the + regstack and adjusts regstack. + (compare_for_stack_reg): Use pop_stack. + +Thu Mar 19 23:51:01 1998 Jeffrey A Law (law@cygnus.com) + + * configure.in (hppa1.0-hp-hpux10): Handle threads for this + config too. + +Thu Mar 19 20:30:31 1998 Philippe De Muyter + + * libgcc2.c (exit): Do not call __bb_exit_func if HAVE_ATEXIT. + + * fold-const.c (fold): Replace sign-extension of a zero extended + value by a single zero extension. + +Thu Mar 19 00:58:07 1998 Jason Merrill + + * except.c (init_eh): Do nothing. + (save_eh_status): Call init_eh_for_function, not init_eh. + * function.c (push_function_context_to): Don't call init_emit. + +Thu Mar 19 13:39:52 1998 Michael Meissner + + * rs6000/sysv4.h (RELATIVE_PREFIX_NOT_LINKDIR): Undef for System V + and EABI. + +Thu Mar 19 10:10:36 1998 Kaveh R. Ghazi + + * final.c (shorten_branches): Add parentheses around +/- in + operand of &. + + * flow.c (life_analysis): Wrap variable `i' in macro ELIMINABLE_REGS. + +Thu Mar 19 09:15:17 1998 Manfred Hollstein + + * regclass.c (memory_move_secondary_cost): Wrap uses of + SECONDARY_INPUT_RELOAD_CLASS and SECONDARY_OUTPUT_RELOAD_CLASS + with #ifdef tests. + +Thu Mar 19 09:06:35 1998 Manfred Hollstein + + * config/m68k/m68k.md (addqi3): Fix typo gen_INT vs. GEN_INT. + + * flow.c (life_analysis): #include to make sure + size_t is defined. + * cplus-dem.c (demangle_function_name): Likewise. + +Thu Mar 19 09:00:01 1998 Manfred Hollstein + + * final.c (insn_noperands): Change type to unsigned int. + (final_scan_insn): Likewise for noperands; + properly check operand number boundaries. + +Wed Mar 18 16:20:30 1998 Richard Henderson + + * alpha.md (extzv): Don't reject register operands. Fix + mode of operand 1. + +Wed Mar 18 16:14:23 1998 Richard Henderson + + * dbxout.c (dbxout_function_end): Fix last change. The correct + predicate is ASM_OUTPUT_SECTION_NAME. + +Wed Mar 18 12:43:20 1998 Jim Wilson + + * sh.md (ashlsi_c-1): Delete 3rd argument to gen_ashlsi_c. + (ashlsi): Use match_dup 1 instead of match_operand 2. + +Wed Mar 18 13:46:07 1998 Richard Kenner + + * fold-const.c (operand_equal_for_comparison_p): See if equal + when nop conversions are removed. + +Wed Mar 18 13:42:01 1998 Richard Kenner + + * expr.c (expand_expr, case COND_EXPR): If have conditional move, + don't use ORIGINAL_TARGET unless REG. + +Wed Mar 18 16:53:19 1998 J"orn Rennecke + + * netbsd.h (ASM_OUTPUT_ALIGN): Redefine. + +Wed Mar 18 12:43:20 1998 Jim Wilson + + * loop.c (struct movable): New field move_insn_first. + (scan_loop): In consec sets code, set it. Clear it otherwise. + (move_movables): In consec sets code, use it. Copy REG_NOTES from + p to i1 only if i1 does not have REG_NOTES. Delete obsolete ifdefed + out code. + +Wed Mar 18 09:52:56 1998 Richard Henderson + + * rtl.c (read_rtx): Fall back on homebrew atoll if HOST_WIDE_INT + is large, and the system doesn't provide atoll or atoq. + (atoll): New. + + * alpha/xm-vms.h (HAVE_ATOLL): Define. + Reported by Klaus Kaempf . + +Wed Mar 18 09:56:26 1998 Kaveh R. Ghazi + + * c-lang.c (finish_file): Wrap variable `void_list_node' with macro + test !ASM_OUTPUT_CONSTRUCTOR || !ASM_OUTPUT_DESTRUCTOR. + + * calls.c (emit_call_1): Wrap variable `already_popped' with macro + test !ACCUMULATE_OUTGOING_ARGS. + + * collect2.c (write_c_file_glob): Wrap function definition in + macro test !LD_INIT_SWITCH. + + * combine.c (try_combine): Wrap variables `cc_use' and + `compare_mode' in macro test EXTRA_CC_MODES. + + * cpplib.c (do_ident): Remove unused variable `len'. + (skip_if_group): Remove unused variables `at_beg_of_line' and + `after_ident'. + (cpp_get_token): Remove unused variable `dummy'. + + * dbxout.c (scope_labelno): Move static variable definition inside + the one function scope where it is used. + (dbxout_function_end): Wrap prototype and definition in + macro test !NO_DBX_FUNCTION_END. + + * dwarf2out.c (add_subscript_info): Wrap variable `dimension_number' + in macro test !MIPS_DEBUGGING_INFO. + + * expr.c (expand_builtin_setjmp): Move declaration of variable `i' + into the scope where it is used. Wrap empty else-statement body + in braces. + + * fix-header.c: Fix typo in comment. + (inf_skip_spaces): Cast results of INF_UNGET to (void). + (check_protection, main): Likewise. + + * flow.c (find_basic_blocks_1): Remove dangling comment text. + + * function.c (contains): Wrap prototype and definition in macro + test HAVE_prologue || HAVE_epilogue. + (fixup_var_refs_1): Remove unused variable `width'. + + * gen-protos.c (main): Remove unused variable `optr'. + + * haifa-sched.c (debug_control_flow): Remove unused variable `j'. + + * libgcc2.c (__udiv_w_sdiv): Provide dummy return value of 0. + (__sjpopnthrow): Remove unused variable `jmpbuf'. + (__throw): Remove unused variable `val'. + + * protoize.c: Check for a previously existing definition before + defining *_OK macros. + + * scan-decls.c (scan_decls): Remove unused variable `old_written'. + +Tue Mar 17 00:45:48 1998 J"orn Rennecke + + * vax.h (ADDR_VEC_ALIGN): Define. + +Mon Mar 16 15:57:17 1998 Michael Meissner + + * gcc.c (default_arg): Don't wander off the end of allocated + memory. + + (From Geoffrey Keating ) + * rs6000.c (small_data_operand): Ensure that any address + referenced relative to the small data area is inside the SDA. + +Mon Mar 16 12:55:15 1998 Jim Wilson + + * config/m68k/netbsd.h (ASM_SPEC): Add %{m68060}. + +Mon Mar 16 15:50:20 EST 1998 Andrew MacLeod + + * except.h (in_same_eh_region): New prototype. + (free_insn_eh_region, init_insn_eh_region): New prototypes. + * except.c (insn_eh_region, maximum_uid): New static variables. + (set_insn_eh_region): New static function to set region numbers. + (free_insn_eh_region): New function to free EH region table. + (init_insn_eh_region): New function to initialize EH region table. + (in_same_eh_region): New function used to determine if two rtl + instructions are in the same exception region or not. + * final.c (final): Initialize the table indicating which instructions + belong in which exception region. + * genpeep.c (main): Add "except.h" to include file list in generated + file insn-peep.c. + * config/sparc/sparc.md: Add calls to 'in_same_eh_region' in 4 + peepholes involving calls and unconditional branches. + +Mon Mar 16 11:16:50 1998 Jim Wilson + + * README.gnat: New file. + +Mon Mar 16 11:14:20 1998 Andreas Schwab + + * config/m68k/m68k.c: Include for atoi. Include + "recog.h" for offsettable_memref_p. + (legitimize_pic_address): Remove unused variable `offset'. + (notice_update_cc): Change return type to void. Add default label + to switch. + (standard_68881_constant_p): Remove unused variable mode. + (print_operand): Define local variable i only if SUPPORT_SUN_FPA. + (const_int_cost): Explicitly declare as returning int. + (output_dbcc_and_branch): Change return type to void. + + * config/m68k/linux.h, config/m68k/m68k.md, config/m68k/m68k.c, + config/m68k/m68k.h: Replace gen_rtx (XXX, ...) with gen_rtx_XXX + (...). Use GEN_INT instead of gen_rtx_CONST_INT. + +Sun Mar 15 22:30:44 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Fri Mar 13 11:30:12 1998 Andreas Schwab + + * config/m68k/m68k.h (CONST_OK_FOR_LETTER_P): Fix logic in range + check for 'M' constraint. + +Thu Mar 12 14:47:14 1998 Jim Wilson + + * cccp.c (create_definition): If pedantic, call pedwarn for macro + varargs feature. + +Thu Mar 12 13:43:25 1998 Bernd Schmidt + + * i386.c (ix86_logical_operator): New function. + (split_di): Ensure that when a MEM is split, the resulting MEMs have + SImode. + * i386.md (anddi3, xordi3, iordi3): New patterns. Add a define_split + to implement them. + +Thu Mar 12 15:13:16 1998 Kaveh R. Ghazi + Richard Earnshaw + Nick Clifton + + * tm.texi (DEFAULT_RTX_COSTS): Document new macro. + + * arm.h (DEFAULT_RTX_COSTS): Define instead of RTX_COSTS. + + * cse.c (rtx_cost): Provide a default case in an enumeration + switch, and call DEFAULT_RTX_COSTS if it's defined. + +Thu Mar 12 10:02:38 1998 Manfred Hollstein + + * basic-block.h (compute_preds_succs): Change return type in + prototype to void. + * flow.c (compute_preds_succs): Likewise in function definition. + + * regmove.c (find_matches): Cast char used as array index to unsigned char + to supress warning. + +Thu Mar 12 09:39:40 1998 Manfred Hollstein + + * i386.h (RTX_COSTS): Insert braces around nested if. + (ADDITIONAL_REGISTER_NAMES): Insert braces around structured + elements. + + * gcc.c (default_compilers): Properly put brackets around array elements in + initializer. + + * getopt.c (_getopt_internal): Add explicit braces around nested if; + reformatted. + + * reg-stack.c (record_asm_reg_life): Add explicit braces around nested if's. + (record_reg_life_pat): Add explicit parens around && and || in expression. + (stack_reg_life_analysis): Add parens around assignment used as expression. + (convert_regs): Likewise. + +Thu Mar 12 09:25:29 1998 Manfred Hollstein + + * bitmap.c (bitmap_element_allocate): Remove unused parameter; + change callers accordingly. + + * cplus-dem.c (arm_special): Remove unused parameter work in prototype + and definition; change all callers accordingly. + + * except.c (init_eh): Avoid assignment of unused return value of + build_pointer_type; cast it to void, instead, and remove unused + variable type. + + * gcc.c (lang_specific_driver): Define prototype only #ifdef + LANG_SPECIFIC_DRIVER. + (temp_names): Define only #ifdef MKTEMP_EACH_FILE. + + * genoutput.c (output_epilogue): Initialize next_name to 0. + + * real.c (efrexp): #if 0 prototype and function definition. + (eremain): Likewise. + (uditoe): Likewise. + (ditoe): Likewise. + (etoudi): Likewise. + (etodi): Likewise. + (esqrt): Likewise. + + * reload.c (push_secondary_reload): Define prototype only + #ifdef HAVE_SECONDARY_RELOADS. + + * varasm.c (assemble_static_space): Define rounded only + #ifndef ASM_OUTPUT_ALIGNED_LOCAL. + +Thu Mar 12 09:11:35 1998 Manfred Hollstein + + * i386.md (andsi): Add default case in enumeration switch. + (iorsi3): Likewise. + (iorhi3): Likewise. + (xorsi3): Likewise. + +Thu Mar 12 08:37:02 1998 Manfred Hollstein + + * c-decl (finish_struct): Change type of min_align to unsigned. + + * cplus-dem.c (demangle_function_name): Change type of variable i to size_t; + remove unused variable len. + + * dwarf2out.c (reg_save): Add explicit cast of -1 to unsigned and a + comment indicating this is proper behaviour. + (reg_loc_descriptor): Remove redundant comparison of unsigned variable + reg >= 0. + (based_loc_descr): Likewise. + + * enquire.c (bitpattern): Change type of variable i to unsigned. + + * final.c (output_asm_insn): Don't cast insn_noperands to unsigned. + + * flow.c (life_analysis): Change type of variable i to size_t; + remove unused variable insn. + + * gcc.c (translate_options): Change type of variables optlen, arglen and + complen to size_t. + (input_filename_length): Change type to size_t. + (do_spec_1): Change type of variable bufsize to size_t. + (main): Change type of variables i and j to size_t; + remove subblock local definition of variable i. + (lookup_compiler): Change type of second argument to size_t; + change type of variable i to size_t. + + * genemit.c (output_init_mov_optab): Change type of variable i to size_t. + + * genopinit.c (get_insn): Change type of variable pindex to size_t. + + * genrecog.c (add_to_sequence): Change type of variable i to size_t. + + * global.c (global_alloc): Change type of variable i to size_t. + + * regclass.c (init_reg_sets): Change type of variables i and j to unsigned. + + * stmt.c (expand_end_bindings): Change type of variable i to size_t. + (expand_end_case): Change type of variable count to size_t. + + * toplev.c (main): Change type of variable j to size_t. + (set_target_switch): Change type of variable j to size_t. + (print_switch_values): Change type of variable j to size_t; + remove unused variable flags. + + * varasm.c (assemble_variable): Change type of variable align to size_t. + (const_hash_rtx): Change type of variable i to size_t. + +1998-03-11 Mark Mitchell + + * dbxout.c (dbxout_type_methods): Only treat TYPE_METHODS as a + TREE_VEC if that's what it really is. + +Wed Mar 11 15:16:01 1998 Michael Meissner + + * {haifa-,}sched.c (rank_for_schedule): Only take void * arguments + as per ISO C spec. + +Wed Mar 11 12:05:20 1998 Teemu Torma + + * gthr.h: Changed the comment about return values. + * gthr-solaris.h (__gthread_once): Do not use errno; return the + error number instead of -1. + (__gthread_key_create): Any non-zero return value is an error. + * libgcc2.c (eh_context_initialize): Check for non-zero return + value from __gthread_once. + Check that the value of get_eh_context was really changed. + +Wed Mar 11 18:26:25 1998 J"orn Rennecke + + * sh.h (LOOP_ALIGN): Only align when optimizing. + * sh.c (find_barrier): Clear inc for CODE_LABELs. + When not optimizing, calculate alignment for BARRIERs directly. + +Wed Mar 11 15:07:18 1998 J"orn Rennecke + + * final.c (shorten_branches): Remove conditionalizing on + SHORTEN_WITH_ADJUST_INSN_LENGTH + * sh.h, pa.h (SHORTEN_WITH_ADJUST_INSN_LENGTH): Remove. + +Wed Mar 11 02:37:41 1998 Jeffrey A Law (law@cygnus.com) + + * flow.c (find_basic_blocks_1): Keep the cfg accurate when removing + an unconditional jump around deleted blocks. + +Mon Mar 9 12:02:23 1998 Jim Wilson + + * profile.c (branch_prob): If see computed goto, call fatal instead of + abort. + + * config/mips/sni-svr4.h (CPP_PREDEFINE): Add -DSNI and -Dsinix. + + * configure.in (alpha-dec-osf): Add default case for osf* to switch. + Patch from Bruno Haible. + + * function.c (put_reg_into_stack): Copy MEM_IN_STRUCT_P from new. + (assign_parms): Set aggregate if hide_last_arg and last_named. + +Mon Mar 9 19:57:56 1998 J"orn Rennecke + + * final.c (shorten_branches): Initialize insn_addresses. + +Mon Mar 9 14:10:23 1998 J"orn Rennecke + + * sh.h (MUST_PASS_IN_STACK): Define. + +Sun Mar 8 13:01:56 1998 Jeffrey A Law (law@cygnus.com) + + * final.c (shorten_branches): Fix minor logic error in + ADDR_DIFF_VEC shortening support. + +Sun Mar 8 02:17:42 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sat Mar 7 00:54:15 1998 Jeffrey A Law (law@cygnus.com) + + * haifa-sched.c (is_cfg_nonregular): Change return type to + an int. No longer compute "estimated" number of edges. Use + computed_jump_p instead of duplicating the code. Fixup/add + some comments. + (build_control_flow): Returns a value indicating an irregularity + in the cfg was detected. Count the number of edges in the cfg. + allocate various edge tables. + (find_rgns): No longer look for unreachable blocks. + (schedule_insns): Do not allocate memory for edge tables here. + Free memory for edge tables before returning. Do not perform + cross block scheduling if build_control_flow returns nonzero. + * flow.c (compute_preds_succs): More accurately determine when + a block drops in. + + * basic-block.h (free_basic_block_vargs): Provide prototype. + + * cccp.c (main): Fix dumb mistakes in last change. + +Fri Mar 6 21:28:45 1998 J"orn Rennecke + + * rtl.h (addr_diff_vec_flags): New typedef. + (union rtunion_def): New member rt_addr_diff_vec_flags. + (ADDR_DIFF_VEC_FLAGS): New macro. + + * sh.c (output_branch): Fix offset overflow problems. + + * final.c (shorten_branches): Implement CASE_VECTOR_SHORTEN_MODE. + (final_scan_insn): New argument BODY for ASM_OUTPUT_ADDR_DIFF_ELT. + * rtl.def (ADDR_DIFF_VEC): Three new fields (min, max and flags). + * stmt.c (expand_end_case): Supply new arguments to + gen_rtx_ADDR_DIFF_VEC. + * 1750a.h (ASM_OUTPUT_ADDR_DIFF_ELT): New argument BODY. + * alpha.h, arc.h, clipper.h, convex.h : Likewise. + * dsp16xx.h, elxsi.h, fx80.h, gmicro.h, h8300.h : Likewise. + * i370.h, i386.h, i860.h, i960.h, m32r.h, m68k.h, m88k.h : Likewise. + * mips.h, mn10200.h, mn10300.h, ns32k.h, pa.h, pyr.h : Likewise. + * rs6000.h, sh.h, sparc.h, spur.h, tahoe.h, v850.h : Likewise. + * vax.h, we32k.h, alpha/vms.h, arm/aof.h, arm/aout.h : Likewise. + * i386/386bsd.h, i386/freebsd-elf.h : Likewise. + * i386/freebsd.h, i386/linux.h : Likewise. + * i386/netbsd.h, i386/osfrose.h, i386/ptx4-i.h, i386/sco5.h : Likewise. + * i386/sysv4.h, m68k/3b1.h, m68k/dpx2.h, m68k/hp320.h : Likewise. + * m68k/mot3300.h, m68k/sgs.h : Likewise. + * m68k/tower-as.h, ns32k/encore.h, sparc/pbd.h : Likewise. + * sh.h (INSN_ALIGN, INSN_LENGTH_ALIGNMENT): Define. + (CASE_VECTOR_SHORTEN_MODE): Define. + (short_cbranch_p, align_length, addr_diff_vec_adjust): Don't declare. + (med_branch_p, braf_branch_p): Don't declare. + (mdep_reorg_phase, barrier_align): Declare. + (ADJUST_INSN_LENGTH): Remove alignment handling. + * sh.c (uid_align, uid_align_max): Deleted. + (max_uid_before_fixup_addr_diff_vecs, branch_offset): Deleted. + (short_cbranch_p, med_branch_p, braf_branch_p, align_length): Deleted. + (cache_align_p, fixup_aligns, addr_diff_vec_adjust): Deleted. + (output_far_jump): Don't use braf_branch_p. + (output_branchy_insn): Don't use branch_offset. + (find_barrier): Remove checks for max_uid_before_fixup_addr_diff_vecs. + Remove paired barrier stuff. + Don't use cache_align_p. + Take alignment insns into account. + (fixup_addr_diff_vecs): Reduce to only fixing up the base label of + the addr_diff_vec. + (barrier_align, branch_dest): New function. + (machine_dependent_reorg, split_branches): Remove infrastructure + for branch shortening that is now provided in the backend. + * sh.md (short_cbranch_p, med_branch_p, med_cbranch_p): New attributes. + (braf_branch_p, braf_cbranch_p): Likewise. + (attribute length): Use new attributes. + (casesi_worker): Get mode and unsignednedd from ADDR_DIFF_VEC. + (addr_diff_vec_adjust): Delete. + (align_2): Now a define_expand. + (align_log): Now length 0. + +Fri Mar 6 14:41:33 1998 Michael Meissner + + * m32r.md (right): Correctly check for length == 2, not 1. + +Fri Mar 6 14:00:04 1998 Kaveh R. Ghazi + + * mips/mips.h: Prototype `machine_dependent_reorg'. + (ASM_OUTPUT_ALIGN): Remove unused variable `mask'. + +Fri Mar 6 11:43:35 1998 Joern Rennecke (amylaar@cygnus.co.uk) + + * final.c (shorten_branches): Restore accidentally removed code. + +Fri Mar 6 11:00:49 1998 Andreas Schwab + + * configure.in: Remove duplicate uses of AC_PROG_CC and + AC_PROG_MAKE_SET. + +Fri Mar 6 00:59:30 1998 Richard Henderson + + * configure.in (target_cpu_default2): Correct typo for alphapca56. + +Thu Mar 5 23:24:50 1998 Jeffrey A Law (law@cygnus.com) + Doug Evans (devans@cygnus.com) + + * haifa-sched.c (build_jmp_edges): Delete dead function. + (build_control_flow): Use cfg routines from flow.c + (schedule_insns): Remove debugging code accidentally checked + in earlier today. + + * basic-block.h: Add external integer list structures, typdefs, + accessor macros and function declarations. Simlarly for + basic block pred/succ support and simple bitmap stuff. + * flow.c: Add functions for integer list, basic block pred/succ + support and simple bitmap support. + (compute_dominators): New function to compute dominators and + post dominators. + (find_basic_blocks): Split into two functions. + (life_analysis): Likewise. + (flow_analysis): Removed. Now handled by calling find_basic_blocks, + the life_analysis from toplev.c + * toplev.c (rest_of_compilation): Call find_basic_blocks, then + life_analysis instead of flow_analysis. + +Thu Mar 5 23:06:26 1998 J"orn Rennecke + + * jump.c (jump_optimize): Call mark_jump_label also for deleted + insns. + (mark_jump_label): Don't increment ref counts for deleted insns. + +Thu Mar 5 09:55:15 1998 Kaveh R. Ghazi + + * mips/iris6.h (TARGET_DEFAULT): Parenthesize macro definition. + + * mips/mips.c: Include stdlib.h and unistd.h. + (mips_asm_file_end): Add braces around empty body in an if-statement. + (function_prologue): Wrap variable `fnname' in + !FUNCTION_NAME_ALREADY_DECLARED. Correct format specifier in fprintf. + (mips_select_rtx_section, mips_select_section): Declare as void. + + * mips/mips.h: Add prototypes for extern functions in mips.c. + (FUNCTION_ARG_REGNO_P): Add parentheses around && within ||. + (ENCODE_SECTION_INFO): Add braces around empty body in an + if-statement. + + * mips/mips.md (movdi): Add parentheses around && within ||. + (movsf, movdf): Likewise. + (branch_zero, branch_zero_di): Add default case in + enumeration switch. + + +Thu Mar 5 02:45:48 1998 Richard Henderson + + * alpha/alpha.h (TARGET_WINDOWS_NT, TARGET_OPEN_VMS): Just make them + real constants, since they can't be changed. + (TARGET_AS_CAN_SUBTRACT_LABELS): New. + * alpha/alpha.md (builtin_setjmp_receiver): Use it. + * alpha/osf.h (TARGET_AS_CAN_SUBTRACT_LABELS): New. + * alpha/osf2or3.h (TARGET_AS_CAN_SUBTRACT_LABELS): New. + * alpha/vms.h (TARGET_OPEN_VMS): New. + * alpha/win-nt.h (TARGET_WINDOWS_NT): New. + +Thu Mar 5 02:41:27 1998 Richard Henderson + + * reload.c (find_reloads): Always force (subreg (mem)) to be + reloaded if WORD_REGISTER_OPERATIONS. + +Thu Mar 5 02:14:44 1998 Richard Henderson + + * haifa-sched.c (free_list): Rename from free_pnd_lst. + (free_pending_lists): Rename free_pnd_lst uses. + (remove_dependence): Place expunged element on unused_insn_list. + (alloc_INSN_LIST, alloc_EXPR_LIST): New. Change all callers of + gen_rtx_*_LIST and alloc_rtx to use them. + (compute_block_backward_dependences): Free the reg_last_* lists. + +Thu Mar 5 00:05:40 1998 Jeffrey A Law (law@cygnus.com) + + * cccp.c (main): Avoid undefined behavior when setting pend_includes + and pend_files. + +Wed Mar 4 21:58:25 1998 Franz Sirl + + * rs6000/linux.h: don't define DEFAULT_VTABLE_THUNKS to 1 if + USE_GNULIBC_1 is defined + * configure.in: add a new case powerpc-*-linux-gnulibc1 which + includes the t-linux-gnulibc1 fragment + +Wed Mar 4 12:11:36 1998 Jim Wilson + + * mips.md (movdf_internal1a): Fix misplaced parenthesis in condition. + +Wed Mar 4 18:47:48 1998 J"orn Rennecke + + * final.c (final_scan_insn, case CODE_LABEL: Cleanup. + +Wed Mar 4 15:51:19 1998 J"orn Rennecke + + * final.c (shorten_branches): Tag the loop alignment onto the + first label after NOTE_INSN_LOOP_BEG even if there is an + intervening insn. + +Tue Mar 3 21:48:35 1998 J"orn Rennecke + + * final.c (insn_current_reference_address): + Use SEQ instead of BRANCH as argument to align_fuzz, to get a + proper alignment chain. + + * final.c (max_labelno): New static variable. + (final_scan_insn): Check max_labelno before outputting an + alignment for a label. + (shorten_branches): Remove unused variable length_align. + +Tue Mar 3 14:27:23 1998 Kaveh R. Ghazi + + * sparc.c (ultrasparc_adjust_cost): Add default case in + enumeration switch. + + * sparc.h: Add prototypes for extern functions defined in + sparc.c. + +Tue Mar 3 10:00:11 1998 Nick Clifton + + * toplev.c: Only generate .dbr file when dumping RTL if + DEALY_SLOTS is defined. + +Tue Mar 3 07:36:37 1998 Manfred Hollstein + + * reorg.c (fill_eager_delay_slots): Add new argument delay_list + in call to fill_slots_from_thread. + +Mon Mar 2 13:45:03 1998 Richard Henderson + + * alpha/linux.h (CPP_PREDEFINES): Correct connecting whitespace + to SUB_CPP_PREDEFINES. Reported by asun@saul4.u.washington.edu. + +Mon Mar 2 22:59:28 1998 J"orn Rennecke + + * final.c (insn_last_address, insn_current_align, uid_align): + New variables. + (in_align_chain, align_fuzz, align_shrink_fuzz): New functions. + (insn_current_reference_address): Likewise. + (shorten_branches, final_scan_insn): Implement LABEL_ALIGN, + LABEL_ALIGN_AFTER_BARRIER and LOOP_ALIGN target macros. + (label_to_alignment): New function. + * genattrtab.c (write_test_expr): If one of LABEL_ALIGN, + LABEL_ALIGN_AFTER_BARRIER or LOOP_ALIGN is defined, call + insn_current_reference_address instead of insn_current_address. + (or_attr_value, write_length_unit_log): New functions. + (main): Call write_length_unit_log. + (write_const_num_delay_slots): Output extra '\n'. + * alpha.h (ASM_OUTPUT_LOOP_ALIGN, ASM_OUTPUT_ALIGN_CODE): + replace with: + (LOOP_ALIGN, ALIGN_LABEL_AFTER_BARRIER). + * i386.h, i386/osfrose.h, i386/svr3dbx.h, m68k.h, sparc.h: Likewise. + * arc.h, m32r.h (ASM_OUTPUT_LOOP_ALIGN): replace with: + (LOOP_ALIGN). + * i960.h, m88k.h: (ASM_OUTPUT_ALIGN_CODE): Replace with: + (LABEL_ALIGN_AFTER_BARRIER). + * ns32k/encore.h, ns32k/merlin.h, ns32k.h, ns32k/sequent.h: Likewise. + * ns32k/tek6000.h: Likewise. + * i386/gas.h (ASM_OUTPUT_LOOP_ALIGN, ASM_OUTPUT_ALIGN_CODE): Delete. + * i386.md (casesi+1): Use ASM_OUTPUT_ALIGN instead of + ASM_OUTPUT_ALIGN_CODE. + +Mon Mar 2 01:05:50 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Mon Mar 2 00:52:18 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sun Mar 1 18:25:49 1998 Michael P. Hayes + + * reorg.c (fill_slots_from_thread): Don't steal delay list from target + if condition code of jump conflicts with opposite_needed. + + * reorg.c (fill_slots_from_thread): Mark resources referenced in + opposite_needed thread. Return delay_list even when cannot get + any more delay insns from end of subroutine. + +Sun Mar 1 18:26:21 1998 Ken Rose (rose@acm.org) + + * reorg.c (fill_slots_from_thread): New parameter, delay_list. + All callers changed. + +Sun Mar 1 18:25:37 1998 Bruno Haible + + * frame.c (start_fde_sort, fde_split, heapsort, fde_merge, + end_fde_sort): New functions for fast sorting of an FDE array. + (fde_insert): Simplified. + (add_fdes): Change argument list. + (frame_init): Use the new functions. + +Sun Mar 1 18:06:21 1998 Jeffrey A Law (law@cygnus.com) + + * ginclude/va-ppc.h (va_arg): Fix typo in long long support. + + * i386.c (reg_mentioned_in_mem): Fix dangling else statement. + + * fold-const.c (fold_range_test): Always return a value. + +Sun Mar 1 17:57:34 1998 Mumit Khan + + * config/i386/winnt.c (i386_pe_unique_section): Put read-only + data in the text section unless READONLY_DATA_SECTION is defined. + +Sun Mar 1 17:48:46 1998 Jeffrey A Law (law@cygnus.com) + + * c-parse.in (undeclared variable error): Tweak error message to + be clearer. + +Sun Mar 1 10:22:36 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +1998-02-28 Mark Mitchell + + * final.c (final_scan_insn): Undo overzealous removal of `set'. + +Sat Feb 28 07:54:03 1998 Kaveh R. Ghazi + + * pa.h (CONST_COSTS): When checking the CONST_DOUBLE enumerated + case, add parentheses to specify the proper order of precedence in + the if-statement. + + + * c-aux-info.c: Include string.h/strings.h. + + * pa.c: Include stdlib.h. + (pa_combine_instructions): Prototype the function. + (pa_can_combine_p, forward_branch_p, shadd_constant_p): Likewise. + (reloc_needed): Add default case for enumeration switch. + (remove_useless_addtr_insns): Remove unused variable `all'. + (hppa_expand_prologue): Add explicit braces to avoid + ambiguous `else'. + (output_function_epilogue): Remove unused variable `i'. + (output_millicode_call): Remove unused variable `link'. + (shadd_constant_p, forward_branch_p): Make the function static. + (following_call): Explicitly declare to return int. + (pa_reorg): Declare as void. + (pa_combine_instructions): Declare as static void. Add + parentheses around && within ||. + + * pa.h: Add prototypes for pa_reorg, symbolic_operand, + following_call, function_label_operand, lhs_lshift_cint_operand + and zdepi_cint_p. + + * pa.md: Add parentheses around && within ||. + + * cppalloc.c: Include stdlib.h. + + * cpperror.c (cpp_print_containing_files): Remove unused variable + `i'. Fix format specifier in fprintf. + + * cse.c (cse_around_loop): Add explicit braces to avoid + ambiguous `else'. + (delete_dead_from_cse): Wrap variable `tem' in macro HAVE_cc0. + + * expr.c (expand_expr): Add parentheses around && within ||. + + * final.c (app_enable): Replace fprintf with fputs where there are + no format specifiers and no trailing argument after the string. + Eg, when printing ASM_APP_ON/ASM_APP_OFF. + (app_disable): Likewise. + (final_end_function): Likewise. + (final_scan_insn): Likewise. Remove unused variable `set'. + (profile_function): Wrap empty if-statement body in {} brackets. + + * function.c: Include stdlib.h. + (pad_below): Wrap prototype and definition in ARGS_GROW_DOWNWARD. + (reposition_prologue_and_epilogue_notes): Add parentheses + around assignment used as truth value. + + * integrate.c (expand_inline_function): Wrap variable + `cc0_insn' in macro HAVE_cc0. + + * jump.c (jump_optimize): Wrap variable `q' in macro + HAVE_cc0. Remove unused variable `prev1'. + + * libgcc2.c (__bb_exit_trace_func): Add parentheses around && + within ||. Fix format specifier in fprintf. + (__bb_init_prg): Add parentheses around assignment used as + truth value. + + * local-alloc.c: Include stdlib.h. + (requires_inout): Add parentheses around assignment used + as truth value. + + * loop.c (analyze_loop_iterations): Wrap prototype and definition + in macro HAVE_decrement_and_branch_on_count. + (insert_bct, instrument_loop_bct): Likewise. + (move_movables): Add parentheses around assignment used as + truth value. + (consec_sets_invariant_p): Likewise. + (maybe_eliminate_biv_1): Wrap variable `new' in macro HAVE_cc0. + + * objc/objc-act.c: Include stdlib.h. + (lookup_method_in_protocol_list): Wrap empty else-statement body + in braces. + (lookup_protocol_in_reflist): Likewise. + (objc_add_static_instance): Remove unused variables `decl_expr' + and `decl_spec'. + (get_objc_string_decl): Remove unused variable `decl'. + (generate_static_references): Remove unused variables `idecl' and + `instance'. + (check_protocols): Wrap empty else-statement body in braces. + + * protoize.c: Include stdlib.h. + (substr): Add parentheses around assignment used as truth value. + (abspath): Likewise. + (shortpath): Likewise. + + * regmove.c (fixup_match_1): Add parentheses around assignment + used as truth value. + + * reload.c (push_secondary_reload): Remove unused variable `i'. + (find_reloads): Add parentheses around assignment used as truth + value. + + * reload1.c: Include stdlib.h. + + * rtl.h: Correct typo in prototype of offsettable_memref_p. + + * stmt.c (add_case_node): Add parentheses around assignment used + as truth value. + (case_tree2list): Likewise. + + * tree.c (valid_machine_attribute): Wrap variable `decl_attr_list' + in macro VALID_MACHINE_DECL_ATTRIBUTE. Wrap variable + `type_attr_list' in macro VALID_MACHINE_TYPE_ATTRIBUTE. + (merge_attributes): Add explicit braces to avoid ambiguous + `else'. + + * unroll.c (copy_loop_body): Wrap variable `cc0_insn' in + macro HAVE_cc0. + + * varasm.c: Include stdlib.h. + + + * system.h: Remove sys/stat.h. + * gcc.c: Add sys/stat.h. + + * genattr.c: Wrap prototype of `free' in NEED_DECLARATION_FREE. + * genattrtab.c: Likewise. + * genconfig.c: Likewise. + * genemit.c: Likewise. + * genextract.c: Likewise. + * genflags.c: Likewise. + * genopinit.c: Likewise. + * genoutput.c: Likewise. + * genpeep.c: Likewise. + * genrecog.c: Likewise. + * tlink.c: Likewise. Also wrap `getenv' in NEED_DECLARATION_GETENV. + +Fri Feb 27 11:02:47 1998 Andreas Schwab + + * invoke.texi: Use @itemx for a secondary item in a @table. + + * config/m68k/m68k.md (movsf+1): Optimize moving a CONST_DOUBLE + zero. + +Thu Feb 26 00:13:21 1998 Ian Lance Taylor + + * choose-temp.c: Fix handling of sys/file.h to work in libiberty. + +Wed Feb 25 23:40:54 1998 Jeffrey A Law (law@cygnus.com) + + * i386.c (struct machine_function): Add new fields for PIC stuff. + (save_386_machine_status): Fix argument to xmalloc. Save pic_label_rtx + and pic_label_name. + (restore_386_machine_status): Corresponding changes. + (clear_386_stack_locals): Also clear pic_label_rtx and pic_label_name. + +Wed Feb 25 01:31:40 1998 Jeffrey A Law (law@cygnus.com) + + * c-parse.y (undeclared variable error): Tweak error message + to be clearer. + +Tue Feb 24 23:54:07 1998 Richard Henderson + + * flags.h (g_switch_value, g_switch_set): Declare. + * alpha.c (override_options): Set g_switch_value=8 if not set. + * alpha/elf.h (CC1_SPEC): New. + (ASM_SPEC): New. + (LINK_SPEC): Pass along the -G value we were given. + (LOCAL_ASM_OP): Remove. + (ASM_OUTPUT_ALIGNED_LOCAL): Output to .bss or .sbss by size. + (MAX_OFILE_ALIGNMENT): New. + (BSS_SECTION_ASM_OP, SBSS_SECTION_ASM_OP, SDATA_SECTION_ASM_OP): New. + (EXTRA_SECTIONS): Add sbss and sdata. + (SECTION_FUNCTION_TEMPLATE): New. + (EXTRA_SECTION_FUNCTIONS): Use it. + (CTORS_SECTION_FUNCTION, DTORS_SECTION_FUNCTION): Remove. + (SELECT_SECTION): Use sdata when small enough. + * alpha/linux.h (ASM_SPEC): Remove. + + +Mon Feb 23 15:09:18 1998 Bruno Haible + * config.sub (sco5): Fix typo. + +Mon Feb 23 18:19:31 1998 Manfred Hollstein + + * config/t-linux (LIBGCC1, CROSS_LIBGCC1, LIBGCC1_TEST): Add macros and + set to empty. + * config/t-linux-aout (LIBGCC1, CROSS_LIBGCC1, LIBGCC1_TEST): Likewise. + * config/alpha/t-linux: Remove file. + * config/sparc/t-linux: Remove file. + * config/m68k/t-linux (LIBGCC1, CROSS_LIBGCC1): Remove. + * config/m68k/t-linux-aout (LIBGCC1, CROSS_LIBGCC1): Likewise. + * configure.in (alpha*-*-linux-gnulibc1*): Use t-linux instead of alpha/t-linux + for tmake_file. + (alpha*-*-linux-gnu*): Likewise. + (sparc-*-linux-gnulibc1*): Use t-linux instead of sparc/t-linux for tmake_file. + (sparc-*-linux-gnu*): Likewise. + +Mon Feb 23 10:47:39 1998 Robert Lipe + * collect2.c (ldd_file_name): Bracket declaration with same + manifests as use. + (full_real_ld_suffix): Deleted. Variable was calloced and + written into, but never read. + +1998-02-23 Mike Stump + + * configure.in: Add support for i386-wrs-vxworks configuration. + * i386/vxi386.h: New file. + +Sun Feb 22 21:16:51 1998 Bruno Haible + + * tree.c (contains_placeholder_p): Ensure function always returns + a value. + * sparc.md (movdi_sp64_insn): Add default case in enumeration switch. + (movsf_const_insn, movdf_const_insn, movtf_const_insn): Likewise. + +Sun Feb 22 20:58:19 1998 Jeffrey A Law (law@cygnus.com) + + * vms.h (SELECT_SECTION): Use TREE_CODE_CLASS correctly. + +1998-02-22 Paul Eggert + + * config/sparc/sol2-sld.h (LINKER_DOES_NOT_WORK_WITH_DWARF2): + Define this new symbol. + (DWARF2_DEBUGGING_INFO, DWARF_DEBUGGING_INFO): Do not #undef. + * toplev.c (main): Do not default to DWARF2_DEBUG with -ggdb if + LINKER_DOES_NOT_WORK_WITH_DWARF2 is defined. + +Sun Feb 22 20:07:32 1998 Jim Wilson + + * iris5.h (DWARF2_UNWIND_INFO): Define to 0. + * iris5gas.h (DWARF2_UNWIND_INFO): Define to 1. + +Sun Feb 22 15:29:48 1998 Richard Henderson + + * objc/Object.m (-error): Call objc_verror with our va_list. + +Sun Feb 22 09:45:39 1998 Kaveh R. Ghazi + + * collect2.c (scan_prog_file): Completely cover uses of variable + `exports' with macro COLLECT_EXPORT_LIST. + +Sat Feb 21 20:36:23 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Fri Feb 20 16:22:13 1998 Michael Meissner + + * sched.c (schedule_block): Remove code to get arguments from hard + regs into pseudos early. Same as Aug 25, 1997 change to + haifa-sched.c. + +1998-02-20 Jason Merrill + + * collect2.c (main): Still handle !do_collecting for non-AIX targets. + +1998-02-16 Mark Mitchell + + * toplev.c (rest_of_compilation): Do not defer the output of a + nested function. + +Fri Feb 20 10:39:47 1998 Michael Tiemann + + * ginclude/va-mips.h (va_arg): Remove trailing space after '\' + continuation character (line 243). + +Fri Feb 20 12:10:26 1998 Andreas Schwab + + * genrecog.c (main): Remove duplicated sentence in emitted comment. + +Thu Feb 19 22:36:53 1998 Andrey Slepuhin + David Edelsohn + + * collect2.c (XCOFF_SCAN_LIBS): Remove. + (export_flag): New variable. + (export_file): #ifdef COLLECT_EXPORT_LIST. + (import_file, exports, imports, undefined): New variables. + (libs, cmdline_lib_dirs, libpath_lib_dirs, libpath, libexts): Same. + (dump_list, dump_prefix_list, is_in_list): New functions. + (write_export_file): $ifdef COLLECT_EXPORT_LIST. + (write_import_file, resolve_lib_name): New functions. + (use_import_list, ignore_library): Same. + (collect_exit): maybe_unlink import_file and #ifdef. + (handler): Same. + (main): New variable importf, #ifdef exportf. Move parsing of + -shared before general argument parsing. Resolve AIX library + paths and import libgcc.a symbols. Treat .so shared libraries the + same as objects and .a libraries. Create alias for object_lst and + increment it instead of original pointer. Scan AIX libraries as + objects earlier instead of using scan_libraries. Perform AIX + tlink later to resolve templates instead of forking ld. + (GCC_OK_SYMBOL): Ensure symbol not in undef section. + (GCC_UNDEF_SYMBOL): New macro. + (scan_prog_file): Loop for members of AIX libraries. Handle + export/import of ctors/dtors. + (aix_std_libs): New variable. + (scan_libraries, XCOFF): Delete. + +Thu Feb 19 22:36:52 1998 Robert Lipe + + * collect2.c (full_real_ld_suffix): #ifdef CROSS_COMPILE. + +1998-02-19 Mike Stump + + * Makefile.in: Use $tooldir for sys-include to match toplevel + configure. + +Thu Feb 19 01:32:37 1998 Jeffrey A Law (law@cygnus.com) + Richard Kenner + + * emit-rtl.c (gen_lowpart_common): Suppress last change if __complex__. + + * emit-rtl.c (hard-reg-set.h): Include. + (get_lowpart_common): Don't make new REG for hard reg in a + class that cannot change size. + * Makefile.in (emit-rtl.o): Depend on hard-reg-set.h. + + * combine.c: Revert previous patch. + +1998-02-19 Paul Eggert + + * config/sparc/sol2-sld.h: New file. + * configure.in (sparc-*-solaris2*): Use it when using the + system linker. + +Thu Feb 19 00:46:59 1998 Jeffrey A Law (law@cygnus.com) + + * loop.c (force_movables): Fix typo. + +Thu Feb 19 08:26:30 1998 Manfred Hollstein + + * m88k.h: Change file pattern to match reality. + +Wed Feb 18 23:19:52 1998 Jeffrey A Law (law@cygnus.com) + + * varasm.c (output_constant_pool): Fix dumb thinko in last + change. + + * pa.h (ASM_OUTPUT_FUNCTION_PREFIX): Correctly translate from + a function name to a section name. + +1998-02-18 Doug Evans + + * tree.h (merge_machine_{type,decl}_attributes): Declare. + (split_specs_attrs, strip_attrs): Add prototypes. + * tree.c (merge_machine_{type,decl}_attributes): New functions. + * c-decl.c (duplicate_decls): Call merge_machine_decl_attributes. + Update olddecl's attributes too. + * c-common.c (strip_attrs): New function. + * c-typeck.c (common_type): Call merge_machine_type_attributes. + * varasm.c (make_function_rtl): New target macro REDO_SECTION_INFO_P. + (make_decl_rtl): Likewise. + +1998-02-18 Jim Wilson + + * c-decl.c (shadow_tag_warned): Call split_specs_attrs. + +Wed Feb 18 09:09:50 1998 Jeffrey A Law (law@cygnus.com) + + Remove this change until we can fix it correctly. + * collect2.c: Bracket declaration of 'exportf' and + 'full_real_ld_suffix'. + +Wed Feb 18 08:44:25 1998 Bernd Schmidt + + * Makefile.in (STAGESTUFF): Add genrtl.c, genrtl.h and gengenrtl. + +Tue Feb 17 23:30:20 1998 Bernd Schmidt + + * c-common.c (c_expand_start_cond, c_expand_end_cond, + c_expand_start_else): Don't warn about non-ambiguous else even if + braces are missing. + +Tue Feb 17 23:56:50 1998 Robert Lipe + + * sco5.h (ASM_OUTPUT_DOUBLE, ASM_OUTPUT_FLOAT, + ASM_OUTPUT_LONG_DOUBLE): Delete. Use the ones from i386.h + instead. + +Tue Feb 17 22:56:14 1998 Richard Henderson + + * combine.c (simplify_rtx): Obey CLASS_CANNOT_CHANGE_SIZE when + simplifying a subreg of a hard reg. + (expand_compound_operation): Likewise. + (force_to_mode): Likewise. + +Tue Feb 17 22:37:22 1998 Kaveh R. Ghazi + + * fold-const.c: Include "system.h" to get stdlib.h and stdio.h. + (lshift_double): Add parentheses around + or - inside shift. + (rshift_double): Likewise. + (size_int_wide): Explicitly set type of `bit_p' to `int'. + + * Makefile.in (fold-const.o): Depend on system.h. + + * Makefile.in (gcc.o): Depend on system.h, in accordance with last + change to gcc.c. + + * haifa-sched.c: Include "system.h" to get and . + (BLOCKAGE_RANGE): Add parentheses around arithmetic in operand of |. + (sched_note_set): Remove unused parameter `b', all callers changed. + (schedule_block): Likewise for `rgn'. + (split_hard_reg_notes): Likewise for `orig_insn'. + (check_live): Likewise for `trg'. + (update_live): Likewise. + (check_live_1): Explcitly declare variable `i' as int. + (update_live_1): Likewise. + (insn_issue_delay): Remove unused variable `link'. + (sched_analyze_2): Add default case in enumeration switch. + (schedule_insns): Remove unused variable `i'. + + * Makefile.in ($(SCHED_PREFIX)sched.o): Depend on system.h. + +Tue Feb 17 22:31:04 1998 Jeffrey A Law (law@cygnus.com) + + * loop.c (rtx_equal_for_loop_p): Add some braces to disambiguate + a dangling else clause. + +Tue Feb 17 21:28:12 1998 Gavin Koch + + * mips/mips.h (CAN_ELIMINATE): Don't eliminate the frame + pointer for the stack pointer in MIPS16 and 64BIT. + +Tue Feb 17 21:17:30 1997 J"orn Rennecke + + * rtl.h (force_line_numbers, restore_line_number_status): Declare. + * emit-rtl.c (force_line_numbers, restore_line_number_status): + New functions. + * stmt.c (struct nesting): Replace seenlabel with line_number_status. + (expand_start_case): Adjust to this change. + (check_seenlabel): New function. + (pushcase, pushcase_range, expand_endcase): Use it. + +Tue Feb 17 10:14:32 1998 J"orn Rennecke + + * i386.md (adddi3): Add =!r,0,0,X alternative. + +Mon Feb 16 16:13:43 1998 David Edelsohn + + * rs6000.h (MY_ISCOFF): Add numeric value of U803XTOCMAGIC. + * x-aix31 (INSTALL): Delete. + +Mon Feb 16 09:24:32 1998 Gavin Koch + + * mips/mips.c (mips_expand_epilogue): Update tsize_rtx if + tsize changes to something other than zero. + +Mon Feb 16 09:11:48 1998 Gavin Koch + + * ginclude/va-mips.h: Replace casts of pointers to int with + casts of pointers to __PTRDIFF_TYPE__. + +Mon Feb 16 08:17:14 1998 John Carr + + * loop.c (strength_reduce, record_biv, record_giv): Use + HOST_WIDE_INT_PRINT_DEC to print CONST_INT values. + +1998-02-16 Jason Merrill + + * tree.c (first_rtl_op): New fn. + (unsave_expr_now): Use it. + * print-tree.c (print_node): Likewise. + * tree.c (has_cleanups): New fn. + * fold-const.c (fold, case CLEANUP_POINT_EXPR): Use it. Be more + conservative about pushing the cleanup point down. + * tree.h: Declare them. + +Sun Feb 15 23:28:44 1998 Jeffrey A Law (law@cygnus.com) + + * toplev.c (flag_schedule_reverse_before_reload): Delete variable. + (flag_schedule_reverse_after_reload): Likewise. + (f_options): Remove reverse scheduling support. + * flags.h (flag_schedule_reverse_before_reload): Delete declaration. + (flag_schedule_reverse_after_reload): Likewise. + * haifa-sched.c (rank_for_schedule): Remove support for reverse + scheduling. + +Sun Feb 15 21:33:55 1998 Kaveh R. Ghazi + + * gcc.c: Get system includes, prototypes and macros via "system.h" + instead of doing it manually. Change all calls of the ctype + macros to custom versions defined in "system.h". + + * system.h: Fix return type of bcmp prototype from `void' to `int'. + Make bcopy, bcmp and bzero prototypes explicitly `extern'. + Add a prototype for getenv. + +Sun Feb 15 17:05:41 1998 Jim Wilson + + * mips/mips.h (INITIAL_ELIMINATION_OFFSET): Readd Jun 6 change. + +Sun Feb 15 15:23:15 1998 John Carr + + * alias.c: Include and . + (init_alias_analysis): Pass NULL_RTX instead of 0 to record_set. + +Sat Feb 14 11:23:09 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sat Feb 14 05:08:21 1998 Richard Earnshaw (rearnsha@arm.com) + + * arm.md (movsfcc): Also validate operands[3] when compiling hard + float. + (movdfcc): Only accept fpu_add_operand for operands[3]. + + * arm/t-semi (STMP_FIXPROTO): Define to nothing. + * arm/t-semiaof (STMP_FIXPROTO): Likewise. + +Sat Feb 14 02:02:41 1998 Jeffrey A Law (law@cygnus.com) + + * varasm.c (output_constant_pool): Bring back 'done' label inside + an appropriate #ifdef. + + * bitmap.c (bitmap_element_allocate): Wrap variable 'i' in an + appropriate #ifdef. + (bitmap_copy, bitmap_operation): Likewise. + * combine.c (combinable_i3pat): Similarly for 'src'. + * function.c (fixup_var_refs_1): Similarly for 'outerdest'. + (locate_and_pad_parm): Similarly for 'reg_parm_stack_space'. + * regclass.c (copy_cost): Similarly for 'secondary_class'. + * reload.c (make_memloc): Simliarly for 'i'. + (find_reloads_address_1): Similarly for 'link'. + * reload1.c (reload): Similarly for 'previous_frame_pointer_needed'. + (emit_reload_insns): Similarly for 'second_reloadreg'. + * unroll.c (iteration_info): Similarly for 'v'. + + * caller-save.c (insert_save_restore): Remove unused variable 'i'. + * calls.c (expand_call): Similarly for 'i'. + (emit_library_call, emit_library_call_value): Similarly for 'mode'. + * fold-const.c (strip_compund_expr): Similarly for 'type'. + * function.c (fixup_var_refs_1): Similarly for 'width'. + (fixup_memory_subreg): Similarly for 'saved'. + (locate_and_pad_parm): Similarly for 'boundary_in_bytes.' + (setjmp_protect): Similarly for 'sub'. + (thread_prologue_and_epilogue_insns): Similarly for 'insn'. + * loop.c (record_giv): Similarly for 'p'. + (combine_givs): Similarly for 'temp_iv'. + (indirect_jump_in_function_p): Similarly for 'is_indirect_jump'. + * recog.c (validate_replace_rtx_1): Similarly for 'width'. + * tree.c (get_set_constructor_bytes): Similarly for 'vals'. + * unroll.c (unroll_loop): Similarly for 'copy'. + (iteration_info): Similarly for 'b'. + * varasm.c (assemble_string): Similarly for 'i'. + * i386.h (LEGITIMIZE_ADDRESS): Similarly for 'orig_x'. + +1998-02-13 Martin von Loewis + + * c-lang.c (lang_print_xnode): New function. + * objc/objc-act.c (lang_print_xnode): Likewise. + * print-tree.c (print_node): Call it + +Fri Feb 13 14:38:34 1998 Jim Wilson + + * dwarf2out.c (decl_scope_node): New type. + (decl_scope_table): Change type to use it. + (decl_scope_table_allocated, decl_scope_depth): Change type to int. + (push_decl_scope): Use new type. New locals containing_scope, i. + Add code to handle setting previous field. + (scope_die_for): Change type of local i to int. Add code to use + previous field. + (dwarf2out_init): Use new type. + +1998-02-13 Jason Merrill + + * except.c (emit_throw): Lose throw_used. + +Fri Feb 13 20:36:05 1998 J"orn Rennecke + + * sched.c (update_flow_info, REG_WAS_0): Ignore if setting insn + was deleted. + * haifa-sched.c (update_flow_info, REG_WAS_0): Likewise. + +Fri Feb 13 12:18:40 1998 Jeffrey A Law (law@cygnus.com) + + * genextract.c (main): Fix typo. + +Fri Feb 13 08:41:49 1998 Robert Lipe + + * c-lang.c (finish_file): Bracket declaration of static_ctors, + static_dtors. + + * calls.c (expand_call): Bracket declaration of 'rtx_before_call', + 'old_stack_arg_under_construction' + (emit_library_call): Bracket declaration of 'upper_bound', + 'lower_bound', 'i', 'reg_parm_stack_space' + (emit_library_call_value): Likewise. + (store_one_arg): + + * collect2.c: include when appropriate. + Bracket declaration of 'exportf' and 'full_real_ld_suffix'. + + * emit-rtl.c (prev_cc0_setter): Remove unused variable 'link'. + + * explow.c (plus_constant_for_output_wide): Remove unused variable + 'code'. + (memory_address): Remove unused variable 'orig_x'. + + * genattrtab.c (make_canonical): Remove unreferenced label 'cond:'. + (write_const_num_delay_slots): Remove unused variable 'i'. + + * genopinit.c (main): Remove unused variables 'dummy', 'insn_ptr'. + (gen_insn): Remove unused variable 'obstack_ptr'. + + * libgcc2.c (__bb_exit_func): Remove unused variables 'ret', + 'j', 'tmp', 'i'. + (__bb_exit_trace_func): Remove unused variable 'e'. + + * optabs.c (expand_binop): remove unused variables 'lhs', 'rhs', + 'funexp'. + (expand_unop): Remove unused variable 'funexp'. + (expand_complex_abs): Remove unused variable 'funexp'. + (init_optabs): Bracket declaration of 'j'. + (init_complex_libfuncs): Deleted. Dead static function. + + * profile.c (branch_prob): Remove unused variables 'insn', 'dest'. + + * reg-stack.c: Fix typo in proto for 'get_asm_operand_lengths' + (reg_to_stack): 'initialized', 'before_function_beg' + explictly type as ints instead of defaulting. + (emit_swap_insn): Remove unused variable 'i2'. + (compare_for_stack_reg): Remove unused variable 'src_note'. + + * rtlanal.c (computed_jump_p): Remove unused variable 'computed_jump'. + + * sched.c (actual_hazard): Bracket declaration of 'this_cost'. + + * stmt.c (add_case_node): Add parens for assignment used as truth. + (all_cases_count): Remove unused variable 'count_high'. + (mark_seen_cases): Remove unused variable 'i'. + (check_for_full_enumeration_handling): Remove unused variable 't'. + Bracket declaration of 'all_values', 'l'. + + * tlink.c: Include , , /. + + * varasm.c (assemble_string): Remove unused variable 'i'. + (immed_double_const): Remove unused variable 'in_current_obstack'. + (immed_real_const_1): Likewise. + (output_constant_pool): Remove unreferenced label 'done'. + (output_constant): Remove unused variable 'x'. + + * i386/i386.h (ENCODE_SECTION_INFO): TREE_PUBLIC is an int, not + a string. + + * i386/sco5.h (ASM_OUTPUT_ASCII): Add parens for assignment used + as truth. + +Fri Feb 13 10:21:41 1998 J"orn Rennecke + + * combine.c (can_combine_p): Handle USEs in PARALLELs. + +Fri Feb 13 01:34:14 1998 H.J. Lu (hjl@gnu.org) + + * config/linux.h (LIB_SPEC): Add -lc for -shared if + USE_GNULIBC_1 is not defined. + * config/sparc/linux.h; Ditto. + + * config/sparc/linux64.h (LIB_SPEC): Add -lc for -shared. + + * config/alpha/linux-elf.h (LIB_SPEC): New. Defined if + USE_GNULIBC_1 is not defined. + +Fri Feb 13 01:29:29 1998 Franz Sirl + + * rs6000/sysv4.h (ENDFILE_SPEC): add missing %(endfile_linux) + for -mcall-linux + +Fri Feb 13 01:23:46 1998 Kaveh R. Ghazi + + * system.h: New file to get common systems includes and various + definitions and declarations based on autoconf macros. + +Fri Feb 13 00:46:19 1998 Jeffrey A Law (law@cygnus.com) + + * cccp.c (new_include_prefix): Correctly handle -I./. + +Thu Feb 12 20:16:35 1998 Michael Meissner + + * rs6000.md: Replace gen_rtx (CONST_INT,...) with GEN_INT. + +Thu Feb 12 16:45:17 1998 Robert Lipe + + * expr.c (expand_assignment): Correct typo exposed by -Wall. + offset should have been a truth value, not an assignment. + +Thu Feb 12 15:26:50 1998 Jeffrey A Law (law@cygnus.com) + + * cse.c (delete_dead_from_cse): If a libcall produces a constant + result and that result can be substituted into SET_SRC of the + insn with the REG_RETVAL note, then perform the substitution + and delete the libcall. + +Thu Feb 12 14:04:09 1998 Gavin Koch + + * mips.md (trucndihi2,truncdiqi2): Change these to support + mips16. + +Thu Feb 12 11:34:55 1998 Gavin Koch + + * mips/mips.c (movdi_operand): Direct referances to symbols + that arn't mips16 consts in mips16 mode arn't valid operands. + + * mips/mips.c (mips_move_2words): Add gprel handling. + +Thu Feb 12 11:18:37 1998 Gavin Koch + + * mips.md (extendsidi2): Allow extension to/from a non-mips16 + register. + +Thu Feb 12 00:04:16 1998 Marc Lehmann + + * i386.c: Conditionally include , , and + . + +Wed Feb 11 11:43:34 1998 Kaveh R. Ghazi + + * Makefile.in (WARN_CFLAGS): New variable. + (bootstrap, bootstrap2, bootstrap3, bootstrap4): Use it. + +1998-02-11 Mark Mitchell + + * config/i386/i386.c (reg_mentioned_in_mem): Don't abort when + falling through default case in switch. + (i386_aligned_p): Likewise. + +Wed Feb 11 12:59:56 1998 Lee Iverson + + * mips/mips.h (mips_abi_string): Correct typo in comment. + +Wed Feb 11 08:29:56 1998 Gavin Koch + + * mips/mips.md (movdi): These PLUS's need to be Pmode. + +Wed Feb 11 01:47:54 1998 Kaveh R. Ghazi + + * Makefile.in (dwarf2out.o, emit-rtl.o, jump.o, cse.o, unroll.o, + reorg.o, regmove.o): Depend on insn-codes.h, it gets included + indirectly via expr.h. + +Wed Feb 11 01:44:13 1998 Richard Henderson + + * stor-layout.c (layout_type): Do upper - lower in the native type, + so as to properly handle negative indices. + +Wed Feb 11 01:35:55 1998 Robert Lipe + + * except.c (start_dynamic_cleanup): Remove unused variable 'dhc'. + (expand_eh_region_start_tree): Remove unused variable 'note'. + (exception_optimize): Remove unused variable 'regions'. + (expand_builtin_eh_stub): Remove unused variable 'temp'. + (copy_eh_entry): Deleted. Dead function. + + * expr.c (move_block_to_reg) Bracket declaration of 'pat' and + 'last' with same #if HAVE_load_multiple as use of it. + (move_block_from_reg): Likewise. + (emit_move_insn_1): Remove unused variable 'insns'. + (store_constructor): Bracket declaration of startb, endb with + #if TARGET_MEMFUNCTIONS. Remove unused variables 'set_word_size' + 'target', and 'xtarget'. + (expand_builtin_setjmp): Remove unused variables 'op0', + 'next_arg_reg', 'old_inhibit_defer_pop'. + (expand_builtin): Remove unused variable 'offset'. + (do_store_flag): Remove unused variables 'pattern', 'jump_pat'. + (emit_queue): Add parens for assignment used as conditional. + (expand_expr): case TARGET_EXPR: Remove unused variable 'temp'. + +Wed Feb 11 01:30:49 1998 Marc Lehmann + + * i386.c: Added include for recog.h. + (override_options): Removed unused variable p. Initialized regno to + avoid warning. + (order_regs_for_local_alloc): Initialized regno to avoid warning. + (legitimize_address): Likewise for 'other'. + (i386_aligned_reg_p): Added default case with abort (). + (print_operand): Likewise. + (reg_mentioned_in_mem): Likewise. + (ix86_expand_binary_operator): Removed unused variables i & insn. + (ix86_expand_unary_operator): Removed unused variable insn. + (output_fp_cc0_set): Removed unused variable unordered_label. + +Wed Feb 11 01:23:03 1998 John F. Carr + + * i386.c, i386.h, i386.md: Change gen_rtx (X, ...) to gen_rtx_X (...). + Use GEN_INT instead of gen_rtx (CONST_INT). Make printf arguments + and format string match. + +Wed Feb 11 01:17:39 1998 Jeffrey A Law (law@cygnus.com) + + * flow.c (life_analysis): Do not conside the stack pointer live at + the end of a function if the fucntio ncalls alloca. + (mark_used_regs): Similarly. + +1998-02-10 John F Carr + + * config/sparc/sparc.md (movdi_v8plus): Output stx on alternative + 1, fzero on alternative 8. + +Tue Feb 10 09:02:19 1998 Richard Kenner + + * rs6000.c (setup_incoming_varargs): Always set rs6000_sysv_varargs_p. + +Tue Feb 10 03:35:43 1998 J"orn Rennecke + + * reload.c (find_reloads_toplev): Handle arbitrary non-paradoxical + SUBREGs of CONST_INTs. + +Mon Feb 9 17:52:36 1998 John Carr + + * mips.c (print_operand, function_prologue): Make printf format + match argument type. + +Mon Feb 9 02:37:25 1998 Kaveh R. Ghazi + + * alpha.c (alpha_return_addr): Remove unused variable `first'. + (alpha_ra_ever_killed): Remove unused variables `ra' and `i'. + (output_epilog): Remove unused variable `frame_size_from_reg_save'. + +Sun Feb 8 14:56:03 1998 Richard Kenner + + * loop.c (strength_reduce): When placing increment for auto-inc + case, do comparison in loop order. + +Sun Feb 8 13:21:38 1998 John Carr + + * bitmap.c (bitmap_debug_file): HOST_PTR_PRINTF converts a pointer, + not a HOST_WIDE_INT. + + * calls.c (expand_call): Change test of expand_inline_function + return value to stop compiler warning. + + * genattrtab.c (RTL_HASH): Cast pointer to long, not HOST_WIDE_INT. + +Sun Feb 8 12:04:24 1998 Jim Wilson (wilson@cygnus.com) + Jeff Law (law@cygnus.com) + + * regmove.c: Fix various minor formatting problems. + (optimize_reg_copy_1): Stop search at CALL_INSNs if flag_exceptions + is true. Make end of basic block tests consistent through regmove.c. + (optimize_reg_copy_2, optimize_reg_copy_3): Likewise. + (fixup_match_2, fixup_match_1, regmove_optimize): Likewise. + +Sun Feb 8 01:49:18 1998 Kaveh R. Ghazi + + * gansidecl.h: Check for a conflicting macro definition before + attempting to prototype bcopy, bcmp or bzero. + +Sun Feb 8 00:09:59 1998 Jeffrey A Law (law@cygnus.com) + + * expr.c (clear_pending_stack_adjust): Handle case where a function + calls alloca, but the user has specified -fomit-fframe-pointer. + + * function.c (assign_parms): Fix typo in last change. + +Sat Feb 7 23:54:29 1998 Robert Lipe + + * gcc.c: Include /, , , + . + (free_path_suffix): Remove unreferenced static function. + (process_command): Remove unused variable temp. + (default_arg): Remove unused variable i. + (do_spec_1): Add parens for assignment used as truth value. + (main): Likewise. + (validate_all_switches): Likewise. + (main): Remove unused variables i, first_time> + + * c-common.c: Include and /. + + * calls.c (expand_call): Remove unused variables funtree, + n_regs, and tmpmode. + + * dbxout.c, except.c: Include /. + + * explow.c: (plus_constant_for_output_wide) Removed unused + variable all_constant. + + * c-decl.c, genattr.c, genattrtab.c, getconfig.c, genemit.c + genextract.c, genflags.c, genopinit.c genoutput.c, genpeep.c, + genrecog.c, global.c, integrate.c , stupid.c : Include + . + + * genextract.c: (walk_rtx) Remove unused variable link. + + * genrecog.c: (concat) Remove unreferenced static function. + + * prefix.c: Include /, + + * stmt.c: Include . + (expand_asm_operands): Remove unused variable val1. + (expand_return): Remove unused variable block. + (pushcase): Remove unused variables l and n. + (pushcaserange): Likewise. + + * unroll.c (unroll_loop): Remove unused variable temp. + +Sat Feb 7 23:46:09 1998 Greg McGary + + * c-decl.c (pushdecl): Set DECL_ORIGINAL_TYPE once only. + +Sat Feb 7 15:11:28 1998 Kaveh R. Ghazi + + * aclocal.m4 (GCC_FUNC_PRINTF_PTR): New macro to test the printf + functions for whether they support the %p format specifier. + * acconfig.h (HOST_PTR_PRINTF): Insert stub for autoconf. + * configure.in (GCC_FUNC_PRINTF_PTR): Use it. + * configure, config.in: Rebuild. + +Fri Feb 6 14:20:16 1998 Jim Wilson + + * function.c (assign_parms): New variable named_arg, with value + depending on STRICT_ARGUMENT_NAMING. Use instead of ! last_named. + +Fri Feb 6 14:34:28 1998 Gavin Koch + + * mips/t-r3900: New - same as t-ecoff but eliminate + multilibs: mips1 and mips3. + * configure.in (tx39*): Use new mips/t-r3900. + * configure: Rebuild. + * mips/r3900.h (MULTILIB_DEFAULTS): Eliminate mips1. + +1998-02-06 Jason Merrill + + * dwarf2out.c: Add old_args_size. + (dwarf2out_args_size): Use it. + (dwarf2out_begin_prologue): Initialize it. + (dwarf2out_stack_adjust): If !asynchronous_exceptions, save up + pushed args until we see a call. + * final.c (final_scan_insn): Hand CALL_INSNs off to the dwarf2 code + before outputting them. + +1998-02-06 Kriang Lerdsuwanakij + + * cplus-dem.c (demangle_template_template_parm): New function. + (demangle_template): Handle template template parameters. + +1998-02-02 Mark Mitchell + + * calls.c (expand_call): Don't confuse member functions named + realloc, setjmp, and so forth with the standard library + functions of the same names. + +Thu Feb 5 21:59:49 1998 Jeffrey A Law (law@cygnus.com) + + * stmt.c (expand_asm_operands): Correctly identify asm statements + no output operands. + +Thu Feb 5 21:56:06 1998 Mumit Khan + + * c-common.c (decl_attributes): Flag unrecognized attribute + functions as warnings instead of as errors. + +1998-02-05 Marc Lehmann + + * integrate.c (INTEGRATE_THRESHOLD): Inline only small functions + when -Os is specified. + * toplev.c (main): Don't disable flag_inline_functions anymore when + -Os is in effect. + +Fri Feb 6 00:27:36 1998 J"orn Rennecke + + * regmove.c: Update. + * flags.h (flag_regmove): Declare. + * rtl.h (optimize_reg_copy_1, optimize_reg_copy_2): Don't declare. + * local-alloc.c (optimize_reg_copy_1, optimize_reg_copy_2): + Moved into regmove; changed caller. + * toplev.c (rest_of_compilation): Call regmove_optimize also for + expensive_optimizations. + +Thu Feb 5 13:38:42 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Thu Feb 5 01:45:19 1998 J"orn Rennecke + Undo this change (the problem was actually in reload): + Fri Jan 23 23:28:59 1998 J"orn Rennecke + + * sh.md (movqi_i+1): New peephole. + +Tue Feb 3 01:11:12 1998 Jeffrey A Law (law@cygnus.com) + + * jump.c (jump_optimize): Lose calls to modified_in_p they are + not needed anymore due to changes elsewhere in jump.c. + + * jump.c (jump_optimize): Fix first arg to modified_in_p in + previous change. + +Mon Feb 2 19:18:14 1998 Richard Henderson + + * expr.c (expand_builtin_setjmp): Accept two new arguments for + the labels to branch to on first and subsequent executions. Don't + play with __dummy. Rename `setjmp' insn to `builtin_setjmp_setup', + and provide it with the jmp_buf. Use only one of + `builtin_setjmp_receiver' or `nonlocal_goto_receiver', + and provide the former with the target label. + (expand_builtin) [BUILTIN_SETJMP]: Generate a label for use by setjmp. + (expand_builtin) [BUILTIN_LONGJMP]: Split out to ... + (expand_builtin_longjmp): ... here. Recognize a `builtin_longjmp' + insn to replace all of the normal nonlocal_goto code. Don't play + with __dummy. Correct arguments to nonlocal_goto. + * expr.h (expand_builtin_setjmp): Update prototype. + * except.c (start_dynamic_handler): When using builtin_setjmp, + generate more accurate flow information. + + * alpha.md (nonlocal_goto_receiver_osf): Delete. + (nonlocal_goto_receiver_vms): Rename to nonlocal_goto_receiver. + (builtin_longjmp, builtin_setjmp_receiver): New. + * sparc.md (update_return): Disambiguate unspec number. + (nonlocal_goto): Rearrange arguments to match caller in except.c. + (builtin_setjmp_setup): Rename from setjmp. Match and ignore the + jmp_buf operand. + * mips.md (nonlocal_goto_receiver, builtin_setjmp_receiver): Remove. + (builtin_setjmp_setup*, builtin_longjmp): New. + +Mon Feb 2 16:43:10 1998 John Carr + + * mips.md: Change gen_rtx (CONST_INT) to GEN_INT. + +Mon Feb 2 13:06:47 1998 Jim Wilson + + * vmsconfig.com: Remove bytecode references. + +1998-01-30 Andreas Schwab + + * dwarf2out.c (dwarf2out_frame_init): Undo last change, so that + -fno-sjlj-exceptions works for a target that defines + DWARF2_UNWIND_INFO as zero. + + * regmove.c (fixup_match_1): Undo last change which removed some + "useless" code, and add a comment explaining this. + +Mon Feb 2 10:47:14 1998 Gavin Koch (gavin@cygnus.com) + + * mips.c (mips_expand_prologue): Change uses of TARGET_64BIT + to TARGET_LONG64. + +Mon Feb 2 10:38:41 1998 Klaus Kaempf + + * makefile.vms: Remove bytecode references. + Create genrtl files. + +Mon Feb 2 02:08:04 1998 Michael P. Hayes + + * jump.c (jump_optimize): Allow conditional loading of floating point + constants and constants from memory. Reinstalled modified_in_p tests. + +Mon Feb 2 01:38:39 1998 J"orn Rennecke + + * loop.c (get_condition): Handle sign-extended constants. + +Mon Feb 2 01:22:46 1998 Hans-Peter Nilsson + + * expr.c (emit_push_insn): Add code to use movstrti if present. + + * expr.c (emit_push_insn): Use same max-move-amount for movstrhi + and movstrqi as in emit_block_move (). + +Mon Feb 2 00:09:52 1998 Toon Moene + + * config/m68k/x-next: Remove /NextDeveloper/Headers from + the directories to fixinclude - /usr/include is a link + to it and hence its contents are fixed by default. + +Sun Feb 1 14:15:33 1998 Franz Sirl + + * rs6000/linux.h: define JUMP_TABLES_IN_TEXT_SECTION + +Sun Feb 1 13:01:15 1998 Klaus Kaempf + + * cccp.c (main): Predefine __VMS_VER on VMS. + +Sun Feb 1 12:39:53 1998 J"orn Rennecke + + * expr.c (get_inner_reference): Use sbitsizetype for type sizes. + * fold-const.c (size_int): Replace with + (size_int_wide). + (make_bit_field_ref): Use bitsize_int for bit position. + * stor-layout.c (sizetype): Delete. + (sizetype_tab, sbitsizetype, ubitsizetype): Declare. + (layout_record, layout_union, layout_type): + Use bitsize_int for bit size. + (set_sizetype): New function. + (make_signed_type, make_unsigned_type): Use it. + * c-decl.c (init_decl_processing): Likewise. + * tree.h (size_int): Don't delcare, #define. + (size_int_wide, sizetype_tab, sbitsize, ubitsize): Declare. + (set_sizetype): Declare. + (bitsize_int, size_int_2, BITS_PER_UNIT_LOG, sizetype, bitsizetype): + Define. + * c-typeck.c (c_sizeof, c_sizeof_nowarn, c_size_in_bytes): + Convert result to sizetype. + (really_start_incremental_init, push_init_level): + Set type of constructor_bit_index to sbitsizetype. + (push_init_level): Use unsigned arithmetic to determine padding. + (output_init_element): Likewise. + +Sun Feb 1 03:32:07 1998 Jeffrey A Law (law@cygnus.com) + + * combine.c (simplify_shift_const): Fix typo in last change. + +Sun Feb 1 02:50:46 1998 John Carr + + * combine.c (simplify_shift_const): (lshiftrt (truncate (lshiftrt))) + is (truncate (lshiftrt)). + +Sun Feb 1 01:06:53 1998 Richard Henderson + + * alpha.c (alpha_expand_unaligned_load): Use expand_binop properly. + Make sure result winds up in TGT. + (alpha_expand_unaligned_store): Use expand_binop properly. Allow + src to be other than DImode. + (alpha_expand_unaligned_load_words): Tidy. Take an offset argument. + (alpha_expand_unaligned_store_words): Likewise. + (alpha_expand_block_move): Use REGNO_POINTER_ALIGN. Restructure so + that source and destination are separately optimized for alignment. + (alpha_expand_block_clear): Use REGNO_POINTER_ALIGN. + +Sun Feb 1 01:55:09 1998 Jeffrey A Law (law@cygnus.com) + + * mips.md (adddi3_internal_2): Be consistent with adddi3 expander + with handling of -32768. + +Sun Feb 1 01:48:18 1998 Kaveh R. Ghazi + + * aclocal.m4 (GCC_NEED_DECLARATION): Modify macro to accept a + shell variable argument instead of only hard coded functions. + (GCC_NEED_DECLARATIONS): New macro to accept multiple functions. + + * configure.in: Collapse multiple calls to AC_CHECK_FUNCS into one + call. Collapse multiple calls to GCC_NEED_DECLARATION into one + call to GCC_NEED_DECLARATIONS (new macro.) Check if we need + declarations for bcopy, bcmp and bzero. + + * acconfig.h: Add stubs for bcopy, bcmp and bzero declarations. + + * gansidecl.h: If we have bcopy but don't declare it, then do so. + Likewise for bcmp and bzero. Only define macros for bcopy, bcmp, + bzero, index and rindex if they aren't already present. + +Sat Jan 31 11:26:58 1998 Jeffrey A Law (law@cygnus.com) + + * toplev.c (close_dump_file): Wrap function prototype for + argument "func" in PROTO. + (dump_rtl): Likewise. + +Fri Jan 30 22:30:39 1998 John Carr + + * sparc.c (sparc_override_options): Make v8plus and ultrasparc set + MASK_V8PLUS. + (output_function_epilogue): Omit epilogue if nothing drops through. + (output_move_double): Supress int ldd usage on ultrasparc and v9. + (registers_ok_for_ldd_peep): Likewise. + (print_operand): Supress b,a on ultrasparc. Let Y accept a constant. + (ultrasparc_adjust_cost): New function. + (sparc_issue_rate): New function. + * sparc.h (MASK_VIS, TARGET_VIS): New + (MASK_V8PLUS, TARGET_V8PLUS): New. + (TARGET_HARD_MUL32, TARGET_HARD_MUL): New. + (TARGET_SWITCHES): Add vis and v8plus. + (REG_CLASS_FROM_LETTER): Accept d and b for VIS. + (REGISTER_MOVE_COST): FP<->INT move cost 12 for ultrasparc. + (RTX_COSTS): Use TARGET_HARD_MUL + (ADJUST_COST): Call ultrasparc_adjust_cost. + (ISSUE_RATE): New. + * sparc.md (attr type): Add sload, fpmove, fpcmove. Adjust users + of load & fp appropritely. + (supersparc function units): Adjust for Haifa. + (ultrasparc function units): Likewise. + (get_pc_via_rdpc): All v9, not just arch64. + (movdi_v8plus, movdi_v8plus+1): New. + (adddi3_sp32+1): New. + (subdi3_sp32+1): New. + (movsi_insn, movsf_const_insn, movdf_const_insn): Know VIS. + (addsi3, subsi3, anddi3_sp32, andsi3, and_not_di_sp32): Likewise. + (and_not_si, iordi3_sp32, iorsi3, or_not_di_sp32, or_not_si): Likewise. + (xorsi3_sp32, xorsi3, xor_not_di_sp32, xor_not_si): Likewise. + (one_cmpldi2_sp32, one_cmplsi2): Likewise. + (ldd peepholes): Suppress for v9. + (return_adddi): Kill redundant test. Arg1 may be arith_operand. + (return_subsi): Revmove. + +Fri Jan 30 18:30:03 1998 John F Carr + + * mips.c (save_restore_insns): Set RTX_UNCHANGING_P in register + save/restore MEM rtl. + +Fri Jan 30 09:08:16 1998 Jeffrey A Law (law@cygnus.com) + + * configure.in: Check for declaration of abort. + * acconfig.h: Corresponding changes. + * toplev.c: Use NEED_DECLARATION_ABORT to determine if abort should + be declared. + +Thu Jan 29 20:26:12 1998 Jeffrey A Law (law@cygnus.com) + + * genattrtab.c (optimize): Define in case PRESERVE_DEATH_INFO_REGNO_P + uses it. + +Thu Jan 29 09:27:56 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Thu Jan 29 10:12:27 1998 Jeffrey A Law (law@cygnus.com) + + * configure.in: Check for atoq and atoll. + * rtl.c (read_rtx): Use HAVE_ATOLL and HAVE_ATOQ to select the + proper routine for converting ascii into long long values. + +Thu Jan 29 01:28:14 1998 Klaus Kaempf + + * cccp.c (SYS$SEARCH, SYS$PARSE): Write as upper-case. + + * vmsconfig.com: Remove bytecode references. + + * alpha/vms.h (PREFIX): Define. + + * alpha/vms.h (ASM_OUTPUT_ALIGNED_COMMON): Remove. + + * am-alpha.h: Don't include alloca for OPEN_VMS. + + * alpha/xm-vms.h (HAVE_CPP_STRINGIFY): Define. + + * alpha/xm-vms.h (INCLUDE_DEFAULTS): Define. + (GCC_INCLUDE_DIR): Define + + * make-cc.com, make-cccp.com, make-cc1.com: Removed. + * makefile.vms: New file. + + * alpha/vms.h (CPP_PREDEFINES): Remove -Dalpha. + + * alpha.c (output_prolog): Output '.name' directive + for minimal traceback information. + + * alpha.c (output_prolog): Don't prepend entry point symbols + with '$' on OPEN_VMS. + +Thu Jan 29 00:25:35 1998 David S. Miller + Jeffrey A Law (law@cygnus.com) + + * rtl.c (read_rtx): Use atol/atoq based upon disposition of + HOST_WIDE_INT. + + * genattrtab.c (write_test_expr): Use HOST_WIDE_INT_PRINT_DEC + as needed. + * genemit.c (gen_exp): Likewise. + * genpeep.c (match_rtx): Likewise. + * genrecog.c (write_tree_1): Likewise. + + * c-lex.c (yyprint): Use proper format string based upon + disposition of HOST_BITS_PER_WIDE_INT. + (yylex): Put casts in right place for args to build_int_2. + +Thu Jan 29 00:24:29 1998 Jeffrey A Law (law@cygnus.com) + + * combine.c: Fix typos in Jan27 changes. + +Thu Jan 29 00:07:49 1998 Ollivier Robert + + * i386/freebsd.h (LIB_SPEC): Correctly handle -shared, -p and friends. + (LINK_SPEC): Likewise. + (STARTFILE_SPEC): Likewise. + +1998-01-28 Mike Stump + + * rtlanal.c (dead_or_set_regno_p): Ignore REG_DEAD notes after + reload completes. + * genattrtab.c (reload_completed): Define. + + * m32r.md, mips.md, mn10200.md, mn10300.md, pyr.md: Remove obsolete + comments. + +Wed Jan 28 20:11:06 1998 J"orn Rennecke + + * reload.c (push_reload): If WORD_REGISTER_OPERATIONS, reload the + SUBREG_REG if the word count is unchanged, also in the input reload + case. Disable non-applicable sanity checks. + +Wed Jan 28 20:08:26 1998 Jeffrey A Law (law@cygnus.com) + + * config/t-svr4 (TARGET_LIBGCC2_CFLAGS): Add -fPIC. + +Wed Jan 28 20:04:43 1998 Ian Lance Taylor + + * i386/t-cygwin32 (LIMITS_H_TEST, LIBGCC2_INCLUDES): Define. + +Wed Jan 28 11:45:27 1998 Per Bothner + + * dbxout.c (dbxout_type): For a RECORD_TYPE, check that TYPE_BINFO + is a TREE_VEC before trying to use it for baseclasses. + (Chill uses the same field for a different purpose.) + + * toplev.c (strip_off_ending): Generalize to endings up to 5 chars. + +Tue Jan 27 23:15:55 1998 Lassi A. Tuura + + * config.sub: More accurate determination of HP processor types. + +Tue Jan 27 23:11:11 1998 Kaveh R. Ghazi + + * c-lex.c: Include and /. Add + prototype for `handle_sysv_pragma', and make it static. Add + parentheses around assignment used as truth value. + + * combine.c (combine_instructions): Protect variable `prev' with + macro HAVE_cc0. + (can_combine_p): Protect variable `link' with AUTO_INC_DEC. + (extract_left_shift): Add parentheses around operand of &. + (merge_outer_ops): Avoid an empty body in an else-statement. + (gen_rtx_combine): Remove unused variable `i'. + + * sparc/gmon-sol2.c: Include . Make return type of + function monstartup `void'. Likewise for internal_mcount. Add + `static void' prototype for moncontrol. Reconcile sprintf format + vs. args. + + * sparc/sparc.c: Include and /. + Make return type of function_arg_slotno explicitly `int'. + (reg_unused_after): Add parentheses around assignment used as + truth value. + (save_regs): Add explicit braces to avoid ambiguous `else'. + (function_arg_slotno): Add parentheses around && within ||. + (function_arg_pass_by_reference): Likewise. + (sparc_flat_output_function_prologue): Reconcile fprintf format + vs. args. + + * svr4.h (ASM_OUTPUT_LIMITED_STRING): Add parentheses around + assignment used as truth value. + + * cplus-dem.c: Include . + (demangle_signature): Avoid an empty body in an else-statement. + (do_type): Remove unused variable `lvl'. + + * cppexp.c: Don't have depend on MULTIBYTE_CHARS. + Include /. + (cpp_lex): Remove unused variable `namelen'. + (cpp_lex): Explicitly declare `num_chars' as an int. + + * cpplib.c: Avoid duplicate inclusion of , include + instead. Explicitly declare is_system_include + returning int. + (make_assertion): Remove unused variable `kt'. + (cpp_expand_to_buffer): Hide variable `obuf'. + (output_line_command): Remove unused variables, `line_end', + `line_cmd_buf' and `len'. + (macarg): Remove unused variable `arg_start'. + (special_symbol): Remove unused variable `i'. Add parentheses + around assignment used as truth value. + (do_include): Remove unused variables `pcfname' and `retried', + hide `pcf' and `pcfbuflimit'. + (do_line): Remove unused variable `i'. + (finclude): Hide variable `missing_newline'. + (cpp_handle_options): Remove unused variable `j'. + (read_token_list): Remove unused variable `eofp'. + (cpp_error_with_line): Remove unused variable `i'. + (cpp_warning_with_line): Likewise. + (cpp_pedwarn_with_line): Explicitly declare `column' as int. + (cpp_error_from_errno): Remove unused variable `i'. + + * cse.c (invalidate): Add parentheses around assignment used as + truth value. + (find_best_addr): Move declaration of variable `our_cost' inside + the conditional macro where its used. + (fold_rtx): Avoid an empty body in an if-statement. + (cse_insn): Wrap variables `this_insn_cc0_mode' and + `this_insn_cc0' in macro HAVE_cc0. + + * dwarf2out.c: Include and /. + (ASM_OUTPUT_DWARF_DATA8): Reconcile format vs. args in fprintf's. + (output_uleb128): Likewise. + (output_sleb128): Likewise. + (output_cfi): Likewise. + (output_call_frame_info): Remove unused variables `j', `fde_size' + and `fde_pad'. + (comp_unit_has_inlines): Hide declaration as per rest of file. + (size_of_line_prolog): Correct typo in prototype. + (add_arange): Likewise. + (output_aranges): Likewise. + (add_name_and_src_coords_attributes): Likewise. + (gen_array_type_die): Likewise. + (gen_inlined_subroutine_die): Likewise. + (equate_decl_number_to_die): Remove unused variable `i'. + (print_die): Reconcile format vs. args in fprintf's. + (print_dwarf_line_table): Likewise. + (output_die): Likewise. + (output_line_info): Likewise. + (add_subscript_info): Avoid an empty body in an else-statement. + (gen_subprogram_die): Remove unused variable `fp_loc'. + + * dwarfout.c: Explicitly declare `next_pubname_number' as int. + Protect `ordering_attribute' prototype with USE_ORDERING_ATTRIBUTE + macro. Protect `src_coords_attribute' prototype with + DWARF_DECL_COORDINATES macro. Hide `output_entry_point_die' + prototype as in the rest of the file. Likewise for + `output_pointer_type_die' and `output_reference_type_die'. Remove + prototype for `type_of_for_scope'. + (output_unsigned_leb128): Reconcile format vs. args in fprintf. + (type_attribute): Add explicit braces to avoid ambiguous `else'. + + * final.c: Include and /. + (shorten_branches): Protect declaration of tmp_length with + SHORTEN_WITH_ADJUST_INSN_LENGTH and ADJUST_INSN_LENGTH macros. + (profile_function): Protect declaration of `sval' and `cxt' + variables with appropriate macros. + (final_scan_insn): Likewise for `note' variable. Add explicit + braces to avoid empty body in an if-statement. + (output_asm_insn): Move variable `i' inside macro conditional + where it is used. Add parentheses around assignment used as truth + value. + (asm_fprintf) Likewise, likewise. + + * fix-header.c (main): Remove unused variable `done'. Protect + declaration of `i' with FIXPROTO_IGNORE_LIST. + + * pexecute.c: Include . Prototype `my_strerror'. + + * print-rtl.c (print_inline_rtx): Explicitly declare the parameter + `ind'. + + * profile.c: Include /. + (instrument_arcs): Remove unused variables `note', `inverted', + `zero' and `neg_one'. + (branch_prob): Avoid empty body in an if-statement. + + * regclass.c: Include . + (reg_alternate_class): Explicitly declare parameter `regno'. + + * regmove.c (regmove_optimize): Remove unused variable `p'. Add + parentheses around assignment used as truth value. + (find_matches): Remove unused variables `output_operand' and + `matching_operand'. + (fixup_match_1): Remove statement with no effect: "if (0) ;". + + * scan.c (sstring_append): Explicitly declare `count' as int. + (scan_string): Explicitly declare parameter `init' as int. + + * sched.c: Include . + (BLOCKAGE_RANGE): Add parentheses around arithmetic in operand of |. + (rank_for_schedule): Add parentheses around assignment used as + truth value. + (schedule_block): Likewise. + (regno_use_in): Likewise. + (schedule_insns): Remove unused variable `i'. + + * toplev.c: Include and /. + (v_message_with_decl): Remove unused variable `n'. + (botch): Explicitly declare parameter `s' as char *. + (main): Add parentheses around assignment used as truth value. + + * tree.c (make_node): Protect the variable `kind' with the + GATHER_STATISTICS macro. + (real_value_from_int_cst): Move variable `e' inside conditional + macro area where it is used. + (tree_last): Add parentheses around assignment used as truth value. + (build1): Protect the variable `kind' with the GATHER_STATISTICS + macro. + (print_obstack_statistics): Reconcile format vs. args in fprintf. + Protect variables `i', `total_nodes', and `total_bytes' with the + GATHER_STATISTICS macro. + +Tue Jan 27 23:01:55 1998 Mike Stump (mrs@wrs.com) + + * m32r.md, mips.md, mn10200.md, mn10300.md, pyr.md: Add + some comments regarding use of dead_or_set_p. + +Tue Jan 27 22:14:48 1998 Todd Vierling + + * fixincludes: Tweak fix for struct exception in math.h + +Tue Jan 27 17:21:09 1998 Gavin Koch (gavin@cygnus.com) + + * mips/mips.c (mips_expand_prologue,mips_expand_epilogue): + Change mode of registers used to add/sub from + hard_frame_pointer_rtx from word_mode to Pmode. + +Tue Jan 27 11:02:04 1998 Nick Clifton + + * v850.h (ASM_OUTPUT_ALIGNED_BSS): Use + asm_output_aligned_bss() instead of asm_output_bss(). + + * toplev.c (rest_of_compilation): Replace references to + stack_reg_dump_file and dbr_sched_dump_file with references to + rtl_dump_file. + +Tue Jan 27 10:22:13 1998 Kamil Iskra + + * tlink.c (scan_linker_output): Call fclose() for opened files. + +Tue Jan 27 05:05:26 1998 Richard Henderson + + * alpha.c (output_epilog [!VMS]): Don't tag global functions if + compiling with -fpic -- we want to be able to override symbols + properly. + (alpha_expand_block_move): Fix thinko in last change. + + * alpha.h (ASM_OUTPUT_MI_THUNK): New define. + * config/alpha/win-nt.h (ASM_OUTPUT_MI_THUNK): New define. + * config/alpha/vms.h (ASM_OUTPUT_MI_THUNK): New undef. + +Tue Jan 27 03:21:23 1998 Richard Henderson + + * alpha.md (abssf, absdf): Revert last change. + +Tue Jan 27 00:26:50 1998 John Carr + + * dwarf2out.c (dwarf2out_frame_init): Test value of DWARF2_UNWIND_INFO. + * mips/sni-svr4.h: Define DWARF2_UNWIND_INFO as 0. + +Tue Jan 27 00:07:02 1998 Jeffrey A Law (law@cygnus.com) + + * emit-rtl.c (gen_lowpart_common): Handle more case where converting + a CONST_INT into SFmode. + +Tue Jan 20 16:01:03 1998 Anthony Green + + * flags.h: New flag (optimize_size). + * toplev.c (main): Parse -Os option and set optimize_space + accordingly. + * gcc.c (default_compilers), cp/lang-specs.h, f/lang-specs.h: Define + __OPTIMIZE_SIZE__ when compiling with -Os. + * config/dsp16xx/dsp16xx.h, config/i386/i386.h, + config/i386/dgux.h, config/i960/i960.h, config/pdp11/pdp11.h, + config/v850/v850.h (OPTIMIZATION_OPTIONS): New SIZE argument + to macro. + * config/i386/i386.c (optimization_options): Accept new SIZE argument. + +Mon Jan 26 23:57:39 1998 Manfred Hollstein + + * libgcc2.c (__clear_insn_cache): On sysV68 enable the memctl + stuff only if MCT_TEXT is #define'd. + +Mon Jan 26 23:52:51 1998 Markus F.X.J. Oberhumer + + * configure.in (i*86-pc-msdosdjgpp): Treat like msdos & go32 + configurations. + +Fri Jan 23 09:39:36 1998 Nick Clifton + + * toplev.c: Add -dM command line option to dump RTL after the + machine dependent reorganisation pass, if there is one. + Reorganise RTL dump code, so that only one file handle is + needed. + +Mon Jan 26 12:09:42 1998 Benjamin Kosnik + + * except.c (check_exception_handler_labels): Disable warning when + flag_syntax_only. + +Mon Jan 26 18:17:32 1998 Jim Wilson + + * sparc.c (pic_setup_code): Don't set LABEL_PRESERVE_P. + +Mon Jan 26 18:11:30 1998 J"orn Rennecke + + * c-decl.c (grokdeclarator): Get parameter tags from + last_function_parm_tags. + * dwarfout.c (output_formal_types): Set TREE_ASM_WRITTEN before + traversing the parameter types. + (output_type): No early exit for FUNCTION_TYPE / METHOD_TYPE context. + +Mon Jan 26 01:44:12 1998 Jeffrey A Law (law@cygnus.com) + + * h8300.c (print_operand): Handle CONST_DOUBLE for 'e', 'f', and + the default case. + (get_shift_alg): Fix typo. + +Sun Jan 25 22:22:04 1998 Richard Henderson + + * alpha.c (alpha_expand_block_move): Copy ADDRESSOF to reg. + +Sun Jan 25 22:14:28 1998 Richard Henderson + + * toplev.c (get_run_time): Make sure each case gets its variables. + +Sun Jan 25 22:10:21 1998 Richard Henderson + + * configure.in (build_xm_file): Add auto-config.h if host=build. + (host_xm_file_list): Don't add $(srcdir) to auto-config.h. + (build_xm_file_list): Likewise. + * configure: Rebuild. + +Sun Jan 25 22:00:25 1998 Alasdair Baird + + * recog.c (validate_replace_rtx_1): Only perform substitutions + of arguments to commutative and comparison operators once. + +Sun Jan 25 12:30:18 1998 Kaveh R. Ghazi + + * sparc.c (output_cbranch): Add default case in + enumeration switch. + + * reorg.c (insn_sets_resource_p): Correct typo in prototype. + (emit_delay_sequence): Eliminate unused parameter, all callers + changed. + (fill_simple_delay_slots): Likewise. + (fill_slots_from_thread): Likewise. + (fill_eager_delay_slots): Likewise. + (mark_referenced_resources): Add default case in enumeration switch. + (mark_set_resources): Likewise. + (rare_destination): Likewise. + (mostly_true_jump): Likewise. + (find_dead_or_set_registers): Likewise. + (redirect_with_delay_slots_safe_p): Remove unused variable `slots'. + (update_reg_unused_notes): Remove unused variable `p'. + (mark_target_live_regs): Remove unused variables `next' and + `jump_count'. + (fill_simple_delay_slots): Remove unused variable `j'. + (fill_slots_from_thread): Add parentheses around assignment used + as truth value. + (dbr_schedule): Likewise. + + * objc/Make-lang.in (objc.stage1): Depend on stage1-start. + (objc.stage2, objc.stage3, objc.stage4): Likewise. + +Sun Jan 25 12:13:47 1998 Michael Tiemann + + * cse.c (simplify_ternary_operation): Don't try to simplify + IF_THEN_ELSE expressions (created by combine) that don't use + relational operators. + +Fri Jan 23 22:48:24 1998 Jeffrey A Law (law@cygnus.com) + + * cse.c (simplify_ternary_operation): Handle more IF_THEN_ELSE + simplifications. + + * crtstuff.c (init_dummy): Keep the epilogue in the init + section for non-ELF systems. + +Fri Jan 23 23:28:59 1998 J"orn Rennecke + + * sh.md (movqi_i+1): New peephole. + +Fri Jan 23 15:39:42 1998 Jim Wilson + + * Makefile.in: Remove remaining bytecode stuff. + * emit-rtl.c, expr.c: Likewise. + +Fri Jan 23 12:41:10 1998 Nick Clifton (nickc@cygnus.com) + + * toplev.c (lang_options): Add unknown-pragma options. + +Thu Jan 22 23:43:38 1998 Per Bothner + + * dwarfout.c (byte_size_attribute): Simplify and fix - don't need + special (and incomplete) handling for Chill arrays. + +Fri Jan 23 00:27:23 1998 John Carr + + * toplev.c (get_run_time): Call sysconf(_SC_CLK_TCK), when available, + to get clock rate. + +Fri Jan 23 00:19:36 1998 Gavin Koch (gavin@cygnus.com) + + * mips.md (muldi3_internal2): Reverse test for TARGET_MIPS16. + +1998-01-22 scott snyder + + * mips.c (function_prologue): Use HARD_FRAME_POINTER_REGNUM in + .frame directive instead of FRAME_POINTER_REGNUM. + +Fri Jan 23 00:08:55 1998 Robin Kirkham + + * m68k.h (TARGET_SWITCHES): -mcpu32 now clears MASK_68881. + (MACHINE_STATE_m68010_up): Replaced __mc68332__ with __mcpu32__. + * m68k/m68k-none.h(CPP_FPU_SPEC): Update relative to TARGET_SWITCHES. + (CPP_SPEC, ASM_SPEC, CC1_SPEC): Likewise. + (CPP_SPEC): -m68332 defines both __mc68332 and __mcpu32__. + * m68k/t-m68kbare (MULTILIB_OPTIONS): Add mcpu32. + (MULTILIB_MATCHES): -m68332 now uses mcpu32 libraries, not m68000. + (MULTILIB_EXCEPTIONS): Don't build 68881 libraries for m68000, + mcpu32 or m5200. + * longlong.h: Replace __mc68332__ with __mcpu32__. + +Thu Jan 22 19:55:40 PST 1998 Jeff Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Thu Jan 22 14:47:31 1998 Jim Wilson + + * reload.c (push_reload): In WORD_REGISTER_OPERATIONS code, add test + to require the SUBREG mode to be smaller than the SUBREG_REG mode. + * reload1.c (eliminate_regs): Likewise. + +Thu Jan 22 14:49:14 1998 Jeffrey A Law (law@cygnus.com) + + * regmove.c (find_matches): Initialize matches->earlyclobber too. + +Thu Jan 22 01:40:52 1998 Richard Henderson + + * alpha.md (abssf2, absdf2): Disable in IEEE mode. + (negsf2, negdf2): Use proper subtract in IEEE mode. + +Tue Jan 20 09:29:09 1998 Jeffrey A Law (law@cygnus.com) + + * Makefile.in: Remove more bytecode stuff. + * expr.c, stmt.c, config/msdos/top.sed: Likewise. + * vax/xm-vms.h, winnt/config-nt.sed: Likewise. + * f/install.texi, objc/Make-lang.in: Likewise. + + * Makefile.in: Remove all bytecode support. + (OBJS): Make sure last entry is a real object file, not EXTRA_OBJS. + * emit-rtl.c: Remove all bytecode support. + * expr.c, expr.h function.c, integrate.c: Likewise. + * output.h, regclass.c, rtl.h, stmt.c, toplev.c: Likewise. + * tree.h, varasm.c: Likewise. + * config/m68k/m68k.h: Likewise. + * bi-*, bc-*, bytecode*: Delete bytecode related files. + * modemap.def: Likewise. + +Tue Jan 20 09:02:31 1998 Gavin Koch (gavin@cygnus.com) + + * mips/mips.md (divsi3,divdi3,modsi3,moddi3,udivsi3,udivdi3, + umodsi3,umoddi3): Handle mips16 div/mod by a constant. + +Mon Jan 19 21:57:00 1998 Richard Henderson + + * i386.md (push): Prohibit symbolic constants if flag_pic. + (movsi+1): Likewise for move to non-register. + +Mon Jan 19 11:15:38 1998 Jim Wilson + + * alpha.c (mode_mask_operand): Accept 0xffffffff on 32 bit host. + (print_operand): Handle 0xffffffff on 32 bit host. + + * configure.in (thread_file): Rename uses before main loop to + target_thread_file. Initialize to empty in main loop. Set thread_file + to target_thread_file after main loop if not set. + * configure: Rebuild. + + * genattrtab.c (find_and_mark_used_attributes): Handle CONST_INT. + (add_values_to_cover): Revert last change (which had no ChangeLog + entry). + (simplify_with_current_value_aux): Handle CONST_INT. + +Mon Jan 19 10:14:55 1998 Andreas Schwab + + * unprotoize.c: Define UNPROTOIZE first, to actually take effect. + +Mon Jan 19 10:11:52 1998 Richard Henderson + + * configure.in: Add cpp stringify test. + * acconfig.h (HAVE_CPP_STRINGIFY): New tag. + * gengenrtl.c: Use it. + * configure, config.in: Rebuild. + +Mon Jan 19 09:43:15 1998 Andreas Schwab + + * Makefile.in (genrtl.c genrtl.h): Add dummy command for GNU make. + +Mon Jan 19 09:38:18 1998 Richard Henderson + + * configure.in: Find declaration for sbrk. + * acconfig.h (NEED_DECLARATION_SBRK): New tag. + * config.in, configure: Rebuild. + * mips-tfile.c: Properly protect declaration of sbrk and free. + * toplev.c: Properly protect declaration of sbrk. + +Sun Jan 18 20:18:01 1998 Richard Henderson + + * alpha.c (alpha_handle_trap_shadows): Ignore CLOBBERs. + +Sun Jan 18 01:54:27 1998 Jeffrey A Law (law@cygnus.com) + + * alpha/xm-winnt.h (HAS_INIT_SECTION): Undefine. + +Sun Jan 18 00:57:35 1998 Mike Stump (mrs@wrs.com) + + * configure.in (i960-wrs-vxworks): Default to latest vxworks release. + +Sat Jan 17 23:41:36 1998 David S. Miller + + * combine.c (force_to_mode, nonzero_bits): Correctly optimize + constant offset computations from objects with known alignment in + the presence of STACK_BIAS. + + * varasm.c (immed_double_const): Add casts to HOST_WIDE_INT where + necessary. + (const_hash): Hash val is unsigned long. + (SYMHASH): Likewise. + + * tree.c (TYPE_HASH): Type of hash val is unsigned long. + + * print-tree.c (print_node_brief): HOST_PTR_PRINTF format wants a + char pointer, not HOST_WIDE_INT. + (print_node): Likewise. Also hash is unsigned long not + HOST_WIDE_INT. + + * cse.c (canon_hash): Hash is unsigned long not HOST_WIDE_INT. + + * explow.c (optimize_save_area_alloca): New function for targets + where SETJMP_VIA_SAVE_AREA is true. + (allocate_dynamic_stack_space): On SETJMP_VIA_SAVE_AREA targets, + compute the amount of stack space needed should we find later that + setjmp is never called by this function, stuff rtl for this inside + a REG_NOTE of the final SET of stack_pointer_rtx. + * toplev.c (rest_of_compilation): If SETJMP_VIA_SAVE_AREA and + current_function_calls_alloca, call optimize_save_area_alloca. + +Sat Jan 17 23:22:59 1998 John Wehle (john@feith.com) + + * i386.md: Remove redundant integer push patterns. + Don't bother checking for TARGET_PUSH_MEMORY when + pushing constants or registers. + +Sat Jan 17 22:35:39 1998 Mumit Khan + J.J VanderHeijden + + * pexecute.c (pexecute): New function for mingw32. Supports pipes. + (pwait): New function for mingw32. + + * gcc.c (execute): Mingw32 pexecute() supports pipes, but cygwin32 + pipe support is broken for now. + +1998-01-17 Lee Iverson + + * emit_rtl.c (init_emit_once): Ensure that potential aliasing + between frame_pointer_rtx, hard_frame_pointer_rtx, and + arg_pointer_rtx is respected in initialization. + (init_emit_once): Use gen_rtx_raw_REG() to create + return_address_pointer_rtx. + + * reorg.c: #include "expr.h" for rtx prototypes. + * Makefile.in (reorg.o): Depend on expr.h + +Sat Jan 17 21:28:08 1998 Pieter Nagel + + * Makefile.in (FLAGS_TO_PASS): Pass down gcc_include_dir and + local_prefix to sub-make invocations. + +Sat Jan 17 21:24:16 1998 David T. McWherter + + * objc-parse.c: Recognize protocol qualifiers in class definitions. + +Sat Jan 17 21:16:19 1998 Jeffrey A Law (law@cygnus.com) + + * rtl.h: Fix typos. + + * acconfig.h (NEED_DECLARATION_ATOL): New declaration to check for. + * configure.in: Check for atol. + * rtl.c (atol): Only provide the declaration if NEED_DECLARATION_ATOL. + + * rtl.c (read_rtx): Initialize list_rtx to NULL, not NULL_RTX. + + * loop.c (find_and_verify_loops): When attempting to move insns from + inside the loop outside the loop, create a BARRIER if no suitable + one was found. + + * jump.c (jump_optimize): Remove Dec 17, 1997 chance in + favor of an equivalent change from gcc-2.8. + + * i386/x-sco5 (CC): Remove trailing whitespace. + +Sat Jan 17 21:09:46 1998 Kaveh R. Ghazi + + * gengenrtl.c (type_from_format): De-ANSIfy function signature. + (accessor_from_format): Likewise. + (xmalloc): New function for use when linking with alloca.o. + +Mon Jan 5 02:53:01 1998 Bruno Haible + + * frame.c (find_fde): Correct FDE's upper bound. + +Fri Jan 16 16:23:52 1998 Richard Henderson + + * gengenrtl.c (DEF_RTL_EXPR): Provide a K&R compliant version. + +Fri Jan 16 10:16:10 1998 Jeffrey A Law (law@cygnus.com) + + * calls.c (expand_call): Move #ifdef code out of macro argument + lists. + (emit_library_call, emit_library_call_value): Likewise. + +Fri Jan 16 00:46:40 1998 Jeffrey A Law (law@cygnus.com) + + * rtl.def (INLINE_HEADER): Fix bug exposed by gen_rtx_FOO changes. + +Thu Jan 15 01:02:30 1998 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Wed Jan 14 22:49:17 1998 Richard Henderson + + * alias.c: Change all uses of gen_rtx(FOO...) to gen_rtx_FOO; + change gen_rtx(expr...) to gen_rtx_fmt_foo(expr...). + * caller-save.c, calls.c, combine.c, cse.c: Likewise. + * dwarf2out.c, except.c, explow.c, expmed.c, expr.c: Likewise. + * final.c, flow.c, function.c, genpeep.c, haifa-sched.c: Likewise. + * halfpic.c, integrate.c, jump.c, local-alloc.c, loop.c: Likewise. + * profile.c, recog.c, reg-stack.c, regclass.c, regmove.c: Likewise. + * reload.c, reload1.c, reorg.c, sched.c, stmt.c, stupid.c: Likewise. + * unroll.c, varasm.c: Likewise. + * config/alpha/alpha.c, config/alpha/alpha.md: Likewise. + +Wed Jan 14 19:36:08 1998 Gavin Koch (gavin@cygnus.com) + + * mips.h: Fix some type-o's from a previous change. + +Wed Jan 14 01:26:05 1998 Jeffrey A Law (law@cygnus.com) + + * loop.c (check_dbra_loop): Make sure initial value is a + CONST_INT before trying to normalize it. + +Tue Jan 13 23:27:54 1998 Robert Lipe (robertl@dgii.com) + + * sco5.h (ASM_OUTPUT_SECTION_NAME): Refresh from ../svr4.h. + +Tue Jan 13 22:47:02 1998 Herman ten Brugge + + * cppexp.c: Include gansidecl.h + +Tue Jan 13 22:43:35 1998 Ian Lance Taylor + + * svr4.h (LINK_SPEC): Never specify -h. + * ptx4.h (LINK_SPEC): Likewise. + * rs6000/sysv4.h (LINK_SPEC): Likewise. + * sparc/sol2.h (LINK_SPEC): Likewise. + +Tue Jan 13 22:39:40 1998 Richard Henderson (rth@cygnus.com) + + * c-typeck.c (comptypes): Exit early on NULL input. + + * haifa-sched.c (schedule_insns): Correctly remove inter-block + dependencies after reload. + +Tue Jan 13 22:22:31 1998 Franz Sirl + + * rs6000/linux.h (CPP_PREDEFINES): Add -D__ELF__. + +Tue Jan 13 22:14:57 1998 Klaus Kaempf + + * alpha/vms.h (DIR_SEPARATOR): define + +Tue Jan 13 22:13:04 1998 Bruno Haible + + * Makefile.in (stamp-proto): Remove. + (protoize.o, unprotoize.o): Straightforward compile. + * unprotoize.c: Define UNPROTOIZE here, not in the Makefile. + +Tue Jan 13 21:59:39 1998 Mumit Khan + + * i386/cygwin32.h (STRIP_NAME_ENCODING): Define for Win32 to strip + off the trailing @[NUM] added by ENCODE_SECTION_INFO. + +Tue Jan 13 21:55:06 1998 Jeffrey A Law (law@cygnus.com) + + * arm/netbsd.h (DWARF2_UNWIND_INFO): Define as zero for now. + * i386/netbsd.h, m68k/netbsd.h, ns32k/netbsd.h: Likewise. + * sparc/netbsd.h, vax/netbsd.h: Likewise. + +Tue Jan 13 21:37:07 1998 Shigeya Suzuki + + * i386/bsd386.h (DWARF2_UNWIND_INFO): Define as zero for now. + +Tue Jan 13 17:50:55 1998 Jim Wilson + + * configure.in (target_cpu_default, target_cpu_default2): Use double + quotes around them when testing their value. + * configure: Rebuilt. + +Tue Jan 13 09:07:44 1998 John Carr + + * gengenrtl.c (gencode): Emit new function obstack_alloc_rtx + to allocate rtx. + (gendef): Call obstack_alloc_rtx. + +Tue Jan 13 01:16:36 1998 Robert Lipe (robertl@dgii.com) + + * configure.in: (i[3456]86-UnixWare7-sysv5): Treat much like SVR4 + for now. + +Thu Dec 18 18:40:17 1997 Mumit Khan + + * i386/mingw32.h (INCOMING_RETURN_ADDR_RTX): Delete. Use the value + of DWARF2_UNWIND_INFO, if any, from i386/cygwin32.h instead. + (STANDARD_INCLUDE_DIR): Change to /usr/local/i386-mingw32/include. + +Tue Jan 13 00:44:02 1998 Jim Wilson + + * mips.md (return_internal): Change mode from SImode to VOIDmode. + +Sat Jan 10 22:11:39 1998 J. Kean Johnston + + * i386/sco5.h (STARTFILE_SPEC, ENDFILE_SPEC): Correctly handle + "-static". + +Sat Jan 10 22:04:15 1998 Stan Cox + + * i386.md: (movsicc_1, movhicc_1): For alternate 3 set the opcode + suffix from operand 3. + +Sat Jan 10 21:50:16 1998 J"orn Rennecke + Jeffrey A Law (law@cygnus.com) + + * regmove.c: New implementation of regmove pass. + * local-alloc.c (optimize_reg_copy_1, optimize_reg_copy_2): Remove + decls, make them have external linkage. Return a value from + optimize_reg_copy_1. + * reload.h (count_occurrences): Add decl. + * reload1.c (count_occurrences): Delete decl, make it have external + linkage. + * rtl.h (optimize_reg_copy_1, optimize_reg_copy_2): Declare. + +Sat Jan 10 20:30:12 1998 Jeffrey A Law (law@cygnus.com) + + * regclass.c (record_address_regs): Don't use REG_OK_FOR_BASE_P + if it is not defined. + +Thu Jan 8 21:06:54 1998 Richard Henderson + + * Makefile.in (OBJ, GEN, RTL_H): Add genrtl.[oh] bits. + * emit-rtl.c (gen_rtx): Move special code to ... + (gen_rtx_CONST_INT): New function. + (gen_rtx_REG): New function. + (*): Update all calls to gen_rtx. + * genemit.c (gen_exp): Emit calls to gen_rtx_FOO for constant FOO. + * rtl.h: Include genrtl.h; prototype CONST_INT & REG generators. + (GEN_INT): Call gen_rtx_CONST_INT. + * gengenrtl.c: New file. + +Mon Jan 5 13:00:18 1998 John F. Carr + + * alias.c (*_dependence): Call base_alias_check before canon_rtx. + (base_alias_check): If no base found for address call canon_rtx and + try again. + +Mon Jan 5 11:39:49 1998 Jeffrey A Law (law@cygnus.com) + + * mips.c (mips_expand_prologue): Handle large frame with no outgoing + arguments for mips16. + (mips_expand_epilogue): Pass "orig_tsize" to save_restore_insns. + Don't lose if tsize is zero after handling large stack for mips16. + * mips.md (return): For trivial return, return address is in $31. + +Sun Jan 4 20:24:00 1998 Nigel Stephens + + * mips/mips16.S: Various changes to make it work with -msingle-float + and -EL. + +Sun Jan 4 14:25:18 1998 Gavin Koch + Ian Lance Taylor + Jeff Law + + * mips.c, mips.h, mips.md: First cut at merging in mips16 + support. Major modifications throughout all three files. + +Sun Jan 4 01:01:50 1998 scott snyder + + * configure.in: Make gthr-default.h a forwarding header instead of + a symlink. + +Sat Jan 3 12:08:06 1998 Kaveh R. Ghazi + + * gcov-io.h: Include sys/types.h to ensure we get size_t. + + * pa.h (ASM_OUTPUT_MI_THUNK): Add missing % in fprintf. + +Fri Jan 2 23:40:09 1998 Jim Wilson (wilson@cygnus.com) + Jeffrey A Law (law@cygnus.com) + + * crtstuff.c (__frame_dummy): New function for irix6. + (__do_global_ctors): Call __frame_dummy for irix6. + * iris6.h (LINK_SPEC): Hide __frame_dummy too. + +Fri Jan 2 04:57:57 1998 Weiwen Liu + + * alpha.c (vms_valid_decl_attribute_p): Move within #if OPEN_VMS. + +Fri Jan 2 04:34:14 1998 Richard Henderson + + * c-decl.c (init_decl_processing): Provide proper fallback symbol + for __builtin_memset. + * expr.c (expand_builtin) [MEMSET]: Arg 3 type code is INTEGER_TYPE + not INTEGER_CST. Assert arg 3 is a constant. + + * alpha.c (mode_width_operand): Accept 64-bit modes. + (mode_mask_operand): Likewise. + (print_operand): Likewise for 'M' and 'U' codes. + (alpha_expand_unaligned_load): New function. + (alpha_expand_unaligned_store): Likewise. + (alpha_expand_unaligned_load_words): Likewise. + (alpha_expand_unaligned_store_words): Likewise. + (alpha_expand_block_move): Likewise. + (alpha_expand_block_clear): Likewise. + * alpha.h (MOVE_RATIO): New define. + * alpha.md (extxl, ext*h, ins*l, mskxl): Name them. + (insql, insxh, mskxh, extv, extzv, insv, movstrqi, clrstrqi): New. + + * alpha.h (ASM_OUTPUT_LOOP_ALIGN, ASM_OUTPUT_ALIGN_CODE): Set to 3. + (CONSTANT_ALIGNMENT, DATA_ALIGNMENT): Disable. + +Thu Jan 1 15:40:15 1998 Richard Henderson + + * configure.in: Put parenthesis around TARGET_CPU_DEFAULT's value. + * configure: Update. + +Thu Jan 1 10:49:12 1998 Jeffrey A Law (law@cygnus.com) + + * emit-rtl.c (operand_subword): Correctly handle extracting a word + from a CONST_DOUBLE for 16bit targets with !WORDS_BIG_ENDIAN. + + * mn10200.md (tstxx, cmpxx): Use "nonimmediate_operand" as predicate + for first argument. + +Wed Dec 31 14:42:18 1997 Ian Lance Taylor + + * configure.in: Set and subsitute host_exeext. Use it when creating + the assembler and linker symlinks. + * configure: Rebuild. + * Makefile.in (exeext): Set to @host_exeext@. + (build_exeext): New variable, set to @build_exeext@. + (FLAGS_TO_PASS): Pass down build_exeext. + (STAGESTUFF): Use build_exeext, not exeext, for gen* and bi* + programs. + +Wed Dec 31 10:05:44 1997 Jeffrey A Law (law@cygnus.com) + + * mn10200.md (addsi3, subsi3): Fix thinkos. + +Tue Dec 30 00:04:49 1997 Richard Henderson + + * sparc.h (ASM_OUTPUT_MI_THUNK): Move %o7 through %g1 instead of + save+restore. Fix pic+big_offset delay slot. Use "pic" case for + unix always, since we want to be able to thunk to functions in a + shared library from an application. + +Mon Dec 29 14:37:31 1997 Ian Lance Taylor + + * mips/t-ecoff (CROSS_LIBGCC1): Define to libgcc1-asm.a. + (LIB1ASMSRC, LIB1ASMFUNCS): Define. + +Mon Dec 29 14:03:38 1997 Jeffrey A Law (law@cygnus.com) + + * expr.c (expand_expr): For {BITFIELD,COMPONENT,ARRAY}_REF, if the + offset's mode is not ptr_mode, convert it. + +Mon Dec 29 15:58:18 1997 Michael Meissner + + * libgcc2.c (inhibit_libc): Don't define inhibit_libc when cross + compiling if it was already defined. + +Sun Dec 28 00:32:16 1997 Jeffrey A Law (law@cygnus.com) + + * flow.c (find_basic_blocks): Don't create a new basic block + for calls in a LIBCALL block. + +Sun Dec 28 00:30:24 1997 David Edelsohn + + * config/fp-bit.c (L_df_to_sf): Fix typo in last change. + +Sat Dec 27 22:43:12 1997 Jeffrey A Law (law@cygnus.com) + + * cse.c (rtx_cost): Remove conflicting default case. + +Sat Dec 27 21:20:02 1997 Richard Henderson + + * configure.in: Move default enabling of Haifa out of for loop. + * configure: Rebuild. + +Thu Dec 25 01:02:54 1997 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +1997-12-25 Teemu Torma + + * Makefile.in (GTHREAD_FLAGS): New var. + (LIBGCC2_CFLAGS): Added $(GTHREAD_FLAGS). + (distclean): Remove gthr-default.h. + + * configure.in: Accept dce as a thread package. + Check for thread.h and pthread.h. + Link gthr-default.h to appropriate thread file and set + gthread_flags. + (hppa1.1-*-hpux10*): If --enable-threads, use dce threads and + include multilib definitions from pa/t-dce-thr. + (sparc-*-solaris2*): Enable threads by default, if thread.h or + pthread.h is found, preferring posix threads over solaris ones. + + * config/pa/t-dce-thr: New file. + * config/pa/t-pa: Removed multilibs. + * config/sparc/t-sol2: Ditto. + + * gthr.h: New file. + * gthr-single.h: New file. + * gthr-posix.h: New file. + * gthr-solaris.h: New file. + * gthr-dce.h: New file. + * libgcc-thr.h: Removed. + * objc/thr-dce.c: New file copied from thr-decosf1.c. + + * frame.c: Include gthr.h instead of libgcc-thr.h. + * libgcc2.c: Include gthr.h instead of libgcc-thr.h. + (eh_context_initialize): If __gthread_once fails, use static eh + context. + (eh_context_free): Call __gthread_key_dtor. + +Wed Dec 24 23:33:17 1997 Jeffrey A Law (law@cygnus.com) + + * expr.h (MUST_PASS_IN_STACK): Allow target port to override. + +Wed Dec 24 23:12:14 1997 Jim Wilson + + * cse.c (max_insn_uid): New variable. + (cse_around_loop): Use max_insn_uid. + (cse_main): Set max_insn_uid. + + * abi64.h (LONG_MAX_SPEC): Check MIPS_ABI_DEFAULT and TARGET_DEFAULT, + and define __LONG_MAX__ appropriately. Add support for -mabi=X, + -mlong64, and -mgp{32,64} options. + * mips.c (mips_abi): Change type to int. + * mips.h (enum mips_abi_type): Delete. + (ABI_32, ABI_N32, ABI_64, ABI_EABI): Define as constants. + (mips_abi): Change type to int. + +Wed Dec 24 22:38:34 1997 John Carr + + * flags.h, toplev.c, calls.c, alias.c: Remove flag_alias_check; + optimization is now always enabled. + + * calls.c (expand_call): Recognize C++ operator new as malloc-like + function. + + * alias.c (memrefs_conflict_p): Eliminate tests now done by + base_alias_check. + (*_dependence): Call canon_rtx before base_alias_check. + (init_alias_once): New function to precompute set of registers which + can hold Pmode function arguments. + + * rtl.h: Declare init_alias_once. + + * toplev.c (compile_file): Call init_alias_once. + +Wed Dec 24 22:34:55 1997 Jeffrey A Law (law@cygnus.com) + + * tree.c (restore_tree_status): Do not dereference a null pointer. + +Tue Dec 23 12:56:46 1997 Paul Eggert : + + * genattrtab.c (main): Check HAVE_{G,S}ETRLIMIT in addition to + RLIMIT_STACK. This maintains consistency with the recent, similar + patch to cccp.c and toplev.c. + +Tue Dec 23 05:17:28 1997 Richard Henderson + + * genattrtab.c (expand_units): For large nr opclasses, expand + function_units_used with ORX to prevent blowups. Tag with FFS. + (num_unit_opclasses): New variable. + (gen_unit): Update it. + (enum operator): Add ORX_OP. + (operate_exp): Treat ORX as or, except don't expand across an if. + Reuse number rtx's after operating on them. + (check_attr_value): Accept IOR, AND, & FFS. + (write_test_expr): Transmute `in_comparison' to `flags'. Allow + for attribute value caching. Handle CONST_STRING, IF_THEN_ELSE. + (write_expr_attr_cache, write_toplevel_expr): New functions. + (write_attr_get): Handle FFS-tagged expressions. + (make_canonical): Don't expand const attributes. + (convert_const_symbol_ref): Dike out. + (evaluate_eq_attr): Handle SYMBOL_REF. + (main): Don't emit get_attr_foo for const attributes. + + * alpha.c (override_options): Reinstate PROCESSOR_EV6. + (alpha_adjust_cost): Add EV6 tuning; streamline EV5 tests. + * alpha.h (REGISTER_MOVE_COST): Increase ftoi/itof cost slightly. + * alpha.md: Redo all of the scheduling, adding EV6 support, and + combining function units where possible. + (attr "type"): Split loads, stores, cmov into int/fp. Combine + multiplies and divides. Add EV6 sqrt, ftoi, itof. + (attr "opsize"): New attribute. + (sqrtsf2-1, sqrtdf2-1): Provide proper TP_INSN patterns. + (movsf2-[12], movdf2-[12]): Provide CIX varients; don't allow CIX + to control register allocation. + (movsi2-1, movdi2-1): Likewise. + +Tue Dec 23 03:53:21 1997 Richard Henderson + + * alpha.h (CPP_PREDEFINES, LIB_SPEC, LINK_SPEC, STARTFILE_SPEC, + MD_STARTFILE_PREFIX, ASM_FILE_START, ASM_SPEC, ASM_FINAL_SPEC): + Move OSF/1 specific defines out. + * alpha/elf.h (TARGET_VERSION, CPP_PREDEFINES, DEFAULT_VTABLE_THUNKS): + Move Linux specific defines out. + (LINK_SPEC): Genericize. + (ASM_FILE_START): Emit .arch if using more than the base insn set. + (ASM_OUTPUT_SOURCE_LINE): Remove; identical to alpha.h version. + (SDB_DEBUGGING_INFO): Remove; gas can't handle it. + (HANDLE_SYSV_PRAGMA): Define. + * alpha/osf.h: New file. + * alpha/linux.h: Split. Retain file-format independant defines. + Import Linux bits from elf.h. + (CPP_PREDEFINES): Take a file-format specific SUB_CPP_PREDEFINES + (FUNCTION_PROFILER): _mcount takes its address in $28. + (MD_EXEC_PREFIX, MD_STARTFILE_PREFIX): Remove undef. + * alpha/linux-ecoff.h: New file. + * alpha/linux-elf.h: New file. + * alpha/vms.h (LIB_SPEC, LINK_SPEC): Copy from osf.h. + * alpha/win-nt.h (TARGET_DEFAULT): Define. + * configure.in (alpha*-*-osf*, alpha*-*-linux*) [tm_file]: + Add new headers as appropriate. + + * configure.in (alpha*): Enable Haifa by default. + (*-*-winnt3*): Change to winnt*, since we're not v3 specific. + * configure: Rebuild. + +Tue Dec 23 03:14:54 1997 Richard Henderson + + * Makefile.in (clean): Remove the stages with their objects here ... + (distclean): ... instead of here. + +Mon Dec 22 11:24:01 1997 Kaveh R. Ghazi + + * cse.c (rtx_cost): Add default case in enumeration switch. + * fix-header.c (recognized_macro): Likewise. + (recognized_extern): Likewise. + (write_rbrac): Likewise. + * objc/objc-act.c (encode_aggregate): Likewise. + (gen_declarator): Likewise. + (gen_declspecs): Likewise. + +Mon Dec 22 09:58:51 1997 Jeffrey A Law (law@cygnus.com) + + * haifa-sched.c (create_reg_dead_note): Detect and handle another + case where we kill more regs after sched than were killed before + sched. + * sched.c (create_reg_dead_note): Similarly. + +Mon Dec 22 09:18:37 1997 Jeffrey A Law (law@cygnus.com) + + * c-pragma.c: Include flags.h. + +Sun Dec 21 22:10:59 1997 Mumit Khan + + * i386/cygwin32.h (NO_IMPLICIT_EXTERN_C): Don't assume anything + about system headers. + (LIB_SPEC): Add -ladvapi32 -lshell32 to be consistent with mingw32 + and also to resolve symbols in prefix.c. + + * i386/xm-cygwin32.h (HAVE_BCOPY): Define. This avoids a conflict + between gansidecl.h and newlib's _ansi.h when building libgcc2.a, + when the definitions in auto-config.h is not visible. + (HAVE_BZERO): Likewise. + (HAVE_BCMP): Likewise. + (HAVE_RINDEX): Likewise. + (HAVE_INDEX): Likewise. + +Sun Dec 21 21:54:22 1997 Jeffrey A Law (law@cygnus.com) + + * pa.c (emit_move_sequence): Handle a function label source + operand. + +Sun Dec 21 16:13:55 1997 Nick Clifton + + * m68k/mot3300.h (ASM_BYTE_OP): Don't include '\t' in the + definition. + (ASM_OUTPUT_ASCII): Prefix ASM_BYTE_OP by one single '\t'. + +Sun Dec 21 13:58:39 1997 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (FPBIT_FUNCS, DPBIT_FUNCS): Define. + (libgcc2.a): Depend on $(DPBIT) and $(FPBIT). Add rules to + generate more fine grained floating point emulation libraries. + * config/fp-bit.c: Add protecting #ifdef to all functions so + that they can be compiled separately. If !FINE_GRAINED_LIBRARIES, + then compile all suitable functions. + (pack_d, unpack_d, fpcmp_parts): Add declarations, define with two + underscores to avoid namespace pollution. + * t-mn10200 (LIB2FUNCS_EXTRA): Remove fp-bit.c + (FPBIT): Define. + * t-mn10300 (LIB2FUNCS_EXTRA): Remove fp-bit.c and dp-bit.c + (FPBIT): Define. + (DPBIT): Define. + +Sat Dec 20 11:26:47 1997 Kaveh R. Ghazi + Jeff Law + + * bitmap.c (bitmap_clear): Ensure `inline' is at the beginning + of the declaration. + * c-decl.c (finish_decl): Use parentheses around && within ||. + * rtl.c: Include stdlib.h. + (read_skip_spaces): Add parentheses around assignments used as + truth values. + (read_rtx): Initialize list_rtx. + * cppexp.c (parse_number): Use || when operands are truth values. + * alias.c (find_base_value): Add default case. + (memrefs_conflict): Likewise. + * combine.c (sets_function_arg_p): Likewise. + * genemit.c (gen_exp): Likewise. + * local-alloc.c (contains_replace_regs): Likewise. + * rtlanal.c (jmp_uses_reg_or_mem): Likewise. + * fold-const.c (fold_convert): Use "&&" for truth values. + (fold): Add default case. + * sdbout.c (sdbout_field_types): Fix typo in declaration. + (sdbout_one_type): Add default case. + * alpha.c (alpha_sa_mask): Prototype only if OPEN_VMS. + (some_operand): Add default case. + (input_operand): Likewise. + (signed_comparison_operator): Likewise. + (divmod_operator): Likewise. + (alpha_set_memflags_1): Likewise. + * reload1.c (reload_cse_simplify_operands): Ensure function + always returns a value. + * scan-decls.c (scan_decls): Likewise. + * c-lex.c (skip_white_space): Fix typo in declaraion. + * c-typeck.c (comp_target_types): Add parentheses around assignment + used as truth value. + (print_spelling): Likewise. + (constructor_implicit, constructor_result): Remove unused variables. + * collect2.c (scan_library): Protect prototype with + #ifdef SCAN_LIBRARIES. + * emit-rtl.c (find_line_note): Fix typo in declaration. + * final.c (asm_insn_count): Protect prototype with + #ifdef HAVE_ATTR_length. + * flow.c (find_auto_inc): Protect prototype with #ifdef AUTO_INC_DEC. + (try_pre_increment_1, try_pre_increment): Likewise. + * regclass.c (auto_inc_dec_reg_p): Protect prototype with + #ifdef FORBIDDEN_INC_DEC_CLASSES. Make return type explicit. + * gcov-io.h (__store_long, __write_long, __read_long): Fix + unsigned/signed comparisons. + * gcov.c (read_files): Remove unused "first_type" variable. + (scan _for_source_files): Initialize s_ptr. + (function_summary): Eliminate "%lf" formatting, use %ld for + longs. + (output_data): Initialize branch_probs and last_line_num. + Eliminate "%lf" formatting, use "%ld" for longs. + +Fri Dec 19 17:31:11 1997 Ian Lance Taylor + + * mips16.S: New file. + + * libgcc2.c (varargs): Handle mips16. + + * expr.c (do_tablejump): Let CASE_VECTOR_PC_RELATIVE be an + expression. + * stmt.c (expand_end_case): Likewise. + * alpha.h (CASE_VECTOR_PC_RELATIVE): Update. + * fx80.h, gmicro.h, m68k.h, m88k.h, ns32k.h: Likewise. + * rs6000.h, sh.h, tahoe.h, v850.h, vax.h: Likewise. + +Tue Dec 16 15:14:09 1997 Andreas Schwab + + * objc/Make-lang.in: Create runtime-info.h and libobjc_entry.o in + the build directory. + (libobjc.a): Update dependency list. + (libobjc.dll): Likewise. Use libobjc_entry.o from the build + directory. + (objc/sendmsg.o): Add -Iobjc to find runtime-info.h. + (objc.mostlyclean): Remove runtime-info.h. + +Fri Dec 19 00:19:42 1997 Richard Henderson + + * tree.c (build_range_type): Allow creation of ranges with no maximum. + * dbxout.c (dbxout_range_type): Handle missing TYPE_MAX_VALUE. + * dwarf2out.c (add_subscript_info): Likewise. + * dwarfout.c (subscript_data_attribute, byte_size_attribute): Likewise. + * sdbout.c (plain_type_1): Likewise. + * stmt.c (pushcase_range, all_cases_count, node_has_high_bound): + Likewise. + * fold-const.c (int_const_binop, fold_convert, make_range, fold): + Likewise. + +Thu Dec 18 17:05:10 1997 Kaveh R. Ghazi + + * mips.c (fatal): Remove declaration. + +1997-12-18 Mark Mitchell + + * integrate.c (get_label_from_map): New function. + (expand_inline_function): Use it. Initialize the label_map to + NULL_RTX instead of gen_label_rtx. + (copy_rtx_and_substitute): Use get_label_from_map. + * integrate.h (get_label_from_map): New function. + (set_label_from_map): New macro. + * unroll.c (unroll_loop): Use them. + (copy_loop_body): Ditto. + +Thu Dec 18 19:19:57 1997 Ian Lance Taylor + + * mips/mips.h (INIT_SUBTARGET_OPTABS): Define if not defined. + (INIT_TARGET_OPTABS): Define. + * mips/ecoff.h: Include gofast.h before mips.h. + (INIT_SUBTARGET_OPTABS): Define instead of INIT_TARGET_OPTABS. + * mips/elf64.h: Likewise. + * mips/elf.h (ASM_OUTPUT_SECTION_NAME): Define. + +Thu Dec 18 14:51:12 1997 Jason Merrill + + * except.c: Remove register_exception_table{,_p}. + +Thu Dec 18 14:57:29 1997 Gavin Koch + + * unroll.c (calculate_giv_inc): Handle constant increment found in + a MEM with an appropriate REG_EQUAL note. + + * calls.c (expand_call): Implement LOAD_ARGS_REVERSED. + + * dwarf2out.c (dwarf2out_frame_debug): Handle adjustments of the + frame pointer in the prologue. + +Thu Dec 18 00:19:38 1997 Robert Lipe + + * i386/x-sco5 (CLIB) Deleted. (ALLOCA) Added. + * i386/xm-sco5.h (USE_C_ALLOCA) Added. + +Tue Dec 16 18:51:00 1997 Bill Moyer + + * config/m68k/m68k.c (output_function_prologue): Typecast + dwarf2out_cfi_label to (char *). + * config/m68k/m68kemb.h (STARTFILE_SPEC): Redefined to "". + +Wed Dec 17 15:06:04 1997 Richard Henderson + + * sparc.md (jump): Don't use the annul bit around an empty loop. + Patch from Kevin.Kelly@East.Sun.COM. + +Wed Dec 17 00:51:36 1997 Stan Cox (scox@cygnus.com) + + * jump.c: (jump_optimize): Don't use the return register as a + source1 of a conditional move. + +Tue Dec 16 23:45:40 1997 Richard Henderson + + * sparc.c (DF_MODES): Or the mask not the bit number. + (function_arg) [ARCH64]: Send unprototyped arg to fp reg first. + +Wed Dec 17 00:13:48 1997 Christian Iseli + + * combine.c (force_to_mode): return immediately if operand is a CLOBBER. + +Tue Dec 16 23:44:54 1997 Manfred Hollstein + + * fixincludes (size_t): Add support for Motorola's stdlib.h + which fails to provide a definition for size_t. + (fabs/hypot): Provide a prototype for fabs on m88k-motorola-sysv3. + (strlen,strspn,strcspn return value): Handle different layout on sysV88. + (hypot): Provide a fake for hypot for m88k-motorola-sysv3. + + * m68k/xm-mot3300.h (ADD_MISSING_POSIX, ADD_MISSING_XOPEN): Define to + prevent unresolved externals in libio. + * m88k/xm-sysv3.h (ADD_MISSING_POSIX, ADD_MISSING_XOPEN): Likewise. + +Tue Dec 16 23:25:45 1997 H.J. Lu (hjl@gnu.org) + + * config/sparc/linux64.h (LIBGCC_SPEC): Removed. + (CPP_SUBTARGET_SPEC): Add %{pthread:-D_REENTRANT}. + (LIB_SPEC): Updated for glibc 2. + +Tue Dec 16 20:11:36 1997 Jeffrey A Law (law@cygnus.com) + + * ginclude/stdarg.h: Undo BeOS changes, they break hpux. + * ginclude/varargs.h: Likewise. + +Tue Dec 16 00:32:01 1997 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Tue Dec 16 00:14:29 1997 H.J. Lu (hjl@gnu.org) + + * frame.h (__register_frame, __register_frame_table, + __deregister_frame): New. + * frame.c (__register_frame, __register_frame_table, + __deregister_frame): New. + * frame.c (__deregister_frame_info): Return void *. + * frame.h (__deregister_frame_info): Ditto. + * collect2.c (__deregister_frame_info): Ditto. + +Mon Dec 15 18:40:08 1997 Richard Henderson + + * expmed.c (expand_shift): If SHIFT_COUNT_TRUNCATED, drop a SUBREG. + +Mon Dec 15 18:31:43 1997 Richard Henderson + + * alpha.c (alpha_cpu_name): New variable. + (alpha_mlat_string): Likewise. + (alpha_memory_latency): Likewise. + (override_options): Handle -mmemory-latency. + (alpha_adjust_cost): Adjust load cost for latency. + * alpha.h (TARGET_OPTIONS): Add meory-latency. + (REGISTER_MOVE_COST): Define in terms of memory_latency. Take + TARGET_CIX into account. + (MEMORY_MOVE_COST): Define in terms of memory_latency. + * invoke.texi (DEC Alpha Options): Document -mmemory-latency. + + * alpha.h (ASM_COMMENT_START): New macro. + +Mon Dec 15 17:48:05 1997 Richard Henderson + + * reload.h, reload1.c (eliminate_regs), caller-save.c, dbxout.c, + dwarfout.c, dwarf2out.c, reload.c, sdbout.c: Revert March 15 change. + + * reload.c (push_reload): If WORD_REGISTER_OPERATIONS, reload the + SUBREG_REG if the word count is unchanged. + * reload1.c (eliminate_regs) [case SET]: If W_R_O, preserve + subregs of identical word size for push_reload. + +Mon Dec 15 Mark Mitchell 11:41:32 1997 + + * toplev.c (rest_of_compilation): Don't call save_for_inline_copy + if all we're doing is dealing with -Wreturn-type. + +Mon Dec 15 09:44:39 1997 Richard Henderson + + * alpha.md (zero_extendqihi2, zero_extendqisi2, zero_extendqidi2): + Use and 255 instead of zapnot 1, since it schedules better. + +Mon Dec 15 08:48:24 1997 Jeffrey A Law (law@cygnus.com) + + * stmt.c (expand_asm_operands): If an ASM has no outputs, then treat + it as volatile. + +Mon Dec 15 00:04:48 1997 Jeffrey A Law (law@cygnus.com) + + * haifa-sched.c (remove_dependencies): Set RTX_INTEGRATED_P on + dependency we delete. Properly update prev for multiple consecutive + deletions. + (priority): Skip deleted dependence. + +Fri Dec 12 18:54:23 1997 Per Bothner + + * expr.c (expand_builtin): Support BUILT_IN_FMOD - just call fmod. + +Fri Dec 12 01:19:48 1997 Jason Merrill + + * flow.c (flow_analysis): Be consistent with find_basic_blocks in + determining when a new basic block starts. + + * alpha/osf2or3.h (LIB_SPEC): Restore missing defn. + + * pa.h (TEXT_SPACE_P): Use TREE_CODE_CLASS. + * pa.md (iorsi3): Add missing args to *_operand calls. + + * except.c (call_get_eh_context): Don't mess with sequences. + (emit_eh_context): Include the call in the sequence here. + +1997-12-11 Paul Eggert + + * collect2.c (write_c_file_glob): Allocate initial frame object + in static storage and pass its address. + +Thu Dec 11 23:33:48 1997 Jason Merrill + + * except.c (call_get_eh_context): Don't take a parm. + Put the call at the top of the function. + (emit_eh_context): Adjust. + (get_eh_context): Replace with former use_eh_context. + (get_eh_context_once, get_saved_pc_ref): Remove. + (start_eh_unwinder, end_eh_unwinder, emit_unwinder): Remove. + * except.h: Adjust. + * integrate.c (expand_inline_function): Adjust. + * toplev.c (rest_of_compilation): Don't call emit_unwinder. + +Fri Oct 10 17:58:31 CEST 1997 Marc Lehmann + + * i386/xm-go32.h (EXECUTABLE_SUFFIX): Define. + (DIR_SEPARATOR, NO_SYS_SIGLIST): Likewise. + +Thu Dec 11 23:55:17 1997 Manfred Hollstein + + * fixincludes (strlen,strspn,strcspn return value): Handle different + layout on sysV88. + (hypot): Provide a fake for hypot which is broken on + m88k-motorola-sysv3. + +Thu Dec 11 23:50:17 1997 John F. Carr + + * tree.c, tree.h: Change tree_code_type, tree_code_length, and + tree_code_name from pointers to arrays. + * tree.c: Remove standard_tree_code_* variables, no longer used. + * print-tree.c: Remove declaration of tree_code_name. + + * cp/lex.c (init_lex): Update for tree_code_* changes. + * objc/objc-act.c (init_objc): Likewise. + + * tree.def, cp/cp-tree.def, objc/objc-tree.def: Update for tree_code + changes. + +Thu Dec 11 23:34:54 1997 Fred Fish + + * config.sub: Add support for BeOS target. + * configure.in: Likewise. + * ginclude/stdarg.h: Likewise. + * ginclude/stddef.h: Likewise. + * ginclude/varargs.h: Likewise. + * rs6000/beos.h: New file for BeOS. + * rs6000/t-beos: Likewise. + * rs6000/x-beos: Likewise. + * rs6000/xm-beos.h: Likewise. + * toplev.c (get_run_time): Just return 0 on BeOS. + +Thu Dec 11 23:25:23 1997 Jeffrey A Law (law@cygnus.com) + Toon Moene (toon@moene.indiv.nluug.nl) + + * m68k.h (GO_IF_LEGITIMATE_ADDRESS): No longer cater to horribly + old and broken Sun3 assemblers. Newer versions handle large + offsets correctly as does the GNU assembler. + +Thu Dec 11 23:06:48 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * objc/objc-act.c (lang_report_error_function): Disable. + * objc/objc-parse.y: Include "output.h". + (yyerror): Remove redundant decl. + (yyprint): Fix prototype. + (apply_args_register_offset): Remove redundant decl. + (get_file_function_name): Likewise. + +Thu Dec 11 22:02:10 1997 Jason Merrill + + * flow.c (find_basic_blocks): A CALL_INSN that can throw starts + a new basic block. + (find_basic_blocks_1): Likewise. + +Thu Dec 11 21:08:48 1997 Jason Merrill + + * except.c (use_eh_context): Don't copy_rtx a REG. + (emit_throw): Lose old unwinder support. + (expand_internal_throw): Likewise. + * libgcc2.c (struct eh_context): Likewise. + (new_eh_context): Likewise. + (__get_eh_info): Lose redundant cast. + (__get_dynamic_handler_chain): Likewise. + (__get_saved_pc): Lose. + Lose all old unwinder support code. + +Thu Dec 11 20:42:18 1997 Teemu Torma + + Thread-safe EH support for pthreads, DCE threads and Solaris threads. + + * integrate.c (expand_inline_function): If the inline fn uses eh + context, make sure that the current fn has one. + * toplev.c (rest_of_compilation): Call emit_eh_context. + * except.c (use_eh_context): New fn. + (get_eh_context_once): New fn. + (call_get_eh_context): New fn. + (emit_eh_context): New fn. + (get_eh_context): Call either get_eh_context_once or + call_get_eh_context, depending on what we have. + (get_dynamic_handler_chain): Call get_eh_context_once. + * except.h: Prototypes for fns above. + * optabs.c (get_eh_context_libfunc): Removed. + (init_optabs): Don't initialize it. + * expr.h (get_eh_context_libfunc): Removed. + * rtl.h, rtl.c: New reg_note REG_EH_CONTEXT. + * config/pa/pa.h (CPP_SPEC): Support for -threads. + * config/pa/pa-hpux10.h (LIB_SPEC): Ditto. + * config/pa/t-pa (MULTILIB_OPTIONS, MULTILIB_DIRNAMES): + New multilib for -threads. + * config/sparc/t-sol2: Added multilibs for -threads and + made -pthreads alias to it. + * config/sparc/sol2.h (CPP_SPEC, LIB_SPEC): + Added -threads and -pthreads options. + * libgcc-thr.h: New file. + * libgcc2.c: (__get_cpp_eh_context): Removed. + (struct cpp_eh_context): Removed. + (struct eh_context): Replaced cpp_eh_context with generic language + specific pointer. + (__get_eh_info): New function. + (__throw): Check eh_context::info. + (__sjthrow): Ditto. + * libgcc2.c: Include libgcc-thr.h. + (new_eh_context, __get_eh_context, + eh_pthread_initialize, eh_context_initialize, eh_context_static, + eh_context_specific, eh_context_free): New functions. + (get_eh_context, eh_context_key): New variables. + (__sjthrow, __sjpopnthrow, __eh_pcnthrow, __throw): Use + get_eh_context to get the context. + (longjmp): Move the declaration inside + #ifdef DONT_USE_BUILTIN_SETJMP. + * frame.c: Include libgcc-thr.h. + (object_mutex): Mutex to protect the object list. + (find_fde, __register_frame, __register_frame_table, + __deregister_frame): Hold the lock while accessing objects. + * except.h (get_eh_context): Declare. + * except.c (current_function_ehc): Define. + (current_function_dhc, current_function_dcc): Removed. + (get_eh_context): New function. + (get_dynamic_handler_chain): Use get_eh_context. + (get_saved_pc_ref): Ditto. + (get_dynamic_cleanup_chain): Removed references to + current_function_dcc. + (save_eh_status, restore_eh_status): Save and restore + current_function_ehc instead. + * optabs.c (get_eh_context_libfunc): New variable. + (init_optabs): Initialize it. + * expr.h: Declare get_eh_context_libfunc. + * function.h (struct function): Replaced dhc and dcc with ehc. + * except.c (get_saved_pc_ref): New functions. + (eh_saved_pc_rtx, eh_saved_pc): Deleted. + (expand_internal_throw_indirect): Use get_saved_pc_ref() instead + of eh_saved_pc. + (end_eh_unwinder): Likewise. + (init_eh): Remove initialization of eh_saved_pc. + * optabs.c (get_saved_pc_libfunc): New variable. + (init_optabs): Initialize it. + * expr.h: Declare get_saved_pc_libfunc. + * except.h (eh_saved_pc_rtx): Deleted. + (get_saved_pc_ref): Declared. + + From Scott Snyder : + * libgcc2.c (__get_saved_pc): New. + (__eh_type, __eh_pc): Deleted. + (__eh_pcnthrow): Use __get_saved_pc() instead of __eh_pc. + (__get_dynamic_handler_chain): Move __dynamic_handler_chain inside + this fcn. + +Thu Dec 11 17:23:48 1997 John F. Carr + + * sparc/sol2.h: Use 64 bit multiply and divide functions in + Solaris libc. Define TARGET_LIVE_G0 and TARGET_BROKEN_SAVERESTORE + as 0. + + * rtl.h (global_rtl): New variable, replacing separate variables for + commonly used rtl. + (const_int_rtx): Now array of rtx_def, not rtx. + * emit-rtl.c: Update for new rtl data structures. + * genattrtab.c: Define global_rtl. + +Thu Dec 11 15:50:29 1997 David Edelsohn + + * configure.in ({rs6000,powerpc}-*-*): Enable Haifa scheduler by + default. + +Wed Dec 10 12:30:18 1997 Anthony Green + + * crtstuff.c (__do_global_ctors): Fix typo. + +Tue Dec 9 09:43:59 1997 Manfred Hollstein + + * toplev.c (main): Check HAVE_GETRLIMIT and HAVE_SETRLIMIT in addition + to RLIMIT_STACK to see if we can call getrlimit and setrlimit. + +Tue Dec 9 09:38:58 1997 David Edelsohn + + * rs6000.h (FUNCTION_ARG_PADDING): Define. + * rs6000.c (function_arg_padding): New function. + +Tue Dec 9 10:34:21 1997 Manfred Hollstein + + * m68k.c: Include tree.h only once. + +Tue Dec 9 09:32:33 1997 Richard Kenner + + * integrate.c (save_for_inline_copying): Make a new reg_parm_stack_loc. + +Tue Dec 9 01:16:06 1997 Jeffrey A Law (law@cygnus.com) + + * Partially cleaned up prototyping code from HJ. + * tree.h: Add many prototypes. + * haifa-sched.c (haifa_classify_insn): Renamed from classify_insn. + All references changed. + * rtl.h: Protect from multiple inclusions. Add many prototypes. + +Tue Dec 9 01:15:15 1997 Fred Fish + + * libgcc2.c (string.h): Hoist inclusion to occur before first use of + string functions like strlen. + +Tue Dec 9 00:57:38 1997 Manfred Hollstein + + * configure.in: Check for functions getrlimit and setrlimit. + * cccp.c (main): Check HAVE_GETRLIMIT and HAVE_SETRLIMIT in addition + to RLIMIT_STACK to see if we can call getrlimit and setrlimit. + +Mon Dec 8 23:53:26 1997 Jay Sachs + + * Makefile.in (compare*): Handle losing behavior from 4.4bsd make. + +Mon Dec 8 21:03:28 1997 Richard Henderson + + * alpha.c (REG_RA, alpha_return_addr, output_epilog): + Fix merge problems. + + * alpha.c (override_options): Don't know about scheduling for EV6. + * alpha.md (ev5 function units): Don't overload as ev6. + + * alpha.c (alpha_adjust_cost): Simplify. Fix typo in ev5 mult case. + * alpha.md (define_attr type): Add mvi. + (ev5_e0): Define sceduling parameters for it. + (TARGET_MAX insns): Type is mvi not shift. + +Mon Dec 8 18:15:00 1997 Richard Henderson + + * alpha/win-nt.h (TRAMPOLINE_TEMPLATE): Fix backported gcc-2.8 bug. + +Mon Dec 8 21:17:28 1997 J"orn Rennecke + + * cstamp-h, auto-config.h: Delete. + +Sun Dec 7 19:19:03 1997 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sat Dec 6 22:22:22 1997 Jeffrey A Law (law@cygnus.com) + + * cccp.c: Fix typo brought over in merge. + + * Merge in changes from gcc-2.8. + +Mon Nov 3 05:45:32 1997 Philippe De Muyter + + * m68k.c: Include tree.h for dwarf2out_cfi_label. + + * gcc.c (process_command): Do not take address of function fatal when + calling lang_specific_driver. + +Sat Dec 6 01:02:38 1997 Mumit Khan + + * config/i386/cygwin32.h (DWARF2_UNWIND): Exception handling + doesn't work with it yet, so set it to 0. + * config/i386/xm-cygwin32.h (NO_SYS_SIGLIST): Define. + +Sat Dec 6 01:01:02 1997 Christian Iseli + + * cse.c (cse_insn): Check for invalid entries when taking references. + +Fri Dec 5 18:26:25 1997 J"orn Rennecke + + * loop.c (invariant_p): Don't test flag_rerun_loop_opt. + (loop_optimize, scan_loop, strength_reduce): New argument unroll_p. + * toplev.c (rest_of_compilation): Pass it. Remove code to + save / clear / restore flag_unroll_{,all_}loops. + +Fri Dec 5 16:26:03 1997 Bernd Schmidt + + * i386.c (notice_update_cc): Remove bogus pentium GCC code. + +Fri Dec 5 16:25:14 1997 Jeffrey A Law (law@cygnus.com) + + * stmt.c (warn_if_unused_value): Don't warn for TRY_CATCH_EXPR. + +Thu Dec 4 11:51:00 1997 Jason Merrill + + * except.c (get_dynamic_handler_chain): Only make the call once per + function. + + * except.c (expand_end_all_catch): Fix for sjlj exceptions. + +Thu Dec 4 12:30:40 1997 J"orn Rennecke + + * sh.c (final_prescan_insn): Use local label prefix + when emitting .uses pseudo-ops. + +Wed Dec 3 12:01:56 1997 Jason Merrill + + * libgcc2.c (__throw): Use __builtin_return_addr instead of __eh_pc. + * except.c: Lose outer_context_label_stack. + (expand_eh_region_end): Rethrow from outer_context here. + (expand_fixup_region_end): Let expand_eh_region_end do the rethrow. + (expand_internal_throw): Take no args. + (expand_internal_throw_indirect): Lose. + (expand_leftover_cleanups, expand_start_all_catch): Use expand_rethrow. + (expand_start_all_catch): Start a rethrow region. + (expand_end_all_catch): End it. + (expand_rethrow): New fn. + * except.h: Reflect above changes. + * flow.c: Revert change of Nov 27. + +Thu Dec 4 00:24:09 1997 Jeffrey A Law (law@cygnus.com) + + * i386/t-sol2 (CRTSTUFF_T_CFLAGS): Turn on the optimizer. + +Wed Dec 3 12:01:56 1997 Jason Merrill + + * except.c (expand_fixup_region_end): New fn. + (expand_fixup_region_start): Likewise. + (expand_eh_region_start_tree): Store cleanup into finalization here. + * stmt.c (expand_cleanups): Use them to protect fixups. + +Wed Dec 3 11:41:13 1997 Gavin Koch + + * mips/mips.md (muldi3_r4000): Broaden the output template + and attribute assignments to handle three operand dmult; + rename to muldi3_internal2. + (muldi3): Call the new muldi3_internal2 for R4000, and + any GENERATE_MULT3 chip. + +Tue Dec 2 19:40:43 1997 Jason Merrill + + * stmt.c (expand_decl_cleanup): Update thisblock after eh_region_start. + +Tue Dec 2 12:54:33 1997 Jim Wilson + + * unroll.c (find_splittable_givs): Remove last change. Handle givs + with a dest_reg that was created by loop. + +Sat Nov 29 12:44:57 1997 David Edelsohn + + * rs6000.c (function_arg_partial_nregs): Undo Nov. 26 patch. + + * rs6000/aix41.h (ASM_CPU_SPEC): Define. + +Fri Nov 28 10:00:27 1997 Jeffrey A Law (law@cygnus.com) + + * configure.in: Fix NCR entries. + +Thu Nov 27 12:20:19 1997 Jeffrey A Law (law@cygnus.com) + + * flow.c (find_basic_blocks): Handle cfg issues for rethrows and + nested exceptions correctly. + + * unroll.c (find_splittable_givs): Don't split givs with a dest_reg + that was created by loop. + +Thu Nov 27 09:34:58 1997 Jason Merrill + + * expr.c (preexpand_calls): Don't look past a TRY_CATCH_EXPR. + + * except.c (expand_start_all_catch): One more do_pending_stack_adjust. + +Wed Nov 26 15:47:30 1997 Michael Meissner + + * rs6000.c (SMALL_DATA_REG): Register to use for small data relocs. + (print_operand): Use SMALL_DATA_REG for the register involved in + small data relocations. + (print_operand_address): Ditto. + + * rs6000/linux.h (LINK_SPEC): Pass -dynamic-linker /lib/ld.so.1 if + -dynamic linker is not used. + + * rs6000.md (call insns): For local calls, use @local suffix under + System V. Don't use @plt under Solaris. + + * rs6000.c (output_function_profiler): Put label address in r0, and + store LR in 4(sp) for System V/eabi. + + * rs6000.h (ASM_OUTPUT_REG_{PUSH,POP}): Keep stack aligned to 16 + byte boundary, and maintain stack backchain. + +Tue Nov 25 14:08:12 1997 Jim Wilson + + * mips.md (fix_truncdfsi2, fix_truncsfsi2, fix_truncdfdi2, + fix_truncsfdi2): Change *. + +Wed Nov 26 11:12:26 1997 Jason Merrill + + * toplev.c (main): Complain about -gdwarfn. + +Tue Nov 25 22:43:30 1997 Jason Merrill + + * dwarfout.c (output_type): If finalizing, write out nested types + of types we've already written. + +Tue Nov 25 20:32:24 1997 Michael Meissner + + (patches originally from Geoffrey Keating) + * rs6000.c (function_arg): Excess floating point arguments don't + go into GPR registers after exhausting FP registers under the + System V.4 ABI. + (function_arg_partial_nregs): Ditto. + + * rs6000.md (call insns): If -fPIC or -mrelocatable, add @plt + suffix to calls. + +Tue Nov 25 23:37:27 1997 Jason Merrill + + * integrate.c (output_inline_function): Just unset DECL_INLINE. + +Tue Nov 25 23:33:29 1997 scott snyder + + * dwarf2out.c (outout_call_frame_info): Ensure that the info has + proper alignment. + + * libgcc2.c (__throw): Initialize HANDLER. + +Tue Nov 25 14:08:12 1997 Jim Wilson + + * mips.md (fix_truncdfsi2, fix_truncsfsi2, fix_truncdfdi2, + fix_truncsfdi2): Change *X to ?*X. + +Tue Nov 25 10:00:42 1997 Richard Henderson (rth@cygnus.com) + + * alpha.h (CONST_OK_FOR_LETTER): Fix 'L' handling. + +Tue Nov 25 10:00:42 1997 Jeffrey A Law (law@cygnus.com) + + * crtstuff.c (do_global_dtors_aux): Handle multiple calls better. + +Tue Nov 25 01:26:55 1997 Bruno Haible : + + * dwarf2out.c (ASM_OUTPUT_DWARF_DELTA1): Implement. + +Mon Nov 24 22:41:55 1997 Jason Merrill + + * except.c (get_dynamic_handler_chain): Build up a FUNCTION_DECL. + * optabs.c (init_optabs): Lose get_dynamic_handler_chain_libfunc. + * expr.h: Likewise. + +Sat Nov 22 18:58:20 1997 Jeffrey A Law (law@cygnus.com) + + * pa-hpux10.h (NEW_HP_ASSEMBLER): Define. + * pa.h (LEGITIMATE_CONSTANT_P): Reject LABEL_REFs if not using + gas and not using the new HP assembler. + +Fri Nov 21 15:20:05 1997 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (program_transform_cross_name): Clean up "-e" confusion. + (GCC_INSTALL_NAME, GCC_CROSS_NAME): Likewise. + +Fri Nov 21 19:37:40 1997 Andrew Cagney + + * config/mips/elf64.h (MULTILIB_DEFAULTS): Test for + TARGET_ENDIAN_DEFAULT == zero instead of testing for macro + definition. + +Fri Nov 21 12:49:56 1997 Bruno Haible + + * stmt.c (expand_end_bindings): Allow jump into block with cleanups. + +Fri Nov 21 12:18:51 1997 Jason Merrill + + * except.h: Add outer_context_label_stack. + * except.c: Likewise. + (expand_start_all_catch): Push the outer_context for the try block + onto outer_context_label_stack. + (expand_end_all_catch): Use it and pop it. + +Fri Nov 21 10:13:11 1997 Robert Lipe (robertl@dgii.com) + + * i386/sco5.h (HAVE_ATEXIT): Revert last change. + +Thu Nov 20 16:11:50 1997 Richard Henderson + + * alpha.c (alpha_emit_set_const_1): Handle narrow hosts better. + +Thu Nov 20 16:11:50 1997 Klaus Kaempf + + * alpha/vms.h (ASM_OUTPUT_ADDR_VEC_ELT): Add an L for the local label + to correspond with the change to ASM_GENERATE_INTERNAL_LABEL. + +Thu Nov 20 14:42:15 1997 Jason Merrill + + * Makefile.in (LIB2FUNCS): Remove C++ memory management support. + * libgcc2.c: Remove __builtin_new, __builtin_vec_new, set_new_handler, + __builtin_delete, and __builtin_vec_delete. + + * except.c (output_exception_table): Don't bother with + __EXCEPTION_END__. + +Thu Nov 20 16:11:50 1997 Jeffrey A Law (law@cygnus.com) + + * pa.md (pre_stwm, post_stwm, pre_ldwm, post_ldwm): Base register + is an in/out operand. + (zero extended variants of stwm/stwm patterns): Similarly. + + * mips/x-iris (FIXPROTO_DEFINES): Add -D_SGI_SOURCE. + +Thu Nov 20 13:19:32 1997 Jason Merrill + + * dwarf2out.c (ASM_OUTPUT_DWARF_OFFSET4): Rename from VALUE4. + Use assemble_name. + (ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL): Use assemble_name. + (output_call_frame_info): Emit a \n after using it. + +Thu Nov 20 00:38:46 1997 Dave Love + + * configure.in: Add AC_ARG_ENABLE for Haifa as documentation. + +Wed Nov 19 12:03:04 1997 Philippe De Muyter + + * dwarf2out.c (CIE_LENGTH_LABEL, FDE_LENGTH_LABEL): New macros. + (ASM_OUTPUT_DWARF_VALUE4): New macro. + (ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL): Define if SET_ASM_OP is + defined. + (output_call_frame_info): Do not output forward label differences + if ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL is defined. + * m68k/mot3300.h (SET_ASM_OP): Define when not using gas. + +Tue Nov 18 23:03:30 1997 J"orn Rennecke + + * sh.md (attribute "type"): Add nil. + (movsi_ie): y/y alternative is type nil. + (movsf_ie): Replace ry/yr/X alternative by r/y/X , y/r/X and y/y/X + alternatives. + (movsf_ie+1): Delete. + +Tue Nov 18 15:39:59 1997 Jim Wilson + + * mips/mips.c (save_restore_insns): If gp_offset or fp_offset are + large_int, emit two insns instead of one splitable insn. + * dwarf2out.c (dwarf2out_frame_debug): When set cfa_store_offset + from cfa_temp_value, use cfa_offset. Add assert checking that + cfa_reg is SP. + +Mon Nov 17 15:35:38 1997 Tom Tromey + + * cccp.c (deps_output): Properly quote file names for make. + +Mon Nov 17 13:21:40 1997 Jeffrey A Law (law@cygnus.com) + + * t-h8300 (MULTILIB_EXCEPTIONS): Define. + +Fri Nov 7 15:33:11 1997 Robert Lipe (robertl@dgii.com) + + * i386/sco5.h (HAVE_ATEXIT): Delete definition. + +Sun Nov 16 23:52:48 1997 Jeffrey A Law (law@cygnus.com) + + * cse.c (cse_insn): Don't look at JUMP_LABEL field of a conditionl + return. + (cse_end_of_basic_block): Similarly. + +Sun Nov 16 23:01:40 1997 J. Kean Johnston + + * i386/sco5.h (ASM_OUTPUT_ALIGNED_BSS): Define. + (SELECT_RTX_SECTION): Define. + (LIBGCC_SPEC, LIB_SPEC): Do the right thing for PIC. + +Sun Nov 16 22:47:03 1997 Manfred Hollstein + + * Makefile.in (compare, compare-lean): Define $stage for each + shell command. + (gnucompare, gnucompare-lean): Likewise. + +Sun Nov 16 22:02:16 1997 Richard Henderson (rth@cygnus.com) + + * alpha/win-nt.h (TRAMPOLINE_TEMPLATE): Fix offsets. + + * alpha.h (ASM_OUTPUT_ADDR_DIFF_ELT): Add an L for the local label + to correspond with the change to ASM_GENERATE_INTERNAL_LABEL. + +Fri Nov 14 09:09:20 1997 Fred Fish (fnf@cygnus.com) + + * dwarfout.c (byte_size_attribute): Add local var upper_bound + and add case to handle STRING_TYPE. + * dwarfout.c (output_string_type_die): Fix code to generate + correct string length attribute for fixed length strings. + Still needs support for varying length strings. + +Fri Nov 14 08:46:56 1997 Jeffrey A Law (law@cygnus.com) + + * toplev.c (get_run_time): Do something sensible for cygwin32. + +Fri Nov 14 07:24:20 1997 Richard Henderson + + * expr.c (expand_builtin_setjmp): Set + current_function_has_nonlocal_label. + * stupid.c (stupid_life_analysis): If has_nonlocal_label, kill + call-saved registers across calls. + + * alpha.md (exception_receiver): Remove. + (nonlocal_goto_receiver_osf): New + (nonlocal_goto_receiver_vms): Renamed from nonlocal_goto_receiver. + (nonlocal_goto_receiver): New, select _osf or _vms. + + * alpha.c (output_prolog [*]): Prefix entry labels with '$' to + keep them from being propogated to the object file. + (alpha_write_linkage): Likewise. + * alpha.md (call_vms): Likewise. + (call_value_vms): Likewise. + (unnamed osf call insns): Likewise. + + * alpha.h (ASM_OUTPUT_INTERNAL_LABEL): Don't omit L from local label. + (ASM_GENERATE_INTERNAL_LABEL): Likewise. + + * alpha.c (call_operand): Any reg is valid for WinNT. + * alpha.md (call_nt, call_value_nt): Don't force address into $27. + (anon nt calls): Add 'R' alternative. + * alpha/win-nt.h (TRAMPOLINE_TEMPLATE, TRAMPOLINE_SIZE, + INITIALIZE_TRAMPOLINE): Handle lack of original $27 and 32-bit ptrs. + +Fri Nov 14 06:59:33 1997 Jeffrey A Law (law@cygnus.com) + + * calls.c (expand_call): Handle pcc_struct_value correctly for C++. + + * i386/xm-cygwin32.h (HAVE_FILE_H, HAVE_RUSAGE): Delete defines. + * i386/xm-mingw32.h (HAVE_FILE_H, HAVE_RUSAGE): Likewise. + * rs6000/xm-cygwin32.h (HAVE_FILE_H, HAVE_RUSAGE): Likewise. + +Thu Nov 13 20:37:33 1997 Michael Meissner + + * reload1.c (new_spill_reg): Improve fixed or forbidden register + spill error message. + +Thu Nov 13 20:29:08 1997 Kaveh R. Ghazi + + * prefix.c: Use stdarg.h only ifdef __STDC__. Otherwise, + use varargs.h. Wrap header with <>, not "". + +Thu Nov 13 20:21:17 1997 Jeffrey A Law (law@cygnus.com) + + * integrate.c (save_for_inline_copying): Add return value from + savealloc. + +Thu Nov 13 19:12:33 1997 Brendan Kehoe + + * fixincludes: Be a little more restrictive on what we will + substitute to replace definitions of MAXINT for HPUX. + +Thu Nov 13 18:41:02 1997 Michael Meissner + + * dbxout.c (dbxout_symbol_location): Don't assume that variables + whose address is the stack or argument pointers are indirect + pointers. + +1997-11-13 Paul Eggert + + * cccp.c, cpplib.c (compare_defs): + Don't complain about arg name respellings unless pedantic. + * cpplib.c (compare_defs): Accept pfile as new arg. + All callers changed. + +Thu Nov 13 23:33:50 1997 J"orn Rennecke + + * fold-const.c (fold_truthop): Fix bug in last change. + +1997-11-13 Paul Eggert + + Fix some confusion with IEEE minus zero. + + * real.h (REAL_VALUES_IDENTICAL): New macro. + + * expr.c (is_zeros_p): Don't consider -0.0 to be all zeros. + * fold-const.c (operand_equal_p): Don't consider -0.0 to be + identical to 0.0. + * tree.c (simple_cst_equal): Don't consider -0.0 to have the + same tree structure as 0.0. + + * varasm.c (immed_real_const_1): Use new REAL_VALUES_IDENTICAL + macro instead of doing it by hand. + +Thu Nov 13 16:56:14 1997 Jeffrey A Law (law@cygnus.com) + + * v850/lib1funcs.asm: Minor whitespace changes. + * v850.c: Fix minor formatting problems in many places. + (construct_restore_jr, construct_save_jarl): Remove unwanted aborts. + +Thu Nov 13 12:53:44 1997 Jim Wilson + + * mips.h (GO_IF_LEGITIMATE_ADDRESS): Delete code swapping xplus0 and + xplus1 when xplus0 is not a register. + +Thu Nov 13 11:41:42 1997 Jeffrey A Law (law@cygnus.com) + + * flow.c (find_basic_blocks): During marking phase, if we encounter + an insn with a REG_LABEL note, make the target block live and + create an edge from the insn to the target block. Do not make + edges from all blocks to the target block. + + * m68k/x-next (OTHER_FIXINCLUDES_DIRS): Include /NextDeveloper/Headers. + + * confiugre.in: Tweak NCR entries. + * configure: Rebuilt. + +Thu Nov 13 11:07:41 1997 Michael Meissner + + * rs6000.c (num_insns_constant): Use REAL_VALUE_FROM_CONST_DOUBLE to + pick apart floating point values, instead of using CONST_DOUBLE_LOW + and CONST_DOUBLE_HIGH. + + * rs6000.md (define_splits for DF constants): Use the appropriate + REAL_VALUE_* interface to pick apart DF floating point constants in + a machine independent fashion. + +Thu Nov 13 00:06:58 1997 J"orn Rennecke + + * fold-const.c (fold_truthop): When changing a one-bit comparison + against zero into a comparison against mask, do a proper sign + extension. + +Wed Nov 12 09:37:01 1997 Jeffrey A Law (law@cygnus.com) + + * except.c: Do not include "assert.h". + (save_eh_status): Turn asserts into conditional aborts. + (restore_eh_status, scan_region): Likewise. + * dwarfout.c: Do not include "assert.h". + (bit_offset_attribute): Turn asserts into conditional aborts. + (bit_size_attribute, output_inlined_enumeration_type_die): Likewise. + (output_inlined_structure_type_die): Likewise. + (output_inlined_union_type_die): Likewise + (output_tagged_type_instantiation): Likewise. + (dwarfout_file_scope_decl): Likewise. + * dwarf2out.c: Do not include "assert.h" + (expand_builtin_dwarf_reg_size): Turn asserts into conditional aborts. + (reg_save, initial_return_save, dwarf2out_frame_debug): Likewise. + (add_child_die, modified_type_die, add_bit_offset_attribute): Likewise. + (add_bit_size_attribute, scope_die_for): Likewise. + (output_pending_types_for_scope): Likewise. + (get_inlined_enumeration_type_die): Likewise. + (get_inlined_structure_type_die): Likewise. + (get_inlined_union_type_die, gen_subprogram_die): Likewise. + (gen_tagged_type_instantiation_die): Likewise. + + * flow.c (find_basic_blocks): Refine further to get a more correct + cfg, especially in the presense of exception handling, computed + gotos, and other non-trivial cases. Call abort if an inaccuracy + is detected in the cfg. + +Tue Nov 11 21:47:27 1997 J"orn Rennecke + + * glimits.h (SHRT_MIN): Define in a way suitable for 16 bit hosts. + + * c-lex.c (whitespace_cr, skip_white_space_on_line): New functions. + (skip_white_space): Use whitespace_cr. + (check_newline): Handle whitespace more consistently. + +Tue Nov 11 16:25:49 1997 Jim Wilson + + * i386/cygwin32.h (CPP_PREDEFINES): Delete -DPOSIX. + * i386/xm-cygwin32.h (POSIX): Define. + +Mon Nov 10 20:53:11 1997 Gavin Koch + + * config/mips/mips.h (MASK_DEBUG_H): Set to zero, so this bit + is available elsewhere. + +Mon Nov 10 16:21:58 1997 Doug Evans + + * sparc/sparc.md (mov[sdt]f_const_insn): Fix condition to match + what the instruction can handle. + +Mon Nov 10 03:02:19 1997 Jason Merrill + + * stmt.c (expand_decl_cleanup_no_eh): New fn. + + * except.c (expand_leftover_cleanups): do_pending_stack_adjust. + +Mon Nov 10 00:05:56 1997 Jeffrey A Law (law@cygnus.com) + + * alias.c (MAX_ALIAS_LOOP_PASSES): Define. + (init_alias_analysis): Break out of loops after MAX_ALIAS_LOOP_PASSES. + +Sun Nov 9 14:34:47 1997 David Edelsohn + + * rs6000.md (lshrdi3_power): Delete '&' from first alternative and + swap instruction order. + +Sun Nov 9 02:07:16 1997 Jeffrey A Law (law@cygnus.com) + + * fixinc.svr4 (__STDC__): Add another case. + +Sun Nov 9 02:00:29 1997 J"orn Rennecke + + * a29k.h (ELIGIBLE_FOR_EPILOGUE_DELAY): Avoid loads from varying + addresses in the epilogue delay slot. + +Sun Nov 9 01:40:40 1997 Manfred Hollstein (manfred@s-direktnet.de) + + * m88k/dgux.h (ASM_CPU_SPEC): Reformatted to suppress wrong whitespace + in generated `specs' file. + +Sun Nov 9 01:37:11 1997 Jim Wilson (wilson@cygnus.com) + + * flags.h (flag_rerun_loop_opt): Declare. + * loop.c (invariant_p, case LABEL_REF): Check flag_rerun_loop_opt. + * toplev.c (flag_rerum_loop_opt): Delete static. + +Sat Nov 8 18:20:21 1997 J"orn Rennecke + + Bring over from FSF: + + Thu Oct 30 12:21:06 1997 J"orn Rennecke + + * va-sh.h (__va_arg_sh1): Define. + (va_arg): Use it. + SH3E doesn't use any integer registers for subsequent arguments + once a non-float value was passed in the stack. + * sh.c (machine_dependent_reorg): If optimizing, put explicit + alignment in front label for ADDR_DIFF_VEC. + * sh.h (PASS_IN_REG_P): Fix SH3E case. + (ADJUST_INSN_LENGTH): If not optimizing, add two extra bytes length. + + Tue Oct 28 15:06:44 1997 J"orn Rennecke + + * sh/elf.h (PREFERRED_DEBUGGING_TYPE): Undefine before including + svr4.h. + + Mon Oct 27 16:11:52 1997 J"orn Rennecke + + * sh.c (machine_dependent_reorg): When -flag_delayed_branches, + put an use_sfunc_addr before each sfunc. + * sh.md (use_sfunc_addr, dummy_jump): New insns. + (casesi): For TARGET_SH2, emit a dummy_jump after LAB. + + Tue Oct 21 07:12:28 1997 J"orn Rennecke + + * sh/elf.h (PREFERRED_DEBUGGING_TYPE): Don't redefine. + +Fri Nov 7 10:22:24 1997 Jason Merrill + + * frame.c (add_fdes, count_fdes): Go back to checking pc_begin for + linked once FDEs. + +Wed Nov 5 14:26:05 1997 Jeffrey A Law (law@cygnus.com) + + * alias.c (find_base_value): Only return the known base value for + pseudo registers. + +Wed Nov 5 11:27:14 1997 Jim Wilson + + * i386.c (load_pic_register): Call prologue_get_pc_and_set_got. + * i386.md (prologue_set_got, prologue_get_pc): Add UNSPEC_VOLATILE + to pattern. + (prologue_get_pc_and_set_got): New pattern. + +Tue Nov 4 20:36:50 1997 Richard Henderson (rth@cygnus.com) + + * alpha.c (summarize_insn): Handle ASM_OPERANDS. Don't recurse + for SUBREG, just fall through. + + * alpha.c (alpha_handle_trap_shadows): Init sum.defd to zero. + + * alpha.md (attr trap): Make TRAP_YES non-zero for sanity's sake. + +Tue Nov 4 18:49:42 1997 Jeffrey A Law (law@cygnus.com) + + * fixincludes: Fix "hypot" prototype in NeXT math.h. + + * Makefile.in (USE_ALLOCA): Always include alloca.o. + (USE_HOST_ALLOCA): Likewise. + + * rtl.def (CODE_LABEL): Use separate fields for LABEL_NUSES + and LABEL_REFS fields. + * rtl.h (LABEL_REFS): Update. + +Tue Nov 4 16:55:11 1997 Jim Wilson + + * combine.c (try_combine): When setting elim_i2, check whether newi2pat + sets i2dest. When calling distribute_notes for i3dest_killed, pass + elim_i2 and elim_i1. When setting elim_i1, check if newi2pat + sets i1dest. + + * mips.md (insv, extzv, extv): Add change_address call. + (movsi_ulw, movsi_usw): Change QImode to BLKmode in pattern. + + * integrate.c (save_for_inline_copying): Copy parm_reg_stack_loc. + + * reload.c (find_reloads, case 'm' and 'o'): Reject HIGH constants. + + * mips.c (mips_expand_epilogue): Emit blockage insn before call to + save_restore_insns if no FP and GP will be restored. + + * dwarf2out.c (expand_builtin_dwarf_reg_size): New variable mode. + Convert CCmode to word_mode before calling GET_MODE_SIZE. + + * acconfig.h (HAVE_INTTYPES_H): Undef. + * configure.in (inttypes.h): Check for conflicts between sys/types.h + and inttypes.h, and verify that intmax_t is defined. + * config/mips/x-iris (CC, OPT, OLDCC): Comment out. + * config/mips/x-iris3: Likewise. + +Tue Nov 4 16:07:15 1997 Jeffrey A Law (law@cygnus.com) + + * alias.c (find_base_value): When copying arguments, return the + tenative value for a hard register. + +Tue Nov 4 13:40:35 1997 Doug Evans + + * c-lex.c (MULTIBYTE_CHARS): #undef if cross compiling. + (yylex): Record wide strings using target endianness, not host. + +Tue Nov 4 13:13:12 1997 Jeffrey A Law (law@cygnus.com) + + * mn10200.h (ASM_OUTPUT_BSS): Delete. + (ASM_OUTPUT_ALIGNED_BSS): New macro + * mn10300.h (ASM_OUTPUT_BSS): Delete. + (ASM_OUTPUT_ALIGNED_BSS): New macro. + * v850.h (ASM_OUTPUT_BSS): Delete. + (ASM_OUTPUT_ALIGNED_BSS): New macro. + +Tue Nov 4 00:55:48 1997 J"orn Rennecke + + * profile.c (branch_prob): Insert an insn after a NOTE_INSN_SETJMP. + +Mon Nov 3 14:36:50 1997 Jeffrey A Law (law@cygnus.com) + + * configure.in (sco5): Use cpio to install header files. + +Sun Nov 2 23:31:43 1997 Manfred Hollstein + + * aclocal.m4 (conftestdata_from, conftestdata_to): Names shortened to + 14 char length. + * configure: Rebuild. + +Sun Nov 2 19:44:00 1997 Robert Lipe (robertl@dgii.com) + + * i386/sco5.h: enable -gstabs once again. + +Sun Nov 2 19:27:21 1997 Jeffrey A Law (law@cygnus.com) + + * arm.c (output_move_double): Allocate 3 entries in otherops array. + +Sat Nov 1 21:43:00 1997 Mike Stump (mrs@wrs.com) + + * except.c (expand_ex_region_start_for_decl): Emit EH_REGION_BEG + notes for sjlj exceptions too. + (expand_eh_region_end): Similarly for EH_REGION_END notes. + (exception_optimize): Optimize EH regions for sjlj exceptions too. + * final.c (final_scan_insn): Don't output labels for EH REGION + notes if doing sjlj exceptions. + +Sat Nov 1 19:15:28 1997 Jeffrey A Law (law@cygnus.com) + + * alias.c (init_alias_analysis): Handle -fno-alias-check when + optimizing correctly. + + * expr.c (expand_builtin_setjmp): Don't emit a SETJMP note + or set current_function_calls_setjmp anymore. + + * flow.c (find_basic_blocks): If we delete the label for an + exception handler, remove it from the EH label list and remove + the EH_BEGIN/EH_END notes for that EH region. + +Sat Nov 1 16:44:49 1997 Jason Merrill (jason@cygnus.com) + + * flow.c (find_basic_blocks): Generate correct flow control + information when exception handling notes are present. + +Sat Nov 1 13:42:19 1997 Jeffrey A Law (law@cygnus.com) + + * dwarf2out.c (output_call_frame_info): Fix length argument + to ASM_OUTPUT_ASCII. + (output_die, output_pubnames, output_line_info): Likewise. + +Fri Oct 31 07:10:09 1997 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump for snapshot. + + * dwarf2out.c (output_call_frame_info): Use ASM_OUTPUT_ASCII to + output ASCII by default. Only use ASM_OUTPUT_DWARF_STRING if + flag_debug_asm is on. + (output_die, output_pubnames, output_line_info): Likewise. + + * alias.c (init_alias_analysis): Add struct_value_incoming_rtx + and static_chain_rtx into the potential base values array if + they are registers. + + * alias.c (new_reg_base_value): New array of potential base values. + (unique_id): Now file scoped static. + (find_base_value, case REG): Return the value in reg_base_value + array for the REG if it exists. Else, return the value from + new_reg_base_value if copying args and REG is a hard register. + (find_base_value, case PLUS): If either operand of the PLUS is + a REG, try to get its base value. Handle base + index and + index + base. + (record_set): Use new_reg_base_value instead of reg_base_value. + (init_alias_analysis): Allocate space for new_reg_base_value too. + Rework code to iterate over the insns propagating base value + information until nothing changes. + + * global.c (global_alloc): Free the conflict matrix after + reload has finished. + +Fri Oct 31 01:45:31 1997 Jason Merrill + + * libgcc2.c (L_eh): Define __eh_pc. + Replace __eh_type with generic pointer __eh_info. + +Fri Oct 31 00:34:55 1996 J"orn Rennecke + + * expr.c (expand_increment): When enqueing a postincrement for a MEM, + use copy_to_reg if address is not a general_operand. + +Fri Oct 31 00:16:55 1997 J"orn Rennecke + + * profile.c (output_func_start_profiler): Clear flag_inline_functions + for the duration of the call to rest_of_compilation. + +Thu Oct 30 14:40:10 1997 Doug Evans + + * configure.in (sparc-*-elf*): Use sparc/elf.h, sparc/t-elf. + Set extra_parts. + (sparc*-*-*): Recognize --with-cpu=v9. + * sparc/elf.h: New file. + * sparc/t-elf: New file. + +Thu Oct 30 13:26:12 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.c (const_8bit_operand): New function. + (mask_ok_for_mem_btst): New funtion. + * mn10300.md (btst patterns with mem operands): Use new functions + to avoid creating btst instructions with invalid operands. + +Wed Oct 29 16:57:19 1997 Michael Meissner + + * rs6000/xm-sysv4.h: Include xm-linux.h instead of xm-svr4.h if we + are running on PowerPC Linux. + +Wed Oct 29 13:10:11 1997 Gavin Koch + + * config/mips/elf64.h (PREFERRED_DEBUGGING_TYPE): Only define + if not previously defined. + +Tue Oct 28 23:55:27 1997 Doug Evans (devans@cygnus.com) + + * function.c (assign_parms): Correct mode of stack_parm if + entry_parm underwent a mode conversion. + +1997-10-28 Brendan Kehoe + + * global.c (global_alloc): Use xmalloc instead of alloca for + CONFLICTS, since max_allocno * allocno_row_words alone can be more + than 2.5Mb sometimes. + +Tue Oct 28 15:29:15 1997 Richard Henderson + + * reload1.c (eliminate_regs [SET]): If [SUBREG] widened the mode of + DEST for the spill, adjust mode of SRC to compensate. + +Tue Oct 28 14:36:45 1997 Richard Henderson + + * alpha.md (reload_inqi): Check for MEM before strict_memory_address_p, + since any_memory_operand() allows pseudos during reload. + (reload_inhi, reload_outqi, reload_outhi): Likewise. + +Tue Oct 28 11:53:14 1997 Jim Wilson + + * m68k.md (btst patterns): Add 5200 support. + +Tue Oct 28 11:58:40 1997 Toon Moene + + * fold-const.c (fold): For ((a * C1) / C3) or (((a * C1) + C2) / C3) + optimizations, look inside dividend to determine if the expression + can be simplified by using EXACT_DIV_EXPR. + +Tue Oct 28 10:19:01 1997 Jason Merrill + + From Brendan: + * dwarf2out.c (output_call_frame_info): Use l1 instead of ".". + +Tue Oct 28 00:32:14 1997 Richard Henderson + + * alpha.c (summarize_insn [SUBREG]): Propogate SET. + +Mon Oct 27 23:59:26 1997 Richard Henderson + + * alpha.c (alpha_handle_trap_shadows): Don't call get_attr_trap + on a CLOBBER. + +Mon Oct 27 21:25:20 1997 Richard Henderson + + * alpha.md (movqi, movhi): Make sure new insns created during reload + won't need reloading themselves. + (reload_inqi, reload_inhi, reload_outqi, reload_outhi): Likewise. + +Mon Oct 27 16:11:10 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.h (GO_IF_LEGITIMATE_ADDRESS): Disable reg+reg. + +Sun Oct 26 13:50:44 1997 Richard Henderson + + * alpha.c (alpha_sa_mask [VMS]): Don't include $26 in the mask. + Patch from Klaus Kaempf . + +Sun Oct 26 13:31:47 1997 Jim Wilson (wilson@cygnus.com) + + * expr.c (expand_expr, case INDIRECT_REF): Optimize a reference + to an element in a constant string. + +Sun Oct 26 11:41:49 1997 Jason Merrill + + * dwarf2out.c (output_call_frame_info): The CIE pointer is now a 32 + bit PC-relative offset. The exception range table pointer is now in + the CIE. + * frame.c (dwarf_cie, dwarf_fde): Rename CIE_pointer to CIE_delta. + (count_fdes, add_fdes, get_cie): Adjust. + (cie_info, extract_cie_info, __frame_state_for): Adjust eh_ptr uses. + + From H.J. Lu: + * frame.c (count_fdes, add_fdes): Skip linked once FDE entries. + +Sun Oct 26 11:52:01 1997 Richard Henderson + + * alias.c (memrefs_conflict_p): Treat arg_pointer_rtx just + like stack_pointer_rtx. + +Sun Oct 26 11:32:16 1997 Manfred Hollstein + + * Makefile.in (bootstrap-lean): Combined with `normal' bootstrap + targets using "$@" to provide support for similar but not identical + targets without having to duplicate code. + (bootstrap4): New goal. + + * Makefile.in (compare, compare-lean, compare3): Combined to one + ruleset determining actions to be performed via $@. + (compare4, compare4-lean): New targets. + (gnucompare, gnucompare3): Combined to one ruleset determining + actions to be performed via $@. Also, note which files failed + the comparison test in .bad_compare. + (gnucompare-lean, gnucompare3-lean, gnucompare4-lean): New targets. + +Sun Oct 26 10:06:11 1997 Toon Moene + + * fold-const (fold): Also simplify FLOOR_DIV_EXPR to EXACT_DIV_EXPR + if the dividend is a multiple of the divisor. + +Sun Oct 26 09:21:40 1997 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (LIBGCC2_CFLAGS): Add -fexceptions. + + * alias.c (find_base_term): Handle PRE_INC, PRE_DEC, POST_INC, + and POS_DEC. + + * alias.c (true_dependence): Fix typo. + + * toplev.c (flag_rerun_loop_opt): New variable. + (f_options): Handle -frerun-loop-opt. + (rest_of_compilation): If -frerun-loop-opt, then run the loop + optimizer twice. + (main): Enable -frerun-loop-opt by default for -O2 or greater. + + * loop.c (simplify_giv_expr): Adding two invariants results + in an invariant. + +Sun Oct 26 09:15:15 1997 Richard Henderson + + * expr.c (get_inner_reference): Remove the array bias after + converting the index to Pmode. + +Sat Oct 25 12:20:58 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.h (TARGET_SWITCHES): Add -mmult-bug and -mno-mult-bug. + (TARGET_MULT_BUG): Define. + (TARGET_DEFAULT): Default to TARGET_MULT_BUG. + * mn10300.md (mulsi3): Handle TARGET_MULT_BUG. + +Fri Oct 24 17:40:34 1997 Jeffrey A Law (law@cygnus.com) + + * mn10200.c (indirect_memory_operand): Delete unused function. + * mn10200.h (EXTRA_CONSTRAINT): Handle 'R'. + * mn10200.md (bset, bclr insns): Handle output in a reg too. + +Fri Oct 24 15:54:57 1997 Richard Henderson + + * alpha.md (call patterns): Revert Oct 16 change; if we are to elide + the callee's ldgp, we must do it ourselves, and we use the jsr tag + for more than scheduling. + +Fri Oct 24 13:23:04 1997 Doug Evans + + * sparc/sparc.h (ASM_SPEC): Delete asm_arch. + +Fri Oct 24 13:19:40 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.c (symbolic_operand, legitimize_address): New functions. + * mn10300.h (LEGITIMIZE_ADDRESS): Call legitimize_address. + (GO_IF_LEGITIMATE_ADDRESS): Don't allow base + symbolic. + +Thu Oct 23 09:35:12 1997 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Thu Oct 23 08:03:59 1997 J"orn Rennecke + + * dbxout.c (dbxout_start_new_source_file): Use output_quoted_string + for FILENAME. + +Wed Oct 22 00:34:12 1997 Jeffrey A Law (law@cygnus.com) + + * toplev.c (flag_exceptions): Default value is 2. + (compile_file): If flag_exceptions still has the value 2, then + set it to 0. + + * rs6000.c (struct machine_function): Add pic_offset_table_rtx. + (rs6000_save_machine_status): Save pic_offset_table_rtx. + (rs6000_restore_machine_status: Restore pic_offset_table_rtx. + + * local-alloc.c (block_alloc): Don't lose if two SCRATCH expressions + are shared. + + * rs6000.md (*movsi_got_internal_mem): New pattern. + (*movsi_got_internal_mem splitter): New define_split. + +Tue Oct 21 18:14:03 1997 Jim Wilson + + * obstack.h (obstack_empty_p): Fix spurious space after backslash. + +Tue Oct 21 18:34:01 1997 Geoffrey KEATING + + * rs6000.c: Avoid creating a stack frame under SYSV ABI if we + only need to save LR. + +Tue Oct 21 10:06:40 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.md (movqi, movhi): Avoid using address registers as + destinations unless absolutely necessary. + + * mn10200.c (expand_prologue): Fix typo. + + * mn10200.h (GO_IF_LEGITIMATE_ADDRESS): Do not allow indexed + addresses. + * mn10200.md (neghi2): Provide an alternative which works if + the input and output register are the same. + + * mn10300.c (print_operand): Handle 'S'. + * mn10300.md (ashlsi3, lshrsi3, ashrsi3): Use %S for + shift amount in last alternative + + * mn10300.c (expand_epilogue): Rework to handle register restores + in "ret" and "retf" instructions correctly. + +Mon Oct 20 16:47:08 1997 Jim Wilson + + * expmed.c (extract_bit_field): Don't make flag_force_mem disable + extzv for memory operands. + + * cse.c (simplify_ternary_operation, case IF_THEN_ELSE): Collapse + redundant conditional moves to single operand. + +Mon Oct 20 15:30:26 1997 Nick Clifton + + * v850.h: Move define of __v850__ from CPP_PREDEFINES + to CPP_SPEC. + + * xm-v850.h: Use __v850 rather than __v850__ to + identify v850 port. + +Mon Oct 20 14:15:02 1997 Jim Wilson + + * mips/mips.c (compute_frame_size): Not a leaf function if + profile_flag set. + +Mon Oct 20 14:16:38 1997 Geoffrey KEATING + + * rs6000/t-ppccomm: Use -msdata=none for crtstuff. + +Mon Oct 20 12:28:17 1997 Doug Evans + + * sparc/sparc.h (SPARC_V9,SPARC_ARCH64): Delete. + (DEFAULT_ARCH32_P): New macro. + (TARGET_ARCH{32,64}): Allow compile time or runtime selection. + (enum cmodel): Declare. + (sparc_cmodel_string,sparc_cmodel): Declare. + (SPARC_DEFAULT_CMODEL): Provide default. + (TARGET_{MEDLOW,MEDANY}): Renamed to TARGET_CM_{MEDLOW,MEDANY}. + (TARGET_FULLANY): Deleted. + (TARGET_CM_MEDMID): New macro. + (CPP_CPU_DEFAULT_SPEC): Renamed from CPP_DEFAULT_SPEC. + (ASM_CPU_DEFAULT_SPEC): Renamed from ASM_DEFAULT_SPEC. + (CPP_PREDEFINES): Take out stuff now handled by %(cpp_arch). + (CPP_SPEC): Rewrite. + (CPP_ARCH{,32,64,_DEFAULT}_SPEC): New macros. + (CPP_{ENDIAN,SUBTARGET}_SPEC): New macros. + (ASM_ARCH{,32,64,_DEFAULT}_SPEC): New macros. + (ASM_SPEC): Add %(asm_arch). + (EXTRA_SPECS): Rename cpp_default to cpp_cpu_default. + Rename asm_default to asm_cpu_default. + Add cpp_arch32, cpp_arch64, cpp_arch_default, cpp_arch, cpp_endian, + cpp_subtarget, asm_arch32, asm_arch64, asm_arch_default, asm_arch. + (NO_BUILTIN_{PTRDIFF,SIZE}_TYPE): Define ifdef SPARC_BI_ARCH. + ({PTRDIFF,SIZE}_TYPE): Provide 32 and 64 bit values. + (MASK_INT64,MASK_LONG64): Delete. + (MASK_ARCH64): Renamed to MASK_64BIT. + (MASK_{MEDLOW,MEDANY,FULLANY,CODE_MODEL}): Delete. + (EMBMEDANY_BASE_REG): Renamed from MEDANY_BASE_REG. + (TARGET_SWITCHES): Always provide 64 bit options. + (ARCH64_SWITCHES): Delete. + (TARGET_OPTIONS): New option -mcmodel=. + (INT_TYPE_SIZE): Always 32. + (MAX_LONG_TYPE_SIZE): Define ifdef SPARC_BI_ARCH. + (INIT_EXPANDERS): sparc64_init_expanders renamed to sparc_init_.... + (FUNCTION_{,BLOCK_}PROFILER): Delete TARGET_EMBMEDANY support. + (PRINT_OPERAND_PUNCT_VALID_P): Add '_'. + * sparc/linux-aout.h (CPP_PREDEFINES): Take out stuff handled by + CPP_SPEC. + (CPP_SUBTARGET_SPEC): Renamed from CPP_SPEC. + * sparc/linux.h: Likewise. + * sparc/linux64.h (SPARC_V9,SPARC_ARCH64): Delete. + (ASM_CPU_DEFAULT_SPEC): Renamed from ASM_DEFAULT_SPEC. + (TARGET_DEFAULT): Delete MASK_LONG64, MASK_MEDANY, add MASK_64BIT. + (SPARC_DEFAULT_CMODEL): Define. + (CPP_PREDEFINES): Take out stuff handled by CPP_SPEC. + (CPP_SUBTARGET_SPEC): Renamed from CPP_SPEC. + (LONG_DOUBLE_TYPE_SIZE): Define. + (ASM_SPEC): Add %(asm_arch). + * sparc/sol2.h (CPP_PREDEFINES): Take out stuff handled by CPP_SPEC. + (CPP_SUBTARGET_SPEC): Renamed from CPP_SPEC. + (TARGET_CPU_DEFAULT): Add ultrasparc case. + * sparc/sp64-aout.h (SPARC_V9,SPARC_ARCH64): Delete. + (TARGET_DEFAULT): MASK_ARCH64 renamed to MASK_64BIT. + (SPARC_DEFAULT_CMODEL): Define. + * sparc/sp64-elf.h (SPARC_V9,SPARC_ARCH64): Delete. + (TARGET_DEFAULT): MASK_ARCH64 renamed to MASK_64BIT. Delete + MASK_LONG64, MASK_MEDANY. + (SPARC_DEFAULT_CMODEL): Define. + (CPP_PREDEFINES): Delete. + (CPP_SUBTARGET_SPEC): Renamed from CPP_SPEC. + (ASM_SPEC): Add %(asm_arch). + (LONG_DOUBLE_TYPE_SIZE): Define. + (DWARF2_DEBUGGING_INFO): Define. + * sparc/splet.h (CPP_SPEC): Delete. + * sparc/sysv4.h (CPP_PREDEFINES): Take out stuff handled by CPP_SPEC. + (FUNCTION_BLOCK_PROFILER): Delete TARGET_EMBMEDANY support. + (BLOCK_PROFILER): Likewise. + * sparc/sparc.c (sparc_cmodel_string,sparc_cmodel): New globals. + (sparc_override_options): Handle code model selection. + (sparc_init_expanders): Renamed from sparc64_init_expanders. + * sparc/sparc.md: TARGET_ renamed to TARGET_CM_.... + TARGET_MEDANY renamed to TARGET_CM_EMBMEDANY. + (sethi_di_embmedany_{data,text}): Renamed from sethi_di_medany_.... + (sethi_di_fullany): Delete. + +Mon Oct 20 02:00:18 1997 Klaus Kaempf + Jeff Law + Richard Kenner + + * alpha/vms.h (DIVSI3_LIBCALL): OTS$ functions are upper case. + (DIVDI3_LIBCALL, UDIVSI3_LIBCALL, UDIVDI3_LIBVALL): Likewise. + (MODSI3_LIBCALL, MODDI3_LIBCALL): Likewise. + (UMODSI3_LIBCALL, UMODDI3_LIBCALL): Likewise. + * alpha/alpha.md (arg_home): Likewise. + + * alpha/alpha.c (vmskrunch): Delete + * alpha/vms.h (ENCODE_SECTION_INFO, ASM_DECLARE_FUNCTION_NAME): Delete. + * alpha.c (output_prolog, VMS): Use alloca for entry_label and don't + truncate to 64 characters. + + * make-l2.com: Support openVMS/Alpha. + + * vmsconfig.com: Fix to work on openVMS/Alpha and openVMS/VAX. + +Sun Oct 19 19:00:35 1997 J"orn Rennecke + + * longlong.h (count_leading_zeros): Add missing casts to USItype. + +Sun Oct 19 18:44:06 1997 Jeffrey A Law (law@cygnus.com) + + * i386/bsd386.h (ASM_COMMENT_START): Define. + +Sat Oct 18 13:47:15 1997 Jason Merrill + + * tree.c (restore_tree_status): Also free up temporary storage + when we finish a toplevel function. + (dump_tree_statistics): Print stats for backend obstacks. + +Sat Oct 18 12:47:31 1997 Doug Evans + + * expr.c (use_group_regs): Don't call use_reg for MEMs. + +Sat Oct 18 09:49:46 1997 Jason Merrill + + * libgcc2.c (__throw): Don't copy the return address. + * dwarf2out.c (expand_builtin_dwarf_reg_size): Ignore return address. + + * except.c (exceptions_via_longjmp): Initialize to 2 (uninitialized). + * toplev.c (main): Initialize exceptions_via_longjmp. + + * tree.c: Add extra_inline_obstacks. + (save_tree_status): Use it. + (restore_tree_status): If this is a toplevel inline obstack and we + didn't want to save anything on it, recycle it. + (print_inline_obstack_statistics): New fn. + * function.c (pop_function_context_from): Pass context to + restore_tree_status. + * obstack.h (obstack_empty_p): New macro. + +Sat Oct 18 00:43:59 1997 Jeffrey A Law (law@cygnus.com) + + * i386/freebsd.h (ASM_COMMENT_START): Fix. + +Fri Oct 17 23:48:52 1997 Jim Wilson (wilson@cygnus.com) + + * v850.c (ep_memory_offset): New function. + (ep_memory_operand, substitute_ep_register, v850_reorg): Call it. + + * v850.h (CONST_OK_FOR_*): Add and correct comments. + (CONSTANT_ADDRESS_P): Add comment. + (EXTRA_CONSTRAINT): Define 'U'. + * v850.md: Add comments on bit field instructions. + (addsi3): Delete &r/r/r alternative. Add r/r/U alternative. + (lshrsi3): Use N not J constraint. + + * v850.md (v850_tst1+1): New define_split for tst1 instruction. + + * v850.c (reg_or_0_operand): Call register_operand. + (reg_or_int5_operand): Likewise. + * v850.h (MASK_BIG_SWITCH, TARGET_BIG_SWITCH): New macros. + (TARGET_SWITCHES): Add "big-switch". + (ASM_OUTPUT_ADDR_VEC_ELT, ASM_OUTPUT_ADDR_DIFF_ELT, CASE_VECTOR_MODE, + ASM_OUTPUT_BEFORE_BASE_LABEL): Add support for TARGET_BIG_SWITCH. + (CASE_DROPS_THROUGH): Comment out. + (CASE_VECTOR_PC_RELATIVE, JUMP_TABLES_IN_TEXT_SECTION): Define. + * v850.md (cmpsi): Delete compare mode. + (casesi): New pattern. + + * v850.h (CONST_OK_FOR_N): Delete redundant compare against zero. + * v850.md (ashlsi3): Use SImode not QImode for shift count. + (lshrsi3): Likewise. + + * v850.c (print_operand): Add 'c', 'C', and 'z' support. Delete + unreachable switch statement after 'b' support. Remove "b" from + strings for 'b' support. + * v850.md (branch_normal, branch_invert): Change %b to b%b. + +Fri Oct 17 23:33:20 1997 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (LIBGCC2_CFLAGS): Avoid a backslash then an + empty line if @inhibit_libc@ is empty. + +Fri Oct 17 23:24:40 1997 Robert Lipe (robertl@dgii.com) + + * i386/sco5.h: Let ELF use dwarf2 unwinding. COFF uses sjlj. + (EH_FRAME_SECTION_ASM_OP, EH_FRAME_SECTION_ASM_OP_ELF): Defined. + (EH_FRAME_SECTION_ASM_OP_COFF): Likewise. + (DWARF2_UNWIND_INFO): Let this track object file format. + (EXTRA_SECTIONS): Add in_eh. + (EH_FRAME_SECTION_ASM_OP, EH_FRAME_SECTION_ASM_OP_ELF): Define. + (EH_FRAME_SECTION_ASM_OP_COFF): Likewise. + +Fri Oct 17 17:13:42 1997 David S. Miller + + * sparc/linux64.h (LINK_SPEC): Dynamic linker is ld-linux64.so.2. + * sparc/sparc.h (FUNCTION_PROFILER): Fix format string when + TARGET_MEDANY. + * sparc/sparc.c (dwarf2out_cfi_label): Extern no longer needed. + (output_double_int): Output DI mode values correctly when + HOST_BITS_PER_WIDE_INT is 64. + (output_fp_move_quad): If TARGET_V9 and not TARGET_HARD_QUAD, use + fmovd so it works if a quad float ends up in one of the upper 32 + float regs. + * sparc/sparc.md (pic_{lo_sum,sethi}_di): New patterns + necessary for PIC support on sparc64. + +Fri Oct 17 13:39:56 1997 Doug Evans + + * sparc/sp64-elf.h (TARGET_DEFAULT): Delete MASK_STACK_BIAS. + * sparc/sparc.h (PROMOTE_MODE): Promote small ints if arch64. + (PROMOTE_FUNCTION_ARGS,PROMOTE_FUNCTION_RETURN): Define. + (SPARC_FIRST_FP_REG, SPARC_FP_REG_P): New macros. + (SPARC_{OUTGOING,INCOMING}_INT_ARG_FIRST): New macros. + (SPARC_FP_ARG_FIRST): New macro. + (CONDITIONAL_REGISTER_USAGE): All v9 fp regs are volatile now. + (REG_ALLOC_ORDER,REG_LEAF_ALLOC_ORDER): Reorganize fp regs. + (NPARM_REGS): There are 32 fp argument registers now. + (FUNCTION_ARG_REGNO_P): Likewise. + (FIRST_PARM_OFFSET): Update to new v9 abi. + (REG_PARM_STACK_SPACE): Define for arch64. + (enum sparc_arg_class): Delete. + (sparc_arg_count,sparc_n_named_args): Delete. + (struct sparc_args): Redefine and use for arch32 as well as arch64. + (GET_SPARC_ARG_CLASS,ROUND_REG,ROUND_ADVANCE): Delete. + (FUNCTION_ARG_ADVANCE): Rewrite. + (FUNCTION_ARG,FUNCTION_INCOMING_ARG): Rewrite. + (FUNCTION_ARG_{PARTIAL_NREGS,PASS_BY_REFERENCE}): Rewrite. + (FUNCTION_ARG_CALLEE_COPIES): Delete. + (FUNCTION_ARG_{PADDING,BOUNDARY}): Define. + (STRICT_ARGUMENT_NAMING): Define. + (doublemove_string): Declare. + * sparc/sparc.c (sparc_arg_count,sparc_n_named_args): Delete. + (single_move_string): Use GEN_INT, and HOST_WIDE_INT. + (doublemove_string): New function. + (output_move_quad): Clean up some of the arch64 support. + (compute_frame_size): Add REG_PARM_STACK_SPACE if arch64. + Don't add 8 bytes of reserved space if arch64. + (sparc_builtin_saveregs): Combine arch32/arch64 versions. + (init_cumulative_args): New function. + (function_arg_slotno): New static function. + (function_arg,function_arg_partial_nregs): New functions. + (function_arg_{pass_by_reference,advance}): New functions. + (function_arg_padding): New function. + * ginclude/va-sparc.h: Rewrite v9 support. + +Fri Oct 17 12:29:48 1997 Christian Iseli + + * regclass.c (record_address_regs): Look at REG_OK_FOR_{BASE,INDEX}_P + for hard regs to determine base and index registers. + + * reload.c (debug_reload_to_stream): New function. Specify stream + into which to write debug info. + (debug_reload): Modify to call debug_reload_to_stream with stderr. + +Thu Oct 16 15:07:51 1997 Richard Henderson + + * combine.c (can_combine_p): Don't combine with an asm whose + output is a hard register. + +Thu Oct 16 15:43:26 1997 Mike Stump (mrs@wrs.com) + + * c-decl.c (start_struct): Ensure that structs with forward + declarations are in fact packed when -fpack-struct is given. + + * stor-layout.c (layout_record): Ignore STRUCTURE_SIZE_BOUNDARY if + we are packing a structure. This allows a structure with only + bytes to be aligned on a byte boundary and have no padding on a + m68k. + +Thu Oct 16 15:17:54 1997 Richard Kenner + + * rs6000.h (ROUND_TYPE_ALIGN): Don't blow up if no fields in record. + +Thu Oct 16 11:20:30 1997 Richard Henderson + + * alpha.c (alpha_return_addr_rtx): New variable. + (alpha_save_machine_status): New; save it. + (alpha_restore_machine_status): New; restore it. + (alpha_init_expanders): New; clear it. + (alpha_return_addr): New; set it. + (alpha_ra_ever_killed): New; if alpha_return_addr_rtx, regs_ever_live + is overly conservative, so search the insns explicitly. + (alpha_sa_mask [VMS]): Check alpha_ra_ever_killed. + (alpha_sa_size [VMS && !VMS]): Likewise. + * alpha.h (RETURN_ADDR_RTX): Call alpha_return_addr. + (INIT_EXPANDERS): New definition. + + * alpha.c: Move REG_PV, REG_RA somewhere more visible in the file. + (output_prolog [!VMS]): Use them. + + * alpha.c (output_prolog [!VMS]): Move gp detection to ... + (alpha_does_function_need_gp): ... a new function. Refine the + CALL_INSN test to just TYPE_JSR. + * alpha.md (most call insns): Fix some jsr/ibr type transpositions. + +Thu Oct 16 09:36:47 1997 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Wed Oct 15 21:38:18 1997 Richard Kenner + + * pa.c (move_operand): Respect -mdisable-indexing. + * pa.h (GO_IF_LEGITIMATE_ADDRESS): Likewise. + +Wed Oct 15 21:34:45 1997 David Edelsohn + + * rs6000.md (udivsi3, divsi3): Split into MQ and non-MQ cases for + PPC601. + (umulsidi3,umulsi3_highpart): Ditto. + (smulsi3_highpart_no_mq): Add !TARGET_POWER. + +Wed Oct 15 18:21:46 1997 Richard Henderson + + * alpha.c (final_prescan_insn): Gut, remove and transform to ... + (alpha_handle_trap_shadows): ... a new function. Handle the entire + function in one go. Emit RTL for trapb, instead of printf directly. + (alpha_reorg): New function. Call alpha_handle_trap_shadows. + (trap_pending): Kill global variable. + (output_epilog): Don't call final_prescan_insn. + (struct shadow_summary): Elide $31 and $f31; now it fits in a word. + * alpha.h (FINAL_PRESCAN_INSN): Remove. + (MACHINE_DEPENENT_REORG): Define. + * alpha.md (jsr patterns with trapb): Stupid and useless. Kill. + (trapb): New insn. + +Wed Oct 15 18:16:05 1997 Richard Henderson + + Tune Haifa scheduler for Alpha: + * alpha.h (ISSUE_RATE): Define. + * alpha.c (alpha_adjust_cost): Handle EV5 mult delay; don't apply + EV4 adjustments to EV5. + * alpha.md: Remove all scaling from function unit delays. Rework + EV5 function units to match the CPU. + (umuldi3_highpart): EV5 added the IMULH insn class. + +Wed Oct 15 17:42:41 1997 Jeffrey A Law (law@cygnus.com) + + * pa.c (following_call): Fail if the CALL_INSN is an indirect + call. + +Tue Oct 14 12:01:00 1997 Mark Mitchell + + * cplus-dem.c (demangle_signature): Don't look for return types on + constructors. Handle member template constructors. + +Tue Oct 14 11:30:29 1997 Jason Merrill + + * tree.c (expr_tree_cons, build_expr_list, expralloc): New fns. + * tree.h: Declare them. + +Fri Oct 10 13:46:56 1997 Doug Evans + + * configure.in: Handle --with-newlib. + * Makefile.in (LIBGCC2_CFLAGS): Add @inhibit_libc@. + + * sparc/t-sp64 (LIBGCC2_CFLAGS): Delete. + +Wed Oct 8 14:37:44 1997 Jeffrey A Law (law@cygnus.com) + + * config/ptx4.h: Fix typo. + +Wed Oct 8 08:57:20 1997 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Tue Oct 7 16:27:34 1997 Manfred Hollstein + + * aclocal.m4: Substitute INSTALL. + * configure: Re-built. + +Tue Oct 7 15:37:35 1997 Jeffrey A Law (law@cygnus.com) + + * integrate.c (save_for_inline_copying): Avoid undefined pointer + operations. + (expand_inline_function): Likewise. + + * dwarf2out.c (output_call_frame_info): Reinstate last change + using flag_debug_asm check instead of flag_verbose_asm. + +Tue Oct 7 12:57:26 1997 Jim Wilson + + * dwarf2out.c (output_call_frame_info): Remove last change. + +1997-10-04 Andreas Schwab + + * frame.c (__frame_state_for): Execute the FDE insns until the + current pc value is strictly bigger than the target pc value. + +Tue Oct 7 11:00:42 1997 Jason Merrill + + * regclass.c (init_reg_modes): If we can't find a mode for the + register, use the previous one. + +Tue Oct 7 10:55:34 1997 Richard Henderson + + * haifa-sched.c (print_block_visualization): Call fprintf directly, + don't sprintf through an alloca'ed buffer. + +Tue Oct 7 10:52:29 1997 Thomas Koenig (ig25@rz.uni-karlsruhe.de) + + * reload.c (decompose): Always initialize val.base. + +Tue Oct 7 10:19:26 1997 Manfred Hollstein (manfred@lts.sel.alcatel.de) + + * m68k/mot3300.h (ASM_OUTPUT_ALIGN): Accept any alignment + instead of aborting. + * dwarf2out.c (output_call_frame_info): Call app_enable and + app_disable to let GNU as accept the generated comments. + +Tue Oct 7 11:41:21 1997 Michael Meissner + + * tree.h (get_file_function_name): Add declaration. + * dwarf2out.c (output_call_frame_info): No need to cast + get_file_function_name call anymore. + * profile.c (toplevel): Remove get_file_function_name + declaration. + * c-lang.c (finish_file): Ditto. + +Tue Oct 7 10:01:45 1997 Chip Salzenberg + + * Makefile.in (program_transform_name): Let autoconf substitute + the correct value. + +Tue Oct 7 09:54:35 1997 Jeffrey A Law (law@cygnus.com) + + * haifa-sched.c (schedule_block): If the first real insn in a + block has any special notes attached to it, remove them. + +Tue Oct 7 09:48:51 1997 Richard Henderson + + * alpha.h (FLOAT_STORE_FLAG_VALUE): It's 2.0 not 0.5. + +Mon Oct 6 12:47:32 1997 Manfred Hollstein (manfred@lts.sel.alcatel.de) + + * m88k.c (m88k_begin_prologue): Remove superfluous backslash. + +Mon Oct 6 12:04:24 1997 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (check-g77): New test target. + (CHECK-TARGETS): Add check-g77. + +Fri Oct 3 11:56:36 1997 Jason Merrill + + * toplev.c (rest_of_compilation): Defer all non-nested inlines. + +Fri Oct 3 15:49:27 1997 Michael Meissner + + * flow.c (print_rtl_with_bb): Cast alloca return value for + in_bb_p. + +Thu Oct 2 21:15:03 1997 Richard Henderson + + * i386.h (RETURN_ADDR_RTX): New definition that works for + __builtin_return_address(0) and -fomit-frame-pointer. + +Wed Oct 1 13:43:53 1997 Jim Wilson + + Bring over from FSF. + Tue Aug 5 16:10:45 1997 Jason Merrill + + * mips.c (function_arg): Handle passing a struct + containing a double in a DFmode register without the PARALLEL. + +Wed Oct 1 11:13:25 1997 Ian Lance Taylor + + * pexecute.c: Use spawn if __CYGWIN32__. + + * pexecute.c: Include "config.h" first, as per autoconf manual + (from Paul Eggert ). + +Wed Oct 1 01:44:36 1997 Philippe De Muyter + + * m68k/x-mot3300 (XCFLAGS): Disable as's long/short jump + optimisation for f/expr.o and f/stb.o. + +Tue Sep 30 23:48:57 1997 Jeffrey A Law (law@cygnus.com) + + * cse.c (this_insn_cc0_mode): Initialize. + +Tue Sep 30 23:09:40 1997 Thomas Koenig + + * cccp.c (expand_to_temp_buffer): Initialize all members of obuf. + + * haifa-sched.c (get_block_head_tail): Remove unneeded initialization. + +Tue Sep 30 23:06:43 1997 Richard Henderson + + * alpha.md (beq): For registers and ints 0-255, use cmpeq+bne, since + that pair will dual-issue on the 21164 and plus+beq won't. + (bne): Likewise for cmpeq+beq. + +Tue Sep 30 16:07:58 1997 Jim Wilson + + * except.c (find_exception_handler_labels): Correct argument to free. + +Tue Sep 30 11:00:00 1997 Brendan Kehoe + + * except.c (find_exception_handler_labels): Free LABELS when we're + done. + +Mon Sep 29 14:04:35 1997 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Mon Sep 29 10:51:53 1997 Jason Merrill + + * flow.c (find_basic_blocks): Mark calls as potentially jumping + to the EH labels. + +Mon Sep 29 09:58:06 1997 Jeffrey A Law (law@cygnus.com) + + * configure.in: Substitute for "install" too. + * configure: Rebuilt. + +Mon Sep 29 00:38:42 1997 Aaron Jackson + + * Makefile.in (bootstrap-lean, compare-lean): New targets. + +Mon Sep 29 00:18:16 1997 Richard Henderson (rth@cygnus.com) + + * alias.c (base_alias_check): Two symbols can conflict if they + are accessed via AND. + (memrefs_conflict_p): Likewise. + + * alpha.h (SETUP_INCOMING_VARARGS): Emit a blockage insn + after flushing argument registers to the stack. + + * Makefile.in (mostlyclean): Remove .regmove files. + +Sun Sep 28 18:59:58 1997 Jason Merrill + + * libgcc2.c (__throw): Fix thinko. + +Sun Sep 28 12:00:52 1997 Mark Mitchell + + * cplus-dem.c (demangle_template): Add new parameter. Handle new + template-function mangling. + (consume_count_with_underscores): New function. + (demangle_signature): Handle new name-mangling scheme. + +Sun Sep 28 01:55:04 1997 Philippe De Muyter + + * flow.c (print_rtl_with_bb): Cast alloca return values for variables + start and end. + +Sun Sep 28 01:05:16 1997 Jeffrey A Law (law@cygnus.com) + + * frame.c: Remove last change. + * dwarf2.h: Remove last change. + * tree.h: Add declarations of DWARF2 unwind info support + functions. + +Sat Sep 27 11:02:38 1997 Jason Merrill + + * c-decl.c (init_decl_processing): Add __builtin_dwarf_reg_size. + * tree.h (built_in_function): Likewise. + * expr.c (expand_builtin): Likewise. + * except.h: Likewise. + * dwarf2out.c (expand_builtin_dwarf_reg_size): New fn. + * libgcc2.c (copy_reg): New fn. + (__throw): Use it. + +Fri Sep 26 08:54:59 1997 Paul Eggert + + * c-typeck.c (build_binary_op): Warn about comparing signed vs + unsigned if -W is specified and -Wno-sign-compare is not. + * c-decl.c (warn_sign_compare): Initialize to -1. + (c_decode_option): -Wall no longer implies -Wsign-compare. + +Fri Sep 26 09:00:13 1997 Andreas Schwab + + * frame.c: Include gansidecl.h for PROTO. + * dwarf2out.c: Move inclusion of dwarf2.h down so that PROTO is + defined. Don't declare dwarf2out_cfi_label here. + * dwarf2.h: Add declarations of DWARF2 unwind info support + functions. + * m68k.c: Include dwarf2.h. + (output_function_prologue): Add dwarf2 support. + * m68k.h (INCOMING_RETURN_ADDR_RTX, DWARF_FRAME_REGNUM): New macros. + (INCOMING_FRAME_SP_OFFSET): Likewise. + + * integrate.c (expand_inline_function): Make sure there is at + least one insn that can be used as an insertion point. + +Wed Sep 24 21:34:06 1997 Jason Merrill + + * dwarf2out.c: s/flag_verbose_asm/flag_debug_asm/ + +Wed Sep 24 22:05:30 1997 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Wed Sep 24 17:36:23 1997 Doug Evans + + Bring over from FSF. + + Wed Sep 24 19:17:08 1997 Doug Evans + + * sparc/sparc.md (get_pc_via_call): Renamed from get_pc_sp32. + (get_pc_via_rdpc): Renamed from get_pc_sp64. + * sparc/sparc.c (finalize_pic): Update call to gen_get_pc_via_call. + + Wed Sep 24 18:38:22 1997 David S. Miller + + * sparc/sparc.h (ASM_CPU_SPEC): Pass -Av9a for v8plus, ultrasparc. + (TARGET_OPTIONS): Add -malign-loops=, -malign-jumps=, + -malign-functions=. + (sparc_align_{loops,jumps,funcs}_string): Declare. + (sparc_align_{loops,jumps,funcs}): Declare. + (DEFAULT_SPARC_ALIGN_FUNCS): New macro. + (FUNCTION_BOUNDARY): Use sparc_align_funcs. + (STACK_BIAS): Define. + (SPARC_SIMM*_P): Cast to unsigned HOST_WIDE_INT first, then perform + test. + (SPARC_SETHI_P): New macro. + (CONST_OK_FOR_LETTER_P): Use it. + (ASM_OUTPUT_ALIGN_CODE): Define. + (ASM_OUTPUT_LOOP_ALIGN): Define. + * sparc/sparc.c (sparc_align_{loops,jumps,funcs}_string): New globals. + (sparc_align_{loops,jumps,funcs}): New globals. + (sparc_override_options): Handle -malign-loops=, -malign-jumps=, + -malign-functions=. + (move_operand): Use SPARC_SETHI_P. + (arith_double_operand): Cast to unsigned HOST_WIDE_INT first, then + perform test. + (arith11_double_operand): Likewise. + (arith10_double_operand): Likewise. + (finalize_pic): Finish sparc64 support. + (emit_move_sequence): Use SPARC_SETHI_P. Simplify low part of + 64 bit constants if able. + (output_fp_move_quad): Don't use fmovq unless TARGET_HARD_QUAD. + (sparc_builtin_saveregs, sparc64 case): Don't save fp regs if + ! TARGET_FPU. + * sparc/sparc.md (*): Use GEN_INT instead of gen_rtx. + (get_pc_sp32): Use for sparc64 as well. + (lo_sum_di_sp{32,64}): Fix handling on 64 bit hosts. + (sethi_di_sp64_const): Likewise. + (movtf_cc_sp64): Check TARGET_HARD_QUAD. + (cmp_zero_extract_sp64): Use unsigned HOST_WIDE_INT in cast. + (ashlsi3, ashldi3, ashrsi3, ashrdi3, lshrsi3, lshrdi3): Likewise. + + Tue Sep 23 19:02:46 1997 Doug Evans + + * sparc/linux-aout.h (COMMENT_BEGIN): Delete. + * sparc/linux.h (COMMENT_BEGIN): Likewise. + * sparc/linux64.h (COMMENT_BEGIN): Likewise. + + Tue Sep 23 14:48:18 1997 David S. Miller + + Add sparc64 linux support. + * configure.in (sparc64-*-linux*): Recognize. Add sparc/xm-sparc.h + to xm_file list on 32-bit sparc-linux. + * sparc/xm-sp64.h: New file. + * sparc/linux64.h: New file. + * sparc/xm-linux.h: Include some standard headers if not inhibit_libc. + Don't include xm-sparc.h. + * config/xm-linux.h (HAVE_PUTENV, HAVE_ATEXIT): Define. + * glimits.h (LONG_MAX): Handle sparc64. + + Sat Sep 20 03:07:54 1997 Doug Evans + + * sparc/sysv4.h (ASM_COMMENT_START): Delete. + * sparc.h (ASM_COMMENT_START): Define. + * sparc.c (output_function_prologue): Use it. + (sparc_flat_output_function_{epi,pro}logue): Likewise. + + Wed Sep 17 15:04:19 1997 Doug Evans + + * sparc/sysv4.h (ASM_OUTPUT_{FLOAT,DOUBLE,LONG_DOUBLE}): Delete, + use sparc.h's copies. + * sparc/sparc.h (ASM_OUTPUT_{FLOAT,DOUBLE,LONG_DOUBLE}): Print + ascii form as well. + + Mon Sep 8 08:45:19 1997 Richard Kenner + + * sparc.c (dwarf2out_cfi_label): Add declaration. + (save_regs, output_function_prologue): Remove cast for it. + (sparc_flat_{save_restore,output_function_prologue): Likewise. + ({save,restore}_regs): No longer inline. + +Tue Sep 23 12:34:51 1997 Richard Kenner + + * fold-const.c (make_range): Correctly handle cases of converting + from unsigned to signed type. + +Tue Sep 23 12:34:51 1997 Bernd Schmidt + + * fold-const.c (merge_ranges): Make sure that if one range is subset + of another, it will always be the second range. Correct (+,-) case to + account for this. + +Tue Sep 23 08:32:51 1997 Jason Merrill + + * final.c (final_end_function): Also do dwarf2 thing if + DWARF2_DEBUGGING_INFO. + (final_start_function): Likewise. + +Tue Sep 23 01:15:50 1997 David S. Miller + + * expmed.c (expand_divmod): If compute_mode is not the same as + mode, handle the case where convert_modes() causes op1 to no + longer be a CONST_INT. + + * reorg.c (dbr_schedule): At end of this pass, add REG_BR_PRED + note holding get_jump_flags() calculation to all JUMP_INSNs. + * rtl.h (enum reg_note): New note types REG_BR_PRED and REG_SAVE_AREA. + * rtl.c (reg_note_name): Add new note types. + +Tue Sep 23 00:59:54 1997 Jeffrey A Law (law@cygnus.com) + + * rtlanal.c (computed_jump_p): Fix typo in last change. + +Tue Sep 23 00:42:44 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * loop.c (indirect_jump_in_function_p): Return 0 + by default. + +Tue Sep 23 00:33:55 1997 Jeffrey A Law (law@cygnus.com) + + * rs6000/xm-rs6000.h: Fix thinko in last change. + * rs6000/xm-sysv4.h: Likewise. + +Mon Sep 22 19:33:53 1997 Jim Wilson + + * mips.c (save_restore_insns): Only set RTX_FRAME_RELATED_P if store_p. + +Mon Sep 22 14:41:00 1997 Jeffrey A Law (law@cygnus.com) + + * reg-stack.c (find_blocks): Fix thinko in last change. + +1997-09-21 Andreas Schwab + + * m68k.c (output_function_prologue): Add dwarf2 support. + + * m68k.h (INCOMING_RETURN_ADDR_RTX, DWARF_FRAME_REGNUM, + INCOMING_FRAME_SP_OFFSET): New definitions. + +Mon Sep 22 11:36:42 1997 David S. Miller + + * combine.c (try_combine): Use NULL_RTX instead of '0' where + appropriate in calls to gen_rtx(). + * cse.c (cse_main): Likewise. + * emit-rtl.c (gen_label_rtx): Likewise. + * expr.c (init_expr_once): Likewise. + * haifa-sched.c (flush_pending_lists, sched_analyze_insn, + sched_analyze, init_rgn_data_dependences, + compute_block_backward_dependences): Likewise. + * sched.c (schedule_insns): Likewise. + * varasm.c (immed_double_const): Likewise. + + * sparc.h (INCOMING_FRAME_SP_OFFSET): Define to + SPARC_STACK_BIAS for sake of dwarf2 on sparc64. + +Mon Sep 22 11:21:33 1997 J. Kean Johnston + + * i386/sco5.h: Make ELF default file format and add -mcoff/-melf.. + (MULTILIB_DEFAULTS): Define. + (ASM_SPEC, CPP_SPEC): Handle -mcoff. + (STARTFILE_SPEC, ENDFILE_SPEC, LINK_SPEC): Likewise. + (LIBGCC_SPEC): Likewise. + (MASK_COFF, TARGET_COFF, TARGET_ELF): Define. + (SUBTARGET_SWITCHES): Add -mcoff and -melf. + * i386/t-sco5 (CRTSTUFF_T_CFLAGS): Add -fPIC. + (CRTSTUFF_T_CFLAGS_S): Tweak for COFF. + (EXTRA_PARTS, TAROUTOPTS): Delete. + (libgcc1-elf, libgcc2-elf, libgcc-elf targets): Delete. + (MULTILIB_OPTIONS): Define. + (MULTILIB_DIRNAMES, MULTILIB_EXCEPTIONS): Likewise. + (MULTILIB_MATCHE, MULTILIB_EXTRA_OPTS): Likewise. + +Mon Sep 22 02:10:43 1997 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sun Sep 21 17:45:45 1997 Jeffrey A Law (law@cygnus.com) + + * loop.c (loop_number): Delete function. Change all references + to use uid_loop_num array. + * loop.h (loop_number): Delete declaration. + * unroll.c (unroll_loop): Change "loop_number" references to + use uid_loop_num instead. + + * loop.c (loop_unroll_factor): Move outside #ifdef HAIFA + conditional. + (loop_unroll_iter): Remove unused variable and all references. + (loop_optimize): Always allocate and clear space for loop_unroll_factor. + (insert_bct): Fix minor formatting problems. + * loop.h (loop_unroll_factor): Move decl outside #ifdef HAIFA. + (loop_unroll_iter): Removed unused decl. + * unroll.c (unroll_loop): Remove code to set loop_unroll_iter. + Always record the unrolling factor. + + * cse.c (simplify_relational_operation): Set h0u just like h0s. + Similarly for h1u and h1s. + + * flow.c (jmp_uses_reg_or_mem): Deleted unused function. + (find_basic_blocks): Use computed_jump_p to determine if a + particular JUMP_INSN is a computed jump. + * reg-stack.c (find_blocks): Use computed_jump_p to determine + if a particular JUMP_INSN is a computed jump. + * rtlanal.c (jmp_uses_reg_or_mem): New function. + (computed_jump_p): Likewise. + * rtl.h (computed_jump_p): Declare. + * genattrtab.c (pc_rtx): Define and initialize. + * loop.c (loop_optimize): Always determine if the current + function has a computed jump. + (indirect_jump_in_function_p): Use computed_jump_p to determine + if a particular JUMP_INSN is a computed jump. + + * loop.c (fix_bct_param): Delete unused function. + (check_bct_param): Likewise. + +Sat Sep 20 16:22:06 1997 Jason Merrill + + * frame.c (__deregister_frame): Check properly for initialized object. + +Fri Sep 19 20:51:03 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * alpha/linux.h (HANDLE_SYSV_PRAGMA): Defined. + +Fri Sep 19 18:53:50 1997 J"orn Rennecke + + * jump.c (thread_jumps): check can_reverse_comparison_p before + threading a reversed-condition jump. + + * sched.c (update_flow_info): Don't pass SCRATCH to dead_or_set_p. + * haifa-sched.c (update_flow_info): Likewise. + +Thu Sep 18 21:13:40 1997 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (BOOT_CFLAGS): Use -O2. + + * configure.in (strtoul, bsearch): Have autoconf check for these + functions. + * configure, config.in: Rebuilt. + + * m68k/xm-mot3300.h (alloca): Properly declare if __STDC__. + * mips/mips.h (alloca): Likewise. + * rs6000/xm-rs6000.h (alloca): Likewise. + * rs6000/xm-sysv4.h: Likewise. + +Thu Sep 18 14:22:22 1997 Jason Merrill + + * final.c (final_scan_insn): Hand BARRIERs off to the dwarf2 code. + * dwarf2out.c (dwarf2out_frame_debug): Pass the whole insn along. + (dwarf2out_stack_adjust): A BARRIER resets the args space to 0. + + * except.c (end_eh_unwinder): Subtract 1 from return address. + * libgcc2.c (__throw): Likewise. + (find_exception_handler): Don't change PC here. Compare end with >. + +Thu Sep 18 10:43:07 1997 Nick Clifton + + * v850.c (compute_register_save_size): Correct register + number. + * v850.md (save_interrupt, return_interrupt): Correct + register number. + * v850/lib1funcs.asm (save_interrupt): Correct register number. + (return_interrupt): Use stack pointer, not element pointer. + +1997-09-18 Brendan Kehoe + + * configure.in, configure: Make sure to create the stage* and include + symbolic links in each subdirectory. + +Thu Sep 18 01:47:06 1997 Jeffrey A Law (law@cygnus.com) + + * pa.md (reload_peepholes): Don't allow addresses with side + effects for the memory operand. + +Wed Sep 17 18:19:53 1997 Jason Merrill + + * libgcc2.c (find_exception_handler): Subtract one from our PC when + looking for a handler, to avoid hitting the beginning of the next + region. + + * except.c (expand_builtin_set_return_addr_reg): Use force_operand. + +Wed Sep 17 18:33:59 1997 Jeffrey A Law (law@cygnus.com) + + * mips/abi64.h (LONG_MAX_SPEC): Define. + * mips.h (LONG_MAX_SPEC): Define. + (CPP_SPEC): Include long_max_spec. + (EXTRA_SPECS): Include long_max_spec. + +Wed Sep 17 14:11:38 1997 Jeffrey A Law (law@cygnus.com) + + * v850.c (construct_save_jarl): Fix thinko in last change. + +Wed Sep 17 09:53:07 1997 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Tue Sep 16 14:22:36 1997 Jason Merrill + + * libgcc2.c (find_exception_handler): Not found is -1. + + * integrate.c (expand_inline_function): Move expand_start_bindings + after expanding the arguments. + +Tue Sep 16 11:13:46 1997 Jim Wilson + + * expr.c (expand_expr): Remove previous incorrect change. + If target and slot has no DECL_RTL, then call mark_addressable + again for the slot after we give it RTL. + +Tue Sep 16 09:18:52 1997 Jason Merrill (jason@cygnus.com) + + * expr.c (expand_expr, case TARGET_EXPR): Call mark_addressable + again for the slot after we give it RTL. + +Tue Sep 16 00:13:20 1997 Nick Clifton + + * v850.c (register_is_ok_for_epilogue, + pattern_is_ok_for_epilogue, construct_restore_jr, + pattern_is_ok_for_prologue, construct_save_jarl): New functions. + + * v850.h (pattern_is_ok_for_prologue, + pattern_is_ok_for_epilogue, register_is_ok_for_epilogue): New + predicates. + + * v850.md: Replace prologue and epilogue patterns with a + match_parallel pattern. + +Mon Sep 15 22:53:01 1997 Jeffrey A Law (law@cygnus.com) + + * aclocal.m4: Add replacement for AC_PROG_INSTALL. + * configure.in: Use EGCS_PROG_INSTALL. + +Mon Sep 15 22:40:55 1997 Jim Wilson (wilson@cygnus.com) + + * dwarf2out.c (gen_subprogram_die): Handle redefinition of an + extern inline function. + +Mon Sep 15 22:40:55 1997 Richard Henderson (rth@cygnus.com) + + * dwarf2out.c (reg_loc_descriptor): Fix prototype. + (concat_loc_descriptor): New function. + (loc_descriptor): Call it. + (add_AT_location_description): Also elide the descriptor if both + halves of a CONCAT are pseudos. + (add_location_or_const_value_attribute): Recognize CONCAT too. + +Mon Sep 15 15:24:00 1997 Richard Henderson + + * alpha.md (movdi): Handle CONST_DOUBLE for TARGET_BUILD_CONSTANTS. + + * alpha/alpha.c (output_prolog): New variable sa_reg. Use it for + out-or-range reg_offset. + (output_epilog): Likewise. + +Mon Sep 15 15:39:26 1997 Jeffrey A Law (law@cygnus.com) + + * cse.c (simplify_relational_operation): If MODE specifies a + mode wider than HOST_WIDE_INT, then the high word of a CONST_INT + is derived from the sign bit of the low word. + +Mon Sep 15 11:43:38 1997 Jason Merrill + + Support dwarf2 unwinding on PUSH_ROUNDING targets like the x86. + + * dwarf2.h: Add DW_CFA_GNU_args_size. + * frame.c (execute_cfa_insn): Likewise. + * dwarf2out.c (dwarf_cfi_name, output_cfi): Likewise. + (dwarf2out_args_size, dwarf2out_stack_adjust): New fns. + (dwarf2out_frame_debug): If this isn't a prologue or epilogue + insn, hand it off to dwarf2out_stack_adjust. + (dwarf2out_begin_prologue): Initialize args_size. + * frame.h (struct frame_state): Add args_size. + * libgcc2.c (__throw): Use args_size. + * final.c (final_scan_insn): If we push args, hand off all insns + to dwarf2out_frame_debug. + * defaults.h (DWARF2_UNWIND_INFO): OK for !ACCUMULATE_OUTGOING_ARGS. + + * dwarf2out.c dwarf2out_frame_debug): Fix typo. + Handle epilogue restore of SP from FP. + * emit-rtl.c (gen_sequence): Still generate a sequence if the + lone insn has RTX_FRAME_RELATED_P set. + + * frame.c (extract_cie_info): Handle "e" augmentation. + * dwarf2out.c (ASM_OUTPUT_DWARF_*): Provide definitions in the + absence of UNALIGNED_*_ASM_OP. + (UNALIGNED_*_ASM_OP): Only provide defaults if OBJECT_FORMAT_ELF. + (output_call_frame_info): Use "e" instead of "z" for augmentation. + Don't emit augmentation fields length. + (dwarf2out_do_frame): Move outside of #ifdefs. + * defaults.h (DWARF2_UNWIND_INFO): Don't require unaligned data + opcodes. + + * sparc.h (UNALIGNED_INT_ASM_OP et al): Don't define here after all. + * sparc/sysv4.h (UNALIGNED_INT_ASM_OP): Define here. + * sparc/sunos4.h (DWARF2_UNWIND_INFO): Define to 0. + * sparc/sun4gas.h: New file. + * configure.in: Use sun4gas.h if SunOS 4 --with-gnu-as. + + * collect2.c (write_c_file_stat, write_c_file_glob): Declare + __register_frame_table and __deregister_frame. + +1997-09-15 Brendan Kehoe + + * except.c (find_exception_handler_labels): Use xmalloc instead of + alloca, since MAX_LABELNO - MIN_LABELNO can be more than 1 million + in some cases. + +Sun Sep 14 21:01:23 1997 Jeffrey A Law (law@cygnus.com) + + * Makefile.in: Various changes to build info files + in the object tree rather than the source tree. + +Sun Sep 14 12:24:30 1997 Jeffrey A Law (law@cygnus.com) + + * fixinc.math: New file to fix math.h on some systems. + * configure.in (freebsd, netbsd): Use fixinc.math on these + systems. + * configure: Rebuilt. + +Sun Sep 14 11:11:05 1997 Jeffrey A Law (law@cygnus.com) + + * regmove.c (regmove_optimize): If we end up moving the + original insn due to lifetime overlaps, make sure to move + REG_NOTES too. + +Sat Sep 13 15:51:11 1997 Manfred Hollstein + + * Makefile.in (INSTALL_{PROGRAM,DATA}): Use value found by configure. + +Sat Sep 13 12:57:26 1997 Jeffrey A Law (law@cygnus.com) + + * haifa-sched.c (add_branch_dependences): Make each insn in + a SCHED_GROUP_P block explicitly depend on the previous insn. + +Fri Sep 12 13:49:58 1997 Jason Merrill + + * except.h: Prototype dwarf2 hooks. + * expr.c: Adjust. + +Thu Sep 11 17:43:55 1997 Jim Wilson + + * configure.in (native_prefix): Delete. + (mips-dec-netbsd): Don't set prefix. + (*linux*): Don't set prefix. + +Thu Sep 11 15:48:32 1997 Fred Fish + + * protoize.c: Include only if HAVE_VARARGS_H is + defined. If not defined, include if + HAVE_SYS_VARARGS_H is defined. + * configure.in: Test for varargs.h and sys/varargs.h. + * configure: Regenerate with autoconf. + * config.in: Regenerate with autoheader. + + * cpplib.c (quote_string): Cast first arg of sprintf call + from "unsigned char *" to "char *". + (output_line_command): Ditto. + (macroexpand): Ditto. + (do_line): Cast atoi arg from "unsigned char *" to "char *". + +Wed Sep 10 21:37:30 1997 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump for snapshot. + + * Makefile.in (compare): Exit with nonzero status if there + are comparison failures. Note which files failed the + comparison test in .bad_compare. + +Wed Sep 10 17:05:46 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * config/alpha/elf.h (CPP_PREDEFINES): Remove -D__PIC__ -D__pic__. + +Wed Sep 10 16:37:28 1997 Fred Fish + + * Makefile.in (LN, LN_S): New macros, use where appropriate. + * aclocal.m4 (GCC_PROG_LN_S, GCC_PROG_LN): New tests. + * configure.in: Use GCC_PROG_LN_S and GCC_PROG_LN. + * configure: Regenerated. + +Thu Sep 11 11:09:43 1997 Jeffrey A Law (law@cygnus.com) + + * loop.c (strength_reduce): Fix typo. + +Wed Sep 10 16:01:15 1997 Jim Wilson + + * m88k/m88k.c (struct option): Rename to struct options. + * m88k/dolph.h (INITIALIZE_TRAMPOLINE): Delete here. + * m88k/sysv3.h (INITIALIZE_TRAMPOLINE): Delete ifdef and comments. + * libgcc2.c (__enable_execute_stack): Check for __sysV88__ not + __DOLPHIN__ or sysV88. + +Wed Sep 10 14:58:40 1997 Jim Wilson + + * emit-rtl.c (gen_lowpart_common): For a SUBREG, add in word when + create new subreg. + +Wed Sep 10 15:19:22 1997 Jeffrey A Law (law@cygnus.com) + + * config.sub: Accept 'amigados' for backward compatability. + +Wed Sep 10 14:05:08 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * Makefile.in (testsuite/site.exp): New target. + (check-gcc, check-g++): Depend on testsuite/site.exp. + Don't stop for failure. + +Wed Sep 10 12:59:57 1997 Jason Merrill + + * expr.c (expand_builtin): Only support __builtin_dwarf_fp_regnum() + if DWARF2_UNWIND_INFO. + +Wed Sep 10 11:49:20 1997 Jason Merrill + + Add support for exception handling using DWARF 2 frame unwind info. + Currently works on SPARC and MIPS, and almost on x86. + + * libgcc2.c (get_reg, put_reg, get_return_addr, put_return_addr, + next_stack_level, in_reg_window): Helper fns. + (__throw): Implement for DWARF2_UNWIND_INFO. + + * expr.c (expand_builtin): Handle builtins used by __throw. + * tree.h (enum built_in_function): Add builtins used by __throw. + * c-decl.c (init_decl_processing): Declare builtins used by __throw. + * dwarf2out.c (expand_builtin_dwarf_fp_regnum): Used by __throw. + * except.c (expand_builtin_unwind_init): Hook for dwarf2 __throw. + (expand_builtin_extract_return_addr): Likewise. + (expand_builtin_frob_return_addr): Likewise. + (expand_builtin_set_return_addr_reg): Likewise. + (expand_builtin_eh_stub): Likewise. + (expand_builtin_set_eh_regs): Likewise. + (eh_regs): Choose two call-clobbered registers for passing back values. + + * frame.c, frame.h: New files for parsing dwarf 2 frame info. + * Makefile.in (LIB2ADD): New variable. Add $(srcdir)/frame.c. + (libgcc2.a): Use it instead of $(LIB2FUNCS_EXTRA) $(LANG_LIB2FUNCS) + (stmp-multilib): Likewise. + ($(T)crtbegin.o, $(T)crtend.o): Add -fno-exceptions. + + * except.c: #include "defaults.h". + (exceptions_via_longjmp): Default depends on DWARF2_UNWIND_INFO. + (emit_throw): Don't defeat assemble_external if DWARF2_UNWIND_INFO. + (register_exception_table_p): New fn. + (start_eh_unwinder): Don't do anything if DWARF2_UNWIND_INFO. + (end_eh_unwinder): Likewise. + + * crtstuff.c: Wrap .eh_frame section, use EH_FRAME_SECTION_ASM_OP, + call __register_frame and __deregister_frame as needed. + * varasm.c (eh_frame_section): New fn if EH_FRAME_SECTION_ASM_OP. + * dwarf2out.c (EH_FRAME_SECTION): Now a function-like macro. Check + EH_FRAME_SECTION_ASM_OP. + * sparc/sysv4.h (EH_FRAME_SECTION_ASM_OP): Define. + * mips/iris6.h: (EH_FRAME_SECTION_ASM_OP): Define. + (LINK_SPEC): Add __EH_FRAME_BEGIN__ to hidden symbols. + + * dwarf2out.c (output_call_frame_info): If no support for + EXCEPTION_SECTION, mark the start of the frame info with a + collectable tag. + * collect2.c (frame_tables): New list. + (is_ctor_dtor): Recognise frame entries. + (scan_prog_file): Likewise. + (main): Pass -fno-exceptions to sub-compile. Also do collection + if there are any frame entries. + (write_c_file_stat): Call __register_frame_table and + __deregister_frame as needed. + (write_c_file_glob): Likewise. + + * defaults.h (DWARF2_UNWIND_INFO): Default to 1 if supported. + Also require unaligned reloc support. + * sparc.h (UNALIGNED_SHORT_ASM_OP, UNALIGNED_INT_ASM_OP, + UNALIGNED_DOUBLE_INT_ASM_OP): Define here. + * sparc/sysv4.h: Not here. + + * toplev.c (compile_file): Call dwarf2out_frame_{init,finish}. + * dwarf2out.c (dwarf2out_init): Don't call dwarf2out_frame_init. + (dwarf2out_finish): Don't call dwarf2out_frame_finish. + + * libgcc2.c (L_eh): Reorganize, moving code shared by different + EH implementations to the top. + (find_exception_handler): Split out. Start from 0. Compare against + end with >=. + (__find_first_exception_table_match): Use it. + * except.c (output_exception_table): Don't do anything if there's + no table. Don't output a first entry of zeroes. + (eh_outer_context): Adjust properly. + (add_eh_table_entry): Use xrealloc. + * toplev.c (compile_file): Just call output_exception_table. + +Wed Sep 10 11:30:36 1997 Jason Merrill + + * i386.c (ix86_prologue): Add dwarf2 support for !do_rtl case. + +Wed Sep 10 08:17:10 1997 Torbjorn Granlund + + * except.c (eh_outer_context): Do masking using expand_and. + +Wed Sep 10 01:38:30 1997 Doug Evans + + Add port done awhile ago for the ARC cpu. + * arc/arc.h: New file. + * arc/arc.c: New file. + * arc/arc.md: New file. + * arc/initfini.c: New file. + * arc/lib1funcs.asm: New file. + * arc/t-arc: New file. + * arc/xm-arc.h: New file. + * ginclude/va-arc.h: New file. + * ginclude/stdarg.h: Include va-arc.h ifdef __arc__. + * ginclude/varargs.h: Likewise. + * Makefile.in (USER_H): Add va-arc.h. + * configure.in (arc-*-elf*): Recognize. + * longlong.h: Add ARC support. + +Wed Sep 10 01:32:54 1997 Jeffrey A Law (law@cygnus.com) + + * expr.c (clear_storage): Use CONST0_RTX instead of const0_rtx. + when clearing non-BLKmode data. + +Wed Sep 10 00:29:29 1997 Manfred Hollstein + + * m88k/sysv3.h (INITIALIZE_TRAMPOLINE) Define. + * libgcc2.c (__enable_execute_stack): Provide for sysV88 too. + + * xm-m88k.h (USG): Only define if it hasn't already been defined. + + * Makefile.in (risky-stage1): Delete gratutious whitespace. + + * Makefile.in (clean): Delete libgcc1-test. + + * Makefile.in (INSTALL): cd to $(srcdir) before running texinfo. + +Tue Sep 9 17:07:36 1997 Stan Cox + + * m88k.c (m88k_expand_prologue): Set MEM_IN_STRUCT_P of va_list + template. + +Tue Sep 9 09:50:02 1997 Richard Kenner + + * dwarf2out.c (output_call_frame_info): Call named_section. + +Tue Sep 9 09:12:17 1997 Jeffrey A Law (law@cygnus.com) + + * haifa-sched.c (print_value): Fix last change. + +Tue Sep 9 01:30:37 1997 Jason Merrill + + * mips.h (DWARF_FRAME_REGNUM): Use the same numbering regardless of + write_symbols. + +Mon Sep 8 16:32:43 1997 Jason Merrill + + * mips.c (function_prologue): Set up the CFA when ABI_32. + + * sparc.c (save_regs): Check dwarf2out_do_frame instead of DWARF2_DEBUG + for dwarf2 unwind info. + (output_function_prologue, sparc_flat_output_function_prologue): Same. + + * final.c (final_end_function): Check dwarf2out_do_frame instead + of DWARF2_DEBUG for dwarf2 unwind info. + (final_scan_insn): Likewise. + (final_start_function): Likewise. Initialize dwarf2 frame debug here. + (final): Not here. + + * expr.c (expand_builtin_return_addr): Only SETUP_FRAME_ADDRESSES if + count > 0. + + * varasm.c (exception_section): Check EXCEPTION_SECTION first. + +Mon Sep 8 15:15:11 1997 Nick Clifton + + * v850.h (ASM_SPEC): Pass on target processor. + (CPP_PREDEFINES): Only define if not already specified. + (TARGET_VERSION): Only define if not already specified. + (MASK_CPU, MASK_V850, MASK_DEFAULT): Bits to specify target + processor. + (EXTRA_SWITCHES): Extra entries in the switches array. + (TARGET_DEFAULT): Set default target processor. + +Mon Sep 8 18:26:35 1997 Jim Wilson + + * m68k.h (MACHINE_STATE_SAVE, MACHINE_STATE_RESTORE): In MOTOROLA + cases, add %# and %/, and add : to make them into extended asms. + +Sun Sep 7 23:57:50 1997 Weiwen Liu + + * alias.c (init_alias_analysis): Clean up incompatible pointer + type warning in bzero. + * regmove.c (regmove_optimize): Ditto. + * haifa-sched.c (find_rgns): Ditto. + + * haifa-sched.c (print_value): Clean up ptr->int cast + warnings. + +Sun Sep 7 23:18:32 1997 Fred Fish + + * INSTALL: Change 'amigados' to 'amigaos' to match current usage. + * install.texi (Configurations): Ditto. + * config.sub: Ditto. + +Sun Sep 7 22:56:56 1997 Weiwen Liu (liu@hepvms.physics.yale.edu) + + * Makefile.in (sdbout.o): Depend on insn-config.h. + +Sun Sep 7 18:44:50 1997 Jim Wilson + + * m68k/m68k.h (TARGET_SWITCHES): For 68000, 68302, subtract MASK_68881. + For 68303, 68332, cpu32, subtract MASK_68040_ONLY. + +Sun Sep 7 18:30:46 1997 Jason Merrill + + * dwarf2out.c (dwarf2out_frame_debug): Assume that in a PARALLEL + prologue insn, only the first elt is significant. + (output_call_frame_info): For exception handling, always use 4-byte + fields as specified by the dwarf2 spec. + Don't skip trivial FDEs. + +Sun Sep 7 14:19:39 1997 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Sun Sep 7 14:17:36 1997 Torbjorn Granlund (tege@pdc.kth.se) + + * expmed.c (expand_divmod): Make op1_is_pow2 depend on unsignedp + for negative constants. Promote EXACT_DIV_EXPR to TRUNC_DIV_EXPR + when op1_is_pow2. + +Sun Sep 7 13:46:46 1997 Jeffrey A Law (law@cygnus.com) + + * final.c (shorten_branches): During first pass, assume worst + possible alignment for ADDR_VEC and ADDR_VEC_DIFF insns. + + * Makefile.in (distclean): Remove various things left around + by running the testsuite. + +Sun Sep 7 13:16:06 1997 Manfred Hollstein + + * configure.in (out_file): Emit definition to config.status in order + to have a defined value for configure.lang. + * configure: Re-built. + +Sun Sep 7 09:59:08 1997 Jan-Jaap van der Heijden (J.J.vanderHeijden@student.utwente.nl) + + * configure.in: Make symlink to as-new rather than as.new. Similarly + for ld-new. + * configure: Rebuilt. + +Fri Sep 5 16:54:55 1997 Jim Wilson + + * profile.c (output_func_start_profiler): Set DECL_EXTERNAL to zero. + +Fri Sep 5 16:16:44 1997 Christian Kuehnke + + * sparc/sparc.md: Add ultrasparc scheduling support. + * sparc/sparc.h (RTX_COSTS): For MULT give v9 a cost of 25 insns. + +Fri Sep 5 14:04:59 1997 Philippe De Muyter + + * integrate.c (save_for_inline_copying): Use 0, not NULL_PTR, + as initial value for real_label_map. + (copy_for_inline): Likewise. + +Fri Sep 5 13:36:44 1997 J"orn Rennecke + + * sched.c (update_flow_info) When looking if to set found_split_dest + or found_orig_dest, look at all parts of a PARALLEL. + * haifa-sched.c (update_flow_info): Likewise. + +Fri Sep 5 10:08:44 1997 Jeffrey A Law (law@cygnus.com) + + * v850: New directory for v850 port. + * v850/lib1funcs.asm: New file. + * t-v850, v850.c, v850.h, v850.md, xm-v850.h: New files. + * ginclude/va-v850.h: New file. + * ginclude/varargs.h, ginclude/stdarg.h: Include va-mn10200.h. + * configure.in (mn10200-*-*): New target. + * configure: Rebuilt. + * config.sub: Handle v850-elf. + * Makefile.in (USER_H): Add va-mn10200.h. + * invoke.texi: Document v850 stuff. + +Fri Sep 5 09:37:50 1997 Jim Wilson (wilson@cygnus.com) + + * sdbout.c (plain_type_1, case ARRAY_TYPE): Verify that TYPE_DOMAIN + has integer TYPE_{MAX,MIN}_VALUE before using them. + + * m68k/m68k.h (MACHINE_STATE_SAVE, MACHINE_STATE_RESTORE): Add + __HPUX_ASM__ versions. + +Fri Sep 5 09:08:44 1997 Jeffrey A Law (law@cygnus.com) + + * install.sh: Delete duplicate install script. + +Thu Sep 4 23:14:27 1997 Stan Cox (coxs@dg-rtp.dg.com) + + * reg-stack.c (subst_stack_regs): Pop the stack register for a + computed goto which sets the same stack register. + + * reg-stack.c (compare_for_stack_reg): Swap only if the source and + destination are both on the regstack. + (subst_stack_regs_pat): Put the destination at the top of the regstack. + +Thu Sep 4 15:02:27 1997 Jim Wilson + + * mips.md (nonlocal_goto_receiver): Define. + + * profile.c (output_arc_profiler): Check next_insert_after for non + NULL before deferencing it. + + * i386/t-sol2 (TARGET_LIBGCC2_CFLAGS): Define to -fPIC. + +Thu Sep 4 14:51:57 1997 Jeffrey A Law (law@cygnus.com) + + * i386.h (CPP_CPU_DEFAULT): Avoid using #elif. + +Thu Sep 4 15:01:49 1997 Michael Meissner + + * toplev.c (rest_of_compilation): For passes starting with + flow_analysis, use print_rtl_with_bb instead of print_rtl. + + * print-rtl.c (print_rtl_single): Print a single rtl value to a + file. + + * flow.c (print_rtl_with_bb): Print which insns start and end + basic blocks. For the start of a basic block, also print the live + information. + +Thu Sep 4 11:51:43 1997 Jim Wilson + + * toplev.c (main): Change #elif to #else/#ifdef + + * tlink.c: Include ctype.h. + * ginclude/va-mips.h: Add _VA_MIPS_H_ENUM ifdef/define/endif. + +Thu Sep 4 11:17:16 1997 Mikeael Meissner (meissner@cygnus.com) + + * bitmap.c: Conditionally include stdlib.h. + (free): Provide a declaration if NEED_DECLARATION_FREE. + +Thu Sep 4 09:58:53 1997 Joel Sherrill (joel@OARcorp.com) + + * i960/i960.h: Added default for SUBTARGET_SWITCHES macro. + +Thu Sep 4 09:53:20 1997 Jim Wilson (wilson@cygnus.com) + + * profile.c (output_arc_profiler): Verify next_insert_after is an + INSN before and after skipping a stack pop. + +Thu Sep 4 07:39:19 1997 J"orn Rennecke + + * final.c (shorten_branches): Don't count the lengths of deleted + instructions. + +Thu Sep 4 09:43:01 1997 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump for snapshot. + +Thu Sep 4 11:04:21 1997 Michael Meissner + + * bitmap.h (EXECUTE_IF_AND_IN_BITMAP): New macro, to iterate over + two bitmaps ANDed together. + (bitmap_print): Declare. + + * bitmap.c (function_obstack): Don't declare any more. + (bitmap_obstack): Obstack for allocating links from. + (bitmap_obstack_init): New static to say whether to initialize + bitmap_obstack. + (bitmap_element_allocate): Use bitmap_obstack to allocate from. + (bitmap_release_memory): Free all memory allocated from + bitmap_obstack. + + * basic-block.h (EXECUTE_IF_AND_IN_REG_SET): New macro, invoke + EXECUTE_IF_AND_IN_BITMAP. + +Wed Sep 3 10:39:42 1997 Jim Wilson + + * alias.c (true_dependence): Address with AND can alias scalars. + (anti_dependence, output_dependence): Likewise. + + * alias.c (true_dependence): Test x for BLKmode, in addition to mem. + +Wed Sep 3 09:28:50 CDT 1997 Joel Sherrill (joel@OARcorp.com) + + * i386/go32-rtems.h, i386/rtems.h, i960/rtems.h, m68k/rtems.h, + mips/rtems64.h, pa/rtems.h, rs6000/rtems.h, sh/rtems.h, + sparc/rtems.h (subtarget_switches): Removed SUBTARGET_SWITCHES + definitions. Use -qrtems instead of -mrtems. + +Wed Sep 3 09:05:41 1997 Robert Lipe (robert@dgii.com) + + * xm-sco5.h (sys_siglist): Define. + (SYS_SIGLIST_DECLARED): Likewise. + +Tue Sep 2 23:33:33 1997 Jeffrey A Law (law@cygnus.com) + + * expr.c (convert_move): Handle truncation from TQFmode to QFmode. + +Wed Sep 3 02:09:30 1997 Torbjorn Granlund + + * except.c (eh_outer_context): Expand masking operation using + expand_binop. + +Tue Sep 2 18:09:39 1997 Jim Wilson + + * alpha.md (floatdisf2-1): New pattern. + +Tue Sep 2 18:41:55 1997 Jeffrey A Law (law@cygnus.com) + + * xm-svr4.h (SYS_SIGLIST_DECLARED): Define. + * xm-news.h (SYS_SIGLIST_DECLARED): Likewise. + * xm-sysv4.h (SYS_SIGLIST_DECLARED): Likewise. + * gcc.texi: Note that if you define sys_siglist that you should + also define SYS_SIGLIST_DECLARED. + + * mn10200.h (INITIALIZE_TRAMPOLINE): PC relative instructions + are relative to the next instruction, not the current instruction. + +Tue Sep 2 14:22:43 1997 Jim Wilson + + * local-alloc.c (contains_replace_regs): New function. + (update_equiv_regs): When adding a REG_EQUIV note for a set of a MEM, + verify that there is no existing REG_EQUIV note, and add a call to + contains_place_regs. + +Tue Sep 2 12:48:11 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * config/alpha/elf.h (CPP_PREDEFINES): Add -D__PIC__ -D__pic__. + (STARTFILE_SPEC): Always use crtbegin.o%s + (ENDFILE_SPEC): Always use crtend.o%s. + +Tue Sep 2 12:00:36 1997 Jim Wilson + + * alpha/alpha.h (PREFERRED_RELOAD_CLASS): Return NO_REGS if NO_REGS + is passed in. + * emit-rtl.c (gen_lowpart_common): Add code to convert CONST_INT to + SFmode for 64 bit hosts. + +Tue Sep 2 13:42:38 1997 Paul N. Hilfinger + + * fixincludes: Permits spaces between # and define. Discard C++ + comments in sys/pci.h on HP/UX 10.20. + +Mon Sep 1 22:13:18 1997 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump for snapshot. + + * pa.c (restore_unscaled_index_insn_codes): New function. + (record_unscaled_index_insn_codes): Likewise. + (output_function_prologue): Call restore_unscaled_index_insn_codes. + (output_function_epilogue): Free memory for unscaled_index_insn_codes. + (pa_reorg): Call record_unscaled_index_insn_codes. + + * haifa-sched.c (move_insn): Handle notes correctly for insns + with SCHED_GROUP_P set. + +Mon Sep 1 16:58:57 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * alpha/xm-linux.h (USE_BFD): Undef before define. + +Mon Sep 1 16:25:34 1997 Jim Wilson + + * cse.c (cse_insn): Don't record BLKmode values. + +Mon Sep 1 11:25:47 1997 Stephen Williams (steve@icarus.icarus.com) + + * i960.h (LINK_SPEC): Handle "-mjX" and "-mrp" switches. + +Mon Sep 1 08:29:46 1997 Jeffrey A Law (law@cygnus.com) + + * cccp.c (sys_errlist): Remove special 4.4bsd declaration. + * collect2.c (sys_errlist): Likewise. + * cpplib.c (sys_errlist): Likewise. + * gcc.c (sys_errlist): Likewise. + * protoize (sys_errlist): Likewise. + * configure.in: Check for strerror. + * xm-freebsd.h (HAVE_STRERROR): Remove definition. + * xm-gnu.h (HAVE_STRERROR): Likewise. + * xm-linux.h (HAVE_STRERROR): Likewise. + * xm-netbsd.h (HAVE_STRERROR): Likewise. + * xm-bsd386.h (HAVE_STRERROR): Likewise. + * xm-cygwin32.h (HAVE_STRERROR): Likewise. + * xm-dos.h (HAVE_STRERROR): Likewise. + * xm-mingw32.h (HAVE_STRERROR): Likewise. + * xm-pa.h (HAVE_STRERROR): Likewise. + * xm-papro.h (HAVE_STRERROR): Likewise. + * xm-sysv4.h (HAVE_STRERROR): Likewise. + * configure, config.in: Rebuilt. + + * Makefile.in: Add several missing "else true" clauses. + + * collect2.c: Change DONT_DECLARE_SYS_SIGLIST to SYS_SIGLIST_DECLARED. + * mips-tfile.c: Likewise. + * gcc.texi: DONT_DECLARE_SYS_SIGLIST: Remove docs. + * xm-linux.h (DONT_DECLARE_SYS_SIGLIST): Delete definition. + * xm-freebsd.h, xm-bsd386.h, xm-sysv4.h, xm-sol2.h: Likewise. + * configure.in: Check for sys_siglist declaration. + * configure, config.in: Rebuilt. + +Mon Sep 1 08:04:07 1997 Joel Sherrill (joel@OARcorp.com) + + * i386/go32-rtems.h, i386/rtems.h, i960/rtems.h, + m68k/rtems.h, mips/rtems64.h, pa/rtems.h, rs6000/rtems.h, + sparc/rtems.h (subtarget_switches): Added -mrtems as a switch. + * i960/i960.h: Added SUBTARGET_SWITCHES macro. + * rs6000/sysv4.h (extra_subtarget_switches): Added new + macro EXTRA_SUBTARGET_SWITCHES. + * configure.in (sh*-*-rtems*): New target. + * sh/rtems.h: New file. + * sh/sh.h: Added SUBTARGET_SWITCHES macro. + * configure: Rebuilt. + +Sat Aug 30 22:54:26 1997 Jim Wilson + + * unroll.c (calculate_giv_inc): Handle increment with code PLUS. + +Sat Aug 30 10:49:46 1997 David Edelsohn + + * rs6000.md: Make DF fused-add operations pay attention to + -mno-fused-add. + +Fri Aug 29 19:19:54 1997 Jim Wilson + + * i386/xm-sysv4.h (DONT_DECLARE_SYS_SIGLIST): Define. + +Fri Aug 29 16:13:51 1997 Jeffrey A Law (law@cygnus.com) + + * pa.md (reload_peepholes): Make sure operand is a REG before + examining REGNO. Allow general registers too. + +Fri Aug 29 11:42:04 1997 Jim Wilson + + * varasm.c (mark_constants): Don't look inside CONST_DOUBLEs. + +Fri Aug 29 09:33:20 1997 Philipp Thomas (kthomas@lxi165.gwdg.de) + + * dwarf2out.c (build_abbrev_table): Use xrealloc, not xmalloc + to reallocate abbrev_die_table. + +Thu Aug 28 15:14:46 1997 Jim Wilson + + * m68k/m68k.md (iorsi_zexthi_ashl16): Disable. + +1997-08-27 Andreas Schwab + + * Makefile.in (config.status): Depend on version.c + + * expr.h (insn_gen_function): Reenable prototype. + + * expr.c (move_by_pieces_1, clear_by_pieces_1): Fix prototype of + first parameter. + +Thu Aug 28 13:01:43 1997 Jim Wilson + + * i386.c (ix86_expand_epilogue): Emit blockage instruction when pic. + +Thu Aug 28 07:03:15 1997 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump for latest snapshot. + + * bc-optab.c: Conditionally include stdlib.h. + (free): Provide a declaration if NEED_DECLARATION_FREE. + * tree.c (free): Provide a declaration if NEED_DECLARATION_FREE. + * rtl.h (free): Remove declaration. + * tree.h (free): Remvoe declaration. + + * configure: Rebuilt. + +Wed Aug 27 21:32:20 1997 Jeffrey A Law (law@cygnus.com) + + * flags.h (flag_move_all_movables): Declare. + (flag_reduce_all_givs): Likewise. + * loop.c (move_movables): Handle flag_move_all_movables. + (strength_reduce): Handle flag_reduce_all_givs. + * toplev.c (flag_move_all_movables): Define. + (flag_reduce_all_givs): Likewise. + (f_options): Add -fmove-all-movables and -freduce-all-givs. + * invoke.texi: Document new options, including alias stuff that + wasn't included last time. + +Wed Aug 27 18:08:51 1997 Bob Manson (manson@cygnus.com) + + * t-h8300: Use TARGET_LIBGCC2_CFLAGS instead of LIBGCC2_CFLAGS. + * t-mn10200: Ditto. + * t-vxsparc: Ditto. + * t-vxworks68: Ditto. + * t-vxworks960: Ditto. + * t-vx29k: Ditto. + +Wed Aug 27 16:35:29 1997 Richard Henderson + + * alpha/xm-alpha.h (alloca): Define alloca to builtin_alloca for GNUC + if not already defined, and USE_C_ALLOCA not defined. + +Wed Aug 27 16:08:43 1997 Jim Wilson + + * config.guess: Replace with script that uses ../config.guess. + + * config/alpha/elf.h (DEFAULT_VTABLE_THUNKS): New. Defined as 1 + if USE_GNULIBC_1 is not defined. + +Wed Aug 27 15:49:12 1997 Richard Henderson + + * alpha/elf.h (LINK_SPEC): Conditionalize on USE_GNULIBC_1. + * config.guess: Recognize alpha-linux-gnulibc1. + * configure.in (alpha-*-linux-gnulibc1): New target. + (alpha-*-linux-gnu*): Don't build crtbegin/end. + +Wed Aug 27 11:52:58 1997 Jim Wilson + + * m68k.md (iorsi3_internal): Readd ! TARGET_5200 check lost in + last change. + +Wed Aug 27 01:56:18 1997 Doug Evans + + * loop.c (combine_movables): Earlier insns don't match later ones. + +Wed Aug 27 01:24:25 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * config/linux.h (CC1_SPEC): Define it only if not defined. + + * config/m68k/linux.h (CC1_SPEC): Undefine it before include + + + * config/linux.h (DEFAULT_VTABLE_THUNKS): New. Defined as 1 if + USE_GNULIBC_1 is not defined. + + * config/rs6000/linux.h (DEFAULT_VTABLE_THUNKS): New. Defined as 1. + + * config/sparc/linux.h (DEFAULT_VTABLE_THUNKS): New. Defined + as 1 if USE_GNULIBC_1 is not defined. + +Wed Aug 27 00:49:14 1997 Jeffrey A Law (law@cygnus.com) + + * reorg.c (dbr_schedule): Allow current_function_return_rtx + to be something other than a REG. + * function.c (expand_function_end): Fix current_function_return_rtx + if it was a pseudo. + + * t-freebsd (USER_H): Include EXTRA_HEADERS and LANG_EXTRA_HEADERS. + * x-netbsd: Likewise + * x-dgux (USER_H): Include EXTRA_HEADERS and LANG_EXTRA_HEADERS + (INSTALL_HEADERS): Delete. + * x-dguxbcs: Likewise. + * x-hp3bsd44: Likewise + * x-pa: Likewise. + +Wed Aug 27 00:30:00 1997 Bernd Schmidt + + * i386.md (pop): pop increments the stack pointer. + (prologue_set_stack_ptr): New pattern. + * i386.c (ix86_expand_prologue): Use prologue_set_stack_ptr + instead of subsi3. + +Tue Aug 26 18:50:32 1997 Jim Wilson + + * reload.c (find_reloads, case '0'): Reject matching a non-offsettable + address where an offsettable address is required. + +Tue Aug 26 17:54:56 1997 Michael P. Hayes (michaelh@ongaonga.chch.cri.nz> + + * loop.c (check_final_value): Don't miss a biv increment in a + parallel. + +Tue Aug 26 12:03:49 1997 Jim Wilson (wilson@cygnus.com) + + * dwarfout.c (dwarfout_file_scope_decl, case TYPE_DECL): Check + TYPE_DECL_IS_STUB instead of DECL_NAME. + +Mon Aug 25 23:27:10 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * objc/Make-lang.in ($(OBJC_O)): Also depend on cc1obj. + +Mon Aug 25 23:27:10 1997 Jim Meyering + + * objc/Make-lang.in ($(OBJC_O)): Also depend on $(GCC_PASSES). + +Mon Aug 25 13:12:24 1997 Jeffrey A Law (law@cygnus.com) + + * haifa-sched.c (find_pre_sched_live): Remove #if 0 code. + (find_post_sched_live): Likewise. + + * haifa-sched.c (schedule_block): Remove old code to get arguments + from hard regs into pseudos early. + +Mon Aug 25 08:55:00 1997 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump for new snapshot. + + * local-alloc.c (update_equiv_regs): All the target to reject + promotion of some REG_EQUAL to REG_EQUIV notes. + * pa.h (DONT_RECORD_EQUIVALENCE): Define. + + * pa.c (secondary_reload_class): (mem (mem ... )) does not need + secondary reloads. + + * pa.c (hppa_builtin_saveregs): Emit a blockage insn after the + store of the argument registers. + +Mon Aug 25 08:39:02 1997 Craig Burley (burley@gnu.ai.mit.edu) + + * fold-const.c (multiple_of_p): New function. + (fold): Turn some cases of *_DIV_EXPR into EXACT_DIV_EXPR. + +Mon Aug 25 01:47:41 1997 Jeffrey A Law (law@cygnus.com) + + * expr.h (insn_gen_function): Temporarily remove prototype. + +Sun Aug 24 17:22:21 1997 Jim Wilson + + * Makefile.in (install-info): Don't cd into srcdir. Add srcdir to + filenames. Use sed to extract base filename for install. + +Sat Aug 23 18:19:40 1997 John F. Carr + + * unroll.c (find_splittable_givs): Only share if two givs have the + same add and multiply values. + +Sat Aug 23 14:36:27 1997 Jim Wilson + + * m68k/next.h (GO_IF_INDEXABLE_BASE): Fix typo in undef. + * m68k/m68kemb.h (LIB_SPEC): Add missing comment end before it. + +Sat Aug 23 00:18:22 1997 Jeffrey A Law (law@cygnus.com) + + * pa.c (pa_reorg): Always put begin_brtab and end_brtab insns + around branch tables. + * pa.md (begin_brtab, end_brtab): Only emit the .begin_brtab + and .end_brtab directives if TARGET_GAS. + +Fri Aug 22 14:05:55 1997 Jim Wilson + + * alias.c (true_dependence): Pass x_addr not x to varies. + + * acconfig.h (NEED_DECLARATION_CALLOC): Add. + * configure.in: Add GCC_NEED_DECLARATION call for calloc. + * rs6000/xm-rs6000.h (malloc, realloc, calloc, free): Delete + declarations. + * config.in, configure: Regenerate. + +Thu Aug 21 23:52:16 1997 John F. Carr + + * alias.c (find_base_value): Improve handling of PLUS, MINUS, and + LO_SUM. + (record_set): Handle LO_SUM like PLUS. + (init_alias_analysis): When following chains of base addresses, + do not stop on reaching a hard register. + +Thu Aug 21 20:17:37 1997 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump for new snapshot. + +Thu Aug 21 17:28:00 1997 Jim Wilson + + * alpha.h (ARCH_ASM_FILE_START): Define. + (ASM_FILE_START): Use ARCH_ASM_FILE_START. + * osf12.h, osf2or3.h (ARCH_ASM_FILE_START): Redefine to null string. + +Thu Aug 21 10:22:19 1997 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (install-common): Put gcov comment at start of line. + +Wed Aug 20 22:47:33 1997 Jeffrey A Law (law@cygnus.com) + + * alias.c (init_alias_analysis): When simplifying the reg_base_value + array, simplify entries for hard registers too. + +Wed Aug 20 12:35:47 1997 Dave Love + + * dwarf2.h (enum dwarf_call_frame_info): Remove trailing comma from + list. + +Wed Aug 20 11:58:33 1997 Jim Wilson + + * stmt.c (start_cleanup_deferal, end_cleanup_deferal): Test + block_stack before dereferencing it. + +Wed Aug 20 11:57:11 1997 Michael Meissner + + * rs6000.h (ISSUE_RATE): Define instead of MACHINE_issue_rate. + +Tue Aug 19 17:10:56 1997 Jason Merrill + + * cplus-dem.c: Add 'extern' to prepends_underscore. + +Tue Aug 19 09:34:57 1997 Jeffrey A Law (law@cygnus.com) + + * haifa-sched.c (ISSUE_RATE): Renamed from MACHINE_issue_rate. + (get_issue_rate): Delete. + * pa.h (ISSUE_RATE): Define. + + * configure.in: Turn on haifa by default for the PA. + * configure: Rebuilt. + * pa.c (override_options): Accept -mschedule=7200 option. + (pa_adjust_cost): No longer need to scale costs for newer + processors. + * pa.h (enum processor_type): Add PROCESSOR_7200. + * pa.md: Revamp scheduling parameters to work better with + haifa. Add scheduling parameters for the 7200. + + * haifa-sched.c (move_insn): Reemit notes for SCHED_GROUP_P + insns too. + (schedule_block): When adjusting basic_block_{head,end}, account + for movement of SCHED_GROUP_P insns too. + + * haifa-sched.c (debug_dependencies): Fix thinko. + + * Makefile.in (EXPECT, RUNTEST, RUNTESTFLAGS): Define. + (site.exp, check, check-g++, check-gcc): New targets. + + * haifa-sched.c: Make lots of variables static. + +Tue Aug 19 07:18:34 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * expr.h, real.h: Finish prototyping. + +Mon Aug 18 21:49:02 1997 Jim Wilson + + * reload.c (find_reloads): Add code to convert RELOAD_FOR_OPADDR_ADDR + reloads to RELOAD_FOR_OPERAND_ADDRESS reloads. + * reload1.c: Undo bugfix from Aug 11. + +Mon Aug 18 17:39:02 1997 Mike Meissner + + * configure.in ({powerpc,rs6000}*-*-*, --with-cpu): Remove single + quotes around the name. + * configure: Regenerate. + +Mon Aug 18 13:46:47 1997 Jim Wilson + + * Makefile.in (stmp-multilib-sub): Fix typo in last change. + +Thu Aug 7 10:33:13 1997 Manfred Hollstein + + * Makefile.in (sub-makes): Pass the current value of LANGUAGES down + to sub-makes to avoid building more passes than the user might have + requested on the command line. + +Sun Aug 17 15:42:17 1997 Dave Love (d.love@dl.ac.uk) + + * configure.in: Expurgate `broken_install' (install is + autoconfed). + + * configure.lang: Substitute autoconfed ${INSTALL} (not currently + relevant). + +Sat Aug 16 01:08:12 1997 Jeffrey A Law (law@cygnus.com) + + * loop.c (is_power_of_2, is_conditional_branch): Delete unused + functions and declarations. + (analyze_loop_iterations): Use condjump_p. + (insert_bct): Likewise. Use exact_log2. + +Fri Aug 15 23:48:32 1997 Jeffrey A Law (law@cygnus.com) + + * haifa-sched.c (find_post_sched_live): Call FREE_REG_SET as needed. + (schedule_region): Likewise. + (schedule_insns): Likewise. + + * PROJECTS: Update with Haifa stuff. + +Fri Aug 15 12:49:56 1997 Jeffrey A Law (law@cygnus.com) + + * version.c: Change the version string to look like: + egcs-2.90.00 970814 (gcc2-970802 experimental). + + * loop.c (is_conditional_branch): Make definition match declaration. + + * gcc.c: Take out experimental snapshot warning message. + +Fri Aug 15 13:43:39 1997 Michael Meissner + + * haifa-sched.c (debug_dependencies): Use GET_NOTE_INSN_NAME to + print out the names of the notes. Print out the name of the insn + that is not a note, and not an {,CALL_,JUMP_}INSN. + +Wed Aug 13 17:32:38 1997 Jason Merrill + + * expr.c (expand_expr, case TARGET_EXPR): Call mark_addressable + again for the slot after we give it RTL. + +Wed Aug 13 01:03:37 1997 Doug Evans + + * configure.in (haifa configury): Fix typo. + * configure: Regenerate. + +Tue Aug 12 10:20:36 1997 Jeffrey A Law (law@cygnus.com) + + * version.c: Bump version to "gcc-3.0.0 970802 experimental". + + * gcc.info*: Rebuilt. + + * COPYING.g77, README.g77: New files. + * real.c (ereal_unto_float, ereal_unto_double): New functions. + * real.h (ereal_unto_float, ereal_unto_double): Declare them. + (REAL_VALUE_UNTO_TARGET_DOUBLE, REAL_VALUE_UNTO_TARGET_SINGLE): Define. + +Mon Aug 11 14:50:55 1997 Jeffrey A Law (law@cygnus.com) + + * Integrate Haifa instruction scheduler. + * Makefile.in (ALL_CFLAGS): Add SCHED_CFLAGS. Prefix all references + to sched with $(SCHED_CFLAGS. + * configure.in: Handle --enable-haifa. + * configure: Rebuilt. + * flags.h: Add new flags for haifa instruction scheduler. + * genattrtab.c (expand_units): For haifa, don't subtract one + when computing blockage. + * toplev.h (flag_schedule_interblock): Haifa scheduler flag. + (flag_schedule_speculative): Ditto. + (flag_schedule_speculative_load): Ditto. + (flag_schedule_speculative_load_dangerous): Ditto. + (flag_schedule_reverse_before_reload): Ditto. + (flag_schedule_reverse_after_reload): Ditto. + (flag_branch_on_count_reg): Ditto. + (f_options): Add Haifa switches. + (main): Turn off some Haifa options if appropriate macro is + defined. Process Haifa switches. + * unroll.c (iteration_info): No longer static, since Haifa + scheduler uses it. + (unroll_loop): Inform HAIFA scheduler about loop unrolling factor. + * unroll.c (unroll_loop): Set loop_unroll_iter, loop_start_value. + * loop.h (loop_unroll_factor, loop_number): Add HAIFA decls. + * loop.h (loop_initial_value,loop_unroll_iter): New globals. + * loop.c (loop_optimize): If HAIFA is defined, allocate additional + storage for the Haifa scheduler. + (mark_loop_jump): If HAIFA defined, set LABEL_OUTSIDE_LOOP_P and + LABEL_NEXTREF. + (strength_reduce): If HAIFA and HAVE_decrement_and_branch_on_count + are defined, call analyze_loop_iterations and insert_bct to use + countdown loops. + (record_giv): Refine test for jumps out of loops if HAIFA is + defined. + (analyze_loop_iterations): New function to identify if we can use + a countdown loop. + (insert_bct): Insert countdown loop. + (instrument_loop_bct): Low level code to insert countdown loop. + (loop_number): Calculate UID of loop. + (indirect_jump_in_function_p): Return true if an indirect jump is + in the function. + (is_power_of_2): Return true if value is a power of 2. + (is_conditional_branch): Return true if insn is a conditional + jump. + (fix_bct_param): Process -fbct-{min,max}-N switches. + (check_bct_param): Return true if loop should be instrumented. + * loop.c (loop_initial_value,loop_unroll_iter): New globals. + (loop_optimize): Initialize. + (get_condition_for_loop): Ditto. + * loop.c (strength_reduce): Inside of code that uses #ifdef + HAVE_decrement_and_branch_on_count code, test it to make sure the + condition is true. + (instrument_loop_bct): Ditto. + * haifa-sched.c: New file. + + + * Integrate regmove pass. + * Makefile.in (OBJS): Add regmove.o + (regmove.o): Add dependencies. + * flow.c (find_use_as_address): No longer static. + * rtl.h (find_use_as_address): Declare. + * toplev.c (regmove_dump, flag_regmove): Define. + (f_options): Add -fregmove. + (regmove_dump_file, regmove_time): Define. + (fatal_insn): Close the regmove dump file. + (compile_file): Initialize regmove_time; open/close the regmove dump + file as needed. Print regmove time as needed. + (rest_of_compilation): Run regmove pass if requested, dump + RTL after regmove if requested. + (main): If -O2 or more, turn on regmove. Handle dump switches. + * regmove.c: New file. + +Mon Aug 11 14:15:02 1997 Jeffrey A Law (law@cygnus.com) + + * Integrate tlink patch from jason@cygnus.com + * gcc.c (SWITCH_TAKES_ARG): Add 'V', 'B' and 'b'. + (process_command): Increment n_switches for them. Don't discard + their args. Validate them. + (main): Escape " marks when creating COLLECT_GCC_OPTIONS. + From Rohan Lenard. + (process_command): Set include_prefixes from COMPILER_PATH. + (main): Set COLLECT_GCC_OPTIONS sooner. + * confiugre.in: Link ../ld/ld.new to collect-ld rather than real-ld. + * tlink.c, hash.c, hash.h: New files. + * Makefile.in (USE_COLLECT2): Always use collect2. + (collect2): Depend on and link in hash.o and tlink.o. + (tlink.o, hash.o): Add dependencies. + +Mon Aug 11 10:04:49 1997 Jeffrey A Law (law@cygnus.com) + + * Integrate alias analysis changes from jfc@mit.edu + * Makefile.in (OBJS): Add alias.o + (alias.o): Add dependencies. + * alias.c: New file. + * sched.c: Remove alias analysis code. It lives in alias.c now. + (sched_analyze_2): Add new arguments to true_dependence. + (schedule_insns): Always call init_alias_analysis. + * calls.c (expand_call): Note calls to malloc, calloc, and realloc; + mark return value from such functions as a pointer and keep track of + them for alias analysis. If a return value from a function is a + pointer, mark it as such. + * combine.c (distribute_notes): Handle REG_NOALIAS. + * cse.c (struct write_data): Delete. No longer needed. + (invalidate): Don't call set_nonvarying_address_components anymore. + Use true_dependence to decide if an entry should be removed from + the hash table. + (invalidate_memory): Remove WRITES argument, simplify appropriately. + Fix all callers. + (note_mem_written): Similarly for WRITE_PTR argument. + (invalidate_from_clobbers): Similarly for W argument. + (invalidate_for_call): Remove memory elements from the hash table. + (refers_to_mem_p, cse_rtx_addr_varies_p): Deleted. + (cse_rtx_varies_p): New function. Derived from old + cse_rtx_addr_varies_p. + (cse_insn): Remove WRITES_MEMORY and INIT variables and all references. + Don't call note_mem_written anymore. Stack pushes invalidate the stack + pointer if PUSH_ROUNDING is defined. No longer need to call + cse_rtx_addr_varies_p to decide if a MEM should be invalidated. + (skipped_writes_memory): Remove variable. + (invalidate_skipped_set): Simplify and wewrite to use invalidate_memory. + (invalidate_skipped_block): Simplify for new alias analysis code. + (cse_set_around_loop): Likewise. + (cse_main): Call init_alias_analysis. + * flags.h (flag_alias_check, flag_argument_noalias): Declare. + * toplev.c (flag_alias_check, flag_argument_noalias): Define. + (f_options): Add new alias checking arguments. + (main): Set flag_alias_check when optimizing. + * local_alloc (validate_equiv_mem_from_store): Add new arguments + to true_dependence. + (memref_referenced_p): Likewise. + * loop.c (NUM_STORES): Increase to 30. + (prescan_loop): Only non-constant calls set unknown_address_altered. + (invariant_p): Add new arguments to true_dependence. + (record_giv): Initialize unrolled and shared fields. + (emit_iv_add_mult): Call record_base_value as needed. + * loop.h (struct induction): Add unrolled and shared fields. + * unroll.c (unroll_loop): Call record_base_value as needed. + (copy_loop_body): Likewise. + (final_biv_value): Likewise. + (final_giv_value): Likewise. + (find_splittable_regs): Likewise. Only create one new pseudo + if we have multiple address GIVs that were combined with the same + dst_reg GIV. Note when a new register is created due to unrolling. + * rtl.c (reg_note_name): Add REG_NOALIAS. + * rtl.h (enum reg_note): Similarly. + (rtx_varies_p, may_trap_p, side_effects_p): Declare. + (volatile_refs_p, volatile_insn_p, remove_note): Likewise. + (note_stores, refers_to_regno_p, reg_overlap_mentioned_p): Likewise. + (true_dependence, read_dependence, anti_dependence): Likewise. + (output_dependence, init_alias_analysis, end_alias_analysis): Likewise. + (mark_user_reg, mark_reg_pointer): Likewise. + + + * Integrate reload bugfix from Wilon which enables the PA port + to bootstrap again. + * reload1.c (reload): Sum needs for both OPADDR_ADDR and + OPERAND_ADDRESS when computing how many registers an insn needs. + (reload_reg_free_p): OPADDR_ADDR and OPERAND_ADDRESS reloads do + conflict. + (reload_reg_free_before_p): Treat OPERAND_ADDRESS reloads just like + OPADDR_ADDR reload. + (reload_reg_reaches_end_p): For RELOAD_FOR_OPADDR_ADDR insns, registers + in reload_reg_use_in_op_addr do not reach the end. + do not reach the end. + (reloads_conflict): RELOAD_FOR_OPADDR_ADDR conflicts with + RELOAD_FOR_OPERAND_ADDRESS. + +Sun Aug 10 12:00:20 1997 Jeffrey A Law (law@cygnus.com) + + * egcs project officially starts. + +Local Variables: +add-log-time-format: current-time-string +End: diff --git a/gcc_arm/ChangeLog.Cygnus b/gcc_arm/ChangeLog.Cygnus new file mode 100755 index 0000000..212eb15 --- /dev/null +++ b/gcc_arm/ChangeLog.Cygnus @@ -0,0 +1,3393 @@ +Mon Oct 18 23:25:10 1999 Jonathan Larmour + + * config/arm/t-thumb-elf (EXTRA_MULTILIB_PARTS): Ensure crtbegin.o + and crtend.o are multilibbed. + +Wed Mar 10 19:56:20 1999 Jeff Johnston + + * config/d10v/d10v.h (LIB_SPEC): Added -lnosys to default libraries + to include stubs for OS routines not provided by newlib. + +1999-02-25 Jim Lemke + + * config/rs6000/sysv4.h: Add -mmpc860c0[=num] option. + * invoke.texi: Add -mmpc860c0[=num] option. + +Mon Mar 1 17:14:25 1999 Jim Wilson + + * flow.c (merge_blocks): Disable when flag_exceptions is true. + +Wed Feb 10 18:22:55 1999 Vladimir N. Makarov + + * config/rs6000/rs6000_output_load_toc_table: Fix the bug (comma + usage). + +Fri Feb 5 16:21:01 1999 Michael Meissner + + * system.h (abort): Add missing comma to error message so filename + is not part of the format string. + + * rs6000.md (movdf_hardfloat32): Add support for non offsetable + load of fp value into integer register support. + +Fri Feb 5 14:26:48 1999 Michael Meissner + + * config/rs6000/rs6000.h (TARGET_OPTIONS): Add -mbranch-cost=n + support. + (BRANCH_COST): Ditto. + (rs6000_branch_cost{,_string}): New externals for altering branch + costs. + + * config/rs6000/rs6000.c (rs6000_branch_cost{,_string}): New + externals for altering branch costs. + (rs6000_override_options): Add support for -mbranch-cost=n. + + * invoke.texi (-mbranch-cost=n): New option description. + +Fri Feb 5 13:28:55 1999 Vladimir N. Makarov + + * invoke.texi (-m{no-}sched-{epilog,prolog}): New options + documentations + + * config/rs6000/rs6000.md (prologue, epilogue, + move{si,di}_{from,to}_cr, load{si,di}_svr4_relocatable_toc, + loadsi_svr4_toc, load{si,di}_nonsvr4_toc): New define_expand and + define_insn for scheduling prologue/epilogue. + + * config/rs6000/rs6000.h (MASK_SCHED_PROLOG, + MASK_SCHED_EPILOG, TARGET_SCHED_PROLOG, TARGET_SCHED_EPILOG): + New macros for new options. + (TARGET_SWITCHES): Add new options description for scheduling + prologue/epilogue. + (rs6000_expand_prologue, rs6000_expand_epilogue): New + functions defintion. + + * config/rs6000/rs6000.c (rs6000_expand_prologue, + rs6000_expand_epilogue, rs6000_output_prolog, + rs6000_output_epilog): New functions for scheduling + prologue/epilogue. + + (rs6000_output_load_toc_table, rs6000_allocate_stack_space, + output_prolog, output_epilog): New cygnus local function + implementations. + +Fri Feb 5 13:12:13 1999 Vladimir N. Makarov + + * Makefile.in (check-consistency): New makefile entry for + GCC compilers consistency testing. + +Thu Feb 4 10:08:11 1999 Jeffrey A Law (law@cygnus.com) + + * mn10300.h (CPP_SPEC): Define __AM33__ when in am33 mode. + +Wed Feb 3 13:22:11 1999 Jeffrey A Law (law@cygnus.com) + + * pa.md (height reduction patterns): Add missing earlyclobbers for + case where the pattern is not split before regalloc. + +Tue Feb 2 20:29:34 1999 Catherine Moore + + * configure.in (arm-*-oabi): Support. + (thumb-*-oabi): Support. + * configure: Regenerate. + * config/arm/telf-oabi.h: New file. + * config/arm/telf.h (ASM_OUTPUT_DWARF2_ADDR_CONST): + Don't use user_label_prefix. + * config/arm/thumb.h (ASM_SPEC): Conditionally define. + * config/arm/unknown-elf-oabi.h: New file. + +Mon Feb 1 15:05:57 1999 Dave Brolley + + * cppfiles.c (find_include_file): Use open_include_file_name instead + of calling open directly. + +Mon Feb 1 11:39:25 1999 Nick Clifton + + * config/fr30/fr30.md: Add attribute 'delay_type'. + Add delay slot specification. + Add delay_type attributes to insns with non default type. + Enable multiplication patterns: mulsidi3 umulsidi3 mulsihi3 + umulsihi3 mulsi3 + Add delayed branch print operands. + + * config/fr30/fr30.c (fr30_print_operand): Add codes '#' and 'p' + to handle delayed branched and hi/lo register pair respectively. + + * config/fr30/fr30.h (PRINT_OPERAND_PUNCT_VALID_P): Define for + '#'. + (DWARF_LINE_MIN_INSTR_LENGTH): Set to 2. + + * config/fr30/t-fr30 (LIB1ASMFUNCS): Remove _mulsi3. + * config/fr30/lib1funcs.asm: Remove mulsi3 function. + +1999-01-31 Michael Meissner + + * config/rs6000/t-vxworks: New file to suppress building libc + routines under VxWorks. + + * configure (powerpcle-wrs-vxworks): Add new configuration. + (powerpc{,le}-*-vxworks*): Include rs6000/t-vxworks. + + * config/rs6000/vxppc.h ({CPP,LIB,LINK,STARTFILE,ENDFILE}_SPEC, + CPP_PREDEFINES): Remove definitions. + ({CPP_OS_DEFAULT,LIB_DEFAULT,STARTFILE_DEFAULT,ENDFILE_DEFAULT, + LINK_START_DEFAULT,LINK_OS_DEFAULT,CPP_ENDIAN_BIG, + CPP_ENDIAN_LITTLE}_SPEC, CPP_PREDEFINES): Define. + + * config/rs6000/vxppcle.h: New little endian VxWorks support file. + + * invoke.texi (-mvxworks): Document. + + * config/rs6000/sysv4.h (CPP_OS_VXWORKS_SPEC): Define CPU_FAMILY + as PPC and define CPU. + (TARGET_SWITCHES): Add -mvxworks switch to control whether or not + the target is VxWorks. If EXTRA_SUBTARGET_SWITCHES is defined, it + provides additional switches from a subtarget that includes + sysv4.h. + (SUBTARGET_EXTRA_SPECS, *_SPEC): Add -mvxwork support. + (USER_LABEL_PREFIX): Undef before including svr4.h. + (ASM_DECLARE_FUNCTION_NAME): Use asm_fprintf to get the current + user prefix in front of the name. + (ASM_OUTPUT_INTERNAL_LABEL_PREFIX): Use asm_fprintf to get the + current internal label prefix in front of the name. + (ASM_OUTPUT_LABELREF): Ditto. + ({USER_LABEL,LOCAL_LABEL,REGISTER,IMMEDIATE}_PREFIX): Define. + (SUBTARGET_OVERRIDE_OPTIONS): Don't set rs6000_wchar_type{,_size}. + (RELATIVE_PREFIX_NOT_LINKDIR): Disable AIX specific support. + (WCHAR_*): Set wchar_t to be an int as per standard, not unsigned + short. + (CPP_SYSV_SPEC): Define _SOFT_FLOAT on machines that use software + floating point. + (CC1_SPEC, LINK_TARGET_SPEC): Fix typos. + + * config/rs6000/eabi-ci.asm (___{C,D}TOR_LIST__): Add + -fleading-underscore support. + + * config/rs6000/eabi-cn.asm (___{C,D}TOR_END__): Ditto. + + * config/rs6000/eabi.asm (__eabi): Don't use FUNC_START/FUNC_END, + always use __eabi, even for libraries compiled with + -fleading-underscore. + + * ginclude/ppc-asm.h (FUNC_START): Make sure label for function + start uses FUNC_NAME. + (FUNC_{START,END,NAME}): Prepend the macro __USER_LABEL_PREFIX__ + into function names. + + * config/rs6000/t-ppcgas (MULTILIB_{OPTIONS,DIRNAMES}): Add new + multilibs that use -fleading-underscore. + + * config/rs6000/rs6000.c (rs6000_wchar_type{,_size}): Remove, + variables are no longer used. + + * config/rs6000/sysv4le.h (LINK_TARGET_SPEC): Explicitly pass + -oformat elf32-powerpcle if -mcall-i960-old. + +1999-01-31 Michael Meissner + + * config/rs6000/sysv4.h (SUBTARGET_OVERRIDE_OPTIONS): Add + support for -mcall-i960-old. The -mcall-i960-old option now sets + -mno-bit-word. If -mcall-i960-old, make wchar_t be an int. + (WCHAR_TYPE{,_SIZE}): If -mcall-i960-old, make wchar_t be an int. + (CPP_SYSV_SPEC): Ditto + (NO_BUILTIN_WCHAR_TYPE): Define, wchar_t is a variable type. + (rs6000_wchar_type{,_size}): New globals to hold type string and + size for wchar_t. + (ASM_SPEC): If -mcall-i960-old, pass -mlittle. + (TARGET_FLAGS): Add -m{,no-}bit-word to control whether bitfields + can cross word boundaries or not, independent of whether they + cause the structure to take on the base type's alignment. + (BITFIELD_NBYTES_LIMITED): Depend on whether -m{,no-}bit-word was + passed. + + * config/rs6000/rs6000.c (rs6000_wchar_type{,_size}): Provide + externals if NO_BUILTIN_WCHAR_TYPE is defined. + + * cccp.c (toplevel): If NO_BUILTIN_WCHAR_TYPE is defined, do not + define wide char support. + (main): Ditto. + (special_symbol): Ditto. + (initialize_builtins): Ditto. + + * cpplib.c (toplevel): If NO_BUILTIN_WCHAR_TYPE is defined, do not + define wide char support. + (special_symbol): Ditto. + (initialize_builtins): Ditto. + + * config/rs6000/t-ppcgas (MULTILIB_*): Add multilib for + -mcall-i960-old. + + * invoke.texi (-mcall-960-old, -m(no-)bit-word): New options + description. + +Sat Jan 30 19:40:16 1999 Jim Wilson + + * fold-const.c (fold): Don't pass MINUS_EXPR to + reduce_expression_tree_depth. + +Thu Jan 28 01:08:31 1999 J"orn Rennecke + + * regmove.c (find_related): Check if a register belonging to a set + of related values is clobbered in an insn where it is also used. + (optimize_related_values_1): Handle REG_UNUSED notes. + (optimize_related_values): Likewise. + +Tue Jan 26 12:42:06 1999 Jim Wilson + + * flow.c (merge_blocks): Don't call squeeze_notes if start == end. + +1999-01-25 Nick Clifton + + * config/generic/generic.md: Add description of backend's + responsibility to fill unfilled delay slots with NOPs. + +Fri Jan 22 07:50:33 1999 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (DRIVER_DEFINES): Fix accidental breakage of + TOOLDIR_BASE_PREFIX. + +Thu Jan 21 18:11:27 1999 Richard Henderson + + * expr.c (emit_push_insn): Fix typo. + +Thu Jan 21 02:54:27 1999 Jeffrey A Law (law@cygnus.com) + + * lcm.c (pre_lcm, pre_rev_lcm): Update comments to reflect reality. + + * flow.c (merge_blocks): When searching for EH notes in a block, + quit when we hit the end of the block. Don't merge with the + exit block if the predecessor has an EH note. Also leave any + CODE_LABEL in its original position when merging with the exit + block. + +Wed Jan 20 15:30:00 1999 Dave Brolley + + * configure.in: Turn on --enable-c-mchar by default. + * configure: Regenerate. + +Tue Jan 19 05:40:26 1999 Jeffrey A Law (law@cygnus.com) + + * flow.c (merge_blocks): Don't merge a block with the epilogue if + the block consists of just a JUMP_INSN. + + * flow.c (merge_blocks): Allow limited merging with the last basic + block. + + * Makefile.in (libgcc2.a, LIB2FUNCS_EH): Remove -O0. Resyncs code + with net version. + +Sat Jan 16 01:06:16 1999 Jeffrey A Law (law@cygnus.com) + + * gcse.c (mem_set_in_block): Deleted. + (mem_first_set, mem_last_set): Deleted. + (modify_mem_list): New variable. + (mems_conflict_for_gcse_p): New function. + (gcse_mems_conflict_p, gcse_mem_operand): New variables. + (load_killed_in_block_p): New function. + (oprs_unchanged_p): Use load_killed_in_block_p. + (oprs_not_set_p, expr_killed_p): Likewise. + (compute_transp): Do not pessimize memory references. + (record_last_mem_set_info): Keep a list of all instructions which + can modify memory for each basic block. + (mark_call, mark_set, mark_clobber): Use record_last_mem_set_info. + (gcse_main): Initialize & finalize alias analysis. + (alloc_gcse_mem): Allocate space for modify_mem_list array. + (free_gcse_mem): Free the modify_mem_list array. + (compute_hash_table): Clear modify_mem_list. + (reset_opr_set_tables): Likewise. + + * gcse.c (invalidate_nonnull_info): Remove unused variables. + + * pa.h (EXTRA_CONSTRAINT): Handle 'S'. + + * pa.md (fused multiply): Add variants which reduce height for the + fused multiply, but which still generate 2 insns. + (fnegabs): Similarly. + + * pa.md (return, return_internal): Use bve for PA2.0. + + * pa.md (subsi3): Turn into an expander. Create two anonymous + patterns. One for PA2.0 one for PA1.x. Use mtsarcm for PA2.0. + +1999-01-15 Brendan Kehoe + + * system.h (abort): Adjust where to report bugs as a cygnus-local + change. + +Fri Jan 15 10:40:37 1999 Nick Clifton + + * configure.in: Remove inclusion of libgloss.h from fr30 target as + it is no longer needed. + * configure: Regenerate. + +1999-01-14 Vladimir N. Makarov + + * config/i960/i960.h (TARGET_FLAG_MOVE_COALESCENCE, + TARGET_MOVE_COALESCENCE, and TARGET_SWITCHES): Definitions for new + options `-mmove-coalescence' and `-mno-move-coalescence'. + (INIT_EXPANDERS, init_expanders): Definitions for i960 insn + expanders. + + * config/i960/i960.c (i960_const0_r12r13, i960_const0_r12r15): New + static variables for making move coalescence. + (machine_function): New structure describing machine status for + expanders. + (i960_save_machine_status, i960_restore_machine_status, + i960_init_expanders): New functions for work with machine status. + (emit_move_sequence, i960_output_move_double_zero, + i960_output_move_quad_zero): New code for coalescing move + instructions. + + * invoke.texi (-mmove-coalescence, -mno-move-coalescence): New + options description. + +1999-01-13 Nick Clifton + + * ginclude/va-fr30.h (va_arg): Handle structures specially. + (va_aggregate_p): New macro: Detect structures based on their + type. + + * config/fr30/fr30.h: (MUST_PASS_IN_STACK): Define: All + structures must now be passed on the stack. + (DEFAULT_PCC_STRUCT_RETUR): Define. + +Mon Jan 11 11:42:07 1999 Jeffrey A Law (law@cygnus.com) + + * pa.md: Add real PA8000 scheduling information. + + * pa.c (adjust_cost): No cost adjustments needed for PA8000. + (following_call): Always return zero for the PA8000. + + * pa.h (REG_ALLOC_ORDER): Rework. + +1999-01-11 Nick Clifton + + * configure.in: Add extra_parts for FR30 target to build C++ + contructor and destructor code. + * configure: Regenerate. + * config/fr30/t-fr30: Add rules to build crti.o and crtn.o. + * config/fr30/fr30.h (STARTFILE_SPEC): Add crti.o and crtbegin.o. + (ENDFILE_SPEC): Add crtend.o and crtn.o. + * config/fr30/crti.asm: New file: Stack frame creation code for + .init amd .fini sections. + * config/fr30/crtn.asm: New file: Stack frame removal code for + .init and .fini sections. + +Sun Jan 10 16:58:23 1999 Jeffrey A Law (law@cygnus.com) + + * pa.h (HAVE_PRE_INCREMENT): Disable on the PA8000, except for + prologue/epilogue sequences. + (HAVE_PRE_DECREMENT, HAVE_POST_INCREMENT): Likewise. + HAVE_POST_DECREMENT): Likewise. + + * pa-hpux10.h, pa-hpux11.h (ASM_FILE_START): Fix minor logic error. + + * pa.h (ISSUE_RATE): Refine for the PA8000. + +Thu Dec 31 16:03:59 1998 Michael Meissner + + * d10v.c ({gpr,accum}_operand): Rewrite December 17th change to + work better during the reload phase if we have run out of + registers. + (reg_or_0_operand): Call gpr_operand for non-integer constants. + (arith16_operand): Ditto. + (arith_4bit_operand): Ditto. + (arith_nonnegative_operand): Ditto. + (arith32_operand): Ditto. + (arith64_operand): Ditto. + (arith_lower0_operand): Ditto. + +1998-12-24 Gavin Romig-Koch + + * config/mips/mips.c (override_options): For TARGET_MIPS16 force + mips_align_loops to 0. + +1998-12-23 Nick Clifton + + * config/fr30/fr30.h (FUNCTION_PROFILER): Define. + + * config/arm/arm.c (arm_asm_output_label): Use variable + 'user_label_prefix' rather than macro USER_LABEL_PREFIX. + + * config/arm/t-thumb-elf: Add multilib option for leading + underscores. + + * config/arm/telf.h (USER_LABEL_PREFIX): Default to no leading + underscore. + (ASM_OUTPUT_DWARF2_ADDR_CONST): Use variable 'user_label_prefix' + rather than macro USER_LABEL_PREFIX. + +Wed Dec 23 10:03:26 1998 Michael Tiemann + + * config/generic/generic.h: Remove space before paren in + LOAD_EXTEND_OP macro. + +1998-12-18 Nick Clifton + + * config/generic/generic.md: Remove contraints from the + define_expand versions of negsi and one_cmpl. + +Fri Dec 18 12:09:17 1998 Nick Clifton + + * config/fr30/fr30.md: Fix define_expands that were using + constraints to work without constraints, since they are not + supported. + +1998-12-18 Nick Clifton + + * config/fr30/lib1funcs.asm: Only use 32 division operations, not 33. + +1998-12-17 Nick Clifton + + * config/fr30/lib1funcs.asm: Use macro to generate body of divide + and modulo functions. + +1998-12-17 Michael Meissner + + * d10v.c ({gpr,accum}_operand): Always check whether a hard + register is valid, instead of just passing the buck to + register_operand before the reload pass. + +1998-12-17 Gavin Romig-Koch + + * config/mips/abi64.h (LONG_MAX_SPEC): Handle -mabi=eabi. + +1998-12-16 Nick Clifton + + * ginclude/va-fr30.h (va_arg): Fix definition to work with small + types and irregularly sized types. + + * config/fr30/fr30.h (FRAME_POINTER_REQUIRED): Use a frame pointer + for varags functions. + (FUNCTION_ARGS): Also check MUST_PASS_IN_STACK(). + (FUNCTION_ARGS_PASS_BY_REFERENCE): Define. + + * config/fr30/fr30.c (fr30_num_arg_regs): Return 0 if the type + satisifies MUST_PASS_IN_STACK(). + + * config/fr30/fr30.md (enter_func): Fix pattern to match real + behaviour of the insn. + +Tue Dec 15 14:09:40 1998 Nick Clifton + + * config/generic/generic.md: Add comments for required patterns + plus how to use a fixed condition code register. + +1998-12-15 Gavin Romig-Koch + + * config/mips/mips.h (GAS_ASM_SPEC): Pass mabi to gas. + (ABI_GAS_ASM_SPEC,abi_gas_asm_spec): New. + (EXTRA_SPECS): Added ABI_GAS_ASM_SPEC,abi_gas_asm_spec. + +Mon Dec 14 19:22:58 1998 Jim Wilson + + * d30v/d30v.c (move_input_operand, move_output_operand): Accept + ADDRESSOF as valid memory operand address. + +1998-12-14 Nick Clifton + + * config/fr30/fr30.c (print_operand): Fix LTU and GEU opcodes. + (print_operand): Add 'A' operator to print a signed byte value as + an unsigned byte value. + (fr30_notice_update_cc): Function removed. + + * config/fr30/fr30.h (TRAMPOLINE_TEMPLATE): Define. + (TRAMPOLINE_SIZE): Define. + (INITIALIZE_TRAMPOLINE): Define. + (NOTICE_UPDATE_CC): Undefine. + + * config/fr30/fr30.md: Switch over from using cc0 to using reg 16 + as a fixed condition code register. + Remove the "cc" attribute. + (movqi_internal): Use 'A' operator to get an unsigned version of a + signed byte value. + +Mon Dec 14 17:08:17 1998 Jim Wilson + + * regmove.c (REL_USE_HASH): Use unsigned HOST_WIDE_INT instead of + unsigned. + +1998-12-13 Nick Clifton + + * configure.in: Add inclusion of libgloss.h + + * config/generic/generic.md (movsi_internal): Improve defintion to + include multiple alternatives and add comment explaining why this + is desireable. + + * config/fr30/fr30.h (STARTING_FRAME_OFFSET): Change value to 0. + + * config/fr30/fr30.md (movqi_internal): Accept any integer value, + not just QI values. + (call): Only allows MEMs in REGs. + + * config/fr30/fr30.c (fr30_function_args_partial_nregs): Fix to + work properly. + +1998-12-12 Nick Clifton + + * config/fr30/lib1funcs.asm: Fix divide routines. + * config/fr30/fr30.h: Rework frame pointer elimination. + * config/fr30/fr30.c: Rework frame pointer elimination. + * config/fr30/fr30.md: Rework use of cc0. + +1998-12-11 Nick Clifton + + * config/generic/generic.md: Do not use memory_operand() to test + for memory references when performing a define_expand() as it will + miss invalid memory constructs. + + * config/fr30/fr30.md: Force MEMs for Qi and HI mode moves to be + loaded into a reg. + Check peephole conversions of push and pop sequences to make sure + that the registers are in ascending order. + + * config/fr30/fr30.c (fr30_check_multiple_regs): New function - + Check registers are in ascending order. + + * config/fr30/fr30.h (ENDFILE_SPEC): Add link with simulator library. + Add prototype for fr30_check_multiple_regs(). + + * config/fr30/lib1funcs.asm: Basic implemenation of divide and + modulo funcitons. + +1998-12-10 Nick Clifton + + * config/fr30/fr30.md: Add pattern for "enter" insn. + * config/fr30/fr30.c: Use enter insns as part of function + prologue. + + * config/generic/generic.c (generic_setup_incoming_varargs): New + stub function. + * config/generic/generic.h: (SETUP_INCOMING_VARARGS): Define. + + * config/fr30/t-fr30: Remove _negsi2 and _one_cmplsi2 functions. + * config/fr30/lib1funcs.asm: Remove stubs for negsi2 and + one_cmplsi2. Make other stubs generate an abort. + + * config/fr30/fr30.h: Create a new fake hard register for the + argument pointer. + (INITIAL_ELIMINATION_OFFSET): Fix to cope with Fr30 frame layout. + (SETUP_INCOMING_VARARGS): Define to call fr30_steup_incoming_varargs(). + (STRICT_ARGUMENT_NAMING); Define as false. + (PREDICATE_CODES): Add low_register_operand(). + + * config/fr30/fr30.md: Add peephole for va_arg() load insns. Not + working yet. + Add peepholes for pushing low registers. + Add patterns for: negsi2 and one_cmplsi2 + Add grunge reload pattern for computing stack addresses. + + * config/fr30/fr30.c: Improve stack layout comment. + (MUST_SAVE_FRAME_POINTER): Also save FP if frame_pointer_needed is + true. + (fr30_expand_prologue): Push arguments into pretend argument area. + (fr30_setup_incoming_varags): New function: compute size of + pretend argument area. + (low_register_operand): New predicate: Return true if argument is + a hard register in the range 0 to 7. + + * Makefile.in: Export va-fr30.h to gcc's include directory. + * ginclude/varargs.h: Include va-fr30.h if __fr320__ is defined. + * ginclude/stdarg.h: Include va-fr30.h if __fr320__ is defined. + * ginclude/va-fr30.h: Varargs implemenation for the FR30. + + * config/arm/arm.h (TARGET_OPTIONS): Fixup egcs merge problem. + +1998-12-08 Nick Clifton + + * config/fr30/fr30.md: Add missing (MEM:SI ...) around memory + references! + (reload_frame_pointer_add): New pattern to cope with implicit + assumption built into reload. + (stack_pointer_store, frame_pointer_store): swap order of operands. + + * config/fr30/fr30.c (fr30_expand_epilogue): Pop frame pointer if + it was pushed during the prologue. + +Sun Dec 6 03:40:07 1998 Jeffrey A Law (law@cygnus.com) + + * fold-const.c (reduce_expression_tree_depth): Set TREE_CONSTANT on + new expressions we create, if applicable. + +Fri Dec 4 23:10:36 1998 Jeffrey A Law (law@cygnus.com) + + * fold-const.c (fold): Call reduce_expression_tree_depth for + simple associative operators. + (reduce_expression_tree_depth): New function. + +1998-12-04 Nick Clifton + + * config/fr30/fr30.md: Improve support for small memory model. + + * Fixed branch length calculations. + +1998-12-03 Nick Clifton + + * config/fr30/fr30.h: Add -msmall-model command line switch. + + Define r0 as a fixed register for use by the .md patterns. + + Undefine MACHINE_DEPENDENT_REORD. + + * config/fr30/fr30.md: Use r0 as a scratch register for branches and + jumps. + + Use LDI:20 instead of LDI:32 to load addresses if TARGET_SMALL_MODEL + is enabled. + + * config/fr30/fr30.c: Delete fr30_reorg() function. + +1998-12-02 Nick Clifton + + * config/fr30/fr30.h: Undefine STARTFILE_SPEC and ENDFILE_SPEC. + * config/fr30/fr30.md: Enable the generation of the LDI:20 + instruction. + +Wed Dec 2 01:18:53 1998 Richard Henderson + + * flow.c (merge_blocks): Call squeeze_notes. + +Tue Dec 1 15:29:17 1998 Nick Clifton + + * config/fr30/fr30.md (movsi_register_store): Allow ADDRESSOF + stores. + (branch_true, branch_false): Use comparision_operator to ensure + that an operator is actually present in the RTL. + (jump, branch): Reduce distance calculation to cope with + inaccuracies in insn length calculations. + + * config/fr30/fr30.c (fr30_print_operand): Add 'R' operand to + print a MEM as if it were a REG. + Add folding to the file. + + * config/fr30/fr30.h: Add folding to the file. + +Tue Dec 1 11:59:12 1998 Jeffrey A Law (law@cygnus.com) + + * mips.md (trap_if): Another typo in !GENERATE_BRANCHLIKELY case. + +Mon Nov 30 17:05:59 1998 Jeffrey A Law (law@cygnus.com) + + * mips.md (trap_if): Fix typo in !GENERATE_BRANCHLIKELY case. + +Fri Nov 27 18:40:10 1998 J"orn Rennecke + + * sh.md (mulsidi3_i, umulsidi3_i): Make rtl describe operation + correctly independent of endianness. + (mulsidi3, umulsidi3): Now define_insn. Hide details that + confuse the optimizers. + (mulsidi3+1, umulsidi3+1): New define_split. + +1998-11-25 Nick Clifton + + * config/fr30/t-fr30 (LIB1ASMFUNCS): Add _one_cmplsi2. + + * config/fr30/lib1funcs.asm (__one_cmplsi2): New function stub. + + * config/fr30/fr30.h (MACHINE_DEPENDENT_REORG): Define and set to + fr30_reorg(). + + * config/fr30/fr30.c (fr30_reorg): New function - detect illegal + jump insns created by jump2 pass of gcc and correct them. + +Thu Nov 26 00:49:47 1998 J"orn Rennecke + + * sh.md (udivsi3_i1, divsi3_i1, umulhisi3_i, mulhisi3_i): Name. + (smulsi3_highpart_i): Name. + (udivsi3): Wrap emitted insns in REG_LIBCALL / REG_RETVAL notes. + (divsi3, mulhisi3, umulhisi3, mulsidi3, umulsidi3): Likewise. + (smulsi3_highpart, umulsi3_highpart): Likewise. + +Tue Nov 24 17:58:29 1998 Nick Clifton + + * config/fr30/fr30.md (jump): Support jumps to code outside +/- + 255 byte range. + +Tue Nov 24 14:03:17 1998 Nick Clifton + + * config/arm/arm.h (TARGET_OPTIONS): Fix merge problem. + +Tue Nov 24 00:34:17 1998 Jeffrey A Law (law@cygnus.com) + + * gcse.c (hoist_expr_reaches_here_p): Make sure to check all paths. + +Mon Nov 23 17:24:24 1998 Nick Clifton + + * config/v850/v850.c (override_options): Use tilde, not minus to + invert a bitfield! + +Sun Nov 22 20:33:20 1998 Jeffrey A Law (law@cygnus.com) + + * mips.md (DImode div and mod insns):Fix typos. + + * z8k.c (struct option): Add new "description field". + + * z8k.h (EXTRA_CONSTRAINT): Do not call abort. + (REG_OK_FOR_INDEX_P): Define with a value. + (OPTIMIZATION_OPTIONS): Add new parameter. + + * mips.md (moddi3): Fix typo. + +Fri Nov 20 14:51:42 1998 Nick Clifton + + * config/fr30/fr30.h: Make MDL and MDH be fixed until the multiply + patterns can be fixed. + + * config/fr30/fr30.c (sp_displacement_operand): Fix range to be + 0 -> 60 not 0 -> 64. + Add %b and %B output operand operators to generate condition + codes. + + * config/fr30/fr30.md: Fix branch patterns to use correct + condition mnemonics. + Rewrite conditional branches to support both long branches and + short branches. + + * config/fr30/t-fr30: Define mutlipy and divide functions for + libgcc1-asm.a + + * config/fr30/lib1funcs.asm: Assembler code for multiply and + divide functions. + +Thu Nov 19 13:33:07 1998 Nick Clifton + + * config/arm/pe.h: Define USER_LABEL_PREFIX as "_" + +Wed Nov 18 14:40:34 1998 Jim Wilson + + * configure.in: Add configury for mips-lsi-elf. + * configure: Regenerate. + * config/mips/t-lsi: New file. + + * range.c (live_range): Fix size arg to insn_ruid bzero call. + Check INSN_UID before storing into insn_ruid array. + +Wed Nov 18 10:57:49 1998 Nick Clifton + + * config/v850/v850.md: Fix define_split for sasf insns, so that it + will not generate bad code if the source and destination registers + are the same. + +Mon Nov 16 09:46:46 1998 Nick Clifton + + * config/d10v/d10v.c (print_operand_memory_reference): Surround + user symbols with parentheses in order to distinguish them from + register names. + + * config/generic/generic.md (movdf, movdf_internal): Commented out + these patterns since they are optional. + +Fri Nov 13 10:14:04 1998 J"orn Rennecke + + * regmove.c (optimize_related_values_1): Reject optimization if + offset for rel_base_reg_user would be to large. + +Fri Nov 13 04:36:06 1998 J"orn Rennecke + + * regmove.c (rel_record_mem): Don't do anything if the register + already has an invalidate_luid. + +Thu Nov 12 16:44:23 1998 Nick Clifton + + * config/generic/generic.md: Fix comment describing epilogue + pattern. + + * config/generic/generic.h: Add required definitions of + ASM_OUTPUT_CHAR, ASM_OUTPUT_SHORT and ASM_OUTPUT_INT. + +Thu Nov 12 23:02:32 1998 J"orn Rennecke + + * regmove.c (invalidate_related): Don't do anything if the register + already has an invalidate_luid. + (optimize_related_values): Don't update death field if + invalidate_luid field is set. + +Sat Oct 31 18:10:40 1998 Jeffrey A Law (law@cygnus.com) + + * mn10300.c (secondary_reload_class): No secondary register is needed + when copying sp+X into any of extended registers. + +Fri Oct 30 14:51:26 1998 Jeffrey A Law (law@cygnus.com) + + * configure.in (languages): Add missing ";;" in case statement. + +Thu Oct 29 19:08:12 1998 Jim Wilson + + * d10v/d10v.c (d10v_split_logical_op): If reload_completed, create + REGs instead of SUBREGS. + +Wed Oct 28 23:05:17 1998 Jeffrey A Law (law@cygnus.com) + + * invoke.texi: Add new alignment options for MIPS targets. + * tm.texi (FUNCTION_BOUNDARY_MAX_SKIP): Document new target macro. + * varasm.c (FUNCTION_BOUNDARY_MAX_SKIP): Provide a default value. + (assemble_start_function): Use ASM_OUTPUT_MAX_SKIP_ALIGN if defined. + * mips.c: Add new variables for alignment and maximum skip support. + (override_options): Handle alignment and maximum skip arguments. + * mips.h (SUBTARGET_TARGET_OPTIONS): Add new alignment and maximum + skip options. + (FUNCTION_BOUNDARY, LOOP_ALIGN, LABEL_ALIGN_AFTER_BARRIER): Use + alignment and maximum skip values computed in override_options. + (FUNCTION_BOUNDARY_MAX_SKIP): Define. + (ASM_OUTPUT_MAX_SKIP_ALIGN): Define. + +Wed Oct 28 15:29:56 1998 Jim Wilson + + * c-common.c (c_get_alias_set): Handle ARRAY_REF of union field. + +Tue Oct 27 17:02:21 1998 Nick Clifton + + * config/generic/generic.md: Commented out some unecessary patterns. + +Tue Oct 27 15:09:42 1998 Nick Clifton (nickc@cygnus.com) + + Merge in arm-elf related changes from EGCS: + + * configure.in: Add arm-*-linux-gnu, armv2-*-linux and arm-*-elf + targets. + + * configure: Regenerated. + + * config/arm/aout.h: Add default definitions of REGISTER_PREFIX, + USER_LABEL_PREFIX and LOCAL_LABEL_PREFIX. Make other macro + definitions conditional on their not having been already defined. + + * config/arm/lin1funcs.asm: Add ELF only macros to generate .size + and .type directives, and add "(PLT)" qualification to function + calls. + + * config/arm/linux.h: Deleted. This file is now superceeded by + either linux-elf.h or linux-aout.h. + + * config/arm/linux-gas.h: Define `inhibit_libc' if cross-compiling. + (CLEAR_INSN_CACHE): New macro, currently disabled (awaiting kernel + support). + Move definitions from old linux.h file here. + + * config/arm/elf.h: Now contains only generic ARM/ELF support. + + * config/arm/linux-aout.h: Support for Linux with a.out. + + * config/arm/linux-elf.h: New file. Support for Linux with ELF. + + * config/arm/linux-elf26.h: New file. Support for Linux with ELF + using the 26bit APCS. + + * config/arm/unknown-elf.h: New file. Support for OS'es other + than Linux with ELF. + + * config/arm/coff.h: Include aout.h for basic assembler macros. + + * config/arm/arm.h: Make macro definitions conditional on their + not having been already defined. + +Thu Oct 22 16:28:42 1998 Jeffrey A Law (law@cygnus.com) + + * reload1.c reload.c reload.h: Install Bernd's reload patches on + this branch for testing. + +Wed Oct 21 15:14:35 1998 Nick Clifton + + * config/generic/t-generic: Add definitions of CROSS_LIBGCC1 and + LIB2FUNCS_EXTRA. + Add (commented out) MULTILIB support. + + * config/generic/generic.c (generic_compute_frame_size): New function stub. + (generic_print_operand_address): New function stub. + (generic_print_operand): New function stub. + + * config/generic/generic.h: Add forward declarations of structure types + for use in exported function prototypes. + Remove *note constructs. + Document --help strings. + Fix conflicts between names of args to macros and references to those + names in the accompanying text. + REG_CLASS_CONTENTS: Define ALL_REGS class in terms of FIRST_PSEUDO_REGISTER. + Uncomment definitions which must be present oin order for cc1 to build. + RETURN_VALUE_REGNUM: New register macro - the number of a register + that holds a scalar function's return value. + +Wed Oct 21 11:43:46 1998 Nick Clifton + + * config/v850/v850ea.h (MASK_US_BIT_SET): Change value to 0x1000 + to avoid clash with MASK_NO_APP_REGS. + (MASK_US_BIT_SET): Change value to 0x2000 to avoid clash with + MASK_NO_DISABLE_CALLT. + + * config/v850/v850.c (construct_dispose_instruction): Obey setting + of TARGET_DISABLE_CALLT. + (construct_prepare_instruction): Obey setting of TARGET_DISABLE_CALLT. + +Mon Oct 19 14:31:56 1998 Nick Clifton + + * configure.in: Add FR30 target. + * configure: Add FR30 target. + * config.sub: Add FR30 target. + * config/fr30: New directory. + * config/fr30/fr30.c: New target specific C source. + * config/fr30/fr30.h: New target specific header file. + * config/fr30/fr30.md: New target specific machine description. + * config/fr30/xm-fr30.h: New target specific cross make header. + * config/fr30/t-fr30: New target specific makefile fragment. + + * config/m32r/m32r.h (TARGET_SWITCHES, TARGET_OPTIONS): Document m32r + specific command line switches. + +Mon Oct 19 14:05:30 1998 Jeffrey A Law (law@cygnus.com) + + * gcse.c (nonnull_local, nonnull_killed): New file static variables. + (invalidate_nonnull_info): New functions + (delete_null_pointer_checks): Likewise. + * toplev.c (rest_of_compilation): Call delete_null_pointer_checks + immediately before and after the first CSE pass. + +Mon Oct 19 07:33:00 1998 Catherine Moore + + * config/rs6000/sysv4.h (CPP_SPEC): Define _SOFT_FLOAT + if -msoft-float. + +Sun Oct 18 14:57:03 1998 Jeffrey A Law (law@cygnus.com) + + * gcse.c (compute_transpout): New function. + (insert_insn_end_bb): New argument PRE. All callers changed. Make + some sanity checks conditional on value of PRE. + (transp, comp, antloc): Renamed from pre_transp, pre_comp, pre_antloc. + Replace all references. + (hoist_transp, hoist_comp, hoist_antloc): Delete. Change all references + to transp, comp and antloc respectively. + (transpout): New bitmap. + (alloc_pre_mem, alloc_hoist_mem): Allocate transpout. + (free_pre_mem, free_hoist_mem): Deallocate transpout. + (compute_pre_data): Compute pre_transpout. + (compute_code_hoist_data): Likewise. + (hoist_code): We can not hoist an expression into a block if the + expression is not in tranpout for the block. + +Fri Oct 16 10:47:53 1998 Nick Clifton + + * config/arm/arm.h (TARGET_SWITCHES): Add --help documentation. + (TARGET_OPTIONS): Add --help documentation. + +Thu Oct 15 13:44:30 1998 Jim Wilson + + * d30v/d30v.c (d30v_eh_epilogue_sp_ofs): New variable. + (d30v_stack_info): Correct calculation for link_offset. + (d30v_function_epilogue): Don't clear d30v_return_addr_rtx here. + (d30v_expand_epilogue): Use d30v_epilogue_sp_ofs. + (struct machine_function): New type. + (d30v_save_machine_status, d30v_restore_machine_status, + d30v_init_expanders): New functions. + (d30v_return_addr): Call push_topmost_sequence, pop_topmost_sequence. + * d30v/d30v.h (INCOMING_RETURN_ADDR_RTX): Change VOIDmode to Pmode. + (INIT_EXPANDERS): New macro. + (d30v_init_expanders, d30v_eh_epilogue_sp_ofs): Add declarations. + * d30/d30v.md (eh_epilogue): New. Set d30v_eh_epilogue_sp_ofs. + +Wed Oct 14 21:38:11 1998 J"orn Rennecke + + * regmove.c (optimize_related_values): Check if cc0 is set. + + * regmove.c (optimize_related_values): Fix problem with multiple + related values in single insn. + +Tue Oct 13 12:25:24 1998 Nick Clifton + + * config/v850/v850.c: Synchronised with egcs. + + * config/v850/v850.md: Synchronised with egcs. + + * config/m32r/m32r.md (sne): Only accept unsigned 16bit integers. + +Tue Oct 13 07:55:04 1998 Catherine Moore + + * config/arm/elf.h: Fix typo. + * config/arm/telf.h: Ditto. + +Mon Oct 12 22:57:24 1998 Jeffrey A Law (law@cygnus.com) + + * sparc.h: Fix minor merge lossage in 64bit sparc support. + +Mon Oct 12 14:10:48 1998 Nick Clifton + + * config/arm/thumb.c: Fix CYGNUS LOCAL markers. + + * config/arm/arm.c (arm_override_options): Add initialisation of + arm_ld_sched boolean. + + Fix CYGNUS LOCAL markers. + + * config/arm/arm.md: Add ldsched attribute and use in computing + functional units. + + Fix CYGNUS LOCAL markers. + + Replace (reg 24) with (reg:CC 24). + + * config/arm/arm.h: Add export of arm_ld_sched. + +Mon Oct 12 09:21:32 1998 Catherine Moore + + * config/arm/elf.h (MAKE_DECL_ONE_ONLY): Define. + (UNIQUE_SECTION_P): Define. + (UNIQUE_SECTION): Define. + * config/v850/v850.c (print_operand): Extend meaning + of 'c' operands to support .vtinherit. + +Sun Oct 11 03:20:26 1998 Jeffrey A Law (law@cygnus.com) + + * pa.c (hppa_legitimize_address): Handle full offsets for PA2.0 + FP loads and stores. + * pa.h (TARGET_PARISC_2_0): Define. + (TARGET_SWITCHES): Add -mpa-risc-2-0, -mno-pa-risc-2-0. + (GO_IF_LEGITIMATE_ADDRESS): Handle full offsets for PA2.0 FP loads + and stores. + (LEGITIMIZE_RELOAD_ADDRESS): Similarly. + * pa.md: Add several new PA2.0 patterns. Split a few of the + fix/float patterns into define_expands and define_insns. + * pa-hpux10.h (ASM_FILE_START): Emit .level pa2.0 if generating + PA2.0 opcodes. + * pa-hpux11.h (ASM_FILE_START): Likewise. + +Thu Oct 8 17:06:15 1998 Nick Clifton + + * config/arm/elf.h (DWARF_DEBUGGING_INFO): Define. + (ASM_OUTPUT_DWARF2_ADDR_CONST): Define. + (ASM_OUTPUT_DWARF_ADDR_CONST): Redfeine to work for Dwarf-1. + + * config/arm/telf.h (DWARF_DEBUGGING_INFO): Define. + (ASM_OUTPUT_DWARF2_ADDR_CONST): Define. + (ASM_OUTPUT_DWARF_ADDR_CONST): Redfeine to work for Dwarf-1. + (ASM_OUTPUT_DEF): Define. + +Thu Oct 8 11:02:06 1998 Jim Wilson + + * d30v.md (seq, sne, sgt, sge, slt, sle, sgtu, sgeu, sltu, sleu): + Add (eq:SI ... (const_int 1)) around operand 1. + (setcc_internal): Likewise. + (decscc): Likewise for operand 2. + (incscc): Switch operands 1 and 2, then likewise for operand 1. + +Thu Oct 8 10:59:42 1998 Nick Clifton + + * d30v.c (d30v_emit_cond_move): Generate pattern that can be + matched by the new setcc_internal pattern. + + * tree.h: Remove (unused) data_area field of struct + tree_decl. + + * c-decl.c (duplicate_decls): Remove code to copy data_area + field of struct tree_decl. + (start_decl): Remove invocation of SET_DEFAULT_SECTION_NAME. + (start_function): Add invocation of SET_DEFAULT_DECL_ATTRIBUTES. + + * tm.texi (SET_DEFAULT_SECTION_NAME): Remove definition of + this unused macro. + +Wed Oct 7 02:39:12 1998 Richard Henderson + + * gcse.c (insert_insn_end_bb): When a call ends a bb, insert + the new insns before the argument regs are loaded. + +Tue Oct 6 10:59:15 1998 Catherine Moore + + * config/sparc/sysv4.h (ASM_OUTPUT_SECTION_NAME): Don't + check for flag_function_sections. + +Mon Oct 5 09:59:40 1998 Jeffrey A Law (law@cygnus.com) + + * Makefile.in: Remove CYGNUS LOCAL markers for unlibsubdir changes. + +Fri Oct 2 16:58:37 1998 Nick Clifton + + * dwarf2out.c (gen_subprogram_die): If errorcount nonzero, don't + call abort if the function is already defined. + +Thu Oct 1 17:59:03 1998 Nick Clifton + + * config/arm/arm.c: Import changes from egcs. + +Wed Sep 30 10:41:21 1998 Nick Clifton + + * config/v850/v850.md: Replace 'memory_operand' with + 'indirect_operand' in set1, not1 and clr1 patterns. + + * config/v850/v850.c (compute_register_save_size): Detect when + out-of-line helper functions will be used to create function + prologues, and allow for their affect on the frame size. + + * config/v850/v850.h (EXTRA_SWITCHES): Default the contents of this + macro to empty. + + * config/v850/lib1funcs.asm: Add type attributes for callt + functions. + +Tue Sep 29 09:36:33 1998 Nick Clifton + + * config/d30v/libgcc1.asm: Fixinstruction ordering conflicts + detected by recent changes in the assembler. + +Mon Sep 28 13:20:44 1998 Catherine Moore + + * configure.in: Add CYGNUS LOCAL markers. + * config/arm/aout.h: Ditto. + * config/arm/arm.h: Ditto. + * config/arm/t-arm-elf: Ditto. + * config/arm/t-thumb-elf: Ditto. + +Fri Sep 15 16:00:00 1998 Jim Wilson + + * reload1.c (reload): Use reload_address_index_reg_class and + reload_address_base_reg_class when setting caller_save_spill_class. + * config/arm/arm.md (insv): Add comment. In CONST_INT case, and + operand3 with mask before using it. + +Wed Sep 23 16:35:17 1998 Nick Clifton + + * config/arm/thumb.h (enum reg_class): Add NONARG_LO_REGS + support. + (REG_CLASS_NAMES, REG_CLASS_CONTENTS, REGNO_REG_CLASS, + PREFERRED_RELOAD_CLASS, SECONDARY_RELOAD_CLASS): Likewise. + (GO_IF_LEGITIMATE_ADDRESS): Disable REG+REG addresses before reload + completes. Re-enable HImode REG+OFFSET addresses. + (LEGITIMIZE_RELOAD_ADDRESS): Define. + +Wed Sep 23 20:42:54 1998 J"orn Rennecke + + * regmove.c (optimize_related_values_1): Set use->insn when emitting + the linking insn before the final 'use' for a register that does not + die within the scope of the optimization. + +Tue Sep 22 10:01:21 1998 Nick Clifton + + * config/generic/generic.h: Update description of HANDLE_PRAGMA + and add description of HANDLE_PRAGMA_PACK_PUSH_POP. + +Mon Sep 21 15:04:16 1998 J"orn Rennecke + + * regmove.c (count_sets): New function. + (gen_add3_insn): If single instruction add fails and source and + destination register are different, try a move / add sequence. + (rel_use_chain): New member match_offset. + (optimize_related_values_1): Set it, and use it to avoid linking + chains when this requires more than one instruction for the add. + (add_limits): New file scope array. + (optimize_related_values): Initialize it. + +Mon Sep 21 14:55:36 1998 J"orn Rennecke + + * regmove.c (optimize_related_values_1): Don't use rel_base->reg + for a chain that needs an out-of-range offset. + Take setting of rel_base_reg_user into account when deciding + if there are enough registers available. + +Fri Sep 18 11:54:03 1998 Catherine Moore + + * config/elfos.h: Modify prefixes for UNIQUE_SECTION_NAME. + * config/svr4.h: Likewise. + * config/mips/elf.h: Likewise. + * config/mips/elf64.h: Likewise. + +Fri Sep 18 09:44:55 1998 Nick Clifton + + * config/m32r/m32r.h (m32r_block_immediate_operand): Add to + PREDICATE_CODES. + + * config/m32r/m32r.md: Add "movstrsi" and "movstrsi_internal" + patterns. + + * config/m32r/m32r.c (m32r_print_operand): Add 's' and 'p' + operators. + (block_move_call): New function: Call a library routine to copy a + block of memory. + (m32r_expand_block_move): New function: Expand a "movstrsi" + pattern into a sequence of insns. + (m32r_output_block_move): New function: Expand a + "movstrsi_internal" pattern into a sequence of assembler opcodes. + +Wed Sep 16 14:13:38 1998 Stan Cox + + * i386-coff.h (DBX_DEBUGGING_INFO): Added. + +Wed Sep 16 12:09:12 1998 Catherine Moore + + * flags.h: Add flag_data_sections. + * toplev.c: Add option -fdata-sections. Add flag_data_sections. + (compile_file): Error if flag_data_sections not supported. + * varasm.c (assemble_variable): Handle flag_data_sections. + +Tue Sep 15 16:41:00 1998 Michael Tiemann + + * fold-const.c (fold): Fix typo in COND_EXPR handling code. + (invert_truthvalue): Enable truthvalue inversion for + floating-point operands if -ffast-math. + + * regmove.c (find_related): We also have to track expressions that + are just naked registers. Otherwise, we burn one register to + prime the related values, and we'll also miss the second (but not + subsequent) opportunities to use related values. + + * lcm.c (compute_antinout): Start by setting all bits in + OLD_CHANGED, not NEW_CHANGED. + (compute_earlyinout): Ditto. + + * lcm.c (compute_redundant): Free temp_bitmap when we're done with + it. + + * libgcc1.c (__abssf2, __absdf2): New libcalls. + * Makefile.in (LIB1FUNCS): Add code for new ABS libcalls. + * optabs.c (init_optabs): Intialize abs_optabs to use ABS + libcalls. + +Tue Sep 15 17:09:49 1998 J"orn Rennecke + + * sh.h (SECONDARY_INPUT_RELOAD_CLASS): Add special case for FPSCR. + (GO_IF_LEGITIMATE_ADDRESS): Allow indexed addressing for PSImode + after reload. + (LEGITIMIZE_RELOAD_ADDRESS): Don't operate on + RELOAD_FOR_INPUT_ADDRESS for PSImode. + * sh.md (movpsi): New expander. + (fpu_switch): Add r/r and m/r alternatives. Move r/m before + c/m. Add insn predicate. + +Tue Sep 15 09:47:50 1998 Catherine Moore + + * config/arm/aout.h: Check if ASM_DECLARE_FUNCTION_NAME + already declared. + * config/arm/elf.h (TYPE_ASM_OP): Define. + (SIZE_ASM_OP): Define. + (TYPE_OPERAND_FMT): Define. + (ASM_DECLARE_RESULT): Define. + (ASM_DECLARE_FUNCTION_NAME): Define. + (ASM_DECLARE_OBJECT_NAME): Define. + (ASM_FINISH_DECLARE_OBJECT): Define. + (ASM_DECLARE_FUNCTION_SIZE): Define. + (ASM_OUTPUT_SECTION_NAME): Change default to "ax". + * config/arm/telf.h (ASM_OUTPUT_SECTION_NAME): Change + default to "ax". + +Mon Sep 14 09:39:28 1998 Jeffrey A Law (law@cygnus.com) + + * flow.c (compute_preds_succs): Only split edges when the last insn + in the basic block is a conditional branch. + (merge_blocks): Do not merge a block with a tablejump with anything. + +Tue Sep 8 21:36:59 1998 Jeffrey A Law (law@cygnus.com) + + * gcse.c (pre_insert): Fix thinko. + +Mon Sep 7 23:50:56 1998 Michael Meissner + + * rs6000.c (rs6000_override_options): Add -mcpu=740 as a place + holder. + +Thu Sep 3 18:16:16 1998 Michael Meissner + + * rs6000.c (rs6000_override_options): Add -mcpu=750 as a place + holder. + +Thu Sep 3 23:33:57 1998 J"orn Rennecke + + * rtl.h (push_obstacks_nochange, end_temporary_allocation): Declare. + * regmove.c (obstack.h): Include. + (REL_USE_HASH_SIZE, REL_USE_HASH, rel_alloc, rel_new): Define. + (struct related, struct related_baseinfo, struct update): New structs. + (struct rel_use_chain, struct rel_use): Likewise. + (regno_related, rel_base_list, unrelatedly_used): New variables. + (related_obstack): Likewise. + (regclass_compatible_p, lookup_related): New functions. + (rel_build_chain, rel_record_mem, invalidate_related): Likewise. + (find_related, chain_starts_earlier, chain_ends_later): Likewise. + (optimize_related_values_1, optimize_related_values_0): Likewise. + (optimize_related_values): Likewise. + (regmove_optimize): Use regclass_compatible_p. + Call optimize_related_values. + +Wed Sep 2 19:00:17 1998 Jeffrey A Law (law@cygnus.com) + + * gcse.c (pre_insert): Do not insert an expression into the same + block more than once. + * lcm.c (compute_antinout): Avoid useless computations when the + global properties of the current block's successors have not changed. + (compute_earlyinout): Similarly. + +Tue Sep 1 11:30:33 1998 Nick Clifton + + * config/m32r/m32r.md: Change (reg:CC 17) to (reg:SI 17). + * config/m32r/m32r.h: Make register 17 be fixed. + +Mon Aug 31 11:29:15 1998 Catherine Moore + + * config/arm/elf.h: Rework constructor/destructor support. + * config/arm/telf.h: Likewise. + * config/arm/t-arm-elf: New file. + * config/arm/t-thumb-elf: New file. + * configure.in: Change tmake_file to t-arm-elf for + arm-elf and to t-thumb-elf for thumb-elf. + * configure: Rebuild. + +Mon Aug 31 09:53:24 1998 Jeffrey A Law (law@cygnus.com) + + * range.c (live_range): Do not perform LRS on phony loops. + + * mn10300.md (widening multiplies): Fix order of output operands + in assembler template. + + * range.c (range_finish): Start block 0 at the first CODE_LABEL or + real insn. + +Wed Aug 26 17:13:37 1998 Tom Tromey + + * gthr.h: Document __GTHREAD_MUTEX_INIT_FUNCTION. + * gthr-qt.h: New file. + * frame.c (init_object_mutex): New function. + (init_object_mutex_once): Likewise. + (find_fde): Call it. + (__register_frame_info): Likewise. + (__register_frame_info_table): Likewise. + (__deregister_frame_info): Likewise. + * configure.in: Recognize `qt' as a thread package. Add + appropriate -I option to gthread_flags when using qt. + * configure: Rebuilt. + +Wed Aug 26 16:22:51 1998 Jeffrey A Law (law@cygnus.com) + + * toplev.c (rest_of_compilation): Enable LRS at -O2 and higher for + systems which prefer stabs debug symbols. + * invoke.texi: Restore lost LRS docs. Note LRS is enabled at -O2 + and higher for some systems. + + * toplev.c (rest_of_compilation): Run recompute_reg_usage before + LRS, not after. + +Wed Aug 26 09:30:59 1998 Nick Clifton + + * config/arm/thumb.c (thumb_exit): Do not move a4 into lr if it + already contains the return address. + + * cse.c (equiv_constant): Cope with gen_lowpart_if_possible() + returning 0. + +Wed Aug 26 11:18:57 1998 Gavin Romig-Koch + + * mips.md (lshrsi3_internal2+2): Fix type-o. + +Tue Aug 25 11:38:21 1998 Nick Clifton + + * config/v850/v850.c (movsi_source_operand): Treat CONSTANT_P_RTX + as an ordinary operand. + +Sat Aug 22 00:11:51 1998 Jeffrey A Law (law@cygnus.com) + + * rs6000.md (movdf_softfloat32): Accept any valid memory + address. + +Fri Aug 21 14:19:52 1998 Jeffrey A Law (law@cygnus.com) + + * mn10300.md (movdi, movdf): When using movu to load the high half + of a DImode/DFmode value, do not forget to also load the load half. + +Thu Aug 20 15:04:28 1998 Michael Meissner + + * d30v.h (ASM_GENERATE_INTERNAL_LABEL): Remove definition, svr4.h + supplies an appropriate one. + + * d10v.c: Include system.h, not stdio.h to get sys/param.h pulled + in before rtl.h in case the system defines MIN and MAX. + * d30v.h: Ditto. + +Wed Aug 19 11:57:57 1998 Nick Clifton + + * config/arm/elf.h (ASM_OUTPUT_INTERNAL_LABEL): Define. + +Tue Aug 18 10:02:53 1998 Catherine Moore + + * config/arm/elf.h: Define ASM_SPEC and LINK_SPEC. + +Wed Aug 12 14:12:40 1998 Nick Clifton + + * config/arm/thumb.md (extendqisi2_insn): Cope with REG + + OFFSET addressing. + + * config/arm/m32r.md (sne): Only generate xor insns when the + constant is unsigned. + +Wed Aug 12 12:09:54 1998 Jeffrey A Law (law@cygnus.com) + + * configure.in (hpux11 support): Move it before the default hpux + case to avoid using the generic hpux config files for hpux11. + * configure: Rebuilt. + +Wed Aug 12 12:47:50 1998 Gavin Romig-Koch + + * mips/mips.h (ENCODE_SECTION_INFO): Set SYMBOL_REF_FLAG for + VAR_DECL's in gp addressable sections. + +Wed Aug 12 09:02:55 1998 Nick Clifton + + * config/m32r/m32r.c (m32r_not_same_reg): New function. Returns + true iff its two arguments are rtx's that refer to different + registers. + + * config/m32r/m32r.h (PREDICATE_CODES): Add m32r_not_same_reg(). + + * config/m32r/m32r.md (andsi3, iorsi3, xorsi3): Use + m32r_not_same_reg() rather than rtx_equal_p(). + +Tue Aug 11 09:15:23 1998 Nick Clifton + + * tm.texi (SET_DEFAULT_SECTION_NAME): Add CYGNUS LOCAL markers. + +Mon Aug 10 11:36:04 1998 Nick Clifton + + * config/v850/v850.h: Add prototypes for some exported functions. + + Remove spurious CYGNUS LOCAL markers, and add required CYGNUS + LOCAL markers. + + Define HANDLE_PRAGMA and SET_DEFAULT_SECTION_NAME macros and the + enums used by the code in v850.c that implements them. + New enums: v850_pragma_state, v850_pragma_type, GHS_section_kind. + + * config/v850/v850.c: Add prototypes for functions not prototypes + in v850.h. + + Add default cases to some switch statements, in order to eliminate + warning messages when compiled with -Wall. + + Add support for sda, tda and zda attributes. Moved here from + c-decl.c. Add code to implement some GHS pragmas. + New functions: push_data_area, pop_data_area, v850_handle_pragma, + mark_current_function_as_interrupt, parse_ghs_pragma_token, + v850_set_default_section_name. + +Fri Aug 7 17:25:29 1998 Nick Clifton + + * c-decl.c (duplicate_decls): Copy data area from old decl into + new decl. + (start_decl): Add use of SET_DEFAULT_SECTION_NAME, if defined. + (start_function): Add use of SET_DEFAULT_SECTION_NAME, if defined. + + * c-lex.c (check_newline): Call HANDLE_PRAGMA before + HANDLE_SYSV_PRAGMA if both are defined. Generate warning messages + if unknown pragmas are encountered. + (handle_sysv_pragma): Interpret return code from + handle_pragma_token (). Return success/failure indication rather + than next unprocessed character. + + * c-pragma.c (handle_pragma_token): Return success/failure status + of the parse. + + * c-pragma.h: Change prototype of handle_pragma_token(). + + * tm.texi (HANDLE_PRAGMA): Document the use of HANDLE_PRAGMA when + USE_CPPLIB is enabled. + (SET_DEFAULT_SECTION_NAME): New macro. Allows backend to setup + the section name of a decl when it is created. + + * tree.h (DECL_DATA_AREA): New macro. Accesses data_area field of + a decl + (struct tree_decl): Add new field 'data_area'. + + * varasm.c: (handle_pragma_weak): Only create this function if + HANDLE_PRAGMA_WEAK is defined. + +Mon Aug 3 08:00:00 1998 Catherine Moore + + * configure.in: Support arm-*-elf and thumb-*-elf. + * configure: Regenerate. + +Fri Jul 31 16:13:04 1998 Catherine Moore + + * config/arm/elf.h: New file. + * config/arm/telf.h: New file. + * config/arm/aout.h: Check if ASM_FILE_START previously + defined. + * config/arm/arm.h: Check if STRUCTURE_SIZE_BOUNDARY + previously defined. + +Fri Jul 31 16:00:41 1998 Ken Raeburn + + * mips.md (mulsi3_mult3): Add TARGET_MIPS5400 to condition. + (muls_r5400, msac_r5400): Don't disparage output-LO alternative. + (msac_r5400): Use "*d" for accumulator, to give preference to LO + initially but not during reload. + (muls_r5400_di, msac_r5400_di, xmulsi3_highpart_5400, + xmulsi3_neg_highpart_5400): Fix typo, SIGN_EXTRACT for + SIGN_EXTEND. + (macc_r5400_di): Absorb into mul_acc_64bit_di. + (mul_acc_64bit_di): Don't use match_dup for accumulator, use "0" + constraint. + * t-vr5000 (MULTILIB_OPTIONS, MULTILIB_DIRNAMES): Add VR5400 + options. + +Fri Jul 31 10:23:55 1998 Doug Evans + + * m32r/m32r.h (ASM_OUTPUT_SOURCE_LINE): Always output line number + labels with .debugsym if no parallel insns. + +Fri Jul 31 09:45:07 1998 Nick Clifton + + * reload1.c (init_reload): On SMALL_REGISTER_CLASSES machines, + when searching for a reload_address_reg_class, avoid fixed + registers as well as argument registers. + +Wed Jul 29 11:47:10 1998 Nick Clifton + + * config/arm/thumb.md (extendqisi2_insn): Remove earlyclobber + constraint from second alternative. + +Tue Jul 28 18:54:28 1998 Stan Cox + + * sp86x-aout.h (HAVE_ATEXIT): New macro. + +Tue Jul 28 11:12:46 1998 Vladimir N. Makarov + + * cse.c (cse_insn): Enable subsitution inside libcall only for REG, + SUBREG, MEM. + * rtlanal.c (replace_rtx): Prohibit replaces in CONST_DOUBLE. + +Fri Jul 24 14:22:39 1998 Jeffrey A Law (law@cygnus.com) + + * mn10300.md (am33 movqi, movhi, movsi, movsf): Handle CONST_DOUBLE. + +Fri Jul 24 11:17:04 1998 Nick Clifton + + * config/arm/thumb.c (thumb_print_operand): Decode %_ in asm + strings as the insertion of USER_LABEL_PREFIX. + * config/arm/thumb.h (PRINT_OPERAND_PUNCT_VALID_P): Accept _ as a + valid code. + * config/arm/thumb.md: Use %_ as a prefix to gcc library function + calls. + +Thu Jul 23 13:16:29 1998 Jim Wilson + + * dwarf2out.c (dwarf2out_finish): Call stripattributes on TEXT_SECTION. + +Thu Jul 23 11:12:06 1998 Alexandre Petit-Bianco + + * expr.c (expand_expr): Expand RETURN_EXPR. + +Wed Jul 22 21:43:54 1998 Stan Cox + + * longlong.h (count_leading_zeros): Sparclite scan instruction was + being invoked incorrectly. + + * i386.c (ix86_prologue): Added SUBTARGET_PROLOGUE invocation. + * i386/cygwin32.h (STARTFILE_SPEC, LIB_SPEC, SUBTARGET_PROLOGUE): + Add -pg support. + * i386/win32.h: New file. Hybrid mingw32.h/cygwin32.h configuration. + +Wed Jul 22 18:40:00 1998 Catherine Moore + + * dwarf2out.c (output_aranges): Call stripattributes + for TEXT_SECTION references. + (output_line_info): Likewise. + +Tue Jul 21 23:42:34 1998 Jeffrey A Law (law@cygnus.com) + + * mn10300.c (print_operand_address): Handle POST_INC. + * mn10300.h (HAVE_POST_INCREMENT): Define. + (GO_IF_LEGITIMATE_ADDRESS): Handle POST_INC for the am33. + (GO_IF_MODE_DEPENDENT_ADDRESS): POST_INC is mode dependent. + +Mon Jul 20 16:40:31 1998 Dave Brolley + + * cpplib.c (cpp_handle_option): More fixes for cplusplus_comments. + +Mon Jul 20 15:09:54 1998 Ken Raeburn + + * mips.md (attribute "type"): Add new value "frsqrt". + (function unit specs): Handle frsqrt like fsqrt, except if r5400. + (sqrtsf2+1 et al): Use frsqrt type for rsqrt.FMT instructions. + (function unit "memory"): Treat r5400 like r5000. + (function unit "imuldiv"): Set costs for r5400. Delete a + duplicated entry. + (function units "adder", "divide"): Don't use for r5400. + (function unit "alu_5400"): Don't use for imul or idiv + instructions; do use for arith, darith, move, icmp, nop. Adjust + issue delay. + +Fri Jul 17 11:16:19 1998 Jeffrey A Law (law@cygnus.com) + + * mn10300.h (LIMIT_RELOAD_CLASS): Refine for the am33. + + * mn10300.h (zero_ereg): Delete declaration for unused variable. + (MODES_TIEABLE_P): Provide am33 aware version. + + * mn10300.md (movqi, movhi): Provide am33 versions which allow + ADDRESS_REGS to be used as destinations. + (umulsidi3, mulsidi3): Do not accept immediate operands. + + * mn10300.h (HARD_REGNO_MODE_OK): Address registers can hold HImode + and QImode objects on the am33. + +Thu Jul 16 14:50:58 1998 Jeffrey A Law (law@cygnus.com) + + * mn10300.md (movXX): Use movu when profitable. + + * mn10300.c (expand_epilogue): Fix thinko in previous change. + + * mn10300.md (umulsidi3, mulsidi3): New am33 patterns. + + * mn10300.c (count_tst_insns): Count tst insns for EXTENDED_REGS + as well as clearing an EXTENDED_REGS register. + (expand_prologue): Set up zero_areg and zero_dreg if we can optimzie + comparisons or sets of EXTENDED_REGS against zero. + (output_tst): Heandle optimizing for extended regs. + + * mn10300.h (REGISTER_MOVE_COST): Define appropriately for the am33. + + * mn10300.md (am33 logicals): New patterns. + (am33 zero and sign extension): New patterns. + (am33 shifts): New patterns. + +Tue Jul 14 14:15:30 1998 Nick Clifton + + * gcc.c: Remove ANSI-C ism from --help code. + + * toplev.c: Support --help with USE_CPPLIB. + +Tue Jul 14 10:57:43 1998 Jeffrey A Law (law@cygnus.com) + + * mn10300.md (am33 mulsi): New pattern. + (am33 tstqi, tsthi): New patterns. + + * mn10300.md (movXX patterns): Optimize loading zero into an + extended register if we know a data or address register already + has the value zero in it. + + * mn10300.h (TARGET_SWITCHES): Turn off -mmult-bug for the am33. + + * mn10300.md (subsi3, am33 version): Fix code generation when + operands0 and operands2 are the same register. + +Mon Jul 13 21:45:17 1998 Jeffrey A Law (law@cygnus.com) + + * expr.c (expand_builtin): Do not warn for targets which do not + support CONSTANT_P_RTX. Temporary patch until next merge + +Mon Jul 13 11:10:15 1998 Nick Clifton + + * config/v850/v850ea.h (EXTRA_SWITCHES): Document these switches. + * config/v850/v850e.h (EXTRA_SWITCHES): Document these switches. + * config/v850/v850.h (TARGET_OPTIONS, TARGET_SWITCHES, + EXTRA_SWITCHES): Document these switches. + + * cccp.c (main): Add support for parsing --help. + (display_help): New function: display command line switches. + + * cpplib.c (cpp_handle_option): Add support for parsing --help. + (display_help): New function: display command line switches. + + * gcc.c (main): Add support for parsing --help, and passing it on + to the sub-processes invoked by gcc. + (display_help): New function: display comman line switches. + + * tm.texi (TARGET_SWITCHES and TARGET_OPTIONS): Document + 'description' field added to structure. + + * toplev.c: Add support for parsing --help. + Add documentation strings to command line option tables. + (display_help): New function: display comman line switches. + +Mon Jul 13 11:18:58 1998 Jeffrey A Law (law@cygnus.com) + + * mn10300.c: Add rough am33 support. + * mn10300.md: Likewise. + * mn10300.h: Likewise. + * t-mn10300: Likewise. +Mon Jul 13 11:10:15 1998 Nick Clifton + + * config/arm/semi.h (USER_LABEL_PREFIX): Change to "" to match + FSF sources. + + * config/arm/tcoff.h (USER_LABEL_PREFIX): Change to "" to match + change to semi.h + +Sun Jul 12 13:34:23 1998 Michael Meissner + + * jump.c (duplicate_loop_exit_test): Fix typo in last change. + +Sat Jul 11 02:59:08 1998 Richard Earnshaw + + * arm.md (extendhisi2_mem, movhi, movhi_bytes): Propagate the volatile + and structure attribute flags to MEMs generated. + (splits for sign-extended HI & QI mode from memory): Also propagate + the volatile flag. + +Sat Jul 11 01:18:33 1998 Jeffrey A Law (law@cygnus.com) + + * jump.c (duplicate_loop_exit_test): Avoid out of bounds access + to the reg info virtual array. + +Thu Jul 9 10:49:08 1998 Jeffrey A Law (law@cygnus.com) + + * arm/tpe.h (JUMP_TABLES_IN_TEXT_SECTION): Define with a value. + * i386/i386elf.h: Likewise. + * i386/rtemself.h: Likewise. + * z8k/z8k.h: Likewise. + + * Makefile.in: Fix minor merge lossage which caused incorrect + dependencies. + +Wed Jul 8 23:37:59 1998 Jeffrey A Law (law@cygnus.com) + + * d30v.h (STDIO_PROTO): Likewise. + +Wed Jul 8 16:53:37 1998 Jim Wilson + + * range.c (range_print_flags): Add static to definition. + +1998-07-08 Vladimir N. Makarov + + * config/fp-bit.c (__gexf2, __fixxfsi, __floatsixf): Add function + stubs. + + * toplev.c (lang_options): Add -Wlong-long, -Wno-long-long + options. + * c-decl.c (warn_long_long): Define. + (c_decode_option): Parse -Wlong-long, -Wno-long-long options. + (grokdeclarator): Add flag `warn_long_long' as guard for + warning "ANSI C does not support `long long'". + * invoke.texi: Add description of options -Wlong-long, + -Wno-long-long. + * gcc.1: The same as above. + +Wed Jul 8 09:45:22 1998 Nick Clifton + + * haifa-sched.c (debug_ready_list): Remove static qualifier, so + that it can be called from machine back ends. + + * libgcc1-test.c: Remove duplicate prototype for memcpy(). + + * config/arm/arm.c (arm_override_options): Reference 'flags' + rather than 'tune_flags'. + +Wed Jul 8 03:22:22 1998 Jeffrey A Law (law@cygnus.com) + + * Merge from egcs snapshot 19980707. + +Mon Jul 6 09:32:14 1998 Nick Clifton + + * config/arm/tpe.h (REDO_SECTION_INFO_P): Define. + + * config/arm/thumb.c (thumb_override_options): Warn about and + ignore '-fpic'. + + * config/m32r/m32r.h (MUST_PASS_IN_STACK): Override default + version. + +Thu Jul 2 08:11:00 1998 Catherine Moore + + * haifa-sched.c (alloc_EXPR_LIST): Change to use + unused_expr_list. + +Mon Jun 29 12:15:00 Catherine Moore + + * config/sparc/lb1spc.asm (.udiv, .div) Replace routines. + +1998-06-26 Michael Meissner + + * m32r.h (LOOP_TEST_THRESHOLD): If loop unrolling and saving + space, don't suppress moving the loop test from top to the bottom. + +Thu Jun 25 09:53:24 1998 Nick Clifton + + * config/arm/arm.h (REG_ALLOC_ORDER): Add ARG_POINTER_REGNUM, + noticed by grahams@rcp.co.uk. + +Wed Jun 24 10:39:32 1998 Stan Cox + + * sparc.md (sethi_di_sp32): Swap registers if we are + compiling in little endian mode. + + * sparc.h (CPP_ENDIAN_SPEC, LIBGCC2_WORDS_BIG_ENDIAN): Check for + mlittle-endian-data in addition to mlittle-endian. + + * sp86x-aout.h (ASM_SPEC, SUBTARGET_SWITCHES): -mlittle-endian-data + + * ginclude/va-d30v.h (va_arg): struct args < 4 bytes must be offset. + +Tue Jun 23 21:27:27 1998 Ken Raeburn + + * reload.c (find_reloads): Fix check for failure to match any + alternative, to account for Mar 26 change in initial "best" cost. + +Tue Jun 23 14:20:57 1998 Nick Clifton + + * config/d30v/d30v.h (FIXED_REGISTERS): Remove reference to return + address register. + (CALL_USED_REGISTERS): Ditto. + +Tue Jun 23 16:42:29 1998 Dave Brolley + + * cpplib.c (open_include_file_name): Mark as local change. + +Mon Jun 22 10:30:00 1998 Catherine Moore + + * varasm.c (assemble_variable): Emit alignment warning. + +Sat Jun 20 04:10:50 1998 Michael Meissner + + * m32r.h (MD_SCHED_{VARIABLE_ISSUE,INIT,REORDER}): Define. + (m32r_sched_{variable_issue,init,reorder}): Add declarations. + + * m32r.c (m32r_sched_odd_word_p): New global to keep track of + whether we are on an odd word or even word. + (m32r_adjust_priority): Optimize slightly. + (m32r_sched_init): New function to zero m32r_sched_odd_word_p. + (m32r_sched_reorder): New function to reorder the ready list based + the instruction sizes. Move long instructions before short ones, + except if we are on an odd word boundary. + (m32r_sched_variable_issue): New function to keep track of whether + we are on an odd byte boundary. + +Fri Jun 19 21:33:21 1998 Michael Meissner + + * m32r.h (whole file): Align \'s to column 72. + (*_SPEC): Use EXTRA_SPECS to move cpu dependent stuff down into + {ASM,CPP,CC1,LINK,STARTFILE,ENDFILE}_CPU_SPEC. + (TARGET_SWITCHES): Add support for new debug switches + -missue-rate={1,2} and -mbranch-cost={1,2}. Add + SUBTARGET_SWITCHES for cpu dependent switches. + (TARGET_OPTIONS): Add support cpu dependent switches. + (MULTILIB_DEFAULTS): Ditto. + (OVERRIDE_OPTIONS): Ditto. + (OPTIMIZATION_OPTIONS): Ditto. + ({FIXED,CALL_USED}_REGISTERS): Ditto. + (REG_ALLOC_ORDER): Ditto. + (CONDITIONAL_REGISTER_USAGE): Ditto. + (REG_CLASS_CONTENTS): Ditto. + (GPR_P): Ditto. + ({,ADDITIONAL_}REGISTER_NAMES): Ditto. + (M32R_MODEL_DEFAULT): Wrap inside #ifndef/#endif. + (SDATA_DEFAULT_SIZE): Ditto. + (IN_RANGE_P): New macro to test if something is in a range of + values. + (INT8_P): Recode to use IN_RANGE_P. + ({,CMP_,U}INT16_P): Ditto. + (UPPER16_P): Ditto. + (UINT{24,5}_P): Ditto. + (INT32_P): Ditto. + (INVERTED_SIGNED_8BIT): Ditto. + ({ACCUM,CARRY}_P): New macros for accumulator and carry. + (BRANCH_COST): Set to 1/2 depending on -mbranch-cost={1,2}. + (ENABLE_REGMOVE_PASS): Delete, no longer used. + (ASM_OUTPUT_ALIGNED_LOCAL): Ditto. + (ISSUE_RATE): Set to 1/2 depending on -missue-rate={1,2}. + (DWARF2_DEBUGGING_INFO): Define. + (whole file): Group most of the m32rx specific stuff together + using the subtarget support. Define the various specs + {ASM,CPP,CC1,LINK,STARTFILE,ENDFILE}_CPU_SPEC. + +Thu Jun 18 09:03:31 1998 Michael Meissner + + * m32r.c ({internal_,}reg_or_eq_int16_operand): New functions to + return whether an operand is suitable for == operations. + (gen_compare): Remove support for handling S operations, just + handle branches. + + * m32r.h (PREDICATE_CODES): Add new predicate functions. + ({internal_,}reg_or_eq_int16_operand ): Add declarations. + (gen_compare): Remove argument saying to produce S operations + instead of a branch. + + * m32r.md (b{eq,ne,lt,le,gt,ge,ltu,leu,gtu,geu}): Update + gen_compare calls. + (s{eq,ne,lt,le,gt,ge,ltu,leu,gtu,geu}): Recode to present the + operation as a distinct RTL until splitting so that the + optimization passes generate better code. + (abs{df,sf}2): Define, so that we can make fabs(-0.0) return 0.0. + +Wed Jun 17 15:12:00 1998 Catherine Moore + + * reload1.c (spill_hard_reg): Check mode of register when + spilling from scratch_list. + +Wed Jun 17 14:55:50 1998 Nick Clifton + + * config/arm/thumb.h (GO_IF_LEGITIMATE_ADDRESS): Disallow REG+REG + addressing when one register is the frame pointer or stack + pointer. Disallow REG+CONST addressing in HI mode. + + * config/arm/arm.h (CANONICALIZE_COMPARISON): Preserve OP1. + +Tue Jun 16 20:50:37 1998 Michael Meissner + + * m32r.c (m32r_adjust_{cost,priority}): New functions to adjust + scheduler cost and priority information. + (direct_return): Don't test -mdebug any more. + + * m32r.h (m32r_adjust_{cost,priority}): Declare. + (m32r_address_cost): Correctly spell function in prototype. + (ADJUST_{COST,PRIORITY}): Define to call the appropriate function. + +Tue Jun 16 17:36:35 1998 Dave Brolley + + * cpplib.h (__GCC_CPPLIB__): Add header guard. + * cpplib.c (open_include_file_name): New function. + (open_include_file): Call open_include_file_name instead of open. +Fri Jun 12 00:03:23 1998 Michael Meissner + + * m32r.h (OPTIMIZATION_OPTIONS): Turn on -fregmove if -O1. If + -Os, turn on -fomit-frame-pointer and -fno-strength-reduce. + (CAN_DEBUG_WITHOUT_FP): No longer define, so we don't confuse the + debugger. + (TARGET_FLAGS): Remove -mold-compare support. + + * m32r.c (gen_compare): Rewrite to be more general. Take an + extra argument to give the output register for scc operations or + the label to jump to for bcc operations. Fix typo for LEU & GTU + of constants. + (internal_reg_or_{cmp_int16,uint16}_operand): Same as the function + without the internal_ prefix, except mode argument is an enum. + (internal_reg_or_zero_operand): Ditto. + + * m32r.h (gen_compare): Add new argument to prototype. + (PRESERVE_DEATH_INFO_REGNO_P): Delete, no longer needed after + June 11 regmove.c change. + + * m32r.md (cmp_eqsi_insn): Make a define_expand instead of a + define_insn. + (cmp_ne_small_const_insn): Delete, no longer used. + (b{eq,ne,lt,le,gt,ge,ltu,leu,gtu,geu}): Rework for gen_compare + changes. + (s{eq,ne,lt,le,gt,ge,ltu,leu,gtu,geu}): Define patterns. + (movsicc): Delete, no longer used. + (peephole): Delete, no longer needed after June 11 regmove.c + change. + +Tue Jun 9 21:05:45 1998 Jeffrey A Law (law@cygnus.com) + + * pa.c (override_options): Handle -mschedule=8000. + (pa_reorg): Do not try to combine independent instructions into + a single instruction for the PA8000. + * pa.h (processor_type): Add PROCESSOR_8000. + * pa.md: Add "8000" cpu attribute. Treat the PA8000 like the + PA7100 temporarily. + +Tue Jun 9 14:13:37 1998 Nick Clifton + + * config/v850/t-v850 (TCFLAGS): Add assembler options to catch + signed and unsigned overflows. + + * config/v850/lib1funcs.asm (__callt_save_interrupt): Use 'addi + 16,sp,sp' instead of 'add 16,sp'. Patch cpurtesy of: Biomedin + + +Thu Jun 4 15:14:04 1998 Michael Meissner + + * jump.c (duplicate_loop_exit_test): Remove May 19th code not + duplicating the loop exit test at the bottom, but keep the part + about testing LOOP_TEST_THRESHOLD. + + * m32r.h (LOOP_TEST_THRESHOLD): If -Os, use 2 instead of 30. + (PREDICATE_CODES): Add extend_operand. + (extend_operand): Declare. + + * m32r.c (extend_operand): New function to return true if an + operand can be used in a sign/zero_extend operation. + + * m32r.md (zero_extend*): Use extend_operand. + (sign_extend{qisi,qihi,hisi}2): Rewrite so sign_extend is + available until after reload is done. + +Tue Jun 2 00:54:38 1998 Jeffrey A Law (law@cygnus.com) + + * toplev.c (rest_of_compilation): Only perform block merging for + -O2 and above. + +Mon Jun 1 03:44:03 1998 Catherine Moore + + * config/sh/sh.h (MAX_OFILE_ALIGNMENT): Define. + + * varasm.c (assemble_variable): Augment alignment warning. + +Sun May 31 01:02:05 1998 Jeffrey A Law (law@cygnus.com) + + * gcc.c (process_command): Use concat instead of effectively + open-coding it. + +Sun May 31 10:37:49 1998 Michael Meissner + + * m32r.c (gen_compare): Fix last change to swap GT/GTU/LE/LEU + arguments if both are registers. Don't convert GTU/LEU of a + negative value into GEU/LTU. + +Fri May 29 14:31:39 1998 Ken Raeburn + Jeff Law + + (mulsi_r5400, macc_r5400): Delete patterns. + (muls_r5400, msac_r5400, muls_r5400_di): Rewrite. + (macc_r5400_di, msac_r5400_di): Likewise. + (xmulsi3_highpart_5400): Likewise. + (xmulsi3_neg_highpart_5400): Likewise. + +Fri May 29 13:36:17 1998 Michael Meissner + + * m32r.c (gen_compare): Cmpui takes a signed 16 bit value, not + unsigned. + * m32r.md (cmp_ltusi_insn): Ditto. + + * m32r.c (gen_compare): If the first compare value is not a + register, force it into a register. If the second compare value + is not a register or a constant integer, force it into a + register. + + * m32r.md (cmpsi): Only allow registers or signed 16 bit values + for the second argument. + +Thu May 28 13:20:25 1998 Jeffrey A Law (law@cygnus.com) + + * gcse.c (pre_delete): Fix code to determine the mode of + the reaching pseudo register. + (hoist_code): Likewise. + + * Simple block merging optimization pass. + * flow.c (merge_blocks): New function. + * toplev.c (rest_of_compilation): Call merge_blocks after each + jump optimization pass, except for the last one. + +Thu May 28 13:47:18 1998 Michael Meissner + + * m32r.c (gen_compare): Convert LE/LEU/GT/GTU of a constant into + LT/LTU/GE/GEU with the constant+1. + +Wed May 27 09:04:36 1998 Gavin Koch + + * config/mips/mips.h (ASM_OUTPUT_ALIGN): Remove trailing semi-colon. + +Tue May 26 20:38:27 1998 Stan Cox + + * config/sparc/sp86x-elf.h (TARGET_LITTLE_ENDIAN_DATA): New. + (INIT_SECTION_ASM_OP): Undef so __main constructor invocation is used. + +Tue May 26 14:48:50 1998 Nick Clifton + + * config/v850/v850.c (v850_output_aligned_bss): use + ASM_DECALRE_OBJECT_NAME if it is available. + +Tue May 26 09:28:07 1998 Catherine Moore + + * config/sparc/lb1spc.asm (.urem, .rem) Replace routines. + +Fri May 22 23:46:37 1998 Jim Wilson + + * gcc.c (make_relative_prefix): Call obstack_1grow with '\0'. + +Thu May 21 14:37:15 1998 Nick Clifton + + * config/arm/README-interworking: Add note about ignoring linker + warning message when --support-old-code is used. + +Tue May 19 18:28:47 1998 Jim Wilson + + * config/generic/xm-generic (NO_STAB_H): Delete reference. + * config/d30v/xm-d30v.h (NO_STAB_H): Delete reference. + +Tue May 19 15:38:48 1998 Michael Meissner + + * stmt.c (expand_end_loop): Instead of using a hard-coded 30 for + the number of insns, use LOOP_TEST_THRESHOLD. + + * jump.c (duplicate_loop_exit_test): Use LOOP_TEST_THRESHOLD for + decided how many instructions to duplicate. If optimizing for + space, don't duplicate the loop exit test at the top. + + * expr.h (LOOP_TEST_THRESHOLD): Define if not defined. + + * tm.texi (LOOP_TEST_THRESHOLD): Document. + +Tue May 19 10:27:15 1998 Jeffrey A Law (law@cygnus.com) + + * flow.c (compute_preds_succs): Do not split more than one edge + into any basic block. + +Mon May 18 15:28:26 1998 Nick Clifton + + * config/v850/lib1funcs.asm: Add .text pseudo op to start of + ___udivsi3. + + * config/v850/lib1funcs.asm: Fix .size pseudo ops to use three + underscores for the prefixes to the names of the maths functions. + + * dbxout.c (dbxout_parms): Revert to using DECL_ARG_TYPE for + parameters passed in memory. Add a comment explaining why. + +Mon May 18 00:21:53 1998 Jeffrey A Law (law@cygnus.com) + + * c-lex.c (check_newline): Remove old CYGNUS LOCAL code that + is no longer needed. + +Sun May 17 20:57:01 1998 Michael Meissner + + * m32r.h (PREDICATE_CODES): Add seth_add3_operand, int8_operand, + and uint16_operand. + (int8_operand): Add declaration. + + * m32r.c (int8_operand): Return true if value is a signed 8 bit + constant int. + (m32r_expand_prologue): Remove duplicate setting of gmask. + (direct_return): Return true if we have no stack to allow jmp lr + to be used as a return. + + * m32r.md ({and,ior,xor}si3): If -Os and we have a 8 bit immediate + constant and different registers, emit two short instructions + instead of a long instruction. Also don't accept integer + arguments greater than 16 bits initially, to give those values a + chance at CSE. + (return): Add return pattern. + +Fri May 15 19:30:29 1998 Michael Meissner + + * m32r.md (mov{si,sf}_insn): Correct attributes for load/store + with inc/dec. + +Fri May 15 14:55:45 1998 Nick Clifton + + * dbxout.c (dbxout_parms): Use TREE_ARG to compute the type of a + function parameter passed in memory. + +Thu May 14 14:37:26 1998 Nick Clifton + + * config/arm/README-interworking: Document dlltool support for + interworking. + + * config/arm/lib1thumb.asm: Add labels to help disassembler + distinguish between ARM and Thumb code. + Fix _interwork_call_via_ip. + * config/arm/lib1funcs.asm: Ditto. + +Thu May 14 13:27:07 1998 Jim Wilson + + * global.c (undo_live_range): Use PUT_REG_NOTE_KIND instead of + REG_NOTE_KIND. + +Wed May 13 22:45:53 1998 Michael Meissner + Jeff Law + + * m32r.c (move_src_operand): Reject loads with PRE_INC or PRE_DEC. + (move_dest_operand): Reject stores with POST_INC. + (m32r_print_operand): Change abort calls into fatal_insn calls. + (m32r_print_operand_address): Ditto. + + * m32r.h (EXTRA_CONSTRAINT): 'S' is now for stores with PRE_INC or + PRE_DEC. 'U' is now for loads with POST_INC. + (HAVE_PRE_{INC,DEC}REMENT): Define. + (HAVE_POST_INCREMENT): Ditto. + (PUSH_POP_P): Delete, no longer used. + (LOAD_POSTINC_P): Recognize loads with POST_INC. + (STORE_PREINC_PREDEC_P): Recognize stores with PRE_{INC,DEC}. + (GO_IF_LEGITIMATE_ADDRESS): Recognize loads with POST_INC, and + stores with PRE_{INC,DEC}. + + * m32r.md (movsi_insn): Separate loads with POST_INC from stores + with PRE_{DEC,INC}. Emit push/pop if pushing/poping stack + pointer. + (movsf_insn): Allow memory loads to have POST_INC, and stores to + have PRE_{DEC,INC}. + +Mon May 11 11:34:17 1998 Jeffrey A Law (law@cygnus.com) + + * egcs -> gcc merge. See ChangeLog.egcs & ChangeLog.12 for + details. + + * lcm.c (compute_latein, compute_firstin): Fix thinko. + +Mon May 11 07:33:27 1998 Michael Meissner + + * lcm.c (compute_latein): Fix typo. + +Mon May 11 02:36:22 1998 Jeffrey A Law (law@cygnus.com) + + * lcm.c (compute_latein): Avoid mis-compiling latein for the + last block. + (compute_firstout): Similarly, but for the first block. + (compute_isoinout): Solve as a backward dataflow problem. + (compute_rev_isoinout): Simlarly, but solve as a forward problem. + +Sun May 10 11:03:03 1998 Jeffrey A Law (law@cygnus.com) + + * gcse.c (compute_hash_table): Delete unused "f" parameter. + (compute_set_hash_table, compute_expr_hash_table): Likewise. + (one_classic_gcse_pass, one_cprop_pass): Likewise. + (one_pre_gcse_pass, one_code_hoisting_pass): Likewise. + (hoist_code): Remove unused variable "changed". + (insert_insn_end_bb): Wrap "note" parameter inside #ifdef HAVE_cc0. + (mark_call): Remove unused "pat" parameter. + + * lcm.c (compute*): Remove either s_preds or s_succs, whichever + is unused. All callers changed. + (compute_rev_redundant, compute_rev_optimal): Delete unused functions. + (pre_lcm, pre_rev_lcm): Delete unused parameter "comp". + * basic-block.h (pre_lcm, pre_rev_lcm): Update declarations. + * gcse.c (compute_pre_data): Corresponding changes. + +Thu May 7 16:20:59 1998 Gavin Koch + + * config/mips/elf.h (ASM_OUTPUT_DEF,ASM_WEAKEN_LABEL, + ASM_OUTPUT_WEAK_ALIAS): Define. + * config/mips/elf64.h: Same. + * config/mips/r3900.h (ASM_OUTPUT_DEF,SUPPORTS_WEAK, + ASM_WEAKEN_LABEL): Removed. + +Tue May 5 14:28:53 1998 Jim Wilson + + * elfb4100.h, elfb4300.h, elfb4320.h, elfb4900.h, elfb5000.h, + elfl4100.h, elfl4300.h, elfl4320.h, elfl4900.h, elfl5000.h + (MULTILIB_DEFAULTS): Move definition after elf64.h include. + +Mon May 4 09:00:56 1998 Jeffrey A Law (law@cygnus.com) + + * lcm.c: New file with generic partial redundancy elimination + and lazy code motion support. + * Makefile.in: Corresponding changes. + * basic-block.h (pre_lcm): Declare. + (pre_rev_lcm): Likewise. + * gcse.c: Remove various static variables no longer needed. + (alloc_pre_mem): Only allocate space for local properties, redundant, + optimal and a scratch bitmap. + (free_pre_mem): Simlarly. + (compute_pre_antinout): Deleted. + (compute_pre_earlyinout, compute_pre_delayinout): Likewise. + (compute_pre_latein, compute_pre_isoinout): Likewise. + (compute_pre_optimal, compute_pre_redundant): Likewise. + (compute_pre_data): Call pre_lcm. + +Thu Apr 30 16:07:02 1998 Nick Clifton + + * config/v850/v850.h (ASM_OUTPUT_ALIGNED_BSS): Call v850_output_aligned_bss(). + * config/v850/v850.c (v850_output_aligned_bss): New + function. Preserve alignment information when emitting symbols + into the bss section. + (v850_output_bss): Function removed. + +Wed Apr 29 16:18:40 1998 Michael Meissner + + * m32r.h (ASM_OUTPUT_SOURCE_LINE): Use .debugsym instead of + creating a label if -Os to prevent extra NOPs. + +Tue Apr 28 11:10:10 1998 Mark Alexander + + * config/sparc/t-sp86x (MULTILIB_OPTIONS): Remove big-endian. + (MULTILIB_DIRNAMES): Add "little" for brevity. + +Mon Apr 27 17:07:09 1998 Nick Clifton + + * config/arm/thumb.h (GO_IF_LEGITIMATE_ADDRESS): Use + frame_pointer_rtx rather than FRAME_POINTER_REGNUM. + +Sun Apr 26 17:04:11 1998 Michael Meissner + + * m32r.c (conditional_move_operand): Silence a debug message. + +Fri Apr 24 06:46:40 1998 Nick Clifton + + * config/arm/thumb.h (GO_IF_LEGITIMATE_ADDRESS): Disallow frame + pointer as second register in REG+REG pair. + +Thu Apr 23 12:13:36 1998 Nick Clifton + + * config/v850/v850.c (expand_prologue): Only generate callt using + insns if TARGET_DISABLE_CALLT is not defined. + +Wed Apr 22 17:53:04 1998 Stan Cox + + * sparc.c (sparc_override_options): New option name -mcpu=sparclite86x. + +Wed Apr 22 17:23:07 1998 Michael Meissner + + * m32r.h (TARGET_M32R): New macro. + (PREDICATE_CODES): Rearrange somewhat, add small_insn/long_insn. + + * m32r.c ({small,long}_insn): New predicates. + + * m32r.md (insn_size): New attribute. + ({,rev_}branch_insn): Add .s qualifier to branches believed to be + short. + (m32r): New attribute. + (small_sequence,long_group): Add initial framework for instruction + grouping. + + * m32r.h (ASM_SPEC): Add -O to the assembler arguments if we are + compiling for the m32rx and optimizing. + + * m32r.md (m32rx{,_pipeline}): New attributes. + (small_parallel): Add initial framework for instruction grouping. + + * rtl.def (GROUP_{PARALLEL,SEQUENCE}: Add new insns. + +Mon Apr 20 13:31:17 1998 Dave Brolley + + * stmt.c (mark_seen_cases): Needs to be external linkage for Chill. + +Mon Apr 20 07:37:49 1998 Michael Meissner + + * i386.c: Include expr.h to get the change_address prototype + declared. + +Sat Apr 18 23:37:59 1998 Stan Cox + + * configure.in: Added sparc86x. + * configure: Regenerate. + + * sparc.h (TARGET_CPU_{hypersparc,sparc86x}, + PROCESSOR_{HYPERSPARC,SPARC86X}): Added for sparc86x/hypersparc. + (ADJUST_COST): Call hypersparc_adjust_cost. + + * sparc.c (hypersparc_adjust_cost): Added for sparc86x/hypersparc. + + * sparc.md (define_function_unit): Added for sparc86x/hypersparc. + (define_attr "cpu"): Added hypersparc/sparc86x. + + * (t-sp86x, sp86x-elf.h, sp86x-aout.h: Added for sparc86x. + +Thu Apr 16 22:38:23 1998 Jeffrey A Law (law@cygnus.com) + + * gcse.c (dump_sbitmap, dump_sbitmap_vector): Move these into + flow.c. + +Tue Apr 14 14:10:43 1998 Dave Brolley + + * toplev.c: Call init_parse using new interface. + + * c-lex.c (init_parse): Now returns char* containing the filename. +Mon Apr 13 11:31:29 1998 Michael Meissner + + * m32r.h (HAIFA_P): Define as 1/0 depending on whether the Haifa + scheduler was selected. + (ISSUE_RATE): Define as 2. + + * configure.in (enable_haifa): Switch m32r to Haifa by default. + * configure: Regenerate. + +Sun Apr 12 13:35:49 1998 Jeffrey A Law (law@cygnus.com) + + * gcse.c (gcse_main): Run code hoisting if optimizing for + code space. + +1998-04-10 Ken Raeburn + + * config/arm/thumb.h, config/d10v/d10v.h, + config/generic/generic.h, config/z8k/z8k.h (MEMORY_MOVE_COST): + Updated to show extra args, currently ignored. See my 16-Mar + change. + * config/d30v/d30v.h (MEMORY_MOVE_COST): Likewise. + +Fri Apr 10 15:38:21 1998 Jim Wilson + + * config/i386/i386elf.h (ENDFILE_SPEC, STARTFILE_SPEC): Delete. + * configure.in (i[34567]86-*-elf*): Add ${xm_file} and xm-svr4.h to + xm_file list. + +Fri Apr 10 10:42:42 1998 Nick Clifton + + * config/m32r/m32r.md: Add trailing newline. + + * rtl.c (read_skip_spaces): Prevent infinite loops upon + encountering unterminated comments. + + * config/arm/aout.c: Add CYGNUS LOCAL markers. + * config/arm/riscix.h: Add CYGNUS LOCAL markers. + * config/arm/riscix1-1.h: Add CYGNUS LOCAL markers. + * config/arm/semiaof.h: Add CYGNUS LOCAL markers. + * config/arm/t-linux: Add CYGNUS LOCAL markers. + * config/arm/thumb.h: Remove CYGNUS LOCAL markers. + * config/arm/thumb.c: Remove CYGNUS LOCAL markers. + +Thu Apr 9 16:26:53 1998 Nick Clifton + + * config/m32r/m32r.md: Add CYGNUS LOCAL markers. + * config/m32r/m32r.c: Add CYGNUS LOCAL markers. + * config/m32r/m32r.h: Add CYGNUS LOCAL markers. + * config/m32r/t-m32r: Add CYGNUS LOCAL markers. + + * config/arm/README-interworking: Added note about DLLs not + working. + + * config/arm/arm.c: Add CYGNUS LOCAL markers. + * config/arm/arm.h: Add CYGNUS LOCAL markers. + * config/arm/arm.md: Add CYGNUS LOCAL markers. + * config/arm/coff.h: Add CYGNUS LOCAL markers. + * config/arm/semi.h: Add CYGNUS LOCAL markers. + * config/arm/t-bare: Add CYGNUS LOCAL markers. + * config/arm/lib1funcs.asm: Add CYGNUS LOCAL markers. + +Thu Apr 9 12:57:05 1998 Alexandre Petit-Bianco + + * tree.def (EXPR_WITH_FILE_LOCATION): New tree node definition. + * tree.h (EXPR_WFL_{NODE,FILENAME,FILENAME_NODE,LINENO, + COLNO,LINECOL,SET_LINECOL,EMIT_LINE_NOTE}): New macros. + (build_expr_wfl): New prototype declaration. + * tree.c (build_expr_wfl): New function, to build + EXPR_WITH_FILE_LOCATION nodes. + (copy_node): Don't zero TREE_CHAIN if copying a + EXPR_WITH_FILE_LOCATION node. + * print-tree.c (print_node): Handle EXPR_WITH_FILE_LOCATION. + * expr.c (expand_expr): Handle EXPR_WITH_FILE_LOCATION. + +Thu Apr 9 12:14:40 1998 Jeffrey A Law (law@cygnus.com) + + * loop.c (loop_optimize): Call init_alias_analysis immediately after + reg_scan. + + * configure.in: Kill mpw. + * config.sub: Likewise. + +Wed Apr 8 15:08:57 1998 Jeffrey A Law (law@cygnus.com) + + * configure.in m68010-adobe-scout): Delete obsolete local config. + (m68k-apollo-sysv, m68k-tandem-*, m68*-netx,vxworks*): Likewise. + (mips-ncd-elf*, powerpc-*-netware*): Likewise. + * config.sub: Kill "scout" references. + + * configure.in: Completely disable objc unless --enable-objc is + specified at configure time. + * objc/Make-lang.in: Remove CYGNUS LOCAL hack. + + * configure.in: Reorganize local configurations to make + merging with egcs easier. + + * gcc.c (process_command): putenv only takes a single argument. + + * gcse.c: Include "system.h". + * Makefile.in (gcse.o): Add missing dependencies. + +Mon Apr 6 11:29:34 1998 Jeffrey A Law (law@cygnus.com) + + * gcse.c (pre_expr_reaches_here): First argument is the starting + basic block; add new arg check_pre_comp. All callers changed. + If !check_pre_comp, then do not require the expression to be set + in the starting basic block. + (pre_insert): Do not insert an expression if it does not reach + any deleted occurences of the expression. + +Mon Apr 6 07:17:52 1998 Catherine Moore + + * combine.c (can_combine_p): Include successor in volatile test. + +Fri Apr 3 15:59:35 1998 Jeffrey A Law (law@cygnus.com) + + * gcse.c (run_jump_opt_after_gcse): Renamed from gcse_jumps_altered. + All references changed. + (gcse_main): If we split any edges, then run jump optimizations + after gcse. + +Wed Apr 1 17:06:19 1998 Nick Clifton + + * config/arm/thumb.h: Add super interworking support. + * config/arm/thumb.c: Add super interworking support. + * config/arm/thumb.md: Add super interworking support. + * config/arm/tpe.h: Add super interworking support. + * config/arm/lib1funcs.asm: Add interworking support. + * config/arm/lib1thumb.asm: Add super interworking support. + * config/arm/t-pe: Add super interworking support. + * config/arm/t-semi: Add interworking support. + * config/arm/t-thumb: Add interworking support. + * config/arm/t-pe-thumb: Add super interworking support. + * config/arm/README-interworking: New file. + +Mon Mar 30 09:22:16 1998 Jeffrey A Law (law@cygnus.com) + + * mips.md (rotrsi3): Use GEN_INT instead of gen_rtx (CONST_INT). + (rotrdi3): Likewise. + +Mon Mar 30 12:27:21 1998 Nick Clifton + + * invoke.texi (ARM Options): Removed spurious @end table marker. + + * config/m32r/m32r.h (EXTRA_CONSTRAINT): Implement 'S' constraint + to perfoirm the equivalent of a negated 'I' constraint. + + * config/m32r/m32r.md (cmp_ne_small_const_insn): Use 'S' + constriant rather than 'I' since the value is negated. + +Sat Mar 28 13:03:22 1998 Nick Clifton + + * invoke.texi: Document more ARM and Thumb options. + +Fri Mar 27 16:15:29 1998 Michael Meissner + + * gcc.c (make_relative_prefix): If argv[0] does not contain a + directory separator, look up the name in the PATH environment + variable. + +Wed Mar 25 13:50:16 1998 Dave Brolley + + * cccp.c: Restore chill support. + +Tue Mar 24 10:44:11 1998 Nick Clifton + + * Makefile.in (gcov$(exeext)): Support .exe extension to gcov. + + * collect2.c (find_a_file): Add debugging. + (find_a_file): Test for win32 style absolute paths if + DIR_SERPARATOR is defined. + (prefix_from_string): Add debugging. + (main): Test for debug command line switch at start of program + execution. + (main): Use GET_ENVIRONMENT rather than getenv(). + +Sun Mar 22 16:15:45 1998 Nick Clifton + + * config/arm/tpe.h (ASM_DECLARE_FUNCTION_NAME): Include + .thumb_func directive in function header. + +Fri Mar 20 09:32:46 1998 Nick Clifton + + * objc/Make-lang.in: Apply patch from Geoff Noer (noer@cygnus.com) + to allow cygwin32 native toolchain builds via canadian crosses. + + * objc/Makefile.in: Apply patch from Geoff Noer (noer@cygnus.com) + to allow cygwin32 native toolchain builds via canadian crosses. + + * Makefile.in: Apply patch from Geoff Noer (noer@cygnus.com) to + allow cygwin32 native toolchain builds via canadian crosses. + + * config/i386/xm-cygwin32.h (PATH_SEPARATOR): Set to a semi-colon. + +Fri Mar 20 09:27:06 1998 Jeffrey A Law (law@cygnus.com) + + * pa.h (CPP_SPEC): Finish last change. + +Thu Mar 19 22:33:35 1998 Jeffrey A Law (law@cygnus.com) + + * configure.in (hppa1.1-hp-hpux11): Use pa-hpux11.h + (hppa1.0-hp-hpux11): Likewise. + * pa/pa-hpux11.h: New file. + + * pa.h (CPP_SPEC): If !ansi, then define __STDC_EXT__. + +Thu Mar 19 13:45:28 1998 Nick Clifton + + * config/i386/xm-cygwin32.h (GET_ENVIRONMENT): Patch resubmitted, + since it appears to have been lost in the shuffle.... + + * config/arm/thumb.c (arm_valid_machine_decl_attribute): Copied + from arm.c for thumb-pe builds. + + * config/arm/t-pe-thumb: New file: makefile fragement for thumb-pe + build. + + * config/arm/tpe.h: New file: PE support for thumb-pe build. + +Thu Mar 19 09:14:19 1998 Jeffrey A Law (law@cygnus.com) + + * configure.in: Handle hpux11 just like hpux10 for now. + +Wed Mar 18 11:21:16 1998 Nick Clifton + + * config/i386/xm-cygwin32.h (GET_ENVIRONMENT): Do not call + cygwin32_posix_path_list_p with a NULL or empty path. + +Wed Mar 18 09:33:13 1998 Nick Clifton + + * config/arm/thumb.c (arm_valid_machine_decl_attribute): New + function for thumb-pe support. + + * configure.in: Add thumb-pe target. + + * configure: Add thumb-pe target. + + * config.sub (maybe_os): Add thumb-pe target. + +Mon Mar 16 16:24:45 1998 Michael Meissner + + * gcc.c (make_relative_prefix): If directory is the same as + expected, or there are no directory separators, don't create a + relative pathname. + +Fri Mar 13 17:55:04 1998 Michael Meissner + + * i386/cygwin32.h (GET_ENVIRONMENT): Delete from here. + * i386/xm-cygwin32.h (GET_ENVIRONMENT): Move to here. + Initialize variable if not a posix style pathname. + +Fri Mar 13 17:54:04 1998 Michael Meissner + + * gcc.c (DIR_UP): If not defined, define as "..". + (standard_bindir_prefix): New static, holds target location to + install binaries. + (split_directories): New function to split a filename into + component directories. + (free_split_directories): New function, release memory allocated + by split_directories. + (make_relative_prefix): New function, make a relative pathname if + the compiler is not in the expected location. + (process_command): Use GET_ENVIRONMENT to read GCC_EXEC_PREFIX. + If GCC_EXEC_PREFIX was not specified, see if we can figure out an + appropriate prefix from argv[0]. + + * Makefile.in (gcc.o): Define STANDARD_BINDIR_PREFIX. + +Fri Mar 13 11:49:49 1998 Stan Cox + + * config/i386/cygwin32.h (GET_ENVIRONMENT): Defined to allow win32 + style environment paths. + +Thu Mar 12 16:22:03 1998 Stan Cox + + * sparc/liteelf.h (MULDI3,DIVDI3,UDIVDI3,MODDI3,UMODDI3)_LIBCALL: + Undefine solaris library routines. + +Thu Mar 12 13:21:38 1998 Nick Clifton + + * config/arm/arm.md (movsi, movhi, movhi_insn_arch4, + movho_insn_littleend, movhi_insn_bigend): Use + ok_integer_or_other(). + (movhi_insn_arch4): Swap order of 2nd and 3rd alternatives to + avoid problem in reload. + + * config/arm/arm.c: (find_barrier_insn): Return barrier insn, if + found, rather than insn after the barrier. + (ok_integer_of_other): New function, to avoid duplication in md + file. + + * config/arm/arm.h: Add prototype for ok_integer_or_other(). + +Wed Mar 11 14:28:30 1998 Jeffrey A Law (law@cygnus.com) + + * toplev.c (compile_file): Print out gcse time. + + * toplev.c (rest_of_compilation): Only rerun jump optimizations + after gcse if gcse changes some jumps. + +Wed Mar 11 15:21:52 1998 Michael Meissner + + * haifa-sched.c (schedule_insns): Remove debug statement. + +Wed Mar 11 15:44:54 1998 Gavin Koch + + * mips/mips.h (MASK_DEBUG_E): Redefine to zero. + +Tue Mar 10 12:20:57 1998 Stan Cox + + * sparc/liteelf.h (PREFERRED_DEBUGGING_TYPE): Make dwarf2 + the default debugging type. + +Mon Mar 9 16:29:34 1998 Michael Meissner + + * expr.c (expand_builtin): Add __builtin_expect code back in. + * rs6000.c (ccr_bit,print_operand): Ditto. + +Mon Mar 9 14:24:27 1998 J"orn Rennecke + + * t-sh (MULTILIB_OPTIONS): Add m4-single-only. + (MULTILIB_MATCHES): Remove m3e=m4-single-only. + +Sun Mar 8 23:46:29 1998 Stan Cox + + * configure, configure.in (sparclite-*-elf*): Added. + * sparc/liteelf.h: New file. + +Sat Mar 7 13:59:47 1998 J"orn Rennecke + + * d10v.h, generic.h (LOOP_ALIGN): Fix comment delimiter. + +Fri Mar 6 21:28:45 1998 J"orn Rennecke + + * d10v.h, generic.h (ASM_OUTPUT_ADDR_DIFF_ELT): New argument BODY. + * arm/thumb.h, i386/i386elf.h, m68k/st2000.h, z8k.h: Likewise. + * d30v.h: Likewise. + +Fri Mar 6 11:35:50 1998 Dave Brolley + + * gcse.c (hoist_code): Should return void. + +Thu Mar 5 23:45:08 1998 Jeffrey A Law (law@cygnus.com) + + * gcse.c: Bring back old classic gcse pass. + (gcse_main): If optimizing for code size perform classic gcse + instead of partial redundancy elimination. + +Thu Mar 5 09:09:08 1998 Catherine Moore + * config/v850/v850.h: Add option -mdisable-callt. + * config/v850/v850.md: Don't generate callt instructions if + -mdisable-callt has been specified. + +Thu Mar 5 09:09:08 1998 Catherine Moore + + * config/v850/lib1funcs.asm (___udivsi3): Don't use r5. + * config/v850/t-v850: Add -mno-app-regs to target build flags. + * config/v850/v850.h: Change STATIC_CHAIN_REGNUM from 5 to 20. + Add option -mno-app-regs. Add CONDITIONAL_REGISTER_USAGE macro. + +Thu Mar 5 14:39:45 1998 Fred Fish + + * config/d30v/d30v.h: Fix prematurely terminated comment. + +Tue Mar 3 09:12:04 1998 Nick Clifton + + * toplev.c: Do not generate a .dbr file when dumping RTL + unless DELAY_SLOTS is defined. + +Mon Mar 2 20:06:04 1998 J"orn Rennecke + + * generic.h (ASM_OUTPUT_LOOP_ALIGN, ASM_OUTPUT_ALIGN_CODE): + replace with: + (LOOP_ALIGN, ALIGN_LABEL_AFTER_BARRIER). + * d10v.h: Likewise. + * d30v.h: Likewise. + +Wed Feb 25 10:02:19 1998 Nick Clifton + + * config/arm/arm.md (movsfcc, movdfcc): Cope with constants that + cannot be placed into instructions. Patch supplied by Richard + Earnshaw. + +Sun Feb 22 22:05:33 1998 Jeffrey A Law (law@cygnus.com) + + * Use lazy code motion to drive placement partially redundant + expressions and register copies. + * First implementation of code hoisting pass. Currently + disabled due to code expansion. + * gcse.c: (compute_{cprop,pre}_local_properties): Combined into a + single function. Accepts additional arguments as needed. All + references updated. + (cprop_insn, cprop, one_cprop_pass): New arg to determine if jumps + can/should be altered. All references changed appropriately. + (insert_insn_end_bb): Renamed from pre_insert_insn. + (alloc_code_hoist_mem): New function for code hoisting. + (free_code_hoist_mem, compute_code_hoist_vbeinout): Likewise. + (compute_code_hoist_data, hoist_expr_reaches_here_p): Likewise. + (hoist_code, one_code_hoisting_pass): Likewise. + (gcse_main): Put check for setjmp at start of gcse_main and + generally clean up initialization. Do not allow cprop to + alter jumps until the last pass. Add appropriate calls to + code hoisting support (currently #ifdef'd out). + (compute_local_properties): New function for computing local + properties for pre, cprop and code hoisting. + (cprop_insn): Only cprop into jumps if alter_jumps is nonzero. + (pre_av{invout}, pre_pav{in,out}, pre_pp{in,out}): Delete old pre + variables. + (pre_early{in,out}, pre_delay{in,out}, pre_latein): New variables + for lazy code motion. + (pre_iso{in,out}, pre_optimal, pre_redundant, temp_bitmap): Likewise. + (pre_reundant_insns): Likewise. + (alloc_pre_mem, free_pre_mem): Updated for changes in pre variables. + (compute_pre_data): Likewise. + (compute_pre_avinout, compute_pre_ppinout): Deleted. + (compute_pre_earlyinout): New function for lazy code motion. + (compute_pre_delayinout, compute_pre_latein): Likewise. + (compute_pre_isoinout, compute_pre_optimal): Likewise. + (compute_pre_redundant): Likewise. + (pre_insert): Rework to only insert expressions at optimal + computation points as determined by lazy code motion. + (pre_insert_copies): Rework to only copy expressions where + necessary for lazy code motion. + (pre_delete): Rework to delete insns which are redundant at + not optimally placed. + (hoist_antloc, hoist_transp, hoist_comp): Variables for code hoisting. + (hoist_vbe{in,out}, hoist_exprs): Likewise. + (dominators, post_dominators): Likewise. + +Fri Feb 20 15:42:56 1998 Gavin Koch + + * mips/t-vr4100 (MULTILIB_OPTIONS, MULTILIB_DIRNAMES): + Add mno-mips16 and mips16. + * mips/elfb4100.h, mips/elfl4100.h (MULTILIB_DEFAULTS) : + Add "mno-mips16". + +Fri Feb 13 14:55:13 1998 Nick Clifton + + * config/m32r/m32r.md: Add peephole optimisation to cope with + PR14189, pending a better solution. + + * config/m32r/m32r.h (PRESERVE_DEATH_INFO_REGNO_P): Define in + order to allow peephole optimisation to work. + +Fri Feb 13 02:57:19 1998 J"orn Rennecke + + * d10v.h (DEFAULT_PCC_STRUCT_RETURN) Define as 0. + +Wed Feb 11 09:07:22 1998 Nick Clifton + + * config/m32r/m32r.h (ASM_SPEC): Pass on + --nmo-warn-explicit-parallel-conflicts to the assembler. +Mon Feb 9 09:53:41 1998 Nick Clifton + + * config/v850/v850.c (v850_output_local): Call + ASM_OUTPUT_ALIGNED_DECL_COMMON rather than ASM_OUTPUT_DECL_LOCAL + (which is not defined). + + * varasm.c (assemble_variable): Ditto. + +Fri Feb 6 14:55:28 1998 Nick Clifton + + * config/v850/v850ea.h: Remove multilibing and add -mUS-bit-set + command line option. + + * config/v850/v850e.h: Remove multilibing. + + * config/v850/v850.c (ep_memory_offset): Support new command line + options -msmall-sld and -mUS-bit-set to allow fine tuning of the + SLD.[BH] offsets. + * config/v850/v850.h: Ditto. + + * config/v850/t-v850: Remove multilibing and replace with single, + universal build using -mv850 and -msmall-sld command line options. + + +Fri Feb 6 09:19:12 1998 Gavin Koch + + * mips/elfb4100.h (DWARF2_DEBUGGING_INFO,PREFERRED_DEBUGGING_TYPE, + SUBTARGET_ASM_DEBUGGING_SPEC): Define. + * mips/elfl4100.h (DWARF2_DEBUGGING_INFO,PREFERRED_DEBUGGING_TYPE, + SUBTARGET_ASM_DEBUGGING_SPEC): Same. + +Fri Feb 6 02:53:28 1998 J"orn Rennecke + + * d10v.h (MUST_PASS_IN_STACK): Define. + + * d10v/libgcc1.asm (__cmpdi): Fix bug in last change. + + * d10v.md (movhi): Don't call force_reg while reloading. + (movsi): Handle case when reload asks us to use an uneven reg pair. + + Undo this change: + * va-d10v.h (__va_start_common): Add DELTA argument to subtract + from register number. + (va_start): Add DELTA argument to __va_start_common call, stdarg + passes 0, varargs needs to ignore last argument. + +Tue Feb 3 15:45:55 1998 Gavin Koch + + * mips/elfb4100.h (SUBTARGET_CPP_SPEC): Insure that __mips64 + is defined. + * mips/elfl4100.h (SUBTARGET_CPP_SPEC): Same. + +Sat Jan 31 02:18:52 1998 Jeffrey A Law (law@cygnus.com) + + * gcse.c (gcse_main): Fix minor typo in critial edge splitting code. + (pre_insert_insn): Correctly handle inserting code before a switch + table. + +Thu Jan 29 18:29:30 1998 Ian Lance Taylor + + * config/d30v/d30v.h (LINK_SPEC): Never specify -h. + +Wed Jan 28 16:43:49 1998 Nick Clifton + + * config/m32r/m32r.c zero_and_one, emit_cond_move): Add support + for MVFC instruction. + + * config/m32r/m32r.h: Ditto. + + * config/m32r/m32r.md: Ditto. + +Mon Jan 26 11:20:55 1998 Gavin Koch + + * configure.in (mips64vr4100-*-elf*,mips64vr4100el-*-elf*): + Add abi64.h to the tm_file list. + * configure: Rebuild. + * mips/elfb4100.h (MIPS_ABI_DEFAULT,SUBTARGET_CPP_SIZE_SPEC, + SUBTARGET_CPP_SPEC): Define. + * mips/elfl4100.h (MIPS_ABI_DEFAULT,SUBTARGET_CPP_SIZE_SPEC, + SUBTARGET_CPP_SPEC): Define. + +Sun Jan 25 21:46:07 1998 Michael Meissner + + * va-d10v.h (__va_start_common): Add DELTA argument to subtract + from register number. + (va_start): Add DELTA argument to __va_start_common call, stdarg + passes 0, varargs needs to ignore last argument. + + * d10v.c (emit_move_word): Use %. to emit code to access the 0 + register, not hardcoded r0. + + * d10v.md (movqi_internal): Use %. to emit code to access the 0 + register, not hardcoded r0. + +Fri Jan 23 13:50:42 1998 Jeffrey A Law (law@cygnus.com) + + * recog.c (validate_replace_src): Allow replacement in JUMP_INSNs. + * toplev.c (rest_of_compilation): Run loop optimizations after + gcse if gcse alters any jumps. + (flag_classic_gcse): Remove flag and all references. + * gcse.c: Clean up some comments, remove classic GCSE code, + variables, comments, etc. + (gcse_jumps_altered): New variable. + (gcse_main): Returns an int now. Fix return statements. Return + zero normally, return nonzero if gcse modifies any jumps. + (compute_preds_succs): Make sure last insn in the block is a + JUMP_INSN before passing it to condjump_p. + (cprop_insn): Handle constant/copy propagation into JUMP_INSNs. + * jump.c (jump_optimize): Delete (set (pc) (pc)) insns created + by gcse. + +Fri Jan 23 09:39:36 1998 Nick Clifton + + * toplev.c: Add -dM command line option to dump RTL after the + machine dependent reorganisation pass, if there is one. + Reorganise RTL dump code, so that only one file handle is + needed. + + * configure.in: Fix indentation of CYGNUS LOCAL markers. + + * configure: Add support for thumb-coff. + + * toplev.c (lang_options): Add -Wunknown-pragmas and + -Wno-unknown-pragmas. + +Fri Jan 23 11:20:19 1998 Michael Meissner + + * d10v.c (override_options): Use GPR_EVEN_P. + (override_options): Change to new ABI where args are in r0..r3, + r14 is zero register. Change names of register class to be + ARG{0,1,2,3}_REGS, not R{2,3,4,5}_REGS, and RETURN_REGS instead of + R13_REGS. + (print_operand{,_memory_reference}): Ditto. + (d10v_stack_info): Ditto. + (function_{pro,epi}logue): Ditto. + (emit_move_4words): Make refers_to_regno_p be type correct. + + * d10v.h (ARG_{FIRST,LAST}): Change to new ABI where args are in + r0..r3, r14 is zero register. Change names of register class to + be ARG{0,1,2,3}_REGS, not R{2,3,4,5}_REGS, and RETURN_REGS instead + of R13_REGS. + (GPR_ZERO_REGNUM): Ditto. + (SAVE_{ACC,GUARD}_REGNUM): Ditto. + ({FIXED,CALL_USED}_REGISTERS): Ditto. + (REG_ALLOC_ORDER): Ditto. + (reg_class): Ditto. + (REG_CLASS_{NAMES,CONTENTS}): Ditto. + (STATIC_CHAIN_REGNUM): Ditto. + ({FUNCTION,LIBCALL}_VALUE): Ditto. + (FUNCTION_VALUE_REGNO_P): Ditto. + + * d10v.md (32-bit shifts): Change to new ABI where args are in + r0..r3, r14 is zero register. Change names of register class to + be ARG{0,1,2,3}_REGS, not R{2,3,4,5}_REGS, and RETURN_REGS instead + of R13_REGS. + + * d10v/libgcc1.asm: Change to new ABI where args are in r0..r3, + r14 is zero register. Change names of register class to be + ARG{0,1,2,3}_REGS, not R{2,3,4,5}_REGS, and RETURN_REGS instead of + R13_REGS. + + * d10v/scrt0.asm (_start): Zero r14, not r0. + +Fri Jan 23 11:20:19 1998 J"orn Rennecke + + * d10v.h (CUMULATIVE_ARGS): Now a typedefed struct. + * d10v.c (init_cumulative_args): Access the appropriate members of cum. + (function_arg, setup_incoming_varargs): Likewise. + (function_arg_advance): When an argument doesn't fit in registers, + retain the remaining argument regsiters for possible use by + subsequent arguments. + * va-d10v.h (__va_list_tag): New three members. + (__va_start_common, va_arg): Update. + + * d10v.c (function_arg_boundary): Alignment for arguments starts + with an arguemnt size of four bytes. + (function_arg): No special case for structures > 4 bytes, if they + fit fully in the remaining argument passing registers, they are + passed in registers. + When an argument would exceed the remaining argument passing + registers, pass it fully on the stack. + (function_arg_advance): Likewise. In the latter case, mark remaining + argument passing registers as used. + (function_arg_partial_nregs): Remove. + * d10v.h (FUNCTION_ARG_PARTIAL_NREGS): Don't define. + + * va-d10v.h (enum __type_class): Remove. + (va_arg): Update. + +Thu Jan 22 10:45:40 1998 Nick Clifton + + * configure.in: Add thumb-*-coff target. + + * config/arm/thumb.c (number_of_first_bit_set): Only use inline + attribute when compiling with GCC. + + * config/arm/thumb.md (mulsi): Fix PR 14644. Patch supplied by + Jim Wilson. + + * config/arm/arm.c (output_func_epilogue): Fix PR14671 by changing + the logic for determining when stack unwinding code is needed. + +Wed Jan 21 11:01:49 1998 Nick Clifton + + * invoke.texi (M32R/D/X Options): Add documentation of -mcond-exec + option. + +Wed Jan 21 08:28:07 1998 Jeffrey A Law (law@cygnus.com) + + (gcse_main): If the first call to compute_preds_succs splits edges, + then call find_basic_blocks again and make another call to + compute_preds_succs. + +Tue Jan 20 16:01:03 1998 Anthony Green + + * invoke.texi (Optimize Options): -Os documentation. + * tm.texi (Run-time Target): New argument to OPTIMIZATION_OPTIONS. + * flags.h: New flag (optimize_size). + * toplev.c (main): Parse -Os option and set optimize_space + accordingly. + * gcc.c (default_compilers), cp/lang-specs.h, ch/lang-specs.h: Define + __OPTIMIZE_SIZE__ when compiling with -Os. + * config/dsp16xx/dsp16xx.h, config/i386/i386.h, + config/i386/dgux.h, config/i960/i960.h, config/pdp11/pdp11.h, + config/v850/v850.h, config/d10v/d10v.h, config/generic/generic.h + config/sh/sh.h (OPTIMIZATION_OPTIONS): New SIZE argument to macro. + * config/i386/i386.c (optimization_options): Accept new SIZE argument. + +Tue Jan 20 16:01:03 1998 Anthony Green + + * config/d30v/d30v.h (OPTIMIZATION_OPTIONS): New SIZE argument to + macro. + +Tue Jan 20 14:13:06 1998 Nick Clifton + + * config/m32r/m32r.md: Add support for conditional execution of + simple unary operators. Add support for conditional execution of + addtion of small constants. + + * config/m32r/m32r.h: Ditto. + + * config/m32r/m32r.c (generate_comparison, + unary_parallel_operator, emit_unary_cond_exec): Ditto. + +Tue Jan 20 12:46:37 1998 Jeffrey A Law (law@cygnus.com) + + * gcse.c (FOLLOW_BACK_EDGES): Enable. + + * gcse.c (dump_occr_list, replace_reg): Likewise. + (alloc_gcse_mem): Delete unused variables. + (compute_kill_rd, can_disregard_other_sets): Likewise. + (find_avail_set, pre_insert_copies, pre_gcse): Likewise. + (want_to_gcse_p): Add default case for switch statement. + (oprs_unchanged_p, hash_expr_1, compute_transp): Likewise. + (expr_equiv_p, oprs_not_set_p, expr_killed_p): Likewise. + (find_used_regs): Likewise. + (insert_expr_in_table): Initialize some variables to avoid + some gcc -Wall warnings. + (insert_set_in_table, handle_avail_expr): Likewise. + (handle_avail_expr): Remove some #if 0 code. + +Mon Jan 19 16:48:43 1998 Nick Clifton + + * config/m32r/m32r.md: Add conditional execution patterns for + simple binary operations. + * config/m32r/m32r.h: Add support for conditional execution + patterns. + * config/m32r/m32r.c (conditional_compare_operand, + binary_parallel_operator, emit_code_exec): New functions to + implement conditional execution of simple binary operations. + +Fri Jan 16 14:30:29 1998 Nick Clifton + + * config/arm/arm.md: PR 14644: Fix multiply patterns to prevent + contraint matching failure when all three registers are the same. + +Thu Jan 15 16:41:18 1998 Nick Clifton + + * config/m32r/m32r.h (PREDICATE_CODES): Add declaration of machine + specific predicates. + * config/m32r/m32r.md: Add patterns for simple conditional move + instructions. + + * config/m32r/m32r.c (gen_compare): Add support for parallel + instructions. + (reg_or_zero_operand): New function. + (conditional_move_operand): New function. + (carry_compare_operator): New function. + (emit_S_clause): New function. + (emit_cond_move): New function. + +Tue Jan 13 17:41:10 1998 Jim Wilson + + * cse.c (invalidate): Remove CYGNUS LOCAL patch. + +Mon Jan 12 16:35:04 1998 Nick Clifton + + * config/v850/v850.md: Removed duplicate entries. + +Mon Jan 5 17:22:09 1998 Michael Meissner + + * d30v.h (CONST_COSTS): Define as an empty instead of not defining + it. + +Wed Dec 31 12:30:03 1997 Nick Clifton + + * config/m32r/m32r.c (call_address_operand): Remove acceptance of + constant values and addresses held in registers. + +Wed Dec 31 12:26:53 1997 Nick Clifton + + * config/m32r/m32r.md: Add patterns for the CMPZ and CMPEQ + instructions. +Tue Dec 30 16:19:47 1997 Michael Meissner + + * d30v.c (d30v_return_addr_rtx): New static variable. + (override_options): Use SPECIAL_REG_P, not ARG_PTR_FIRST. + (d30v_stack_info): Note where link pointer is stored. + (d30v_function_epilogue): Reset d30v_return_addr_rtx. + (d30v_legitimate_address_p): Correctly test r1 for r0+r1 + addressing. + (d30v_emit_cond_move): Emit code to do a conditional move. If the + move is just the same as setcc or setcc of the reverse condition, + just emit that code instead. + (d30v_return_addr): Insert code to copy return address into a + temporary before saving it. + + * d30v.h (SPECIAL_REG_*): Delete ARG_PTR* macros, replace with + SPECIAL_REG_* macros. + ({FIXED,CALL_USED}_REGISTERS): Make registers easier to add new + registers, by starting each group on a separate line. + (REG_ALLOC_ORDER): Ditto. + (REGISTER_NAMES): Ditto. + (MASK_WORD3): Convert a register number into bitmask for 3rd word + of REG_CLASS_CONTENTS. + (*_MASK): Use MASK_WORD3 for each of the special/cr/flag/accum + registers. + (REG_CLASS_CONTENTS): Use the *_MASK macros. + ({,INCOMING_}RETURN_ADDR_RTX): Define. + (INCOMING_FRAME_SP_OFFSET): Ditto. + (ELIMINABLE_REGS): Simplify somewhat. + (d30v_emit_cond_move): Add declaration. + (d30v_return_addr): Ditto. + + * d30v.md (mov{qi,hi,si}cc): Use d30v_emit_cond_move to generate + conditional moves. + +Mon Dec 29 14:09:01 1997 Jim Wilson + + * configure.in (enable_fortran): Delete one too many '[' ']' levels. + +Mon Dec 29 14:38:50 1997 Ian Lance Taylor + + * mips/t-vr4100 (LIB2FUNCS_EXTRA): Add mips16.S. + * mips/t-vr4300: Likewise. + +Mon Dec 29 11:39:10 1997 Felix Lee (flee@cygnus.com) + + * gcse.c (pre_insert_insn): Deref maybe_cc0_setter only if non-NULL. + +Mon Dec 29 11:11:51 1997 Nick Clifton + + * config/m32r/m32r.h: Add support for second accumulator register. + + * config/m32r/m32r.c: Add support for second accumulator register. + +Mon Dec 29 11:06:16 1997 Jeffrey A Law (law@cygnus.com) + + * configure.in: Disable fortran by default. + +Tue Dec 16 23:08:00 1997 J"orn Rennecke + + * d10v.h (REG_OK_FOR_BASE_P): Fix non-strict definition. + + * d10v.c (function_arg): Don't pass DImode partially in registers. + (function_arg_pass_by_reference): Don't pass structs / unions by + reference. + +Tue Dec 16 20:12:39 1997 J"orn Rennecke + + * d10v.c (emit_comparison): Use CONSTANT_P to detect constant op1. + Check it for being a CONST_INT before using its value. + Use plus_constant_for_output to add to it. + Fix bug in output template for >= 32767. + +Tue Dec 16 11:17:12 1997 Nick Clifton + + * config/arm/arm.c (arm_override_options): Force apcs-32 mode if + interworking is specified. + +Fri Dec 12 18:54:23 1997 Per Bothner + + * expr.c (expand_builtin): Support BUILT_IN_FMOD - just call fmod. + +Fri Dec 12 23:09:29 1997 J"orn Rennecke + + * d10v.c (override_options): Fix regno_reg_class for registers + 1, 7, 9, 11 and 15. + + (d10v_subword): Fix word_num calculation for SUBREG. + + (emit_subtract): Carry is ! Borrow. + + (emit_comparison): Handle CONSTs. + +Fri Dec 12 07:37:49 1997 Michael Meissner + + * gcse.c (compute_can_copy): If AVOID_CCMODE_COPIES, don't bother + calling emit_insn/recog to set if we can copy CCmodes. + +Wed Dec 10 11:33:38 1997 Jeffrey A Law (law@cygnus.com) + + * gcse.c (compute_can_copy): Don't allow copies for CCmode values + if AVOID_CCMODE_COPIES is defined. + * mips.h (AVOID_CCMODE_COPIES): Define. + +Mon Dec 8 17:12:47 1997 Nick Clifton + + * config/arm/arm.c (all_architectures): Removed processor field. + +Wed Dec 3 10:44:25 1997 Gavin Koch + + * mips/mips.md (muldi3_r4000): Broaden the output template + and attribute assignments to handle three operand dmult; + rename to muldi3_internal2. + (muldi3): Call the new muldi3_internal2 for R4000, and + any GENERATE_MULT3 chip. + +Tue Dec 2 09:20:50 1997 Nick Clifton + + * config/arm/lib1funcs.asm: Add error condition if + __USER_LABEL_PREFIX__ is not defined. + + * config.sub: Add support for Thumb target. + + * configure: Add support for Thumb target. + +Tue Nov 25 19:10:56 1997 J"orn Rennecke + + * Makefile.in (fixproto-defines): New rule. + (fixhdr.ready): Depend on fixproto-defines. + (mostlyclean): Remove fixproto-defines. + (install-common): Don't create a temporary file, install the + ready-built fixproto-defines. + +Tue Nov 25 11:22:11 1997 Nick Clifton + + * config/arm/arm.c: Brought up to date with respect to devo and + branch. + * config/arm/aout.h: Ditto. + * config/arm/arm.h: Ditto. + * config/arm/arm.md: Ditto. + * config/arm/coff.h: Ditto. + * config/arm/lib1funcs.asm: Ditto. + * config/arm/pe.h: Ditto. + * config/arm/riscix.h: Ditto. + * config/arm/riscix1-1.h: Ditto. + * config/arm/semi.h: Ditto. + * config/arm/semiaof.h: Ditto. + * config/arm/t-bare: Ditto. + * config/arm/t-linux: Ditto. + * config/arm/aout.h: Ditto. + * config/arm/lib1thumb.asm: Imported from branch. + * config/arm/t-thumb: Imported from branch. + * config/arm/thumb.c: Imported from branch. + * config/arm/thumb.h: Imported from branch. + * config/arm/tcoff.h: Imported from branch. + * config/arm/thumb.md: Imported from branch. + * config/arm/xm-thumb.h: Imported from branch. + +Mon Nov 24 17:19:39 1997 Nick Clifton + + * config/arm/arm.md: Updated with changes in devo. + * config/arm/arm.c: Updated with changes in devo. + * config/arm/arm.h: Updated with changes in devo. + * config/arm/aout.h: Updated with changes in devo. + * config/arm/semi.h: Updated with changes in devo. + +Sat Nov 22 15:32:00 1997 Nick Clifton + + * gcc.c (SWITCH_CURTAILS_COMPILATION): Definition. + (DEFAULT_SWITCH_CURTAILS_COMPILATION): True for options -S and -c. + (process_command): If HAVE_EXECUTABLE_SUFFIX is defined then scan + command line arguments to see if an executable is not being + created, and if so - do not append the suffix. + + * tm.texi (SWITCH_CURTAILS_COMPILATION): Add description of new + driver macro. + +Sat Nov 22 01:01:41 1997 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (AR_FOR_TARGET): Clean up "-e" confustion with + program_transform_name. + (RANLIB_FOR_TARGET): Likewise. + +Tue Nov 11 22:38:02 1997 J"orn Rennecke + + * combine.c (nonzero_bits): For paradoxical subregs, take + LOAD_EXTENDED_OP into account. + +Mon Nov 10 20:53:11 1997 Gavin Koch + + * config/mips/mips.h (MASK_DEBUG_H): Set to zero, so this bit + is available elsewhere. + + +Local Variables: +add-log-time-format: current-time-string +End: diff --git a/gcc_arm/ChangeLog.lib b/gcc_arm/ChangeLog.lib new file mode 100755 index 0000000..7e03e76 --- /dev/null +++ b/gcc_arm/ChangeLog.lib @@ -0,0 +1,3781 @@ +Wed Jan 1 17:54:47 1998 J.J. van der Heijden + + * pexecute.c (pexecute, [_WIN32]): Yes, mask termstat for mingw32. + +Mon Dec 22 18:59:34 1997 Pascal Obry + + * pexecute.c (pexecute, [_WIN32]): For mingw32, don't mask termstat. + +Sat Dec 13 09:39:32 1997 Richard Kenner + + * pexecute.c (fix_argv): Remove outer "const" from return type. + (pexecute): errmsg_arg is pointer to const. + +Sat Nov 29 08:06:34 1997 Jan-Jaap van der Heijden + + * pexecute.c: Include signal.h for _WIN32. + +Wed Nov 26 17:31:44 1997 J.J. van der Heijden + + * pexecute.c (pwait): For _WIN32, distinguish whether child process + caught fatal signal or reported nonzero exit code. + +Wed Nov 26 13:24:30 1997 Richard Kenner + + * choose-temp.c (sys/file.h): Include if HAVE_SYS_FILE_H. + +Mon Nov 17 09:07:52 1997 Richard Kenner + + * choose-temp.c (choose_temp_base): Remove incorrect code for VMS. + +Sun Oct 19 10:34:11 1997 Richard Kenner + + * pexecute.c (fix_argv, pexecute): Cast result of xmalloc. + +Sat Oct 18 16:55:18 1997 Jason Merrill + + * obstack.h (obstack_empty_p): New macro. + +Mon Sep 29 12:27:59 1997 Ian Lance Taylor + + * pexecute.c: Use spawn if __CYGWIN32__. + +Wed Sep 10 15:14:20 1997 Jeffrey A Law (law@cygnus.com) + + * config.sub: Use "amigaos" instread of "amigados". Still + recognize "amigados" for backward compatability. + +Tue Sep 9 18:23:57 1997 Doug Evans + + * config.sub: Recognize ARC cpu. + +1997-09-09 Richard Kenner Richard Kenner + + * config.guess (alpha): Replace CPU-determining program with one + that's more precise and also supports pca56 and ev6. + Handle those in returned name. + +1997-09-08 Richard Kenner + + * config.guess (alpha:OSF1:*:*): For V4.0, get the letter suffix. + +1997-09-05 Jeffrey A Law (law@cygnus.com) + + * config.sub: Recognize v850-elf. + +1997-08-26 Richard Henderson + + * config.guess (*:Linux:*:*): Recognize alpha-linux-gnulibc1. + +1997-08-17 Jeff Law + + * config.sub: Recognize tx39/r3900. + +1997-08-08 Paul Eggert + + * choose-temp.c, pexecute.c: + Include "config.h" first, as per autoconf manual. + +1997-08-01 Richard Stallman + + * config.sub: Translate -svr4 to -sysv4 and -unixware to -sysv4.2uw. + +1997-07-26 Per Bothner + + * config.guess: Recognize SunOS 3.x. + From Tom Schmidt . + +1997-07-22 Richard Stallman + + * getloadavg.c: Test `__unix' along with `unix'. + +Sun Jul 20 20:58:43 1997 Richard Kenner + + * config.guess (alpha*): Run program to see if ev4, ev5, or ev56. + * config.sub (alphaev5, alphaev56): New CPU types. + +Wed Jul 16 10:46:14 1997 Richard Earnshaw + + * config.guess (arm32:NetBSD:*:*): Canonicalize to normal format + for ARM systems. + +Tue Jul 15 09:13:05 1997 Jim Meyering + + * getloadavg.c: Add comment describing HAVE_PSTAT_GETDYNAMIC. + +1997-07-14 Richard Stallman + + * config.guess (pc:*:*:*): New entry, for DJGPP. + +1997-07-07 Richard Stallman + + * config.guess (i?86:UNIX_SV:4.2MP:2.*): Recognize unixware. + +1997-07-06 Richard Stallman + + * getloadavg.c [OSF_ALPHA]: + Include sys/mbuf.h, sys/socket.h, net/route.h. + +1997-06-30 Richard Stallman + + * getloadavg.c [__GNU__]: Test for not NeXT. + +Fri Jun 27 15:20:29 1997 Scott Christley + + * config.sub (-mingw32*): New OS. + * config.guess (i*:MINGW*:*): New case. + * pexecute.c (fix_argv): New function. + (pexecute): Win32 but not Cygwin32 needs its arguments fixed. + Add underscore to cwait function call. + +Mon Jun 23 10:51:53 1997 Jeffrey A Law (law@cygnus.com) + + * config.sub (mn10200): Recognize new basic machine. + +1997-06-22 Richard Stallman + + * config.guess: Add mips-sony-newsos6. + +1997-06-09 Richard Stallman + + * config.guess: Use i?86, not i.86. + Don't test /usr/lib/ldscripts; instead, test whether ld_help_string + does not contain "supported emulations". + Use a case statement to distinguish systems when there IS + "supported emulations". + +1997-06-07 H.J. Lu (hjl@gnu.ai.mit.edu) + + * config.guess (*:Linux:*:*): Always use ${VENDOR}. + +1997-06-05 Richard Stallman + + * config.guess (*:Linux:*:*): Don't test for elf_i.86 or m68kelf. + + * config.guess (*:Linux:*:*): Recognize sparclinux. + Don't recognize UNAME_MACHINE = sparc. + Make the sample program check for libc version + and handle various machine types. + + * config.sub (mipsel*-linux* and mips*-linux*): + Set `os' to -linux-gnu directly, don't go via -linux. + +Mon May 26 12:46:25 1997 Paul Eggert + + * getopt.c, getopt.h, getopt1.c: Moved to libc-copy/copies. + +Wed May 7 15:17:59 1997 Thomas Bushnell, n/BSG + + * config.guess: Recognize either / or - as a machine/suptype + separator from uname -m to cope with older systems that have the + older uname. Suggested by Michael Snyder (msnyder@cygnus.com). + +Mon May 5 18:05:35 1997 Per Bothner + + * config.guess: CLIX patch from Thomas Dickey via + urs@akk.uni-karlsruhe.de (Urs Janssen). + +Thu Apr 17 13:59:13 1997 Per Fogelstrom + + * config.guess: Fixes for MIPS OpenBSD systems. + +Fri Apr 11 16:39:06 1997 Niklas Hallqvist + + * config.guess: Recognize OpenBSD systems correctly. + +Mon Mar 24 15:38:37 1997 Doug Evans + + * config.sub: Recognize m32r and mn10300 cpus. + +Sat Feb 22 22:36:44 1997 Miles Bader + + * getloadavg.c [__GNU__] (NeXT, host_self): New macros, to make + hurd systems use the NeXT code for getting load averages. + +Sat Feb 15 19:03:48 1997 Geoffrey Noer (noer@cygnus.com) + + * pexecute.c: Remove special cases for cygwin32. + (pwait): Remove local definition of `pid'. + +Wed Jan 15 22:36:59 1997 Jim Meyering + + * getloadavg.c [hpux && HAVE_PSTAT_GETDYNAMIC]: Use HPUX's + pstat_getdynamic function so we don't need any special privileges + to determine load averages. Patch from Kaveh Ghazi, based on a + sample implementation from Richard J. Rauenzahn. + Indent cpp-directives to reflect nesting. + +Tue Jan 7 14:29:37 1997 David J. MacKenzie + + * config.guess: Add hppa1.1-hitachi-hiuxmpp support, passed along + by rms. + +Sat Jan 4 22:43:21 1997 Miles Bader + + * config.guess (*:GNU:*:*): The machine/subtype separator printed + by uname -m is now `-', not '/'. + +Fri Jan 3 08:38:49 1997 Philippe De Muyter (phdm@info.ucl.ac.be) + + * config.guess (M68*:*:R3V[567]*:*): Use uppercase 'M'. + +Tue Dec 31 15:51:13 1996 Ian Lance Taylor + + * config.guess, config.sub: Recognize mips-unknown-linux-gnu. + +Tue Dec 10 09:44:57 1996 Paul Eggert + + * choose-temp.c (choose_temp_base): Don't dump core if TMPDIR is empty. + + * choose-temp.c (try): Insist that temp dir be searchable. + +Sat Dec 7 17:48:02 1996 Dave Love + + * config.guess (PENTIUM:CPunix:4.0*:*): New case. + +Sun Nov 24 19:41:31 1996 Per Bothner + + * config.guess: Recognize machten. + From Eric W. Bates . + +Sun Nov 24 18:17:53 1996 Dave Love + + * config.guess (PENTIUM:CPunix:4.0*:*): New case. + +Fri Nov 22 11:44:13 1996 David J. MacKenzie + + * config.guess: Undo accidental lowercasing in + m68k-motorola-sysv regexp. + +Wed Nov 20 16:27:37 1996 David J. MacKenzie + + * config.guess, config.sub: Additions for the Fujitsu UXP/V. + From joda@pdc.kth.se (Johan Danielsson). + +Tue Nov 19 13:34:12 1996 David J. MacKenzie + + * getpagesize.h: If no sys/param.h, default to 8k. + Indent for readability. + +Wed Nov 13 14:59:46 1996 Per Bothner + + * config.guess: Patch for Dansk Data Elektronik servers, + from Niels Skou Olsen . + + For ncr, use /bin/uname rather than uname, since GNU uname does not + support -p. Suggested by Mark Mitchell . + + Patch for MIPS R4000 running System V, + from Eric S. Raymond . + + Fix thinko for nextstep. + + Patch for OSF1 in i?86, from Dan Murphy via Harlan Stenn. + + Sat Jun 24 18:58:17 1995 Morten Welinder + * config.guess: Guess mips-dec-mach_bsd4.3. + + Thu Oct 10 04:07:04 1996 Harlan Stenn + * config.guess (i?86-ncr-sysv*): Emit just enough of the minor + release numbers. + * config.guess (mips-mips-riscos*): Emit just enough of the + release number. + + Tue Oct 8 10:37:22 1996 Frank Vance + * config.guess (sparc-auspex-sunos*): Added. + (f300-fujitsu-*): Added. + + Wed Sep 25 22:00:35 1996 Jeff Woolsey + * config.guess: Recognize a Tadpole as a sparc. + +Wed Nov 13 00:53:09 1996 David J. MacKenzie + + * config.guess: Don't assume that NextStep version is either 2 or + 3. NextStep 4 (aka OpenStep 4) has come out now. + +Tue Nov 12 18:26:15 1996 Doug Rupp (rupp@gnat.com) + + * pexecute.c (vfork): Supply new definition for VMS. + (pwait): Use waitpid instead of wait for VMS. + +Mon Nov 11 23:52:03 1996 David J. MacKenzie + + * config.guess: Support Cray T90 that reports itself as "CRAY TS". + From Rik Faith . + +Fri Nov 8 11:34:58 1996 David J. MacKenzie + + * config.sub: Contributions from bug-gnu-utils to: + Support plain "hppa" (no version given) architecture, reported by + OpenStep. + OpenBSD like NetBSD. + LynxOs is not a hardware supplier. + + * config.guess: Contributions from bug-gnu-utils to add support for: + OpenBSD like NetBSD. + Stratus systems. + More Pyramid systems. + i[n>4]86 Intel chips. + M680[n>4]0 Motorola chips. + Use unknown instead of lynx for hardware manufacturer. + +Mon Oct 28 17:15:52 1996 Christian Limpach + + * config.sub: Recognize hppa-next as a valid CPU-COMPANY combination. + +Wed Oct 23 17:36:39 1996 Doug Rupp (rupp@gnat.com) + + * choose-temp.c (choose_temp_base): On VMS, use proper syntax + for current directory. + +Wed Oct 9 23:30:18 1996 Jim Meyering + + * getloadavg.c: [__hpux]: Define hpux. From Eric Backus. + [__sun]: Define sun. Reported by Kaveh Ghazi. + +Mon Sep 23 22:45:15 1996 Sean McNeil + + * config.sub (-vxsim*): New operating system. + + 1996-09-12 Richard Stallman + + * config.guess: Use pc instead of unknown, for pc clone systems. + Change linux to linux-gnu. + +Thu Sep 12 20:12:26 1996 Richard Stallman + + * config.sub: Use pc instead of unknown, for pc clones. + Use -linux-gnu for Linux-based GNU systems. + +1996-09-04 Richard Stallman + + * getloadavg.c (getloadavg): Add new code for SUNOS_5 to use -lkstat. + +Sat Aug 17 15:23:39 1996 Geoffrey Noer + + * choose-temp.c: Delete !defined(_WIN32) condition when including + sys/file.h (NO_SYS_FILE_H is still used). + * getopt.c: Change win32 test from WIN32 to _WIN32. + * pexecute.c: Update test for win32 (&& ! cygwin32). + +Mon Jul 15 23:51:11 1996 Karl Heuer + + * config.guess: Avoid non-portable tr syntax. + +Mon Jul 15 11:53:00 1996 Jeffrey A Law (law@cygnus.com) + + * config.guess (HP 9000/811): Recognize this as a PA1.1 + machine. + +Thu Jul 11 17:02:23 1996 David J. MacKenzie + + * install-sh: Add MIT copyright notice. From gordoni@cygnus.com. + +Sun Jul 7 13:27:04 1996 Joel Sherrill + + * config.sub: Recognize rtems as an o/s. + +Tue Jul 2 16:45:02 1996 Torbjorn Granlund + + * config.guess: Generalize C90 alternative to all x90 machines. + +Fri Jun 28 13:29:05 1996 Richard Kenner + + * config.guess (mips:*:*:UMIPS): Fix typo in last change. + +Tue Jun 25 22:43:48 1996 Doug Evans + + * pexecute.c (PEXECUTE_VERBOSE): Define. + (MPW pexecute): Check flags & PEXECUTE_VERBOSE instead of verbose_flag. + +Mon Jun 24 14:32:22 1996 Jim Wilson + + * getopt.c (getpid): Don't redefine it if __CYGWIN32__ is defined. + +Thu Jun 20 12:20:33 1996 Michael Meissner + + * config.guess (*:Linux:*:*): Add support for PowerPC Linux. + +Mon Jun 10 16:10:57 1996 Doug Evans + + * pexecute.c: New file. + +Fri Jun 7 18:16:52 1996 Harlan Stenn + + * config.guess (i?86-ncr-sysv*): Emit minor release numbers. + Recognize the NCR 4850 machine and NCR Pentium-based platforms. + +Wed Jun 5 00:09:17 1996 Per Bothner + + * config.guess: Combine mips-mips-riscos cases, and use cpp to + distinguish sysv/svr4/bsd variants. + Based on a patch from Harlan Stenn . + +Mon Jun 3 08:49:14 1996 Karl Heuer + + * config.guess (*:Linux:*:*): Add guess for sparc-unknown-linux. + +Mon May 27 20:16:42 1996 Karl Heuer + + * getloadavg.c [SOLARIS2]: Define SUNOS_5. + +Fri May 24 18:34:53 1996 Roland McGrath + + * config.guess (AViiON:dgux:*:*): Fix typo in recognizing mc88110. + +Wed May 22 17:20:59 1996 Roland McGrath + + * getloadavg.c [WIN32]: No-op as for [MSDOS]. + + * getopt.c [WIN32] (getpid): Define using GetCurrentProcessId. + + * getopt.c [VMS]: Include unixlib.h, string.h. + +Tue May 21 18:55:59 1996 Roland McGrath + + * config.sub: Restore `hp9k2[0-9][0-9] | hp9k31[0-9])' case line + apparently accidentally removed in the last change. + +Mon May 20 11:58:15 1996 Jeffrey A. Law + + * config.sub: Recognize -proelf as a basic system type. + +Fri May 3 02:35:56 1996 Noah Friedman + + * mkinstalldirs: Don't report an error if mkdir fails because + a directory was created by another process. + +Sun Apr 21 09:50:09 1996 Stephen L Moshier (moshier@world.std.com) + + * choose-temp.c: Include sys/types.h before sys/file.h for sco3.2v5. + +Tue Apr 9 14:37:31 1996 Ulrich Drepper + + * obstack.h [__STDC__] (obstack_init, obstack_begin, + obstack_specify_allocation, obstack_specify_allocation_with_arg, + obstack_chunkfun, obstack_freefun): Duplicate definition with complete + type cast. + +Wed Apr 17 14:28:43 1996 Doug Evans + + * choose-temp.c: Don't include sys/file.h ifdef NO_SYS_FILE_H. + #include . + (choose_temp_base): Make tmp,usrtmp, static locals. + +Mon Apr 15 14:08:12 1996 Doug Evans + + * choose-temp.c: New file. + +Fri Apr 12 20:03:59 1996 Per Bothner + + * config.guess: Combine two OSF1 rules. + Also recognize field test versions. From mjr@zk3.dec.com. + + * config.guess (dgux): Use /usr/bin/uname rather than uname, + because GNU uname does not support -p. From pmr@pajato.com. + +Mon Apr 8 16:16:20 1996 Michael Meissner + + * config.guess (prep*:SunOS:5.*:*): Turn into + powerpele-unknown-solaris2. + +Thu Mar 28 02:06:03 1996 Roland McGrath + + * error.c (_): New macro, define iff undefined. + (private_strerror): Use it for message string. + (error_at_line): New function. + (error_one_per_line): New variable. + * error.h (error_at_line, error_one_per_line): Declare them. + +Thu Mar 21 14:42:26 1996 Doug Evans + + * config.sub (os): sunos[3456] -> sunos[34], + sunos[56] have their own entries. + +Wed Mar 20 09:59:30 1996 Roland McGrath + + * signame.c [HAVE_STRING_H]: Include string.h. + +Tue Mar 19 20:07:39 1996 Roland McGrath + + * alloca.c (NULL): Define only if not already defined. + + * alloca.c [HAVE_STRING_H]: Include string.h. + [HAVE_STDLIB_H]: Include stdlib.h. + +Thu Mar 14 19:12:52 1996 Ian Lance Taylor + + * config.guess: Recognize mips-*-sysv*, with a specific case for + NEC (which has its own compiler and libraries). + +Sat Mar 9 23:52:33 1996 Jim Meyering (meyering@na-net.ornl.gov) + + * getdate.y (RelativeMonth): Add 1900 to the year so that relative + date specs that push the year through the end of the century work. + For example, `date -d "01/01/1998 3 years" +%Y' now prints 2001. + From Peter Dalgaard (pd@kubism.ku.dk). + +Tue Mar 5 18:43:43 1996 Richard Henderson + + * config.sub: Add -apple and -aux. + +Tue Mar 5 03:02:53 1996 Erik Naggum + + * config.sub (moss): Fix previous change. + +Mon Mar 4 18:03:38 1996 Bryan Ford (baford@cs.utah.edu) + + * config.sub: Accept -moss* as op sys. + +Fri Mar 1 09:57:54 1996 Roland McGrath + + * config.sub: Recognize cpu-vendor [ctj]90-cray, default + c90-cray-unicos. From tege. + +Wed Feb 28 19:55:05 1996 Miles Bader + + * getopt.c (_getopt_internal): Always set OPTOPT to *something* if + returning '?', so it can be distinguished from an option. + +Thu Feb 22 15:51:09 1996 Karl Heuer + + * getdate.y (Convert): Accept dates beyond 1999. + +Tue Feb 13 13:20:32 1996 Miles Bader + + * getopt.c (_getopt_internal): Give FIRST_NONOPT & LAST_NONOPT + rational values if OPTIND has been moved back by the user. + +Mon Feb 12 18:23:35 1996 Doug Evans + + * config.sub: Recognize sparclet cpu. + +Sun Feb 11 18:40:11 1996 Richard Stallman + + * config.sub: Fix typo in previous change. + +Sat Feb 10 08:28:12 1996 Martin Anantharaman + + * config.sub (-psos*): New case. + +Thu Feb 8 15:37:52 1996 Brendan Kehoe + + * config.guess (UNAME_VERSION): Recognize X4.x as an OSF version. + +Sun Feb 4 16:51:11 1996 Steve Chamberlain + + * config.guess (*:CYGWIN*): New + +Mon Feb 12 15:33:59 1996 Christian Bauernfeind + + * config.guess: Support m68k-cbm-sysv4. + +Sat Feb 10 12:06:42 1996 Andreas Schwab + + * config.guess (*:Linux:*:*): Guess m68k-unknown-linux and + m68k-unknown-linuxaout from linker help string. Put quotes around + $ld_help_string. + +Wed Feb 7 15:31:09 1996 Roland McGrath + + * getopt.c [__GNU_LIBRARY__]: Include . + + * getopt.c (nonoption_flags, nonoption_flags_len): New variables. + (_getopt_initialize): If not POSIXLY_CORRECT, check for special + environment variable from Bash 2.0 and set those vars from it. + (_getopt_internal): Do not consider as options argv elts whose + nonoption_flags elt from the shell is '1'. + +Thu Feb 1 09:10:02 1996 Steve Chamberlain + + * config.sub (-cygwin32): New. + +Wed Jan 31 14:13:25 1996 Richard Henderson + + * config.sub: Add support for A/UX. + * config.guess: Recognize A/UX. + +Tue Jan 23 13:15:50 1996 Roland McGrath + + * obstack.h [__STDC__] (struct obstack, _obstack_begin, + _obstack_begin_1): Use prototypes in function decls. + * obstack.c (CALL_CHUNKFUN, CALL_FREEFUN): Cast function type for + call w/o extra_arg. + + * error.c (error_print_progname) [__STDC__]: Declare with + prototype. + [_LIBC]: Include errno.h to declare program_invocation_name. + + * getopt.c [__STDC__] (exchange, _getopt_initialize): Declare + prototypes for these. + +Mon Jan 22 08:53:45 1996 Roland McGrath + + * xmalloc.c [__STDC__] (fixup_null_alloc): Declare prototype. + +Sun Jan 21 01:08:09 1996 Roland McGrath + + * error.h: Declare error_print_progname. Add comments. + +Wed Jan 17 17:39:51 1996 Richard Stallman + + * config.sub: Default OS to nextstep if machine vendor is Next. + -ns2 is an alias for -nextstep. + +Wed Jan 17 09:51:58 1996 Doug Evans + + * config.sub: Recognize go32* as an os. + +Sun Jan 7 02:00:27 1996 Karl Heuer + + * alloca.c (alloca): If malloc fails, just abort. + +Mon Jan 15 20:59:49 1996 J. Kean Johnston + + * config.sub (sco5): New case. + +Tue Dec 19 15:56:15 1995 Eli Zaretskii + + * getloadavg.c (getloadavg) [MSDOS]: Return 0 load instead of + failing the call. + +Fri Dec 15 22:34:08 1995 Stan Coxs + + * config.guess (AViiON): Add ix86-dg-dgux + * config.sub (i*86*) Change [345] to [3456] + +Thu Dec 7 09:03:24 1995 Tom Horsley + + * config.guess (powerpc-harris-powerunix): Add guess for port + to new target. + +Wed Dec 6 09:44:53 1995 Paul Eggert + + * install-sh (transformbasename): Fix misspelling in initialization. + +Wed Dec 6 06:58:23 1995 Richard Earnshaw (rearnsha@armltd.co.uk) + + * config.sub: Recognize aof in the OS field. + +Tue Dec 5 18:36:41 1995 Roland McGrath + + * error.c [_LIBC]: Adapt for use in GNU libc. + +Mon Dec 4 13:21:51 1995 Jeffrey A. Law + + * config.guess: Recognize HP model 816 machines as having + a PA1.1 processor. + +Thu Nov 30 16:57:33 1995 Per Bothner + + * config.guess: Recognize Pentium under SCO. + From Robert Lipe . + +Tue Nov 21 16:59:12 1995 Richard Stallman + + * getdate.y: If config.h defines FORCE_ALLOCA_H, include alloca.h. + +Mon Oct 16 11:34:00 1995 Jeffrey A. Law + + * config.guess: Recognize HP model 819 machines as having + a PA 1.1 processor. + +Sat Sep 30 14:03:17 1995 Roland McGrath + + * getopt.c (_): New macro, define if not already defined. + (gettext): Never define as a macro. + (_getopt_internal): Use ``_("message")'' instead of + `gettext ("message")''. + +Mon Aug 14 19:27:56 1995 Per Bothner + + * config.guess (*Linux*): Add missing "exit"s. + Also, need specific check for alpha-unknown-linux (uses COFF). + +Fri Jul 28 00:16:31 1995 Jeffrey A. Law + + * config.guess: Recognize lynx-2.3. + +Thu Jul 27 13:31:05 1995 Fred Fish (fnf@cygnus.com) + + * config.guess (*:Linux:*:*): First try asking the linker what the + default object file format is (elf, aout, or coff). Then if this + fails, try previous methods. + +Mon Aug 7 16:48:13 1995 Roland McGrath + + * getloadavg.c [ps2]: Use nlist instead of knlist #ifdef _AIX. + +Fri Aug 4 10:27:54 1995 Jim Meyering (meyering@comco.com) + + * getopt.c (_getopt_internal) [lint]: Initialize INDFOUND to + avoid warning from gcc. + +Tue Aug 1 14:29:43 1995 Roland McGrath + + * getloadavg.c (getloadavg): Set FD_CLOEXEC flag on /dev/kmem file + descriptor. + +Wed Jul 26 00:26:34 1995 David J. MacKenzie + + * mkinstalldirs: Remove weird unnecessary shell construction. + +Wed Jun 28 17:57:27 1995 David Edelsohn + + * config.guess (AIX4): More robust release numbering discovery. + +Thu Jun 22 19:01:24 1995 Kenneth Stailey (kstailey@eagle.dol-esa.gov) + + * config.guess (i386-sequent-ptx): Properly get version number. + +Thu Jun 22 18:36:42 1995 Uwe Seimet (seimet@iris1.chemie.uni-kl.de) + + * config.guess (mips:*:4*:UMIPS): New case. + +Tue Jun 20 02:41:41 1995 Roland McGrath + + * getloadavg.c [convex] (LOAD_AVE_TYPE, LDAV_CVT): Define to + double, no conversion. + + * obstack.c (OBSTACK_INTERFACE_VERSION): New macro. Rewrote + conditionals to use that macro to ensure that the installed GNU + libc supports the interface the obstack.h corresponding to this + obstack.c needs, and only then elide the code in this file. + +Sun May 28 18:53:29 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * config.guess (21064:Windows_NT:50:3): New case. + +Fri May 19 16:52:50 1995 Roland McGrath + + * error.c (error_message_count): New variable. + (error): Increment it. + * error.h: Declare error_message_count. + +Mon May 15 17:47:55 1995 Per Bothner (bothner@spiff.gnu.ai.mit.edu) + + * config.guess: Recognize Cray90 (from Pete TerMaat). + +Thu May 11 17:13:14 1995 Per Bothner (bothner@wombat.gnu.ai.mit.edu) + + * config.guess: Recognize PCs running Solaris2. + (Patch from Bruno Haible .) + * config.guess: Merge two CRAY*Y-MP entries. + Ignore system field for Cray xmp and cray2 since "uname -s" on + a Cray gets you the hostname, which is useless. + (According to Pete TerMaat .) + +Wed May 10 11:03:56 1995 Roland McGrath + + * getloadavg.c: AIX support from Tim Bell : + [_AIX] (LOAD_AVE_TYPE, FSCALE, NLIST_STRUCT): Define these for AIX. + (getloadavg) [_AIX]: Use `knlist' instead of `nlist'. + +Fri May 5 05:50:56 1995 Allen Briggs (briggs@puma.bevd.blacksburg.va.us) + + * config.guess: Add more NetBSD cases: atari, sun3*, and mac68k. + +Wed May 3 16:22:31 1995 Richard Stallman + + * crt0.c: Add APOLLO alternative. + +Sat Apr 29 15:48:03 1995 Roland McGrath + + * signame.c: Move include of config.h before all others. + +Thu Apr 27 11:33:29 1995 Michael Meissner (meissner@cygnus.com) + + * config.guess (*:Linux:*:*): Check for whether the pre-BFD linker is + installed, and if so return linuxoldld as the system name. + +Thu Apr 27 13:11:11 1995 Jim Meyering (meyering@comco.com) + + * error.h: Use __-protected versions of `format' and `printf' + attributes only with gcc-2.7 and later. + +Thu Apr 27 09:22:33 1995 Peder Chr. Norgaard + + * config.guess (i[34]86:*:3.2:*) test for /usr/options/cb.name + before calling uname. + +Wed Apr 26 17:19:34 1995 Roland McGrath + + * signame.c [HAVE_UNISTD_H]: Include unistd.h so it can declare + sys_siglist. + +Wed Apr 26 14:00:00 1995 Michael Meissner (meissner@cygnus.com) + + * config.guess (*:Linux:*:*): Determine whether the default compiler is + a.out or ELF based. + (parisc*:Lites*:*:*): New entry from Jeff Law. + +Wed Apr 26 11:48:21 1995 Jim Meyering (meyering@comco.com) + + * error.h: New file. + +Wed Apr 26 10:27:50 1995 Travis L Priest (T.L.Priest@larc.nasa.gov) + + * config.guess (CRAY*Y-MP:*:*:*): New entry. + +Wed Apr 26 12:54:26 1995 Jeffrey A. Law + + * config.guess: Add hppa1.1-hp-lites support. + +Thu Apr 6 19:55:54 1995 Richard Stallman + + * crt0.c [__bsdi__]: Maybe declare __progname. + +Fri Mar 24 00:52:31 1995 Roland McGrath + + * getopt.c (_getopt_internal): When optind is zero, bump it to 1 + after initializing; we don't want to scan ARGV[0], which is the + program name. + +Tue Mar 21 16:44:37 1995 Roland McGrath + + * signame.c (signame_init): Define SIGINFO. + +Tue Mar 7 01:41:09 1995 Roland McGrath + + * signame.c (strsignal): Cast sys_siglist elt to char *. + +Thu Feb 23 18:42:16 1995 Roland McGrath + + * signame.h [! __STDC__]: Don't use prototype for strsignal decl. + +Wed Feb 22 19:08:43 1995 Niklas Hallqvist (niklas@appli.se) + + * config.guess: Recognize NetBSD/Amiga as m68k-cbm-netbsd. + +Tue Feb 21 22:13:19 1995 Roland McGrath + + * signame.h (strsignal): Declare it. + * signame.c [! HAVE_STRSIGNAL] (strsignal): New function. + +Wed Feb 8 10:03:36 1995 David J. MacKenzie + + * install-sh config.guess mkinstalldirs: Add a blank in the #! + line for 4.2BSD, Dynix, etc. + +Sat Feb 4 12:59:59 1995 Jim Wilson + + * config.guess (IRIX): Sed - to _. + +Sat Jan 28 20:09:49 1995 Daniel Hagerty + + * error.c: Under older versions of SCO, strerror is a preprocessor + macro. Added a check for this. + +Fri Jan 27 09:55:28 1995 Jim Meyering (meyering@comco.com) + + * getdate.y: Remove obsolete comments. Rewrite others. + +Mon Jan 23 19:41:57 1995 Karl Heuer + + * config.guess (i[34]86:*:3.2:*): Test for ISC before SCO; newer + ISC releases have uname -X. + +Tue Jan 10 09:26:41 1995 Jim Meyering (meyering@comco.com) + + * getdate.y (ToSeconds): Interpret 12am as 00:00 and 12pm as 12:00. + Before, `date -d 'Jan 1 12am'' printed `...12:00:00...'. + From Takeshi Sone . + +Sat Jan 7 11:57:40 1995 Roland McGrath + + * getloadavg.c: Include config.h first. + +Wed Jan 4 15:52:17 1995 Per Bothner (bothner@spiff.gnu.ai.mit.edu) + + * config.guess: Recognize BSD/OS as bsdi. + Patch from Chris Torek . + +Wed Dec 21 15:51:08 1994 Warner Losh (imp@boulder.openware.com) + + * config.guess (sun4:SunOS:*:*): Handle Solbourne OS/MP systems. + +Tue Dec 6 02:29:42 1994 Roland McGrath + + * config.guess (dummy.c) [sony]: Include and emit + newsos4 #ifdef NEWSOS4. + +Tue Nov 29 17:01:29 1994 Mark Dapoz (md@bsc.no) + + * config.guess (ibmrt): Add more cases for various forms of BSD. + +Tue Nov 29 16:19:54 1994 Paul Eggert + + * getopt.c (_getopt_internal): Add gettext wrappers around + message strings. + + * xmalloc.c (fixup_null_alloc): Add gettext wrapper. + Capitalize initial letter of error message, for consistency + with regex.c. + +Fri Nov 25 19:22:24 1994 Roland McGrath + + * crt0.c (start1): Add self reference. + +Wed Nov 23 16:51:11 1994 R. Bernstein (rocky@panix.com) + + * config.guess: Add cases for romp-ibm-aix and romp-ibm-bsd. + +Mon Nov 14 19:03:29 1994 Per Bothner (bothner@spiff.gnu.ai.mit.edu) + + * config.guess: Support paragon as i860-intel-osf1. (From RMS.) + +Fri Nov 11 14:04:58 1994 Andreas Luik (luik@isa.de) + + * obstack.h: Add one missing test on value of __STDC__. + +Sat Nov 05 08:08:52 1994 Jim Meyering (meyering@comco.com) + + * obstack.h: NextStep 2.0 cc is really gcc 1.93 but it defines + __GNUC__ = 2 and does not implement __extension__. So add + `|| (__NeXT__ && !__GNUC_MINOR__)' to the test for whether to + define-away __extension__. Reported by Kaveh Ghazi. + +Thu Nov 03 14:36:58 1994 Jim Meyering (meyering@comco.com) + + * filemode.c (rwx): Use S_IRUSR, S_IWUSR, S_IXUSR instead of + obsolete S_IREAD, S_IWRITE, S_IEXEC. + Make sure the former three are defined. + +Tue Nov 1 14:24:39 1994 Per Bothner (bothner@spiff.gnu.ai.mit.edu) + + * config.guess (*-unknown-freebsd): Remove [-(] from + UNAME_RELEASE. Patch from Warner Losh . + +Mon Oct 31 07:02:15 1994 Roland McGrath + + * getopt.h: Change #if __STDC__ to #if defined (__STDC__) && + __STDC__. + * getopt.c: Change #ifndef __STDC__ to #if !defined (__STDC__) || + !__STDC__. + * getopt1.c: Likewise. + * obstack.c: Change #ifdef __STDC__ to #if defined (__STDC__) && + __STDC__. + * obstack.h: Likewise. + +Wed Oct 26 20:34:59 1994 Roland McGrath + + * getloadavg.c [alliant && i860] (FSCALE): Move defn before + #ifndef FSCALE. + +Tue Oct 25 19:10:41 1994 Paul Eggert + + * xmalloc.c (fixup_null_alloc): New function. + (xmalloc, xrealloc): Use it to fix up returned NULL values, + instead of preemptively adjusting a zero N to 1. + +Tue Oct 25 11:22:30 1994 David J. MacKenzie + + * xmalloc.c (xmalloc, xrealloc): If 0 bytes requested, pretend + it's 1, for diff. + +Thu Oct 20 18:47:53 1994 Per Bothner (bothner@wombat.gnu.ai.mit.edu) + + * config.guess: Better support for NCR - covers more machines, + and prints sysv4.3 if uname says the OS is 4.3. + Patch from Tom McConnell . + +Wed Oct 19 15:55:38 1994 David J. MacKenzie + + * config.guess: Add licensing exception for Autoconf. + +Tue Oct 18 19:26:31 1994 David Edelsohn (edelsohn@npac.syr.edu) + + * config.guess: Revise support for AIX 4.1 on POWER and PowerPC. + +Mon Oct 17 19:16:38 1994 David Edelsohn + + * config.guess: Add support for AIX 4.1 and architecture. + +Wed Oct 12 16:51:35 1994 David J. MacKenzie (djm@duality.gnu.ai.mit.edu) + + * error.c: Add hook for alternate name printing function. + From Franc,ois Pinard. + Use varargs for _doprnt too. + + * xmalloc.c: Add hook for alternate exit status. + From Franc,ois Pinard. + +Mon Oct 10 17:35:19 1994 Roland McGrath + + * getpagesize.h: If NBPC is not defined, try PAGESIZE. + +Fri Oct 07 18:53:28 1994 Jim Meyering (meyering@comco.com) + + * filemode.c: Remove #if 0'd block around mode_t definition. + From Andreas Luik (luik@marx.isa.de). + +Thu Oct 06 21:15:16 1994 Jim Meyering (meyering@comco.com) + + * pathmax.h: Fix typo: HAVE_SYS_PATH_MAX_H -> HAVE_SYS_PARAM_H. + From Andreas Schwab (schwab@issan.informatik.uni-dortmund.de). + +Thu Oct 6 18:02:32 1994 Per Bothner (bothner@wombat.gnu.ai.mit.edu) + + * config.guess: Patch from Chris Smith + to handle old Convex systems without uname. + +Tue Oct 4 03:02:39 1994 Richard Stallman + + * getdate.y (main): Use MAX_BUFF_LEN consistently. + Clear the last element of buf. + +Mon Oct 3 01:48:48 1994 Roland McGrath + + * config.guess: Recognize GNU. + +Thu Sep 29 18:47:34 1994 Jerry Frain (jerry@sneffels.tivoli.com) + + * config.guess (i[34]86:UNIX_SV:4.*:*): Remove "UNIX_SV" for + Unixware; move DYNIX above this one now that this is wildcard. + +Wed Sep 28 17:00:12 1994 Roland McGrath + + * getloadavg.c [alliant && i860] (LOAD_AVE_TYPE, FSCALE, + NLIST_STRUCT): Define. + +Mon Sep 26 17:53:05 1994 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu) + + * alloca.c error.c filemode.c getopt.c getopt1.c getdate.y + getloadavg.c getugroups.c getusershell.c signame.c: + Remove CONFIG_BROKETS ifdef. No one should use "config.h". + +Sat Sep 24 21:20:12 1994 Jim Meyering (meyering@comco.com) + + * getdate.y [struct _TABLE]: Add `const' to NAME member dcl. + +Fri Sep 23 02:39:55 1994 Richard Stallman + + * crt0.c [__FreeBSD__] (__progname): Declared. + +Tue Sep 20 23:27:02 1994 Richard Stallman + + * getdate.y: Whitespace reformatted. + (MAX_BUFF_LEN): New macro. + (main): Use fgets, not gets. Use MAX_BUFF_LEN to declare buff. + +Mon Sep 19 18:25:40 1994 Per Bothner (bothner@kalessin.cygnus.com) + + * config.guess (HP-UX): Patch from Harlan Stenn + to also emit release level. + +Wed Sep 7 13:15:25 1994 Jim Wilson (wilson@sphagnum.cygnus.com) + + * config.guess (sun4*:SunOS:*:*): Change '-JL' to '_JL'. + +Fri Sep 16 20:16:36 1994 Richard Stallman + + * getloadavg.c (getloadavg): Add OSF_ALPHA support. + +Fri Sep 16 18:34:22 1994 Paul Eggert + + * getdate.y (difftm): Don't store a long value into an int variable. + +Thu Sep 08 00:26:29 1994 Jim Meyering (meyering@comco.com) + + * getdate.y: Accept `MESZ' timezone. + +Sun Aug 28 18:13:45 1994 Per Bothner (bothner@kalessin.cygnus.com) + + * config.guess (*-unknown-freebsd*): Get rid of possible + trailing "(Release)" in version string. + Patch from Paul Richards . + +Sat Aug 27 15:00:49 1994 Per Bothner (bothner@kalessin.cygnus.com) + + * config.guess: Fix i486-ncr-sysv43 -> i486-ncr-sysv4.3. + Fix type: *-next-neststep -> *-next-nextstep. + +Sat Jun 4 17:23:54 1994 Per Bothner (bothner@kalessin.cygnus.com) + + * configure.in: Use mh-ncrsvr43. Patch from + Tom McConnell . + +Sat Aug 27 17:21:04 1994 Jim Meyering (meyering@comco.com) + + * filemode.c [STAT_MACRO_BROKEN]: Remove spurious #ifdef's. + +Fri Aug 26 19:17:22 1994 Per Bothner (bothner@spiff.gnu.ai.mit.edu) + + * config.guess (netbsd, freebsd, linux): Accept any machine, + not just i[34]86. + +Fri Aug 26 18:45:25 1994 Philippe De Muyter (phdm@info.ucl.ac.be) + + * config.guess: Recognize powerpc-ibm-aix3.2.5. + +Fri Aug 26 15:12:50 1994 Per Bothner (bothner@kalessin.cygnus.com) + + * config.guess: Merges from Cygnus version. + (alpha-dec-osf*): More general. + (*-hp-hpux*): Combine cases. + (*-next-ns[23]): Rename to *-next-neststep[23]. + Make code fragment shorter. + (config.guess, i386-unknown-bsd): Don't recognize __bsdi__ here; + it is handled using uname. + + Sat Jul 16 12:03:08 1994 Stan Shebs (shebs@andros.cygnus.com) + + * config.guess: Recognize m88k-harris-csux7. + + Tue Jun 28 13:43:25 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config.guess: Recognize Mach. + + Wed Apr 6 20:44:56 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * config.guess: Add SINIX support. + + Sun Mar 6 23:13:38 1994 Hisashi MINAMINO (minamino@sra.co.jp) + + * config.guess: about target *-hitachi-hiuxwe2, fixed + machine guessing order. [Hitachi's CPU_IS_HP_MC68K + macro is incorrect.] + + Thu Feb 24 07:09:04 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * config.guess: Handle OSF1 running on HPPA processors + + Fri Feb 11 15:33:33 1994 Stu Grossman (grossman at cygnus.com) + + * config.guess: Add Lynx/rs6000 config support. + +Thu Aug 25 20:28:51 1994 Richard Stallman + + * config.guess (Pyramid*:OSx*:*:*): New case. + (PATH): Add /.attbin at end for finding uname. + (dummy.c): Handle i860-alliant-bsd. Follow whitespace conventions. + +Wed Aug 17 18:21:02 1994 Tor Egge (tegge@pvv.unit.no) + + * config.guess (M88*:DolphinOS:*:*): New case. + +Thu Aug 11 17:00:13 1994 Stan Cox (coxs@dg-rtp.dg.com) + + * config.guess (AViiON:dgux:*:*): Use TARGET_BINARY_INTERFACE + to select whether to use ELF or COFF. + +Thu Jul 28 19:16:24 1994 Uwe Seimet (seimet@chemie.uni-kl.de) + + * config.guess: Recognize m68k-atari-sysv4. + +Sun Jul 24 16:20:53 1994 Richard Stallman + + * config.guess: Recognize i860-stardent-sysv and i860-unknown-sysv. + +Sat Jul 23 02:15:01 1994 Karl Heuer (karl@hal.gnu.ai.mit.edu) + + * config.guess (isc): Distinguish isc from generic sysv32. + +Mon Jul 11 23:55:13 1994 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * getopt.c (posixly_correct): New variable. + (_getopt_initialize): Set posixly_correct from envvar. + (_getopt_internal): Don't use "illegal" in error message + unless posixly_correct. + +Sun Jul 03 08:46:58 1994 Jim Meyering (meyering@comco.com) + + * pathmax.h: Add HAVE_SYS_PARAM_H to and remove !MS_DOS from + preprocessor conditional guarding inclusion of sys/param.h. + +Mon Jun 20 23:45:34 1994 Jim Meyering (meyering@comco.com) + + * modechange.c (mode_compile) [lint]: Initialize CHANGE to suppress + used uninitialized compiler warning. + +Wed Jun 15 19:07:49 1994 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * config.guess (alpha): Supoort OSF/1 V2.0 and later. + +Tue Jun 14 17:50:05 1994 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * obstack.h (obstack_grow{,0}): Cast WHERE to char * before + passing to bcopy. + +Mon Jun 6 04:59:28 1994 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * config.guess: Add support for bsdi. + +Sat Jun 4 01:24:59 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * getloadavg.c: Put #include of errno.h and decl of errno before + #ifndef HAVE_GETLOADAVG. + +Thu Jun 2 13:42:39 1994 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * alloca.c [emacs]: Block input around the garbage reclamation. + Include blockinput.h. + +Tue May 10 16:53:55 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * config.guess: Add trap cmd to remove dummy.c and dummy when + interrupted. + +Sun May 1 10:23:10 1994 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * config.guess: Guess the OS version for HPUX. + +Wed Apr 27 15:14:26 1994 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * install.sh: If $dstdir exists, don't check whether each + component does. + +Mon Apr 25 14:39:06 1994 Poul-Henning Kamp (phk@login.dkuug.dk) + + * config.guess: Recognize FreeBSD. + +Sun Apr 24 17:56:58 1994 Jim Meyering (meyering@comco.com) + + * getdate.y (difftm, get_date): Revert my April 18 changes. + Paul Eggert pointed out that that hack probably wouldn't work + for places like Chile that had DST in effect on 31 Dec 1970. + * (get_date): Instead, add 60 minutes to timezone if DST is in + effect locally. From andy@eng.kvaerner.no (Andrew Walker). + Remove static declaration of `RCS.' + +Fri Apr 22 22:15:28 1994 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * install.sh: Add -d, -t, -b options. Make leading directories. + Don't partially install files. + From zoo@cygnus.com. + +Wed Apr 20 18:07:13 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * config.guess (dummy.c): Redirect stderr for `hostinfo' command. + (dummy): Redirect stderr from compilation of dummy.c. + +Wed Apr 20 06:36:32 1994 Philippe De Muyter (phdm@info.ucl.ac.be) + + * config.guess: Recognize UnixWare 1.1 (UNAME_SYSTEM is SYSTEM_V + instead of UNIX_SV for UnixWare 1.0). + +Mon Apr 18 22:01:27 1994 Jim Meyering (meyering@comco.com) + + * getdate.y (difftm): Remove function. + (get_date): Get timezone *without DST bias* from localtime(&zero). + Modeled after the hack in localtime.pl from the perl distribution. + This fixes an error that had `date -d '4apr94'' producing + `Sun Apr 3 23:00:00 CDT 1994'. + +Fri Apr 15 22:46:59 1994 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * getdate.y: Delete special alloca code. + +Tue Apr 12 15:05:08 1994 Noah Friedman (friedman@prep.ai.mit.edu) + + * config.guess: Merge rms' new entry for i486-ncr-sysv4 with the + previously existing one. + +Mon Apr 11 00:54:33 1994 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * getopt.c [not __GNU_LIBRARY__] [__GCC__] [not __STDC__]: + Declare strlen to return int. Don't include stddef.h. + + * config.guess: Add 3[34]??,3[34]??:*:4.0:* for i486-ncr-sysv4. + +Sat Apr 9 14:59:28 1994 Christian Kranz (kranz@sent5.uni-duisburg.de) + + * config.guess: Distinguish between NeXTStep 2.1 and 3.x. + +Fri Apr 1 00:38:17 1994 Jim Wilson (wilson@mole.gnu.ai.mit.edu) + + * obstack.h, getopt.c: Delete use of IN_GCC to control whether + stddef.h or gstddef.h is included. + +Fri Mar 25 23:01:17 1994 David J. MacKenzie (djm@geech.gnu.ai.mit.edu) + + * mkinstalldirs: Preserve leading slash in file names. + From Jim Meyering. + +Sun Mar 20 01:29:20 1994 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * alloca.s [emacs]: Use <...> to include config.h. + +Tue Mar 1 21:53:03 1994 Karl Heuer (kwzh@hal.gnu.ai.mit.edu) + + * config.guess (UNAME_VERSION): Recognize aix3.2.4 and aix3.2.5. + +Thu Feb 24 14:54:23 1994 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu) + + * getopt.c: Remove #ifdef GETOPT_COMPAT and #if 0 code. + (_getopt_initialize): New function, broken out of _getopt_internal. + (_getopt_internal): + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + +Thu Feb 10 14:44:16 1994 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * getopt.c [not __GNU_LIBRARY__] [__GNUC__] [not IN_GCC]: + Test just __STDC__, not emacs. + +Wed Feb 9 17:46:31 1994 Karl Heuer (kwzh@mole.gnu.ai.mit.edu) + + * getdate.y (difftm): Simplify return expression. + +Wed Feb 9 00:14:00 1994 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * getopt.c [not __GNU_LIBRARY__] [__GNUC__] [not IN_GCC] + [emacs] [not __STDC__]: Don't include stddef.h. Don't declare strlen. + +Tue Feb 8 14:14:31 1994 David J. MacKenzie (djm at douglas.gnu.ai.mit.edu) + + Handle obstack_chunk_alloc returning NULL. This allows + obstacks to be used by libraries, without forcing them + to call exit or longjmp. + * obstack.c (_obstack_begin, _obstack_begin_1, _obstack_newchunk): + If CALL_CHUNKFUN returns NULL, set alloc_failed, else clear it. + (_obstack_begin, _obstack_begin_1): Return 1 if successful, 0 if not. + * obstack.h (struct obstack): Add alloc_failed flag. + _obstack_begin, _obstack_begin_1): Declare to return int, not void. + (obstack_finish): If alloc_failed, return NULL. + (obstack_base, obstack_next_free, objstack_object_size): + If alloc_failed, return 0. + (obstack_grow, obstack_grow0, obstack_1grow, obstack_ptr_grow, + obstack_int_grow, obstack_blank): If alloc_failed, do nothing that + could corrupt the obstack. + (obstack_chunkfun, obstack_freefun): New macros, used in GDB. + +Sun Jan 30 17:58:06 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * config.guess: Recognize vax hosts. + +Mon Jan 24 18:40:06 1994 Per Bothner (bothner@kalessin.cygnus.com) + + * config.guess: Clean up NeXT support, to allow nextstep + on Intel machines. Make OS be nextstep. + +Sun Jan 23 18:47:22 1994 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * config.guess: Add alternate forms for Convex. + +Thu Jan 6 14:00:23 1994 david d `zoo' zuhn (zoo@cygnus.com) + + * config.guess: add support for Tektronix 68k and 88k boxes; + better Apollo, Sony NEWS information + +Sun Dec 26 03:58:32 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * filemode.c (ftypelet): Don't use mode_t. Take long arg. + (mode_t): Don't ever define it. + (mode_string): Cast ftypelet's arg to long. + +Fri Dec 24 19:43:00 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * getopt.c (_NO_PROTO): Define before config.h is included. + +Wed Dec 22 17:01:19 1993 Jim Meyering (meyering@comco.com) + + * getdate.y (date): Parse dates like 17-JUN-1991. + +Tue Dec 07 14:52:39 1993 Jim Meyering (meyering@comco.com) + + Mon Dec 6 11:13:07 1993 Jason Merrill (jason@deneb.cygnus.com) + + * getdate.y (number): Change parsing of number > 10000 to + YYMMDD rather than YYHHmm. + +Sat Nov 20 17:47:50 1993 Noah Friedman (friedman@gnu.ai.mit.edu) + + * error.c (error): fflush stdout before writing to stderr. + +Tue Nov 09 10:05:48 1993 Jim Meyering (meyering@comco.com) + + * getdate.y (ToSeconds): Add a `default: abort ();' case. + +Thu Nov 4 12:59:19 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) + + * config.guess: add support for {i386,m68k,sparc} LynxOS; Hitachi + HPPA machines; Acorn Risc Machines; DG/UX; Motorola SVr3 on m88k + +Wed Nov 3 08:06:08 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c (getloadavg) [__NetBSD__]: Fix typo. + +Tue Nov 02 16:03:41 1993 Jim Meyering (meyering@comco.com) + + * getdate.y [!defined(USG) && defined(HAVE_FTIME)]: Don't test + these when deciding whether to include sys/timeb.h. Test only + HAVE_SYS_TIMEB_H. + +Sat Oct 16 23:31:34 1993 Jim Meyering (meyering@comco.com) + + * getusershell.c (getusershell): Always return a string allocated + by malloc. + +Tue Oct 12 00:53:26 1993 Jim Meyering (meyering@comco.com) + + * getugroups.c [HAVE_CONFIG_H, CONFIG_BROKETS]: Include + or "config.h". + * getusershell.c: Ditto. + +Thu Oct 07 19:08:00 1993 Jim Meyering (meyering@comco.com) + + * getdate.y [!__GNUC__ && !HAVE_ALLOCA_H]: Declare alloca as void* + rather than char*. The latter conflicts with a dcl from bison.simple. + +Tue Oct 05 14:52:02 1993 Jim Meyering (meyering@comco.com) + + * error.c [CONFIG_BROKETS]: Include only under + this condition, else "config.h". + * modechange.c: Likewise. + + * filemode.c, modechange.c [STAT_MACROS_BROKEN]: Test this. + +Sun Oct 3 15:33:07 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c (getloadavg) [__NetBSD__]: New netbsd support using + /kern/loadavg. + +Mon Sep 20 15:59:03 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * alloca.c [emacs || CONFIG_BROKETS]: Include only under + these, else "config.h". + * filemode.c: Likewise. + * signame.c, getloadavg.c, getopt.c, getopt1.c: Likewise. + +Wed Sep 15 00:03:40 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * config.guess: New version from Cygnus; has netbsd support. + +Mon Sep 13 19:25:24 1993 david d 'zoo' zuhn (zoo@geech.gnu.ai.mit.edu) + + * config.guess: add support for OSF/1 v1.3 and 4.4 and 4.3BSD + on hp300 machines + +Fri Sep 10 00:22:04 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * config.guess: Recognize netbsd on i[34]86 and hp300. + + * alloca.c: Include instead of "config.h". + * crt0.c: Likewise. + * filemode.c: Likewise. + * getdate.y: Likewise. + +Fri Aug 27 10:27:13 1993 Paul Eggert (eggert@twinsun.com) + + * xmalloc.c: Include "config.h" if HAVE_CONFIG_H. Use size_t, + not int, when needed. + (VOID): New macro. Use it when needed. + (error): Declaration uses varargs if required. + +Fri Aug 27 09:59:26 1993 Paul Eggert (eggert@wombat.gnu.ai.mit.edu) + + * error.c: Include "config.h" if HAVE_CONFIG_H. + +Wed Aug 25 17:46:01 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * signame.c [! HAVE_SYS_SIGLIST] [! SYS_SIGLIST_DECLARED]: Declare + sys_siglist. + +Mon Aug 16 15:10:30 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * alloca.c: Reverse sense of GCC 2 #ifdef. + +Sat Aug 14 23:26:30 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * config.guess: Detect mips-mips-ricos... + Handle 9000/4??:HP-UX like 9000/3??:HP-UX. + Fix 9000/7??:4.3bsd... + +Thu Aug 12 16:18:12 1993 Paul Eggert (eggert@twinsun.com) + + * getdate.y (get_date): To determine the time zone, compare localtime + to gmtime output, instead of trying to use buggy and unportable + OS timezone primitives. + (difftm): New function. + (HAVE_GETTIMEOFDAY): Remove. + (timezone): Undef it if defined (not if sgi). + +Thu Aug 12 18:16:49 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c, getopt.c, getopt1.c [HAVE_CONFIG_H]: Include + instead of "config.h". + +Wed Aug 11 03:27:12 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * alloca.c: Do nothing if compiling with GCC version 2. + +Tue Aug 10 17:27:27 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * alloca.c: Always declare malloc, whether or not it is defined + as xmalloc. + +Sat Aug 7 16:55:06 1993 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu) + + * getopt1.c: Declare const the way getopt.c does. + +Mon Aug 2 16:48:14 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c [OSF_ALPHA]: #undef and redefine FSCALE. + +Sun Aug 1 16:39:00 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c [TEST] (main): If NAPTIME is zero, don't set it to 5. + Break out of loop at end if NAPTIME is zero. + [! HAVE_GETLOADAVG]: Protect all but [TEST] portion with this. + +Fri Jul 30 18:28:40 1993 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu) + + * getpagesize.h: Don't define HAVE_GETPAGESIZE; assume + configure has detected it. + +Thu Jul 29 23:20:52 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c [__linux__]: Test this instead of [LINUX]. + +Mon Jul 26 13:36:55 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c (OSF_ALPHA): Test [__alpha] as well as [__alpha__]. + + * signame.h (psignal) [!HAVE_PSIGNAL]: Don't test [! HAVE_SYS_SIGLIST]. + * signame.c (psignal) [!HAVE_PSIGNAL]: Test this instead of + [! HAVE_SYS_SIGLIST]. + + * getloadavg.c [sgi || sequent]: #undef FSCALE before defining it. + +Wed Jul 21 17:08:07 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * obstack.c [__STDC__]: Declare prototype for _obstack_allocated_p. + +Wed Jul 14 00:55:24 1993 Jim Blandy (jimb@wookumz.gnu.ai.mit.edu) + + * config.guess: Add case for Bull dpx/2. + +Tue Jul 13 12:38:13 1993 Jim Meyering (meyering@comco.com) + + * alloca.c: Enable the Cray stack-segment unwinding code only + if configure defines CRAY_STACKSEG_END. The C-90 doesn't need + (and can't use) any of the Cray-specific code. + +Mon Jul 12 18:13:16 1993 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu) + + * getloadavg.c (getloadavg) [NEXT]: It's ok if the user asks + for >1 numbers -- just return 1. + +Wed Jul 7 14:03:45 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * getopt.c: Separate __STDC__ conditional from const conditional. + +Tue Jul 6 19:03:25 1993 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu) + + * getloadavg.c (getloadavg) [SUNOS_5]: Set `offset' from + kvm_nlist. Don't do the nlist but do initialize the struct + nlist for use by kvm_nlist. + +Mon Jun 28 14:55:05 1993 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu) + + * pathmax.h: Use !__GNUC__ instead of USG to check for whether + to include limits.h on non-POSIX systems. + +Sat Jun 26 15:26:13 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * getopt.c [not __GNU_LIBRARY__, but __GNUC__] (strlen): + Include stddef.h or gstddef.h, and declare strlen. + +Fri Jun 25 15:44:11 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getopt.c (exchange): Declare missing variables I. + +Tue Jun 22 00:03:11 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * getopt.c (exchange): Use just one slot of temporary space. + (alloca, __alloca): All definitions deleted. + (my_bcopy): All definitions deleted. + +Wed Jun 16 17:09:47 1993 Jim Blandy (jimb@wookumz.gnu.ai.mit.edu) + + * crt0.c: [hp9000s300, ! OLD_HP_ASSEMBLER] Add flag_68040 to + the list of flags already present. + +Thu Jun 10 16:28:34 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * config.guess: New version from Cygnus. + +Wed Jun 9 16:28:36 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c [! LOAD_AVE_TYPE]: Protect LOAD_AVE_TYPE definitions + with this. Use "#if defined (ardent) && defined (titan)", instead + of the bogus "#ifdef ardent && titan". Fix typo tex4300 -> tek4300. + +Wed Jun 9 05:19:56 1993 Jim Blandy (jimb@wookumz.gnu.ai.mit.edu) + + * getopt.c: Remove "|| defined(__sgi)" from the conditions for + #including "alloca.h"; autoconf ought to be able to figure + this out accurately, and that change was supposedly made for + the sake of Emacs, which does use autoconf. + + * getloadavg.c: Break up #if lines longer than 256 characters, + for VMS. + +Tue Jun 8 07:56:45 1993 Jim Blandy (jimb@wookumz.gnu.ai.mit.edu) + + * config.guess: Add clause to the first big case statement to + detect Motorola Delta 68k, up to r3v7. + +Sun Jun 6 03:52:21 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * filemode.c: Include config.h if HAVE_CONFIG_H. + (mode_t): Define, if NO_MODE_T. + +Fri May 28 03:21:21 1993 Jim Blandy (jimb@geech.gnu.ai.mit.edu) + + * getopt.c: If __sgi is defined, #include too. + +Mon May 24 20:43:38 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * alloca.c [!emacs]: Define malloc as xmalloc. Declare xmalloc. + +Mon May 24 17:40:32 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c (getloadavg) [OSF_MIPS]: Don't define + LDAV_PRIVILEGED. Cast LOAD_AVE.tl_lscale to double. + +Mon May 24 11:53:18 1993 Jim Blandy (jimb@wookumz.gnu.ai.mit.edu) + + * alloca.c: Make this safe for Emacs. + [! emacs] Declare malloc. + (alloca): Call malloc, not xmalloc. + +Mon May 24 00:59:13 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * getloadavg.c (getloadavg) [NO_GET_LOAD_AVG]: Just fail. + +Sun May 23 21:56:11 1993 Jim Blandy (jimb@wookumz.gnu.ai.mit.edu) + + * getdate.y [__GNUC__] (alloca): #undef this before we give + our new definition. + +Sun May 23 13:53:12 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * alloca.c: Call xmalloc (once again). + [emacs]: Define xmalloc as malloc. + [!emacs]: Declare xmalloc. + +Sun May 23 05:47:31 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * mkinstalldirs (errstatus): New variable. + Use inner `for' loop instead of `while test' on $#. + +Sat May 22 20:14:23 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * mkinstalldirs: Set IFS to % instead of / and use sed to translate + /s in the directory name into %s first. Initialize PATHCOMP always + to empty. + +Fri May 21 19:32:43 1993 Jim Blandy (jimb@geech.gnu.ai.mit.edu) + + * alloca.c (free): Don't #define this to be xfree whenever + emacs is #defined. That's only appropriate for some of the + files in Emacs which use alloca. + (xmalloc): Remove this declaration. It's inappropriate. + (alloca): Call malloc, not xmalloc. + +Thu May 20 16:22:12 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c (getloadavg) [LINUX]: Close FD if read fails. + Check return value of sscanf. + +Wed May 19 21:16:24 1993 Jim Blandy (jimb@wookumz.gnu.ai.mit.edu) + + * getloadavg.c (getloadavg): Add support for Linux, from + Michael K. Johnson. + +Wed May 19 13:47:02 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c [__osf__ && (mips || __mips__)]: Include + and #define OSF_MIPS. + (getloadavg) [OSF_MIPS]: Special code using `table'. + +Mon May 17 15:55:47 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c [butterfly]: Define NLIST_STRUCT; not LOAD_AVE_TYPE. + +Sun May 16 22:00:06 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * a.out.gnu.h [sequent && i386] (N_MAGIC, N_MACHTYPE, N_FLAGS, + N_SET_INFO, M_SET_MAGIC, N_SET_MACHTYPE, N_SET_FLAGS, [OZN]MAGIC, + N_BADMAG, N_ADDRADJ, N_DATOFF, N_TRELOFF, N_SYMOFF, N_TXTADDR, + N_COMM, N_FN, PAGE_SIZE, SEGMENT_SIZE): Define. + +Sat May 15 00:50:03 1993 Jim Meyering (meyering@comco.com) + + * getdate.y: Fix the time.h versus sys/time.h problem once and + for all. Packages that use this file should use autoconf's + AC_TIME_WITH_SYS_TIME and AC_HAVE_HEADERS(sys/time.h) macros. + +Fri May 14 16:38:56 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c [butterfly] (LOAD_AVE_TYPE): Define as long. + +Thu May 13 01:49:31 1993 Jim Meyering (meyering@comco.com) + + * error.c: Move extern dcl of program_name out of error. + +Sun May 9 15:21:11 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c [HPUX && ! hpux]: Define hpux. + +Sat May 8 20:35:04 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * getloadavg.c: Rename initialized to getloadavg_initialized. + +Sat May 8 13:32:15 1993 Jim Meyering (meyering@comco.com) + + * alloca.c: Indent and reformat comments. + + * alloca.c (i00afunc): New functions for determining relative + stack frame ordering for Crays. From Otto Tennant. + +Fri May 7 15:54:30 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c [NeXT]: Include #ifdef + HAVE_MACH_MACH_H, else . + +Wed May 5 13:31:55 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c (LDAV_SYMBOL) [hpux && ! hp9000s300]: Use this + conditional, not just [hpux], to define as "avenrun". + + * getloadavg.c [unix && m68k && mc68000 && mc68020 && + _MACH_IND_SYS_TYPES]: Define tek4300. + [tek4300] (LOAD_AVE_TYPE): Define as long. + [tek4300] (FSCALE): Define as 100.0. + +Mon May 3 22:17:45 1993 Jim Meyering (meyering@comco.com) + + * getugroups.c: Don't define GETGROUPS_T. Now configure does it. + +Mon May 3 17:12:41 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c (getloadavg) [VMS]: Don't define LDAV_DONE. + + * getloadavg.c [ardent && titan] + (LOAD_AVE_TYPE): Define as long. + (FSCALE): Define as 65536.0. + (LDAV_SYMBOL): Define as "avenrun". + +Tue Apr 27 14:07:18 1993 Jim Blandy (jimb@geech.gnu.ai.mit.edu) + + * getdate.y: If HAVE_SYS_TIMEB_H is #defined, then include + instead of defining struct timeb ourselves. + +Thu Apr 22 17:23:42 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c (getloadavg) [!LDAV_DONE && LOAD_AVE_TYPE && !VMS]: + Don't #define LDAV_DONE here. + [!LDAV_DONE && LOAD_AVE_TYPE]: Define it here instead. + +Mon Apr 19 18:09:18 1993 Jim Meyering (meyering@comco.com) + + * getdate.y: Use TM_IN_SYS_TIME. + +Fri Apr 16 18:10:06 1993 Jim Blandy (jimb@wookumz.gnu.ai.mit.edu) + + * getdate.y [emacs] (static): If the Emacs configuration files + have #defined static to be the empty string, then #undefine + it; this file doesn't need that hack. + +Fri Apr 16 12:13:37 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * obstack.c, getopt.c, getopt1.c: Surround code with + #if defined (_LIBC) || !defined (__GNU_LIBRARY__) + +Fri Apr 16 10:52:12 1993 Michael Meissner (meissner@osf.org) + + * getopt.h (getopt): Do not declare getopt with a prototype of + (void) for a non-ANSI compiler. If not GNU library and a + standard compiler, do not declare a prototype for getopt, just + like the comments say, due to different libraries having + different signatures for getopt. + +Thu Apr 15 16:36:03 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c: Move #include to top and out of [USG]. + [sgi, UMAX]: Don't include it again later. + +Wed Apr 14 13:06:50 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c: "#ifdef !define ..." -> "#if !defined ..." + + * getopt.c (_NO_PROTO): Don't define if already defined. + +Tue Apr 13 14:56:33 1993 Jim Meyering (meyering@comco.com) + + * getdate.y [HAVE_MEMCPY && !HAVE_BCOPY]: Define bcopy in terms + of memcpy for old versions of bison that generate parsers that + use bcopy. + +Tue Apr 13 00:48:41 1993 Jim Blandy (jimb@wookumz.gnu.ai.mit.edu) + + * getloadavg.c: Changes for Mach from Thorston Ohl + : + #include , instead of . + (getloadavg): Don't forget to test LDAV_DONE in the CPP + conditional protecting the last load average technique. + +Mon Apr 12 23:03:20 1993 Jim Blandy (jimb@wookumz.gnu.ai.mit.edu) + + * getloadavg.c: Changes for VMS from Richard Levitte: + (LOAD_AVE_TYPE, NLIST_STRUCT): Collapse multi-line #if + directives into one line; VMS CPP can't handle that. + [VMS] (getloadavg): Add static `initialized' variable, and + set the dsc$w_length and dsc$a_pointer fields of descriptior + instead of the size and ptr fields. + +Mon Apr 12 13:55:34 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getopt.c (my_index): Rename arg STRING to STR. + +Sun Apr 11 17:37:19 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getopt.h: Declare optopt. + + * getopt.c (my_index): First arg is `const char *'. + (my_bcopy): Likewise. + +Tue Apr 6 13:23:28 1993 Jim Meyering (meyering@comco.com) + + * getdate.y [hp9000 && !hpux]: Change erroneous #ifdef to #if. + +Mon Apr 5 17:28:35 1993 Jim Blandy (jimb@wookumz.gnu.ai.mit.edu) + + * getdate.y: #include whenever HAVE_GETTIMEOFDAY + is #defined. If it isn't defined, try to guess it. + (main): If HAVE_GETTIMEOFDAY is #defined, use it. + +Sun Apr 4 11:24:59 1993 Jim Meyering (meyering@comco.com) + + * getdate.y [sgi]: Undefine timezone before including . + + * getdate.y [time.h vs sys/time.h]: Fix boolean algebra typo from + Mar 31 consolidation. + + * getdate.y: Move static dcls of yyerror and yylex to a point + following the definition of those symbols to getdate_{yyerror,yylex}. + + * getdate.y [_AIX]: AIX needs time.h as well as sys/time.h. + +Fri Apr 2 13:30:03 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getopt.c: Define _NO_PROTO before including . + +Wed Mar 31 18:38:05 1993 Jim Blandy (jimb@geech.gnu.ai.mit.edu) + + * getdate.y: Consolidate the expressions saying when to + #include , to avoid multiple inclusions. + + * getdate.y (yylex, yyerror): Added forward static declarations. + + * getdate.y: Note that David Mackenzie's change of March 16 + 1992 introduces another shift/reduce conflict. + +Wed Mar 31 17:30:29 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * alloca.c [emacs]: Define free as xfree. + (alloca): Use free, not xfree. + +Mon Mar 29 13:46:17 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * a.out.gnu.h [i386] (SEGMENT_SIZE): Don't use this defn on [sequent]. + [sequent && i386]: #include "/usr/include/a.out.h" explicitly, + since in glibc this is installed as . + +Mon Mar 15 17:34:53 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * getopt.c (optopt): Initialize it. + +Sun Mar 14 16:39:57 1993 Jim Blandy (jimb@wookumz.gnu.ai.mit.edu) + + * getpagesize.h: Add definition for VMS. + +Wed Mar 10 20:57:21 1993 Jim Blandy (jimb@wookumz.gnu.ai.mit.edu) + + * getloadavg.c: If USG is defined, #include . + Move the test for HAVE_FCNTL_H and _POSIX_VERSION down after this. + + * alloca.c: Use xfree instead of free. + +Wed Mar 10 15:22:56 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * getloadavg.c [__osf__ && __alpha__] (OSF_ALPHA): Define this. + [OSF_ALPHA] (LOAD_AVE_TYPE): Define as long. + [OSF_ALPHA] (NLIST_STRUCT): Define this. + +Wed Feb 24 12:45:00 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c [NeXT]: #undef FSCALE to indicate that the nlist + method is not the desireable one. + (getloadavg) [NeXT]: Return with errno==EINVAL if called with NELEM>1, + since we can get only the one-minute load average on this system. + +Mon Feb 22 08:59:03 1993 Jim Blandy (jimb@wookumz.gnu.ai.mit.edu) + + * getloadavg.c (LDAV_CVT): If LDAV_CVT has already been + defined above in terms of Emacs's LOAD_AVE_CVT, don't redefine + it just because we have FSCALE. + +Sun Feb 21 14:52:01 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getopt.c (optopt): New variable. + (_getopt_internal): On any failure for a single-letter option, set + `optopt' to the losing option character. + When a required arg is missing, return ':' instead of '?' if the + first char in OPTSTRING (possibly after the - or +) is a ':'. + Use 1003.2-standard formats for error messages (it specifies + precise formats for unrecognized option and for missing arg). + + * signame.c: #include before . + +Thu Jan 28 17:10:08 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c (LOAD_AVE_TYPE) [sequent]: Define as long. + (FSCALE) [sequent]: Define as 1000.0, like sgi. + (LDAV_CVT) [FSCALE]: Move outside if #ifndef FSCALE. + +Fri Jan 22 14:51:36 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c (NLIST_STRUCT): Put defined(sony_news) inside the + parens so we don't redefine NLIST_STRUCT when it's already defined. + + * signame.h [!__STDC__] (psignal): Surround decl with #ifndef + HAVE_SYS_SIGLIST || HAVE_PSIGNAL. + (sys_siglist): Surround decl with #ifndef HAVE_SYS_SIGLIST. + +Sun Jan 17 19:55:30 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * getopt.c, getopt1.c: Do define const if IN_GCC. + +Thu Jan 14 15:35:33 1993 David J. MacKenzie (djm@kropotkin.gnu.ai.mit.edu) + + * getopt.c, getopt1.c: Don't redefine const; let callers do it. + +Wed Jan 13 15:38:40 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getopt.c [_AIX]: Put #pragma alloca before all else. + +Tue Jan 12 16:48:04 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * getloadavg.c: Removed #ifdef TEST around #include of errno.h. + +Mon Jan 11 15:17:29 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * getloadavg.c [ultrix]: Define BSD. + + * signame.h [!HAVE_SYS_SIGLIST && !HAVE_PSIGNAL]: Put psignal decl + inside these #ifs. + [!HAVE_SYS_SIGLIST]: Put sys_siglist decl inside this #if. + +Fri Jan 8 17:36:41 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c [HAVE_CONFIG_H]: Test this only for actually + including "config.h". Everything else that HAVE_CONFIG_H used to + turn off is now turned on always. + (KERNEL_FILE) [sequent, hpux], (LDAV_SYMBOL) [alliant]: Don't + define if already defined. + [!LDAV_DONE && LOAD_AVE_TYPE && !VMS]: Define LDAV_PRIVILEGED. + + * getloadavg.c (getloadavg) [!LDAV_DONE]: Set errno to zero. + +Wed Jan 6 18:17:28 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * signame.c: #include "signame.h" after possibly defining `const', + so signame.h and signame.c consistently use it or don't use it. + + * signame.h: Use "#if defined (__STDC__) && __STDC__", in place of + "#ifdef __STDC__". + +Sat Jan 2 18:32:01 1993 David J. MacKenzie (djm@kropotkin.gnu.ai.mit.edu) + + * getopt.c: Turn off GETOPT_COMPAT by default. + +Thu Dec 31 12:34:41 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * signame.c [HAVE_CONFIG_H]: #include "config.h". + +Tue Dec 8 21:10:29 1992 David J. MacKenzie (djm@kropotkin.gnu.ai.mit.edu) + + * getloadavg.c: Include fcntl.h if HAVE_FCNTL_H, not USG. + + * getdate.y: Include alloca.h if HAVE_ALLOCA_H, not sparc. + +Tue Dec 1 13:27:40 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu) + + * getopt.c, getopt1.c, getdate.y, alloca.c, getloadavg.c + [HAVE_CONFIG_H]: Include config.h. + +Tue Nov 24 09:42:29 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu) + + * getugroups.c: Use HAVE_STRING_H, not USG. + +Mon Nov 23 14:36:33 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * signame.c (init_sigs): Renamed to signame_init, made global. + (sig_abbrev, sig_number): Changed callers. + * signame.h (signame_init): Declare it. + + * signame.c (init_sigs): Add SIGDANGER. + +Thu Nov 19 21:34:43 1992 Jim Blandy (jimb@totoro.cs.oberlin.edu) + + * getloadavg.c: #include whether or not the + "emacs" CPP symbol is defined. + +Mon Nov 16 13:35:30 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * a.out.gnu.h (SEGMENT_SIZE): Define as PAGE_SIZE if undefined. + (PAGE_SIZE): Define as 16 if undefined; for i386-minix, which has + no predefine we can test. + +Thu Nov 12 23:31:53 1992 Jim Meyering (meyering@hal.gnu.ai.mit.edu) + + * getdate.y, getusershell.c: Give statically initialized arrays + const attribute. + +Sat Nov 7 13:50:27 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu) + + * getopt1.c: Only include stdlib.h for __GNU_LIBRARY__. + [!__STDC__]: Don't define const if it was already defined. + +Sat Nov 7 03:28:08 1992 Jim Blandy (jimb@apple-gunkies.gnu.ai.mit.edu) + + * getdate.y [emacs]: Include ; under Emacs, we get + some additional configuration information from that. + +Sat Nov 7 00:53:35 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu) + + * getopt.c [!__STDC__]: Don't define const if it was already defined. + +Tue Nov 3 20:12:01 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * getloadavg.c: Added `!defined (LDAV_DONE) &&' to all the #if's + for different system types. We want to get one and only one of the + chunks of code which defines LDAV_DONE. + +Tue Oct 27 23:51:02 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu) + + * getloadavg.c [sequent]: implies NLIST_STRUCT. + [SYSV || _POSIX_VERSION]: include fcntl.h, not sys/file.h. + +Mon Oct 26 22:43:25 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * install.sh: Move or copy first to temp file, then mv to real dest. + +Mon Oct 19 18:35:04 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * obstack.h (__need_ptrdiff_t): Don't define, if __NeXT__. + +Sat Oct 17 03:17:01 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * getopt.c: Include string.h only with GNU library. + +Fri Oct 16 17:40:54 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * getopt.h (no_argument, required_argument, optional_argument): + Define as macros. + (enum _argtype): Removed. + +Fri Oct 2 18:18:35 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * signame.c (NSIG): #define if not #define'd. + +Thu Oct 1 23:33:55 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu) + + * getpagesize.h: That should have been HAVE_UNISTD_H, Mike . . . + (no initial underscore). + + * pathmax.h [__MSDOS__]: Don't include sys/param.h. + +Wed Sep 30 13:54:36 1992 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * getpagesize.h: Test for _HAVE_UNISTD_H, because + _POSIX_VERSION is defined by unistd.h, and thus can't be used + in deciding whether to include it. + +Tue Sep 29 07:36:29 1992 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * getloadavg.c: if symbol `sony_news' is defined, define + NLIST_STRUCT and declare LOAD_AVE_TYPE as long. + +Thu Sep 17 20:10:03 1992 Karl Berry (karl@geech.gnu.ai.mit.edu) + + * regex.[ch]: made links into ../regex/, per rms' suggestion. + Please put further ChangeLog entries there. + +Tue Sep 15 20:13:30 1992 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * getpagesize.h: Posix-ify. + +Mon Sep 14 23:48:55 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * getloadavg.c: Define SUNOS_5 if appropriate. + +Mon Sep 14 16:31:01 1992 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * getdate.y: AIX needs sys/time.h as well as time.h. + +Sun Sep 13 07:17:09 1992 Jim Blandy (jimb@wookumz.gnu.ai.mit.edu) + + * getdate.y: Don't forget to include the file which defines + struct timeval and struct timezone, if we're using those. + +Fri Sep 11 10:42:24 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * getopt.h: Only prototype getopt for the GNU libc. + +Fri Sep 11 07:46:21 1992 Karl Berry (karl@hal.gnu.ai.mit.edu) + + * regex.h (_RE_ARGS) [!__STDC__]: expand to empty parens. + +Fri Sep 11 00:57:56 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * regex.c (SET_LIST_BIT): Always treat c as positive. + +Thu Sep 10 19:38:59 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * getugroups.c: Always declare getgrent. getgroups fills in + an array of int on 386BSD, too. + +Thu Sep 10 16:35:10 1992 Jim Blandy (jimb@wookumz.gnu.ai.mit.edu) + + * getdate.y: Generalize previous change; always use + gettimeofday to find the current time zone's Greenwich offset, + unless we're being compiled under USG or some other system + which already has CPP conditionals saying how to get the time + zone offset. + + * getdate.y: Don't divide the Greenwich offset returned by + gettimeofday by 60; it's already expressed in minutes, so it + doesn't need to be converted. + +Wed Sep 9 21:49:20 1992 Karl Berry (karl@apple-gunkies.gnu.ai.mit.edu) + + * regex.[ch]: version 0.10, incorporating below changes and + more. See /gd/gnu/lib/regex-*/ChangeLog. + +Wed Sep 9 03:09:55 1992 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * malloc.c: if USG, define macros for bcopy and bzero. + Don't redefine USG for hpux if already defined. + +Tue Sep 1 16:46:47 1992 Jim Blandy (jimb@pogo.cs.oberlin.edu) + + * getdate.y: If __ultrix__ is defined, then we don't have the + timezone array, but we do have ftime, so use that instead. + +Fri Aug 28 15:52:40 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * getloadavg.c [SUNOS_5]: New code from Epoch 4.2. + +Thu Aug 27 16:38:22 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * getloadavg.c: Don't check NLIST_STRUCT to decide whether to + define LOAD_AVE_TYPE. + +Wed Aug 26 16:45:54 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * getloadavg.c (FSCALE): Don't #define if already defined. + +Mon Aug 24 13:00:34 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * getopt.c: Include string.h if USG or STDC_HEADERS as well as + if __GNU_LIBRARY__. + +Sun Aug 23 02:51:31 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * regex.[ch] (re_comp): Remove const from return value, to + avoid conflict with 386BSD unistd.h. + +Sat Aug 22 18:30:58 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * getloadavg.c: Define FCALE, then LDAV_CVT in terms of that. + +Fri Aug 21 16:02:20 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * getloadavg.c (_SEQUENT_): Define NLIST_STRUCT. + +Wed Aug 19 16:35:33 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c [NLIST_NAME_UNION]: Test this intead of convex. + +Tue Aug 18 23:06:47 1992 Jim Blandy (jimb@wookumz.gnu.ai.mit.edu) + + * regex.c (DO_RANGE): Make end and this_char integers, and + fetch this_char's initial value using an 'unsigned char *', so that + character ranges including '\177' through '\377' will work. + +Tue Aug 18 17:32:40 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * getopt.c, getopt1.c, getopt.h: Change license back to GPL from LGPL. + +Fri Aug 14 07:38:34 1992 Torbjorn Granlund (tege@jupiter.sics.se) + + * obstack.h: Fix spelling errors. + +Sat Aug 1 18:12:07 1992 Michael Meissner (meissner@osf.org) + + * obstack.c (CALL_FREEFUN): Recode to use if/else instead of + ?:, since the MIPS compiler does not like ?: expressions where + the two alternate values are both void. + +Sat Aug 1 00:11:25 1992 Fred Fish (fnf at fishpond) + + * obstack.h (obstack_specify_allocation): Use malloc/free + compatible calling convention. + * obstack.h (obstack_specify_allocation_with_arg): Use mmalloc/ + mfree compatible calling convention. + +Wed Jul 29 18:53:13 1992 Karl Berry (karl@hal) + + * regex.c: version 0.9; fixes bug wrt always finding the longest + match. See /gd/gnu/lib/regex-*/ChangeLog. + +Sun Jul 26 18:24:13 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c [NeXT]: #undef BSD after . + +Sun Jul 26 17:04:20 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * obstack.h (struct obstack): extra_arg is now char *. + (obstack_alloc_arg): Deleted. + (obstack_specify_allocation): Take new arg, to specify extra_arg. + Call _obstack_begin_1. + * obstack.c (_obstack_begin_1): New function. + +Fri Jul 24 16:29:17 1992 Fred Fish (fnf at fishpond) + + * obstack.h (struct obstack): Change maybe_empty_object to + bitfield. Add use_extra_arg bitfield and extra_arg. + * obstack.h (obstack_init, obstack_begin): Cast type of + obstack_chunk_free as well as obstack_chunk_alloc. + * obstack.h (obstack_specify_allocation, obstack_alloc_arg): + New macros. + * obstack.c (CALL_CHUNKFUN, CALL_FREEFUN): New macros to hide + details of chunk allocator/deallocator calls. + * obstack.c (_obstack_begin, _obstack_newchunk): Use CALL_CHUNKFUN. + * obstack.c (_obstack_free, _obstack_newchunk): Use CALL_FREEFUN. + +Fri Jul 24 16:09:37 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * getugroups.c [_POSIX_SOURCE]: Define endgrent as empty. + + * getloadavg.c [HAVE_UNISTD_H]: Include unistd.h. + +Sun Jul 19 23:29:27 1992 John Gilmore (gnu@cygnus.com) + + * stab.def: Order values numerically, and add some stabs + used by Solaris. + +Fri Jul 17 20:21:20 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * getopt.c: Only include stdlib.h for GNU C library, due to + conflicting getopt prototypes. + +Fri Jul 17 05:49:07 1992 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * obstack.c (DEFAULT_ALIGNMENT): Cast to widest integer type to + avoid possible warning if int is narrower than pointer. + +Fri Jul 17 03:47:16 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * getdate.y: Use HAVE_FTIME instead of FTIME_MISSING. + * signame.c: Use HAVE_SYS_SIGLIST instead of SYS_SIGLIST_MISSING. + +Tue Jul 14 18:53:46 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getopt.c (exchange): Cast args to my_bcopy to (char *). + +Tue Jul 14 14:34:33 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * getopt.c: Include stdlib.h and string.h if STDC_HEADERS as + well as if __GNU_LIBRARY__. + +Sat Jul 11 13:24:12 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * obstack.h: Define __need_ptrdiff_t for gstddef.h. + +Fri Jul 10 15:01:25 1992 Karl Berry (karl@hal) + + * regex.[ch]: new version (0.8), incorporating the changes + below. See /gd/gnu/regex/ChangeLog. + +Fri Jul 10 03:46:24 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * obstack.h: Get ptrdiff_t from gstddef.h when building GCC with GCC. + +Thu Jul 9 21:38:37 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getloadavg.c [DGUX]: Cast first arg to dg_sys_info to (long int *). + +Wed Jul 8 19:43:26 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * error.c (private_strerror): Ok if errnum == sys_nerr. + +Wed Jul 8 12:38:37 1992 Jim Blandy (jimb@wookumz.gnu.ai.mit.edu) + + * regex.c: Applied tentative patches from Karl Berry: + Miscellaneous doc fixes and reformatting. + (REGEX_REALLOCATE): Parenthesize call to realloc. + Test HAVE_ALLOCA_H, instead of testing for things like sparc, + etc. Don't declare alloca under AIX, since that's done with + the pragma at the top of the file. + (IS_IN_FIRST_STRING): Renamed to FIRST_STRING_P. + (re_match_2): Uses of IS_IN_FIRST_STRING changed. + (TALLOC): Parenthesize call to malloc. + (REGEX_TALLOC): New macro. + (FREE_NONNULL): New macro. + (FREE_VARIABLES): Use FREE_NONNULL instead of always freeing. + (re_match_2): Don't use initializers in declarations of + regstart, regend, old_regstart, old_regend, reg_info, + best_regstart, best_regend, reg_dummy, and reg_info_dummy. + Initialize them only if we actually use the registers. + New variable match_end for use instead of best_regend[0], in + case we don't allocate the registers. Don't fuss with + best_regend[0] directly. + +Sat Jul 4 07:53:45 1992 Karl Berry (karl@hal) + + * regex.c (re_compile_fastmap): init succeed_n_p (to false). + +Fri Jul 3 14:45:29 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * error.c: Change FOO_MISSING to HAVE_FOO. + +Thu Jul 2 15:47:20 1992 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu) + + * getloadavg.c: Tweak #defines for SVR4. + Include sys/param.h if unix, not if BSD. + +Wed Jul 1 11:48:37 1992 Karl Berry (karl@hal) + + * regex.[ch]: new version (0.7). See /gd/gnu/regex/ChangeLog. + +Sun Jun 28 06:05:39 1992 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * obstack.h: Define a type for the result of __PTR_TO_INT. + +Sat Jun 27 10:50:59 1992 Jim Blandy (jimb@pogo.cs.oberlin.edu) + + * xregex.c (re_match_2): When we have accepted a match and + restored d from best_regend[0], we need to set dend + appropriately as well. It may happen that dend == end_match_1 + while the restored d is in string2, so we should be prepared + to set dend to end_match_2 in this case. + +Tue Jun 23 22:27:36 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu) + + * getloadavg.c (getloadavg) [DGUX]: Don't initialize structure; + the error handling doesn't work that way now. + +Fri Jun 19 13:14:57 1992 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu) + + * install.sh: Use - instead of :- in variable assignments. + +Tue Jun 16 19:32:46 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getopt.c [HAVE_ALLOCA_H]: Test to include . + +Thu Jun 11 15:15:38 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * arscan.c: Removed. It is now part of Make. + +Mon Jun 8 18:03:28 1992 Jim Blandy (jimb@pogo.cs.oberlin.edu) + + * regex.h (RE_NREGS): Doc fix. + + * xregex.c (re_set_registers): New function. + * regex.h (re_set_registers): Declaration for new function. + +Wed Jun 3 16:59:49 1992 Karl Berry (karl@geech.gnu.ai.mit.edu) + + * regex.[ch]: new version (0.6). See ~karl/regex/ChangeLog. + +Sat May 23 22:28:54 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * getopt.c [LIBC]: No longer need to #include . + + * getopt.h, getopt.c, getopt1.c: Changed copyright notice to LGPL. + +Fri May 22 14:50:25 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * getopt.c: Change sparc conditional so that sun && sparc + causes use of alloca.h. + +Thu May 14 16:50:28 1992 Karl Berry (karl@kropotkin.gnu.ai.mit.edu) + + * regex.c, regex.h: new version (0.5). See ~karl/regex/ChangeLog. + +Tue May 12 03:27:19 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu) + + * getopt.c (_getopt_internal): Don't allow it. + +Tue May 12 00:33:31 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * getopt.c (_getopt_internal): Allow optional arg to be in ARGV elt + after switch. + +Thu May 7 11:46:18 1992 Jim Blandy (jimb@pogo.cs.oberlin.edu) + + * crt0.c (_start): When m68000 is #defined, don't use the + simple C version of _start that simply calls start1; GCC 2.1 + without optimization has _start push a word of garbage on the + stack, which screws up the CRT0_DUMMIES hack. Instead, use an + assembly-language version of _start. + +Mon May 4 16:26:49 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu) + + * getopt.h: #ifdef __STDC__ -> #if __STDC__. + +Thu Apr 30 18:53:52 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * a.out.gnu.h [NeXT]: Define PAGE_SIZE, and not SEGMENT_SIZE. + +Sun Apr 26 02:33:50 1992 Jim Blandy (jimb@pogo.cs.oberlin.edu) + + * crt0.c: Don't #include "config.h" unless emacs is #defined. + +Tue Apr 21 17:45:54 1992 Jim Blandy (jimb@pogo.cs.oberlin.edu) + + * regex.c (re_match_2): If we've already allocated memory for + the search buffers, don't allocate them again. + +Mon Apr 13 20:17:47 1992 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu) + + * getopt.h: Make the multiple inclusion protection look like + the rest of libc's. + +Wed Apr 1 06:10:15 1992 Jim Blandy (jimb@wookumz.gnu.ai.mit.edu) + + * regex.c [emacs]: Include , since regex.h wants it. + +Tue Mar 31 12:01:32 1992 Jim Blandy (jimb@wookumz.gnu.ai.mit.edu) + + * crt0.c: The changes below are the results of a merge with + the Emacs 19 sources: + (start1): Declare this static before all uses. + Add conditionals for ALLIANT_2800. + + * (_start) for alliant: Set _curbrk and _minbrk from _setbrk, + to help with Emacs dumping. + +Mon Mar 30 18:00:41 1992 Jim Blandy (jimb@wookumz.gnu.ai.mit.edu) + + * malloc.c [VMS]: Include vlimit.h. + (calloc): Add a quick implementation of this, in case + something from another library uses it. + (get_lim_data): There are several versions of this function, + tailored for different operating systems; the appropriate + version is chosen by checking for preprocessor symbols which + indicate which operating system Emacs is being compiled for. + Re-arrange the preprocessor conditionals so that the generic + "none of the above" version is last, in the final "else" clause. + + * alloca.c: Do nothing if alloca is defined as a macro. + +Fri Mar 20 02:53:14 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * a.out.gnu.h: Added missing backslash in #if. + +Mon Mar 16 23:46:18 1992 David J. MacKenzie (djm@apple-gunkies.gnu.ai.mit.edu) + + * getdate.y: Support ISO 8601 format. yyyy-mm-dd. + +Sun Mar 15 22:50:30 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * a.out.gnu.h [NeXT || mips] (SEGMENT_SIZE): Define as PAGE_SIZE. + [NeXT] (PAGE_SIZE): Define as 0x2000. + [mips] (PAGE_SIZE): Define as 4096. + + * getopt.c [sparc && svr4]: No . + +Thu Mar 12 14:26:48 1992 Karl Berry (karl@apple-gunkies.gnu.ai.mit.edu) + + * regex.[ch]: new version (0.4). See ~karl/regex/ChangeLog. + +Tue Mar 10 22:26:14 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * a.out.gnu.h [sun && mc68000]: SEGMENT_SIZE == 0x2000. + +Thu Feb 27 21:37:53 1992 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * getdate.y: `#undef timezone' on SGI systems to avoid naming + clash. + (get_date): Use underscore version for SGI. + [This fix is from beebe@mach.utah.edu.] + +Tue Feb 25 21:23:50 1992 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) + + * getopt.c [__GNU_LIBRARY__]: #include . + +Thu Feb 20 13:04:57 1992 Karl Berry (karl@wombat.gnu.ai.mit.edu) + + * regex.[ch]: new version (0.3). See ~karl/regex/ChangeLog for all + the details. + +Wed Feb 19 23:04:05 1992 Charles Hannum (mycroft@gnu.ai.mit.edu) + + * regex.c [_AIX]: Move #pragma alloca to top of file to accommodate + AIX C compiler. + +Mon Feb 17 03:44:03 1992 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) + + * a.out.gnu.h [sparc] (_N_HDROFF): Define as (-sizeof (struct exec)). + That is as if SEGMENT_SIZE were 0, but that would be wrong. + + * a.out.gnu.h [i386] (SEGMENT_SIZE): Define. + +Sun Feb 16 03:10:23 1992 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) + + * a.out.gnu.h [sparc] (PAGE_SIZE, SEGMENT_SIZE): Define. + (PAGSIZ): Define as PAGE_SIZE. + (SEGSIZ): Define as SEGMENT_SIZE. + +Thu Jan 30 19:03:29 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * regex.c (re_search_2): Improve comments. + +Tue Jan 28 00:28:15 1992 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * getopt.h (struct option): Change has_arg back to an int. + +Mon Jan 27 23:03:33 1992 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * getopt.c (_getopt_internal): Don't use a relational operator (>) + on the has_arg field, which is now an enum. + +Fri Jan 17 21:34:02 1992 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) + + * getopt.h: Don't declare envopt. + + * envopt.c: Tweaks to compile under libc. + +Fri Jan 17 21:23:02 1992 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * getopt.c: Describe the new args to _getopt_internal. + +Fri Jan 17 19:26:54 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getopt.h: Remove decls of _getopt_* and option_index. + Make `name' elt of `struct option' const char *. + Make `has_arg' an enum (integer values same). + * getopt.c (_getopt_internal): Renamed from getopt, taking 3 new args + in place of global vars _getopt_long_options, _getopt_long_only, + and option_index (which are all now gone). + (getopt): New fn, front end to _getopt_internal. + * getopt1.c (getopt_long, getopt_long_only): Use _getopt_internal. + +Tue Jan 7 02:08:10 1992 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * regex.c (malloc, realloc): Don't specify arg types--can + cause error. + +Mon Jan 6 12:53:42 1992 Karl Berry (karl at apple-gunkies.gnu.ai.mit.edu) + + * regex.[ch]: new versions. See ~karl/regex/ChangeLog for all + the details. + +Tue Dec 24 22:42:59 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * obstack.h: Indentation fix. + +Mon Dec 23 23:41:39 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * regex.c, putenv.c, getugroups.c: Change POSIX ifdefs to + HAVE_UNISTD_H and _POSIX_VERSION. + +Wed Dec 18 14:24:35 1991 Michael Meissner (meissner at osf.org) + + * getopt.h (whole file): Protect getopt.h from being included + twice. + +Fri Dec 6 13:00:42 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * getopt.c (getopt): Cast argv to (char **) (with no const) + when passing to exchange, to be explicit about what's happening. + + * getopt.c: Change POSIX_ME_HARDER to POSIXLY_CORRECT. + +Thu Dec 5 12:12:18 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * getopt.c (my_bcopy, my_index): New functions. + Use instead of bcopy and index. + Avoid conditionals on USG, NeXT, hpux, __GNU_LIBRARY__, etc. + + * getopt1.c, getopt.h (getopt_long*): Like yesterday's getopt change. + +Wed Dec 4 10:51:45 1991 Ron Guilmette (rfg at ncd.com) + + * getopt.c, getopt.h (getopt): Correct the type of the second + parameter so that it agrees with ANSI/POSIX standards. + + * getopt.h: Make all function declarations explicitly `extern'. + +Tue Dec 3 01:34:59 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * getopt.c: Fix some wrong comments. + +Mon Dec 2 17:49:50 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * getopt.c (getopt): Support `+' to introduce long-named + options, as well as `--', if GETOPT_COMPAT is defined. + It is defined by default. + +Sun Dec 1 21:12:32 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * getopt.c (getopt): Long-named options are introduced by `--' + instead of `+'. + Protect all fprintfs with checks of opterr. + Include getopt.h instead of redeclaring things, to stay in sync. + * getopt1.c (getopt_long): No longer disable long options if + POSIX_ME_HARDER is set. + (main): Handle -d. Remove unused var. + +Mon Nov 4 23:06:54 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * regex.h [!__STDC__]: regerror was declared to return size_t * + instead of size_t. + +Sat Nov 2 21:26:42 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * error.c: Use STRERROR_MISSING instead of STDC_HEADERS to + control compiling strerror. + +Fri Oct 18 00:33:43 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * getugroups.c: GID_T -> GETGROUPS_T, for clarity. + +Wed Oct 9 14:14:31 1991 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * getopt.c: Treat hpux like USG. + +Tue Oct 8 21:36:52 1991 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * alloca.c: Add some parens to make precedence clearer. + +Sat Oct 5 13:17:59 1991 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * getopt.c: Treat NeXT like USG. + +Sat Sep 28 02:01:45 1991 David J. MacKenzie (djm at churchy.gnu.ai.mit.edu) + + * regex.c: Include stdlib.h only if STDC_HEADERS, not if POSIX + (POSIX.1 doesn't require it to exist). + +Wed Sep 4 17:32:51 1991 Kathryn A. Hargreaves (letters at apple-gunkies) + + * regex.[ch]: Put current version (0.1) here, after backing up old + files. For ChangeLog details, please refer to the ChangeLog + file in my regex directory. + +Sat Aug 24 04:22:01 1991 David J. MacKenzie (djm at apple-gunkies) + + * getopt1.c: Declare getenv. + +Mon Aug 19 01:35:48 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * regex.c, getopt.c: Indent '#pragma alloca' so non-ANSI + compilers won't choke on it. + +Mon Aug 12 16:43:17 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * getopt.c: _POSIX_OPTION_ORDER renamed to POSIX_ME_HARDER. + * getopt1.c: Support POSIX_ME_HARDER. + +Wed Aug 7 00:53:00 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu) + + * getdate.y: Add patch from perf@efd.lth.se to support + explicit "dst", for European timezones. + +Tue Jul 30 17:00:23 1991 David J. MacKenzie (djm at apple-gunkies) + + * getdate.y: Rename NEED_TZSET to FTIME_MISSING. + +Fri Jul 26 23:09:22 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * regex.h: Delete `#pragma once'. + +Fri Jul 26 17:07:39 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * a.out.gnu.h [sparc]: #define SEGMENT_SIZE 0. Is that right?? + +Wed Jul 24 03:29:26 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * getopt.c, regex.c: Put alloca stuff first, where RS6000 requires it. + * getopt.c: Use const instead of CONST, and define it to + nothing if not __STDC__. + + * xmalloc.c (xmalloc, xrealloc): Exit with value 2 on error, + not 1, so cmp can use it. + +Tue Jul 23 15:01:26 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * getugroups.c: GID_T is int if ultrix as well as if sun. + +Mon Jul 22 17:39:35 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * getugroups.c: If POSIX and not sun (bogus!), take an array + of gid_t instead of an array of int. + +Tue Jul 16 21:24:43 1991 Michael Meissner (meissner at wookumz.gnu.ai.mit.edu) + + * obstack.h (__extension__): If compiling with a 1.xx GCC + compiler define __extension__ as nothing. + +Tue Jul 16 20:25:22 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * obstack.h [not __GNUC__] (obstack_finish): Add extra parens for clarity. + (conditionals for __GNUC__): Do not test __STRICT_ANSI__. + [__GNUC__] (most macros): Use __extension__ to avoid -pedantic warning. + +Tue Jul 16 17:12:02 1991 Michael Meissner (meissner at wookumz.gnu.ai.mit.edu) + + * obstack.h (obstack_finish): If compiling with a non-GCC + compiler, use the argument (h) to point to the obstack + structure, rather than the __o1 pointer, which only exists in + the GNU side of the macros. + (#if __GNUC__ && __STDC__): If -pedantic is used do not use + the GNU CC ({}) optimizations, since these cause warnings to + be omitted. + +Tue Jul 16 01:59:58 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu) + + * getdate.y (TimezoneTable): #if 0 zones which would require + storing a float in a time_t. + +Fri Jul 12 17:01:58 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * obstack.h (struct obstack): New flag maybe_empty_object. + (obstack_finish, both versions): Set the flag if allocate empty object. + Don't make the object nonempty. This replaces May 7 change. + * obstack.c (_obstack_begin, _obstack_newchunk): Clear the flag. + (_obstack_newchunk): Don't free "empty" chunk if flag is set. + (_obstack_free): Set the flag if we change chunks. + +Sat Jul 6 21:09:31 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu) + + * getdate.y [NEED_TZSET]: Declare `timezone'. + +Thu Jun 20 01:11:31 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu) + + * getopt.c: Separate decls of getenv and malloc from decls of + index and bcopy, to reduce duplicated code. + +Tue Jun 11 00:11:07 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu) + + * regex.c (re_match_2): In case wordbeg, check whether we are + at the start of the string before checking the previous + character, not after, just like in case wordend. + + * getdate.y: Declare alloca for old bisons. + +Mon May 20 13:13:32 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * obstack.c (obstack_free, _obstack_free): Define both, the same way. + +Sun May 19 18:37:38 1991 David J. MacKenzie (djm at churchy.gnu.ai.mit.edu) + + * getdate.y: Rename getdate to get_date to avoid conflict with SVR4. + +Fri May 17 21:09:14 1991 David J. MacKenzie (djm at churchy.gnu.ai.mit.edu) + + * filemode.c (ftypelet): Only test for S_ISBLK if it's defined. + +Sat May 11 14:49:43 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * obstack.h (obstack_finish): Typo in last change (non-GNUC version). + +Tue May 7 15:38:51 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * obstack.h (obstack_finish): Make each object at least 1 byte. + +Tue Apr 30 13:58:16 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * getopt.c, regex.c [_AIX]: Do #pragma alloca. + +Wed Apr 10 19:08:02 1991 Per Bothner (bothner at pogo.gnu.ai.mit.edu) + + * signame.h: Make sys_siglist be const char[] if __STDC__ + is defined (thus making it compatible with signame.c). + +Tue Apr 2 16:49:02 1991 Roland McGrath (roland at churchy.gnu.ai.mit.edu) + + * glob.c: Put #ifndef alloca around alloca goop. + (glob_vector): Put #ifdef SHELL around label used only there. + +Tue Apr 2 14:32:47 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu) + + * glob.c: Attempt to reconcile with bash and make versions of + #ifdefs and #includes. + + * glob.c (glob_vector): If _POSIX_SOURCE, don't use + (non-POSIX) d_ino field of struct dirent. (from bfox) + +Sun Mar 17 16:25:23 1991 Richard Stallman (rms@mole.ai.mit.edu) + + * regex.c (PUSH_FAILURE_POINT): Was multiplying stack size by + a big number. Multiply by 2 instead. + + * signame.c (init_sigs): Define i. + +Fri Feb 22 12:38:22 1991 Mike Haertel (mike at apple-gunkies) + + * obstack.c (_obstack_allocated_p): Use >=, not >, when + comparing with the beginning of the chunk, for the exact + same reason as RMS' change below. + +Thu Feb 21 21:29:50 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * obstack.h [not __GNUC__] (obstack_free): Use >, not >=, + when comparing with beginning of chunk. + + * getopt.c (bcopy): Never declare it. + +Thu Feb 21 09:18:47 1991 David J. MacKenzie (djm at geech.ai.mit.edu) + + * glob.c: Don't declare bcopy if it is a macro. + Use BSD strings for NeXT. Don't include memory.h on POSIX. + +Mon Feb 18 23:41:20 1991 David J. MacKenzie (djm at geech.ai.mit.edu) + + * glob.c: Add special code for bash, #ifdef SHELL. + (glob_pattern_p): Only recognize `[' as a metacharacter if + there is a matching `]', for POSIX.2. (from bfox) + +Mon Jan 28 00:30:39 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * crt0.c [m68k]: Add conditionals for sun_68881, sun_fpa, sun_soft. + +Sun Jan 27 15:18:26 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * getopt.c (bcopy): Don't declare it if it's a macro. + +Thu Jan 24 22:16:14 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * regex.c (re_compile_pattern): Don't translate chars in char set + until the time the bits are set for them. + +Sat Dec 15 18:36:50 1990 David J. MacKenzie (djm at apple-gunkies) + + * filemode.c: Define each S_ISFOO function if not defined by + sys/stat.h. + +Sat Dec 15 15:10:14 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * obstack.h (obstack_init): Cast the chunk alloc function. + (obstack_begin): Likewise. + +Thu Dec 13 17:58:07 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * obstack.h: At all calls to _obstack_newchunk, + enclose in (..., 0), so that both alternatives are ints. + +Thu Dec 6 11:39:11 EST 1990 Jay Fenlason (hack@ai.mit.edu) + + * getdate.y: Add support for 'date' style yymmddhhss dates. + +Mon Dec 3 14:09:40 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * obstack.h: + At all calls to _obstack_newchunk, cast the other alternative to void. + +Sat Dec 2 21:56:25 1990 Roland McGrath (roland at albert.ai.mit.edu) + + * a.out.gnu.h (N_COMM): Define this. + +Thu Nov 30 00:04:35 1990 Roland McGrath (roland at geech.ai.mit.edu) + + * a.out.gnu.h (_N_HDROFF): Use SEGMENT_SIZE rather than a hard-coded + 1024. What moron did this?? + +Wed Nov 29 17:41:09 1990 Roland McGrath (roland at albert.ai.mit.edu) + + * a.out.gnu.h [vax, hp300, pyr] (SEGMENT_SIZE): Define as PAGE_SIZE, + not page_size. + +Wed Nov 14 00:35:16 1990 David J. MacKenzie (djm at apple-gunkies) + + * regex.c (SIGN_EXTEND_CHAR): If UNSIGNED_CHAR is defined, use + an alternate definition (suggested in the GNU grep README). + +Thu Nov 8 12:08:52 1990 David J. MacKenzie (djm at apple-gunkies) + + * filemode.c (ftypelet): Pass a mode_t instead of unsigned + short, so it works on Evans' Minix. If _POSIX_SOURCE is not + defined, define mode_t as unsigned short. Define S_ISTYPE + macros if needed. Use them. + + * modechange.c: Use S_ISDIR. Define if needed. + +Fri Oct 26 16:50:01 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * obstack.c (_obstack_newchunk): If old_chunk becomes empty, free it. + +Mon Oct 15 13:50:17 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * obstack.h (obstack_free): In non-GNU C case, don't use + value of _obstack_free. + +Sun Oct 14 18:51:51 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * crt0.c (new hp assembler): Double flag_fpa and flag_68881 if %d2!=0. + + * alloca.s [MOTOROLA_DELTA]: Avoid putting sp above stack top. + +Mon Oct 1 16:20:02 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * obstack.h Declare _obstack_free and _obstack_begin as void instead + of int. Otherwise, GCC won't let you compile obstack.c + +Fri Sep 28 23:53:28 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * obstack.h: Declare the functions we use from obstack.c. + (obstack_blank): In both definitions, rearrange pointer math to avoid + pointing past end of allocated memory. + +Wed Sep 19 21:09:26 1990 Richard Kenner (kenner at vlsi1.ultra.nyu.edu) + + * obstack.h (obstack_int_grow): In non-GCC case, don't try to + post-increment a cast. + +Mon Sep 3 22:18:38 1990 David J. MacKenzie (djm at apple-gunkies) + + * error.c [DOPRNT_MISSING]: Pass args as a fixed number of + `char *'. + +Sun Sep 2 20:51:02 1990 David J. MacKenzie (djm at apple-gunkies) + + * regex.c: Use standard string functions if STDC_HEADERS is + defined. + +Fri Aug 31 06:59:47 1990 Jim Kingdon (kingdon at albert.ai.mit.edu) + + * getopt1.c (getopt_long{,_only}): If opt_index is NULL, don't + try to store into *opt_index. + +Tue Aug 28 18:45:16 1990 David J. MacKenzie (djm at albert.ai.mit.edu) + + * regex.c: Include some system header files if appropriate. + +Wed Aug 15 14:38:15 1990 David J. MacKenzie (djm at apple-gunkies) + + * regex.c: Define isgraph if ctype.h doesn't (as on Sequents). + +Sun Aug 12 00:20:19 1990 David J. MacKenzie (djm at albert.ai.mit.edu) + + * getopt.c (getopt): If optstring starts with '+', don't + permute; this is for utilities like time, nice, xargs, and + env, which don't want to mix up their options with those of + the programs they run, but don't want to turn off permuting + for those programs by setting _POSIX_OPTION_ORDER. + +Fri Aug 3 14:25:35 1990 David J. MacKenzie (djm at pogo.ai.mit.edu) + + * getopt.c (main), getopt1.c (main): Read option chars into an + int, not a char. + + * getopt.c (getopt): Increment `optind' after finding + unrecognized or ambiguous long named option. + +Thu Jul 5 09:50:25 1990 David J. MacKenzie (djm at apple-gunkies) + + * getopt.c: If long option's `flag' field is zero, return the + contents of the `val' field. + +Fri Jun 29 01:30:22 1990 David J. MacKenzie (djm at apple-gunkies) + + * getopt.h: Mention in comment how to handle long options that + don't just store a constant in an int. + +Mon Jun 25 18:15:46 1990 David J. MacKenzie (djm at albert.ai.mit.edu) + + * filemode.c (ftypelet): Distinguish between regular files and + unknown file types using '-' and '?'. + +Sat Jun 16 11:18:26 1990 David J. MacKenzie (djm at albert.ai.mit.edu) + + * getopt.c: If STDC_HEADERS or __GNU_LIBRARY__ is defined, + include ANSI C header files. + +Thu Jun 14 13:21:42 1990 David J. MacKenzie (djm at apple-gunkies) + + * glob.c (glob_match): Eliminate '^' as a character class + negator, leaving just the POSIX '!'. + +Thu Jun 7 01:01:40 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * glob.c: __GNU_LIBRARY__ implies DIRENT and STDC_HEADERS. + +Thu Jun 7 03:45:33 1990 David J. MacKenzie (djm at albert.ai.mit.edu) + + * glob.c: Use if DIRENT is defined, not _POSIX_SOURCE. + +Wed Jun 6 00:05:03 1990 David J. MacKenzie (djm at albert.ai.mit.edu) + + * glob.c (glob_filename): Remove tilde expansion code. + +Tue Jun 5 00:35:48 1990 David J. MacKenzie (djm at albert.ai.mit.edu) + + * error.c: Use VPRINTF_MISSING instead of VPRINTF to control + use of _doprnt. + (error): Use strerror. + (strerror) [!STDC_HEADERS]: New function. + + * glob.c: Optionally support POSIX and STDC headers. + (glob_filename): Make tilde expansion work for patterns + containing subdirectories. + +Mon Jun 4 16:31:40 1990 David J. MacKenzie (djm at albert.ai.mit.edu) + + * glob.c (glob_match): Allow '!' as well as '^' to negate + character classes. Check for end of filename when comparing + with char class. Check for end of pattern after backslash in + character class. + (glob_vector): Only calculate D_NAMLEN once, for efficiency. + Don't allocate name_vector if a previous malloc failed. + (glob_dir_to_array): Make string copying more efficient. + (glob_filename): directory_size was off by 1. + Reallocation of result had '1' instead of 'l'. + +Thu May 31 01:45:16 1990 David J. MacKenzie (djm at apple-gunkies) + + * glob.c: Reformat to resemble the bash version more. + + * filemode.c: If _POSIX_SOURCE is defined, use POSIX macro + names for mode bits. + +Sat May 19 15:17:42 1990 David J. MacKenzie (djm at albert.ai.mit.edu) + + * filemode.c (mode_string): New function. + (filemodestring): Reimplement in terms of mode_string. + (ftypelet): Take an unsigned short instead of a struct stat *. + Fix up comments. + +Thu May 10 12:57:11 1990 David J. MacKenzie (djm at albert.ai.mit.edu) + + * error.c: If __STDC__, use stdarg instead of varargs. + +Tue May 1 16:07:32 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * alloca.s [hp9000s300]: Avoid using sp as temporary. + +Fri Apr 20 16:58:24 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * obstack.c, obstack.h (obstack_free): Use >, not >=, to compare + object with chunk address. + +Mon Apr 9 15:11:22 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + + * a.out.encap.h: Protect against multiple inclusion. + +Fri Apr 6 23:27:46 1990 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * a.out.gnu.h (enum machine_type): Put missing comma after M_SPARC. + +Mon Apr 2 04:49:18 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + + * malloc.c: Make get_lim_data always "static void" regardless + of #ifdefs. Declare it before using it. + +Mon Mar 26 00:36:52 1990 David J. MacKenzie (djm at spike.ai.mit.edu) + + * getopt.c (getopt): For long-named options that take optional + args, never use the next argv-element as an arg; args for + these must be part of the same argv-element, separated from + the option name by a '='. This makes them consistent with how + short-named options with optional args are handled. + + * getopt.h, getopt.c, getopt1.c: Add some const declarations + if __STDC__. + +Sun Mar 4 12:11:31 1990 Kathy Hargreaves (kathy at hayley) + + * regex.h: Added syntax bit RE_NO_EMPTY_RANGES which is set if + an ending range point has to collate higher or equal to the + starting range point. + Added syntax bit RE_NO_HYPHEN_RANGE_END which is set if a hyphen + can't be an ending range point. + Set to two above bits in RE_SYNTAX_POSIX_BASIC and + RE_SYNTAX_POSIX_EXTENDED. + + regex.c: (re_compile_pattern): Don't allow empty ranges if the + RE_NO_EMPTY_RANGES syntax bit is set. + Don't let a hyphen be a range end if the RE_NO_HYPHEN_RANGE_END + syntax bit is set. + (ESTACK_PUSH_2): renamed this PUSH_FAILURE_POINT and made it + push all the used registers on the stack, as well as the number + of the highest numbered register used, and (as before) the two + failure points. + (re_match_2): Fixed up comments. + Added arrays best_regstart[], best_regstart_seg1[], best_regend[], + and best_regend_seg1[] to keep track of the best match so far + whenever reach the end of the pattern but not the end of the + string, and there are still failure points on the stack with + which to backtrack; if so, do the saving and force a fail. + If reach the end of the pattern but not the end of the string, + but there are no more failure points to try, restore the best + match so far, set the registers and return. + Compacted some code. + In stop_memory case, if the subexpression we've just left is in + a loop, push onto the stack the loop's on_failure_jump failure + point along with the current pointer into the string (d). + In finalize_jump case, in addition to popping the failure + points, pop the saved registers. + In the fail case, restore the registers, as well as the failure + points. + + +Sun Feb 18 15:08:10 1990 Kathy Hargreaves (kathy at hayley) + + * regex.c: (global): Defined a macro GET_BUFFER_SPACE which + makes sure you have a specified number of buffer bytes + allocated. + Redefined the macro BUFPUSH to use this. + Added comments. + + (re_compile_pattern): Call GET_BUFFER_SPACE before storing or + inserting any jumps. + + (re_match_2): Set d to string1 + pos and dend to end_match_1 + only if string1 isn't null. + Force exit from a loop if it's around empty parentheses. + In stop_memory case, if found some jumps, increment p2 before + extracting address to which to jump. Also, don't need to know + how many more times can jump_n. + In begline case, d must equal string1 or string2, in that order, + only if they are not null. + In maybe_finalize_jump case, skip over start_memorys' and + stop_memorys' register numbers, too. + +Thu Feb 15 15:53:55 1990 Kathy Hargreaves (kathy at hayley) + + * regex.c (BUFPUSH): off by one goof in deciding whether to + EXTEND_BUFFER. + +Wed Jan 24 17:07:46 1990 Kathy Hargreaves (kathy at hayley) + + * regex.h: Moved definition of NULL to here. + Got rid of ``In other words...'' comment. + Added to some comments. + + regex.c: (re_compile_pattern): Tried to bulletproof some code, + i.e., checked if backward references (e.g., p[-1]) were within + the range of pattern. + + (re_compile_fastmap): Fixed a bug in succeed_n part where was + getting the amount to jump instead of how many times to jump. + + (re_search_2): Changed the name of the variable ``total'' to + ``total_size.'' + Condensed some code. + + (re_match_2): Moved the comment about duplicate from above the + start_memory case to above duplicate case. + + (global): Rewrote some comments. + Added commandline arguments to testing. + + +Wed Jan 17 11:47:27 1990 Kathy Hargreaves (kathy at hayley) + + * regex.c: (global): Defined a macro STORE_NUMBER which stores a + number into two contiguous bytes. Also defined STORE_NUMBER_AND_INCR + which does the same thing and then increments the pointer to the + storage place to point after the number. + Defined a macro EXTRACT_NUMBER which extracts a number from two + continguous bytes. Also defined EXTRACT_NUMBER_AND_INCR which + does the same thing and then increments the pointer to the + source to point to after where the number was. + + +Tue Jan 16 12:09:19 1990 Kathy Hargreaves (kathy at hayley) + + * regex.h: Incorporated rms' changes. + Defined RE_NO_BK_REFS syntax bit which is set when want to + interpret back reference patterns as literals. + Defined RE_NO_EMPTY_BRACKETS syntax bit which is set when want + empty bracket expressions to be illegal. + Defined RE_CONTEXTUAL_ILLEGAL_OPS syntax bit which is set when want + it to be illegal for *, +, ? and { to be first in an re or come + immediately after a | or a (, and for ^ not to appear in a + nonleading position and $ in a nontrailing position (outside of + bracket expressions, that is). + Defined RE_LIMITED_OPS syntax bit which is set when want +, ? + and | to always be literals instead of ops. + Fixed up the Posix syntax. + Changed the syntax bit comments from saying, e.g., ``0 means...'' + to ``If this bit is set, it means...''. + Changed the syntax bit defines to use shifts instead of integers. + + * regex.c: (global): Incorporated rms' changes. + + (re_compile_pattern): Incorporated rms' changes + Made it illegal for a $ to appear anywhere but inside a bracket + expression or at the end of an re when RE_CONTEXTUAL_ILLEGAL_OPS + is set. Made the same hold for $ except it has to be at the + beginning of an re instead of the end. + Made the re "[]" illegal if RE_NO_EMPTY_BRACKETS is set. + Made it illegal for | to be first or last in an re, or immediately + follow another | or a (. + Added and embellished some comments. + Allowed \{ to be interpreted as a literal if RE_NO_BK_CURLY_BRACES + is set. + Made it illegal for *, +, ?, and { to appear first in an re, or + immediately follow a | or a ( when RE_CONTEXTUAL_ILLEGAL_OPS is set. + Made back references interpreted as literals if RE_NO_BK_REFS is set. + Made recursive intervals either illegal (if RE_NO_BK_CURLY_BRACES + isn't set) or interpreted as literals (if is set), if RE_INTERVALS + is set. + Made it treat +, ? and | as literals if RE_LIMITED_OPS is set. + Cleaned up some code. + + +Thu Dec 21 15:31:32 1989 Kathy Hargreaves (kathy at hayley) + + * regex.c: (global): Moved RE_DUP_MAX to regex.h and made it + equal 2^15 - 1 instead of 1000. + Defined NULL to be zero. + Moved the definition of BYTEWIDTH to regex.h. + Made the global variable obscure_syntax nonstatic so the tests in + another file could use it. + + (re_compile_pattern): Defined a maximum length (CHAR_CLASS_MAX_LENGTH) + for character class strings (i.e., what's between the [: and the + :]'s). + Defined a macro SET_LIST_BIT(c) which sets the bit for C in a + character set list. + Took out comments that EXTEND_BUFFER clobbers C. + Made the string "^" match itself, if not RE_CONTEXT_IND_OPS. + Added character classes to bracket expressions. + Change the laststart pointer saved with the start of each + subexpression to point to start_memory instead of after the + following register number. This is because the subexpression + might be in a loop. + Added comments and compacted some code. + Made intervals only work if preceded by an re matching a single + character or a subexpression. + Made back references to nonexistent subexpressions illegal if + using POSIX syntax. + Made intervals work on the last preceding character of a + concatenation of characters, e.g., ab{0,} matches abbb, not abab. + Moved macro PREFETCH to outside the routine. + + (re_compile_fastmap): Added succeed_n to work analogously to + on_failure_jump if n is zero and jump_n to work analogously to + the other backward jumps. + + (re_match_2): Defined macro SET_REGS_MATCHED to set which + current subexpressions had matches within them. + Changed some comments. + Added reg_active and reg_matched_something arrays to keep track + of in which subexpressions currently have matched something. + Defined MATCHING_IN_FIRST_STRING and replaced ``dend == end_match_1'' + with it to make code easier to understand. + Fixed so can apply * and intervals to arbitrarily nested + subexpressions. (Lots of previous bugs here.) + Changed so won't match a newline if syntax bit RE_DOT_NOT_NULL is set. + Made the upcase array nonstatic so the testing file could use it also. + + (main.c): Moved the tests out to another file. + + (tests.c): Moved all the testing stuff here. + + +Sat Nov 18 19:30:30 1989 Kathy Hargreaves (kathy at hayley) + + * regex.c: (re_compile_pattern): Defined RE_DUP_MAX, the maximum + number of times an interval can match a pattern. + Added macro GET_UNSIGNED_NUMBER (used to get below): + Added variables lower_bound and upper_bound for upper and lower + bounds of intervals. + Added variable num_fetches so intervals could do backtracking. + Added code to handle '{' and "\{" and intervals. + Added to comments. + + (store_jump_n): (Added) Stores a jump with a number following the + relative address (for intervals). + + (insert_jump_n): (Added) Inserts a jump_n. + + (re_match_2): Defined a macro ESTACK_PUSH_2 for the error stack; + it checks for overflow and reallocates if necessary. + + * regex.h: Added bits (RE_INTERVALS and RE_NO_BK_CURLY_BRACES) + to obscure syntax to indicate whether or not + a syntax handles intervals and recognizes either \{ and + \} or { and } as operators. Also added two syntaxes + RE_SYNTAX_POSIX_BASIC and RE_POSIX_EXTENDED and two command codes + to the enumeration regexpcode; they are succeed_n and jump_n. + + +Sat Nov 18 19:30:30 1989 Kathy Hargreaves (kathy at hayley) + + * regex.c: (re_compile_pattern): Defined INIT_BUFF_SIZE to get rid + of repeated constants in code. Tested with value 1. + Renamed PATPUSH as BUFPUSH, since it pushes things onto the + buffer, not the pattern. Also made this macro extend the buffer + if it's full (so could do the following): + Took out code at top of loop that checks to see if buffer is going + to be full after 10 additions (and reallocates if necessary). + + (insert_jump): Rearranged declaration lines so comments would read + better. + + (re_match_2): Compacted exactn code and added more comments. + + (main): Defined macros TEST_MATCH and MATCH_SELF to do + testing; took out loop so could use these instead. + + +Tue Oct 24 20:57:18 1989 Kathy Hargreaves (kathy at hayley) + + * regex.c (re_set_syntax): Gave argument `syntax' a type. + (store_jump, insert_jump): made them void functions. + +Tue Mar 6 23:29:26 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + + * signame.c (sig_number): Return -1 if not found. + +Fri Mar 2 16:32:20 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + + * signame.h [!__STDC__]: Remove comments cuz they're in [__STDC__]. + signame.{c,h}: Make sig_abbrev return char *, not const char *. + +Thu Mar 1 14:10:32 1990 David J. MacKenzie (djm at albert.ai.mit.edu) + + * getopt.c (getopt): If _getopt_long_only, for options that + start with '-' and are not a valid long-named option, only + interpret them as short options if the first letter is a valid + short option. Otherwise the error message would be printed + naming the short option letter instead of the whole option, and + if, for example, there is a 'T' long option, '-Tfoo' would print + "prog: invalid option `-T'" (which is wrong). + +Wed Feb 28 19:38:49 1990 David J. MacKenzie (djm at albert.ai.mit.edu) + + * signame.h: Use ANSI C prototypes ifdef __STDC__. + * signame.c: Add const declarations ifdef __STDC__. + +Wed Feb 28 19:06:36 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + + * signame.c (SIGPWR): Change name to "Power failure". + +Wed Feb 28 18:46:36 1990 David J. MacKenzie (djm at albert.ai.mit.edu) + + * getopt.h: ifdef out decl of _getopt_option_name. + +Wed Feb 28 15:05:54 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + + * getopt.c (getopt): Change typo (optstr -> optstring). + + * getopt.c: Remove all _getopt_option_name stuff. + If RETURN_IN_ORDER, return one, not zero, to distinguish between + this and a long option. + + * signame.{c,h}: New files. + +Tue Feb 27 13:32:45 1990 David J. MacKenzie (djm at rice-chex) + + * getopt.c (getopt): In RETURN_IN_ORDER mode, set + _getopt_option_name to zero when returning a non-option arg in + optarg, to distinguish it from getting a long-named option + that takes an arg. + Print the correct option-introducing character (can be + either `+' or `-') in error messages for long-named options. + If _getopt_long_only is nonzero, no long options match an + option arg that starts with a dash, and there are valid short + options, try matching the arg against the short options. + +Thu Feb 22 19:50:49 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + + * obstack.c (_obstack_begin): Use slightly smaller default size + so that it still fits in one block if malloc range checking is + in use. + +Mon Feb 19 15:41:14 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + + * getopt1.c (getopt_long_only): New function. + getopt.h: Declare getopt_long_only and _getopt_long_only. + getopt.c: Define _getopt_long_only. + (getopt): If _getopt_long_only, accept '-' as well as '+' to start + long option. + +Sat Feb 3 16:28:00 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * alloca.s [MOTOROLA_DELTA]: New alternative for 68k. + +Sun Jan 28 22:29:17 1990 David J. MacKenzie (djm at hobbes.ai.mit.edu) + + * getopt1.c (main): Fix bug that prevented the first long + option from being recognized. + + * getopt.c: Move comment on the return value for long-named + options to a more appropriate place. + +Wed Jan 24 19:11:27 1990 David J. MacKenzie (djm at hobbes.ai.mit.edu) + + * glob.c (glob_filename): Change '==' to '=' in what was + clearly supposed to be an assignment statement. + +Mon Jan 22 18:14:40 1990 David J. MacKenzie (djm at rice-chex) + + * regcmp.c (regcmp): Allocate whole return value with one call + to malloc, so freeing the buffer works the same way as it does + on System V. + +Tue Jan 16 22:17:03 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + + * a.out.gnu.h [hp300, pyr]: Define SEGMENT_SIZE to be page_size + +Wed Jan 10 06:57:10 1990 David J. MacKenzie (djm at hobbes.ai.mit.edu) + + * glob.c: Use if SYSNDIR is defined (some Xenix + systems need this). + +Mon Jan 8 12:33:55 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * regex.c (re_compile_pattern): Add missing break in prev change. + +Mon Jan 1 12:16:56 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * regex.c (re_compile_pattern): Ignore \<, etc., checking + context of $. + +Mon Dec 25 12:00:16 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * obstack.h (obstack_object_size, obstack_room): Eliminate _obstack. + +Sat Dec 23 16:20:13 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * regex.c (re_compile_fastmap): Put back deleted local k. + +Wed Dec 20 02:03:43 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu) + + * getopt.h: Add function decls/prototypes for getopt and + getopt_long. + + * getopt.c: Bring some comments up to date with the code. + +Tue Dec 19 03:12:48 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu) + + * regex.h: Add function prototypes if __STDC__ is defined. + + * regex.c: Declare some external functions if emacs is not + defined. Add a few casts. + (re_compile_fastmap): Remove unused variable. + +Mon Dec 18 14:12:53 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu) + + * getopt.c: Declare some external functions. + +Mon Nov 20 19:57:00 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * a.out.gnu.h: Wrap N_MAGIC in #ifndef...#endif. + +Fri Nov 17 03:12:28 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * a.out.gnu.h: Wrap many things in #ifndef...#endif so file + can be used in addition to a system-supplied a.out.h. + +Tue Oct 31 17:03:06 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * getopt1.c (getopt_long): Delete mistaken test for index == 0. + +Wed Oct 25 17:50:51 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * getopt.c (getopt): Set option_index properly for long options. + +Tue Oct 24 23:41:06 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * getopt1.c (main): Fix initializers. + + * getopt.c (getopt): Was off by 1, checking for missing arg + for long option. + +Wed Oct 18 13:15:18 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * getopt.c: Improve comments and an error message. + Don't initialize most variables, for the sake of unexec. + +Tue Oct 17 03:06:14 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * getopt.c (getopt): Uniformly don't recognize `+' as option + if program doesn't use long options. + + * getopt.c (getopt): Complain about ambiguous option abbreviations. + But accept any exact match even if ambiguous. + + * getopt.c (getopt): Report error for unrecognized long options. + +Sat Sep 30 14:47:29 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * malloc.c: "#else rcheck" -> "#else /* rcheck */". + +Tue Sep 19 19:00:58 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * regex.h: Define RE_SYNTAX_POSIX_AWK. + +Sun Sep 17 15:20:46 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * regex.h: Last change in RE_SYNTAX_AWK broke RE_SYNTAX_EGREP. + +Sat Sep 16 01:53:53 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * regex.c (re_search_2): Stupid error propagating return code -2. + +Tue Sep 12 13:50:05 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * crt0.c [ISI68K]: Reinstall label __start. + +Tue Sep 5 15:43:24 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * malloc.c: Define USG if hpux defined. + +Mon Aug 28 17:50:27 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * regex.c (re_compile_pattern): With RE_AWK_CLASS_HACK, \ quotes + all characters inside [...]. + +Sat Aug 26 00:20:26 1989 Richard Stallman (rms at apple-gunkies.ai.mit.edu) + + * regex.h: Define RE_AWK_CLASS_HACK and change RE_SYNTAX_AWK. + * regex.c (re_compile_pattern): Change syntax of \ inside [...] + when RE_AWK_CLASS_HACK is set. + + * regex.c (re_match_2): Declare strings to search as char *, + and cast inside the function. + +Sat Aug 19 14:55:19 1989 Richard Stallman (rms at apple-gunkies.ai.mit.edu) + + * regex.c (EXTEND_BUFFER): Don't clobber c; do pointer arith + to update b in portable fashion. + +Thu Aug 17 15:56:36 1989 Joseph Arceneaux (jla at spiff) + + * regex.c (EXTEND_BUFFER): Set c to bufp->buffer - old_buffer. + +Sun Aug 13 15:21:02 1989 Richard Stallman (rms at hobbes.ai.mit.edu) + + * obstack.h: Typos in comments. + +Sun Jul 30 20:24:52 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * obstack.c (_obstack_newchunk): Never copy bytes past the end + of the object. Copy by COPYING_UNIT only for complete units + that fit in the object; then copy remaining bytes singly. + If obstack has less than the default alignment, + copy all bytes singly. + +Thu Jul 20 01:51:56 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * crt0.c: Delete spaces at ends of lines. + [ISI68K]: Unconditionally enclose asms in function `_start'. + Delete assembler definition of that function. + Use a6, not fp, as register name. + +Sun Jul 16 16:32:52 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * a.out.encap.h: Remove #ifdef ALTOS code because according to + Jyrki Kuoppala it doesn't do what he put it + in to do (which was work around a kernel bug). + +Thu Jun 29 19:59:16 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * malloc.c (valloc): Changed to be conditionalized on ! hpux + instead of ! HPUX (hpux this is generated by the OS). + +Tue Jun 20 21:14:57 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * Makefile: include ../Makerules. + Added .y->.tab.c implicit rule and rule to make unctime.tab.o. + Use $(archpfx) in front of object files. + Made some rules use $({LINK,COMPILE}.?) instead of $(CC), etc. + +Sat Jun 17 14:22:53 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * regex.h (struct re_pattern_buffer): Make ALLOCATED and USED long. + * regex.c (EXTEND_BUFFER): Use long constants to compare with them. + Move assignment outside if-condition. + Do pointer relocation arithmetic in strictly correct order. + +Sat Jun 10 00:26:01 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * glob.c [USG]: Define rindex; declare getpwent, etc. + +Wed Jun 7 22:36:51 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * alloca.s [hp9000s300]: Increase MAXREG for fpregs. + + * crt0.c: For new hp assembler, define float_loc as fixed location. + +Wed May 31 17:51:41 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * a.out.gnu.h: Define SEGMENT_SIZE for Altos. + +Mon May 22 17:59:17 1989 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * glob.c: Several changes for USG compatibility, etc. that have been + in the version distributed with Make for a while. + Today added new variable glob_tilde which makes glob_filename expand + ~ or ~USER, and made glob_filename, when given a directory with the + file name pattern, return the directory alone. + +Wed May 17 16:45:36 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * getopt.c (getopt): Add feature for long-named options; + starting with `+'. + +Mon May 8 17:21:40 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * crt0.c [sps7]: Handle mostly like orion, etc. + +Fri May 5 15:26:58 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * obstack.c (_obstack_free): If __STDC__, define this as well as + obstack_free. + + * crt0.c [hp9000s300]: Give fixed address to fpa_loc, per cph. + +Tue May 2 14:42:26 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * crt0.c [hp9000s300]: Allocate fpa_loc and float_loc. + +Sun Apr 23 00:22:37 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * a.out.encap.h (COFF_MAGIC, SEGMENT_SIZE, N_DATADDR): + Alternate definitions if ALTOS or if m68k. + + * getopt.c: If __GNUC__, use builtin alloca. + Define index if USG. + +Wed Apr 19 13:03:18 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * crt0.c [m68000]: Call finitfp_() if nec on Sun. + +Fri Apr 7 22:22:38 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * malloc.c: Rename BSD42 to BSD4_2, as in Emacs. + If `emacs', let config.h decide whether to define that. + (morecore): Change malloc_sbrk_used, etc., after error check. + +Thu Mar 23 18:21:56 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * glob.c: Added new copyright notice. + +Thu Mar 16 16:56:54 1989 Randall Smith (randy at gluteus.ai.mit.edu) + + * malloc.c (malloc): Made sure that the MAGIC1 bytes written at + the end of the space were positioned with regard to the new + offset. + +Fri Mar 10 16:50:12 1989 Randall Smith (randy at sugar-bombs.ai.mit.edu) + + * malloc.c (realloc): Make sure that the start of the mhead is + found correctly even when sizeof (struct mhead) doesn't divide 8 + properley. + + * malloc.c (morecore): Added code to reset sigmask to correct + value on a "no-more-room" return. + + * malloc.c (malloc, free, realloc): Leave 8 bytes of space, not 4, + before the actual data block. + +Fri Mar 3 10:52:14 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * a.out.encap.h, stab.def: Modified to use new GNU General Public + License. + +Thu Mar 2 15:45:46 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * a.out.gnu.h [nlist]: Made n_type an unsigned char (for compilers + where chars default to signed, which can screw up comparisons) and + made n_value an unsigned long. + +Wed Mar 1 13:04:25 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * getopt.c: Changed copyright header to reflect new GNU General + public license. + +Fri Feb 24 13:00:21 1989 Randall Smith (randy at gluteus.ai.mit.edu) + + * regex.c, regex.h: Changed copyright header to reflect new GNU + General public license. + +Sun Feb 19 08:02:01 1989 Richard Stallman (rms at apple-gunkies.ai.mit.edu) + + * getopt.c: If option argument is missing, return `?'. + +Fri Feb 10 13:31:05 1989 Randall Smith (randy at plantaris.ai.mit.edu) + + * stab.def: Changed comment on LSYM; also used for type + descriptions. + +Wed Feb 1 23:15:39 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * filemode.c (setst): Give `T' if sticky but not executable. + +Mon Jan 9 10:31:20 1989 Pace Willisson (pace at prep.ai.mit.edu) + + * a.out.gnu.h: Change a_magic to a_info, and define macros + to access it. Programs that refer to the magic number should + access it with N_MAGIC (exec), and set it with N_SET_MAGIC (exec, + val). This is a step to having a header that is unambiguous + between big and little endian machines. + + * a.out.encap.h: Use macros to access a_info fields. + +Wed Dec 28 18:58:53 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * crt0.c (hp9000s300): Changes from Jinx: new flag `flag_fpa' + set with a subx. d0 loaded from a0 and doubled before first subx. + +Tue Dec 20 22:13:49 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * a.out.gnu.h (N_DATADDR): Always define this if not already defined. + (SEGMENT_SIZE): Define this for the vax. + +Tue Dec 20 14:57:38 1988 Pace Willisson (pace at prep.at.mit.edu) + + * a.out.gnu.h: Changed exec header to have two bytes + (a_machtype and a_flags) instead of a_encap. a_machtype + is the same as on modern sun systems; a_flags can have + machine specific flags. (There may be some endian problems + here: You would like to have the magic number be the + first two bytes in the file, and then the next two could + be these options. It looks like the 68000 definitions + have to declare the options first to force this to happen.) + Defined M_386 for a_machtype. + Added definitions for N_DATOFF, N_TRELOFF, N_DRELOFF, + N_DATADDR, N_BSSADDR (which are present in sun release 4.0) + + * a.out.encap.h: Defined A_ENCAP as an a_flags value. Changed + uses of a_encap to a_flags & A_ENCAP + +Wed Dec 7 11:18:30 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * malloc.c: Added functions malloc_mem_used and malloc_mem_free to + return total amount of space allocated to program, and total space + left in free pool before sbrk must be called. + +Tue Nov 22 13:05:25 1988 Randall Smith (randy at cream-of-wheat.ai.mit.edu) + + * glob.c: Incorporated some bug fixes and changes sent by Brian. + None of them look disasterous. + +Fri Oct 21 12:40:24 1988 Randall Smith (randy at cream-of-wheat.ai.mit.edu) + + * malloc.c (free): Added code (within #ifdef rcheck) to given + slightly more verbose warnings then an abort if free was called + with garbage. + +Local Variables: +add-log-time-format: current-time-string +mode: indented-text +left-margin: 8 +version-control: never +End: diff --git a/gcc_arm/FSFChangeLog b/gcc_arm/FSFChangeLog new file mode 100755 index 0000000..5a9c6cf --- /dev/null +++ b/gcc_arm/FSFChangeLog @@ -0,0 +1,1503 @@ +Tue Jun 9 07:24:01 1998 Richard Kenner + + * regmove.c ({next,prev}_insn_for_regmove): Properly handle end of + function. + +Mon Jun 8 15:26:49 1998 Juha Sarlin + + * h8300.c (get_shift_alg): Add special cases for shifts of 8 and 24. + +Mon Jun 8 14:40:02 1998 John Wehle (john@feith.com) + + * i386.md (movsf_push, movsf_mem): Remove. + (movsf_push): Rename from movsf_push_nomove and move in front of + movsf; allow memory operands during and after reload. + (movsf_push_memory): New pattern. + (movsf): Don't bother checking for push_operand. If TARGET_MOVE and + both operands refer to memory then force operand[1] into a register. + (movsf_normal): Change to unnamed pattern. + Likewise for movdf, movxf, and friends. + +Mon Jun 8 13:18:04 1998 Martin v. Loewis + + * Makefile.in (TREE_H): Add tree-check.h. + (tree-check.h, s-check, gencheck): New targets. + (STAGESTUFF): Add s-check. + * gencheck.c: New file. + * tree.c (tree_check, tree_class_check, expr_check): New functions. + * tree.h (TREE_CHECK, TREE_CLASS_CHECK): Define. + (TYPE_CHECK, DECL_CHECK): Define. + Modify all access macros to use generated checking macros. + * acconfig.h (ENABLE_CHECKING): Undefine. + * configure.in (--enable-checking): New option. + +Mon Jun 8 12:13:25 1998 Richard Kenner + + * regmove.c: Remove include for varargs or stdarg. + +Mon Jun 8 07:49:41 1998 Andris Pavenis + + * gcc.c (link_command_spec): Support LINK_COMMAND_SPEC. + +Sun Jun 7 18:00:28 1998 Andreas Schwab + + * fold-const.c (fold, case EQ_EXPR): When folding VAR++ == CONST + or VAR-- == CONST construct a proper mask if VAR is a bitfield. + Cope with CONST being out of range for the bitfield. + +Sun Jun 7 17:19:35 1998 Tom Quiggle + + * mips/iris6.h (DWARF2_FRAME_INFO): Define. + * dwarf2out.c (dwarf2out_do_frame): Do something if DWARF2_FRAME_INFO. + +Sun Jun 7 15:29:04 1998 Andreas Schwab + + * regmove.c: New file. + * Makefile.in (OBJS): Add regmove.o. + (regmove.o): New rules. + (mostlyclean): Remove regmove dumps. + * toplev.c (regmove_{dump,dump_file,time}, flag_regmove): New vars. + (f_options): Add -foptimize-register-move. + (compile_file): Run regmove pass after combine pass and do its dump. + (main): Enable regmove dump when -dN or -da. + (fatal_insn): Flush regmove dump file. + * flags.h (flag_regmove): Declare. + * flow.c (find_use_as_address): Export. + * rtl.h (find_use_as_address): Declare. + * local-alloc.c (optimize_reg_copy_{1,2}): Removed, all calls deleted. + * reload1.c (count_occurrences): Export. + * reload.h (count_occurrences): Declare. + +Sun Jun 7 09:30:31 1998 Richard Kenner + + * Makefile.in (uninstall): Uninstall gcov. + + * alpha.h (ASM_COMMENT_START): Define. + + * alpha.h (EXTRA_CONSTRAINT, case 'S'): New case. + * alpha.md ({ashl,ashr,lshr}di3): Use 'S' for constraint. + + * i386.md (cmpxf): Add missing extend pattern from SFmode and fix + operand numbers in one extend pattern from DFmode. + + * pa.md ({pre,post}_{ld,st}wm and similar): When operand is being + incremented, use '+', not '=', for constraint. + + * reload.c (find_reloads): Give preference to pseudo that was the + reloaded output of previous insn. + + * emit-rtl.c (init_emit_once): Provide default for DOUBLE_TYPE_SIZE. + + * expr.c (init_expr_once): Free all RTL we generate here. + * expmed.c (init_expmed): Allocate all RTX in memory we'll free. + + * genemit.c (main): Generate #include "reload.h". + + * expr.c (expand_expr, case INDIRECT_EXPR): A dereference of + a REFERENCE_TYPE is always considered in a structure. Likewise for + a dereference of a NOP_EXPR whose input is a pointer to aggregate. + +Sat Jun 6 17:25:14 1998 Richard Kenner + + * mips.md (reload_{in,out}di): Allow other operand to be invalid + MEM and get any reload replacement before using address. + +Tue May 26 18:52:23 1998 Richard Kenner + + * reload1.c (reload): Get MEM_IN_STRUCT_P and RTX_UNCHANGING_P + from reg_equiv_memory_loc; set the latter when changing REG to MEM. + (alter_reg): Don't set RTX_UNCHANGING_P for shared slots. + +Mon May 25 12:07:12 1998 Hans-Peter Nilsson + + * cplus-dem.c (MBUF_SIZE): Bumped from 512 to 32767. + +Sun May 24 21:50:12 1998 Alan Modra + + * i386/linux{,-aout,oldld}.h (ASM_COMMENT_START): Define. + +Sun May 24 11:58:37 1998 Andreas Schwab + + * m68k.md (adddi3, subdi3): Properly negate the DImode constant. + +Sun May 24 11:30:08 1998 Torbjorn Granlund + + * m68k/lb1sf68.asm (__addsf3): Fix typo in exg on coldfire. + +Sun May 24 09:38:17 1998 John Wehle (john@feith.com) + + * i386.md (movsi): Remove redundant integer push patterns. + Don't check for TARGET_PUSH_MEMORY when pushing constants or registers. + +Sun May 24 08:59:27 1998 Richard Kenner + + * fold-const.c (fold, case EQ_EXPR): Split COMPLEX_TYPE operands + if either is COMPLEX_CST in addition to COMPLEX_EXPR. + + * expr.c (do_jump, case EQ_EXPR, case NE_EXPR): Check for COMPLEX + before testing for operand 1 being zero. + + * genattrtab.c (optimize): Define. + + * configure.lang: Fix substitution of target_alias. + +Sat May 23 22:31:17 1998 Michael P. Hayes + + * emit_rtl.c (double_mode): New variable. + (init_emit_once): Set and use it. + * real.c (ereal_atof, real_value_truncate): Handle double_mode not + being DFmode for C4x. + +Sat May 23 22:19:55 1998 Mike Stump + + * expr.c (expand_builtin_setjmp): Handle BUILTIN_SETJMP_FRAME_VALUE. + * i960.h (SETUP_FRAME_ADDRESSES, BUILTIN_SETJMP_FRAME_VALUE): Define. + * i960.md (ret, flush_register_windows): Define. + (nonlocal_goto): Likewise. Nested function nonlocal gotos don't + work yet. + +Sat May 23 18:45:59 1998 Andreas Schwab + + * m68k/t-linux: Remove stuff already included in config/t-linux. + +Sat May 23 18:35:07 1998 Richard Kenner + + * final.c: Select and "gstab.h" with NO_STAB_H. + + * gcc.c (default_compilers): Remove ".ada" extension. + + * combine.c (rtx_equal_for_field_assignment): Remove code that + checks get_last_value. + + * Makefile.in (uninstall): Delete info files. + +Sat May 23 18:28:27 1998 Herman A.J. ten Brugge + + * c-decl.c (start_decl): Use new macro SET_DEFAULT_DECL_ATTRIBUTES. + * c-lex.c (check_newline): Put last read character back on input + stream. + +Sat May 23 18:13:53 1998 David Edelsohn + + * rs6000.md (floatsidf2_loadaddr): rs6000_fpmem_offset will be + negative in a stackless frame. + * rs6000.c (rs6000_stack_info): Don't include fixed-size link area + in stackless frame size. Support 64-bit stackless frame size. + Combine fpmem offset calculations and don't add total_size to + offset if not pushing a stack frame. + + * tree.c (get_inner_array_type): New function. + * tree.h (get_inner_array_type): Likewise. + +Wed May 20 15:42:22 1998 Richard Kenner + + * expmed.c (expand_divmod): Save last divison constant and + if rem is same as div, don't adjust rem cost. + +Thu May 14 14:11:37 1998 Richard Kenner + + * alpha/vxworks.h: New file. + * configure.in (alpha*-*-vxworks*): New target. + + * alpha.c (tree.h): Include earlier. + (alpha_initialize_trampoline): New function. + * alpha.h (INITIALIZE_TRAMPOLINE): Call it. + * alpha/linux.h (INITIALIZE_TRAMPOLINE): Don't redefine. + +Thu May 14 13:35:53 1998 Cyrille Comar + + * Makefile.in (STAGESTUFF): Add s-under. + +Wed May 13 17:38:35 1998 Richard Kenner + + * combine.c (simplify_comparison, case AND): Don't commute AND + with SUBREG if constant is whole mode and don't do if lowpart + and not WORD_REGISTER_OPERATIONS. + + * expmed.c (expand_mult): Use 0 as add_target if should preserve + subexpressions. + +Mon May 11 17:26:06 1998 Paul Eggert + + * dwarf2out.c: Undo most recent change. + +Sun May 10 17:09:20 1998 Richard Kenner + + * fold-const.c (fold_range_test, fold): If need to make SAVE_EXPR + to do optimization, suppress if contains_placeholder_p. + +Thu May 7 18:14:31 Paul Eggert + + * dwarf2out.c: Don't assume `.section ".text"' causes assembler to + treat .text as label for start of section; instead, output + `.section ".text"; .LLtext0:' and use .LLtext0 in label contexts. + (ABBREV_LABEL, DEBUG_INFO_LABEL, DEBUG_LINE_LABEL, TEXT_LABEL): New. + (abbrev_label, debug_info_label, debug_line_label, text_label): New. + (dwarf2out_init): Initialize the vars. Output defn for text_label. + (dwarf2out_finish): Output defns for the other 3 vars. + (dw_val_node): Rename val_section to val_section_label, as it's + now a label, not a section. + (add_AT_section_offset): Arg is now a label, not a section. + (print_die): In label contexts, output section label, not section. + (output_die, output_compilation_unit_header): Likewise. + (output_{pubnames,aranges,line_info}, dwarf2out_finish): Likewise. + + * fixinc.wrap: Renamed from fixinc.math. Put wrapper around + curses.h if it contains `typedef char bool;'. + + * configure.in (arm-*-netbsd*): Rename fixinc.math to fixinc.wrap. + (i[34567]86-*-freebsdelf*, i[34567]86-*-freebsd*): Likewise. + (i[34567]86-*-netbsd*, i[34567]86-*-solaris2*): Likewise. + (m68k-*-netbsd*, mips-dec-netbsd*, ns32k-pc532-netbsd*): Likewise. + (powerpcle-*-solaris2*, sparc-*-netbsd*, sparc-*-solaris2*): Likewise. + (vax-*-netbsd*): Likewie. + +Wed May 6 06:44:28 1998 Richard Kenner + + * combine.c (simplify_rtx, case TRUNCATE): Reflect that it sign-extends + instead of zero-extending. + +Sat May 2 20:39:22 1998 Richard Kenner + + * fold-const.c (fold): When commutting COND_EXPR and binary operation, + avoid quadratic behavior if have nested COND_EXPRs. + +Tue Apr 28 17:30:05 1998 Richard Kenner + + * mips.h (HOST_WIDE_INT): Define if not already. + (compute_frame_size, mips_debugger_offset): Return HOST_WIDE_INT. + (DEBUGGER_{AUTO,ARG}_OFFSET): Cast second arg to HOST_WIDE_INT. + * mips.c (mips_debugger_offset): Now returns HOST_WIDE_INT. + Likewise for internal variable frame_size. + + * final.c (alter_subreg): Make new SUBREG if reload replacement + scheduled inside it. + + * dwarf2out.c (add_bound_info, case SAVE_EXPR): Pass + SAVE_EXPR_RTL address through fix_lexical_addr. + +Mon Apr 27 18:57:18 1998 Jim Wilson + + * mips/sni-svr4.h (CPP_PREDEFINES): Add -Dsinix and -DSNI. + +Mon Apr 20 14:48:29 1998 Michael Meissner + + * rs6000.md (mov{sf,df} define_splits): When splitting move of + constant to int reg, don't split insns that do simple AND and OR + operations; just split each word and let normal movsi define split + handle it further. + +Sun Apr 19 20:21:19 1998 Michael P. Hayes + + * real.h (C4X_FLOAT_FORMAT): New macro. + * real.c (c4xtoe, etoc4x, toc4x): New functions. + +Sun Apr 19 20:17:32 1998 Niklas Hallqvist + + * m68k.c (notice_update_cc): Use modified_in_p to check for update. + +Sun Apr 19 18:48:07 1998 K. Richard Pixley + + * fixincludes: Discard empty C++ comments. + Special case more files with C++ comments nested in C comments. + +Sun Apr 19 18:30:11 1998 Andreas Schwab + + * m68k.md ({add,sub}di3): Optimize for constant operand. + +Sun Apr 19 18:27:11 1998 Alan Modra + + * i386.c (output_387_binary_op): Swap operands when popping if result + is st(0). + +Sun Apr 19 17:58:01 1998 Peter Jeremy + + * expr.c (do_jump_by_parts_equality_rtx): Now public. + * expmed.c (do_cmp_and_jump): New function. + (expand_divmod): Use do_cmp_and_jmp instead of emit_cmp_insn and + emit_jump_insn. + +Sun Apr 19 07:48:37 1998 Richard Kenner + + * c-typeck.c (build_c_cast): Check underlying type when seeing + if discarding const or volatile. + + * c-decl.c (pushdecl): Avoid duplicate warning about implicit redecl. + + * configure.in (stab.h): Check for it. + (i386-*-vsta): Include xm-i386.h too. + * dbxout.c (stab.h): Include based on autoconf results. + * vax/xm-vms.h (NO_STAB_H): Deleted. + * alpha/xm-vms.h, xm-mips.h, i386/xm-mingw32.h, i386/go32.h: Likewise. + * i386/xm-cygwin32.h: Likewise. + * i386/xm-vsta.h (NO_STAB_H): Likewise. + (i386/xm-i386.h): No longer include. + + * mips.c: Cleanups and reformatting throughout. + ({expand,output}_block_move): Use HOST_WIDE_INT for sizes. + (mips_debugger_offset, compute_frame_size): Likewise. + (save_restore_insns, mips_expand_{pro,epi}logue): Likewise. + (siginfo): Deleted. + (override_options): Don't set up to call it; don't call setvbuf. + +Mon Apr 13 06:40:17 1998 Richard Kenner + + * configure.in (sparc-*-vxsim*): Include xm-siglist.h and + define USG and POSIX. + +Sun Apr 12 21:59:27 1998 Jeffrey A. Law + + * calls.c (expand_call): Fix typo in STRICT_ARGUMENT_NAMING. + +Sun Apr 12 21:42:23 1998 D. Karthikeyan + + * m68k.h (TARGET_SWITCHES): Add missing comma. + +Sun Apr 12 21:33:33 1998 Eric Valette + + * configure.in (i[34567]86-*-rtemself*): New configuration. + * i386/rtemself.h: New file. + +Sun Apr 12 21:08:28 1998 Jim Wilson + + * loop.c (loop_optimize): Reset max_uid_for_loop after + find_and_verify_loops call. + (strength_reduce): In auto_inc_opt code, verify v->insn has valid + INSN_LUID. + +Sun Apr 12 20:54:59 1998 Richard Earnshaw (rearnsha@arm.com) + + * configure.in (sparc-*-solaris2*): Add xm-siglist.h to xm_file. + Add USG and POSIX to xm_defines. + +Sun Apr 12 20:47:37 1998 Pat Rankin + + * cccp.c (eprint_string): New function. + (do_elif, do_else, verror): Use it instead of fwrite(,,,stderr). + (error_from_errno, vwarning): Likewise. + ({verror,vwarning,pedwarn}_with_line): Likewise. + (pedwarn_with_file_and_line, print_containing_files): Likewise. + +Sun Apr 12 20:40:44 1998 Richard Henderson + + * configure.in (alpha*-*-linux-gnu*): Add alpha/t-crtbe. + Add crt{begin,end}.o in extra_parts and delete crt{begin,end}S.o.o + * alpha/t-crtbe, alpha/crt{begin,end}.asm: New files. + + * alpha.h (PRINT_OPERAND_PUNCT_VALID_P): Accept '(' for s/sv/svi. + * alpha.c (print_operand): Handle it. + * alpha.md (fix_trunc[ds]fdi2): Use it. Add earlyclobber pattern + for ALPHA_TP_INSN. + +Sun Apr 12 13:09:46 1998 Scott Christley + + * objc/encoding.c (objc_sizeof_type, _C_VOID): New case. + +Sun Apr 12 13:04:55 1998 Nikolay Yatsenko (nikolay@osf.org) + + * configure.in (i[34567]86-*-osf1*): New entry. + * i386/osf1-c[in].asm: New files for OSF/1. + * i386/osf1elf{,gdb}.h, i386/[xt]-osf1elf, i386/xm-osf1elf.h: Likewise. + +Sun Apr 12 10:03:51 1998 Noel Cragg + + * fixincludes: Remove specification of parameters when renaming + functions in Alpha DEC Unix include files. + +Sun Apr 12 07:33:46 1998 Richard Kenner + + * mips.c (large_int): Use HOST_WIDE_INT, not int. + (print_operand): Use HOST_WIDE_INT_PRINT_* macros. + + * toplev.c (main): Sort order of handling of -d letters. + Use `F' instead of `D' for addressof_dump. + + * libgcc2.c (_eh_compat): Deleted. + * Makefile.in (LIB2FUNCS): Delete _eh_compat. + + * configure.in (alpha*-*-linux-gnu*): Don't include alpha/xm-linux.h. + + * c-common.c (check_format_info): Properly test for nested pointers. + + * pa.md (casesi0): Add missing mode for operand 0. + + * function.c (purge_addressof_1, case MEM): If BLKmode, put ADDRESSOF + into stack. + + * c-parse.in (label): Give warning if pedantic and label not integral. + + * c-decl.c (grokdeclarator): Don't warn about return type if in + system header. + + * reload.c (reload_nongroup): New variable. + (push{_secondary,}_reload): Initialize it. + (find_reloads): Compute it. + (debug_reload): Print it. + * reload.h (reload_nongroup): Declare. + * reload1.c (reload): Use reload_nongroup instead of local computation. + Check caller_save_spill_class against any nongroup reloads. + (reloads_conflict): No longer static. + +Sun Apr 12 05:52:18 1998 John David Anglin + + * vax.md (call patterns): Operand 1 is always a CONST_INT. + +Sat Apr 11 16:01:11 1998 Richard Kenner + + * convert.c (convert_to_{pointer,integer,real,complex}): Use switch. + Add missing integer-like types. + Simplify return of zero in error case. + (convert_to_pointer): Remove dubious abort. + (convert_to_integer, case POINTER_TYPE): Make recursive call. + (convert_to_integer, case COND_EXPR): Always convert arms. + * tree.c (type_precision): Deleted. + + * cccp.c (do_warning): Give pedantic warning if -pedantic and not + in system file. + * cpplib.c (do_warning): Likewise. + + * function.c (target_temp_slot_level): Define here. + (push_temp_slots_for_target, {get,set}_target_temp_slot_level): New. + * stmt.c (target_temp_slot_level): Don't define here. + * expr.h (temp_slot_level): New declaration. + +Fri Apr 10 16:35:48 1998 Paul Eggert + + * c-common.c (decl_attributes): Support strftime format checking. + (record_function_format, {check,init_function}_format_info): Likewise. + (enum format_type): New type. + (record_function_format): Now static; takes value of type + enum format_type instead of int. + (time_char_table): New constant. + (struct function_format_info): format_type member renamed from is_scan. + (check_format_info): Use `warning' rather than sprintf followed by + `warning', to avoid mishandling `%' in warnings. + Change a `pedwarn' to `warning'. + * c-tree.h (record_function_format): Remove decl. + +Thu Apr 2 17:34:27 1998 Manfred Hollstein + + * regclass.c (memory_move_secondary_cost): Protect uses of + SECONDARY_{INPUT,OUTPUT}_RELOAD_CLASS with #ifdef tests. + +Thu Apr 2 07:06:57 1998 Andreas Schwab + + * m68k.c (standard_68881_constant_p): Don't use fmovecr on 68060. + +Thu Apr 2 06:19:25 1998 Ken Raeburn + + * Makefile.in (version.c): Put "cvs log" output in build directory. + + * reload.h (MEMORY_MOVE_COST): Define here if not already defined. + (memory_move_secondary_cost): Declare. + * regclass.c (MEMORY_MOVE_COST): Don't define default here. + (memory_move_secondary_cost) [HAVE_SECONDARY_RELOADS]: New function. + (regclass, record_reg_classes, copy_cost, record_address_regs): + Pass register class and direction of move to MEMORY_MOVE_COST. + (top_of_stack) [HAVE_SECONDARY_RELOADS]: New static array. + (init_regs) [HAVE_SECONDARY_RELOADS]: Initialize it. + * reload1.c (MEMORY_MOVE_COST): Don't define default here. + (emit_reload_insns, reload_cse_simplify_set): Pass register class + and direction of move to MEMORY_MOVE_COST. + * 1750a.h (MEMORY_MOVE_COST): Add extra ignored arguments. + * a29k.h, alpha.h, arc.h, arm.h, dsp16xx.h, i386.h, m32r.h: Likewise. + * m88k.h, rs6000.h: Likewise. + * mips.h (MEMORY_MOVE_COST): Likewise. + Add memory_move_secondary_cost result to cpu-specific cost. + +Mon Mar 30 13:56:30 1998 Jim Wilson + + * mips/ultrix.h (SUBTARGET_CPP_SPEC): Define. + +Wed Mar 25 16:09:01 1998 Michael Meissner + + * rs6000.h (FUNCTION_ARG_PADDING): Cast result to be enum direction. + (function_arg_padding): Declare. + + * rs6000.c: Include stdlib.h if we have it. + (function_arg_padding): Change return type to int, cast enum's to int. + + (From Kaveh R. Ghazi ) + * rs6000.c (rs6000_override_options): Change type of `i', `j' and + `ptt_size' from int to size_t. + (rs6000_file_start): Likewise for `i'. + (rs6000_replace_regno): Add default case in enumeration switch. + (output_epilog): Remove unused variable `i'. + (rs6000_longcall_ref): Remove unused variables `len', `p', `reg[12]'. + + * rs6000.h (ADDITIONAL_REGISTER_NAMES): Add missing braces around + initializer. + (get_issue_rate, non_logical_cint_operand): Add prototype. + (rs6000_output_load_toc_table): Likewise. + + * rs6000.md (udivmodsi4): Add explicit braces to avoid ambiguous + `else'. + +Wed Mar 25 02:39:01 1998 Paul Eggert + + * configure.in (i[34567]86-*-solaris2*, powerpcle-*-solaris2*, + sparc-*-solaris2*): Use fixinc.svr4 if Solaris 2.0 through 2.4. + +Mon Mar 23 07:27:19 1998 Philippe De Muyter + + * m68k.md (ashldi_const): Allow shift count in range ]32,63]. + (ashldi3): Allow constant shift count in range ]32,63]. + (ashrdi_const, ashrid3, lshrdi_const, lshrdi3): Likewise. + + * m68k.md (zero_extend[qh]idi2, iordi_zext): New patterns. + (zero_extendsidi2): Avoid useless copy. + (iorsi_zexthi_ashl16): Avoid "0" constraint for operand 2. + (iorsi_zext): New name for old unnamed pattern; indentation fixes. + +Mon Mar 23 07:12:05 1998 Richard Kenner + + * final.c (only_leaf_regs_used): If pic_offset_table_rtx used, + make sure it is a permitted register. + +Sun Mar 22 06:57:04 1998 Richard Kenner + + * expmed.c (extract_bit_field): Don't confuse SUBREG_WORD with + endian adjustment in SUBREG case. + Don't abort if can't make SUBREG needed for extv/extzv. + +Sat Mar 21 08:02:17 1998 Richard Gorton + + * alpha.md (zero_extendqi[hsd]i2): Use "and", not "zapnot". + +Sat Mar 21 07:47:04 1998 Richard Kenner + + * unroll.c (verify_addresses): Use validate_replace_rtx. + (find_splittable_givs): If invalid address, show nothing same_insn. + +Fri Mar 20 10:24:12 1998 Philippe De Muyter + + * fold-const.c (fold, case CONVERT_EXPR): Replace sign-extension of + a zero-extended value by a single zero-extension. + +Thu Mar 19 14:59:32 1998 Andrew Pochinsky + + * sparc.h (ASM_OUTPUT_LOOP_ALIGN): Fix error in last change. + +Thu Mar 19 14:48:35 1998 Michael Meissner + + * gcc.c (default_arg): Don't wander off the end of allocated memory. + + * rs6000/sysv4.h (RELATIVE_PREFIX_NOT_LINKDIR): Undef for System V + and EABI. + +Thu Mar 19 06:17:59 1998 Richard Kenner + + * Makefile.in (toplev.o): Depend on Makefile. + +Wed Mar 18 17:40:09 1998 Michael P. Hayes + + * expr.c (convert_move): Add [QH]Imode/P[QH]Imode conversions. + * machmode.def (PQImode, PHImode): New modes. + +Wed Mar 18 17:11:18 1998 Andreas Schwab + + * m68k.md (movsf+1): Optimize moving a CONST_DOUBLE zero. + +Wed Mar 18 17:07:54 1998 Ken Raeburn + + * regclass.c (init_reg_sets): Delete init of reg-move cost tables. + (init_reg_sets_1): Put it here. + +Wed Mar 18 16:43:11 1998 Jim Wilson + + * i960.md (tablejump): Handle flag_pic. + + * profile.c (branch_prob): If see computed goto, call fatal. + + * calls.c (expand_call): Fix typos in n_named_args computation. + +Wed Mar 18 05:54:25 1998 Richard Kenner + + * fold-const.c (operand_equal_for_comparison_p): See if equal + when nop conversions are removed. + + * expr.c (expand_expr, case COND_EXPR): If have conditional move, + don't use ORIGINAL_TARGET unless REG. + + * function.c (fixup_var_refs_insns): Also delete insn storing pseudo + back into arg list. + + * combine.c (gen_binary): Don't make AND that does nothing. + (simplify_comparison, case AND): Commute AND and SUBREG. + * i386.h (CONST_CONSTS, case CONST_INT): One-byte integers are cost 0. + +Mon Mar 16 15:57:17 1998 Geoffrey Keating + + * rs6000.c (small_data_operand): Ensure any address referenced + relative to small data area is inside SDA. + +Sun Mar 15 16:01:19 1998 Andrew Pochinsky + + * sparc.h (ASM_OUTPUT_LOOP_ALIGN): Write nop's. + +Sun Mar 15 15:53:39 1998 Philippe De Muyter + + * libgcc2.c (exit): Don't call __bb_exit_func if HAVE_ATEXIT. + +Sun Mar 15 15:44:41 1998 Paul Eggert + + * cccp.c: Fix bugs relating to NUL in input file name, + e.g. with `#line 2 "x\0y"'. + (PRINTF_PROTO_4): New macro. + (struct {file_buf,definition,if_stack}): New member nominal_fname_len. + (main, expand_to_temp_buffer): Store length of input file names. + (finclude, create_definition, do_line, conditional_skip): Likewise. + (skip_if_group, macroexpand): Likewise. + (make_{definition,undef,assertion}): Likewise. + (special_symbol, do_include): Use stored length of input file names. + (do_define, do_elif, do_else, output_line_directive, verror): Likewise. + (error_from_errno, vwarning, verror_with_line): Likewise. + (vwarning_with_line, pedwarn_with_file_and_line): Likewise. + (print_containing_files): Likewise. + (do_line): Fix off-by-1 problem: 1 too many bytes were being allocated. + (quote_string, pedwarn_with_file_and_line): New arg specifies length. + All callers changed. + +Sun Mar 15 15:38:16 1998 Andreas Schwab + + * c-typeck.c: Collect pending initializers in AVL tree instead of list. + (add_pending_init, pending_init_member): New functions. + (output_init_element): Use them. + (output_pending_init_elements): Rewritten to exploit AVL order. + +Sun Mar 15 05:10:49 1998 Richard Kenner + + * gnu.h (GNU_CPP_PREDEFINES): Deleted; not valid in traditional C. + * {i386,mips}/gnu.h (CPP_PREDEFINES): Don't call GNU_CPP_PREDEFINES. + + * flow.c (insn_dead_p): A CLOBBER of a dead pseudo is dead. + + * alpha.h (REG_ALLOC_ORDER): Put $f1 after other nonsaved. + + * sparc.c (sparc_type_code): Fix error in previous change. + +Sat Mar 14 05:45:21 1998 Richard Kenner + + * i386/xm-aix.h, i386/xm-osf.h (i386/xm-i386.h): Don't include. + (USG): Don't define. + * i386/xm-isc.h (i386/xm-sysv3.h): Don't include. + * i386/xm-sco.h (i386/xm-sysv3.h): Likewise. + (BROKEN_LDEXP, SMALL_ARG_MAX, NO_SYS_SIGLIST): Don't define. + * m68k/xm-3b1.h (m68k/xm-m68k.h): Don't include. + (USG): Don't define. + * m68k/xm-atari.h (m68k/xm-m68kv.h): Don't include. + (HAVE_VPRINTF, FULL_PROTOTYPES): Don't define. + * m68k/xm-crds.h (m68k/xm-m68k.h): Don't include. + (USE_C_ALLOCA, unos, USG): Don't define. + * m68k/xm-mot3300.h (m68k/xm-m68k.h): Don't include. + (USE_C_ALLOCA, NO_SYS_SIGLIST): Don't define. + * m68k/xm-plexus.h (m68k/xm-m68k.h): Don't include. + (USE_C_ALLOCA, USG): Don't define. + * m88k/xm-sysv3.h (m88k/xm-m88k.h): Don't include. + * m68k/xm-next.h (m68k/xm-m68k.h): Don't include. + * ns32k/xm-pc532-min.h (ns32k/xm-ns32k.h): Don't include. + (USG): Don't define. + * rs6000/xm-mach.h: Don't include xm-rs6000.h. + * rs6000/xm-cygwin32.h (rs6000/xm-rs6000.h): Don't include. + (NO_STAB_H): Don't define. + * sparc/xm-linux.h (xm-linux.h): Don't include. + * sparc/xm-sol2.h (sparc/xm-sysv4.h): Don't include. + * a29k/xm-unix.h, alpha/xm-linux.h, arm/xm-linux.h: Deleted. + * arm/xm-netbsd.h, i386/xm-bsd386.h, i386/xm-gnu.h: Deleted. + * i386/xm-linux.h, i386/xm-sun.h, i386/xm-sysv3.h: Deleted. + * i386/xm-winnt.h, m68k/xm-altos3068.h, m68k/xm-amix.h: Deleted. + * m68k/xm-amix.h, m68k/xm-hp320.h, m68k/xm-linux.h: Deleted. + * m68k/xm-m68kv.h, mips/xm-iris5.h, ns32k/xm-genix.h: Deleted. + * sparc/xm-pbd.h, vax/xm-vaxv.h, xm-svr3.h, xm-linux.h: Deleted. + * configure.in: Reflect above changes. + + * xm-siglist.h, xm-alloca.h: New files. + * i386/xm-sysv4.h (i386/xm-i386.h, xm-svr4.h): Don't include. + (USE_C_ALLOCA, SMALL_ARG_MAX): Don't define. + * i386/xm-sco5.h (i386/xm-sysv3.h): Don't include. + (SYS_SIGLIST_DECLARED, USE_C_ALLOCA): Don't define. + * rs6000/xm-sysv4.h, sparc/xm-sysv4.h: Don't include xm-svr4.h. + * xm-svr4.h, i386/xm-dgux.h, mips/xm-news.h, mips/xm-sysv4.h: Deleted. + * configure.in: Reflect above changes. + + * configure.in ({,host_,build_}xm_defines): New variables. + Set to USG instead of including xm-usg.h. + Write #define lines in config.h files from xm_defines vars. + * xm-usg.h: Deleted. + +Fri Mar 13 07:10:59 1998 Richard Kenner + + * calls.c (expand_call): Fix typo in previous change. + + * sparc.c (sparc_type_code): Avoid infinite loop when have + pointer to array of same pointer. + (sparc_type_code, case REAL_TYPE): Process subtypes here too. + + * mips/bsd-4.h, mips/iris3.h, mips/news{4,5}.h: Don't include mips.h. + * mips/news5.h, mips/osfrose.h, mips/svr{3,4}-4.h: Likewise. + * mips/ultrix.h: Likewise. + * mips/cross64.h: Don't include iris6.h. + * mips/ecoff.h: Don't include mips.h or gofast.h. + * mips/elforion.h: Don't include elf64.h. + * mips/iris4.h: Don't include iris3.h. + * mips/iris4loser.h: Don't include iris4.h. + * mips/iris5gas.h: Don't include iris5.h. + * mips/elflorion.h, mips/nws3250v4.h, mips/xm-iris{3,4}.h: Deleted. + * mips/xm-nws3250v4.h, mips/xm-sysv.h: Deleted. + * mips/rtems64.h: Don't include elflorion.h. + * mips/sni-gas.h: Don't include sni-svr4.h. + * mips/svr4-t.h: Don't include svr4-5.h. + * mips/dec-osf1.h: Also include mips.h. + * mips/ecoffl.h, mips/elf.h: Also include mips.h and gofast.h. + * mips/iris5.h: Also include iris3.h and mips.h. + * xm-usg.h: New file. + * mips/xm-iris5.h: Don't include xm-mips.h; don't define USG. + * mips/xm-news.h, mips/xm-sysv4.h: Don't include xm-sysv.h. + * configure.in: Reflect above changes. + +Thu Mar 12 07:18:48 1998 Richard Kenner + + * expr.h (STRICT_ARGUMENT_NAMING): Provide default value of 0. + * calls.c (expand_call): Use value of STRICT_ARGUMENT_NAMING. + * function.c (assign_parm): Likewise. + * mips/abi64.h (STRICT_ARGUMENT_NAMING): Return 0 for ABI_32. + * sparc.h (STRICT_ARGUMENT_NAMING): Only nonzero for V9. + + * calls.c (expand_call, expand_library_call{,_value}, store_one_arg): + Rework handling of REG_PARM_STACK_SPACE to treat return value of + zero as if macro not defined; add new arg to emit_push_insn. + * expr.c (emit_push_insn): New arg, REG_PARM_STACK_SPACE. + * expr.h (emit_push_insn): Likewise. + * mips/abi64.h (REG_PARM_STACK_SPACE): Define. + +Wed Mar 11 06:58:13 1998 Andreas Schwab + + * m68k.h (CONST_OK_FOR_LETTER_P, case 'M'): Correct range check. + +Wed Mar 11 06:15:52 1998 Richard Kenner + + * expr.c (emit_push_insn): Use loop to find movstr patterns + instead of explicit tests. + + * Makefile.in (extraclean): Don't delete install1.texi. + +Tue Mar 10 14:27:51 1998 Richard Kenner + + * combine.c (make_field_assignment): Don't get confused if OTHER + has VOIDmode and don't do anything if DEST is wider than a host word. + + * vax.c (check_float_value): Cast bcopy args to char *. + +Tue Mar 10 13:56:12 1998 Jim Wilson + + * mips/abi64.h (LONG_MAX_SPEC): Check MIPS_ABI_DEFAULT and + TARGET_DEFAULT and define __LONG_MAX__ appropriately. + Add support for -mabi=X, -mlong64, and -mgp{32,64} options. + * mips.c (mips_abi): Change type to int. + * mips.h (enum mips_abi_type): Delete. + (ABI_32, ABI_N32, ABI_64, ABI_EABI): Define as constants. + (mips_abi): Change type to int. + +Mon Mar 2 08:06:58 1998 Richard Kenner + + * Version 2.8.1 released. + + * Makefile.in (mostlyclean): Remove duplicate deletion of temp + files. Delete more stamp files and [df]p-bit.c + (clean): Don't delete stamp files here. + (VERSION_DEP): New variable. + (distdir-finish): Pass a value of null for it. + (version.c): Use it. + Avoid broken pipe with cvs log. + + * objc/Make-lang.in (objc/runtime-info.h): Rename emptyfile to + tmp-runtime and delete at end. + +Sun Mar 1 05:50:25 1998 Richard Kenner + + * tree.c (build_reference_type): Handle obstacks like + build_pointer_type. + + * Makefile.in (tmp-gcc.xtar): Renamed from gcc.xtar. + (gcc.xtar.gz): Deleted; merged with `dist'. + (diff): Create gcc-$(oldversion)-$(version).diff. + (distdir): Depend on distdir-cvs. + (distdir-cvs): New rule. + (distdir-start): Depend on version.c and TAGS. + (TAGS): Use tmp-tags instead of temp. + (dist): Create gcc-$(version).tar.gz. + + * varasm.c (compare_constant_1): Fix typo in previous change. + + * objc/Make-lang.in (objc-distdir): Properly rebuild objc-parse.c. + +Sat Feb 28 16:58:08 1998 Tristan Gingold + + * stmt.c (expand_decl): If -fcheck-memory-usage, put vars in memory. + * expr.c (get_memory_usage_from_modifier): Convert + EXPAND_{CONST_ADDRESS, INITIALIZER} to MEMORY_USE_DONT. + +Sat Feb 28 08:13:43 1998 Richard Kenner + + * i860/fx2800.h (DATA_ALIGNMENT): Use POINTER_TYPE_P. + * m68k/a-ux.h (FUNCTION_VALUE): Likewise. + * expr.c (get_pointer_alignment, compare, do_store_flag): Likewise. + (expand_builtin): Likewise. + * fold-const.c (force_fit_type, fold_convert, fold): Likewise. + * function.c (assign_parms): Likewise. + * integrate.c (expand_inline_function): Likewise. + * sdbout.c (sdbout_field_types): Likewise. + * tree.c (integer_pow2p, tree_log2, valid_machine_attribute): Likewise. + * stmt.c (expand_decl): Likewise. + ({,bc_}expand_decl_init): Also test for REFERENCE_TYPE. + + * configure.in (version_dep): New variable; if srcdir is CVS working + directory, set to ChangeLog. + (version): Supply default if no version.c. + * Makefile.in (version.c): New rule. + + * gcc.c (snapshot_warning): New function. + (main): Call it for snapshots. + + * dwarf2out.c (expand_builtin_dwarf_reg_size): If reg_raw_mode + not valid for reg, use last size. Also refine range assertion. + +Sat Feb 28 05:04:47 1998 Michael P. Hayes + + * enquire.c (cprop): Don't perform exhaustive search for char_min + and char_max when bits_per_byte > 16. + +Thu Feb 26 15:12:03 1998 Christopher Taylor + + * fixincludes: Avoid using '0-~' in egrep. + +Thu Feb 26 08:04:05 1998 Tristan Gingold + + * function.c (assign_parms): Call 'chkr_set_right' when DECL_RTL + is stack_parm. + * expr.c (get_memory_usage_from_modifier): Convert + EXPAND_{SUM, CONST_ADDRESS, INITIALIZER} to MEMORY_USE_RO. + +Thu Feb 26 07:33:53 1998 Paul Eggert + + * c-lex.c (yylex): Don't munge errno before using it. + * cccp.c (error_from_errno, perror_with_name): Likewise. + * cpplib.c (cpp_error_from_errno): Likewise. + * gcc.c (pfatal_pexecute): Likewise. + * protoize.c (safe_write, find_file, process_aux_info_file): Likewise. + (rename_c_file, edit_file): Likewise. + + * c-lex.c (yylex): Remove unused variable exceeds_double. + +Thu Feb 26 07:05:14 1998 Michael P. Hayes + + * reorg.c (fill_slots_from_thread): Don't steal delay list from target + if condition code of jump conflicts with opposite_needed. + +Thu Feb 26 06:45:23 1998 Richard Kenner + + * Makefile.in (distdir-start): Don't copy CVS subdirectory of config. + + * varasm.c ({compare,record}_constant_1, case CONSTRUCTOR): + Handle the case when we have TREE_PURPOSE values. + +Thu Feb 26 05:59:01 1998 Philippe De Muyter + + * fixincludes (sys/limits.h): Fix a nested comment problem with + HUGE_VAL definition on sysV68 R3V7.1. + +Wed Feb 25 21:09:38 1998 Philippe De Muyter + + * toplev.c (TICKS_PER_SECOND): Renamed from CLOCKS_PER_SECOND. + +Wed Feb 25 20:50:08 1998 Michael P. Hayes + + * reorg.c (fill_slots_from_thread): Mark resources referenced in + opposite_needed thread. Return delay_list even when cannot get + any more delay insns from end of subroutine. + +Wed Feb 25 19:50:01 1998 Mikael Pettersson + + * gcc.c (lookup_compiler): Remove redundant test. + +Wed Feb 25 07:24:22 1998 Richard Kenner + + * vax.md (call insns): Second operand to CALL rtl is SImode. + + * configure.in (i[34567]86-*-mingw32): Support msv and crt suffix. + * i386/crtdll.h: New file. + + * sparc.c (pic_setup_code): If -O0, write USE of pic_offset_table_rtx. + + * expr.c (safe_from_p): Add new arg, TOP_P; all callers changed. + +Sat Feb 21 07:02:39 1998 Jim Wilson + + * mips/iris5.h (DWARF2_UNWIND_INFO): Define to 0. + * mips/iris5gas.h (DWARF2_UNWIND_INFO): Define to 1. + +Fri Feb 20 08:27:46 1998 Paul Eggert + + * sparc/sol2-sld.h: New file. + * configure.in (sparc-*-solaris2*): Use it when using system linker. + * toplev.c (main): Don't default to DWARF2_DEBUG with -ggdb + if LINKER_DOES_NOT_WORK_WITH_DWARF2 is defined. + +Fri Feb 20 08:21:49 1998 H.J. Lu (hjl@gnu.org) + + * alpha/elf.h (STARTFILE_SPEC, ENDFILE_SPEC): Support shared library. + (LIB_SPEC, DEFAULT_VTABLE_THUNKS): Defined #ifndef USE_GNULIBC_1. + * sparc/linux.h (DEFAULT_VTABLE_THUNKS): Likewise. + (LIB_SPEC): Add -lc for -shared #ifndef USE_GNULIBC_1. + * linux.h (LIB_SPEC): Likewise. + * sparc/linux64.h (LIB_SPEC): Likewise; also updated for glibc 2. + (LIBGCC_SPEC): Removed. + (CPP_SUBTARGET_SPEC): Add %{pthread:-D_REENTRANT}. + +Fri Feb 20 05:22:12 1998 Richard Kenner + + * Makefile.in (distdir-start): Add dependence on bi-parser.[ch]. + +Thu Feb 19 18:07:11 1998 Jim Wilson + + * m68k.h (TARGET_SWITCHES): For 68000, 68302, subtract MASK_68881. + For 68303, 68332, cpu32, subtract MASK_68040_ONLY. + +Wed Feb 18 09:37:29 1998 Paul Eggert + + * fixincludes (stdlib.h): Do not double-wrap the size_t typedef. + +Wed Feb 18 07:32:11 1998 Jim Wilson + + * i960.c (emit_move_sequence): Handle unaligned stores to pseudos. + * i960.md (store_unaligned_[dt]i_reg): Handle register dest. + (store_unaligned_ti_reg): Likewise. + + * m68k.h (MACHINE_STATE_{SAVE,RESTORE} [MOTOROLA]): Add %# and %/; + add : to make them into extended asms. + +Wed Feb 18 07:08:05 1998 Richard Kenner + + * reg-stack.c (compare_for_stack_reg): Only handle FP conditional + move as next insn specially. + + * reload.c (find_reloads): Always convert address reload for + non-reloaded operand to RELOAD_FOR_OPERAND_ADDRESS. + + * emit-rtl.c (hard-reg-set.h): Include. + (get_lowpart_common): Don't make new REG for hard reg in a + class that cannot change size. + * Makefile.in (emit-rtl.o): Depend on hard-reg-set.h. + +Sat Feb 14 09:59:00 1998 Richard Earnshaw (rearnsha@arm.com) + + * arm.md (movsfcc): Also validate operands[3] for hard float. + (movdfcc): Only accept fpu_add_operand for operands[3].8 + +Sat Feb 14 09:32:34 1998 Jim Wilson + + * dwarf2out.c (expand_builtin_dwarf_reg_size): New variable mode. + Convert CCmode to word_mode before calling GET_MODE_SIZE. + +Sat Feb 14 09:27:42 1998 David Edelsohn + + * rs6000.h (MY_ISCOFF): Check for U803XTOCMAGIC. + +Sat Feb 14 08:29:43 1998 Arvind Sankar + + * t-svr4 (TARGET_LIBGCC_CFLAGS): New definition. + +Sat Feb 14 07:45:16 1998 Ken Rose (rose@acm.org) + + * reorg.c (fill_slots_from_thread): New parameter, delay_list. + All callers changed. + +Sat Feb 14 07:14:02 1998 Richard Kenner + + * reload.c (debug_reload): Properly output insn codes. + + * pa.c (emit_move_sequence): If in reload, call find_replacement. + + * gansidecl.h (bcopy, bzero, {,r}index): Don't define if IN_LIBGCC2. + + * combine.c (distribute_notes, case REG_DEAD): When seeing if place + to put new note sets register, use reg_bitfield_target_p, as in + original code. + + * gcc.c (process_command): If file is for linker, set lang to "*". + (lookup_compiler): Return 0 for language of "*". + + * sched.c (attach_deaths, case SUBREG): Fix error in last change. + + * i386.md (mov[sdx]fcc): Disable for now. + (mov[sd]fcc_1): Add earlyclobber for output on last alternative. + +Sat Feb 14 06:42:50 1998 Jason Merrill + + * except.c (get_dynamic_handler_chain): Only make call once per func. + (expand_fixup_region_{start,end}): New functions. + (expand_eh_region_start_tree): Store cleanup into finalization here. + * stmt.c (expand_cleanups): Use new functions to protect fixups. + + * except.c (get_dynamic_handler_chain): Build up a FUNCTION_DECL. + * optabs.c (init_optabs): Don't init get_dynamic_handler_chain_libfunc. + * expr.h (get_dynamic_handler_chain_libfunc): Deleted. + +Sat Feb 14 06:34:41 1998 Peter Lawrence + + * optabs.c (emit_conditional_move): Don't reverse condition for FP. + +Fri Feb 13 07:22:04 1998 Richard Kenner + + * Makefile.in (mostlyclean): Only use s-* convention for stamp + files in main dir. + + * configure.in: Add support for i786 (Pentium II); same as i686. + +Thu Feb 12 20:16:35 1998 Michael Meissner + + * rs6000.md: Replace gen_rtx (CONST_INT,...) with GEN_INT. + +Thu Feb 12 10:08:14 1998 John Hassey + + * configure.in (i[3456]86-dg-dgux*): Don't need fixincludes. + +Thu Feb 12 07:27:39 1998 Mumit Khan + + * i386/cygwin32.h (NO_IMPLICIT_EXTERN_C): Define. + about system headers. + (LIB_SPEC): Add -ladvapi32 -lshell32. + +Thu Feb 12 07:19:31 1998 Richard Kenner + + * expr.c (expand_assignment): Fix typo in checking OFFSET. + + * gbl-ctors.h (atexit): Don't define unless needed. + + * combine.c (distribute_notes): Completely check for note operand being + only partially set on potential note target; adjust what notes + we make in that case. + + * i386/xm-go32.h (HAVE_{BCOPY,BZERO,INDEX,RINDEX}): Deleted. + +Wed Feb 11 08:53:27 1998 Richard Kenner + + * calls.c (emit_call_1): Size args now HOST_WIDE_INT. + (expand_call): struct_value_size now HOST_WIDE_INT. + +Tue Feb 10 09:04:39 1998 Richard Kenner + + * integrate.c (initialize_for_inline): Ensure DECL_INCOMING_RTL + is always copied. + +Tue Feb 10 06:10:49 1998 Paul Eggert + + * cccp.c (rescan): Fix bug with macro name appearing + immediately after L'x'. + +Mon Feb 9 20:45:32 1998 Andreas Schwab + + * c-common.c (format_char_info): Add new field zlen. + (print_char_table): Remove entry for 'Z' as a format character. + Initialize zlen field as appropriate. + (scan_char_table): Set zlen field to NULL in each entry. + (check_format_info): Recognize 'Z' as a length modifier, with a + warning in pedantic mode. + Avoid infinite loop when a repeated flag character is detected. + +Mon Feb 9 09:24:04 1998 Paul Eggert + + * c-parse.in (primary): Minor wording fix in diagnostic. + +Mon Feb 9 07:50:19 1998 Richard Kenner + + * c-decl.c (grokdeclarator): Remove warning on inline of varargs. + + * reload.c (find_reloads): Check for const_to_mem case before + checking for invalid reload; use force_const_mem if no_input_reloads. + + * function.c (push_function_context_to): Call init_emit last. + + * protoize.c (my_link): Define as -1 in mingw32. + (link): Remove declaration. + + * rs6000.c (setup_incoming_varargs): Always set rs6000_sysv_varargs_p. + + * integrate.c (expand_inline_function): Clear label_map with bzero. + + * unroll.c (copy_loop_body, case JUMP_INSN): Correct error in last + change: call single_set on COPY, not INSN. + +Sun Feb 8 08:07:37 1998 Richard Kenner + + * msdos/top.sed, winnt/config-nt.sed: Change version number to 2.8.1. + + * configure.in (i[3456]86-*-sco3.2v5*): Use cpio for headers. + +Sat Feb 7 07:32:46 1998 Richard Kenner + + * i386/mingw32.h (LIBGCC_SPEC, STARTFILE_SPEC, MATH_LIBRARY): + Use msvcrt, not crtdll. + +Fri Feb 6 20:32:06 1998 Geert Bosch + + * i386/xm-os2.h (EMX, USG, BSTRING, HAVE_{PUTENV,VPRINTF,STRERROR}): + Define ifdef __EMX__. + (strcasecmp): Define to be stricmp if __EMX__. + (spawnv{,p}): Don't define if EMX. + (OBJECT_SUFFIX): Don't define if EMX. + (MKTEMP_EACH_FILE): Define. + +Fri Feb 6 16:37:29 1998 Kaveh R. Ghazi + + * objc/Make-lang.in (objc.stage1): Depend on stage1-start. + (objc.stage2, objc.stage3, objc.stage4): Likewise for the + respective stageN-start targets. + (objc/sendmsg.o): Depend on objc/runtime-info.h. + +Fri Feb 6 16:27:09 1998 Bernd Schmidt + + * stmt.c (expand_asm_operands): Properly treat asm statement + statements with no operands as volatile. + +Fri Feb 6 16:03:25 1998 Greg McGary + + * c-decl.c (pushdecl): Set DECL_ORIGINAL_TYPE once only. + +Fri Feb 6 15:57:36 1998 Mumit Khan + + * i386/cygwin32.h (STRIP_NAME_ENCODING): New macro. + +Fri Feb 6 15:50:42 1998 Paul Eggert + + * libgcc2.c (__floatdi[xtds]f): Round properly even when rounding + large negative integer to plus or minus infinity. + +Fri Feb 6 15:45:16 1998 Philippe De Muyter + + * sdbout.c (plain_type_1): Return T_DOUBLE, not T_VOID, for + long double #ifndef EXTENDED_SDB_BASIC_TYPES. + +Fri Feb 6 15:23:49 1998 John David Anglin + + * vax/ultrix.h (HAVE_ATEXIT): Define. + * x-vax: File deleted. + +Fri Feb 6 14:34:19 1998 Douglas Rupp + + * gcc.c (process_command, case "-dumpversion"): Print spec_version. + +Fri Feb 6 11:01:13 1998 Josh Littlefield + + * i386/gmon-sol2.c (internal_mcount): Do set-up when program starts + and install hook to do clean-up when it exits. + * i386/sol2-c1.asm (_mcount): Make a weak instead of global symbol. + * i386/sol2dbg.h (ASM_SPEC): Support Solaris bundled assembler's -V + argument; pass -s argument to assembler. + +Fri Feb 6 09:13:21 1998 Jim Wilson (wilson@cygnus.com) + + * function.c (assign_parms): New variable named_arg, with value + depending on STRICT_ARGUMENT_NAMING. Use instead of ! last_named. + + * crtstuff.c (__frame_dummy): New function for irix6. + (__do_global_ctors): Call __frame_dummy for irix6. + * mips/iris6.h (LINK_SPEC): Hide __frame_dummy too. + +Fri Feb 6 09:08:21 1998 Mike Stump + + * rtlanal.c (dead_or_set_regno_p): Ignore REG_DEAD notes after reload. + * genattrtab.c (reload_completed): Define. + + * configure.in (i960-wrs-vxworks): Same as i960-wrs-vxworks5*. + +Fri Feb 6 08:47:38 1998 Richard Kenner + + * Makefile.in (diff): Add INSTALL, configure, and config.in; + remove objc-*. + * objc/config-lang.in (diff_excludes): Add objc-parse.[cy]. + + * i386/xm-mingw32.h (link): Delete macro. + + * alpha.c (output_prolog): Write out frame sizes as longs and + print too large sizes as zero. + + * function.c (combine_temp_slots): No need to allocate and free rtx. + Don't do anything if too many slots in the list. + (put_var_into_stack): Don't use ADDRESSOF if not optimizing. + + * function.c (purge_addressof_1): Force into mem if VOLATILE reference. + + * calls.c (expand_call): Show VAR_DECL made for structure return + address is used; remove bogus set of MEM_IN_STRUCT_P. + * expr.c (expand_expr, case SAVE_EXPR, case TARGET_EXPR): Show used. + (expand_builtin, case BUILT_IN_LONGJMP): Show __dummy used. + * function.c (put_reg_into_stack): New arg USED_P; all callers changed. + + * expr.c (expand_expr, case SAVE_EXPR): assign_temp with KEEP of 3. + * function.c (var_temp_slot_level): New variable. + (push_function_context_to, pop_function_context_from): Save/restore + it and target_temp_slot_level. + (assign_stack_temp): Implement KEEP of 3. + (push_temp_slots_for_block): New function. + (init_temp_slots): Initialize var_temp_slot_level. + * function.h (struct function, fields {var,target}_temp_slot_level): + New fields. + * stmt.c (expand_start_bindings): Call push_temp_slots_for_block. + + * function.c (struct temp_slot): SIZE, BASE_OFF_SET, and FULL_SIZE + now HOST_WIDE_INT. + (assign_{,outer_}stack_local, assign_{,stack_}temp): Size arg is + now HOST_WIDE_INT. + (assign_stack_temp): Do size computations in HOST_WIDE_INT. + (fixup_var_refs_1, optimize_bit_field, instantiate_decls): Likewise. + (instantiate_virtual_regs_1, fix_lexical_address): Likewise. + * rtl.h (assign_stack_{local,temp}): Size arg is HOST_WIDE_INT. + (assign_temp): Likewise. + * expr.h (struct args_size): Field CONSTANT is now HOST_WIDE_INT. + + * sched.c (attach_deaths, case REG): Don't check for REG_UNUSED. + (attach_deaths, case SUBREG, STRICT_LOW_PART, {ZERO,SIGN}_EXTRACT): + Don't pass set_p of 1 if partial assignment. + + * tree.h (size_in_bytes): Returns HOST_WIDE_INT. + * tree.c (size_in_bytes): Likewise. + Tighen up logic some to avoid returning a bogus value instead of -1. + + * expr.c (get_inner_reference, case ARRAY_EXPR): Make WITH_RECORD_EXPR + just for index. + (expand_expr, case PLACEHOLDER_EXPR): Refine search again; look + at each expression and look for pointer to type. + + * expr.c (safe_from_p, case ADDR_EXPR): If TREE_STATIC, no trampoline. + (expand_expr, case ADDR_EXPR): Likewise. + + * expr.c (emit_block_move): Use conservative range for movstr mode. + + * configure.in: See if "cp -p" works if "ln -s" doesn't; else "cp". + + * combine.c (try_combine.c): Pass elim_i2 and elim_i1 to + distribute_notes for i3dest_killed REG_DEAD note. + + * configure.in (mips-dec-netbsd*): Remove bogus setting of prefix. + + * c-decl.c (duplicate_decls): Set DECL_IGNORED_P in newdecl if + different bindings levels. + + * configure.in: Test ln -s by symlinking gcc.c. + + * configure.in (i[3456]86-dg-dgux): Add wildcard for version. + + * crtstuff.c (__do_global_ctors_aux): Switch back to text section + in proper place. + + * rtlanal.c (rtx_varies_p, case REG): pic_offset_table_rtx is fixed. + * genattrtab.c (pic_offset_table_rtx): Define (dummy). + * cse.c (set_nonvarying_address_components): Understand PIC refs. + + * loop.c (strength_reduce): When placing increment for auto-inc + case, do comparison in loop order. + + * i860.c (output_delayed_branch): Add missing arg to recog. + (output_delay_insn): Add missing arg to constrain_operands. + + * configure.in: Truncate target after finished comparing it with host. + + * i386.h (MAX_FIXED_MODE_SIZE): Delete. + + * c-parse.in (expr_no_comma): Clarify undefined error. + + * prefix.c (get_key_value): Don't default to PREFIX here. + (translate_name): Remove bogus addition of "$" if getenv fails; + clean up application of default value of PREFIX. + + * fold-const.c (fold_convert): Call force_fit_type even if input + already overflows. + +Fri Feb 6 07:45:01 1998 Robert Hoehne + + * i386/xm-go32.h (HAVE_{BCOPY,BZERO,BCMP,RINDEX,INDEX}): Define. + + * gcc.c (main): Treat paths starting with '$' or DOS drives + as absolute in standard_startfile_prefix. + +Thu Feb 5 21:07:12 1998 John David Anglin + + * cpplib.c (IS_INCLUDE_DIRECTIVE_TYPE): Add casts from enum to int. + * cccp.c (IS_INCLUDE_DIRECTIVE_TYPE, handle_directive): Likewise. + +Thu Feb 5 19:00:44 1998 Richard Kenner + + * expr.c (expand_expr, case CONSTRUCTOR): Correct shift count + when making signed bit field; use EXPAND_NORMAL, not 0. + +Thu Feb 5 17:42:43 1998 Manfred Hollstein + + * libgcc2.c (__clear_insn_cache): On sysV68 enable the memctl + stuff only if MCT_TEXT is #define'd. + +Thu Feb 5 17:32:01 1998 Robert Hoehne + + * Makefile.in: Changed most stamp-* to s-*. + +Tue Feb 3 19:45:50 1998 James Hawtin + + * i386/sol2.h (STARTFILE_SPEC, LIB_SPEC): Update -pg files. + * configure.in (i[3456]86-*-solaris2*): Add gcrt1.o and gmon.o + to extra_parts. + +Tue Feb 3 17:28:48 1998 Christopher C Chimelis + + * configure.in (alpha*-*-linux-gnu*): Add extra_parts for crtstuff. + +Tue Feb 3 17:18:19 1998 Richard Earnshaw + + * arm.c (find_barrier): Fix one-too-many bug if fail to find barrier. + + * arm.c (arm_reload_in_hi): Handle cases where the MEM is too + complex for a simple offset. + +Tue Feb 3 16:14:21 1998 Robert Hoehne + + * i386/xm-go32.h (EXECUTABLE_SUFFIX): Define. + + * configure.in (i[3456]86-pc-msdosdjgpp*): New entry. + +Tue Feb 3 07:33:58 1998 Richard Kenner + + * explow.c (probe_stack_range): Properly check for small + number of probes. + + * gcc.c (process_command, case 'V'): Validate arg. + + * configure.in (sbrk): Add check for needed declaration. + * acconfig.h (NEED_DECLARATION_SBRK): New entry. + * toplev.c (sbrk): Update declaration conditional. + * mips-tfile.c (sbrk, free): Likewise. + + * sparc/sysv4.h (DBX_REGISTER_NUMBER): Remove abort. + + * mips.c (mips_expand_prologue): Pass reg 25 to gen_loadgp. + * mips.md (loadgp): Add second operand for register number to add. + (builtin_setjmp_receiver): Pass new label and reg 31 to loadgp. + + * toplev.c: Include insn-codes.h, insn-config.h, and recog.h. + (compile_file): Try to emit nop to separate gcc_compiled symbol. + * Makefile.in (toplev.o): Depends on insn-{codes,config}.h, recog.h. + +Tue Feb 3 06:58:46 1998 Mark Mitchell + + * integrate.c (get_label_from_map): New function. + (expand_inline_function): Use it. + Initialize label_map to NULL_RTX instead of gen_label_rtx. + (copy_rtx_and_substitute): Use get_label_from_map. + * integrate.h (get_label_from_map): New function. + (set_label_from_map): New macro. + * unroll.c (unroll_loop, copy_loop_body): Use them. + +Mon Feb 2 16:33:01 1998 Richard Kenner + + * i386.md (mov{si,hi,sf,df,xf}cc{,_1}): Remove cases with branches. + + * rs6000/x-aix31 (INSTALL): Deleted. + * mips/x-dec-osf1, mips/x-osfrose, i386/x-osfrose: Likewise. + * arm/x-riscix: Likewise. + + * c-typeck.c (signed_or_unsigned_type): Properly handle pointer types. + +Mon Feb 2 15:33:58 1998 Michael P. Hayes + + * unroll.c (copy_loop_body): Use single_set instead of + PATTERN to detect increment of an iv inside a PARALLEL. + +Fri Jan 16 20:29:50 1998 Paul Eggert + + * toplev.c (): New include. + (get_run_time): Prefer CLK_TCK (if available) to HZ, and + prefer sysconf (_SC_CLK_TCK) (if available) to CLK_TCK. + * configure.in (sysconf): Call AC_CHECK_FUNCS. + +Wed Jan 14 20:10:51 1998 Paul Eggert + + * cccp.c: (rescan): Don't report line 0 as the possible real start + of an unterminated string constant. + Don't mishandle backslash-newlines that in are the output of + a macro expansion. Properly skip // style comments between a function + macro name and '(', as well as backslash-newlines in comments there. + (handle_directive): Handle / \ newline * between # and directive name. + In #include directives, \ does not escape ". + (do_include): For `#include "file', do not bother expanding into temp + buffer. When error encountered when expanding, do not try result. + (skip_if_group): When skipping an include directive, use include + tokenization, not normal tokenization. Backslash-newline is still + special when skipping. Handle * \ newline / correctly in comments + when skipping. + (skip_quoted_string): After \ newline, set *backslash_newlines_p + even if count_newlines is 0. + (macroexpand): Newline space is not a special marker inside a string. + (macroexpand, macarg): Do not generate \ddd for control characters + when stringifying; the C Standard does not allow this. + (macarg1): New arg MACRO. All callers changed. + Do not treat /*, //, or backslash-newline specially when processing + the output of a macro. + (discard_comments): Don't go past limit if looking for end of comment. + Discard backslash-newline properly when discarding comments. + (change_newlines): \" does not end a string. + (make_definition): Do not treat backslash-newline specially, as it + has already been removed before we get here. + + * profile.c (output_func_start_profiler): Don't fflush output + if -quiet. + * toplev.c (rest_of_compilation): Likewise. + + * i386/x-sco5 (CC): Remove trailing white space. + * x-convex (CCLIBFLAGS): Likewise. + * arm/t-semi (LIBGCC2_CFLAGS): Likewise. + +Wed Jan 7 18:02:42 1998 Richard Kenner + + * Version 2.8.0 released. + +Wed Jan 7 17:54:41 1998 J. Kean Johnston + + * i386/sco5.h ({END,START}FILE_SPEC): Link with correct crtbegin.o + and crtend.o when using -static. + +Wed Jan 7 17:49:14 1998 Jan Christiaan van Winkel + + * cppexp.c (gansidecl.h): Include. + +Wed Jan 7 17:45:07 1998 Tristan Gingold + + * expr.c (get_push_address): Use copy_to_reg instead of force_operand. + (emit_push_insn): Avoid null pointer deference if aggregate has no + types. + (expand_expr): Avoid finite but useless recursion. + (expand_builtin): Fix typo in calling function. + * function.c (assign_parms): Avoid useless call to chkr_set_right. + +Wed Jan 7 17:31:13 1998 Christian Iseli + + * combine.c (force_to_mode): Return if operand is a CLOBBER. + +Wed Jan 7 17:23:24 1998 Richard Kenner + + * x-rs6000 (INSTALL): Remove. + + * jump.c (jump_optimize): Don't use a hard reg as an operand + of a conditional move if small register classes. + +Wed Jan 7 17:09:28 1998 Jim Wilson + + * cse.c (max_insn_uid): New variable. + (cse_around_loop): Use it. + (cse_main): Set it. + +See ChangeLog.11 for earlier changes. + +Use a consistent time stamp format in ChangeLog entries. +Not everyone has Emacs 20 yet, so stick with Emacs 19 format for now. + +Local Variables: +add-log-time-format: current-time-string +End: diff --git a/gcc_arm/FSFChangeLog.10 b/gcc_arm/FSFChangeLog.10 new file mode 100755 index 0000000..513ac72 --- /dev/null +++ b/gcc_arm/FSFChangeLog.10 @@ -0,0 +1,10110 @@ +Sun Mar 31 05:10:10 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * stor-layout.c (layout_decl): Don't make a bitfield an integral mode + if the mode of the field type is not MODE_INT. + + * sched.c (schedule_block): CALL_INSNs don't affect fixed regs. + * flow.c (propagate_block): CALL_INSNs don't kill fixed regs. + +Sat Mar 30 03:32:48 1996 Torbjorn Granlund + + * expmed.c (expand_divmod, case TRUNC_DIV_EXPR): Move some code + to avoid shifting by a too large count. + +Fri Mar 29 15:45:51 1996 Doug Evans + + * configure (i[3456]86-*-sunos5*): Delete, config.sub converts + sunos5 to solaris2. + (sparc-*-sunos5*): Likewise. + (sparc64-*-{solaris2*,sunos5*}): Delete. Stick with sparc-*-solaris2*. + + * sparc.h (FUNCTION_PROFILER): Save/restore %g2 around mcount call. + +Fri Mar 29 14:20:31 1996 Stan Cox + + * i386.c (notice_update_cc): Clear cc_status if ref modified MEM. + +Fri Mar 29 09:37:52 1996 Jeffrey A. Law + + * calls.c (expand_call): Remove current_call_is_indirect nonsense. + Add additional argument to INIT_CUMULATIVE_ARGS. + (emit_library_call): Likewise. + (emit_library_call_value): Likewise. + * expr.c (expand_builtin): Likewise. + * function.c (assign_parms): Likewise. + * pa.h (hppa_args): New field "indirect". + (INIT_CUMULATIVE_ARGS): Initialize "indirect" field. + (FUNCTION_ARG): Check "indirect" field, rather than + "current_call_is_indirect". + * a29k.h (INIT_CUMULATIVE_ARGS):New arg, INDIRECT. + * alpha.h (INIT_CUMULATIVE_ARGS): Likewise. + * arm.h (INIT_CUMULATIVE_ARGS): Likewise. + * clipper.h (INIT_CUMULATIVE_ARGS): Likewise. + * convex.h (INIT_CUMULATIVE_ARGS): Likewise. + * dsp16xx.h (INIT_CUMULATIVE_ARGS): Likewise. + * elxsi.h (INIT_CUMULATIVE_ARGS): Likewise. + * fx80.h (INIT_CUMULATIVE_ARGS): Likewise. + * gmicro.h (INIT_CUMULATIVE_ARGS): Likewise. + * h8300.h (INIT_CUMULATIVE_ARGS): Likewise. + * i370/mvs.h (INIT_CUMULATIVE_ARGS): Likewise. + * i386.h (INIT_CUMULATIVE_ARGS): Likewise. + * i860.h (INIT_CUMULATIVE_ARGS): Likewise. + * i960.h (INIT_CUMULATIVE_ARGS): Likewise. + * m68k.h (INIT_CUMULATIVE_ARGS): Likewise. + * m68k/mot3300.h (INIT_CUMULATIVE_ARGS): Likewise. + * m88k.h (INIT_CUMULATIVE_ARGS): Likewise. + * mips.h (INIT_CUMULATIVE_ARGS): Likewise. + * ns32k.h (INIT_CUMULATIVE_ARGS): Likewise. + * pdp11.h (INIT_CUMULATIVE_ARGS): Likewise. + * pyr.h (INIT_CUMULATIVE_ARGS): Likewise. + * romp.h (INIT_CUMULATIVE_ARGS): Likewise. + * rs6000.h (INIT_CUMULATIVE_ARGS): Likewise. + * sh.h (INIT_CUMULATIVE_ARGS): Likewise. + * sparc.h (INIT_CUMULATIVE_ARGS): Likewise. + * spur.h (INIT_CUMULATIVE_ARGS): Likewise. + * tahoe.h (INIT_CUMULATIVE_ARGS): Likewise. + * vax.h (INIT_CUMULATIVE_ARGS): Likewise. + * we32k.h (INIT_CUMULATIVE_ARGS): Likewise. + * mips.c (mips_expand_prologue): Add extra arg to + INIT_CUMULATIVE_ARGS call. + +Thu Mar 28 18:45:49 1996 Richard Kenner + + * alpha.c (summarize_insn): Fix three "off-by-one" bugs in loop bounds. + +Thu Mar 28 16:50:10 1996 Doug Evans + + * ginclude/inl-sparc.h: Deleted. + +Thu Mar 28 12:07:31 1996 Jeffrey A. Law + + * va-h8300.h (va_arg): Don't assume sizeof (int) == 4. + + * pa.c (hppa_legitimize_address): Don't lose for + (plus (plus (mult (A) (shadd_const)) (B)) (C)) if + B + C isn't a valid address for indexing. + (basereg_operand): Only accept base registers after + cse has completed. Don't accept the frame pointer if + it's likely to be eliminated. + * pa.md (unscaled indexing patterns): Add variants with + basereg and index register reversed. + (HImode and QImode loads): Add zero extended variants. + +Wed Mar 27 07:45:27 1996 Richard Kenner + + * expmed.c (negate_rtx): Fix typo in previous change. + +Tue Mar 26 13:50:43 1996 Jim Wilson + + * calls.c (expand_call): In convert_to_mode call, use word_mode + not SImode. + +Tue Mar 26 13:44:34 1996 Doug Evans + + * configure: Delete unnecessary special handling of --with-cpu. + +Tue Mar 26 10:41:57 1996 Jeffrey A. Law + + * expr.c (emit_push_insn): When doing a partial push, emit + a CLOBBER so that flow doesn't think the entire register + is live. + +Tue Mar 26 10:00:52 1996 Richard Kenner + + * alpha.c (summarize_insn, default case): Properly use format_ptr. + +Tue Mar 26 09:51:09 1996 Philippe De Muyter (phdm@info.ucl.ac.be) + + * m68k.h (output_move_simode_const): New extern declaration. + * m68k.c (output_move_simode_const): New function. + (singlemove_string): Call it. + * m68k.md (fullword move): Likewise. + +Tue Mar 26 05:43:06 1996 Torbjorn Granlund + + * vax.md (insv matcher): Call CC_STATUS_INIT. + * vax.h (NOTICE_UPDATE_CC): Handle ZERO_EXTRACT destination. + +Mon Mar 25 19:18:08 1996 Jason Merrill + + * function.c (expand_function_start): Don't set up context_display + unless current_function_needs_context. + +Mon Mar 25 18:48:18 1996 Philippe De Muyter + + * fold-const.c (fold, case BIT_IOR_EXPR): Recognize rotates + with variable count. + +Mon Mar 25 18:05:28 1996 Jim Wilson + + * Makefile.in (libgcc1-test): Undo Feb 12 change. + +Mon Mar 25 08:09:59 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * objc/thread-single.c (objc_mutex_unlock): Properly declare thread_id. + +Mon Mar 25 08:02:50 1996 Philippe De Muyter + + * configure (m68k-motorola-sysv*): Fixed indentation. + +Sun Mar 24 08:16:42 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expmed.c (negate_rtx): Don't try to negate a constant ourself; + instead call simplify_unary_operation. + +Sun Mar 24 07:29:06 1996 Richard Henderson + + * gcc.c (process_command): Instead of hardcoding non-empty + switches_need_spaces to turn on "o" and "L", make the string + contain the switches that need the spaces. + * m68k/ccur-GAS.h (SWITCHES_NEED_SPACES): Change definition + correspondingly. + +Sat Mar 23 18:34:44 1996 Harry Dolan + + * i860/paragon.h (LIB_SPEC): Always output -lmach. + +Sat Mar 23 18:25:39 1996 J"orn Rennecke (amylaar@meolyon.hanse.de) + + * c-typeck.c (set_init_index): Check for use outside an array + initializer. + + * defaults.h (ASM_OUTPUT_ADDR_DIFF_ELT): Delete. + * pdp11.h (ASM_OUTPUT_ADDR_DIFF_ELT): Don't define. + +Sat Mar 23 15:55:35 1996 Doug Evans + + * combine.c (make_extraction): In BITS_BIG_ENDIAN correction of POS, + need to treat MEM and REG differently. + + * sparc.h (SPARC_SIMM{10,11,13}_P): Define. + (SMALL_INT): Use SPARC_SIMM13_P. + (CONST_OK_FOR_LETTER_P): Support new letters L,M. + * sparc.c (arith11_operand): Use SPARC_SIMM11_P. + (arith10_operand): Use SPARC_SIMM10_P. + * sparc.md (*mov{qi,hi,si,di}_cc_sp64): Fix constraints. + (*mov{qi,hi,si,di}_cc_reg_sp64): Likewise. + +Sat Mar 23 07:47:19 1996 Andreas Schwab + + * m68k/linux.h (TRAMPOLINE_TEMPLATE): Correct first instruction. + * m68k/m68kv4.h (TRAMPOLINE_TEMPLATE): Likewise. + +Sat Mar 23 07:06:55 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * bc-emit.c (bc_emit_instruction): Add missing va_end call. + + * c-typeck.c (build_array_ref): Give error if subscripting a function. + +Fri Mar 22 09:11:45 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * local-alloc.c (optimize_reg_copy_1): Only update reg_live_length + if it is non-negative. + +Thu Mar 21 14:42:26 1996 Doug Evans + + * sparc/splet.h (STARTFILE_SPEC,LINK_SPEC): Define. + +Wed Mar 20 17:23:18 1996 Jim Wilson + + * cse.c (note_mem_written): Delete obsolete code for handling + (mem (scratch)). + + * mips.c (mips_expand_prologue): In initialization of fnargs, delete + special treatment of METHOD_TYPE. + +Wed Mar 20 17:07:45 1996 Doug Evans + + * sparc/sol2.h (ASM_CPU_SPEC): Recognize -mcpu=v8plus, not v9. + Fix typo in ultrasparc entry. + * sparc.h (CPP_CPU_SPEC): Add v8plus entry. + (ASM_CPU_SPEC): Likewise. + + * sparc.c (fcc_reg_operand): Ensure correct mode. + (icc_or_fcc_reg_operand): Likewise. + (gen_v9_scc): IF_THEN_ELSE must have a mode. + (print_operand): New operand code `x' for all condition codes. + New operand codes `c,d' for reversed conditional moves. + * sparc.md (movqicc,movhicc): New named patterns. + (movdicc): if_then_else must have a mode. + (movsicc,movsfcc,movdfcc,movtfcc): Likewise. + Change condition to TARGET_V9, not TARGET_ARCH64. + Fail if DImode compare and ! TARGET_ARCH64. + (conditional move matchers): Rewrite. + +Wed Mar 20 16:12:29 1996 Stan Cox + + * i386.h (HARD_REGNO_MODE_OK): Relax QImode constraint to + avoid a reload problem. + +Wed Mar 20 13:12:22 1996 Jeffrey A. Law + + * pa.c (hppa_legitimize_address): Don't lose for x[n-const] + when n-const will not be shifted. Don't pessimize code for + x[n-const] when const is small. + +Wed Mar 20 11:42:32 1996 Markus Theissinger + + * m68k/sun3.h (LIB_SPEC): Don't link /usr/lib/bb_link.o with `gcc -a'. + (__bb_init_func): Deleted. + (BLOCK_PROFILER_CODE): Don't set macro to nothing. + + * m68k/xm-sun3.h: New file. + * configure (m68k-sun-sunos*): Use it. + + * xm-linux.h (HAVE_POPEN): New define. + +Wed Mar 20 11:28:37 1996 Andreas Schwab + + * m68k/linux.h (ASM_SPEC): Deleted. + (STRUCT_VALUE_REGNUM): Redefine as register a0. + (STATIC_CHAIN_REGNUM): Redefine as register a1. + (TRAMPOLINE_TEMPLATE): Redefine to use the right register. + +Wed Mar 20 08:04:34 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * libgcc2.c (__dummy): New function. + * Makefile.in (LIB2FUNCS): Add __dummy. + * expr.c (expand_builtin, case BUILT_IN_SETJMP): Call "setjmp" + pattern, if any. + Call dummy function pointed to by static chain pointer. + (expand_builtin, case BUILT_IN_LONJMP): Ignore second expression. + Set address of __dummy into static chain pointer. + Copy the label to return to into a pseudo earlier. + + * stupid.c (last_setjmp_suid, regs_crosses_setjmp): New variables. + (stupid_life_analysis, stupid_mark_refs): Use them to track which + regs are live over a setjmp; don't allocate such regs. + +Tue Mar 19 22:02:07 1996 Jason Merrill + + * cplus-dem.c (demangle_template): Fix for non-mangled pointer + arguments. + +Tue Mar 19 13:54:06 1996 Jeffrey A. Law + + * pa.c (compute_frame_size): Update comments to reflect reality. + (hppa_expand_prologue): Don't save registers which aren't + used, even if it creates holes. Partially undoes changes from + early March. + (hppa_expand_epilogue): Likewise. + +Tue Mar 19 08:25:17 1996 J"orn Rennecke (amylaar@meolyon.hanse.de) + + * stmt.c (struct case_node): New member balance. + (add_case_node): New function. + (pushcase, pushcase_range): Use it. + (case_tree2list): New function. + (expand_end_case): Use it. + +Tue Mar 19 07:44:22 1996 Stephen L Moshier (moshier@world.std.com) + + * regstack.c (move_for_stack_reg): Avoid stack overflow while + storing XFmode from fp reg to memory. + +Tue Mar 19 07:38:03 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * m68k.h (MASK_*): New macros. + (OVERRIDE_OPTIONS): Use them. + (TARGET_SWITCHES): Likewise. + Treat -m68332 like -m68000. + +Mon Mar 18 20:04:13 1996 Richard Earnshaw (rearnsha@armltd.co.uk) + + * expmed.c (emit_store_flag): If expanding (GE X 0) will need two + insns, don't use subtarget for the result of the first insn. + Move a likely constant to the start of a condition. + +Mon Mar 18 19:48:14 1996 Philippe De Muyter + + * m68k.h (CONST_OK_FOR_LETTER_VALUE): New constraint 'M'. + * m68k.c (output_function_epilogue): Restore registers using sp+ + instead of fp(n) in leaf functions. + (USE_MOVQ, use_movq): Function replaced by macro. + * m68k.md (pushexthisi_const, movsi_const0): New names. + (andsi3, iorsi3): Allow only 'M', not 'K' constants, if dest is 'd'. + +Mon Mar 18 19:33:20 1996 Fila Kolodny + + * i370/t-mvs: New file. + * configure (i370-*-mvs*): Use it. + * i370/mvs.h (FUNCTION_PROLOGUE): LE/370 takes 120 bytes for DSA. + Have only one copy of timestamp and PPA2 per object module. + Only have unnamed CSECT to match IBM C. + +Mon Mar 18 19:26:21 1996 Paul Russell (Rusty.Russell@adelaide.maptek.com.au) + + * combine.c (simplify_if_then_else): Allow for case that + condition might no longer be a condition. + +Mon Mar 18 19:14:42 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * c-typeck.c (build_conditional_expr): If OP1 is null, set + both OP1 and ORIG_OP1 to IFEXP. + + * c-iterate.c (iterator_loop_epilogue): Don't clear DECL_RTL + for a static decl. + +Mon Mar 18 08:02:25 1996 Stephen L Moshier + + * alpha.c (summarize_insn, case SUBREG, CONST_*): New cases. + +Sun Mar 17 16:55:00 1996 Doug Evans + + * combine.c (find_split_point): Handle NULL return from + make_extraction. + (make_field_assignment): Likewise. + +Sat Mar 16 18:56:47 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * tree.c (substitute_in_expr, case COMPONENT_REF): Ignore + if inner PLACEHOLDER_EXPR has not yet been initialized. + + * i386.c (standard_80386_constant_p): -0.0 is not 0.0. + * i386.md (insv): Restore missing end of comment. + + * combine.c (make_extraction): Correct typo in force_to_mode + call in previous change. + Return 0 if pos+len out of range of want desired mode. + +Sat Mar 16 16:20:43 1996 David Mosberger-Tang + + * alpha.md (trap): New attribute. + Modify patterns for all floating-point trap generating instructions. + * alpha.h (CPP_SPEC): Added -mieee and -mieee-with-inexact. + (alpha_trap_precision, alpha_fp_rounding_mode, alpha_fp_trap_mode): + New enum types. + (target_flags, alpha_tp, alpha_fprm, alpha_fptm): New external vars. + (alpha_fprm_string, alpha_fptm_string, alpha_tp_string): Likewise. + (TARGET_IEEE{,_WITH_INEXACT,_CONFORMANT}): New macros. + (MASK_IEEE{,_WITH_INEXACT,_CONFORMANT}): Likewise. + (MASK_FP, MASK_FPREGS, + (TARGET_SWITCHES): Added "ieee-conformant", "ieee", and + "ieee-with-inexact"; use MASK symbols. + (TARGET_OPTIONS): New macro. + (OVERRIDE_OPTIONS, FINAL_PRESCAN_{INSN,LABEL}): New macros. + (PRINT_OPERAND_PUNCT_VALID_P): Allow operand codes for FP insns. + (CC1_SPEC): New macro. + * alpha.c (alpha_tp, alpha_fprm, alpha_fptm): New variables. + (alpha_tp_string, alpha_fprm_string, alpha_fptm_string + (trap_pending): Likewise. + (override_options, summarize_insn, final_prescan_insn): New functions. + (print_operand): Handle cases '&', '\'', ')', and '+'. + (output_prolog): Emit ".eflag 48" if TARGET_IEEE_CONFORMANT. + (output_epilog): Call final_prescan_insn before emitting epilog. + + * final.c (final_scan_insn, case CODE_LABEL): Invoke + FINAL_PRESCAN_INSN if FINAL_SCAN_LABEL is defined. + + * alpha/{linux.h,x-linux,xm-linux.h}: New files. + * configure (alpha-*-linux*): New case. + * alpha.c (output_prolog): Set alpha_function_needs_gp if profiling + and TARGET_PROFILING_NEEDS_GP defined. + +Thu Mar 14 22:28:20 1996 David Edelsohn + + * rs6000.h (LEGITIMATE_OFFSET_ADDRESS_P): Fix last change. + * aix41.h (LINK_SPEC): add -bnoentry if shared and no explicit entry. + +Thu Mar 14 12:47:33 1996 Jim Wilson + + * mips.h (ASM_OUTPUT_DOUBLE_INT): Use 'X' if CONST_INT and + HOST_BITS_PER_WIDE_INT == 64. + + * mips.c (mips_expand_prologue): Change TYPE_NEEDS_CONSTRUCTING to + TREE_ADDRESSABLE; + +Thu Mar 14 11:21:37 1996 Michael Meissner + + * rs6000.h (LEGITIMATE_OFFSET_ADDRESS_P): For 32-bit mode, + allow TImode variables with int offsets, so that structures + greater than 8 bytes and less than or equal to 16 bytes can be + instantiated correctly. + + * rs6000.c (rs6000_valid_type_attribute_p): Add exception + attribute for Windows NT. + + * win-nt.h (ASM_OUTPUT_FUNCTION_PREFIX): Delete, merge into + ASM_DECLARE_FUNCTION_NAME. + (ASM_DECLARE_FUNCTION_NAME): Add support for exception attribute + setting fields 3 & 4 of the structured exception handling table. + +Thu Mar 14 01:53:19 1996 Jeffrey A. Law + + * pa.h (ASM_DECLARE_FUNCTION_NAME): Change TYPE_NEEDS_CONSTRUCTING + to TREE_ADDRESSABLE. From Jim Wilson. + +Wed Mar 13 13:40:32 1996 Jim Wilson + + * c-tree.h (warn_sign_compare): Add extern to declaration. + +Wed Mar 13 13:37:00 1996 Doug Evans + + * configure: Use cross-make and build-make if building + cross compiler with cross compiler. + +Wed Mar 13 12:00:34 1996 Michael Meissner + + * i386/cygwin32.h (ASM_OUTPUT_ALIGN): Correct defination. + + * rs6000/{win-nt,cygwin32}.h (STARTFILE_SPEC): Add crti.o before + all objects. + (ENDFILE_SPEC): Add crtn.o after all objects. + + * configure (powerpcle-*-cygwin32): Use t-winnt, not t-cygin32 + * rs6000/t-cygwin32: Delete, no longer used. + + * rs6000/t-winnt ({,INSTALL_}LIBGCC): Build and install crti.o and + crtn.o. + + * rs6000/win-nt.h (EXTRA_SECTION_FUNCTIONS): Add ctors_section and + dtors_section. + (INVOKE__main): Define, so that __main is called. + (ASM_OUTPUT_{CONSTRUCTOR,DESTRUCTOR}): Define to put pointers to + the constructor/destructor in the appropriate section. + + * nt-c{i,n}.asm: New files to be linked before/after all of the users' + objects. + +Wed Mar 13 00:42:17 1996 Per Bothner + + * dbxout.c (dbxout_type): Better "variant" handling to ignore + const/volatile but not typedef names. Improves Feb 12 change. + +Tue Mar 12 17:25:14 1996 David Mosberger-Tang + + * glimits.h (__LONG_MAX__): On Alpha, use 64 bit value. + +Tue Mar 12 15:07:49 1996 Torbjorn Granlund + + * m68k.c (valid_dbcc_comparison_p): Don't test cc_prev_status here. + (flags_in_68881): New function. + * m68k.md (dbra peepholes): Use flags_in_68881. + +Tue Mar 12 13:54:15 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * sparc.md (nonlocal_goto): Emit barrier after jump. + (setjmp{,_64,_32}): New patterns. + +Tue Mar 12 12:43:27 1996 Jim Wilson + + * i960.h (ROUND_TYPE_SIZE): Return round_up result instead of + COMPUTED. + + * expr.c (expand_expr, case COMPONENT_REF): For unaligned object in + an aligned union, delete check for EXPAND_SUM. + + * expr.h (clear_storage): Add comment terminator. + +Mon Mar 11 19:07:50 1996 Jeffrey A. Law + + * recog.c (constrain_operands, case 'V'): Don't call + offsettable_memref_p before reload has completed. + +Mon Mar 11 16:06:13 1996 Doug Evans + + * h8300.h (SP_AND_G_REGS): Renamed from SP_AND_G_REG. + (CC_DONE_CBIT): Delete. + (CC_OVERFLOW_0,CC_OVERFLOW_UNUSABLE,CC_NO_CARRY): Define. + * h8300.c (cond_string): Delete CC_DONE_CBIT handling. + (notice_update_cc): Delete CC_CBIT, CC_WHOOPS. Add CC_SET_ZN_C0. + (restore_compare_p): New function. + (shift_one): Use shll instead of shal so overflow bit is usable. + Set cc_valid bits to cc_status.flags values. + (emit_a_shift): Set cc_status.flags. + * h8300.md (attr cc): Delete whoops,cbit. Add set_zn_c0. + (all patterns) Update cc attr setting. + (tstqi,tsthi,tstsi): Delete CC_DONE_CBIT handling. + (addhi3,subhi3): Change define_expand to define_insn. + (branch_true,branch_false): Check if compare needs to be restored. + +Mon Mar 11 13:55:23 1996 Michael Meissner + + * rs6000.h (CONST_DOUBLE_OK_FOR_LETTER_P): Add 'H' for movdi + patterns in 32 bit that generate 3 instructions. + (num_insns_constant): Add declaration. + + * rs6000.c (num_insns_constant{,_wide}) Functions to determine the + number of insns it takes to generate an integer constant. + (easy_fp_constant): Allow DImode in easy constants. Use + num_insns_constant_wide. + (input_operand): Allow any CONST_{INT,DOUBLE}'s for {SI,DI}mode. + + * rs6000.md (movdi): Generate a normal movdi using a CONST_DOUBLE + for 32 bit mode rather than using SUBREG's. For 64 bit mode, + break large integer constants into smaller pieces. Add various + define_splits to handle loading the various DImode constants. + +Mon Mar 11 06:54:19 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * combine.c (make_extraction): Use proper mode for INNER in all cases. + (simplify_comparison, case ZERO_EXTRACT): For bits big endian and + no extzv, use BITS_PER_WORD. + * fx80.md, gmicro.md, i386.md, m68k.md, tahoe.md, vax.md: + Use proper modes and predicates for {sign,zero}_extract. + +Sun Mar 10 06:23:52 1996 J"orn Rennecke (amylaar@meolyon.hanse.de) + + * emit-rtl.c (free_insn): New variable. + (init_emit, restore_emit_status): Clear it. + (gen_sequence): Store insn in free_insn when sequence length is 1. + (make_insn_raw): Use free_insn if available and still in the + rtl generation phase. + +Fri Mar 8 15:37:31 1996 Mike Stump + + * expr.c (expand_expr, case TARGET_EXPR): Delay putting the cleanup + on the cleanup chain until after the subexpression has been expanded. + +Fri Mar 8 16:14:51 1996 J"orn Rennecke (amylaar@meolyon.hanse.de) + + * i386.c (ix86_binary_operator_ok): One memory operand is OK. + This is independent of commutativity. + +Fri Mar 8 14:07:43 1996 Jim Wilson + + * expr.c (store_constructor_field): Call store_field if bitpos is + nonzero and target is not a MEM. + + * jump.c (jump_optimize): When handle a USE insn before an + unconditional jump, disable the optimization if the USE is the + only insn in the loop. + + * sh.c (reg_unused_after): Return 0 if see a JUMP_INSN. + +Fri Mar 8 12:08:36 1996 Doug Evans + + * sparc/lynx.h (CPP_SPEC): Use %(cpp_cpu). + + * sparc/sparc.md (move_pic_label_si,move_label_di): Rewrite length + attr calcs to be more conservative. + +Thu Mar 7 19:14:21 1996 Doug Evans + + * sparc/t-splet: New file. + * sparc/splet.h: New file. + * configure (sparclet-*-aout*): Use them. + + * sparc.h (MASK_LIVE_G0,TARGET_LIVE_G0): Define. + (FIRST_PSEUDO_REGISTER): Add 1 for %icc (now 101). + (FIXED_REGISTERS,CALL_USED_REGISTERS): Update. + (FIXED_REGISTERS): %g0 is fixed by default. + (SPARC_{FIRST,LAST}_V9_FCC_REG): Define. + (SPARC_{ICC,FCC}_REG): Define. + (CONDITIONAL_REGISTER_USAGE): Don't fix %fcc0 if v8. + (REG_CLASS_CONTENTS): Reg 0 is an int reg, reg 100 is %icc. + (REGNO_REG_CLASS): Rewrite to use global `sparc_regno_reg_class'. + (REG_ALLOC_ORDER,REG_LEAF_ALLOC_ORDER,LEAF_REGISTERS): Add %icc. + (REG_CLASS_FROM_LETTER): Handle 'c' for FPCC_REGS in non-v9 case. + (REGNO_OK_FOR_{BASE,INDEX}_P): Treat %g0 as a normal reg. + (REG_OK_FOR_{BASE,INDEX}_P,EXTRA_CONSTRAINT): Likewise. + (REGISTER_NAMES): Add %icc. + (ADDITIONAL_REGISTER_NAMES): Use SPARC_ICC_REG. + * sparc.c (leaf_reg_remap): Add %icc=100. + (reg_or_0_operand): Don't allow 0 if TARGET_LIVE_G0. + (fcc_reg_operand): Renamed from ccfp_reg_operand. + Use SPARC_FCC_REG. Don't treat reg 0 as an fcc reg. Don't match + modes if `mode' argument is VOIDmode. + (icc_or_fcc_reg_operand): New function. + (gen_compare_reg): Use SPARC_FCC_REG for v8 fp compares. + Use SPARC_ICC_REG for int compares. + (eligible_for_epilogue_delay): Don't allow anything if TARGET_LIVE_G0. + Delete unnecessary test for %g0. + (emit_move_sequence): Don't emit (set (mem) (const_int 0)) if + TARGET_LIVE_G0. + (output_scc_insn): Label moved to operand 3. Condition code reg + moved to operand 2. + (sparc_mode_class): Enum C_MODE renamed to CC_MODE. + (hard_32bit_mode_classes): Set reg 0 to S_MODES. Add entry for %icc. + (hard_64bit_mode_classes): Set reg 0 to D_MODES. Add entry for %icc. + (sparc_regno_reg_class): New global. + (sparc_init_modes): Initialize it. + (output_cbranch): Delete fp_cond_reg argument. + (print_operand, MEM op): Don't print "%g0+" if TARGET_LIVE_G0. + (sparc_flat_eligible_for_epilogue_delay): Don't allow anything if + TARGET_LIVE_G0. + * sparc.md (live_g0): New attribute. + (*): Integer condition code register is now reg 100. + Use SPARC_ICC_REG instead of hardcoding reg 100 where possible. + Non-v9 floating point condition code register is now reg 96. + (*cmp{sf,df,tf}_{fpe,fp}_sp{32,64}): Combine v9/non-v9 cases. + (*{normal,inverted}_{,fp,fpe}_branch): Update call to output_cbranch. + (*mov{qi,hi,si}_insn): Don't use if TARGET_LIVE_G0. + (*mov{qi,hi,si}_insn_liveg0): New patterns. + (*mov{si,di,sf,df,tf}_ccfp{,e}_sp64): ccfp_reg_operand renamed to + fcc_reg_operand. + (*negdi2_sp32,negsi2,one_cmplsi2,ffssi2): Ensure %%g0 is 0 if + TARGET_LIVE_G0. + (*one_cmpldi2_sp32): Move operand 1 to rs1 and use 0 as rs2. + (patterns that use %g0 in rs2): Use 0 immediate value instead. + (patterns that read %g0): Don't use if TARGET_LIVE_G0. + +Thu Mar 7 15:39:16 1996 Jim Wilson + + * sh.h (PASS_IN_REG_P): Change < to <=. + * va-sh.h (va_start): Change __SH3E___ to __SH3E__. + (va_arg): Add little-endian SH3E support. Fix big-endian version + to work for arguments smaller than the word size. + +Thu Mar 7 10:37:37 1996 Jeffrey A. Law + + * lib2funcs.asm: Remove entry/exit routines. Move them into... + * ee.asm: New file. Entry/exit code. + * ee_fp.asm: New file. Entry/exit code with frame pointer. + * t-pa: Corresponding changes. + * t-pro: Corresponding changes. + + * pa.c: Fix misc small typos/thinkos in recent changes. + +Wed Mar 6 17:36:03 1996 Jason Merrill + + * cplus-dem.c (demangle_template): Fix for address-of-extern arguments. + +Wed Mar 6 15:12:55 1996 Jeffrey A. Law + + * t-pro (dp-bit rule): Fix typo. + + * lib2funcs.asm (__outline_prologue): Remove frame pointer + support. + (__outline_prologue_fp): Out of line prologue with frame pointer. + (__outline_epilogue, outline_epilogue_fp): Similarly. + * pa.c (compute_frame_size): Allocate enough space to avoid holes + in the callee register saves. Remove some special handling of %r3. + (hppa_expand_prologue): Don't do an out of line prologue/epilogue + if it would take more insns than an inline prologue/epilogue. + Don't leave holes in the callee register save set. + (hppa_expand_prologue): Corresponding changes. Pass stack size + to out of line epilogue code. + * pa.h (FRAME_POINTER_REQUIRED): Revert last change. + * pa.md (outline_prologue_call): Handle outline prologues which + don't need frame pointers. + (outline_epilogue_call): Similarly. + * t-pro: Reenable multilib code. Build a set of libraries that + optimize for space. + +Wed Mar 6 14:28:14 1996 Jim Wilson + + * Makefile.in (USER_H): Add ginclude/va-sh.h. + * ginclude/stdarg.h, ginclude/varargs.h: Use va-sh.h. + * ginclude/va-sh.h: New file. + + * sh.h (PASS_IN_REG_P): Fix typo in last change. + +Wed Mar 6 11:42:06 1996 David Edelsohn + + * rs6000.h (enum processor_type): Remove PROCESSOR_PPC602. + (RTX_COSTS): Remove PROCESSOR_PPC602. PPC603 MULT cost depends + on constant and domain. + * rs6000.c (processor_target_table): 602 uses PROCESSOR_PPC603. + (get_issue_rate): Remove CPU_PPC602. + * rs6000.md (function units): Remove PPC602. Add store and + fpstore type attribute values. Update patterns. + +Tue Mar 5 18:43:43 1996 Richard Henderson + + * m68k/coff.h (ASM_OUTPUT_SECTION_NAME): New define. + + * m68k/{aux-crt1.c,aux-crt[2n].asm}: New files. + * m68k/{aux-exit.c,aux-low.gld,aux-mcount.c}: More new files. + * m68k/{aux.h,auxgnu.h,auxstd.h}: Even more new files. + * m68k/{t-aux,xm-aux.h}: The rest of the new files. + * m68k/sgs.h (ASM_OUTPUT_CASE_END): Add missing semicolon. + (switch_table_difference_label_flag): Make extern. + * fixincludes (sys/param.h): Fix c89 __asm statements. + * configure (m68k-apple-aux*): New target. + +Tue Mar 5 17:38:19 1996 Doug Evans + + * sparc.md (*mov{qi,hi,si}_insn): Simplify length attribute. + (*movsi_insn): Use fpload/fpstore attributes for fp loads/stores. + %r1 -> %1 for fpstore alternative. + (*movsf_insn,*movsf_no_f_insn): %r1 -> %1. + +Tue Mar 5 17:19:17 1996 Jason Merrill + + * expr.c (expand_expr, case *_DECL): If we make a non-local + reference from a function with DECL_NO_STATIC_CHAIN set, abort. + (expand_expr, case ADDR_EXPR): We don't need a trampoline for a + function with DECL_NO_STATIC_CHAIN set. + * function.c (lookup_static_chain): If we're checking on a function + that doesn't need a static chain, return 0. + (init_function_start): We don't need context if DECL_NO_STATIC_CHAIN + is set. + * tree.c (staticp): Check DECL_NO_STATIC_CHAIN on nested functions. + +Tue Mar 5 15:04:29 1996 Jim Wilson + + * sh.md (push_e, pop_e): Add TARGET_SH3E to condition. + * sh.h (JUMP_TABLES_IN_TEXT_SECTION): Define. + * sh.c (find_barrier): Set si_limit to 1018 instead of 1020, and + hi_limit to 510 instead of 512. + +Tue Mar 5 13:39:44 1996 Doug Evans + + * loop.c (init_loop): Use pseudo reg in add_cost computation + so cost doesn't vary depending on whether reg 0 happens to be + fixed or not. + +Tue Mar 5 09:32:24 1996 J"orn Rennecke (amylaar@meolyon.hanse.de) + + * reg-stack.c (record_label_references): Check for undefined label. + +Tue Mar 5 09:22:20 1996 Scott Christley (scottc@net-community.com) + + * objc/objc-api.h, objc/runtime.h: Include objc/thread.h. + * objc/class.c (__objc_init_class_tables): Surround sarray access + with mutex lock/unlock. + (__objc_add_class_to_hash, objc_lookup_class): Likewise. + (objc_get_class, objc_get_next_class): Likewise. + (__objc_resolve_class_links, class_pose_as): Likewise. + * objc/init.c (__objc_runtime_mutux, __objc_runtime_thread_alive): + New variables. + (objc_init_statics, __objc_init_protocols): Surround sarray access + with mutex lock/unlock + (__objc_exec_class): Likewise. + Initialization for thread-safe global variables. + Declarations for thread-safe functions and global variables + * objc/sendmsg.c (get_imp, __objc_responds_to): + Surround sarray access with mutex lock/unlock. + (__objc_init_install_dtable): Likewise. + (__objc_update_dispatch_table_for_class): Likewise. + (__objc_print_dtable_stats): Likewise. + * objc/selector.c (sel_get_typed_uid, sel_get_any_typed_uid): Likewise. + (sel_get_any_uid, sel_get_name, sel_register_name): Likewise. + (sel_register_typed_name): Likewise. + * objc/sarray.h (union sversion): New. + (struct sarray): Maintain multiple versions. + (sarray_remove_garbage): Add prototype. + * objc/sarray.c (sarray_{remove,free}_garbage): New functions. + (sarray_at_put, sarray_new, sarray_lazy_copy): + Modify/copy sarray structure/data in a thread-safe manner + (sarray_{realloc,free}): Reallocate/free sarray structure/data in a + thread-safe manner. + + * objc/THREADS, objc/thread.c, objc/thread.h: New files. + * objc/thread-{decosf1,irix,solaris,win32,single}.c: New files. + * objc/objc-list.h: Renamed from objc/list.h. + * objc/Makefile: Changes to compile new files and name renaming. + * objc/makefile.dos: Likewise. + +Tue Mar 5 07:51:31 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * bc-emit.c, bc-optab.c (free): Delete declaration of library function. + + * c-decl.c (duplicate_decl): If making decl non-external, copy + context from old to new. + +Tue Mar 5 02:27:35 1996 Jeffrey A. Law + + * sparc.md (*cmp{si,di}_insn): %r0 -> %0. + (DFmode move define_split): Ensure registers not extended v9 fp regs. + (*mov{sf,df,tf}_cc_reg_sp64): %r3 -> %3. + +Mon Mar 4 18:46:37 1996 Manfred Hollstein + + * Makefile.in (CRT0STUFF_T_CFLAGS): New macro. + (stamp-crt0, crt0.o, mcrt0.o): New goals. + (STAGESTUFF): stamp-crt0 added. + + * collect2.c (main): Check new define DEFAULT_A_OUT_NAME. + + * m68k.c (print_operand): Emit .l as scale factor #ifdef MOTOROLA. + * m68k/mot3300-crt0.S, m68k/mot3300Mcrt0.S: New files. + * m68k/mot3300g.h: Deleted. + * m68k/mot3300.h (FUNCTION_PROFILER): Emit label references + corresponding to those generated by ASM_OUTPUT_INTERNAL_LABEL. + (MOTOROLA, MOTOROLA_BSR, ...): Define #ifndef USE_GAS. + (ASM_SPEC): Define properly #ifdef USE_GAS. + (LIB_SPEC): -L/usr/lib/libp deleted. + (STARTFILE_SPEC): -L/usr/lib/libp added. + (DEFAULT_A_OUT_NAME): Define. + (LINK_SPEC): Pass -v if GNU ld is used. + (LOCAL_LABEL_PREFIX): Local labels start with .L using GAS, else L%. + (USER_LABEL_PREFIX): Undefine. + (FUNCTION_PROFILER): Call asm_fprintf instead of normal fprintf. + (ASM_APP_ON, ASM_FILE_START): GAS supports it. + (CTORS_.../DTORS_...): Define if GNU ld is used. + (ASM_FILE_START): Define properly for Motorola and GNU as syntax. + (TARGET_VERSION): Re-define only #ifndef USE_GAS. + (CALL_USED_REGISTERS): Deleted. + (GLOBAL_ASM_OP): Re-define only #ifndef USE_GAS. + (ASM_{LONG,SHORT,CHAR,BYTE,BYTE_OP}): New macros. + (ASM_OUTPUT_{DOUBLE,LONG_DOUBLE,FLOAT,INT,SHORT}): Use them. + (ASM_OUTPUT_{CHAR,BYTE,ASCII,FLOAT_OPERAND,DOUBLE_OPERAND}): Likewise. + (ALIGN_ASM_OP, SKIP_ASM_OP): New macros. + (ASM_OUTPUT_{ALIGN,SKIP}): Use them. + (ASM_OUTPUT_SOURCE_FILENAME): Define only if not using GNU as. + (ASM_{GENERATE,OUTPUT}_INTERAL_LABEL): Provide proper definitions for + Motorola and GNU as syntax. + (ASM_OUTPUT_ADDR_{VEC,DIFF}_ELT): Changed for portability between + Motorola and GNU as syntax. + (ASM_OUTPUT_{CASE_LABEL,OPCODE}): Define only if not using GNU as. + (ASM_OUTPUT_CASE_FETCH, ASM_RETURN_CASE_JUMP): New macros. + (ASM_OUTPUT_{COMMON,LOCAL}): Proper defns for Motorola and gas syntax. + (SDB_...): Define only for Motorola as. + (ALT_LIBM): New define to tell g++.c about an alternative name for + `-lm'. + (MATH_LIBRARY, NEED_ATEXIT, HAVE_ATEXIT, EXIT_BODY): New macros. + * m68k/t-mot3300, m68k/t-mot3300-{gald,gas,gld}: New files. + * m68k/x-mot3300-gas: New file. + * m68k/xm-mot3300.h (USG): Set to 1. + * configure (m68k-motorola-sysv*): Keep track of new different + combinations (--with-gnu-...), and provide proper definitions for + tm_file, xmake_file, tmake_file, use_collect2, and extra_parts. + + * gbl-ctors.h (HAVE_ATEXIT): Define if NEED_ATEXIT is defined. + (atexit): Use `int atexit' prototype also if NEED_ATEXIT is defined. + (on_exit): According to man on_exit on the Sun it returns int not void. + * libgcc2.c (L_bb/atexit, onexit): Declarations replaced by + #include'ing "gbl-ctors.h". + (L_exit/atexit): New function. + (L_exit/exit): Call any registered functions. + +Mon Mar 4 18:03:38 1996 Bryan Ford (baford@cs.utah.edu) + + * configure (i[3456]86-moss-msdos*): New target. + * i386/moss.h: New file. + +Mon Mar 4 17:38:50 1996 Jim Wilson + + * sh.h (PASS_IN_REG_P): Don't reject BLKmode for SH3e. + For SH3e, do reject parameter that won't fit entirely in registers. + + * sh.md (mulhisi3-2, mulhisi3-1, mulsidi3_i, umulsidi3_i, + smulsi3_highpart, umulsi3_highpart): Renames operands 1/2 to 0/1. + (mulsidi3, umulsidi3): Add support for TARGET_LITTLE_ENDIAN. + + * sh.c (machine_dependent_reorg): In TARGET_RELAX code, when scan + forward from LINK, fail if pass a CODE_LABEL before finding INSN. + Fail if SCAN not INSN is a JUMP_INSN. + +Mon Mar 4 11:27:10 1996 Michael Meissner + + * rs6000.h (CALL_LONG): Change CALL_xx values from an enumeration + to bitmasks. Add CALL_LONG to support longcall attributes. + (rs6000_args): Call_cookie field is now an int. + (rs6000_longcall_ref): Add declaration. + + * rs6000.c (init_cumulative_args): Add support for longcall + attributes to always call through a pointer. + (function_arg): Ditto. + (rs6000_valid_type_attribute_p): Ditto. + (rs6000_longcall_ref): New function for long calls. + + * rs6000.md (call insns): Add support for longcall attributes. + +Mon Mar 4 08:42:14 1996 J"orn Rennecke (amylaar@meolyon.hanse.de) + + * real.c (significand_size): Don't test the modes, but their sizes. + + * dwarfout.c (xstrdup): Moved from here. + * toplev.c (xstrdup): New function. + * tree.h (xstrdup): Declare. + * bc-emit.c (bc_xstrdup): Delete. + * expr.c (bc_strdup): Delete. + (bc_load_externaddr_id): Use xstrdup instead of bc_xstrdup. + * function.c (bc_expand_function_start): Likewise. + * 1750a.c (strdup): Delete. + (float_label): Use xstrdup instead of strdup. + * 1750a.h (xstrdup): Declare instead of instead of strdup. + (ASM_OUTPUT_LABEL): Use xstrdup instead of strdup. + (FIX_FRAME_POINTER_ADDRESS): Don't use DEPTH in string. + +Mon Mar 4 08:23:23 1996 Richard Kenner + + * xm-we32k.h (NO_WAIT_H): Deleted. + + * collect2.c: Never include wait.h. + +Sat Mar 2 22:43:07 1996 Torbjorn Granlund + + * configure (code for making links): Work around sh bug on FreeBSD. + +Sat Mar 2 13:40:29 1996 Jeffrey A. Law + + * h8300.h (BIGGEST_FIELD_ALIGNMENT): Replace uses of + TARGET_ALIGN_STRUCT_300 with TARGET_ALIGN_300. + (BIGGEST_ALIGNMENT): Likewise. + +Sat Mar 2 08:04:50 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * calls.c (expand_call): If passing by invisible ref, not const. + + * sparc.c (SKIP_CALLERS_UNIMP_P): Make agree with test used in call. + + * expr.c (do_jump, case COMPOUND_EXPR): Call preserve_temp_slots. + + * fold-const.c (fold, case *_DIV_EXPR): Ignore SAVE_EXPR if has RTL. + +Fri Mar 1 17:59:17 1996 Jeffrey A. Law + + * optabs.c (emit_cmp_insn): Immediately copy the return + value from the library call into a pseudo register. + (emit_float_lib_cmp): Likewise. + +Fri Mar 1 14:37:40 1996 Michael Meissner + + * rs6000/sysv4.h (BSS_SECTION_ASM_OP): Define. + (*_SECTION_ASM_OP): Change tab after .section into a space. + (ASM_OUTPUT_INT): Ditto. + (ASM_OUTPUT_ALIGNED_LOCAL): Rewrite to use bss_section. + (ASM_OUTPUT_ALIGNED_BSS): Define to use ASM_GLOBALIZE_LABEL and + ASM_OUTPUT_ALIGNED_LOCAL. + + * rs6000/win-nt.h (BSS_SECTION_ASM_OP): Define. + (ASM_OUTPUT_ALIGNED_LOCAL): Define. + (ASM_OUTPUT_LOCAL): Don't define any more. + (ASM_OUTPUT_ALIGNED_BSS): Define to use ASM_GLOBALIZE_LABEL and + ASM_OUTPUT_ALIGNED_LOCAL. + +Thu Feb 29 17:33:12 1996 Jim Wilson + + * c-typeck.c (push_init_level): When output padding to align structure + field, set constructor_unfilled_fields. + + * dbxout.c (dbxout_type, case METHOD_TYPE): Add CHARS (1) call + after emitting second '#' character. + +Thu Feb 29 13:59:27 1996 Doug Evans + + * h8300.h (ASM_OUTPUT_BSS): Define. + * m68k/coff.h (BSS_SECTION_ASM_OP): Define. + (ASM_OUTPUT_ALIGNED_BSS): Define. + * m68k/m68k-aout.h (BSS_SECTION_ASM_OP): Define. + (ASM_OUTPUT_BSS): Define. + +Thu Feb 29 13:39:39 1996 Per Bothner + + * varasm.c (compare_constant_1): For a SET_TYPE CONSTRUCTOR, + first extract and compare the set length. + + * varasm.c (record_constant_1): For SET_TYPE CONSTRUCTOR, + permanent_obstack.next_free is *end* of available space. + +Thu Feb 29 13:14:14 1996 Jeffrey A. Law + + * pa.h (TARGET_SWITCHES): Add new flags "-mlong-load-store" and + "-mno-long-load-store". + (TARGET_LONG_LOAD_STORE): Define. + * pa.md (symbolic high part): Handle TARGET_LONG_LOAD_STORE. + +Thu Feb 29 11:39:30 1996 Stan Cox + + * i386.md (cmpxf*): XF compare cannot have mem operands. + (casesi expand): Put (minus:SI..) into subsi3 format. + * i386.c (i386_return_pops_args): Cleanup extra argument + used as address of a returned structure. + +Wed Feb 28 22:24:28 1996 Doug Evans + + * varasm.c (enum in_section): Define in_bss if BSS_SECTION_ASM_OP + is defined. + (bss_section,asm_output_bss,asm_output_aligned_bss): New functions. + (assemble_variable): Delete redundant test for too large an object. + Rewrite test for uninitialized variables. Use new macros + ASM_OUTPUT{,_ALIGNED}_BSS if defined to output global uninitialized + but not common variables. + * bytecode.h (BC_OUTPUT_BSS): Define. + * lynx.h (EXTRA_SECTIONS): Delete in_bss. + (EXTRA_SECTION_FUNCTIONS): Delete BSS_SECTION_FUNCTION. + * svr3.h (EXTRA_SECTIONS): Likewise. + (BSS_SECTION_FUNCTION): Delete. + * convex.h (EXTRA_SECTIONS,EXTRA_SECTIONS_FUNCTIONS): Delete. + * dsp16xx.h (EXTRA_SECTIONS): Delete in_bss. + (EXTRA_SECTION_FUNCTIONS): Delete bss_section. + * gmicro.h (EXTRA_SECTIONS,EXTRA_SECTIONS_FUNCTIONS): Delete. + * i386/aix386ng.h (EXTRA_SECTION_FUNCTIONS): Delete + BSS_SECTION_FUNCTION. + * i386/att.h (BSS_SECTION_FUNCTION): Delete. + * i386/sco5.h (EXTRA_SECTIONS): Delete in_bss. + (EXTRA_SECTION_FUNCTIONS): Delete BSS_SECTION_FUNCTION. + (BSS_SECTION_FUNCTION): Delete. + * i386/seq-sysv3.h (BSS_SECTION_FUNCTION): Delete. + * i386/svr3gas.h (EXTRA_SECTIONS): Delete in_bss. + (EXTRA_SECTION_FUNCTIONS): Delete BSS_SECTION_FUNCTION. + (BSS_SECTION_FUNCTION): Delete. + * i860/paragon.h (EXTRA_SECTIONS,EXTRA_SECTIONS_FUNCTIONS): Undef. + * m68k/crds.h (EXTRA_SECTIONS,EXTRA_SECTIONS_FUNCTIONS): Delete. + (BSS_SECTION_ASM_OP): Define. + * m68k/m68k.h (BC_OUTPUT_BSS): Define. + * mips/iris6.h (EXTRA_SECTIONS): Delete in_bss. + * pa.h (EXTRA_SECTIONS): Delete in_bss. + (EXTRA_SECTION_FUNCTIONS): Delete bss_section. + * sparc/litecoff.h (EXTRA_SECTIONS): Delete in_bss. + +Wed Feb 28 14:12:25 1996 Jim Wilson + + * sh.h (FUNCTION_VALUE_REGNO_P, FUNCTION_ARG_REGNO_P): Include FP + registers only when TARGET_SH3E. + (PASS_IN_REG_P): Exclude BLKmode only when ! TARGET_SH3E. + +Wed Feb 28 12:03:26 1996 Michael Meissner + + * rs6000.c (rs6000_trampoline_{template,size}): Change Windows NT + trampoline template so it doesn't require making stack executable. + Add support for 64 bit systems. + (rs6000_initialize_trampoline): Ditto. + +Tue Feb 27 16:42:00 1996 David Edelsohn + + * rs6000.c (print_operand): New code 'H'. + * rs6000.md (insv, extzv): Add DImode patterns. Use 'h' + consistently for masking SImode shifts. + (rotldi3, ashldi3, lshrdi3, ashrdi3): Use 'H'. + (movsf split): Generate CONST_INT instead of SUBREG. + +Tue Feb 27 15:02:17 1996 Doug Evans + + * sh.h (HANDLE_PRAGMA): Delete `return'. + +Tue Feb 27 08:18:12 1996 Richard Earnshaw (rearnsha@armltd.co.uk) + + * arm.c (aof_text_section): Remove pseudo read-only hack. Doesn't + take a parameter any more. + * arm/aof.h (EXTRA_SECTIONS, EXTRA_SECTION_FUNCTIONS): Remove + readonly data sections. + (READONLYDATA_SECTION, READONLY_DATA_SECTION): Delete. + + * arm.h (enum arm_cond_code): New enum. + (ARM_INVERSE_CONDITION_CODE): Moved here from arm.c. + (SELECT_CC_MODE): Call arm_select_cc_mode to do the work. + (PREDICATE_CODES): Add dominant_cc_register; delete + reversible_cc_register. + * arm.c (arm_current_cc): Now an enum. + (ARM_INVERSE_CONDITION_CODE): Moved to arm.h + (revsersible_cc_register): Delete. + (dominant_cc_register): New function. + (select_dominance_cc_mode): New function. + (arm_select_cc_mode): New function. + (output_return_instruction): New parameter REVERSE, used to + reverse the condition of a conditional return. All callers + changed. + (arm_print_operand case 'D'): Only suppress condition printing + if the operand is a NULL pointer. + (get_arm_condition_code): Now a static function returning + enum arm_cond_code. Handle dominance expressions. Return enum + values rather than integers. + * arm.md (*addsi3_compare0_scratch): New insn. + (*movsi_compare0, *cmpsi_insn, *cmpsi_shiftsi): Make sure the + compare has mode CC. + (cmp{si,sf,df,xf} expands): Just provide sufficient information + to allow the parameters to be matched properly. + (*cmpsi_negsi): Delete (of dubious validity). + (*cmpsi_shiftsi_swp): New pattern. + (*condbranch_reversed): No longer needs to check REVERSIBLE_CC_MODE. + (mov{si,sf,df}cc, *mov{si,sf,df}{,_hard,_soft}_insn): The mode of the + IF_THEN_ELSE must be appropriate to the target (not void). + (*and_scc): Match cc_register, not reversible_cc_register. + (*ior_compare_compare): Delete. + (split for ior_compare_compare + condjump): Delete. + (*impossible_cond_compare): Delete. + (*condition_compare_ior): Delete. + (*cond_move): Mode for the IF_THEN_ELSE must be SImode. + (*and_scc_scc): Delete. + (split for and_scc_scc + condjump): Delete. + (*impossible_cond_branch_and): Delete. + (*cmp_ite0, *cmp_ite1): New patterns. + (if_compare_not): Should be an anonymous pattern. + (Peephole for move and compare): Compare mode must be mode CCmode. + (Split pattern for comparing shifted reg then branch): Delete. + (*loadqi_compare): Delete, replaced with a split pattern to do + the same thing. + (*cond_move_not): Match cc_register, not reversible_cc_register. + + * arm.c ({load,store}_multiple_sequence): New functions. + (emit_{ldm,stm}_seq): New functions. + * arm.md (load/store multiple peepholes): Rewrite using the above + functions. + (all patterns taking immediate_operand): If the code later assumes + this is a CONST_INT, then match const_int_operand instead. + +Mon Feb 26 17:26:13 1996 Doug Evans + + * sparc.md: Add sparclet scheduling parameters. + (compare define_insn's): Move closer to compare define_expand's. + (32 bit multiply patterns): Use for TARGET_SPARCLET. + (*smacsi,*smacdi,*umacdi): Multiply/accumulate patterns for the + sparclet. + +Sat Feb 24 19:13:29 1996 David Edelsohn + + * rs6000.md (movsf split): Fix typo in last patch. + +Sat Feb 24 10:02:55 1996 Michael Meissner + + * toplev.c (fatal_insn): Flush stdout/stderr. + +Sat Feb 24 02:03:28 1996 Jeffrey A. Law + + * pa.md (abssi2): Rework to avoid matching constraints. + +Fri Feb 23 11:21:43 1996 Jeffrey A. Law + + * pa.c (override_options): Warn if both PIC code generation and + profiling are requested. + +Fri Feb 23 08:47:38 1996 Richard Kenner (kenner at vlsi1) + + * expr.c (expand_builtin, case BUILT_IN_SETJMP): Set CONST_CALL_P + on NOTE_INSN_SETJMP instead of emitting USE insns for call-saved regs. + * reload1.c (reload): For special CONST_CALL_P NOTE_INSN_SETJMP, + mark all call-saved regs as used. + * sched.c (sched_analyze): Record NOTE_INSN_SETJMP if no + CALL_INSN as prev; preserve CONST_CALL_P bit. + (reemit_notes): Restore CONST_CALL_P. + +Thu Feb 22 17:45:12 1996 Doug Evans + + * configure (sparclet-*-aout*): Set extra_headers. + * ginclude/inl-sparc.h: New file. + +Wed Feb 21 20:39:53 1996 Doug Evans + + * configure (sparc64-*-solaris2*): Merge with sparc-*-solaris2*. + * sparc.h (enum processor_type): Declare. + (sparc_cpu_attr): Define. + (TARGET_OPTIONS): Add -mtune=. + (sparc_select): Declare. + (sparc_cpu_string): Delete. + (FIRST_PSEUDO_REGISTER): Set to 100. + ({FIXED,CALL_USED}_REGISTERS): Merge !v9/v9 cases. + (CONDITIONAL_REGISTER_USAGE): Mark %g5 as fixed if !v9. + Mark %g1 as fixed if v9. Fix v9-only regs if !v9. + Mark fp{16..47} as call-saved if v9. + (enum reg_class): Merge !v9/v9 cases. + (REG_CLASS_NAMES,REG_CLASS_CONTENTS,REGNO_REG_CLASS): Likewise. + (REG_ALLOC_ORDER,REG_LEAF_ALLOC_ORDER,LEAF_REGISTERS): Likewise. + (FP_REG_CLASS_P,SPARC_REGISTER_NAMES): Likewise. + (REG_CLASS_FROM_LETTER): Test TARGET_V9 at runtime. + * sparc.c (sparc_cpu_string): Delete. + (sparc_select): New global. + (sparc_override_options): Handle -mtune=xxx. + * sparc.md (cpu attr): Add sparc{lite,let} implementations. + * sparc/sp64-sol2.h: Deleted. + + * arm.md (consttable_end): Delete call to text_section. + (align_4): Delete call to readonly_data_section. + +Wed Feb 21 14:29:06 1996 Ian Lance Taylor + + * cplus-dem.c (demangle_template): Initialize is_bool. Correctly + handle 0 as a pointer value parameter. + +Wed Feb 21 14:13:29 1996 Jason Merrill + + * tree.c (decl_function_context): Do decl_function_context right for + function-local classes. + +Wed Feb 21 12:42:52 1996 Jeffrey A. Law + + * c-typeck.c (initializer_constant_valid_p): Don't dereference + a null pointer on partial structure initialization. + +Wed Feb 21 11:49:58 1996 David Edelsohn + + * rs6000.h (ASM_OUTPUT_EXTERNAL): Append section info + even when verbatim symbol prefix '*' present. + * rs6000/aix3newas.h (ASM_OUTPUT_EXTERNAL): Same. + * rs6000/aix41.h (ASM_OUTPUT_EXTERNAL): Same. + * rs6000/powerpc.h (ASM_OUTPUT_EXTERNAL): Same. + * rs6000/win-nt.h (ASM_OUTPUT_EXTERNAL): Same. + +Wed Feb 21 03:55:32 1996 Paul Eggert + + * cccp.c (validate_else): Don't loop given `#endif /'. + Handle multiple adjacent backslash-newlines correctly. + Accept a new parameter LIMIT to specify end of input; + this prevents confusion when the input contains '\0' characters. + (collect_expansion): Fix off-by-1 error when searching for `*/' + at end of a comment used for traditional token concatenation. + (macarg1): Fix off-by-1 error when skipping past `*/' + at end of comment. + +Tue Feb 20 16:12:31 1996 Doug Evans + + * hard-reg-set.h (twice unrolled GO_IF_HARD_REG_EQUAL): Add missing \. + +Tue Feb 20 14:21:16 1996 Jeffrey A. Law + + * pa.h (DBX_CONTIN_LENGTH): Define to 4000 characters. + + * pa.c (hppa_expand_epilogue): Always emit a blockage insn + before cutting back the stack. + +Mon Feb 19 19:42:15 1996 Brendan Kehoe + + * sparc.h (TARGET_SWITCHES): Add -m{,no-}impure-text. + (MASK_IMPURE_TEXT, TARGET_IMPURE_TEXT): Define. + (LINK_SPEC): Only add `-assert pure-text' if -mimpure-text wasn't used. + +Mon Feb 19 19:20:15 1996 Doug Evans + + * configure (sparc-aout): sparc-aout.h renamed to aout.h. + (sparclet-aout): Likewise. + (sparclite-*-aout*): Renamed from sparclite-*-*. + Don't set use_collect2. + (target_cpu_default): Set to TARGET_CPU_ for sparc. + + * sparc.h (TARGET_CPU_sparc{,let,lite,64}): Define. + ({CPP,ASM}_DEFAULT_SPEC): Set from TARGET_CPU_foo. + (SPARC_ARCH64 CPP_PREDEFINES): Define __arch64__. + (CPP_SPEC): Add %(cpp_cpu). + (CPP_CPU_SPEC): Define. + (CC1_SPEC): Convert -m to -mcpu=. + (ASM_SPEC): Add %(asm_cpu). + (ASM_CPU_SPEC): Define. + (EXTRA_SPECS,SUBTARGET_EXTRA_SPECS): Define. + (OVERRIDE_OPTIONS): Call SUBTARGET_OVERRIDE_OPTIONS after + sparc_override_options. + ({MASK,TARGET}_SUPERSPARC): Delete. + ({MASK,TARGET}_SPARCLET): Define. + (MASK_ISA): Renamed from MASK_CPUS. + (TARGET_SWITCHES): Delete no-{v8,sparclite}. + (sparc_cpu,sparc_cpu_string): Declare. + ({SUB,}TARGET_OPTIONS): Define. + (FIXED_REGISTERS): Add definitions for sparc64 in 32 bit mode. + (CONDITIONAL_REGISTER_USAGE): Don't set fixed_regs[234] if sparc64. + Don't set call_used_regs[48..80] for sparc64 in 32 bit mode. + Don't clobber fixed_regs[234] if -ffixed- was passed. + (ADJUST_COST): Change test for supersparc. + * sparc.c (sparc_cpu_string,sparc_cpu): New globals. + (sparc_override_options): Set ISA and CPU from sparc_cpu_string. + Delete tests for v9 only switches if not v9. + Error if -mcpu=v9 and v9 support not compiled in. + * sparc/sol2.h (CPP_SPEC): Use %(cpp_cpu). + (ASM_SPEC): Likewise. + (ASM_{DEFAULT,CPU}_SPEC): Use Solaris syntax for sparc64. + * sparc/sysv4.h (ASM_SPEC): Add %(asm_cpu). + * sparc/t-sparcbare (MULTILIB_*): -mv8 renamed to -mcpu=v8. + * sparc/t-sparclite (MULTILIB_*): Delete msoft-float and mno-flat, + they're the defaults. Add -mcpu=f934 as synonym for -mfpu. + * va-sparc.h (__arch64__): Renamed from __sparc_v9__. + + * sparc/lite.h: #include aoutos.h. + (TARGET_DEFAULT): Use MASK_FOO values. + * sparc/sp64-aout.h: #include aoutos.h. + (TARGET_DEFAULT): Add MASK_APP_REGS. + (JUMP_TABLES_IN_TEXT_SECTION,READONLY_DATA_SECTION): Delete. + * sparc/sp64-elf.h (TARGET_DEFAULT): Add MASK_APP_REGS. + (CPP_PREDEFINES): Define __arch64__. + * sparc/sp64-sol2.h (TARGET_DEFAULT, SUBTARGET_SWITCHES): Delete. + (ASM_SPEC): Delete. + + * sparc.h ({MASK,TARGET}_FRW): Delete. + (FRAME_POINTER_REQUIRED,INITIAL_FRAME_POINTER_OFFSET, + BASE_{INCOMING_ARG,OUTGOING_VALUE}_REG,INCOMING_REGNO,OUTGOING_REGNO, + FUNCTION_{PROLOGUE,EPILOGUE},DELAY_SLOTS_FOR_EPILOGUE): TARGET_FRW + renamed to TARGET_FLAT. + + * sparc.md (cpu attr): Add all cpu variants. + (negtf2,negdf2,abstf2,absdf2): Use isa attr, not arch attr, in + determining insn lengths. + + * sparc/aout.h: Renamed from sparc-aout.h. + (CPP_PREDEFINES): Delete __GCC_NEW_VARARGS__. + Add -Acpu(sparc) -Amachine(sparc). + +Mon Feb 19 17:49:08 1996 David Edelsohn + + * rs6000.md (movsf split): Use SUBREG, not operand_subword. + (movdf split): operand_subword TARGET_32BIT and new split using + SUBREG for TARGET_64BIT. + * rs6000.c (easy_fp_constant): Rewrite to not use operand_subword. + (input_operand): Remove final add_operand test made irrelevant by + Dec. 8 change. + (output_toc): Handle DImode values. + +Mon Feb 19 13:38:00 1996 Lee Iverson + + * i386/sol2.h (SWITCH_TAKES_ARG): Restore -R. + * sparc/sol2.h (SWITCH_TAKES_ARG): Likewise. + +Mon Feb 19 08:19:00 1996 Michael Meissner + + * hard-reg-set.h (HARD_REG macros): If more than + HOST_BITS_PER_WIDE_INT hard registers and less than or equal to + 4*HOST_BITS_PER_WIDE_INT hard registers, unroll loops by hand. + +Mon Feb 19 07:35:07 1996 Torbjorn Granlund + + * rs6000.md (not:SI with assign and compare): Fix typo. + (not:DI with assign and compare): Likewise. + +Mon Feb 19 07:17:25 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * sparc.md (nonlocal_goto): No longer need USE of %o0. + (goto_handler_and_restore): Show uses %o0. + + * combine.c (force_to_mode, case IOR): Fix typo in commuting + IOR and LSHIFTRT. + + * alpha.c (call_operand): If in REG, only reg 27 valid. + +Mon Feb 19 06:57:34 1996 Richard Earnshaw (rearnsha@armltd.co.uk) + + * emit-rtl.c (operand_subword): For 32-bit targets, return + the appropriate subword of extended precision CONST_DOUBLEs. + + * arm.c (offsettable_memory_operand): New function. + (alignable_memory_operand): New function. + (gen_rotated_half_load): New function. + (get_arm_condition_code): Extract the mode of the comparison and + use it to generate the correct return value. + * arm.h (EXTRA_CC_MODES, EXTRA_CC_NAMES): Add CC_Zmode. + (SELECT_CC_MODE): return CC_Zmode if the operand is QImode. Allow LT + and GE comparisons in CC_NOOVmode. + (PREDICATE_CODES): add offsettable_memory_operand and + alignable_memory_operand. + * arm.md (*zeroextract[qs]i_compare0_scratch): Use const_int_operand + for operands 1 and 2. + (split patterns for aligned memory half-word operations): New patterns. + (movhi): Handle memory accesses where the alignment is known in a more + efficient manner. + (*compareqi_eq0): Use CC_Zmode. + +Mon Feb 19 05:34:08 1996 Jason Merrill + + * toplev.c (lang_options): Add -W{no-,}sign-compare. + + * c-tree.h: Declare warn_sign_compare. + + * c-typeck.c (build_binary_op): Check warn_sign_compare rather + than extra_warnings to decide whether to warn about comparison of + signed and unsigned. + + * c-decl.c (c_decode_option): Handle warn_sign_compare. -Wall + implies -Wsign-compare. + +Sun Feb 18 21:13:44 1996 Pat Rankin (rankin@eql.caltech.edu) + + * c-lex.c (yylex, case '0'..'9','.'): For cases '0' and '1', + check for single digit constant before resorting to general + number processing. + +Sun Feb 18 19:29:44 1996 J.T. Conklin + + * m68k.h (TARGET_68060): New macro. + (TARGET_SWITCHES): Add -m68060. + * m68k.md (const_umulsi3_highpart): Disable for TARGET_M68060. + (ftruncdf2, ftruncsf2, muldf3, mulsidi3): Likewise. + (smulsi3_highpart, umulsi3_highpart, umulsidi3): Likewise. + + * {m68k,ns32k,sparc}/netbsd.h (DBX_NO_XREFS): Removed. + +Sun Feb 18 13:29:56 1996 Charles M. Hannum (mycroft@netbsd.org) + + * c-common.c (check_format_info): Warn about `L' if -pedantic. + +Fri Feb 16 20:13:23 1996 Paul Eggert + + * c-typeck.c (convert_for_assignment): + Bring back conversion to union without a cast, + undoing the Jan 16 change, but with the following differences: + - The union must have the transparent_union attribute. + - The conversion must be for a function argument. + - Warn consistently about such conversions if pedantic. + - Do not warn about an assignment incompatibility for one union member + if another union member is compatible with no warning. + +Fri Feb 16 12:06:21 1996 Stan Cox + + * i386.c (ix86_*_binary_operator*): Allow CONST_INT as operand1 + of MINUS. + * i386/dgux.h (OPTIMIZATION_OPTIONS): Call optimization_options. + +Fri Feb 16 08:39:47 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * configure: Change stdout report when have multiple files in + tm_file, host_xm_file, or build_xm_file. + (a29k-*-bsd): Use both a29k.h and unix.h. + (a29k-*-udi): Rename a29k-udi.h to udi.h; + use a29k.h, dbxcoff.h, and it. + (a29k-*-vxworks): Use a29k.h, dbxcoff.h, a29k/udi.h, and a29k/vx29k.h. + (alpha-dec-osf[23456789]*): Use alpha.h, not osf2.h. + (alpha-dec-osf1.2): Use alpha.h and alpha/osf12.h. + (alpha-*-osf*): Add explicit assignment of tm_file. + * a29k/udi.h: Renamed from a29k-udi.h. + Don't include a29k.h or dbxcoff.h. + * a29k/unix.h: Don't include a29k.h. + * a29k/vx29k.h: Don't include a29k-udi.h. + * alpha.h (WCHAR_TYPE, WCHAR_TYPE_SIZE): Use unsigned int. + * alpha/osf2.h: Deleted. + * alpha/osf12.h: Don't include alpha.h. + (WCHAR_TYPE, WCHAR_TYPE_SIZE): Use short unsigned int. + * alpha/win-nt.h (WCHAR_TYPE, WCHAR_TYPE_SIZE): Use short unsigned int. + +Thu Feb 15 18:26:04 1996 Michael Meissner + + * rs6000/ntstack.asm (__allocate_stack): Round up length to 16 + byte boundary. + + * rs6000.md (allocate_stack): On Windows NT, call set_sp to + indicate to CSE stack pointer changes with call to __allocate_stack. + (set_sp): New pattern. + +Thu Feb 15 16:49:15 1996 Jim Wilson + + * integrate.c (save_for_inline_copying): Allocate reg_map with size + based on regno_pointer_flag_length instead of max_reg+1. + +Thu Feb 15 07:48:34 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * fixincludes (rpc/types.h): Remove spurious "ls" command. + + * reload1.c (eliminate_regs, case USE): If using a register that + is source of elimination, show can't be eliminated. + + * expr.c (expand_builtin, case BUILT_IN_SETJMP): Shows clobbers FP + and all caller-save registers. + Set current_function_has_nonlocal_goto. + +Wed Feb 14 13:51:55 1996 David Edelsohn + + * rs6000.md (fix_truncdfsi2): Use SUBREG not operand_subword. + (movdi): Test HOST_BITS_PER_WIDE_INT at build time. + * collect2.c (scan_libraries): Append '/' to import path if missing. + +Wed Feb 14 09:01:55 1996 Michael Meissner + + * rs6000.md (movdi): Use HOST_WIDE_INT, not long long. + +Tue Feb 13 19:36:21 1996 Per Bothner + + * expr.c (store_constructor): Fix flow control thinko (merge error). + * expr.c (store_constructor): Pass correct value to recursive call. + +Wed Jan 31 11:34:45 1996 Mike Stump + + * expr.c (expand_expr, case TARGET_EXPR): We must always store + into the allocated slot for TAREGT_EXPRs. + +Tue Feb 13 18:27:05 1996 Philippe De Muyter + + * configure (powerpc-ibm-aix3): Look for 3.2.x, not 3.2x. + + * fixincludes (memory.h): Fix it also on sysV68. + +Tue Feb 13 17:59:03 1996 Lee Iverson + + * gcc.c (DEFAULT_SWITCH_TAKES_ARG): New macro, from SWITCH_TAKES_ARG. + (SWITCH_TAKES_ARG): Use it. + * i386/{osfrose,sol2}.h (SWITCH_TAKES_ARG): Likewise. + * mips/{gnu,mips}.h (SWITCH_TAKES_ARG): Likewise. + * sparc/sol2.h (SWITCH_TAKES_ARG): Likewise. + * config/svr4.h (SWITCH_TAKES_ARG): Likewise. + +Tue Feb 13 17:43:46 1996 Jim Wilson + + * integrate.c (save_constants_in_decl_trees): New function. + (save_for_inline_copying, save_for_inline_nocopy): Call it. + +Tue Feb 13 17:40:27 1996 Richard Kenner + + * expr.c (convert_move): Fix typo in extendqfh2 case. + + * reload1.c (reload): Make some non-group code no longer + conditional on SMALL_REGISTER_CLASSES. + +Tue Feb 13 17:30:45 1996 J"orn Rennecke (amylaar@meolyon.hanse.de) + + * pdp11.c: #include flags.h + (output_function_prologue, function_epilogue): Remove declarations + of call_used_regs and frame_pointer_needed. + + * c-common.c (overflow_warning): Fix typo in warning message. + + * c-decl.c (finish_decl): TREE_ASM_WRITTEN says if duplicate_decls + modified declaration to match an outside file scope declaration. + + * stmt.c (expand_end_case): Don't use ADDR_DIFF_VEC for PIC if + ASM_OUTPUT_ADDR_DIFF_ELT is not defined. + * a29k.h, romp.h (ASM_OUTPUT_ADDR_DIFF_ELT): Remove. + +Tue Feb 13 13:36:36 1996 Michael Meissner + + * rs6000/cygwin32.h (CPP_PREDEFINES): Do not define PPC, just + define __PPC__. Also define _ARCH_PPC to be compatible with the + other rs6000/powerpc ports. + * rs6000/win-nt.h (CPP_PREDEFINES): Ditto. + + * rs6000/cygwin32.h (LIBGCC_SPEC): Don't define, always link in. + (SDB_DEBUGGING_INFO): Undef. + (DBX_DEBUGGING_INFO): Define. + (PREFERRED_DEBUGGING_TYPE): Define as DBX_DEBUG. + + * rs6000/t-{cygwin32,winnt} (MULTILIB*): Remove multilib support. + + * rs6000/x-cygwin32 (LANGUAGES): Delete, don't override. + + * rs6000/ntstack.asm: New file to provide __allocate_stack, which + guarantees all pages in a dynamically allocated stack frame are + touched in order, so that the stack is properly grown. + + * rs6000/cgywin32.asm: Delete unused file. + + * rs6000/t-{cygwin32,winnt} (LIB2FUNCS_EXTRA): Add ntstack.S + to libgcc2 build. + + * rs6000.md (allocate_stack): For NT, call __allocate_stack to + bump the stack if the size is large or variable. + + * libgcc1-test.c (mainCRTStartup,__start): New startup functions + to silence more linkers. + +Tue Feb 13 13:30:53 1996 Jim Wilson + + * expr.c (store_constructor_field): Only call change_address if + bitpos is nonzero. + +Tue Feb 13 08:21:01 1996 Fila Kolodny + + * i370/mvs.h (CPP_SPEC): Add '-trigraphs' because IBM's h files + contain them. + +Tue Feb 13 08:17:52 1996 Bernd Schmidt + + * c-typeck.c (quality_type prototype): Typo, rename as + qualify_type. + (build_binary_op): Fix precedence errors. + * combine.c (force_to_mode, num_sign_bit_copies, simplify_comparison): + Fix precedence errors. + * emit-rtl.c (gen_lowpart): Could return without a value. + * jump.c (jump_optimize): Fix potential infinite loop. + * reg-stack.c (record_reg_life_pat): Fix precedence error. + * reload1.c (emit_reload_insns): Fix precedence errors. + * stmt.c (bc_pushcase): Fix precedence error. + +Mon Feb 12 23:14:02 1996 Jason Merrill + + * toplev.c (rest_of_compilation): Also set RTX_INTEGRATED_P when + we aren't going to emit the inline just yet. + +Mon Feb 12 21:31:02 1996 Jim Wilson + + * rtl.h (INLINE_REGNO_POINTER_FLAG, INLINE_REGNO_POINTER_ALIGN): + Add one to array index. + +Mon Feb 12 20:55:39 1996 H.J. Lu (hjl@gnu.ai.mit.edu) + + * configure (i[345]86-*-linux*): Set tmake_file t-linux. + Add crtbeginS.o and crtendS.o to extra_parts. + * i386/linux.h (CC1, LIB_SPEC): Deleted. + * config/linux.h (STARTFILE_SPEC): Add crtbeginS.o if -shared. + (CC1_SPEC): New. + (LIB_SPEC): Remove %{mieee-fp:-lieee}; use -lc_p for -profile. + * config/t-linux: New file. + +Mon Feb 12 20:42:11 1996 Randy Smith + + * i386/x-osfrose (XCFLAGS{,_NODEBUG}): Remove $(SHLIB). + (XCFLAGS): New variable. + (libdir, mandir, bindir): Delete. + * i386/t-osf: New file. + * i860/paragon.h (STARTFILE_SPEC): Make gcc find crt0.o, not loader. + (LIB_SPEC): Remove /usr/lib. + * Makefile.in (TCFLAGS): New variable. + (GCC_CFLAGS): Add $(TCFLAGS). + (LIBGCC2_CFLAGS): Add -D for __GCC_FLOAT_NOT_NEEDED. + (libgcc1-test): Remove -nostdlib. + (float.h-cross): Don't give error #ifdef __GCC_FLOAT_NOT_NEEDED. + * enquire.c: Define __GCC_FLOAT_NOT_NEEEDED. + * configure (i[3456]86-*-osfrose): Add t-osf as tmake_file. + +Mon Feb 12 18:43:54 1996 Oliver Kellogg (oliver.kellogg@space.otn.dasa.de) + + * 1750a.c (add_1_to_mem): Corrected. + +Mon Feb 12 18:23:35 1996 Doug Evans + + * configure (sparclet-*-aout*): New configuration. + +Mon Feb 12 14:43:50 1996 Per Bothner + + Changes to distinguish typedef from original type in debug output. + * tree.h (DECL_ORIGINAL_TYPE): New macro. + * tree.c (copy_node): Zero out type.symtab union. + * c-decl.c (pushdecl): Set DECL_ORIGINAL_TYPE for typedef origin. + * dbxout,c (dbxout_type): Don't canonicalize typedef type to base. + +Mon Feb 12 12:01:16 1996 Richard Earnshaw (rearnsha@armltd.co.uk) + + * arm.h: (CPP_SPEC): Define __ARMEB__, __ARMEL__, and + __ARMWEL__ depending on the endian flags passed to the compiler. + (ARM_FLAG_LITTLE_WORDS): Define. + (TARGET_SWITCHES): Add option -mwords-little-endian. + (TARGET_LITTLE_WORDS): Define. + (WORDS_BIG_ENDIAN): Select based on the endian switches. + (LIBGCC2_WORDS_BIG_ENDIAN): Define based on run-time endian + defines. + * arm.c (output_move_double): Cope with both word-endian + alternatives. Remove extraneous parameters from calls to + output_mov_immediate. + (arm_print_operand): New print code 'Q' for the least significant + register of a DImode operand. Make code 'R' always print the + most significant register, rather than the highest numbered. + * arm.md (all DImode output patterns): Use print code + 'Q' to access the least significant word. Make sure the + patterns are fully aware of the word endianness. + + * arm/semi.h (CPP_SPEC): Define __ARMEB__, __ARMEL__, and + __ARMWEL__ depending on the endian flags passed to the compiler. + (LINK_SPEC): Pass -EB to the linker if compiling for big-endian + mode. + (ASM_SPEC): Likewise for the assembler. + * arm/semiaof.h (CPP_SPEC): Define __ARMEB__, __ARMEL__, and + __ARMWEL__ depending on the endian flags passed to the compiler. + +Mon Feb 12 10:15:29 1996 Ian Lance Taylor + + * configure: Permit tm_file and xm_file to be a list of header + file names, rather than just a single file. For many targets, + handle --with-stabs by adding dbx.h to tm_file, rather than using + a different tm_file. + * dbx.h: New file. + * alpha/gdb-osf2.h, alpha/gdb-osf12.h, alpha/gdb.h: Deleted. + * i386/sysv4gdb.h, mips/iris{5gdb,4gl,4gdb,3gdb}.h: Likewise. + * mips/dec-gosf1.h, mips/news{4,5}-gdb.h, mips/svr4-t-gdb.h: Likewise. + * mips/ultrix-gdb.h, mips/bsd-{4,5}-gdb.h: Likewise. + * mips/svr{4-5,4-4,3-5,3-4}-gdb.h, mips/mips-5-gdb.h: Likewise. + * mips/ecoff{,l}-gdb.h, mips/mips-4-gdb.h: Likewise. + +Mon Feb 12 07:22:20 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * integrate.c (save_for_inline_copying): Put virtual regs into + new regno_reg_rtx copy. + +Sun Feb 11 18:53:12 1996 Torbjorn Granlund + + * i386.md: Delete spurious integer subtract patterns. + Delete % from subtract operand constraints. + +Sun Feb 11 19:17:24 1996 Jeffrey A. Law + + * m68k.md (movqi): Call CC_STATUS_INIT when loading to/from + an address register via a data register. + +Sun Feb 11 08:44:49 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * c-common.c (check_format_info): Handle missing type in format + when terminated by a new `%'. + +Sat Feb 10 15:14:22 1996 J.T. Conklin + + * cross-make (STMP_FIXPROTO): Moved from here to build-make. + * build-make (STMP_FIXPROTO): Moved here from cross-make. + +Sat Feb 10 08:39:05 1996 Oliver Kellogg (oliver.kellogg@space.otn.dasa.de) + + * 1750a.md (movstrqi): Corrected. + (zero_extendqihi2): Taken out, let GCC synthesize. + (movhi-1): Added insn to move HImode small constant to memory. + (movhf-1): Added insn to move HFmode zero to memory. + (movtqf-1): Added insn to move TQFmode zero to memory. + (numerous insns): Taken out B (Base Reg with Index) mode. + + * 1750a.c (movcnt_regno_adjust): Corrected. + (mov_memory_operand, zero_operand): Added. + (b_mode_operand): Corrected. + (simple_memory_operand, add_1_to_mem): Added. + (print_operand_address): Corrected case of 'Q' output modifier. + + * 1750a.h (REG_ALLOC_ORDER): Changed back to natural order. + (CONST_DOUBLE_OK_FOR_LETTER_P): Added letter 'G'. + (EXIT_IGNORE_STACK): Set to 0. + (REG_OK_FOR_BASE_P, REG_OK_FOR_INDEX_P): Use corresponding REGNO_OK. + (MOVE_MAX, MOVE_RATIO): Defined. + +Sat Feb 10 08:28:12 1996 Martin Anantharaman + + * configure (m68k-*-psos*): New configuration. + * psos.h: New file. + * m68k/m68k-psos.h: New file. + +Sat Feb 10 08:07:52 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * sched.c (flush_pending_lists): Add new arg, ONLY_WRITE. + (sched_analyze_{1,2,insn}): Add new arg to flush_pending_lists. + (sched_analyze): Always flush pending write list for call, even const. + + * integrate.c (save_for_inline_copying): Put reg_map in function's + maybepermanent obstack instead of using alloca; set regno_reg_rtx + to it; delete recently-added copying of this later. + +Sat Feb 10 00:49:58 1996 Doug Evans + + * sched.c (add_dependence): Add test for next != CODE_LABEL. + +Fri Feb 9 16:10:04 1996 Stan Cox (coxs@dg-rtp.dg.com) + + * i386.md (fp, integer): Added function units for pentium. + (cmp*,mov*,add*,sub*,mul*,div*,extend*,trunc*,and*,ior*,xor*,neg*, + abs*,sqrt*,sin*,cos*,not*,ash*,lsh*,rot*,sub): Tightened constraints, + added attribute support, and made changes for new `binary' and + `unary' functions. + + * i386.c (processor_costs): New variable. + (optimization_options, ix86_expand_binary_operator, + ix86_binary_operator_ok, ix86_expand_unary_operator, + ix86_unary_operator_ok, is_mul, is_div, copy_all_rtx, rewrite_address, + last_to_set_cc, doesnt_st_condition_code, sets_condition_code, + str_immediate_operand, is_fp_insn, is_fp_dest, is_fp_store, + agi_dependent, reg_mentioned_in_mem): New functions. + + * i386.h (OPTIMIZATION_OPTIONS, ALIGN_DFmode, IS_STACK_MODE, + IX86_EXPAND_BINARY_OPERATOR): New macros. + (RTX_COSTS, REGISTER_MOVE_COST, ADJUST_BLOCKAGE) Changed for pentium. + +Fri Feb 9 14:47:27 1996 Doug Evans + + * sparc.c (sp64_medium_pic_operand): New function. + (move_pic_label): Delete. + (legitimize_pic_address): Simplify using some named patterns. + (finalize_pic): Add preliminary sparc64 support. + (emit_move_sequence): Reorganize. + * sparc.md (pic_lo_sum_si,pic_sethi_si,get_pc_sp32,get_pc_sp64, + move_pic_label_si,move_label_di,sethi_di_sp64): Make named patterns. + (sethi_di_sp64_const,sethi_di_medium_pic): New anonymous patterns. + (move_pic_label_si,move_label_di): Optimize for near labels. + (tablejump): Use for TARGET_MEDANY. + (casesi): Delete. + +Fri Feb 9 13:48:45 1996 Jim Wilson + + * mips.md (probe+2, probe+4): New conditional move patterns. + (movsicc): Don't truncate comparison if it is DImode. + + * sh.h (CPP_SPEC): Add defines for -m1, -m2, and -m3. + +Fri Feb 9 09:11:28 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * toplev.c (rest_of_compilation): Set RTX_INTEGRATED_P in + INLINE_HEADER iff function is inlineable. + * calls.c (expand_call): Test RTX_INTEGRATED_P in DECL_SAVED_INSNS. + +Thu Feb 8 01:11:15 1996 Jeffrey A. Law + + * pa.md (floatunssisf2 expander): Don't use "general_operand". + (floatunssidf2 expander): Likewise. + +Wed Feb 7 16:59:31 1996 Michael Meissner + + * rs6000/{sysv4,win-nt,netware,cygwin32}.h ({ASM,LINK}_SPEC): + Don't use %{V} for either linker or assembler. + +Tue Feb 6 17:22:29 1996 Per Bothner + + * dbxout.c (dbxout_range_type): Emit non-range INTEGER_TYPE + as a sub-range of itself (so gdb can tell the difference). + +Tue Feb 6 17:01:44 1996 David Edelsohn + + * rs6000.md (addsi3 and adddi3 split): Use cleaner computation + and portable HOST_WIDE_INT. + (iordi3 split): Use HOST_WIDE_INT. + (movdi): Add TARGET_64BIT support and generate 64 bit constants. + (movdi matcher, TARGET_POWERPC64): Add immediate constraint handled + by new define_split. + (allocate_stack): Use TARGET_32BIT. + (tablejump): Add TARGET_64BIT support using ... + (tablejumpsi): Rename original tablejump pattern. + (tablejumpdi): New pattern. + +Tue Feb 6 15:29:22 1996 Per Bothner + + * stor-layout.c (layout_type): Use same code to layout CHAR_TYPE + as for INTEGER_TYPE (instead of hard-wiring in QImode). + +Tue Feb 6 15:13:38 1996 Jeffrey A. Law + + * pa.md (various patterns): Avoid using "general operand" in + define_insn patterns. + +Sun Feb 4 21:37:05 1996 Michael Meissner + + * rs6000/eabi{,sim}.h (LINK_START_SPEC): Bump the default start address + for the simulator to 0x10000074 so that we don't waste a page in the + linked file. + +Fri Feb 2 19:44:10 1996 Michael Meissner + + * rs6000/eabi-c{i,n}.asm (.sdata2, .sbss2): Put these in the + read-only section, not read-write. + + * libgcc2.c (__unwind_function, rs6000/powerpc): Use _ARCH_PPC + being defined to indicate to use PowerPC mnemonics. + + * config/rs6000/t-cygwin32 (MULTILIB*): Add software floating + point support. + +Thu Feb 1 09:10:02 1996 Steve Chamberlain + + * {i386,rs6000}/cygwin32.{asm,h}: New templates. + * {i386,rs6000}/{t,x}-cygwin32: Ditto. + * {i386,rs6000}/xm-cygwin32.h: Ditto. + * configure (powerpcle-*-cygwin32, i[3456]86-*-cygwin32): New. + +Fri Feb 2 17:42:40 1996 Paul Eggert + + * c-decl.c (finish_struct): + Fix typo in transparent union warning that led to core dump. + + * c-parse.in (stmt): Warn about `goto *expr;' if pedantic. + (label): Warn about `case expr ... expr:' if pedantic. + +Fri Feb 2 11:05:27 1996 Doug Evans + + * h8300.h (TARGET_ALIGN_300): Renamed from TARGET_ALIGN_STRUCT_300. + (TARGET_SWITCHES): Rename -malign-struct-300 to -malign-300. + (BIGGEST_ALIGNMENT): Use TARGET_ALIGN_300. + +Fri Feb 2 08:25:49 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * flow.c (jmp_uses_reg_or_mem): Renamed from uses_reg_or_mem. + Don't look into condition of an IF_THEN_ELSE; also make faster. + (find_basic_blocks): Use new name. + +Fri Feb 2 06:49:56 1996 J"orn Rennecke (amylaar@meolyon.hanse.de) + + * reload.c (debug_reload): Fix typo for reload_noncombine. + +Thu Feb 1 21:49:02 1996 Jeffrey A. Law + + * pa-pro.h (TARGET_DEFAULT): Turn on TARGET_SOFT_FLOAT by + default for all pro targets. + * t-pro: Delete all multilib references. + +Thu Feb 1 17:50:02 1996 Doug Evans + + * c-lex.c (check_newline): Return result of HANDLE_PRAGMA. + * h8300.h (HANDLE_PRAGMA): Pass result back to caller. + * i960/i960.h (HANDLE_PRAGMA): Likewise. + * sh.h (HANDLE_PRAGMA): Likewise. + * nextstep.h (HANDLE_PRAGMA): Likewise. + +Wed Jan 31 19:26:03 1996 Doug Evans + + * m68k/m68k-none.h: Rewrite to use EXTRA_SPECS. + * m68k/vxm68k.h (CPP_SPEC): Delete. + (SUBTARGET_EXTRA_SPECS): Define. + +Wed Jan 31 15:10:59 1996 David Edelsohn + + * rs6000.c (output_epilog): Fix PPC64 typos and use TARGET_32BIT. + (output_prolog): Same. + (rs6000_trampoline_template, rs6000_trampoline_size): Use TARGET_32BIT. + * rs6000.md (movdf TARGET_POWERPC64 matcher): Fix std typo. + (movdi TARGET_POWERPC64 matcher): Same. + +Wed Jan 31 09:46:11 1996 Richard Earnshaw (rearnshaw@armltd.co.uk) + + * regs.h (regno_pointer_align, REGNO_POINTER_ALIGN): Delete from here. + * rtl.h (regno_pointer_align, REGNO_POINTER_ALIGN): Put them here. + +Wed Jan 31 08:26:12 1996 Andreas Schwab (schwab@issan.informatik.uni-dortmund.de) + + * m68k/linux.h (STRICT_ALIGNMENT): Define to zero. + (LEGITIMATE_PIC_OPERAND_P): Match definition from m68kv4.h. + + * m68k.h (TRAMPOLINE_{TEMPLATE,SIZE}): Avoid need for helper function. + (INITIALIZE_TRAMPOLINE): Likewise. + (TRAMPOLINE_ALIGNMENT): Renamed from TRAMPOLINE_ALIGN. + * m68k/next.h (INITIALIZE_TRAMPOLINE): Adjusted accordingly. + + * m68kv4.h (STATIC_CHAIN_REGNUM): Redefine to use register a1. + (TRAMPOLINE_TEMPLATE): Likewise. + + * m68k/linux.h, m68kv4.h (LIBCALL_VALUE): Return XFmode value in fp0. + * m68k.c (init_68881_table): Use SFmode for the first six + constants and DFmode for the seventh. + + * m68k.md (movqi): Use moveq if possible. + +Wed Jan 31 08:18:15 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (expand_builtin, case BUILT_IN_NEXT_ARG): Strip off + INDIRECT_REF when checking second arg. + + * calls.c (struct arg_data, expand_call): Test STRICT_ALIGN with #if. + +Wed Jan 31 07:47:56 1996 Tim Wright (timw@sequent.com) + + * configure (i[345]-sequent-sysv*): Change to sysv3*; add i686. + (i[3456]86-sequent-ptx4*, i[3456]86-sequent-sysv4*): New cases. + * fixinc.ptx (sys/mc_param.h): Remove embedded asm. + * fixinc.svr4 (__STDC__): Add one more case. + * i386/ptx4-i.h, ptx4.h: New files. + +Wed Jan 31 07:15:23 1996 Philippe De Muyter (phdm@info.ucl.ac.be) + + * m68k.h (MACHINE_STATE_{SAVE,RESTORE}): Allow MOTOROLA syntax. + + * m68k.md ({adddi,subdi}_sexthishl32): 'a' and 'd' versions merged + and fixed; do not generate 'add/sub a,m'. + + * gcc.c (warn_std_ptr): Initialize with 0 instead of NULL_PTR. + +Tue Jan 30 13:29:05 1996 Ian Lance Taylor + + * dbxout.c: Don't include . + Don't compare strchr result to NULL. + + * config/svr4.h (ASM_FINAL_SPEC): Use %|, not ${pipe:-}. + +Tue Jan 30 06:48:43 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * combine.c (nonzero_bits, case REG): Ignore REG_POINTER_ALIGNMENT. + Restore old code for SP, but use it for all pointers to + defined locations in the frame. + +Mon Jan 29 11:25:28 1996 Ian Lance Taylor + + * dbxout.c (dbxout_type_methods): Don't use #ifndef inside call to + strchr. + +Sun Jan 28 14:44:09 1996 Doug Evans + + * config/dbxcoff.h (*): #undef first. + +Sat Jan 27 21:46:16 1996 David Edelsohn + + * rs6000.c (rs6000_sync_trampoline): Add cmpdi to 64bit case. + (rs6000_initialize_trampoline): CSE of Pmode to pmode. + * rs6000.md (movdf): Handle move between FPR and 64 bit GPR. + (movdi matcher): Handle SPR move to itself and add "mr." combiner. + +Sat Jan 27 10:06:31 1996 Michael Meissner + + * rs6000/sysv4.h (ASM_OUTPUT_ALIGNED_LOCAL): Redefine, put small + data items in .sbss if -msdata. + (SWITCH_TAKES_ARG): Add 'B', 'b', and 'V'. + +Sat Jan 27 07:59:25 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * tree.h (enum built_in_function): Add BUILT_IN_{SET,LONG}JMP. + * expr.c: Include hard-reg-set.h. + (arg_pointer_save_area): New declaration. + (expand_builtin, case BUILT_IN_{SET,LONG}JMP): New cases. + * Makefile.in (expr.o): Includes hard-reg-set.h. + * c-decl.c (init_decl_processing): Add definitions for + __builtin_setjmp and __builtin_longjmp. + * cccp.c (initialize_builtins): Add def of __HAVE_BUILTIN_SETJMP__. + + * expr.c (expand_expr, case COMPONENT_REF): Pass EXPAND_INITIALIZER + to recursive call. + +Fri Jan 26 17:24:07 1996 Doug Evans + + * sparc.h (sparc_arch_type): Delete. + ({,TARGET_}MASK_DEPRECATED_V8_INSNS): Define. + (ARCH64_SWITCHES): Renamed from V9_SWITCHES. + * sparc.c (sparc_arch_type): Delete. + (sparc_init_modes): Likewise. + (output_move_quad): Don't use ldq/stq unless TARGET_HARD_QUAD. + * sparc/sp64-sol2.h (TARGET_DEFAULT): Add MASK_DEPRECATED_V8_INSNS. + (SUBTARGET_SWITCHES): Add -m{no-,}deprecated-v8-insns. + * sparc.md (arch attribute): Rewrite. + (isa): New attribute. + (32 bit multiply/divide patterns): Use if TARGET_DEPRECATED_V8_INSNS. + (32 bit divide patterns): V9 doesn't require delay after y reg write. + +Fri Jan 26 12:08:43 1996 David Edelsohn + + * rs6000.h (TARGET_32BIT): Define. + (BITS_PER_WORD, UNITS_PER_WORD): Invert so 32bit expected case. + (LONG_TYPE_SIZE, POINTER_BOUNDARY, PARM_BOUNDARY): Likewise. + (RS6000_REG_SAVE, RS6000_SAVE_AREA, RS6000_VARARGS_SIZE): Likewise. + (RETURN_ADDRESS_OFFSET, CASE_VECTOR_MODE, MOVE_MAX): Likewise. + (Pmode, FUNCTION_MODE): Likewise. + (LEGITIMATE_OFFSET_ADDRESS_P): Handle TARGET_64BIT. + (GO_IF_LEGITIMATE_ADDRESS, LEGITIMIZE_ADDRESS): Likewise. + (GO_IF_MODE_DEPENDENT_ADDRESS): Same. + +Fri Jan 26 10:37:52 1996 Stan Coxs + + * m88k.md (umulsidi3): Added for the 88110 + +Fri Jan 26 09:35:42 1996 Michael Meissner + + * rs6000/sysv4.h (STRIP_NAME_ENCODING): Deal with names that have + both @ and * prefix characters. + (ASM_OUTPUT_LABELREF): Ditto. + +Thu Jan 25 10:03:34 1996 Michael Meissner + + * rs6000.h (LEGITIMIZE_ADDRESS): Rewrite to use HOST_WIDE_INT, not + plain int. + (optimize,flag_expensive_optimizations): Provide declaration for + expander functions. + + * rs6000.md (movsi): Correct code in splitting an address into + load from the TOC, and add low/high integer parts. If expensive + optimizations, and reload hasn't started, use separate pseudo regs + for each step. + + * rs6000.c (small_data_operand): Don't use the function + eliminate_constant_term, unwind code directly. + (input_operand): SYMBOL_REF/CONST of small data operand is valid. + (print_{,address_}operand): Add @sda21(0) in appropriate cases for + small data. + %L, etc. so that if the item is in small memory, the appropriate + relocation is used. + (rs6000_select{,_rtx}_section): Don't put floating point constants + or small strings in .sdata2 since we can't tell from the pointer + whether it is in the small data area or not. + + * rs6000.h (EXTRA_CONSTRAINT): Add 'U' for small data references. + (LEGITIMATE_SMALL_DATA_P): Test explicitly for SYMBOL_REF or CONST + before calling small_data_operand. + + * rs6000.md (movsi): Handle the addresses of small data items. + + * rs6000/sysv4.h (g_switch_{value,set}): Add declarations. + (SDATA_DEFAULT_SIZE): Default to 8. + (SUBTARGET_OVERRIDE_OPTIONS): If -G was not set, set it to + SDATA_DEFAULT_SIZE. + (CC1_SPEC): Pass -G nn to the compilers. + (SWITCH_TAKES_ARG): Add -G nn support. + (LINK_SPEC): Pass -G nn to the linker. + +Thu Jan 25 09:16:34 1996 Doug Evans + + * configure (sparc64-*-solaris2*): New target. + * sparc.h (SPARC_{V9,ARCH64}): Default value is 0. + (*): Replace SPARCV9 with SPARC_{V9,ARCH64}. + (MASK_CPUS): Define. + ({MASK,TARGET}_ENV32): Delete. + ({MASK,TARGET}_ARCH64,TARGET_ARCH32): Define. + (TARGET_SWITCHES): Reset cpu flags first for each variant. + (CONDITIONAL_REGISTER_USAGE): If 32 bit v9 system, unfix g1-g4, + fix g5, and make %f48-%f80 call used. + * sparc/sp64-aout.h (SPARC_{V9,ARCH64}): Define. + (TARGET_VERSION): Define. + (TARGET_DEFAULT): Add MASK_ARCH64, delete MASK_ENV32. + (JUMP_TABLES_IN_TEXT_SECTION): Define. + (READONLY_DATA_SECTION): Make text_section. + * sparc/sp64-elf.h (SPARC_{V9,ARCH64}): Define. + (TARGET_DEFAULT): Add MASK_ARCH64. + (ENDFILE_SPEC): No longer need to check for -nostartfiles. + (ASM_IDENTIFY_GCC): Define as empty. + * sparc/sp64-sol2.h: New file. + * sparc.c (*): Replace TARGET_V9 with TARGET_ARCH64. + (hard_32bit_mode_classes): Add v9 regs. + (gen_v9_scc): Handle 32 bit v9 case. Call v9_regcmp_p. + * sparc.md (*): Replace TARGET_V9 with TARGET_ARCH64 in places + requiring 64 bit environment. + (multf3_extend): Require TARGET_HARD_QUAD. + +Thu Jan 25 00:33:25 1996 Ian Lance Taylor + + * dbxcoff.h (DBX_USE_BINCL): Define. + (DBX_CONTIN_LENGTH): Define if not defined. + +Wed Jan 24 18:00:12 1996 Brendan Kehoe + + * alpha.c (alpha_write_verstamp): Only emit MS_STAMP and LS_STAMP, + not the extra numbers. + +Wed Jan 24 15:18:15 1996 Michael Meissner + + * rs6000.c (init_cumulative_args): Rewrite to use DEFAULT_ABI + runtime tests, instead of V.4 #ifdefs. + (function_arg{,_advance,_partial_nregs,_pass_by_reference}): Ditto. + (setup_incoming_varargs): Ditto. + (init_cumulative_args): Set call_cookie field to CALL_NORMAL or + CALL_NT_DLLIMPORT. + (function_arg): Add support for DLL imports. + (rs6000_valid_{decl,type}_attribute_p): New functions for NT + attributes cdecl, stdcall, dllimport, and dllexport. + (rs6000_comp_type_attributes): New attribute support. + (rs6000_set_default_type_attributes): Ditto. + (rs6000_dll_import_ref): Ditto. + + * rs6000.h (FP_ARG_{AIX,SYSV}_MAX_REG): Move here from sysv4.h. + * sysv4.h (FP_ARG_{AIX,SYSV}_MAX_REG): Move to rs6000.h. + + * rs6000.h (rs6000_call_cookie): New enum to describe the integer + that is the 2nd argument to call insns and 3rd argument to + call_value insns. Add support for NT DLL imports. + (rs6000_args): Add call_cookie field. + (VALID_MACHINE_{DECL,TYPE}_ATTRIBUTE): Define to call C functions. + ({COMP_TYPE,SET_DEFAULT_TYPE}_ATTRIBUTES): Ditto. + (rs6000_valid_{decl,type}_attribute_p): Add declarations. + (rs6000_comp_type_attributes): Ditto. + (rs6000_set_default_type_attributes): Ditto. + (rs6000_dll_import_ref): Ditto. + + * win-nt.h (ASM_DECLARE_FUNCTION_NAME): Add support for dllexport + attribute. + + * rs6000.md (call insns): Add support for NT dllimport functions, + and fix up NT indirect calls. Also correctly set the flag + rs6000_save_toc_p on NT indirect calls. + + * aix41.h (LINK_SPEC): Use new extra specs to avoid separate + versions for native and cross compilation. + * rs6000.h (LINK_SPEC): Ditto. + * sysv4.h (LINK_SPEC): Ditto. + + * rs6000.h (EXTRA_SPECS): Add link_syscalls, link_libg, link_path, + link_specs, and also allow target to define more with the macro + SUBTARGET_EXTRA_SPECS. + (LINK_{LIBG,SYSCALLS}_SPEC): Define as fixed pathnames if native + compilation, and currently nothing if cross compiling. + (LINK_START_SPEC): If not defined, define as empty. + * eabi{,sim}.h (LINK_START_SPEC): Add default -Ttext for + simulator. + + * eabi{aix,le}.h (MULTILIB_DEFAULTS): Add -mno-sdata default. + * sysv4{,le}.h (MULTILIB_DEFAULTS): Ditto. + + * rs6000.c (small_data_operand): New function to return true if + the operand lives in small data under eabi. + (rs6000_select{,_rtx}_section): New functions to determine whether + to put global and static items in the V.4/eabi small data areas if + -msdata. + + * rs6000.h (LEGITIMATE_SMALL_DATA_P): Call small_data_operand it + if V.4. + (GO_IF_LEGITIMATE_ADDRESS): If LEGITIMATE_SMALL_DATA_P, the item + is a valid address. + (ASM_OUTPUT_LABELREF): Use fputs, not fprintf. + (small_data_operand): Declare function. + + * sysv4.h (TARGET_SWITCHES): New switch -msdata to use V.4 and + eabi defined small data sections. + (SUBTARGET_OVERRIDE_OPTIONS): Don't allow -msdata and + -mrelocatable or -mcall-aix options. + (EXTRA_SECTION{S,_FUNCTIONS}): Add .sdata, .sdata2, and .sbss + sections. + (SELECT{,_RTX}_SECTION): Call (rs6000_select{,_rtx}_section). + (ASM_SPEC): The -msdata switch passes -memb to the assembler. + (ENCODE_SECTION_INFO): Prepend a '@' to the name, if the item + lives in a small data region. + (STRIP_NAME_ENCODING): Strip '@' in addition to '*'. + (ASM_OUTPUT_LABELREF): Strip a leading '@'. + + * t-{ppc,eabi}gas (MULTILIB*): Add support for libraries built + with/without -msdata. Drop support for -mcall-aixdesc libraries. + +Wed Jan 24 15:18:15 1996 Kim Knuttila + + * rs6000/win-nt.h (LIB_SPEC): Change options to GNU ld style. + (From Jason Molenda) + +Wed Jan 24 14:32:48 1996 Jim Wilson + + * reload1.c (used_spill_regs): New variable. + (reload): Set it. + * reorg.c (find_dead_or_set_registers): New function. + (mark_target_live_regs): Delete loop looking forward from target + and instead call find_dead_or_set_registers. + (fix_reg_dead_note): New function. + (fill_slots_from_thread): Call it. + + * loop.c (scan_loop): Correct comment. + (strength_reduce): Correct comments. Don't set maybe_multiple when + pass branch to scan_start. Don't set not_every_iteration after + passing a CODE_LABEL, or after passing a branch out of the loop. + When outputting DEST_ADDR giv increments, put them next to the memory + address on machines with auto-increment addresses. + (record_biv): Set new field always_executed. + (record_giv): Set new fields always_executed and auto_inc_opt. + (maybe_eliminate_biv_1): Reject biv with auto_inc_opt optimization + in some cases. + * loop.h (struct induction): New fields always_executed and + auto_inc_opt. + + * c-typeck.c (pointer_int_sum): Use TYPE_PRECISION (sizetype) not + POINTER_SIZE to agree with expr.c. + +Tue Jan 23 15:17:30 1996 Doug Evans + + * sparc/sol2.h (ASM_OUTPUT_ALIGNED_LOCAL): Delete, use svr4.h's. + +Tue Jan 23 03:28:01 1996 Paul Eggert + + * cexp.y: Use preprocessor arithmetic instead of C arithmetic + to avoid warnings on some compilers. + (HOST_WIDE_INT_MASK): Remove. + (MAX_CHAR_TYPE_MASK, MAX_WCHAR_TYPE_MASK): New macros. + (yylex): Use them. + +Mon Jan 22 18:39:21 1996 Per Bothner + + * cppexp.c (cpp_parse_expr): Set HAVE_VALUE flag for unary + minus, even if skip_evaluation is true. + +Mon Jan 22 16:53:48 1996 David Edelsohn + + * rs6000.h (BIGGEST_ALIGNMENT): Increase to 64 always. + (BIGGEST_FIELD_ALIGNMENT): Define. + (GO_IF_LEGITIMATE_ADDRESS): Merge PRE_INC and PRE_DEC cases. + (LEGITIMIZE_ADDRESS): Use Pmode not SImode. + (CASE_VECTOR_MODE): Depend on TARGET_64BIT. + (ASM_OUTPUT_COMMON): Delete. + (ASM_OUTPUT_ALIGNED_COMMON): Define. + * rs6000/sysv4.h (BIGGEST_FIELD_ALIGNMENT): Undefine. + * rs6000.md (adddi3, subdi3, negsi2): New PowerPC64 patterns. + (ashldi3, lshrdi3, ashrdi3, anddi3, iordi3, xordi3): Same. + (moddi3, cmpdi, tablejump matchers): Same. + (divdi3): Update PowerPC64 patterns. + * rs6000.c (rs6000_initialize_trampoline, case ABI_AIX): Use Pmode + not SImode. + +Sun Jan 21 23:33:24 1996 Ian Lance Taylor + + * dbxout.c: Include + +Fri Jan 19 17:17:00 1996 Per Bothner + + * tree.h (CONSTRUCTOR_TARGET_CLEARED_P): Removed. + * expr.c (is_zeros_p, mostly_zeros_p): Handle SET_TYPE CONSTRUCTORs. + (store_constructor_field): New helper function. + (store_constructor): Take 'cleared' parameter. + (expand_expr): Fix store_constructor_call to pass 'cleared' of 0. + + * expr.c (store_constructor, SET_TYPE): Fix off-by-one-error. + Also, devide start byte by BITS_PER_UNIT before passing to memset. + (store_constructor): `continue' in wrong place. + + * expr.c (store_constructor): If storing into a range of array + elements, and the range is small, or the target it not memory, + unroll the loop (and use store_field, which handles REGs). + (store_constructor): Handle RANGE_EXPR in array index. + +Fri Jan 19 16:52:25 1996 Doug Evans + + * svr4.h (SWITCH_TAKES_ARG): Add 'x'. + * sparc/sol2.h (SWITCH_TAKES_ARG): Likewise. + +Fri Jan 19 15:18:38 1996 Ian Lance Taylor + + * dbxout.c (flag_minimal_debug): Initialize to 0 if both + NO_DOLLAR_IN_LABEL and NO_DOT_IN_LABEL are defined. + (dbxout_type_methods): If the mangled method name uses the special + C++ marker character, pass show_arg_types as 1 when calling + dbxout_type. + +Fri Jan 19 11:48:28 1996 Michael Meissner + + * rs6000/eabi-ci.asm (_SDA_BASE_): Move the default definition + from the .got section to the .sdata section. Do not add 32768. + (_SDA2_BASE_): Provide a default definition. + + * rs6000/eabi-cn.asm (.got.blrl): Don't define this section any + more, linker now directly creates the blrl instruction at + _GLOBAL_OFFSET_TABLE_-4. + +Fri Jan 19 05:12:31 1996 Richard Earnshaw + + * arm/lib1funcs.asm (__divsi3, __modsi3, __udivsi3, __umodsi3): + Replace with smaller, faster versions. + +Thu Jan 18 17:41:46 1996 Jim Wilson + + * sh.c (ctype.h): Delete. + (regno_reg_class, reg_class_from_letter): Add SH3e support. + (prepare_scc_operands, broken_move, push, pop, push_regs): Likewise. + (calc_live_regs, sh_expand_prologue, sh_expand_epilogue): Likewsie. + (initial_elimination_offset, arith_reg_operand): Likewise. + (sh_builtin_saveregs, fp_zero_operand, fp_one_operand): New functions. + (sh_function_arg, sh_function_arg_partial_nregs): Delete. + * sh.h (CPP_SPEC, CONDITIONAL_REGISTER_USAGE): Add SH3E support. + (TARGET_SWITCHES, OVERRIDE_OPTIONS, FIRST_PSEUDO_REGISTER): Likewise. + (FIXED_REGISTERS, CALL_USED_REGISTERS, HARD_REGNO_MODE_OK): Likweise. + (enum reg_class, REG_CLASS_NAMES, REG_CLASS_CONTENTS): Likewise. + (REG_ALLOC_ORDER, CONST_DOUBLE_OK_FOR_LETTER_P, NPARM_REGS): Likewise. + (FUNCTION_VALUE, LIBCALL_VALUE, FUNCTION_VALUE_REGNO_P): Likewise. + (FUNCTION_ARG_REGNO_P, CUMULATIVE_ARGS, ROUND_REG): Likewise. + (INIT_CUMULATIVE_ARGS, FUNCTION_ARG_ADVANCE, FUNCTION_ARG): Likewise. + (FUNCTION_ARG_PARTIAL_NREGS, LEGITIMATE_CONSTANT_P): Likewise. + (MODE_DISP_OK_4, REGISTER_MOVE_COST, REGISTER_NAMES): Likewise. + (DBX_REGISTER_NUMBER, enum processor_type): Likewise. + (SH3E_BIT, TARGET_SH3E, FPUL_REG, FIRST_FP_REG, LAST_FP_REG): New. + (FIRST_FP_PARM_REG, FIRST_FP_RET_REG, BASE_RETURN_VALUE_REG): New. + (BASE_ARG_REG, enum sh_arg_class, struct sh_args): New. + (GET_SH_ARG_CLASS, PASS_IN_REG_P, sh_builtin_saveregs): New. + (EXPAND_BUILTIN_SAVEREGS, DOUBLE_TYPE_SIZE): New. + (TARGET_SWITCHES): Delete broken -m3l option. + * sh.md (cpu, movsi_i, movsf_i, blt, bge, sle, sge): Add SH3E support. + (push_e, pop_e, movsi_ie, movsf_ie, addsf3, subsf3): New patterns. + (mulsf3, macsf3, divsf3, floatsisf2, fix_truncsfsi2): New patterns. + (cmpgtsf_t, cmpqesf_t, cmpsf, negsf2, sqrtsf2, abssf2): New patterns. + (abssf2+9, abssf2+10): Add SH3e support to peepholes + (abssf2+11, abssf2+12): New peepholes for SH3e. + * t-sh (MULTILIB_OPTIONS): Add SH3E support. + (MULTILIB_DIRNAMES): Define to empty. + +Thu Jan 18 11:29:11 1996 Ian Lance Taylor + + * cplus-dem.c (cplus_demangle_opname): Change type of opname + parameter to const char *. + (cplus_mangle_opname): Change return type and type of opname + parameter to const char *. Don't cast return value. + * demangle.h (cplus_demangle_opname): Update declaration. + (cplus_mangle_opname): Likewise. + +Thu Jan 18 10:07:33 1996 Michael Meissner + + * gcc.c (extra_specs): If EXTRA_SPECS is defined, define + extra_specs array to hold the extra specs the machine description + defines. + (set_spec): If EXTRA_SPECS is defined, handle the extra + specifications. + (process_command, main, validate_all_switches): Likewise. + + * rs6000/{rs6000.h,powerpc.h,aix41.h} ({CPP,ASM}_SPEC): Use common + specs with EXTRA_SPECS, only modifying things in the target that + needs to be modified, rather than having tons of mostly duplicate + definitions. + * rs6000/{sysv4{,le}.h,}netware.h,lynx.h,} ({CPP,ASM}_SPEC): Ditto. + * rs6000/eabi{le,aix}.h,aix3newas.h}} ({CPP,ASM}_SPEC): Ditto. + +Wed Jan 17 19:38:24 1996 Paul Eggert + + * cexp.y (HOST_WIDE_INT_MASK): Renamed from LONG_MASK; + use HOST_WIDE_INT. + (HOST_WIDE_INT, HOST_BITS_PER_WIDE_INT): Put back. + (parse_c_expression, expression_value, parse_escape, left_shift, + right_shift, struct constant, exp, parse_number, yylex): + Replace `long' with `HOST_WIDE_INT'. + * cccp.c (PTR_INT_TYPE): Remove obsolete define to `long'. + (parse_escape, parse_c_expression, eval_if_expression, get_lintcmd, + do_line, do_if, do_elif): Replace `long' with `HOST_WIDE_INT'. + (trigraph_pcp): Don't assume a pointer difference fits in an int. + +Wed Jan 17 18:56:31 1996 Jim Wilson + + * expmed.c (extract_bit_field): For multi-word bitfield, clobber + target before storing to it. + +Wed Jan 17 14:19:34 1996 J.T. Conklin + + * sparc/{t-sol2,t-sunos40,t-sunos41}: Define away LIBGCC1_TEST + so that cross compilers targeted at these systems will build. + +Wed Jan 17 09:51:58 1996 Doug Evans + + * sparc.h (v9 INIT_CUMULATIVE_ARGS): Fix typos. + + * gcc.c (process_command): New local lang_n_files, and use + it in test of -c with -o. Move test of -save-temps. + Test for trailing NUL in -c. + + * i386/t-go32: New file. + * i386/xm-go32.h: New file. + * configure (i[345]86-*-go32*): Define xm_file and tmake_file. + +Wed Jan 17 07:47:43 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * cccp.c (HOST_BITS_PER_WIDE_INT, HOST_WIDE_INT): Put back. + (pcfinclude): Use HOST_WIDE_INT for casting pointer to integer. + +Wed Jan 17 05:25:06 1996 Jeffrey A. Law + + * va-pa.h (__gnuc_va_list): Use a "void *". + +Tue Jan 16 18:45:23 1996 Per Bothner + + * cppexp.c (cpp_lex): Do cpp_pop_buffer after CPP_POP so retried + cpp_skip_hspace will actually work. + + * cppexp.c (SKIP_OPERAND): New macro. + (cpp_parse_expr): Suppress evaluation and diagnostics in + unevaluated subexpressions. + Corresponds to Eggert's Fri Jun 9 17:58:29 1995 change. + +Tue Jan 16 11:59:07 1996 Mike Stump + + * expr.c (expand_expr, case COND_EXPR): Make sure cleanups live on + the function_obstack as they are used by the exception handling code. + (defer_cleanups_to): Ditto. + (TRUTH_ANDIF_EXPR): Ditto. + (TRUTH_ORIF_EXPR): Ditto. + +Tue Jan 16 13:57:13 1996 Jim Wilson + + * cccp.c (new_include_prefix): Ignore ENOTDIR error from stat. + +Tue Jan 16 12:18:56 1996 Doug Evans + + * i386/t-sol2 (crt[1in].o): Add missing -c. + * sparc/t-sol2 (crt[1in].o,gcrt1.o): Likewise. + Source files are assembler. + + * gcc.c (do_spec_1, case 'W'): Rename local `index' to `cur_index' to + avoid warning on solaris. + +Tue Jan 16 11:42:09 1996 Ian Lance Taylor + + * dbxcoff.h: New file for stabs in COFF support. + * a29k/a29k-udi.h: Use dbxcoff.h. + * h8300.h, i960/i960-coff.h, m68k/coff.h, m88k/m88k-coff.h: Likewise. + * sh.h, sparc/litecoff.h: Likewise. + +Tue Jan 16 08:21:45 1996 Hans-Peter Nilsson + + * optabs.c (expand_fix): Don't copy TARGET to TO if same. + + * expr.c (emit_move_insn_1): Don't emit clobber when moving + by parts and source equals destination. + +Tue Jan 16 08:08:29 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expmed.c (extract_bit_field): Don't abort if not MEM_IN_STRUCT_P. + + * local-alloc.c (memref_referenced_p, case REG): Fix last change. + + * fold-const.c (const_binop): Strip NOPS from both args. + + * regclass.c (regclass): Remove useless cast. + +Tue Jan 16 07:06:03 1996 Paul Eggert + + * cexp.y: General code cleanup in the style of 1995-04-01 change. + Add prototypes for static functions. + Add parentheses suggested by `gcc -Wparentheses'. + Use `long' uniformly, instead of long, int, HOST_WIDE_INT mess. + (struct constant): Use `signedp' flag (with sign bit) instead of + `unsignedp' flag; it's a little more convenient. + + (HAVE_STDLIB_H, STDC_HEADERS, LONG_MASK, __attribute__, PROTO, + VA_START, PRINTF_ALIST, PRINTF_DCL, PRINTF_PROTO, PRINTF_PROTO_1, + vfprintf, SIGNED, UNSIGNED): New symbols. + : Include if HAVE_STDLIB_H. + : New include. + (HOST_BITS_PER_WIDE_INT, HOST_WIDE_INT): Remove. + (yylex, yyerror, expression_value, parse_number, + initialize_random_junk): Now static. + + (overflow_sum_sign): Renamed from possible_sum_sign, with an + extra arg SIGNEDP. + (parse_number): Inline strcmp when checking for "0x". + (yylex): Keep track of mask needed when decoding wide characters. + (parse_escape): New arg RESULT_MASK; use it instead of + assuming char width. + (yylex, parse_escape, parse_c_expression): Store all host + integers as long, not int or HOST_WIDE_INT. + (left_shift): No need to do signed left shifts separately. + + These changes are for the test program (if TEST_EXP_READER): + (pedantic, traditional): Allocate storage. + (main): Set pedantic, traditional, yydebug depending on args. + (is_hor_space, warning, lookup): Change types and implementation + to match rest of program. + (pedwarn, check_assertion, xmalloc): New functions. + + * cccp.c (HOST_BITS_PER_WIDE_INT, HOST_WIDE_INT): Remove. + (parse_escape, parse_c_expression, eval_if_expression): + Change return type to `long'; all callers changed. + (pcfinclude): Use `int', not HOST_WIDE_INT; any integral type will do. + + * cccp.c (skip_quoted_string): If pedantic and not pedantic_errors, + skipped multiline strings elicit a warning, not an error. + (rescan): Minor code reorg to keep it parallel with skip_quoted_string. + + * fold-const.c (left_shift_overflows): Remove; unused. + + * c-typeck.c (convert_for_assignment): Don't automatically convert + from a union member to the union. + +Tue Jan 16 06:26:00 1996 Stefan Vogel (stefan@ssw.de) + + * config/svr4.h (ASM_OUTPUT_SECTION_NAME): Define section attributes + only when a section is defined the first time. + +Tue Jan 16 06:03:27 1996 Thomas Graichen + + * i386/freebsd.h (ASM_WEAKEN_LABEL): Deleted; not supported. + +Mon Jan 15 20:59:49 1996 J. Kean Johnston + + * Makefile.in (LIBGCC2_CLFAGS): Add -DIN_LIBGCC2. + (libgcc1.a): Add -DIN_LIBGCC1. + (stamp-crtS): Remove -fpic, use CRTSTUFF_CFLAGS_S. + * config/t-libc-ok: Add CRTSTUFF_CFLAGS_S. + + * configure (i[3456]86-*-sco3.2v5*): New case. + * i386/sco5.h, i386/t-sco5, i386/x-sco5, i386/xm-sco5.h: New files. + * ginclude/stdarg.h, ginclude/varags.h: Add test for SCO Open Server 5. + +Mon Jan 15 20:44:13 1996 J.T. Conklin + + * m68k/netbsd.h (ASM_SPEC): New macro. + +Mon Jan 15 17:01:16 1996 Doug Evans + + * c-lex.c (check_newline): Pass character after `#pragma' to + HANDLE_PRAGMA. Don't call get_directive_line if at end of line. + * c-common.c (get_directive_line): Watch for EOF. + * h8300.h (HANDLE_PRAGMA): New argument `c'. + Must issue `return' now. + * i960.h (HANDLE_PRAGMA): Likewise. + * sh.h (HANDLE_PRAGMA): Likewise. + * nextstep.h (HANDLE_PRAGMA): Likewise. + * h8300.c (handle_pragma): New argument `ch'. + Simplify pragma processing. Delete support for `#pragma section'. + * i960.c (process_pragma): New argument `c'. Change result to + terminating character. + * nextstep.c (handle_pragma): Likewise. + * sh.c (handle_pragma): Likewise. Also simplified. + + * sched.c (reemit_notes): Add prototype. + (sched_analyze_2): Reorganize comments. Call prev_nonnote_insn. + (sched_analyze): Add abort call. + (schedule_block): Call prev_nonnote_insn. + Move call of reemit_notes to after SCHED_GROUP_P scheduling. + Set `head' to `last'. + +Mon Jan 15 16:12:25 1996 Roland McGrath + + * configure (*-*-gnu*): Use tmake_file=t-gnu. + * config/t-gnu (CRTSTUFF_T_CFLAGS): New file. + * configure (*-*-gnu*): Remove crtbeginS.o and crtendS.o frmo + $extra_parts. Use xmake_file=x-linux. + +Mon Jan 15 15:30:49 1996 Gran Uddeborg + + * i386/svr3{,z}.ifile: Allocate address areas for the "stab" + and "stabstr" sections. + +Mon Jan 15 14:39:14 1996 Paul Eggert + + * c-decl.c (finish_incomplete_decl): Warn if completing an + array that wasn't declared extern. Simplify test for whether + completion is needed. + + * cccp.c (do_xifdef): Warn about `#ifdef 0' if not traditional; + formerly the warning was issued if not pedantic. + +Mon Jan 15 13:24:12 1996 Michael Meissner + + * rs6000.md ({add,sub}di3): Make it work on little endian PowerPC + systems. + + * rs6000/eabi-c{i,n}.asm (.sbss2 section): Don't make .sbss2 a + .bss section just yet, because it confused the linker. + +Mon Jan 15 08:50:31 1996 Philippe De Muyter (phdm@info.ucl.ac.be) + + * m68k.md (pushdi): Allow "i" for operand 1. + (extendqidi2): Improve 68000 code generation. + (adddi_lshrdi_63): New pattern. + +Mon Jan 15 08:38:40 1996 H.J. Lu {hjl@gnu.ai.mit.edu) + + * configure (i[3456]86-*-linux*): Add extra_parts. + * i386/linux.h (LIB_SPEC): Remove %{mieee-fp:-lieee}. + Use -lc_p for -profile. + (CC1_SPEC): New macro. + * linux.h (STARTFILE_SPEC): Use crtbegin.o for both shared llibrary + and normal executable; use gcrt1.o for -profile. + (ENDFILE_SPEC): Use crtend.o for shared llibrary and normal executable. + * x-linux (INSTALL_ASSERT_H): Unset it. + * configure (i[3456]86-*-linux*oldld*): Set xmake_file to x-linux-aout. + (i[3456]86-*-linux*aout*): Likewise. + * x-linux-aout: New file, copied from config/x-linux. + +Mon Jan 15 07:41:05 1996 Dmitry K. Butskoy (buc@stu.spb.su) + + * varasm.c (in_data_section): New function. + +Mon Jan 15 07:37:13 1996 Andreas Schwab (schwab@issan.informatik.uni-dortmund.de) + + * c-typeck.c (build_c_cast): Don't warn about alignment when we + have an opaque type. + +Mon Jan 15 07:22:59 1996 Michel Delval (mfd@ccv.fr) + + * reload.c (find_equiv_reg): Apply single_set, not PATTERN, to WHERE. + +Mon Jan 15 07:02:21 1996 John F. Carr + + * reorg.c (mark_referenced_resources, case TRAP_IF): Set volatil. + +Mon Jan 15 06:20:38 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * gcc.c (process_commands): Remove inadvertant fallthrough. + + * function.c ({,round_}trampoline_address): TRAMPOLINE_ALIGNMENT is + in bits, not bytes. + + * objc/archive.c (objc_{write,read}_type, case _C_STRUCT_B): Fix typo. + + * expr.c (expand_expr, case COMPONENT_REF): Don't make recursive + call on object with EXPAND_SUM. + + * stmt.c (save_expr_regs): Delete declaration; unused. + +Sun Jan 14 21:44:26 1996 Michael Meissner + + * rs6000/eabi-ci.asm (__EXCEPT_START__): Provide label for start + of g++ exception pointers. + + * rs6000/eabi-cn.asm (__EXCEPT_END__): Provide label for end of + g++ exception pointers. + + * rs6000/eabi.asm (__eabi): Relocate exception pointers unless + they are NULL. + + * va-ppc.h (va_arg): Long longs are always passed in odd registers. + + * rs6000.c (function_arg_boundary): On V.4, long longs are always + passed in odd registers. + + * rs6000.md ({add,sub}di3): Remove restriction for POWER only, + since all of the instructions used are common to both + architectures. + +Sun Jan 14 20:34:03 1996 Jeffrey A. Law + + * expr.c (expand_assignment): Fix alignment parm in emit_block_move. + +Sun Jan 14 19:00:25 1996 Jim Wilson + + * sched.c (schedule_block): Copy RTX_INTEGRATE_P bit when create + a new note. + + * integrate.c (save_for_inline_copying, case NOTE): Copy + RTX_INTEGRATED_P bit. + +Sun Jan 14 17:57:52 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * stupid.c (stupid_find_reg): Don't try to allocate reg if live + over more than 5,000 insns. + +Sat Jan 13 23:09:07 1996 Jeffrey A. Law + + * pa.h (STACK_BOUNDARY): Bring back down to 64bits. + + * pa.md (pre_ldwm): Fix bug exposed by recent changes. + Simplify. + (pre_stwm, post_ldwm, post_stwm): Likewise. + (HImode and QImode variants): Likewise. + * pa.c (hppa_expand_prologue): Corresponding changes. + (hppa_expand_epilogue): Likewise. + + * pa.c (hppa_legitimize_address): Generate more indexing + address modes. + +Fri Jan 12 19:03:21 1996 Doug Evans + + * sparc/sol2.h (COMMON_ASM_OP): Delete, use sysv4.h's. + + * sched.c (schedule_block): Maintain a valid chain so + emit_note_before works. + +Fri Jan 12 13:20:01 1996 Michael Meissner + + * rs6000/eabi{,-ci,-cn}.asm: Add support for V.4 .sbss/.sdata, and + eabi .sbss2/.sdata2 sections, loading up r13 and r2 respectively + if the sections were used, and we don't need to relocate the + pointers. + +Thu Jan 11 19:41:07 1996 Per Bothner + + * sparc.h (FUNCTION_ARG_PASS_BY_REFERENCE): Use AGGREGATE_TYPE_P so + QUAL_UNION_TYPE and SET_TYPE are also passed by invisible reference. + * sparc.h (INIT_CUMULATIVE_ARGS for SPARCV9): Return types of + QUAL_UNION_TYPE and SET_TYPE also make invisible 1st argument. + +Thu Jan 11 18:33:50 1996 Doug Evans + + * h8300.h (TARGET_ALIGN_STRUCT_300): New macro. + (TARGET_SWITCHES): Add -malign-struct-300. + (BIGGEST_FIELD_ALIGNMENT): Update. + +Thu Jan 11 12:07:44 1996 J.T. Conklin + + * h8300.h (CPP_PREDEFINES): Delete -D_DOUBLE_IS_32BITS. + +Thu Jan 11 11:09:33 1996 David Edelsohn + + * rs6000.md (mulsf3 !POWERPC): Use dmul attribute. + (divsf3 !POWERPC): Use ddiv attribute. + +Thu Jan 11 11:09:33 1996 Michael Meissner + + * rs6000/eabi-ctors.c (__do_global_ctors): If global variable + __atexit is non-NULL, call it with __do_global_dtors address to + register the function to run destructors. + (__do_global_{c,d}tors): Guard against NULL pointers. + + * rs6000/eabi.asm (__eabi): If the __eabi function was already + called, do nothing. + +Thu Jan 11 11:29:09 1996 Doug Evans + + * fixincludes: Wrap rpc/types.h in extern "C", for osf2.0. + +Wed Jan 10 13:16:03 1996 Doug Evans + + * varasm.c (variable_section): New function. + (assemble_variable): Call it. + +Wed Jan 10 11:27:28 1996 Michael Meissner + + * rs6000/eabi-c{i,n}.asm (__DTOR_{LIST,END}__): Fix typo. + * rs6000/eabi{,sim}.h ({START,END}FILE_SPEC): Add %s to object + files. + + * rs6000/t-{eabi,eabigas,ppc,ppcgas} (MULTILIB_MATCHES): Drop + support for obsolete -mcpu=mpc403. + Add -mcpu=821 and -mcpu=860 to soft-float defaults. + + * rs6000/t-eabi{,gas} (LIBGCC): Add stmp-crt. + (INSTALL_LIBGCC): Add install-crt. + (EXTRA_PARTS): Delete. + (stmp-crt{,-sub}): New rules to build crti.o and crtn.o in a + multilib fashion. + (install-crt): Install the multilib crt values. + +Tue Jan 9 17:30:16 1996 Doug Evans + + * c-tree.h (merge_attributes): Moved from here. + * tree.h (merge_attributes): To here. + * c-typeck.c (merge_attributes): Moved from here. + * tree.c (merge_attributes): To here. + +Mon Jan 8 18:27:38 1996 Arne H. Juul + + * mips/netbsd.h (LINK_SPEC): Change nostdlib to nostartfiles. + (LOCAL_LABEL_PREFIX): Delete. + (ASM_OUTPUT_SECTION_NAME): Define. + +Sun Jan 7 17:11:11 1996 David Edelsohn + + * collect2.c (scan_libraries): Correct Import File ID interpretation. + +Sun Jan 7 16:56:56 1996 Michael Meissner + + * {svr4,mips/elf{,64}}.h (MAX_OFILE_ALIGNMENT): Define as 32768*8. + +Sat Jan 6 15:52:36 1996 Doug Evans + + * a29k/vx29k.h (CPP_SPEC): Define. + + * configure: Recognize any --with/--without option. + + * Makefile.in (MAKEINFOFLAGS): New variable. + (cpp.info,gcc.info): Use it. + + * sparc/t-sol2 (crt1.o,crti.o,crtn.o,gcrt1.o): Use $(GCC_FOR_TARGET). + * i386/t-sol2 (crt1.o,crti.o,crtn.o): Likewise. + +Fri Jan 5 10:44:25 1996 Michael Meissner + + * rs6000/aix{3newas,41}.h ({ASM,CPP}_SPEC): Update for new + processors. + * rs6000/eabi{aix,le}.h ({ASM,CPP}_SPEC): Ditto. + * rs6000/{lynx,netware,powerpc,sysv4}.h ({ASM,CPP}_SPEC): Ditto. + + * rs6000.c (rs6000_override_options): Remove requirement that + -mcpu=common be big endian. + (rs6000_stack_info): If NAME__main is defined, mark this function + as doing a call, even if there are no arguments. + + * rs6000.md (SI*SI->DI splitters): Add reload_completed + condition. + (mulsidi3): If big endian, do move directly, rather than moving by + pieces. + + * rs6000/eabi{,sim}.h (STARTFILE_SPEC): Add crti.o before any + other objects. + (ENDFILE_SPEC): Add crtn.o after any objects. + * rs6000/t-eabi{,gas}: Build crt{i,n}.o from eabi-crt{i,n}.asm. + * rs6000/eabi-crt{i,n}.asm: New files to provide begin/end labels + for all special sections used by eabi as opposed to relying on GLD + to set all of these symbols. + * rs6000/eabi.asm (__eabi): Change to use the new labels provided + above. Don't assume that the .got2, .ctors, .dtors, and .fixup + sections are contiguous. + +Fri Jan 5 10:40:37 1996 David Edelsohn + + * rs6000.md (mulh_call): Remove r4 clobber. + (quoss_call): Remove cr0 and cr1 clobbers. + + * rs6000.md (function units): Add MPC505/821/860 support. + (SF multiply add combiner patterns): Use dmul attribute when limited + to DFmode POWER instructions. + * rs6000.c (processor_target_table): Add MPC505/821/860 support. + Remove MASK_POWER and add MASK_PPC_GFXOPT for PPC602. Always use + new mnemonics for common mode. + (rs6000_override_options): Don't set SOFT_FLOAT based upon + PROCESSOR_DEFAULT. + * rs6000.h (processor_type): Add PROCESSOR_MPCCORE. + (RTX_COSTS): Add PROCESSOR_MPCCORE cases. + (CPP_SPEC): Add new processor support. + +Fri Jan 5 00:32:49 1996 Doug Evans + + * sparc.h (MACHINE_STATE_RESTORE): Add missing .align. + +Wed Jan 3 18:29:32 1996 Doug Evans + + * arm/lib1funcs.asm (__USER_LABEL_PREFIX__): Define if not already. + (CONCAT1,CONCAT2,SYM): Define. + (__udivsi3,__divsi3,__umodsi3,__modsi3,__div0): Use SYM to define + global labels. + +Wed Jan 3 02:41:39 1996 Jeffrey A. Law + + * pa.h (DBX_OUTPUT_MAIN_SOURCE_FILE_END): Call text_section. + +Tue Jan 2 16:12:13 1996 Jim Wilson + + * sh.c (gen_shifty_op): Output a NOP for a shift by 0. + (find_barrier): New variables si_limit, hi_limit. Set them depending + on whether we are optimizing. Set found_hi if the destination is + HImode. + (machine_dependent_reorg): If not optimizing, then change scan to a + note instead of calling delete_insn. + * sh.h (OVERRIDE_OPTIONS): Don't set optimize or flag_delayed_branch. + + * dbxout.c (gstab.h): Include if cross compiling. + +Mon Jan 1 21:13:43 1996 Arkady Tunik + + * configure (i[3456]-*-solaris2*): Support stabs. + * i386/sol2dbg.h: New file. + +Mon Jan 1 09:08:01 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * c-typeck.c: Use DECL_C_BIT_FIELD, not DECL_BIT_FIELD in all tests. + + * global.c (reg_allocno): No longer static. + * reload1.c (reg_allocno): Declare. + (order_regs_for_reload): New arg, GLOBAL. + Bias against regs allocated in local-alloc. + (reload): Pass new parm to order_regs_for_reload. + + * local-alloc.c (reg_equiv_replacement): New variable. + (memref_referenced_p, case REG): Check for reg_equiv_replacement. + (update_equiv_regs): reg_equiv_replacement now file-scope. + + * c-decl.c (finish_struct): Warn if field with enumeral type is + narrower than values of that type. + + * combine.c (rtx_equal_for_field_assignment_p): New function. + (make_field_assignment): Use it. + Expand compound operations on both sides of an IOR. + Properly adjust constand in IOR when computing bit position. + +Sun Dec 31 18:47:22 1995 Doug Evans + + * m68k-none.h (MULTILIB_DEFAULTS): Define. + +Sun Dec 31 15:47:20 1995 Jeffrey A. Law + + * hard-reg-set.h (losing_caller_save_reg_set): Declare. + * regclass.c (losing_caller_save_reg_set): Define. + (init_reg_sets_1): Initialize losing_caller_save_reg_set. + * global.c (find_reg): Avoid caller-saving registers in + losing_caller_save_reg_set. + * local-alloc.c (find_free_reg): Avoid caller-saving registers + in losing_caller_save_reg_set. + (CLASS_LIKELY_SPILLED_P): Delete definition. Moved into regs.h. + * regs.h (CLASS_LIKELY_SPILLED_P): Define if not already defined. + + * reorg.c (fill_simple_delay_slots): Try to fill from the + target of an unconditional branch if necessary. + + * pa.h (REG_ALLOC_ORDER): Allocate PA1.1 caller-saved FP regs + before PA1.0 caller-saved FP regs. + + * sched.c (adjust_priority): Use ADJUST_PRIORITY if its defined. + + * pa.h (ADJUST_PRIORITY): Define to keep lifetimes of registers + that will be allocated to %r1 shorter. + +Sun Dec 31 14:20:49 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * rtl.h (assign_temp): Add extra arg. + * function.c (assign_temp): Add extra arg, DONT_PROMOTE. + Don't return (const_int 0) for VOIDmode. + * stmt.c (expand_asm_operands): Call assign_temp with extra arg. + * expr.c (save_nocopied_parts, expand_expr): Likewise. + (expand_expr, case SAVE_EXPR): Set TEMP to (const_int 0) + if MODE is VOIDmode. + (expand_expr): Don't use assign_temp for pseudos when might + want to be TMODE. + + * stmt.c (tail_recursion_args): Compare TYPE_MAIN_VARIANTs. + + * calls.c (expand_call): Don't warn about not being able to + inline if -O0. + * expr.c (clear_pending_stack_adjust): Don't do optimization if -O0. + * function.c (instantiate_decls): Check DECL_SAVED_INSNS to see + if obstack change is needed. + * toplev.c (rest_of_compilation): Leave DECL_INLINE set even if + won't inline. + + * tree.h: Add documentation on uses of common area flags. + (DECL_ERROR_ISSUED): New macro. + (DECL_NO_STATIC_CHAIN): New macro; currently unused. + * c-aux-info.c (gen_decl): DECL_REGISTER isn't defined + for FUNCTION_DECL. + * toplev.c (compile_file): Likewise. + * stmt.c (fixup_gotos): Use DECL_ERROR_ISSUED instead + of DECL_REGISTER. + * varasm.c ({bc_,}make_decl_rtl): Don't look at DECL_REGISTER + for functions. + +Sat Dec 30 07:57:11 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * sdbout.c (plain_type_1, case ARRAY_TYPE): Subtract lower bound + when writing dimension. + +Fri Dec 29 18:23:58 1995 Paul Eggert + + * cccp.c (eval_if_expression): End expression with '\n', not '\0' + so '\0' can be diagnosed properly. + * cexp.y (yylex, parse_c_expression, main): Likewise. + +Thu Dec 28 18:24:54 1995 Per Bothner + + * tree.h (TYPE_ARRAY_MAX_SIZE): New macro (used by Chill). + * function.c (assign_temp): New function. Can handle Chill-style + variable-sized array with static maximum size. + * rtl.h (assign_temp): New declaration. + * stmt.c (expand_asm_operands): Use new assign_temp function. + * expr.c (save_noncopied_parts, expand_expr): Likewise. + +Thu Dec 28 15:28:47 1995 Per Bothner + + * function.c (assign_parms): Fix thinko for struct value arg. + +Fri Dec 29 12:41:47 1995 Michael Meissner + + * rs6000.md (movdf): Reinstate 12/24 change accidently dropped in + undoing 12/27 changes. + +Thu Dec 28 22:24:53 1995 Michael Meissner + + * rs6000.h: (reg_class): Undo 12/27 changes, except for formatting. + (REG_NAMES, REG_CLASS_CONTENTS, REGNO_REG_CLASS): Likewise. + (REG_CLASS_FROM_LETTER): Likewie. + (PREDICATE_CODES): Delete predicate functions. + (gpc_reg{0,3,4,34}_operand): Delete declaration. + (cc_reg{0,1}_operand): Likewise. + * rs6000.c (gpc_reg{0,3,4}_operand): Delete. + (cc_reg{0,1}_operand): Likewise. + + * rs6000.md (common mode functions): Undo 12/27 changes,and add + appropriate clobbers for common mode calls. Keep define_splits for + powerpc SI*SI->DI. + +Thu Dec 28 11:08:11 1995 Mike Stump + + * sparc.h (RETURN_ADDR_OFFSET): Rename from NORMAL_RETURN_ADDR_OFFSET; + returns offset for the current function specifically. + +Thu Dec 28 07:07:14 1995 Paul Eggert + + * c-lex.c (yylex): Improve error message for bogus numbers. + Consolidate duplicated code. + + * cexp.y (parse_number): Improve error message for bogus numbers. + (yylex): Consider `0xe-1' to be a (bogus) number if not traditional. + + * cccp.c (do_include): In VMS, worry only about EACCES when open fails. + (new_include_prefix): Don't try to stat dir prefixes in VMS. + +Wed Dec 27 14:02:54 1995 Per Bothner + + * fix-header.c: Add EXIT_FAILURE and EXIT_SUCCESS to stdlib.h if + missing. Re-write how errno is added to be done similarly. + (XOPEN_SYMBOL, XOPEN_EXTENDED_SYMBOL): New macros, to mark XPG4 + functions. + (std_include_table): Add a number of functions (mostly XPG4). + +Tue Dec 26 23:18:34 1995 Per Bothner + + * sys-types.h: Add dummy definition for ssize_t. + * sys-protos.h (bcmp, bcopy, gethostname, lockf, read, readlink, + write): Fix prototypes to match Posix and XPG4. + (socket, strcasecmp, strncasecmp): New prototypes (from XPG4). + +Wed Dec 27 15:30:04 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * libgcc2.c (_bb_init_prg): Cast arg to bzero to (char *). + + * regs.h (reg_rtx_no, regno_pointer_{flag_length,align): New decls. + (REGNO_POINTER_ALIGN): New macro. + * emit-rtl.c (regno_pointer_align): New variable. + (gen_reg_rtx): Extend regno_pointer_align table. + Allocate tables in saveable obstack. + (mark_reg_pointer): New arg, ALIGN. + (gen_inline_header): New args for reg info. + (set_new_first_and_last_insn): Set cur_insn_uid. + ({save,restore}_emit_status): Save and restore regno_pointer_align. + (restore_reg_data{,_1}): Deleted. + (init_emit): Allocate register tables in saveable obstack. + Set REGNO_POINTER_ALIGN for regs pointing into frame. + * function.c (assign_parms): Set REGNO_POINTER_ALIGN for + parms that are pointers. + * function.h (struct function): New field regno_pointer_align. + * expr.c (expand_expr, case VAR_DECL): Set REGNO_POINTER_ALIGN + when copying address into memory. + (expand_expr, case COMPONENT_REF, case ADDR_EXPR): Set alignment + of register when result or result's address. + (expand_expr, case CONVERT_EXPR): Don't handle -fforce-mem here. + * combine.c (set_nonzero_bits_and_sign_copies): Handle reg even + if only set once and in one basic block. + (nonzero_bits, case REG): Use REGNO_POINTER_ALIGN instead of + explicit alignment of registers pointing into frame. + * stmt.c (expand_decl): Set alignment of register for pointer + variable. + * optabs.c (emit_unop_insn): Don't do -fforce-mem for SIGN_EXTEND. + * cse.c (find_best_addr): Make sure folded address better before using. + * rtl.h (INLINE_REGNO_{RTX,POINTER_FLAG,POINTER_ALIGN}): New macros. + (gen_inline_header): Add three new parms. + * rtl.def (INLINE_HEADER): Add three new fields. + * integrate.c: Include regs.h. + (initialize_for_inline): Pass additional args to gen_inline_header. + (save_for_inline_copying): Make new regno_reg_rtx, regno_pointer_flag, + and regno_pointer_align arrays. + (expand_inline_function): Set alignment of reg for parm if passed + by hidden pointer. + Set regno_pointer_{flag,align} into remap table. + (copy_rtx_and_substitute): Set alignment of pointers into + stack frame. + Copy pointer flag and alignment to regs that are copies of + pointer registers from the original regs. + (output_inline_function): Don't call restore_reg_data. + Restore reg_rtx_no, regno_{reg_rtx,pointer_flag,pointer_align}. + * integrate.h (struct inline_remap): New fields regno_pointer_flag + and regno_pointer_align. + * unroll.c (unroll_loop): Set regno_pointer_{flag,align} in + remap table. + * explow.c (memory_address, allocate_dynamic_stack_space): + Pass additional arg to mark_reg_pointer. + * Makefile.in (integrate.o): Includes regs.h. + + * alpha.c ({non,}aligned_memory_operand): Test REGNO_POINTER_ALIGN. + (reg_or_unaligned_mem_operand): New function. + (get_unaligned_address): Add new arg, EXTRA_OFFSET. + * alpha.h ({CONSTANT,DATA}_ALIGNMENT): Align to at least BITS_PER_WORD. + (PREDICATE_CODES): Add reg_or_unaligned_mem_operand. + * alpha.md (extend{qihi,qisi,hisi}2): Allow unaligned memory + as arg 1 and pass to extend_{q,h}idi2. + (unaligned_extend{q,h}idi): New patterns. + (extend{q,h}idi2): If unaligned memory, call above new patterns. + (ext{q,l,w}h recognizer): Update to proper RTL. + (ext define_split): Comment out for now; wrong and maybe useless. + (unaligned_{load,store}hi): Do similarly to QImode. + (movhi, reload_{in,out}hi): Call unaligned case differently. + +Wed Dec 27 11:38:20 1995 Michael Meissner + + * rs6000.md (mulsidi3{,_common}): Undo previous change using + register classes instead of fixed registers for SI*SI->DI common + mode multiplies. + + * rs6000.c (gpc_reg34_operand): Delete unused function. + * rs6000.h (gpc_reg34_operand): Likewise. + + * rs6000.c (gpc_reg{3,4}_operand): Reorganize code and don't allow + SUBREG's. + + * rs6000.c (rs6000_override_options): Do not allow -mcpu=common on + little endian PowerPC's. + (gpc_reg{0,3,4,34}_operand): New functions to match a specific + register. + (cc_reg{0,1}_operand): Likewise. + + * rs6000.h (reg_class): Add register classes for register 3 by + itself, register 4 by itself, registers 3&4, and CR1. + (REG_NAMES): Add support for new register classes. + (REG_CLASS_CONTENTS, REGNO_REG_CLASS, REG_CLASS_FROM_LETTER): Likewise. + (PREDICATE_CODES): Add new predicate functions. + (gpc_reg{0,3,4,34}_operand): Add declaration. + (cc_reg{0,1}_operand): Likewise. + + * rs6000.md (common mode multiplication/division): Move/rename common + mode calls so they are closer to define_expands that call them. + Set attribute type to be jmpreg, rather than integer, so optimizer + knows branch processing unit is used; make SI*SI->DI multiplier use + register classes instead of hardwired registers. + Add appropriate clobbers of CR0/CR1 as mandated by PowerOpen spec. + (PowerPC SI*SI->DI multipliers): Add appropriate define_splits. + + * rs6000/t-{,x}newas (MULTILIB*): Don't build power2 or 601 + specific libraries. + +Tue Dec 26 21:52:18 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * fold-const.c (fold_convert): When converting a NaN to + another type, change the type of the node before returning it. + +Mon Dec 25 17:12:10 1995 Richard Kenner + + * c-typeck.c (mark_addressable): Fix error in last change. + +Sun Dec 24 22:19:49 1995 Jeffrey A. Law + + * pa.c (output_function_epilogue): Use assemble_integer rather + than calling ASM_OUTPUT_INT directly. + * pa.h (ASM_OUTPUT_INT): Use labels for everything in the + exception table section. + + * pa.c (print_operand): Don't call fprintf to output a register + name. Use fputs instead. + + * pa.h (ASM_OUTPUT_FUNCTION_PREFIX): Strip any name encoding + on the section name. + +Sun Dec 24 17:46:03 1995 Markus Theissinger + + * toplev.c (main): Add -ax option. + * gcc.c (struct compilers): Likewise. + * final.c (end_final): Extended header increased to 11 words. + (profile_after_prologue): FUNCTION_BLOCK_PROFILER uses + count_basic_blocks instead of profile_label_no. + + * libgcc2.c (struct bb): Add flags field. + (HAVE_POPEN): Test new define. + (struct __bb, struct bb_{edge,func}): New structs. + (__bb_init_{prg,file},__bb_{init,exit}_trace_func,__bb_trace_ret, + (__bb_trace_func{,_ret},gopen,gclose): New functions. + + * sparc.h, i386.h, m68k.h (FUNCTION_BLOCK_PROFILER, BLOCK_PROFILER): + Extension for -ax option (profile_block_flag == 2). + (MACHINE_STATE_SAVE,MACHINE_STATE_RESTORE): New macros. + (FUNCTION_BLOCK_PROFILER_EXIT): New macro. + * sparc.c (output_function_epilogue), i386.c (function_epilogue): + Use FUNCTION_BLOCK_PROFILER_EXIT. + * m68k.c (output_function_epilogue): Likewise. + * xm-sparc.h: Define HAVE_POPEN. + +Sun Dec 24 06:50:30 1995 Barrett Richardson (barrett@iglou.com) + + * floatlib.c (__divdf3): Rewrite to do software divide of two + doubles instead of using __divsf3. + +Sun Dec 24 06:38:15 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * rs6000.md (movdf): Don't copy a word at a time; nearly always loses. + + * c-tree.h (DECL_C_BIT_FIELD): New macro. + * c-decl.c (finish_struct): Set it when set DECL_BIT_FIELD. + * c-typeck.c (mark_addressable, case COMPONENT_REF): + Give error if taking address of a bit field. + + * gcc.c (unused_prefix_warning): Include machine_suffix if + require_machine_suffix. + (warn_B, warn_std, warn_std_ptr): New variables. + (process_commands): Use them and NULL_PTR as WARN arg to add_prefix. + + * gcc.c (process_command): Give error for -c with -o and + multiple compilations. + (handle_braces): Rename variable "pipe" to "pipe_p". + + * expr.h (clrstr_optab): New declaration. + (clear_storage): New parm, ALIGN. + * tree.h (CONSTRUCTOR_TARGET_CLEARED_P): New macro. + * genopinit.c (optabs): Add "clrstr%a%". + * optabs.c (init_optabs): Initialize clrstr_optab. + * expr.c (struct clear_by_pieces): New structure. + (clear_by_pieces{,_1}, {is,mostly}_zeros_p): New functions. + (clrstr_optab): New optab. + (clear_storage): Rework to try to use clear_by_pieces, then + new clrstr insn, then library call. + (store_constructor): Track if target is already cleared. + Clear target first if CONSTRUCTOR is mostly zeros. + Don't write zeros if target has been cleared. + Add new arg to clear_storage call. + (expand_expr, case CONSTRUCTOR): Don't put static constructor + in memory if mostly zero. + * i386.md (clrstrsi): New pattern and associate anonymous pattern. + +Sat Dec 23 12:21:53 1995 Jeffrey A. Law + + * pa.c (output_move_double): Correctly identify and handle + overlapping moves. + * pa.md (movdi patterns): Eliminate earlyclobbers in mem<->gr cases. + (movdf patterns): Likewise. + +Fri Dec 22 17:29:42 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (store_constructor): Don't call change_address on REG. + (expand_expr, case CONSTRUCTOR): Likewise. + + * mips.c (expand_block_move): Preserve MEM flags in call to + movstrsi_internal. + + * pa.c (emit_move_sequence): Don't try to set REGNO_POINTER_FLAG + for a SUBREG. + + * reload.c (find_valid_class): New function. + (push_reload): Use it in cases where a SUBREG and its contents + both need to be reloaded. + + * toplev.c (rest_of_compilation): Never defer functions that + contain nested functions. + +Fri Dec 22 15:55:00 1995 Michael Meissner + + * rs6000.md (function units): Add 403 support which deleted + by accident on Nov 21st. Mark all compares from 602, 603, 604, + 620, 403, like was done for rios{1,2} and 601 as needing the bpu, + so that compares are hoisted far enough branches for zero cycle + branch support. + +Fri Dec 22 15:13:47 1995 Stan Cox + + * i386.h (TARGET_UNROLL_STRLEN): New macro. + * i386.c (output_strlen_unroll): New function. + * i386.md (strlensi): New pattern. + +Thu Dec 21 18:53:31 1995 Roland McGrath + + * /gnu.h (GNU_CPP_PREDEFINES): Add missing space after -Amachine(CPU). + +Thu Dec 21 12:23:42 1995 Michael Meissner + + * configure ({powerpc,rs6000}*): Change --enable-cpu to --with-cpu. + * rs6000.c (rs6000_select): Likewise. + + * rs6000/aix41.h (LINK_SPEC): Do not pass -bexport to the linker + if -g and -shared. + +Wed Dec 20 11:23:39 1995 Michael Meissner + + * configure ({powerpc,rs6000}-ibm-aix*): Merge these two into the + same case statement. Aix 4 now generates -mcpu=common by default. + ({powerpc,rs6000}*): Add support for --enable-cpu= to + select the default cpu to compile for. + + * rs6000/aix41.h (TARGET_DEFAULT): Make -mcpu=common default behavior. + (PROCESSOR_DEFAULT): Likewise. + (MULTILIB_DEFAULTS): Set mcpu=common. + + * rs6000.h (TARGET_CPU_DEFAULT): Define to be NULL if not defined. + (PROCESSOR_COMMON): Set this to PROCESSOR_601. + (PROCESSOR_POWERPC): Set this to PROCESSOR_604. + (TARGET_OPTIONS): Add -mtune= switch. + (rs6000_select): New structure to hold -mcpu=, -mtune= switches + and the result of configuring --enable-cpu=. + (OVERRIDE_OPTIONS): Pass TARGET_CPU_DEFAULT to + rs6000_override_options. + + * rs6000.c (rs6000_cpu_string): Delete global variable. + (rs6000_select): Define new global variable. + (rs6000_override_options): Take default_cpu argument, and provide + support for it and -mtune= in addition to -mcpu=. + + * rs6000/{aix{3newas,41},lynx,netware,powerpc}.h (ASM_SPEC): Add + support for -mcpu=power2. + * rs6000/{rs6000,sysv4}.h (ASM_SPEC): Likewise. + + * rs6000/{aix41,eabiaix,eabile,lynx,powerpc}.h (CPP_SPEC): Make + sure all -mcpu=xxx targets are supports. + * rs6000/{rs6000,sysv4,sysv4le}.h (CPP_SPEC): Likewise. + + * rs6000/t-x{newas,rs6000}: New files to be used when making a + cross compiler, to prevent libgcc1-test from being made. + + * rs6000/t-{x,}newas (MULTILIB_*): Build multlilib libraries for + power, power2, 601, powerpc, and common mode processors. + + * rs6000/aix41ppc.h: Delete, no longer used. + +Tue Dec 19 18:31:21 1995 Jim Wilson + + * mips.c (mips_reg_names, mips_sw_reg_names, mips_regno_to_class): + Add entry for new RAP reg. + * mips.h (FIRST_PSEUDO_REGISTER): Increment. + (FIXED_REGISTERS, CALL_USED_REGISTERS, REGISTER_NAMES, + DEBUG_REGISTER_NAMES): Add entry for new RAP reg. + (RAP_REG_NUM, RETURN_ADDRESS_POINTER_REGNUM): New macros. + (RETURN_ADDR_RTX): Define. + (ELIMINABLE_REGS, CAN_ELIMINATE, INITIAL_ELIMINATION_OFFSET): + Add RETURN_ADDRESS_POINTER_REGNUM support. + * emit-rtl.c (return_address_pointer_rtx): New global variable. + (gen_rtx, init_emit_once): Add support for it. + +Tue Dec 19 15:08:31 1995 Jason Merrill + + * collect2.c: Remove auto_export functionality. + +Tue Dec 19 10:57:23 1995 Kim Knuttila + + * ppc-asm.h: Do not compile the register macros under winnt. + +Mon Dec 18 19:31:23 1995 Adam Fedor + + * objc/encoding.c (objc_alignof_type): Handle _C_PTR case. + +Mon Dec 18 18:40:34 1995 Jim Wilson + + * combine.c (simplify_rtx, case SUBREG): For SUBREG of a constant, + use <= instead of < when comparing mode sizes. + (force_to_mode, case NOT): Use full mask inside the NOT operation. + + * expr.c (emit_block_move): When call emit_libary_call for bcopy, + pass arguments using correct types and modes. + (emit_push_insn, expand_assignment): Likewise. + (clear_storage, store_expr): Likewise for memset and bzero. + (store_constructor): Likewise for memset. + * optabs.c (emit_cmp_insn): Likewise for memcmp and bcmp. + * convex.c (expand_movstr_call): Likewise for memcpy. + * m88k.c (expand_block_move): Likewise for memcpy and bcopy. + * mips.c (block_move_call): Likewise for memcpy and bcopy. + * mips.h (INITIALIZE_TRAMPOLINE): Likewise for cacheflush. + + * c-common.c (WCHAR_TYPE_SIZE): Add a default definition. + + * sdbout.c (sdbout_symbol, case FUNCTION_DECL): Use DECL_INITIAL + instead of DECL_EXTERNAL to identify declarations. + + * svr4.h (ASM_IDENTIFY_GCC): Don't output stab here. + (ASM_IDENTIFY_GCC_AFTER_SOURCE): Output stab here instead of above. + + * stmt.c (expand_asm_operands): Handle numeric constraints in + with the default case. + +Mon Dec 18 16:49:43 1995 John F. Carr + + * expr.h (expand_mult_highpart_adjust): Declare. + +Mon Dec 18 16:39:41 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (store_constructor): Fix error in last change: just + copy MEM, but be sure to share address. + (expand_expr, case CONSTRUCTOR): Likewise. + +Mon Dec 18 16:22:46 1995 Michael Meissner + + * rs6000.h (ASM_GENERATE_INTERNAL_LABEL): Put leading '*' in label + string so as to not confuse dbxout.c. + +Mon Dec 18 09:44:56 1995 Mike Stump + + * libgcc2.c (__empty): An empty function used by the C++ frontend for + defaulting cleanup actions. + + * tree.c (save_tree_status, restore_tree_status): Save and restore + temporary_firstobj. + +Mon Dec 18 07:49:34 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * function.c (fixup_var_refs_1): Fix error in last change (when + mode of VAR is not the same as PROMOTED_MODE). + +Sun Dec 17 12:14:37 1995 Jeffrey A. Law + + * pa.h (ASM_OUTPUT_FUNCTION_PREFIX): Don't surround section names + with '$'; that confuses collect2. + (ASM_OUTPUT_SECTION_NAME): Likewise. + + * sched.c (canon_rtx): Recursively look for equivalences; + look for expressions equivalent to MEMs. + (true_dependence): Canonicalize inputs before operating + on their values. + (anti_dependence, output_dependence): Likewise. + + * jump.c (follow_jumps): Don't follow an unconditional jump + that is not a simple_jump. + + * pa.c (override_options): Make 7100 scheduling the default. + + * pa.md: Add 2nd reload peephole somehow omitted from Nov27 changes. + + * regclass.c (regclass): Use SECONDARY_RELOAD_CLASS if it's + defined to avoid useless work. + + * combine.c (find_split_point): Try to split SET_DEST + just like we do for SET_SRC. + +Sun Dec 17 11:37:25 1995 Torbjorn Granlund + + * expmed.c (expand_mult_highpart): When doing widening multiply, + put constant in a register. + (expand_mult_highpart): When mode is word_mode use gen_highpart + instead of right shift by size. + + * expr.c (expand_expr, case MULT_EXPR): Generalize code for widening + multiply to handle signed widening multiply when only unsigned optab + is defined, and vice versa. + +Sun Dec 17 07:35:50 1995 Pat Rankin + + * vax/vms.h (WCHAR_TYPE_SIZE): Define. + +Sun Dec 17 07:08:34 1995 Ronald F. Guilmette . + + * fp-test.c: New file. + +Sun Dec 17 07:06:03 1995 Peter Flass + + * i370.md (cmpqi): Fix generation of literal operand of CLM instruction + to avoid double literals (=X'=F'...). + +Sun Dec 17 06:57:02 1995 Paul Eggert + + * cccp.c: Try harder not to open or stat the same include file twice. + Simplify include file names so that they are more likely to match. + E.g. simplify "./a//b" to "a/b". Represent directories with simplified + prefixes, e.g. replace "./a//b" with "a/b/", and "." with "". + (absolute_filename): New function. + (do_include): Use it. + (read_name_map): Likewise; this makes things more consistent for DOS. + (main, do_include, open_include_file): -M output now contains + operands of -imacros and -include. + (skip_to_end_of_comment): When copying a // comment, don't try to + change it to a /* comment. + (rescan, skip_if_group, skip_to_end_of_comment, macarg1): Tune. + (rescan, skip_if_group, skip_to_end_of_comment, macarg1): + If warn_comments is nonzero, warn if backslash-newline appears + in a // comment. Simplify method for finding /* /* */ comment. + (skip_if_group): Optionally warn if /* /* */ appears between # and + a directive inside a skipped if group. + (macarg): Optionally warn if /* /* */ appears in a macro argument. + (strncat, VMS_strncat, vms_ino_t, ino_t): Remove. + (INCLUDE_LEN_FUDGE): Add 2 if VMS, for trailing ".h". + (INO_T_EQ, INO_T_HASH): New macros. + (struct file_buf): New member `inc'. + (expand_to_temp_buffer): Initialize it. + (struct file_name_list): New member `inc'. + (struct file_name_list): New member `st'. + c_system_include_path is now 1 if not 0. + fname is now an array, not a pointer. + (struct include_file): New members `next_ino', `deps_output', `st'. + Remove members `inode' and `dev'; they are now in `st'. + (INCLUDE_HASHSIZE): Rename from INCLUDE_HASH_SIZE. + (include_hashtab): Rename from include_hash_table. + (include_ino_hashtab): New variable. + (main): Store file status in struct stat, not in long and int pieces. + Use base_name to strip prefixes from file names. + When printing directory prefixes, omit trailing / and print "" as ".". + Fatal error if the input file is a directory. + (main, path_include): Regularize operands of -include, -imacros, + -isystem, -iwithprefix, and -iwithprefixbefore. + Regularize default include directories. + (do_include): + Allocate dsp with alloca, since fname is now dynamically allocated. + Use -3 to represent a never-opened file descriptor. + Make copy of file name, and simplify the copy. + Use base_name to identify the end of fname's directory. + Do not prepend dir for "..." if it matches the search list's first dir. + open_include_file now subsumes redundant_include_p and lookup_import. + Use bypass_slot to remember when to skip directories when including + a file that has already been seen. + Instead of using 0 to represent the working directory, and "" + to represent a directory to be ignored, use "" for the former, + and assume the latter has been removed before we get here. + Assume the directory prefixes have already been simplified. + Report as errors all open failures other than ENOENT. + Fatal error if fstat fails. + Use new deps_output member to avoid printing dependencies twice. + (bypass_hashtab): New variable. + (do_include, open_control_file, record_control_macro): New convention: + control_macro is "" if the file was imported or had #pragma once. + (pragma_once_marker): Remove. + (redundant_include_p, include_hash, lookup_include, lookup_import, + add_import, file_size_and_mode): Remove; subsumed by open_include_file. + (skip_redundant_dir_prefix): Remove; subsumed by simplify_filename. + (is_system_include, read_name_map, remap_include_file): + Assume arg is a directory prefix. + (base_name, simplify_filename, remap_include_file, + lookup_ino_include, new_include_prefix): New functions. + (open_include_file): New arguments `importing' and `pinc'. + Move filename mapping into new remap_include_file function. + First try to find file by name in include_hashtab; + if that doesn't work, open and fstat it and try to find it + by inode and dev in include_ino_hashtab. + (finclude): Get file status from inc->st instead of invoking fstat. + Store inc into fp->inc so that record_control_macro doesn't + need to do a table lookup. + (finclude, record_control_macro): Accept struct include_file * + instead of char * to identify include file. All callers changed. + (check_precompiled): Get file status from new argument `st'. + (do_pragma): Output at most one warning about #pragma implementation. + Always return 0 instead of returning garbage sometimes. + (do_pragma, hack_vms_include_specification): + Use base_name for consistency, and remove redundant code. + + From Per Bothner: + Unify the 3 separate mechanisms for avoiding processing + of redundant include files: #import, #pragma once, and + redundant_include_p to use a single more efficient data structure. + (struct file_name_list): Remove no-longer needed field control_macro. + (dont_repeat_files, all_include_files): Remove, no longer used. + (struct import_file): Renmed to struct include_file, moved earlier + in file, renamed field name to fname, and added control_macro field. + (pragma_once_marker): New constant. + (import_hash_table): Renamed to include_hash_table. + (import_hash): Renamed to include_hash. + (IMPORT_HASH_SIZE): Renamed to INCLUDE_HASH_SIZE. + (main, path_include): Don't clear removed control_macro field. + (lookup_include): New function - look up fname in include_hash_table. + (redundant_include_p): Re-write to use lookup_include. + (lookup_import, record_control_macro): Likewise. + (add_import): Defer fstat to caller. Combine two xmallocs into one. + (do_once): Use pragma_once_marker in include_hash_table. + (do_pragma): Re-implement to scan include_hash_table. + (do_include): Use new lookup_include and add_import. + +Sun Dec 17 06:45:43 1995 John F. Carr + + * configure (savesrcdir): Do not create paths with trailing "/.". + + * combine.c (try_combine): When checking for two sets of the same + register in a split insn, also test for setting a ZERO_EXTRACT, + STRICT_LOW_PART, or SUBREG. + +Sun Dec 17 06:37:00 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * reload.c (push_secondary_reload): Don't strip paradoxical SUBREG + if reload_class is CLASS_CANNOT_CHANGE_SIZE. + +Sat Dec 16 18:24:20 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (expand_assignment): Fix alignment parm in emit_block_move. + +Sat Dec 16 18:16:08 1995 John Hassey (hassey@rtp.dg.com) + + * local-alloc.c (optimize_reg_copy_2): Don't attempt + optimization if destination register dies. + +Sat Dec 16 08:31:16 1995 Paul Eggert + + * fold-const.c (fold): Don't record overflow when negating + unsigned constants. + +Sat Dec 16 07:45:11 1995 Gran Uddeborg (uddeborg@carmen.se) + + * configure (i[3456]-*-isc, gas, stabs): Remove crt* from extra_files + +Sat Dec 16 07:03:33 1995 Philippe De Muyter (phdm@info.ucl.ac.be) + + * stor-layout.c (layout_record): When PCC_BITFIELD_TYPE_MATTERS, + compute bitpos using field_size % type_align instead of field_size. + + * fixincludes (stdio.h): Fix return type of fread and fwrite + on sysV68. + +Sat Dec 16 06:57:14 1995 Thomas Lundqvist (d0thomas@dtek.chalmers.se) + + * function.c (fixup_var_refs_1): Fix two incorrect calls to single_set. + +Fri Dec 15 22:30:27 1995 Torbjorn Granlund + + * i386.h (REGISTER_MOVE_COST): Simplify. + +Fri Dec 15 22:30:27 1995 Stan Cox + + * i386.h (TARGET_CPU_DEFAULT*, PROCESSOR_*, + TARGET_{LEAVE,386_ALIGNMENT,PUSH_MEMORY,ZERO_EXTEND_WITH_AND, + DOUBLE_WITH_ADD,BIT_TEST}): New macros. + * i386.c (ix86_cpu*, ix86_isa*): New global variables. + (override_options): Add -mcpu and -misa support + * i386.md: Use TARGET* macros. + * i386/dgux.{c,h}: New files. + * m88k/t-dgux: (GCC_FOR_TARGET, T_CFLAGS): New macros. + * m88k/t-dguxbcs: New file. + * m88k/x-{dgux,dguxbcs}: (GCC_FOR_TARGET, X_CFLAGS): Removed. + +Fri Dec 15 18:41:50 1995 Philippe De Muyter (phdm@info.ucl.ac.be) + + * fixincludes (sys/wait.h): Add forward declaration of struct rusage + on AIX 3.2.5. + +Fri Dec 15 18:39:36 1995 Marco S Hyman (marc@dumbcat.sf.ca.us) + + * xm-bsd386.h (DONT_DECLARE_SYS_SIGLIST): Defined. + +Fri Dec 15 18:36:42 1995 Gran Uddeborg (uddeborg@carmen.se) + + * i386/svr3dbx.h (DO_GLOBAL_DTORS_BODY): Delete; obsolete. + +Fri Dec 15 18:21:34 1995 Richard Kenner + + * i386/i386iscgas.h, i386/t-iscscodbx: Deleted; long dead. + +Fri Dec 15 10:01:27 1995 Stan Cox + + * configure (target_cpu_default) Set for 486/586/686 + (m88k-dg-dgux) Use t-dguxbcs instead of x-dguxbcs + (i*86*) Change [345] to [3456] + (i[3456]86-dg-dgux) Added + * Makefile.in (out_object_file) Add MAYBE_TARGET_DEFAULT + +Fri Dec 15 08:05:49 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * function.c (init_temp_slots): New function. + (init_function_start): Code moved to new function and called here. + * toplev.c (rest_of_compilation): Call init_temp_slots. + + * expmed.c (store_bit_field): Don't use insv for BLKmode value. + (store_split_bit_field): Set total_bits to BITS_PER_FOR for + BLKmode value. + +Fri Dec 15 06:35:36 1995 David Edelsohn + + * xcoffout.h (DBX_STATIC_BLOCK_END): Use macro arguments. + (xcoff_begin_function_line, xcoff_current_function_file): Remove + unused extern declarations. + (DBX_OUTPUT_MAIN_SOURCE_FILENAME): Use macro argument. + * xcoffout.c (xcoff_begin_function_line): Make static. + (xcoff_inlining): Likewise. + (xcoff_current_function_file): Likewise. + (xcoff_output_standard_types): Remove TARGET_64BIT dependencies from + int and unsigned int. + +Mon Oct 16 12:25:52 1995 Per Bothner + + * fix-header.c: Support different kinds of functions (ANSI and + Posix1). Enable ANSI proptotypes if __STRICT_ANSI__. + (namelist_end): Removed. + (std_include_table): Divide up functions into kinds. + (add_symbols): New function. + (read_scanfile, write_rbrac, main): Use new data structures. + +Thu Dec 14 19:17:12 1995 Torbjorn Granlund + + * rs6000.md (umulsidi3): New pattern. + +Thu Dec 14 18:08:59 1995 Torbjorn Granlund + + * expmed.c (expand_divmod, case TRUNC_DIV_EXPR): Only reject + larger-than-HOST_BITS_PER_WIDE_INT modes for general constants, + not for powers-of-2. + + * i960.md (andsi3): Match op2 with logic_operand, change constraints + accordingly. Output andnot for negative op2. + (iorsi3, xorsi3): Analogous changes. + * i960.c (logic_operand): New function. + (i960_print_operand): Handle code `C'. + * i960.h (PREDICATE_CODES): Add logic_operand. + (CONST_OK_FOR_LETTER_P): Handle `M'. + * i960.md: Move all plain logical patterns together. + * i960.h (SHIFT_COUNT_TRUNCATED): Define as 0 as appropriate. + + * clipper.md (untyped_call): New pattern. + + * m68k.md (ashrsi_31): New pattern. + +Thu Dec 14 17:22:14 1995 Richard Earnshaw (rearnsha@armltd.co.uk) + + * arm.c (output_move_double): Extract DFmode constants using + REAL_VALUE_TO_TARGET_DOUBLE. + +Thu Dec 14 15:05:13 1995 Doug Evans + + * Makefile.in (distclean): Delete float.h. + * configure: Set CROSS_FLOAT_H from float_format. + * config/float-i64.h: New file. + * config/float-i32.h: New file. + * config/float-vax.h: New file. + * arm/cross-float.h: Delete. + * arm/t-semi (CROSS_FLOAT_H): Delete. + +Wed Dec 13 19:16:57 1995 Mike Stump + + * expr.c (expand_expr, case ADDR_EXPR): Ensure op0 isn't QUEUED. + +Wed Dec 13 19:12:21 1995 Paul Eggert + + * gcc.c (my_strerror): Return "cannot access" if errno is 0. + (perror_with_name, pfatal_with_name, perror_exec): Don't assume that + the returned value from my_strerror contains no '%'s. + (sys_nerr): Declare only if HAVE_STRERROR is not defined. + +Wed Dec 13 19:05:47 1995 Alan Modra (alan@spri.levels.unisa.edu.au) + + * Makefile.in (c-parse.y, objc-parse.y): Add warning that file is + automatically generated. + +Wed Dec 13 15:40:30 1995 Mike Stump + + * function.c (identify_blocks): Start with chain of BLOCKs to match + rest of backend (dbxout.c), instead of just one BLOCK. + (reorder_blocks, all_blocks): Likewise. + + * stmt.c (find_loop_tree_blocks): Pass the toplevel list of + blocks, not just the first subblock. + +Wed Dec 13 16:11:18 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expmed.c (expand_divmod): Don't use TARGET if it's the wrong mode. + +Wed Dec 13 15:02:39 1995 Ian Lance Taylor + + * dbxout.c (struct typeinfo): Define. + (typevec): Change to be struct typeinfo *. Change other uses as + appropriate. + (struct dbx_file): Define if DBX_USE_BINCL. + (current_file): New static variable if DBX_USE_BINCL. + (next_file_number): Likewise. + (dbxout_init): If DBX_USE_BINCL, initialize new variables. + (dbxout_start_new_source_file): New function. + (dbxout_resume_previous_source_file): New function. + (dbxout_type_index): New function. + (dbxout_range_type): Use dbxout_type_index. + (dbxout_type): Likewise. If DBX_USE_BINCL, initialize new typevec + fields. + * c-lex.c (check_newline): If DBX_DEBUGGING_INFO and write_symbols + == DBX_DEBUG, call dbxout_start_new_source_file and + dbxout_resume_previous_source_file when appropriate. + * sparc/sunos4.h (DBX_USE_BINCL): Define. + * svr4.h (DBX_USE_BINCL): Define. + +Wed Dec 13 06:52:40 1995 Michael Meissner + + * rs6000/win-nt.h (ASM_OUTPUT_EXTERNAL): Do not emit .extern for + builtin functions. + +Tue Dec 12 15:37:48 1995 David Edelsohn + + * rs6000.c: Replace many uses of fprintf with putc and fputs. + (output_function_profiler): Use more efficient mnemonics, target + dependent mnemonics, asm_fprintf, and reg_names array. + + * rs6000.h: Replace many uses of fprintf with putc and fputs. + + * rs6000.h (INT_TYPE_SIZE): Remove TARGET_64BIT dependency. + (MAX_INT_TYPE_SIZE): Delete. + +Tue Dec 12 13:58:57 1995 Doug Evans + + * t-h8300 (MULTILIB_{OPTIONS,DIRNAMES}): Add -mint32 support. + +Sun Dec 10 18:51:21 1995 Torbjorn Granlund + + * rs6000.md (matcher for neg:SI (geu:SI ..)): Get ppc syntax right. + +Sun Dec 10 08:47:16 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * combine.c (simplify_if_then_else): Convert "a == b ? b : a" to "a". + + * expr.c (expand_expr, case CONSTRUCTOR): If TREE_READONLY, + set RTX_UNCHANGING_P in TARGET. + (expand_expr, case COMPONENT_REF): If result is BLKmode, + use that to access object too. + +Sun Dec 10 01:06:57 1995 Jeffrey A. Law + + * pa.md (millicode delay slot description): Remove reference + to defunct TARGET_MILLICODE_LONG_CALLS. + +Sat Dec 9 18:05:03 1995 Jim Wilson + + * expr.c (expand_expr, case INDIRECT_REF): Correct typo in May 8 + change. + + * sh.h (ADDRESS_COST): Define. + * sh.md (subsi3): Rename to subsi3_internal. Add new define_expand + to handle subtracting a register from a constant. + +Fri Dec 8 19:17:30 1995 Mike Meissner + + * rs6000.c (input_operand): Allow any integer constant, not + just integers that fit in 1 instruction. + +Fri Dec 8 10:45:07 1995 Richard Earnshaw (rearnsha@armltd.co.uk) + + * arm/lib1funcs.asm (RET, RETCOND): Define according to whether we + are compiling for 32 or 26 bit mode. + (all return instructions): Use RET or RETCOND as appropriate. + +Wed Dec 6 06:58:23 1995 Richard Earnshaw (rearnsha@armltd.co.uk) + + * arm.c (arm_gen_constant): New function. + (arm_split_constant): Split most of the functionality into + arm_gen_constant. Try to decide which way of handling the constant + is optimal for the target processor. + + * arm.c (arm_prgmode): New enum. + (target_{cpu,fpe}_name, arm_fast_multiply, arm_arch4): New variables. + (all_procs): New table describing processors and capabilities. + (arm_override_options): New function. + (arm_return_in_memory): New function. + (arm_rtx_costs): Adjust the multiply costs to cope with processors + with fast multiplication instructions. + (output_move_double): Use the ldm/stm variants more efficiently. + Delete cases that can no-longer occur. + (output_return_instruction, output_func_epilogue): Use TARGET_APCS_32, + not TARGET_6 for determining the type of return instruction to emit. + (final_prescan_insn case CALL_INSN): Use TARGET_APCS_32, not TARGET_6 + to determine condition preservation. + * arm.h (CPP_SPEC): Add defines for the cpu type, hard or soft floating + point, and the APCS PC size. + (TARGET_*): Restructure. + (ARM_FLAG_*): Many new definitions for different target options, not + all of which are supported yet. + (TARGET_SWITCHES): Use the ARM_FLAG_* definitions instead of explicit + numbers. + (prog_mode_type): New enum. + (floating_point_type): Split emulated floating point into FP_SOFT[23]. + (OVERRIDE_OPTIONS): Call arm_override_options. + (ARM_CPU_NAME): Default to NULL if not defined by a subtarget. + (BYTES_BIG_ENDIAN): Can now be set as a compilation option. + (RETURN_IN_MEMORY, DEFAULT_PCC_STRUCT_RETURN): New definitions. + (GO_IF_LEGITIMATE_OFFSET): Use different HImode offsets if compiling + for an architecture 4 target. The offsets for floating point + constants are the same as for integers if compiling TARGET_SOFT_FLOAT. + (GO_IF_LEGITIMATE_ADDRESS): Don't allow PRE_INC and POST_DEC if + the size is more than 4 bytes. Restrict the range offsets for DImode; + likewise for DFmode when TARGET_SOFT_FLOAT. + (LEGITIMIZE_ADDRESS): Use symbol_mentioned_p, not LEGITIMATE_CONSTANT_P + to determine if a constant address might be better in a register. + Handle DFmode addresses in the same way as DImode if TARGET_SOFT_FLOAT. + (LOAD_EXTEND_OP): If arm_arch4, then HImode also zero-extends. + * arm.md (attributes): Rearrange order, so that condition clobbering + can be automatically determined for call insns. + (attribute cpu): Add new cpu ARM7. + (attribute type): Add new type MULT. + (attribute prog_mode): New attribute. + (attribute conds): Clobbering of call insns can now be determined + using prog_mode attribute. + (function units "write_buf", "write_blockage"): Model the write buffer + as two function units, so that conflicts are avoided more often. + (funcion unit "core"): New function unit, so that elapsed cycles can + be more accurately determined. + (all anonymous patterns): Add names. + (mulsidi3, umulsidi3): New patterns available with fast multiply + variants. + (all call insns): The conds attribute is now determined automatically. + (zero_extendhisi): Expand for architecture 4 variants if appropriate. + (*zero_extendhisi_insn): New pattern. + (extendqi{hi,si}, extendhisi): Expand for architecture 4 variants if + appropriate. + (*extendhisi_insn, *extendqihi, *extendqisi): New patterns. + (storehi_single_op): New expand. + (movhi): Handle architecture 4 expansion. + (*movhi_insn_arch4): New pattern. + (*movhi_*): Adjust applicability conditions to handle architecture 4. + (reload_outdf): Handle pre/post inc/dec reloads. + (tablejump): Delete. + (matcher for optimized tablejump): delete. + (casesi): New expand. + (casesi_internal): New pattern. + * semi.h (EXIT_BODY): Delete. + (TARGET_DEFAULT): Set to ARM_FLAG_APCS_32. + (CPP_SPEC): Define. + arm/cross-float.h: New file, used when building a cross-compiler. + * t-semi: Don't define inhibit_libc when building libgcc2.a. + (CROSS_FLOAT_H): Define. + + * arm.c ({symbol,label}_mentioned_p): New functions. + (add_constant, dump_table, fixit, find_barrier, broken_move): New + support functions for handling constant spilling. + (arm_reorg): New constant spilling pass, for putting unhandlable + constants into the rtl where we can load them efficiently. + (output_load_symbol): Delete. + * arm.h (SECONDARY_OUTPUT_RELOAD_CLASS): No need to handle floating + point constants any more, since arm_reorg will deal with them. + (LEGITIMATE_CONSTANT_P): Is now anything that doesn't contain a + LABEL. + (GO_IF_LEGITIMATE_ADDRESS): Recognize address expressions generated + by arm_reorg, but only after reload has completed. + (MACHINE_DEPENDENT_REORG): Define. + (ASM_OUTPUT_SPECIAL_POOL_ENTRY): There should be nothing left in + the pool, even if it might look like it. + * arm.md (*movsi_insn): Much simpified now that constants are handled + properly. + (movaddr): New expand. + (movsf, movdf): No need to force constants into the pool any more. + (*movdf_hard_insn): Much simplified. + (consttable_4, consttable_8, consttable_end, align_4): New patterns + for supporting embedded constants. + + * configure: New target arm-semi-aof. + * arm.c (strings_fpa): Use a form which is common to both GAS and + ARMASM. + (output_return_instruction, output_func_epilogue): Call + assemble_external_libcall, before trying to generate an abort call + in the assembler. + (arm_asm_output_label): Call ARM_OUTPUT_LABEL, rather than assuming + that labels are followed by a colon. + (aof_text_section, aof_add_import, aof_delete_import, + aof_dump_imports): New functions to support ARMASM assembler + generation. + * arm/aout.h: New file. + * arm/aof.h: New file. + * arm.h (most assembler-specific defines): Move to arm/aout.h. + (CONSTANT_ADDRESS_P): Can't directly access constant strings when + generating assembler for ARMASM. + (ENCODE_SECTION_INFO): Don't define if generating ARMASM assembler. + (ASM_OUTPUT_INTERNAL_LABEL): Generalize, so that it can be used + with all targeted assemblers. + (ASM_OUTPUT_LABEL): Call arm_asm_output_label. + * riscix.h: Include arm/aout.h, not arm/arm.h. + * riscix1-1.h: Likewise. + * semi.h: Likewise. + * arm/semiaof.h: New file. + * arm/t-semiaof: New file. + +Mon Dec 4 22:17:37 1995 Jason Merrill + + * gcc.c (LIBGCC_SPEC): Do link with libgcc when -shared. + * alpha.h (LIBGCC_SPEC): Remove. + * linux.h (LIBGCC_SPEC): Remove. + * svr4.h (LIBGCC_SPEC): Remove. + * i386/t-crtpic (TARGET_LIBGCC2_CFLAGS): Use -fPIC. + * t-pa (TARGET_LIBGCC2_CFLAGS): Use -fPIC. + * sparc/t-sunos41 (TARGET_LIBGCC2_CFLAGS): Use -fPIC. + * sparc/t-sol2 (TARGET_LIBGCC2_CFLAGS): Use -fPIC. + * configure (i386-linux): Use i386/t-crtpic. + + * i386/xm-sco.h: #define NO_SYS_SIGLIST. + +Mon Dec 4 21:30:37 1995 Jim Wilson + + * sh.c (shiftcosts): For SH3, max cost of arithmetic right shift is 3. + (expand_ashiftrt): For SH3, if shift cost is more than 3, then + call gen_ashrsi3_d to use shad instruction. + +Mon Dec 4 18:29:08 1995 Jason Merrill + + * c-decl.c (finish_struct): Don't mess with the type of bitfields. + +Mon Dec 4 15:28:02 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (store_constructor, record): If field is READONLY, + set RTX_UNCHANGING_P in TO_RTX. + +Mon Dec 4 12:59:33 1995 Ian Lance Taylor + + * sparc/t-sol2 (CRTSTUFF_T_CFLAGS): Use -fPIC unconditionally. + +Sun Dec 3 20:55:43 1995 Jeffrey A. Law + + * pa.h (ASM_OUTPUT_FUNCTION_PREFIX): Handle arbitrary sections. + (ASM_OUTPUT_SECTION_NAME): Define. + +Sat Dec 2 22:19:16 1995 Jeffrey A. Law (law@cygnus.com) + + * pa.h: Replace many uses of fprintf with fputs. + * pa.c: Likewise. + * pa-pro.h: Likewise. + + * pa.h (SECONDARY_RELOAD_CLASS): Don't call secondary_reload_class + to handle trivial cases. + * pa.c (secondary_reload_class): Rework to be more efficient. + +Sat Dec 2 07:52:46 1995 Michael Meissner + + * rs6000.md (movsi): Don't split large constants in the + movsi pattern, let the define_split split it later as needed. + +Fri Dec 1 16:00:42 1995 Brendan Kehoe + + * sparc.c (output_double_int): Handle CODE_LABEL's if v9. + +Fri Dec 1 09:13:23 1995 Michael Meissner + + * m68k.md (decrement_and_branch_until_zero): Split into a + define_expand and an anonymous define_insn. + * fx80.md (decrement_and_branch_until_zero): Ditto. + * m88k.md (decrement_and_branch_until_zero): Ditto. + +Thu Nov 30 15:02:16 1995 Jim Wilson + + * sh.c (noncall_uses_reg): New function. + (machine_dependent_reorg): Add support for TARGET_RELAX. + (final_prescan_insn): Likewise. + * sh.h (ASM_SPEC, LINK_SPEC): Pass on -mrelax. + (RELAX_BIT, TARGET_RELAX): New macros. + (TARGET_SWITCHES): Add -mrelax. + + * sh.c (insn-attr.h): Include. + (pragma_nosave_low_regs): New global variable. + (calc_live_regs): If SH3 and pragma_nosave_low_regs, then don't + save registers r0 through r7 for interrupt functions. + (function_epilogue): Clear pragma_nosave_low_regs. + (handle_pragma): Set pragma_nosave_low_regs if see pragma for it. + + * sh.h (FUNCTION_PROFILER): Use trap #33 instead of trap #5. + Put additional .align before trapa instruction. + +Thu Nov 30 14:45:13 1995 Doug Evans + + * sparc.md (seqdi_special_trunc, snedi_special_trunc, + seqsi_special_extend, snesi_special_extend): Delete uses of SUBREG. + Make compare modes match modes of operands. + (snesi_zero_extend, snedi_zero_trunc_sp32, snedi_zero_trunc_sp64, + seqsi_zero_extend, seqdi_zero_trunc_sp32, seqdi_zero_trunc_sp64): + New patterns. + +Thu Nov 30 12:27:22 1995 Michael Meissner + + * genmultilib: Take a 4th argument that says are the exceptions to + the multilibs, so illegal combinations can be eliminated. + + * Makefile.in (multilib.h): Pass $(MULILIB_EXCEPTIONS) as the 4th + argument to genmultilib. + + * configure (powerpc*): Remove little endian and eabiaix versions + of the t-* files. Accept powerpc{,le}-*-sysv in addition to + *-sysv4. + (powerpc{,le}-*-eabisim): Use standard t-eabigas instead of + t-eabisim. + (powerpcle-*-{winnt3,pe}): Add support for Windows NT on PowerPC. + * rs6000/t-{eabiaix,eabisim,eabilegas,ppclegas}: Delete. + + * rs6000/{t-winnt,win-nt.h}: New files for PowerPC Windows NT. + + * ginclude/ppc-asm.h: New file to provide common macros for the + various PowerPC calling sequences. + * rs6000/eabi.asm: Use ppc-asm.h. + + * rs6000/aix3newas.h (CPP_SPEC): Add support for -mcpu=603e, 602, + and 620. + * rs6000/{aix41,powerpc,rs6000,eabi{aix,le}}.h (CPP_SPEC): Ditto. + * rs6000/sysv4{,le}.h (CPP_SPEC): Ditto. + + * rs6000/aix3newas.h (LINK_SPEC): If cross compiling, don't use + absolute paths. + * rs6000/{aix41,aixppc,rs6000}.h (LINK_SPEC): Ditto. + + * rs6000/eabi.h (INVOKE__main): Don't define any more. + (ASM_OUTPUT_INT): Move to sysv4.h. + ({STARTFILE,LIB}_SPEC): If -msim or -mmvme add the appropriate + libraries. + + * rs6000/{eabiaix,eabile,sysv4{,le}}.h (CPP_SPEC): Add support for + -mcall-{aixdesc,nt} directives. + (MULTILIB_DEFAULTS): Define. + + * rs6000/eabi{,le}sim.h (TARGET_DEFAULT, CPP_SPEC): No longer + define, simulator supports floating point. + ({STARTFILE,LIB}_SPEC): If -mvme, use mvme libraries, not + simulator libraries. + + * rs6000/{mach,netware}.h (TARGET_AIX): Define as 0. + + * rs6000/netware.h (RS6000_OUTPUT_BASENAME): Don't redefine + anymore. + (STRIP_NAME_ENCODING): Undef. + + * rs6000.c (rs6000_save_toc_p, rs6000_abi): New globals. + (rs6000_override_options): Add 602, 603e, and 620 support. + (count_register_operand): New function to return true if operand + is the count register. + (easy_fp_constant): All constants are easy if -msoft-float. + (volatile_mem_operand): New function to return true if operand is + in volatile memory. + ({fp_,}reg_or_mem_operand): Call volatile_mem_operand. + (input_operand): Allow support for Windows NT loading SYMBOL_REFs + and LABEL_REFs from the TOC. + (function_arg_boundary): On Windows NT, any argument >= 8 bytes + must be double word aligned. + (function_arg{_advance,}): Call function_arg_boundary to determine + if we need to align to an odd register for large arguments. + Changes to accomidate new method of determining which ABI we're + adhering to. + (expand_block_move_mem): Copy RTX_UNCHANGING_P, and if + MEM_UNALIGNED_P is defined, copy that too. + (expand_block_move): Copy dest/src to registers using + copy_addr_to_reg. + (print_operand): Changes to accomidate Windows NT. + (first_reg_to_save): Ditto. + (rs6000_stack_info): Ditto. + (debug_stack_info): Ditto. + (output_{prolog,epilog,toc,function_profiler}): Ditto. + (rs6000_stack_info): Save main's arguments around __eabi call. + (svr4_traceback): Delete, current V.4 ABI no longer wants + tracebacks in this format. + (output_prolog): Call __eabi here, saving and restoring main's + args if needed. Save the toc pointer if needed. + (get_issue_rate): New function to return # of instructions a + machine can issue at once. + (rs6000_sync_trampoline): Emit instructions to synchronize the + PowerPC caches after a trampoline. + (rs6000_trampoline_{template,size}): New functions to provide + common trampoline support for all ABI's. + (rs6000_initialize_trampoline): Ditto. + + * rs6000.h (TARGET_{WINDOWS_NT,AIX,MACOS}): Define. + (processor_type): Add 602. + (PROCESSOR_COMMON): Assume current processor is a 604, not a 601. + (SUBTARGET_OPTIONS): Define if not defined. + (TARGET_OPTIONS): Include SUBTARGET_OPTIONS. + (COUNT_REGISTER_REGNUM): Define as 66. + (EXTRA_CONTRAINT): Add 'S' and 'T' for Windows NT. + (rs6000_abi): Add ABI_AIX_NODESC, ABI_NT. + (DEFAULT_ABI): Define if not defined. + (rs6000_stack): Add fields for Windows NT support. + (RS6000_SAVE_TOC): Add for Windows NT support. + (FUNCTION_ARG_BOUNDARY): Call function_arg_boundary. + (trampoline macros): Call trampoline functions in rs6000.c. + (RETURN_ADDRESS_OFFSET): Add Windows NT support. + (toc_section): Skip leading '*'. + (PREDICATE_CODES): Add volatile_mem_operand, + count_register_operand. + (MACHINE_issue_rate): Define. + (function decls): Add new function decls from rs6000.c. + + * rs6000.md (cpu attribute): Add 602. + (function units): Update to match reality better. + (calls through pointer): Rework to support Windows NT. + (movsi): Add Windows NT support. + (movstrsi): Remove match_operand predicates, since + expand_block_move does the checking. + (sync_isync): Delete. + (icbi, dcbst, sync, isync): New insns to generate named instruction + for making trampolines on eabi/V.4 properly flush the caches. + (decrement_and_branch_on_count): Rename from + decrement_and_branchsi. Add update of count in insn pattern. + + * rs6000/sysv4.h (TARGET_SWITCHES): Drop -mtraceback. Keep + -mno-traceback but don't do anything with it. Add + -mcalls-{nt,aixdesc}. Add -m{,no-}relocatable-lib. Add -msim, + -mmvme, and -memb. + (TARGET_TOC): Update for use with -mcalls-{nt,aixdesc}. + (SUBTARGET_OVERRIDE_OPTIONS): Update for new switches. + (RS6000_OUTPUT_BASENAME): Delete. + (toc_section): Add support for -mcall-{nt,aixdesc}. + (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P): Ditto. + (ASM_DECLARE_FUNCTION_NAME): Use STRIP_NAME_ENCODING instead of + RS6000_OUTPUT_BASENAME. For -mcall-{nt,aixdesc} emit the proper + function descriptor. + (ASM_SPEC): Pass appropriate -mxxx switches to the assembler based + on the -mcpu=xxx options. + (ASM_OUTPUT_INT): Move here from eabi.h. + (ENCODE_SECTION_INFO): If -mcall-{nt,aixdesc} add approriate magic + so function name has two or one leading periods. + (ASM_OUTPUT_SOURCE_LINE): Delete, use version in svr4.h. + (trampoline macros): Call trampoline functions in rs6000.c. + + * t-{eabi,ppc}{,gas} (EXTRA_HEADERS): Add ginclude/ppc-asm.h. + (LIB2FUNCS_EXTRA): Depend on eabi.S, not eabi.s. + (eabi.S): Rename from eabi.asm. + + * t-{eabi,ppc}gas (MULTILIB_*): Add -mcall-aixdesc libraries, but + don't build either little endian or -mrelocatable versions of + those libraries. + +Tue Nov 28 00:10:27 1995 David Edelsohn + + * rs6000.md (divsi3): Reorder so common mode does not negate + power-of-2 shift optimization. + +Wed Nov 29 22:06:11 1995 J.T. Conklin + + * configure (sparc-*-solaris2*): Add gcrt1.o to extra_parts. + * sparc/sol2.h (STARTFILE_SPEC): Link with gcrt1.o with -pg. + * sparc/sol2-g1.asm: New file, startup code for profiled + executables. + * sparc/t-sol2: Add make rule for gcrt1.o. + * sparc/gmon-sol2.c (_mcleanup): Add support for PROFDIR + environment variable. + +Wed Nov 29 21:41:13 1995 Ian Lance Taylor + + * mips/abi64.h (CPP_SPEC): If -msingle-float and not + -msoft-float, pass -D__mips_single_float. Likewise for -m4650 and + not -msoft-float. + * mips/dec-bsd.h (CPP_SPEC): Likewise. + * mips/dec-osf1.h (CPP_SPEC): Likewise. + * mips/elf64.h (CPP_SPEC): Likewise. + * mips/iris3.h (CPP_SPEC): Likewise. + * mips/iris5.h (CPP_SPEC): Likewise. + * mips/mips.h (CPP_SPEC): Likewise. + * mips/netbsd.h (CPP_SPEC): Likewise. + * mips/osfrose.h (CPP_SPEC): Likewise. + * mips/t-ecoff (MULTILIB_OPTIONS, MULTILIB_DIRNAMES, + MULTILIB_MATCHES): Add -msingle-float support. + +Wed Nov 29 17:57:48 1995 Doug Evans + + * toplev.c (main): Invoke OPTIMIZATION_OPTIONS after target_flags + has been initialized so sets of target_flags aren't clobbered. + + * cccp.c (do_include): Recognize c:\foo as absolute path name in DOS. + + * svr4.h (MD_EXEC_PREFIX): Don't use if cross compiling. + (MD_STARTFILE_PREFIX): Likewise. + (LINK_SPEC): Don't use absolute path names if cross compiling. + * svr3.h (LIB_SPEC): Likewise. + + * gcc.c (do_spec_1): Fix typos in version calculation. + +Wed Nov 29 14:06:13 1995 Jim Wilson + + * sh.md (ashrsi3_d): Use %0 not %1 in output pattern. + + * svr4.h (MAX_OFILE_ALIGNMENT): Define. + + * mips/iris5.h (WORD_SWITCH_TAKES_ARG): Define. + (LINK_SPEC): Add rpath. + * mips/iris6.h (LINK_SPEC): Likewise. + + * stupid.c (stupid_mark_regs): For hard registers, use regno+j + instead of just regno in MARK_LIVE_AFTER and SET_HARD_REG_BIT calls. + + * c-common.c (combine_strings): Add support for WCHAR_TYPE as short. + +Wed Nov 29 13:59:58 1995 J"orn Rennecke (amylaar@meolyon.hanse.de) + + * c-decl.c (duplicate_decls): Add new parameter different_binding_level. + Lots of changes to use new new parameter. + (pushdecl): Delete variable declared_global. New variable + different_binding_level and code to set it. Move extern/static + warning before duplicate_decls call. Don't let global typedefs + conflict with nested extern declarations. Move oldglobal test + inside code for setting IDENTIFIER_LIMBO_VALUE. + (lookup_name_current_level_global): Delete. + * c-tree.h (merge_attributes): New declaration. + * c-typeck.c (merge_attributes): New function. Move code from + common_type to here. + (common_type): Call merge_attributes instead of having inline code. + * integrate.c (integrate_decl_tree): Delete variable newd. + Always set DECL_ABSTRACT_ORIGIN before calling pushdecl. + +Tue Nov 28 21:57:04 1995 Jim Wilson + + * mips.c (mips_function_value): Add check for i > 0 when deciding + if structure should be return in FP registers. + +Tue Nov 28 12:47:52 1995 Jeffrey A. Law + + * pa.md (define split for (plus (reg) (large_constant)): Try + another way to handle this with only 2 insns. From Tege. + +Mon Nov 27 02:05:18 1995 Jeffrey A. Law + + * lib1funcs.asm, pa-pro.h, t-pro.h, xm-papro.h: New PA + target files. + * configure (hppa*-*-pro*): Use new target files. + + * toplev.c (rest_of_compilation): Always call jump_optimize + at least once. + + * pa.h (ASM_OUTPUT_EXTERNAL): Don't let assemble_name clobber + the value of TREE_SYMBOL_REFERENCED. + + * pa-ghpux9.h (LINK_SPEC): Pass "-z" to the linker to enable + trap on null pointer dereference for programs built on hpux9. + * pa-hpux9.h, pa1-ghpux9.h, pa1-hpux9.h: Likewise. + + * pa.c (output_function_prologue): No longer need to keep + track of the total number code bytes when TARGET_GAS && + not TARGET_PORTABLE_RUNTIME. + * pa.h (DBX_OUTPUT_MAIN_SOURCE_FILE_END): Use .NSUBSPA when + not TARGET_PORTABLE_RUNTIME. + (ASM_OUTPUT_FUNCTION_PREFIX): Define. Prefix functions with + .NSUBSPA when TARGET_GAS and not TARGET_PORTABLE_RUNTIME. + + * pa.md (symbolic high patterns): Use 'H' to print the symbolic + address so that the constant part gets rounded. + * pa.c (print_operand): Handle 'H' operand for high part of a + symbolic address with a rounded constant. + (output_global_address): New argument "rounded_constant". All + callers changed appropriately. + + * x-pa-hpux (FIXPROTO_DEFINES): Add -D_HPUX_SOURCE. + + * pa.h (CPP_SPEC): Only pass -D_HPUX_SOURCE and -D_HIUX_SOURCE if + -ansi is not present. + (CPP_PREDEFINES): Remove -D_HPUX_SOURCE and/or -D_HIUX_SOURCE. + * pa-ghiux.h (CPP_PREDEFINES): Likewise. + * pa-gux7.h (CPP_PREDEFINES): Likewise. + * pa-hiux.h (CPP_PREDEFINES): Likewise. + * pa-hpux.h (CPP_PREDEFINES): Likewise. + * pa-hpux7.h (CPP_PREDEFINES): Likewise. + * pa1-ghiux.h (CPP_PREDEFINES): Likewise. + * pa1-hiux.h (CPP_PREDEFINES): Likewise. + + * pa-hpux.h (LINK_SPEC): If -mlinker-opt, then pass -O to the + linker. + * pa-ghpux.h, pa-hpux9.h, pa-ghpux9.h: Likewise. + * pa1-ghpux9.h, pa1-hpux9.h: Likewise. + * pa.h (LINK_SPEC): Likewise. + (TARGET_SWITCHES): Add -mlinker-opt. + + * pa.md (all peepholes): Disable if TARGET_SOFT_FLOAT. + + * pa.c (pa_reorg): If TARGET_GAS, then emit insns to mark + the beginning and end of the branch table. + * pa.md (begin_brtab): New insn. Just a marker so GCC knows + where to put the .begin_brtab pseudo-op. + (end_brtab): Similarly. + + * pa.h (EXTRA_SECTIONS): Add in_ctors and in_dtors if + CTORS_SECTION_FUNCTION is defined. Else define dummy + versions of CTORS_SECTION_FUNCTION and DTORS_SECTION_FUNCTION. + (EXTRA_SECTION_FUNCTIONS): Add CTORS_SECTION_FUNCTION and + DTORS_SECTION_FUNCTION. + + * pa.md: Add peepholes to improve spill code generated + by reload when we run out of FP registers. + + * xm-pa.h: Remove spurious double-quote. + + * pa.md (call expanders): For indirect calls, load %r22 with the + function's address. + (indirect call patterns): No need to copy the call address into + %r22 anymore. + + * pa.c (output_cbranch): Fix buglet in length handling of + backwards branches with unfilled delay slots. + (output_bb, output_bvb, output_dbra, output_movb): Likewise. + + * pa.md: Fix off-by-one error in length computations for all + conditional branch patterns. + + * pa.h (output_bvb): Declare. + * pa.c (output_bvb): New function to output branch on variable + bit insns. + * pa.md (branch-on-variable-bit): New patterns. + + * pa.h (TARGET_MILLICODE_LONG_CALLS): Delete swtich and all + references. + (output_millicode_call): Declare new function + * pa.md (millicode calls): Update length computation to handle + variable length millicode calls. + (call pattners): Likewise. + (indirect call patterns): Update length compuations and output + templates to handle variable length millicode calls. + (plabel_dereference): Likewise. + * pa.c (override_options): Give warnings when incompatable + options are used. + (output_mul_insn): Call output_millicode_call instead of + output_call, eliminate last argument to output_millicode_call. + (output_div_insn): Likewise. + (output_mod_insn): Likewise. + (output_call): Rewrite long call code to handle variable length + millicode calls. Eliminate support for calling mul, div and mod + millicode routines. + (output_millicode_call): New function for calling mul, div and mod + millicode routines. + + * pa.md (abssi2): New pattern. + + * pa.c (secondary_reload_class): Loads from reg+d addresses into + FP registers don't need secondary reloads. + * pa.h: Delete soem #if 0 code. Update some comments. + (EXTRA_CONSTRAINT, case 'Q'): Only accept valid memory addresses. + + * pa.h (RTX_COSTS): Tege's rewrite. + + * pa.c (hppa_legitimize_address): Generate unscaled indexed + addressing for (plus (symbol_ref) (reg)). + (emit_move_sequence): Set REGNO_POINTER_FLAG appropriately + to encourage unscaled indexing modes. + (basereg_operand): New function for unscaled index address support. + * pa.md (unscaled indexing patterns): New patterns for unscaled + index address support. + + * pa.h (MOVE_RATIO): Define. + * pa.md (movstrsi expander): Refine tests for when to use the + library routine instead of an inlined loop copy. Provide an + additional scratch register for use in the inlined loop copy. + (movstrsi_internal): Name the pattern for ease of use. Add + additional scratch register. + * pa.c (output_block_move): Greatly simplify. Use 2X unrolled + copy loops to improve performance. + (compute_movstrsi_length): Corresponding changes. + + * pa.c (print_operand): Handle 'y' case for reversed FP + comparisons. Delete some #if 0 code. Fix various comment typos. + * pa.md (fcmp patterns): Try and reverse the comparison to avoid + useless add,tr insns. + +Sun Nov 26 14:47:42 1995 Richard Kenner + + * Version 2.7.2 released. + + * function.c (fixup_var_refs_1): Make pseudo for DEST + in PROMOTED_MODE unless in a SUBREG. + + * cse.c (insert): Don't put a REG into qty_const. + + * msdos/top.sed: Change version to 2.7.2. + * winnt/config-nt.sed: Likewise. + +Sun Nov 26 14:41:49 1995 Douglas Rupp (drupp@cs.washington.edu) + + * Makefile.in (stamp-objlist): Change .o to $objext. + + * alpha/win-nt.h (CPP_PREDEFINES): Set __unaligned and __stdcall + to null. + (ASM_SPEC): Add a translation for -g to -Zi. + * winnt/ld.c (main): Don't pass -g to link. + * winnt/oldnames.c: Reformat and add some new functions for gnat1. + * winnt/win-nt.h (LINK_SPEC): Pass -g to ld.exe. + Increase default stack size. + * configure ({alpha-dec,i386-ibm}-winnt3.5): Add oldnames.o + to extra_objs. + * libgcc2.c (trampoline): Add getpagesize and mprotect for WINNT. + +Sun Nov 26 14:25:26 1995 Uwe Seimet (seimet@chemie.uni-kl.de) + + * atari.h (FUNCTION_VALUE): Deleted; incorrect. + +Sun Nov 26 14:23:03 1995 Philippe De Muyter (phdm@info.ucl.ac.be) + + * fixincludes (curses.h): Allow space or tab after bool keyword, + instead of tab or tab. + +Sun Nov 26 14:14:11 1995 Oliver Kellogg (oliver.kellogg@space.otn.dasa.de) + + * 1750a.md (pattern for HImode PSHM): Corrected. + (trunchiqi2, zero_extendqihi2, extendhftqf2): Corrected. + (pattern for movhi of CONST_INT to REG): Corrected. + (divmodqi pattern for DISN): Corrected. + (all shift patterns): Corrected. + + * 1750a.h (REG_OK_FOR_INDEX_P, REG_OK_FOR_BASE_P): Corrected. + (ASM_OUTPUT_[datatype]): Corrected datalbl[].size computation + for output of arrays. + +Sun Nov 26 14:08:57 1995 Dave Love + + * mips/iris5.h (NO_IMPLICIT_EXTERN_C): Define this again so + that unistd.h doesn't get badly `fixed' for C++. libg++ will now + build with this definition. + +Sun Nov 26 14:02:43 1995 Robert E. Brown (brown@grettir.bibliotech.com) + + * configure: Better workaround for Nextstep bug. + +Sun Nov 26 13:55:07 1995 Torbjorn Granlund + + * rs6000.md (load_multiple matcher): Fix typo in opcode. + +Sun Nov 26 13:51:08 1995 Lee Iverson + + * final.c (final_start_function): Move call to sdbout_begin_function + back to final_scan_insn on MIPS systems so parameter descriptions are + recognized. + +Sun Nov 26 13:43:06 1995 DJ Delorie (dj@delorie.com) + + * msdos/top.sed: Don't insert "go32". + +Sun Nov 26 12:08:23 1995 Jim Wilson + + * combine.c (nonzero_bits, case REG): Put POINTERS_EXTEND_UNSIGNED + code before stack pointer code. Return nonzero at end of stack + pointer code. + + * sparc.h (PRINT_OPERAND_ADDRESS): Handle CONST inside PLUS. + + * Makefile.in (cppalloc.o): Add a rule to build it. + + * alpha.c (alpha_emit_set_const): Don't output SImode sequences + that rely on invisible overflow. Sign extend new when SImode. + Don't recur if new == c. Don't allow shift outside mode. Make + logical right shift be unsigned. + +Sun Nov 26 11:37:50 1995 Arne H. Juul (arnej@idt.unit.no) + + * Makefile.in (compare*): Add "|| true" to avoid spurious + failure messages from some versions of make. + +Sun Nov 26 11:20:09 1995 Dmitry K. Butskoy (buc@stu.spb.su) + + * expr.c (truthvalue_conversion): Add declaration. + +Sun Nov 12 18:09:35 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * Version 2.7.1 released. + + * function.c (put_reg_into_stack): New arg volatile_p. + (put_var_into_stack): Call with new arg. + +Sat Nov 11 08:25:34 1995 Jim Wilson + + * reload.c (output.h): Include it. + * Makefile.in (reload.o): Add dependence on output.h. + +Thu Nov 9 11:24:20 1995 Jim Wilson + + * mips.h (HARD_REGNO_NREGS): If FP_REG_P, always use UNITS_PER_FPREG + to calculate number of words needed. + +Thu Nov 9 11:04:50 1995 Oliver Kellogg (Oliver.Kellogg@space.otn.dasa.de) + + * 1750a.md (cmphf): Addd Base Reg with Offset address mode (LB,STB,..) + (movqi,movhi,movhf,addqi3,addhf3,subqi3,subhf3,mulqihi3): Likewise. + (mulhf3,divhf3,andqi3,iorqi3): Likewise. + (define_peephole): Remove the Base mode peepholes. Replace the + special addqi define_insn for "LIM Ra,sym,Rb" by a define_peephole. + (ashlqi3): Took out futile 0th alternative. + (lshrqi3, lshrhi3, ashrqi3, ahsrhi3): Correct case of non-constant + shift count. + + * 1750a.h (REG_ALLOC_ORDER): Define. + (REGNO_OK_FOR_BASE_P): Include stack pointer in test against + reg_renumber[REGNO]. + (ASM_OUTPUT_DESTRUCTOR): Remove bogus assembler comment. + +Thu Nov 9 11:01:33 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (expand_expr, case ARRAY_REF): Properly convert types + of index, size, and multiplication. + +Wed Nov 8 09:00:22 1995 Richard Earnshaw (rearnsha@armltd.co.uk) + + * arm.md (mov*cc_{,soft_}insn): Use match_operator to test the + comparison and check that the condition code register is used. + +Wed Nov 8 08:49:35 1995 Michael Meissner + + * rs6000/sysv4.h (ASM_OUTPUT_{CONSTRUCTOR,DESTRUCTOR}): Undef before + including svr4.h. + +Tue Nov 7 10:58:12 1995 Torbjorn Granlund + + * m68k.md (subxf3): Properly name pattern. + +Tue Nov 7 10:53:09 1995 Michael Meissner + + * libgcc2.c (__{C,D}TOR_LIST): For AIX, initialize these arrays to + 0,0, just like NeXT to avoid a warning message from the AIX 4.1 + linker. + +Tue Nov 7 09:58:34 1995 John F. Carr + + * cppexp.c (cpp_lex): Correctly parse character constants. + +Tue Nov 7 09:52:15 1995 Jason Merrill + + * rs6000.h (ASM_OUTPUT_{DES,CONS}TRUCTOR): Define. + +Mon Nov 6 10:27:15 1995 Doug Evans + + * combine.c (force_to_mode): Fix typo. + +Sun Nov 5 18:37:02 1995 Torbjorn Granlund + + * m68k.md (cmpxf): Don't call force_const_mem, it looses for PIC; + get predicates right instead. Get rid of separate DEFINE_EXPAND. + (addxf3, subxf3, mulxf3, divxf3): Likewise. + (All XFmode patterns): Delete `F' and `G' constraints. + (absxf2, negxf2): Delete spurious condition on TARGET_FPA. + +Sun Nov 5 11:05:44 1995 Philippe De Muyter (phdm@info.ucl.ac.be) + + * fixincludes (malloc.h): Fix return type of {m,re}alloc. + +Sun Nov 5 11:02:26 1995 J"orn Rennecke (amylaar@meolyon.hanse.de) + + * cse.c (invalidate): For a pseudo register, do a loop to + invalidate all table entries, irrespective of mode. + +Sun Nov 5 10:57:43 1995 Richard Kenner + + * combine.c (force_to_mode): Put in last change properly. + +Sun Nov 5 10:53:49 1995 Jeffrey A Law (law@cygnus.com) + + * pa.h (CONDITIONAL_REGISTER_USAGE): Make sure FP regs + get disabled regardless of PA1.0 vs PA1.1 code generation + when TARGET_SOFT_FLOAT or TARGET_DISABLE_FPREGS is on. + +Sun Nov 5 10:49:43 1995 Doug Evans + + * i960.c (emit_move_sequence): Add a scratch register to + multi-reg stores. + (i960_output_move_{double,quad}): New functions. + (i960_print_operand): Handle new operand types E, F. + * i960.md (movdi matchers): Rewrite. + (store_unaligned_di_reg): New pattern. + (movti matchers): Rewrite. + (store_unaligned_ti_reg): New pattern. + +Sun Nov 5 10:45:24 1995 Ian Lance Taylor (ian@cygnus.com) + + * mips.h (MULTILIB_DEFAULTS): Define. + * mips/elf64.h, mips/iris6.h (MULTILIB_DEFAULTS): Define. + +Sun Nov 5 10:41:48 1995 Jim Wilson + + * reload.c (push_reload): Delete abort for RELOAD_OTHER case added + in last change. + * reload1.c (emit_reload_insns): For RELOAD_OTHER output reloads, + output the reload insns in descending order of reloads. + + * sh.md (mulsidi3-1, mulsidi3, umulsidi3-1, umulsidi3): Enable. + (smulsi3_highpart-1, smulsi3_highpart): New patterns. + (umulsi3_highpart-1, umulsi3_highpart): Likewise. + (movdi-1): Add r/x constraint. + * t-sh (MULTILIB_OPTIONS): Add m2. + (MULTILIB_DIRNAMES): Add m2. + (MULTILIB_MATCHES): Define. + + * sparc.h (RTX_COSTS, case MULT): Check for TARGET_SPARCLITE. + + * abi64.h, elf64.h (CPP_SPEC): Add -EB and -EL support. + +Sat Nov 4 10:36:26 1995 Jim Wilson + + * sh.md (casesi_worker): Change constraint from = to +. + + * svr4.h (ASM_IDENTIFY_GCC_AFTER_SOURCE): Delete. + (ASM_IDENTIFY_GCC): Output stab here. + +Sat Nov 4 10:32:37 1995 John Carr + + * cpplib.c (finclude): Set current input pointer when input + is not a regular file. + + * cppmain.c: Define progname, required by cpplib. + +Sun Oct 29 07:48:36 1995 Michael Meissner + + * xcoffout.h (DBX_FINISH_SYMBOL): Deal with names created via + the __asm__ construct that start with a leading '*'. + * xcoffout.c (xcoff_declare_function): Likewise. + +Sun Oct 29 07:45:41 1995 Jim Wilson + + * stupid.c (stupid_mark_refs): Handle SUBREG of pseudo-reg in a + SET_DEST same as we handle a pseudo-reg in a SET_DEST. + +Sun Oct 29 07:43:15 1995 Pat Rankin + + * libgcc2.c (L_eh: __unwind_function): Implement for VAX. + * vax.h (RETURN_ADDRESS_OFFSET, RETURN_ADDR_RTX): Define. + +Sun Oct 29 12:39:08 1995 Richard Kenner a + + * i386/sol2.h (CPP_PREDEFINES): Add -D__SVR4. + +Sun Oct 29 07:14:36 1995 J"orn Rennecke (amylaar@meolyon.hanse.de) + + * reload.c (find_equiv_reg): Check for nonsaving setjmp. + +Fri Oct 27 15:15:56 1995 Jim Wilson + + * Makefile.in (out_object_file): Depend on TREE_H. + +Fri Oct 27 06:42:36 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * alpha.c (call_operand): Only allow reg 27 on NT too. + * alpha.md (call_value_nt, call_nt): Force non-SYMBOL_REF + into reg 27, just like for OSF. + + * rs6000.c (struct asm_option): Changed from struct option. + (expand_block_move_mem): Remove erroneously-added line. + + * expr.c (clear_storage): SIZE is now rtx, not int. + (store_constructor): Call clear_storage with rtx. + (get_inner_reference): Convert index to precision of + sizetype, not POINTER_SIZE. + (expand_expr, case ARRAY_REF): Likewise. + * expr.h (clear_storage): Second arg is rtx, not int. + +Fri Oct 27 05:45:58 1995 J"orn Rennecke (amylaar@meolyon.hanse.de) + + * combine.c (force_to_mode, case ASHIFTRT): Properly handle + mask wider than HOST_WIDE_INT. + + * c-decl.c (pushdecl): Don't test TREE_PUBLIC when deciding whether + to register a duplicate decl in the current block. + +Thu Oct 26 21:55:39 1995 Jason Merrill + + * calls.c (expand_call): Don't trust the callee to copy a + TREE_ADDRESSABLE type. + * function.c (assign_parms): Likewise. + +Thu Oct 26 19:25:05 1995 Mike Stump + + * libgcc2.c (__unwind_function): Provide a default definition for + implementations that don't yet have a function unwinder. + +Thu Oct 26 18:08:19 1995 Paul Eggert + + * cccp.c (handle_directive): Don't treat newline as white + space when coalescing white space around a backslash-newline. + +Thu Oct 26 17:57:34 1995 Ian Lance Taylor + + * mips-tdump.c (enum st): Define st_Struct, st_Union, and st_Enum. + (st_to_string): Handle them. + (type_to_string): Add fdp argument; pass it to emit_aggregate. + (print_symbol): Add fdp argument; pass it to type_to_string. + Handle st_Struct, st_Union, and st_Enum. + (emit_aggregate): Add fdp argument. Handle opaque types. Map + through RFD entries. + (print_file_desc): Pass FDR to print_symbol. + (main): Pass null FDR to type_to_string. + +Thu Oct 26 08:07:10 1995 Michael Meissner + + * configure (powerpc-ibm-aix[456789]*): Use rs6000/t-newas, + not rs6000/t-rs6000. + (rs6000-ibm-aix3.2.[456789]*): Likewise. + (rs6000-ibm-aix[456789]*): Likewise. + + * rs6000/t-newas: Copy from t-rs6000. + * t-rs6000: Don't build -mcpu=common multilib variants of libgcc.a. + + * rs6000.md (load_multiple insn): If address register is among regs, + don't load it with a lwsi instruction, which is undefined on PowerPC. + +Thu Oct 26 08:01:32 1995 Jim Wilson + + * dwarfout.c (output_compile_unit_die): Handle language_string + of "GNU F77". + + * reload.c (find_reloads_address): When check for out of range constant + plus register, accept any hard register instead of just fp, ap, sp. + + * combine.c (distribute_notes): For Oct 19 change, add additional + check to verify that place has a valid INSN_CUID. + + * sparc/t-vxsparc (LIBGCC1_TEST): Define. + + * sh.md (negdi2): Use TARGET_LITTLE_ENDIAN. + + * combine.c (force_to_mode, case ASHIFTRT): Verify mode bitsize is + within HOST_BITS_PER_WIDE_INT before shifting by it. + + * final.c (final_scan_insn): When recur for instruction in delay slot, + add loop around recursive call in case the instruction gets split. + +Thu Oct 26 07:28:45 1995 J"orn Rennecke (amylaar@meolyon.hanse.de) + + * genrecog.c (write_tree_1): Avoid emitting '-2147483648'. + + * jump.c (duplicate_loop_exit_test): Return 0 if found + a NOTE_INSN_LOOP_CONT. + +Tue Oct 24 15:30:14 1995 Jeffrey A Law + + * calls.c (expand_call): Make sure valreg is at least + a full word. + +Sun Oct 22 19:35:41 1995 Jim Wilson + + * sh.h (INIT_SECTION_ASM_OP): Delete. + (HAVE_ATEXIT): Define. + +Sun Oct 22 07:46:04 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * libgcc2.c (__fixuns[xds]fsi): #undef MIN and MAX before #include + of limits.h. + + * pa.c (pa_adjust_cost): Use pa_cpu, not pa_cpu_attr. + +Sun Oct 22 07:38:58 1995 J"orn Rennecke (amylaar@meolyon.hanse.de) + + * alpha.h (CONST_OK_FOR_LETTER_P): Use 'U' for unsigned constants. + * alpha.c (alpha_emit_set_const): Likewise. + * mips.c (gen_int_relational): Likewise. + +Sun Oct 22 07:14:35 1995 Douglas Rupp (drupp@cs.washington.edu) + + * i386.c (i386_return_pops_args): Don't need a FUNDECL to + check for type attributes in FUNTYPE. + +Sat Oct 21 18:17:42 1995 Jim Wilson + + * sh.md (define_delay): Don't accept any instruction for an annulled + slot, only accept those for which in_delay_slot is yes. + * sh.c (find_barrier): When hi_const returns true, increment count_si + by two if found_si is true. + Always use get_attr_length to compute length of instructions. + If count_hi or count_si out of range at end, need two PREV_INSN calls + not one. + When create new label, set LABEL_NUSES to 1. + (reg_unused_after): Ifdef out code for handling labels. + (prepare_scc_operands): New local variable mode. Set it from + sh_compare_op0 or sh_compare_op1. Use it instead of SImode in + force_reg calls. + + * optabs.c (expand_float): Emit missing barrier after unconditional + jump. + +Sat Oct 21 14:16:46 1995 Torbjorn Granlund + + * alpha.md (cmpdf): Make conditional on TARGET_FP. + +Fri Oct 20 19:11:12 1995 J"orn Rennecke (amylaar@meolyon.hanse.de) + + * combine.c (distribute_notes): Delete instructions without + side effect that set a subreg of an unused register. + + * m68k.h (PREFERRED_RELOAD_CLASS): Check for !G constants + for DATA_OR_FP_REGS also. + +Fri Oct 20 18:57:10 1995 Ian Lance Taylor + + * genmultilib: Output negations of unused alternatives, even if + one of the alternatives is selected. + +Fri Oct 20 18:48:50 1995 Jeff Law (law@hurl.cygnus.com) + + * integrate.c (output_inline_function): Turn on flag_no_inline + to avoid function integration once we begin writing deferred + output functions. + +Fri Oct 20 18:46:33 1995 Michael Meissner + + * rs6000.c (float_conv_temp): Delete global variable. + (stack_temps): New static array to hold stack temps. + (offsettable_mem_operand): Delete function. + (offsettable_addr_operand, rs6000_stack_temp): New functions. + (output_epilog): Zero stack_temps. + + * rs6000.h (offsettable_addr_operand): Declare instead of + offsettable_mem_operand. + (PREDICATE_CODES): Use offsettable_addr_operand. + (float_conv_temp): Delete variable. + + * rs6000.md (move_to_float insns): Change move_to_float so + that it doesn't have a clobber of the memory address, and instead + passes the stack temp's memory address as one of the unspec args. + (fix_truncdfsi2): Use rs6000_stack_temp to allocate the temp. + (multiply, shift insns): Fix all cases of multiply and shift insns so + that the right mnemonics are used for -mcpu=common with both + -m{old,new}-mnemonics. + +Fri Oct 20 17:58:19 1995 Jim Wilson + + * expr.c (safe_from_p, case RTL_EXPR): Return 0 if RTL_EXPR_SEQUENCE + exists. Delete code to return 0 if exp_rtl is zero. + + * function.c (init_function_start): Don't call init_insn_lengths here. + * toplev.c (rest_of_compilation): Call it here. + +Thu Oct 19 19:19:06 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * c-common.c (check_format_info): Make test for null pointer + more general. + +Thu Oct 19 18:56:16 1995 Satoshi Adachi (adachi@wisdom.aa.ap.titech.ac.jp) + + * fixincludes (stdlib.h): Be more general in edit to change + declaration of {c,m,re}alloc. + +Thu Oct 19 18:48:53 1995 Torbjorn Granlund + + * libgcc2.c (__udiv_w_sdiv): If we don't have sdiv_qrnnd, define + dummy variant of __udiv_w_sdiv. + +Thu Oct 19 18:45:21 1995 Jim Wilson + + * alpha.h (ASM_SPEC): If GNU as is the default, then pass -g to + the assembler if -malpha-as. If GNU as is not the default, then pass + -g to the assembler is not -mgas. + + * combine.c (distribute_notes): When search for new place to put + REG_DEAD note, call distribute_links if this new place is between + i2 and i3, and i2 uses the register. + +Thu Oct 19 18:41:36 1995 Michael Meissner + + * rs6000.md (float{,uns}sidf2): Rewrite to break the conversion + process into several general insns. + (move_to_float): New insns to move 2 integer regs into a float register + through memory, taking endianess into account. Make sure that the + floating temporary is a valid address. Use one temporary for all + floats converted. + (fix_truncdfsi2): Take endianess into account. + + * rs6000.c ({low_32_bit,offsettable_mem}_operand): The function + low_32_bit_operand is now unused, delete it. New function + offsettable_mem_operand to determine if a memory address is + offsettable. + * rs6000.h ({low_32_bit,offsettable_mem}_operand): Ditto. + (PREDICATE_CODES): Ditto. + + * rs6000.{c,h} (float_conv_temp): New global. + * rs6000.c (output_epilog): Zero out float_conv_temp. + + * Makefile.in (libgcc{1,2}.a): Allow LIB{1,2}FUNCS_EXTRA files to + end in .S as well as .c and .asm. + +Wed Oct 18 17:56:45 1995 Jose Alonso (sidinf@fpsp.fapesp.br) + + * c-typeck.c (parser_build_binary_op): Warn about x^y==z, etc. + +Mon Oct 9 12:38:06 1995 Michael Meissner + + * protoize.c (reverse_def_dec_list): Silence compiler warnings. + +Mon Oct 9 12:35:54 1995 Andrew Cagney + + * ginclude/va-ppc.h (va_arg): Deal with long longs that would be + passed in the 7th register, and are passed in the stack instead. + +Fri Oct 6 13:47:10 1995 Jim Wilson + + * alpha.h (ASM_SPEC): Add -g. + +Fri Oct 6 13:42:50 1995 Richard Kenner + + * alpha.h (alpha_{arg,auto}_offset): Make extern. + +Fri Oct 6 13:24:43 1995 Michael Meissner + + * rs6000.h (RETURN_ADDRESS_OFFSET): Correct previous change. + +Fri Oct 6 13:14:43 1995 Doug Evans + + * rtlanal.c (reg_set_last): Fix call to reg_set_between_p. + +Tue Oct 3 12:31:38 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * stor-layout.c (layout_type, case ARRAY_TYPE): Strip MAX_EXPR + from upper bound when computing length if it just protects against + negative length. + + * expr.c (emit_move_insn_1): When doing multi-word move, show + output is clobbered. + +Tue Oct 3 12:26:07 1995 Jim Wilson + + * cse.c (set_nonvarying_address_components, case AND): Add *pend to + end. Add constant to start instead of subtracting it. + +Tue Oct 3 12:23:28 1995 Torbjorn Granlund + + * combine.c (simplify_rtx): In code that attempts to simplify + conditional expressions, if the result is an NE around another + comparison, return the original expression. + + * longlong.h (mips umul_ppmm): Use `l' and `h' constraints; + remove mflo and mfhi instructions. + +Tue Oct 3 12:21:29 1995 Michael Meissner + + * ginclude/va-ppc.h (va_start, stdarg case): Call + __builtin_next_arg, and ignore the result, so that the compiler + can report the proper error, if the second argument is not the + last argument. + +Tue Oct 3 12:02:51 1995 Kohtala Marko + + * function.c (assign_stack_temp): Adjust full_size field of + temp_slot when splitting an unused slot. + +Tue Oct 3 11:51:59 1995 Mike Stump + + * expr.c (expand_builtin_return_addr): Break out functionality + from expand_builtin. + (expand_builtin): Call expand_builtin_return_addr. + * rs6000.h (RETURN_ADDR_RTX): Remove call to copy_to_reg. + Offset to return address is 4 when !TARGET_64BIT and v4_call_p, + 8 otherwise. + * sparc.h (RETURN_ADDR_RTX): Remove call to copy_to_reg. + * alpha.h (RETURN_ADDR_RTX): New definition. + +Sun Oct 1 21:23:30 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * tree.c (staticp, case INDIRECT_EXPR): Disable case. + + * expr.c (expand_expr, case COMPONENT_REF): If getting component + of union of variable size, propagate TARGET. + +Fri Sep 29 07:48:09 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (store_expr): When storing promoted value, don't return + MEM if address contains target. + +Thu Sep 28 14:30:03 1995 Paul Eggert + + * cccp.c (rescan): Expand `#if foo && #bar' without a bogus + complaint about preprocessor directives within macro args. + Expand `foo' in `foo#bar' without requiring a space before `#'. + +Thu Sep 28 14:24:26 1995 Philippe De Muyter (phdm@info.ucl.ac.be) + + * m68k.md (anonymous DImode shift patterns setting cc0): Turned + off due to reload problems. + +Thu Sep 28 14:05:22 1995 Niklas Hallqvist (niklas@appli.se) + + * Makefile.in (USER_H): Move up so can override. + (INSTALL_ASSERT_H): New definition. + (install-headers): Use it. + (stmp-int-hdrs): Handle USER_H being empty. + * config/x-netbsd (INSTALL_ASSERT_H): Define as empty. + + * i386/netbsd.h (WCHAR_{TYPE,UNSIGNED,TYPE_SIZE}): Now int. + * m68k/netbsd.h, ns32k/netbsd.h, sparc/netbsd.h: Likewise. + * vax/netbsd.h: Likewise. + (SIZE_TYPE): Use unsigned int. + + * m68k.c (output_scc_di): Swap operands when needed. + * m68k.h (LEGITIMATE_PIC_OPERAND): Allow SYMBOL_REF_FLAG symref. + * m68k.md: Make both assembler syntaxes do the same for PIC calls. + +Tue Sep 26 16:51:44 1995 Michael Meissner + + * mips.c (override_options): Don't allow anything but integers to + go in the HI/LO registers. + +Tue Sep 26 16:36:18 1995 John F. Carr + + * c-common.c (check_format_info): Don't warn about format type + mismatch if the argument is an ERROR_MARK. + +Mon Sep 25 17:50:50 1995 Craig Burley (burley@gnu.ai.mit.edu) + + * stor-layout.c (put_pending_sizes): New function. + * tree.h (put_pending_sizes): Add declaration. + * tree.c (save_expr): Return original for ERROR_MARK. + +Fri Sep 22 19:20:01 1995 Jeff Law (law@hurl.cygnus.com) + + * expr.c (expand_builtin, case BUILT_IN_MEMCPY): Strip off + all NOP exprs from the source and destination nodes, then + set MEM_IN_STRUCT_P. + +Fri Sep 22 18:50:31 1995 Michael Meissner + + * rs6000/eabi.h (ASM_OUTPUT_INT): Test for whether the integer + being output is also a constant so &sym - &sym2 is not fixed up. + +Fri Sep 22 18:49:07 1995 Peter Flass (FLASS@LBDRSCS.BITNET) + + * i370.md (cmpsi): Add missing constraints to operand 1. + +Fri Sep 22 18:27:33 1995 Torbjorn Granlund + + * i386.h (CONST_OK_FOR_LETTER_P): Make `N' match range 0..255 + for `outb' instruction. + + * pyr.h (PRINT_OPERAND): Handle code `R' for REG. + * longlong.h (pyr umul_ppmm): Use it. + +Fri Sep 22 18:24:38 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * c-parse.in (enumlist): Propagate error_mark_node. + + * c-aux-info.c (gen_type): Handle ERROR_MARK. + + * alpha.md (movdi): Avoid memory sharing problem when in reload. + +Wed Sep 20 14:27:09 1995 Peter Flass + + * mvs.h (FUNCTION_PROLOGUE): Maintain savearea forward chain + per MVS standards. + +Wed Sep 20 14:20:52 1995 Torbjorn Granlund + + * pyr.md (cmphi recognizer): Make condition match constraints. + (cmpqi recognizer): Likewise. + +Wed Sep 20 12:42:59 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * integrate.c (expand_inline_function): Do copy something setting + the result register if it is setting it to itself and has a REG_NOTE. + + * integrate.c (set_decl_{origin_self,abstract_flags}): Treat + a DECL_INITIAL of error_mark_node the same as one of NULL_TREE. + +Tue Sep 19 19:30:18 1995 Dave Pitts (dpitts@nyx.cs.du.edu) + + * i370.md (cmphi, movhi, movstricthi, extendhisi2): Correct generation + of short integer (Halfword) + ({add,sub,mul,and,ior,xor}hi3): Likewise. + * i370/mvs.h (MACROPROLOGUE): New macro. + (FUNCTION_{PRO,EPI}LOGUE): Added ability to use IBM supplied function + prologue macros. + (FUNCTION_PROLOGUE): Corrected function "in-line" prologue alignment + problems. + (ASM_DECLARE_FUNCTION_NAME): Changed alignment to FullWord. + (ASM_OUTPUT_{SHORT,ASCII}): Reworked. + +Tue Sep 19 19:22:15 1995 Douglas Rupp (drupp@cs.washington.edu) + + * winnt/win-nt.h: Renamed from winnt/win-nt.h. + (LINK_SPEC): Add -noinhibit-exec. + * {alpha,i386}/win-nt.h: Renamed from {alpha,i386}/winnt.h. + Include winnt/win-nt.h, not winnt/winnt.h. + * winnt/oldnames.c: New file. + * winnt/headers.mak (fixinc-nt.obj): Fix typo. + * winnt/config-nt.bat: Change winnt.h to win-nt.h. + * i386/config-nt.sed: Likewise. + * configure ({alpha,i386}-*-winnt3*): Likewise. + +Mon Sep 18 14:00:45 1995 Oliver Kellogg (Oliver.Kellogg@space.otn.dasa.de) + + * 1750a.h (enum reg_class, REG_CLASS_NAMES, REG_CLASS_CONTENTS): + Added R2 and R0_1. + (REG_CLASS_FROM_LETTER): New letters 't' and 'z'. + (EXTRA_CONSTRAINT): New letter 'Q'. + +Sun Sep 17 12:39:22 1995 Jeff Law (law@snake.cs.utah.edu) + + * pa.h (ASM_DECLARE_FUNCTION_NAME): If a parameter's type + has TYPE_NEEDS_CONSTRUCTING on, then it's passed by invisible + reference. + +Sat Sep 16 17:42:33 1995 Jim Wilson + + * loop.c (find_and_verify_loops): Fix error in last change. + +Sat Sep 16 08:38:22 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * alpha.h (GO_IF_LEGITIMATE_ADDRESS): Disallow SYMBOL_REF for + current function. + + * cse.c (recorded_label_ref): New variable. + (insert): Set instead of cse_jumps_altered. + (cse_main): Initialize it and return 1 if nonzero at end. + +Fri Sep 15 18:26:49 1995 Torbjorn Granlund (tege@matematik.su.se) + + * fold-const (div_and_round_double): Change `carry', `quo_est', + and `scale' from plain int to `unsigned HOST_WIDE_INT'. + +Fri Sep 15 18:24:24 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * cse.c (insert): Set cse_jumps_altered when inserting a LABEL_REF. + +Fri Sep 15 17:29:41 1995 Oliver Kellogg (Oliver.Kellogg@space.otn.dasa.de) + + * 1750a.c (b_mode_operand): New function. + (print_operand): Added code 'Q'. + +Fri Sep 15 17:27:23 1995 Jim Wilson + + * loop.c (find_and_verify_loops): When moving exit blocks out of + the loop, verify that the target of P is within the current loop. + + * reorg.c (fill_slots_from_thread): Update thread if it is split. + +Fri Sep 15 17:06:51 1995 Michael Meissner + + * rs6000.md (decrement_and_branchsi and related insns): Don't use + a "2" to select a register preference for operand 1 if operand 2 + hasn't been seen yet. + Add appropriate clobbers in decrement_and_branchsi. + Add patterns where the pc/label_ref are interchanged. + + * Makefile.in (gnucompare, stmp-multilib-sub): Remove extra . in + front of $(objext). + + * rs6000.c (output_toc): Align DF constants if STRICT_ALIGNMENT. + + * config/fp-bit.c (FLO_union_type): Add words field if double + precision to get at the separate words. + (FLO_union_type, pack_d, unpack_d): Use FLOAT_BIT_ORDER_MISMATCH + to determine when the bitfields need to be reversed, and + FLOAT_WORD_ORDER_MISMATCH when the words need to be reversed. + +Fri Sep 15 16:41:43 1995 Jeff Law (law@snake.cs.utah.edu) + + * reorg.c (fill_simple_delay_slots): When filling insn's delay slot + with JUMP_INSN, don't assume it immediately follows insn on + unfilled slots obstack. + + * Makefile.in (caller-save.o): Depend on insn-codes.h. + +Thu Sep 14 17:41:49 1995 Jim Meyering (meyering@comco.com) + + * protoize.c (do_cleaning): Don't blank out backslash-escaped + newlines in double quoted strings. + +Thu Sep 14 16:20:35 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * emit-rtl.c (gen_lowpart): If gen_lowpart_common fails + for a REG, load it into a pseudo and try again. + +Thu Sep 14 14:15:16 1995 Stan Cox (coxs@dg-rtp.dg.com) + + * m88k.h (VERSION_INFO1): Removed BCS reference. + * m88k/dgux.h (ASM_SPEC, *_LEGEND): + Added -mno-legend option. -mstandard no longer implies that + legend information not be produced. + (LINK_SPEC): Removed -z text + +Tue Sep 12 19:05:39 1995 Jim Wilson + + * cccp.c (is_system_include): Call skip_redundant_dir_prefix. + +Tue Sep 12 18:58:21 1995 John Carr + + * sparc.md: Change `*return "string"' to "string" in patterns. + +Tue Sep 12 18:48:47 1995 Craig Burley (burley@gnu.ai.mit.edu) + + * function.c (put_var_into_stack): For CONCAT case, order of + placement depends on FRAME_GROWS_DOWNWARD, not STACK_GROWS_DOWNWARD. + +Tue Sep 12 18:34:10 1995 Doug Evans + + * va-sparc.h (v9 varargs va_start): Handle __builtin_va_alist + being stack argument. + + * sparc.h (STATIC_CHAIN_REGNUM): Use %g5 for sparc64. + (TRAMPOLINE_TEMPLATE): Rewrite for sparc64. + (TRAMPOLINE_SIZE): Is 40 for sparc64. + * sparc.c (sparc64_initialize_trampoline): Rewrite. + +Tue Sep 12 18:30:22 1995 Douglas Rupp (drupp@cs.washington.edu) + + * cp/Make-lang.in (cc1plus) : Removed unnecessary $(exeext). + + * configure: Added code to handle gcc_extra_objs. + (alpha-winnt): Changed xmake_file to winnt/x-winnt. + Added extra_gcc_objs=spawnv.o; changed extra_programs to ld.exe. + (i386-winnt): Changed xmake_file to winnt/x-winnt. + Added extra_gcc_objs=spawnv.o; changed extra_programs to ld.exe. + * configure.bat: Changed to used common winnt/config-nt.bat. + * Makefile.in: Changed various .o's to .$(objext)'s + (specs): Removed unnecessary $(exeext). + (EXTRA_GCC_OBJS): New variable. + (clean): Removed $(LIB2FUNCS_EXTRA) + * objc/Makefile: Changed archive command for libobjc.a to use $? + for objects. + + * alpha/x-winnt, i386/x-winnt: Deleted. + * alpha/config-nt.bat, i386/config-nt.bat: Deleted. + * alpha/config-nt.sed, i386/config-nt.sed: Moved architecture + independent commands to config/winnt/config-nt.sed. + * alpha/winnt.h: Added -D_M_ALPHA to CPP_PREDEFINES. + Changed LIB_SPEC to be compatible with Gnu ld for NT. + * i386/winnt.h: Added -D_cdecl=__attribute__((__cdecl__)). + Change LIB_SPEC to be compatible with Gnu ld for NT. + * winnt/config-nt.bat, winnt/config-nt.sed: New files. + * winnt/dirent.{c,h}, winnt/fixinc-nt.c, winnt/headers.mak: New files. + * winnt/ld.c: Changed precedence of libraries to look for + libfoo.lib before libfoo.a + Changed to work like Gnu ld for NT. + * winnt/libgcc.mak, winnt/mklibgcc.c: New files. + * winnt/spawnv.c: Changed spawn function entry points to __spawn* + instead of spawn*. + * winnt/x-winnt: New file. + * fixinc-nt.sed: New file. + * fixinc.winnt: Rewritten to use fixinc-nt.sed. + + * gcc.c: Remove fix_argv kludge. + +Tue Sep 12 13:24:17 1995 Michael Meissner + + * rs6000.md (power subdi3 pattern): Fix pattern to have 5 + alternatives, and correct 4th alternative to match reality. + + * rs6000.md (adddi3, subdi3, negdi2): Add constraints so output reg + does not overlap one reg with one of the inputs. + +Tue Sep 12 13:09:48 1995 Philippe De Muyter (phdm@info.ucl.ac.be) + + * m68k.c (output_scc_di): Fixed for non-SGS_CMP_ORDER syntax. + + * collect2.c (scan_libraries): Cast lsyms' alloca to LDSYM*. + +Tue Sep 12 13:04:12 1995 Niklas Hallqvist (niklas@appli.se) + + * stmt.c (expand_start_stmt_expr): Do stack adjust in right place. + + * stdarg.h (__gnuc_va_list): Make char * for NetBSD. + +Tue Sep 12 12:44:46 1995 Jason Merrill + + * ginclude/va-ppc.h (va_arg): Reorganize to avoid BIND_EXPRs of + aggregate or array type. + +Tue Sep 12 12:42:27 1995 Ian Lance Taylor + + * fixincludes: Fix HP/UX for g++ -pedantic-errors. + + * fixincludes (curses.h): typedef bool need not take up entire line. + +Mon Sep 11 19:05:42 1995 Stan Cox (coxs@dg-rtp.dg.com) + + * c-typeck.c (digest_init): Don't recursively call digest_init + when in traditional mode if the type is invalid. + +Mon Sep 11 18:58:26 1995 Oliver Kellogg (Oliver.Kellogg@space.otn.dasa.de) + + * 1750a.md: Added DLB/DSTB peepholes for HFmode. + Corrected mnemonics for HImode DSTB peephole. + +Mon Sep 11 18:48:06 1995 Michael Meissner + + * config/fp-bit.c (FLO_union_type): Remove bitfields to set sign, + exponent, and mantissa, and add value_raw field, which is an + integer of the appropriate type. If _DEBUG_BITFLOAT is defined, + provide little and big endian bitfields. If the macro + FLOAT_BIT_ORDER_MISMATCH is defined, use explicit bitfields. + (pack_d, unpack_d): Switch to use value_raw and explicit shifts + and masks so that we don't have to worry about whether the target + is big or little endian unless FLOAT_BIT_ORDER_MISMATCH is + defined. If single precision floating point, rename to pack_f and + unpack_f, so there is no confusion in the debugger. + + * rs6000.h (rs6000_abi): New enumeration to describe which + ABI we're conforming to. + (rs6000_stack): Use abi enum, not AIX vs. V.4 boolean. + (ASM_OUTPUT_OPTIONS): New macro to print output options in .s file. + (ASM_FILE_START): Use it. + (output_options,rs6000_float_const): Declare new functions. + + * rs6000.c (output_option{,s}): New functions to write -f, -m, + and -W options to the asm file. + (rs6000_float_const): New function to generate floating point + constants portably used in signed,unsigned -> double conversions. + (rs6000_stack_info,debug_stack_info): Use ABI enumeration instead + of AIX vs. V.4 boolean. + + * rs6000.md (float{,uns}sidf2): Call rs6000_float_const to + portably build the proper floating point constant for conversions. + (movdi): Properly handle movdi of CONST_{INT,DOUBLE} on little + endian systems. + + * rs6000/sysv4.h (LIBGCC2_WORDS_BIG_ENDIAN): Define to be 0/1 + depending on the target endianess. + (ASM_FILE_START): Define, to call output_options in addition to + output_file_directive. + (TRAMPOLINE_SIZE): Correct size to match code. + + * rs6000/eabi{,le}sim.h (CPP_SPEC): Define the correct endian + macro for varargs/stdargs use. + +Mon Sep 11 18:41:58 1995 Jim Wilson + + * c-decl.c (redeclaration_error_message): For TYPE_DECLs, return 0 + if TYPE_MAIN_VARIANT of old type is same as new type. + +Mon Sep 11 17:39:35 1995 Rob Ryan (robr@cmu.edu) + + * xcoffout.c (xcoff_inlining): New variable, used in place of + xcoff_current_include_file when determining whether to use + absolute line numbers. + (xcoffout_source_file): Switched to using xcoff_inlining to + determine when to emit .bi/.ei directives. + +Mon Sep 11 16:55:06 1995 Torbjorn Granlund + + * m68k.md (cmpdi): Change patterns to allocate scratch register at + RTL generation time. + (tstdi): Likewise. + +Sun Sep 3 09:03:50 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * fold-const.c (size_binop): Don't pass 1 to NOTRUNC. + +Thu Aug 31 19:27:00 1995 Roland McGrath + + * libgcc2.c: Include longlong.h. + [L_udivdi3 || L_divdi3 || L_umoddi3 || L_moddi3] (__udivmoddi4): + Define this `static inline' when defining these, so they all + remain leaf functions. + +Thu Aug 31 18:38:21 1995 Paul Eggert + + * c-parse.in (ends_in_label): New %union member. + (stmts, stmt_or_label): Use new member to avoid lexical lookahead hack. + (lineno_stmt_or_labels): New rule. + (lineno_stmt_or_label, stmt_or_label): Yield nonzero if it ends + in a label. + +Thu Aug 31 08:31:40 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * cse.c (canon_hash, CONST_DOUBLE): Hash integer and real + differently. + * varasm.c (struct rtx_const): Add new field DI to union. + (decode_rtx_const, case CONST_DOUBLE): Use to hash CONST_DOUBLE + representing an integer. + + * va-alpha.h (__gnuc_va_list): Make __offset an int. + * alpha.c (alpha_builtin_saveregs): Properly compute address + of __offset both OSF and WINNT. + + * xm-alpha.h (sbrk): Don't define here. + * gmon.c (sbrk): Define here for __alpha. + * toplev.c (sbrk): Likewise. + * mips-tfile.c (malloc, calloc, realloc): Don't define for anybody. + + * reload.c (push_reload): Add case for output reload of a SUBREG + of a hard reg when output mode is invalid for that mode. + In both that case and existing case for in, don't remove SUBREG. + * reload1.c (emit_reload_insns): Emit RELOAD_OTHER output reloads last. + +Tue Aug 29 19:16:06 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * c-common.c (decl_attribute, case A_PACKED): Check is_type first. + (decl_attribute, case A_T_UNION): Likewise. + Don't access TYPE_FIELDS if DECL is zero. + * c-decl.c (finish_struct): If transparent_union attribute + specified, validate it once we finish laying the union out. + +Mon Aug 28 05:58:03 1995 Paul Eggert + + * arm.c (arm_gen_movstrqi): Remove unused variable const_sxteen. + + * bi-lexer.c (buffer, inpoint): Remove unused variables. + + * i370/mvs.h, i370/mvs370.c (mvs_label_emitted): Renamed + from mvs_label_emited. + + * msdos/configur.bat: Fix misspelling of `maintainer-clean'. + +Sat Aug 26 06:57:17 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * reload.c (push_secondary_reload): If X is a paradoxical SUBREG, + get mode and thing to reload from inside. + * reload1.c (emit_reload_insns): Do nothing for SUBREG whose + operand is unused subsequently. + In secondary reload case, if paradoxical SUBREG for output, reload + thing inside SUBREG, just like gen_reload. + +Fri Aug 25 19:26:53 1995 Paul Eggert + + * c-typeck.c (set_init_label): Don't die if an entire + brace-pair level is superfluous in the containing level. + +Fri Aug 25 19:22:46 1995 Michael Meissner + + * configure (powerpc{,le}-eabisim): Add support for a new target + that works under the PSIM simulator. + * rs6000/eabisim.h, rs6000/eabilesim.h, rs6000/t-eabisim: New files. + + * rs6000/eabi.h (STRICT_ALIGNMENT): If little endian, always set + strict alignment to 1. + +Fri Aug 25 19:22:23 1995 David Edelsohn + + * rs6000.md ({add,sub,mulsi}di3): Support both endian possibilities. + (negdi2): Likewise. + +Fri Aug 25 19:10:41 1995 Oliver Kellogg (Oliver.Kellogg@space.otn.dasa.de) + + * 1750a.md: Added peephole definitions for Load/Store Base insns + and eliminating redundant load in an equivalent store/load sequence. + +Fri Aug 25 18:33:27 1995 Craig Burley (burley@gnu.ai.mit.edu) + + * toplev.c (report_error_function): Don't attempt to use input + file stack to identify nesting of #include's if file name oflocation + diagnosed is not same as input_filename. + +Fri Aug 25 07:31:47 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * integrate.c (output_inline_function): Switch to function obstack. + +Mon Aug 21 13:29:54 1995 J"orn Rennecke (amylaar@meolyon.hanse.de) + + * i386.c (arithmetic_comparison_operator): New function. + (print_operand): Take into account that overflow flag is not + set the same as after a compare instruction. + * i386.md (decrement_and_branch_until_zero): Use + arithmetic_comparison_operator to decide if there is comparison + suitable to be expressed by condition code from an arithmetic op. + +Mon Aug 21 13:26:13 1995 Philippe De Muyter (phdm@info.ucl.ac.be) + + * m68k.md (adddi3, subdi3): "&" added to clobber's constraints. + +Mon Aug 21 12:11:14 1995 Jim Wilson + + * t-sparclite (MULTILIB_*, LIBGCC, INSTALL_LIBGCC): Define. + + * sh.md (movdi-1, movdf-1): Make conditional on reload_completed, + delete conditions checking for pseudo registers and Q addresses. + Add code to handle SUBREG. + + * local-alloc.c (wipe_dead_reg): Make a register mentioned in a + REG_INC note die after the instruction. + + * m68k.md: For all dbra pattern, change constraint from 'g' to 'd*g'. + + * Makefile.in: (underscore.c): Rename rule to stamp-under, and + touch stamp-under at the end. Add new rule for underscore.c that + depends on stamp-under. + + * sh.c (reg_unused_after): For a SEQUENCE, make sure all insns are + safe before returning 1. + + * sh.h (PROMOTE_FUNCTION_ARGS, PROMOTE_FUNCTION_RETURN): Define. + + * sh.c (output_stack_adjust): Add new argument reg. Use it instead + of stack_pointer_rtx. + (sh_expand_prologue, sh_expand_epilogue): Pass new argument to + output_stack_adjust. + +Sat Aug 19 17:34:15 1995 Jim Wilson + + * sparc/gmon-sol2.c (_mcount): Define. + * sparc/sol2.h (STARTFILE_SPEC, ENDFILE_SPEC): Delete superfluous + -pg tests. + (LINK_SPEC): Add libp directories to -Y when -pg. + + * unroll.c (calculate_giv_inc): Handle increment computed by ASHIFT. + +Sat Aug 19 17:28:56 1995 Philippe De Muyter (phdm@info.ucl.ac.be) + + * m68k.md (subdi3): Should not be commutative. + (one_cmpldi2): Fixed typo with register operand. + +Sat Aug 19 17:20:43 1995 Michael Meissner + + * rs6000.c (output_prolog): Fixup code to set stack pointer + if stack size > 32k. + * rs6000.md (sync_isync): Renamed from sync; added an isync insn + after the sync to properly deal with PowerPC's with split I/D caches. + * sysv4.h (INITIALIZE_TRAMPOLINE): Sync function now named sync_isync. + +Sat Aug 19 17:07:09 1995 Doug Evans + + * h8300.h (STATIC_CHAIN_REGNUM): Use r3. + (REGISTER_NAMES): Print r7 as sp. + (ADDITIONAL_REGISTER_NAMES): Recognize r7. + (ASM_OUTPUT_ALIGN): Alignment is power of 2. + * h8300.md (fancy_btst,fancy_btst1): Branch target must be + operand 0 for length attribute to work. + +Sat Aug 19 16:43:11 1995 Paul Franklin + + * assert.h: Declare __eprintf with attribute noreturn. + +Sat Aug 19 16:40:12 1995 Jason Merrill + + * stddef.h: Don't define wchar_t if __cplusplus is defined. + +Tue Aug 15 18:01:01 1995 Paul Eggert + + * cccp.c (warning_with_line): Fix typo in declaration when + !HAVE_VPRINTF and defined (__STDC__). + +Tue Aug 15 17:57:54 1995 Stephen L Moshier + + * real.c (ediv, emul): Set sign bit of IEEE -0.0 result. + +Tue Aug 15 17:49:47 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (safe_from_p): Only safe if EXP is variable-size and X + is BLKmode. + + * stmt.c (fixup_gotos): When some fixups done, reset to point + to next instead of zeroing TREE_VALUE, which may be shared. + +Mon Aug 14 09:15:45 1995 Doug Evans + + * m68k/m68kemb.h (STARTFILE_SPEC): Define as empty. + +Mon Aug 14 09:08:57 1995 Pat Rankin + + * vax.c (vms_check_external): Update `pending_head' properly + when the first list element is removed. + +Mon Aug 14 09:01:32 1995 Jeffrey A. Law + + * pa.md (call expanders): Emit a blockage insn after restoring + %r19 when generating PIC. + +Sun Aug 13 21:58:49 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * toplev.c (main): Change text of unsupported -g option warning. + +Sun Aug 13 21:47:57 1995 Andrew McCallum + + * objc/selector.c (sel_get_any_typed_uid): New function. + * objc/objc-api.h (sel_get_any_typed_uid): Declare new function. + +Sun Aug 13 21:43:17 1995 John Carr + + * c-typeck.c (c_expand_asm_operands): Check for read-only output + operand where the variable is read-only but the type is not. + +Sun Aug 13 21:16:12 1995 David Edelsohn + + * rs6000.c (direct_return): Epilogue required if CR saved. + +Sun Aug 13 19:09:25 1995 Jeff Law (law@snake.cs.utah.edu) + + * configure (hppa1.?-hp-hpux10): Recognize and treat just like hpux9. + +Sun Aug 13 19:07:23 1995 Doug Evans + + * i960.md (movdi matchers): Fix src/dest order in unaligned + reg->reg case. + +Sun Aug 13 18:49:01 1995 DJ Delorie + + * i386/xm-dos.h (HAVE_STRERROR): New definition. + + * msdos/configur.bat: Add missing carriage return. + +Sun Aug 13 18:40:55 1995 Andrew Cagney + + * Makefile.in (USER_H): Add va-ppc.h. + +Sun Aug 13 18:36:17 1995 M. Warner Losh + + * stmt.c (expand_asm_operands): Type '0'..'4' operands may + allow regs, so move them to the default case. + +Sun Aug 13 18:32:35 1995 Paul Eggert + + * cccp.c (warning_with_line): New function. + (trigraph_pcp): Use it, to avoid reporting line number. + (vwarning_with_line): Don't report line number if zero. + +Sun Aug 13 18:23:08 1995 Jason Merrill + + * toplev.c (vmessage): Support four arguments. + +Sun Aug 13 18:19:51 1995 Michael Meissner + + * ginclude/stdarg.h: Add ppc svr4 calling sequence support. + * ginclude/varargs.h: Likewise. + * ginclude/va-ppc.h: New file. + +Sun Aug 13 18:05:20 1995 Michael Gschwind + + * configure (pdp-*-*): Add support for t-pdp11. + * t-pdp11: New file. + * Makefile.in (LIBGCC2_CFLAGS): Add TARGET_LIBGCC2_CFLAGS. + +Sun Aug 13 14:50:58 1995 Jim Wilson + + * final.c (final_start_function): Always call sdbout_begin_function + and xcoffout_begin_function, even if no line number info. + + * mips/abi64.h (SETUP_INCOMING_VARARGS): In if statement, only + subtract one for stdarg. Don't subtract PRETEND_SIZE from + argument pointer when calculating stack address. + * mips.h (INITIAL_ELIMINATION_OFFSET): For 64 bit ABI, subtract + current_function_pretend_args_size when converting from argument + pointer. + * va-mips.h (va_start): For stdarg, delete separate define for + 64 bit ABI. For varargs, don't subtract 64, and only add -8 when + all argument registers are used. + + * gcc.c (main): When concat gcc_exec_prefix and + standard_startfile_prefix, put machine_suffix in the middle. + + * iris6.h (INIT_SECTION_ASM_OP): Don't define. + (LD_INIT_SWITCH, LD_FINI_SWITCH, HAS_INIT_SECTION): Don't undef. + (ASM_OUTPUT_CONSTRUCTOR, ASM_OUTPUT_DESTRUCTOR): Ifdef out. + * configure (mips-sgi-irix6, mips-sgi-irix5cross64): Define + use_collect2 to yes. + + * combine.c (move_deaths): When have a multi-reg hard register, + if don't find a note, then recur for each individual hard register. + + * cse.c (set_nonvarying_address_components): Handle addresses + which are the sum of two constant pseudo regs. + (cse_rtx_addr_varies_p): Likewise. + + * Makefile.in (gfloat.h): Add a - before the rm command. + + * loop.c (find_and_verify_loops): Set dest_loop only if + JUMP_LABEL (insn) is non-zero. + +Mon Jul 31 14:31:53 1995 Ian Lance Taylor + + * fixincludes: Avoid clobbering VxWorks drv/netif/if_med.h file. + +Sat Jul 29 16:21:42 1995 Jason Merrill + + * collect2.c: (XCOFF_SCAN_LIBS): Define if OBJECT_FORMAT_COFF and + XCOFF_DEBUGGING_FORMAT. + (SCAN_LIBRARIES): Also define if XCOFF_SCAN_LIBS. + +Sat Jul 29 16:19:42 1995 Stuart D. Gathman + + * collect2.c (scan_libraries): Implement for AIX. + +Sat Jul 29 09:59:33 1995 Michael Gschwind + + * configure: (pdp11-*-bsd) New target. + * 2bsd.h: New file. + + * pdp11.c (output_move_double): Handle CONST_INT parameters properly. + * pdp11.h (RTX_COSTS): Fill in missing default values. + * pdp11.md (truncdfsf2, extendsfdf2, floatsidf2, fix_truncdfsi2): + Allow register parameters, required by gcc to generate correct code. + * xm-pdp11.h: Include tm.h. + +Sat Jul 29 09:55:17 1995 Andreas Schwab + + * configure (m68k-*-linux*aout*, m68k-*-linux*): New targets. + * m68k/linux-aout.h, m68k/linux.h, m68k/t-linux, m68k/xm-linux.h: New. + * m68k.md [USE_GAS]: Output `jbsr' instead of `jsr' for normal + function calls and `bsr.l' instead of `bsr' for pic function calls. + +Sat Jul 29 09:44:13 1995 Jim Wilson + + * sh.h (CAN_DEBUG_WITHOUT_FP): Comment out. + + * reload.c (find_reloads_address_1, case PLUS): When handle SUBREG, + add SUBREG_WORD offset to SUBREG_REG register number. + (find_reloads_address_1, case SUBREG): If a pseudo register inside + a SUBREG is larger than the class, then reload the entire SUBREG. + * sh.h (SUBREG_OK_FOR_INDEX_P): New macro. + (INDEX_REGISTER_RTX_P): Use it. + +Sat Jul 29 09:33:19 1995 Doug Evans + + * mips/netbsd.h (CPP_SPEC): Fix typo. + + * configure (a29k-*-vxworks*): Define extra_parts for crt{begin,end}.o. + * t-a29k, t-a29kbase, t-vx29k ({,CROSS_}LIBGCC1): Define as empty. + +Sat Jul 29 09:15:17 1995 Jeffrey A. Law + + * pa/lib2funcs.asm (gcc_plt_call): Rewrite to avoid the need + for being called by _sr4export. Inline expand $$dyncall to + avoid the need for long-call and PIC support. + +Sat Jul 29 07:30:04 1995 Oliver Kellogg (Oliver.Kellogg@space.otn.dasa.de) + + * ms1750.inc (ucim.m, ucr.m, uc.m): New. + * 1750a.md (cmpqi): Account for unsigned comparisons. + (rotrqi3, rotrhi3): Reworked. + * 1750a.c (notice_update_cc): INCM and DECM set condition codes. + (unsigned_comparison_operator, next_cc_user_is_unsigned): New fcns. + * 1750a.h (FUNCTION_EPILOGUE): Local variables freed from SP, not FP. + (ASM_OUTPUT_BYTE): Make distinct from ASM_OUTPUT_CHAR. + (ASM_OUTPUT_CONSTRUCTOR): Add FILE arg to assemble_name. + +Fri Jul 28 09:40:07 1995 Jeffrey A. Law + + * pa.h (DO_GLOBAL_DTORS_BODY): Use an asm statement to keep optimizer + from deleting an assignment it believes dead. + +Fri Jul 28 08:47:51 1995 Jim Wilson + + * unroll.c (unroll_loop): When preconditioning, output code to + execute loop once if initial value is greater than or equal to final + value. + + * configure (lang_specs_files, lang_options_files): Add $srcdir to + file names when adding them to these variables. + + * c-typeck.c (pointer_int_sum): Don't distribute if intop is unsigned + and not the same size as ptrop. + + * function.c (assign_stack_temp): When split a slot, set base_offset + and full_size in the newly created slot. + (combine_temp_slots): Update full_size when slots are combined. + + * sh.c (reg_unused_after): New function. + * sh.md (define_peephole): Add peepholes to use r0+rN addressing mode + for some address reloads. + + * final.c (final_start_function): If SDB_DEBUG, call + sdbout_begin_function. If XCOFF_DEBUG, call xcoffout_begin_function + instead of xcoffout_output_first_source_line. + (final_scan_insn): Don't call sdbout_begin_function or + xcoffout_begin_function. + * xcoffout.c (xcoffout_output_first_source_line): Delete. + (xcoffout_begin_function): Call dbxout_parms and + ASM_OUTPUT_SOURCE_LINE. + + * va-mips.h: Change every occurance of #if __mips>=3 to + #ifdef __mips64. + * mips/abi64.h (CPP_SPEC): Output -D__mips64 when -mips3, or -mips4, + or -mgp64. Output -U__mips64 when -mgp32. + * mips/dec-bsd.h, mips/elf64.h, mips/iris3.h: Likewise. + * mips/iris5.h, mips/mips.h, mips/netbsd.h, mips/osfrose.h: Likewise. + + * i960.c (i960_function_epilogue): Don't clear g14 for functions with + an argument block. + (i960_output_reg_insn): Likewise. + (i960_output_call_insn): Clear g14 for functions wtih an argument + block. + +Fri Jul 28 08:43:52 1995 Doug Evans + + * i960.c (i960_arg_size_and_align): Correct alignment of XFmode + values in library calls. + * i960.md (movdi matchers): Support odd numbered regs. + +Fri Jul 28 08:37:25 1995 Michael Gschwind + + * pdp11.md (divhi3, modhi3, divmodhi4): Rewrite. + +Wed Jul 26 10:15:52 1995 Hallvard B Furuseth (h.b.furuseth@usit.uio.no) + + * collect2.c (end_file): Fix typo in error message text. + +Wed Jul 26 09:22:22 1995 Jeff Law (law@snake.cs.utah.edu) + + * xm-pa.h (USE_C_ALLOCA): Always define. + * xm-pahpux.h (USE_C_ALLOCA): Likewise. + + * x-pa (CC): Remove useless definition. + * xm-pa.h (HAVE_STRERROR): Define. + (__BSD_NET2__): Define. + +Wed Jul 26 09:10:25 1995 Jason Merrill + + * expr.c (preexpand_calls): Don't look past a CLEANUP_POINT_EXPR. + +Wed Jul 26 08:43:42 1995 Jim Wilson + + * cse.c (cse_insn): When do special handling for (set REG0 REG1), + must delete REG_EQUAL note from insn if it mentions REG0. + + * loop.c (find_and_verify_loops): When moving blocks of code, verify + that the just destination is not in an inner nested loop. + (mark_loop_jump): Don't mark label as loop exit if it jumps to + an inner nested loop. + +Wed Jul 26 08:40:31 1995 Paul Eggert + + * cccp.c (do_include, read_name_map): Omit leading "./" and + trailing "/" when it makes sense. + (skip_redundant_dir_prefix): New function. + +Wed Jul 26 08:36:41 1995 Michael Meissner + + * stmt.c (emit_nop): Do not emit a nop if there is a single + insn before a label or at the start of a function. + +Wed Jul 26 08:21:21 1995 Doug Evans + + * Makefile.in (gfloat.h): Delete previous copy before updating. + +Wed Jul 26 08:18:29 1995 Roland McGrath + + * Makefile.in (STAGESTUFF): Add stamp-crtS. + (crtbeginS.o, crtendS.o, stamp-crtS): New rules; just like + crtbegin.o et al, but compiled using -fPIC. + * configure (*-*-gnu*): Add crtbeginS.o and crtendS.o to $extra_parts. + +Wed Jul 26 08:11:52 1995 Michael Gschwind + + * pdp11.md: Fixed typos ('bhos' -> 'bhis'). + +Wed Jul 26 08:05:41 1995 Jim Wilson + + * hp320.h, m68k.h, m68kv4.h (LEGITIMATE_PIC_OPERAND_P): Reject + CONST_DOUBLE with MEM with invalid pic address. + * reload1.c (real.h): Include it. + * Makefile.in (reload1.o): Depends on real.h. + +Wed Jul 26 07:58:22 1995 Ian Lance Taylor + + * gcc.c (MULTILIB_DIRS): Provide default if not defined. + (multilib_defaults): New static variable. + (default_arg): New static function. + (set_multilib_dir): Ignore default arguments. + (print_multilib_info): Ignore entries which use default arguments. + +Tue Jul 25 10:06:09 1995 Michael Meissner + + * rs6000.md (allocate_stack): Don't copy the LR register to + the new stack end. + * rs6000.c (rs6000_stack_info): Correctly store the LR in + the caller's frame, not the current frame, for V.4 calls. + * rs6000/eabi.asm (_save*, _rest*): Provide all mandated V.4 save + and restore functions, except for the save*_g functions which + return the GOT address. + +Fri Jul 21 14:24:25 1995 Michael Meissner + + * rs6000/eabi.h (__eabi): Load up r13 to be the small data + pointer, unless -mrelocatable. + + * rs6000/aix3newas.h (LINK_SPEC): Import machine independent + functions if -mcpu=common. + * rs6000/milli.exp: Import file referenced in aix3newas.h. + + * rs6000/eabi.asm (__eabi): Support for fixing up user initialized + pointers when -mrelocatable is used. + * rs6000/eabi.h (ASM_OUTPUT_INT): Record any pointers initialized + by the user if -mrelocatable, to be fixed up by __eabi. + (CONST_SECTION_ASM_OP): If -mrelocatable, put read-only stuff in .data, + not .rodata, to allow user initialized pointers to be updated by __eabi. + + * rs6000.h (TARGET_SWITCHES): Add -mdebug-{stack,arg}. + (TARGET_{ELF,NO_TOC,TOC}): Add defaults for non system V. + (rs6000_stack): New structure to describe stack layout. + (RS6000_{REG_SAVE,SAVE_AREA,VARARGS_*}): New macros used to + support both AIX and V.4 calling sequences. + (FP_ARG_*, GP_ARG_*): Ditto. + (FP_SAVE_INLINE): Ditto. + (STARTING_FRAME_OFFSET): Modify to support both AIX and V.4 + calling sequences. + (FIRST_PARM_OFFSET): Ditto. + (REG_PARM_STACK_SPACE): Ditto. + (STACK_POINTER_OFFSET): Ditto. + (FUNCTION_ARG_REGNO_P): Ditto. + ({,INIT_}CUMULATIVE_ARGS): Ditto. + (LEGITIMATE_LO_SUM_ADDRESS_P): Ditto. + (FUNCTION_ARG{,_ADVANCE,PARTIAL_NREGS,PASS_BY_REFERENCE}): Ditto. + (SETUP_INCOMING_VARARGS): Ditto. + (EXPAND_BUILTIN_SAVEREGS): Ditto. + (CAN_ELIMINATE): Ditto. + (INITIAL_ELIMINATION_OFFSET): Ditto. + (LEGITIMATE_CONSTANT_POOL_{BASE,ADDRESS}_P): Ditto. + (GO_IF_{LEGITIMATE_ADDRESS,MODE_DEPENDENT_ADDRESS}): Ditto. + (LEGITIMIZE_ADDRESS): Ditto. + (CONST_COSTS): Ditto. + (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P): Ditto. + (ASM_OUTPUT_REG_{PUSH,POP}): Use reg_names to print registers. + (function declarations): Add new rs6000.c function declarations, + and delete decls of deleted functions. + (SHIFT_COUNT_TRUNCATED): Parenthesize the expression. + + * rs6000.c (init_cumulative_args): New function to support AIX + and V.4 calling sequences. + (function_arg{,_advance,partial_nregs,pass_by_reference}): Ditto. + (setup_incoming_varargs): Ditto. + (expand_builtin_saveregs): Ditto. + (rs6000_stack_info): Ditto. + (debug_stack_info): Ditto. + (direct_return): Changes to support AIX and V.4 calling sequences. + (first_reg_to_save): Ditto. + (svr4_traceback): Ditto. + (output_{prolog,epilog}): Ditto. + (print_operand): Use reg_names to print registers. Add support + for V.4 HIGH/LO_SUM address modes. + (must_save_cr): Function deleted, in rewrite of AIX/V.4 calling + sequence support. + (rs6000_sa_size): Ditto. + (rs6000_pushes_stack): Ditto. + (output_toc): Add abort if no toc. + + * rs6000.md (call insns): Add a new argument to flag a V.4 + function needs to set bit 6 of the CR. + (elf_{low,high}): New V.4 functions to create addresses via HIGH + and LO_SUM patterns. + (movsi): Use elf_{low,high} if appropriate. + (mov{si,di}_update): Name these patterns for allocate_stack. + (allocate_stack): Support for V.4 stack layout. + (sync): New pattern for V.4 trampolines to issue the sync + instruction. + + * rs6000/sysv4.h (TARGET_SWTICHES): Add -mcall-{aix,sysv}, and + -mprototype. Remove separate flag bit for -mno-toc. + (SUBTARGET_OVERRIDE_OPTIONS): Don't test for -mno-toc. + (FP_ARG_*): Adjust for V.4 calling sequences. + (RS6000_*): Ditto. + (FP_SAVE_INLINE): Ditto. + (toc_section): Eliminate use of AIX style full TOC. + (TRAMPOLINE_{TEMPLATE,SIZE}): Redefine for V.4 support. + (INITIALIZE_TRAMPOLINE): Ditto. + + * rs6000/eabi.h (CPP_SPEC): Define _CALL_SYSV or _CALL_AIX, + depending on whether -mcall-sysv or -mcall-aix was used. + * rs6000/eabile.h (CPP_SPEC): Ditto. + * rs6000/sysv4le.h (CPP_SPEC): Ditto. + + * rs6000/t-eabigas (MULTILIB_{OPTIONS,DIRNAMES}): Delete no-toc + libraries, explicit big endian libraries. + * rs6000/t-ppcgas (MULTILIB_{OPTIONS,DIRNAMES}): Ditto. + + * rs6000/t-eabiaix: New file for eabi, using -mcall-aix as the + default. + * rs6000/eabiaix.h: Ditto. + + * rs6000/t-eabilegas: New file for eabi on little endian systems. + * rs6000/t-ppclegas: New file for V.4 on little endian systems. + + * rs6000/t-rs6000 (MULTILIB_{OPTIONS,DIRNAMES}): Build libgcc.a + for -mcpu=common. + + * configure (powerpc-*-eabiaix): New configuration for defaulting + to old-style AIX calling sequence. + (powerpcle*): Use new t-{eabi,ppc}legas files, to avoid building + explicit little endian multilib libraries. + +Fri Jul 21 13:23:06 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * toplev.c (main): Don't define sbrk #ifdef __alpha__. + +Tue Jul 18 19:23:44 1995 Paul Eggert + + * cccp.c (do_include): Prefix -H output lines with spaces, not dots. + (output_dots): Remove. + + * cccp.c (main): cplusplus_comments now defaults to 1. + But clear it if -traditional or the new option -lang-c89 is given. + * gcc.c (default_compilers, cpp): Specify -lang-c89 if -ansi is given. + This turns off C++ comment recognition. + +Tue Jul 18 19:16:38 1995 Jim Wilson + + * va-sparc.h (va_arg): Add support for 128 bit long double type. + +Tue Jul 18 19:11:18 1995 Jorn Rennecke (amylaar@meolyon.hanse.de) + + * c-common.c (decl_attributes, case A_ALIGNED): Handle is_type + case properly. + +Tue Jul 18 19:03:02 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * fold-const.c (fold, case CONVERT_EXPR): Don't merge conversions + if outer is to handle a type with differing precision. + +Mon Jul 17 14:37:35 1995 Pat Rankin (rankin@eql.caltech.edu) + + * vax/vms.h (HAVE_ATEXIT): Define. + (DO_GLOBAL_CTORS_BODY): Don't call atexit; let __do_global_ctors do it. + * vax/xm-vms.h (HAVE_VPRINTF): Define. + +Mon Jul 17 06:41:19 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * c-typeck.c ({unsigned,signed}_type): Handle intXX_type_node types. + + * xm-alpha.h (sbrk): Add declaration. + + * convert.c (convert_to_integer): If TYPE is a enumeral type or + if its precision is not the same as the size of its mode, + convert in two steps. + + * m68k.md (tstdi, cmpdi): Use match_scratch, not match_operand. + +Fri Jul 14 19:23:42 1995 Andreas Schwab + + * c-decl.c (field_decl_cmp): Rewritten to make sure that a null + name always sorts low against other names. + * c-typeck.c (lookup_field): Change name comparison to match what + field_decl_cmp does. + +Fri Jul 14 18:46:24 1995 Michael Meissner + + * rs6000.md (movsi): Convert a CONST_DOUBLE into a CONST_INT of + the low part. + +Fri Jul 14 18:30:52 1995 Doug Evans + + * toplev.c (main): Reword dwarf/c++/-g warning. + +Fri Jul 14 18:19:34 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.h (NO_DEFER_POP): Remove last change. + * expr.c (stor_expr): Force stack adjust before NO_DEFER_POP. + (expand_expr, case COND_EXPR): Likewise. + * stmt.c (expand_start_stmt_expr): Likewise. + +Fri Jul 14 07:58:35 1995 Jim Wilson + + * function.c (struct temp_slot): New fields base_offset, full_size. + (assign_stack_temp): For !FRAME_GROWS_DOWNWARD, set p->size to size. + Set new fields base_offset and full_size. + (combine_temp_slots): Use new fields base_offset and full_size instead + of slot and size. + + * loop.c (loop_number_exit_count): New global variable. + (loop_optimize): Allocate space for it. + (find_and_verify_loops, mark_loop_jump): Set it. + (strength_reduce, check_dbra_loop): Use loop_number_exit_count + instead of loop_number_exit_labels. + * loop.h (loop_number_exit_count): Declare it. + * unroll.c (find_splittable_{regs,givs}, final_[bg]iv_value): Use + loop_number_exit_count instead of loop_number_exit_labels. + (reg_dead_after_loop): Check loop_number_exit_count, and fail + if the count doesn't match loop_number_exit_labels. + + * cse.c (cse_insn): Ifdef out code that pre-truncates src_folded. + + * sparc.md (sethi_di_sp64): Return null string at end. + + * function.h (struct function): Add stdarg field. + * function.c (current_function_stdarg): New global variable. + (push_function_context_to): Save it. + (pop_function_context_from): Restore it. + (assign_parms): Set it. + (init_function_start): Clear it. + * output.h (current_function_stdarg): Declare it. + * i960.md: Modify all patterns which handle stores to memory to also + check current_function_varargs and current_function_stdarg. + + * reorg.c (fill_simple_delay_slots): When trying to take instruction + from after the branch, don't continue past target label. Local + variables passed_label and target_uses are no longer necessary. + +Thu Jul 13 19:30:04 1995 Jeff Law (law@snake.cs.utah.edu) + + * pa.c (output_bb): Fix error in long backwards branch with + nullified delay slot. + +Thu Jul 13 19:26:13 1995 Jim Wilson + + * expmed.c (SHIFT_COUNT_TRUNCATED): Use #ifdef not #if. + +Mon Jul 10 20:16:44 1995 Paul Eggert + + * cccp.c (rescan): Don't address outside of array when + preprocessing C++ comments. + +Mon Jul 10 20:05:46 1995 Michael Meissner + + * rs6000.c (expand_block_move): Remove #if 0 conditionals + against using larger block moves. + + * t-rs6000 (EXTRA_PARTS): Copy milli.exp to release dir. + (milli.exp): Copy to build dir from machine dependend dir. + +Mon Jul 10 20:03:29 1995 Richard Earnshaw (rearnsha@armltd.co.uk) + + * arm.md (matcher for (shiftable_op (cond-exp) (reg))): If + shiftable_op is minus, then subtract from zero when cond fails. + +Mon Jul 10 19:58:26 1995 John F. Carr + + * sparc.h (SELECT_SECTION): Use TREE_CODE_CLASS instead of directly + referencing tree_code_type. + +Mon Jul 10 19:54:31 1995 Jim Wilson + + * protoize.c (reverse_def_dec_list): Delete const qualifiers from + local variables, and delete casts which were casting away const. + +Mon Jul 10 19:14:39 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * c-lang.c (finish_file): Add missing parm to start_function call. + + * jump.c (jump_optimize): Pass outer_code arg to rtx_cost. + + * varasm.c (assemble_name, bc_assemble_integer): Call + bc_emit_labelref with proper args. + + * function.c (setjmp_args_warning): Remove bogus arg. + +Mon Jul 10 18:20:54 1995 Fergus Henderson (fjh@cs.mu.oz.au) + + * gcc.c (p{fatal,error}_with_name, perror_exec): Quote filename. + +Mon Jul 10 18:12:51 1995 Gran Uddeborg (uddeborg@carmen.se) + + * i386/iscdbx.h (STARTFILE_SPEC): Handle -Xp. + +Wed Jul 5 02:42:17 1995 Per Bothner (bothner@spiff.gnu.ai.mit.edu) + + * cpphash.h (enum node_type): Remove unneeded and non-standard + forward declaration. + +Sat Jul 1 20:15:39 1995 Jim Wilson + + * mips/t-mips, mips/t-mips-gas (MULTILIB_*, LIBGCC, INSTALL_LIBGCC): + Delete. + + * sparc/sol2.h (LINK_SPEC): Revert March 16 change. Do not add -R + for each -L. + + * collect2.c (libcompare): Verify that file name extensions are valid. + Put files with invalid extensions last in the sort. + + * integrate.c (integrate_decl_tree): Set DECL_ABTRACT_ORIGIN before + pushdecl call for local variables. + +Sat Jul 1 08:13:38 1995 Richard Earnshaw (rearnsha@armltd.co.uk) + + * cpplib.c (output_line_command): If not emitting #line directives + delay returning until after adjust_position has been called. + + * arm.md (mov{si,sf,df}cc): Call gen_compare_reg to generate + the condition code register. + +Sat Jul 1 06:55:09 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * fold-const.c (decode_field_reference): New parm PAND_MASK. + (unextend): New parm MASK. + (fold_truthop): Pass new parms to decode_field_reference and unextend. + + * va-alpha.h (__va_tsize): Use __extension__ to avoid warning + on use of `long long'. + + * expr.h (NO_DEFER_POP): Do any pending stack adjusts. + + * recog.c (register_operand): Disallow subreg of reg not allowed to + change size. + +Thu Jun 29 05:51:57 1995 Jeff Law (law@snake.cs.utah.edu) + + * pa.md (reload addsi3): New pattern to avoid reload lossage + with register eliminations. + + * pa.c (output_cbranch): When checking for a jump to the given + insn's delay slot, handle the case where JUMP_LABEL for the + given insn does not point to the first label in a series of + labels. + (output_bb, output_dbra, output_movb): Likewise. + +Wed Jun 28 18:04:56 1995 Jeff Law (law@snake.cs.utah.edu) + + * pa.h (PIC_OFFEST_TABLE_REGNUM_SAVED): Define to %r4. + (CONDITIONAL_REGISTER_USAGE): Make it fixed when compiling + PIC code. + (INIT_EXPANDERS): Delete. + * pa.c (hppa_save_pic_table_rtx): Delete variable. + (hppa_expand_prologue): For PIC generation, copy the PIC + register into a fixed callee register at the end of the + prologue of non-leaf functions. + * pa.md (call expanders): Reload the PIC register from the + fixed callee saved register. Don't try to save the PIC + register before the call. + +Wed Jun 28 18:01:14 1995 Stan Cox (coxs@dg-rtp.dg.com) + + * m88k/dguxbcs.h (ASM_SPEC): Removed -h flag. + * m88k/dgux.h (ASM_SPEC): Likewise. + +Wed Jun 28 17:01:58 1995 David Edelsohn + + * rs6000.c (processor_target_table): Remove CPU name synonyms. + * rs6000.h (CPP_SPEC): Likewise. + * rs6000/sysv4.h (CPP_SPEC): Likewise. + (ASM_SPEC): Likewise. + * rs6000/sysv4le.h (CPP_SPEC): Likewise. + * rs6000/eabile.h (CPP_SPEC): Likewise. + * rs6000/powerpc.h (CPP_SPEC): Likewise. + (ASM_SPEC): Set assembler target according to compiler target. + * rs6000/aix3newas.h (CPP_SPEC): Likewise. + (ASM_SPEC): Likewise. + * rs6000/aix41.h (CPP_SPEC): Likewise. + (ASM_SPEC): Likewise. + +Wed Jun 28 16:25:53 1995 Gran Uddeborg (uddeborg@carmen.se) + + * i386/x-isc3 (INSTALL_HEADERS_DIR): Delete; done by configure. + +Wed Jun 28 16:10:47 1995 Philippe De Muyter (phdm@info.ucl.ac.be) + + * xm-rs6000.h (alloca): Extern decl added for non-GNU compiler. + +Wed Jun 28 11:31:30 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * cpplib.c (progname): Remove definition from here. + + * final.c (final_scan_insn): Fix error in last change. + + * rtlanal.c (reg_set_p_1): Now static; add extra parm. + + * stmt.c: Delete redundant forward decls. + (expand_anon_union_decl): Correctly call expand_decl. + + * toplev.c (strip_off_ending): Strip off any ending; don't + pretend we know what valid endings are. + + * svr4.h (ASM_OUTPUT_SECTION_NAME): Don't crash if DECL is null. + + * rs6000.md ({load,store}_multiple): Don't use indirect_operand + in define_insn; use explicit MEM of register_operand instead. + +Tue Jun 27 11:42:56 1995 Stephen L Moshier + + * i386/i386.c (print_operand, case `J'): Use jns for GE and js for + LT. + +Tue Jun 27 07:58:55 1995 Jason Merrill + + * expr.c (expand_expr, TARGET_EXPR): Only use original_target + if !ignore. + +Tue Jun 27 07:27:26 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * fold-const.c (fold_truthop): Commute unextend and convert on + l_const and r_const. + + * c-common.c (decl_attributes, case A_CONSTRUCTOR, A_DESTRUCTOR): + Set TREE_USED. + + * final.c (final_scan_insn): Don't call alter_cond unless + condition is on cc0. + + * stmt.c (expand_asm_operands): Handle input operands that may not + be in a register. + +Mon Jun 26 19:23:05 1995 Richard Earnshaw (rearnsha@armltd.co.uk) + + * arm/lib1funcs.asm (L_dvmd_tls): Renamed from L_divmodsi_tools. + * arm/t-semi (LIB1ASMFUNCS): Rename _dvmd_tls from _divmodsi_tools. + +Mon Jun 26 19:18:06 1995 Jim Wilson + + * unroll.c (find_splittable_regs): When completely unrolling loop, + check for non-invariant initial biv values. + +Mon Jun 26 19:13:54 1995 Gran Uddeborg + + * configure (i[345]86-*-isc*): Fix misspelled "rfile" to "ifile". + +Mon Jun 26 18:58:22 1995 Mike Stump + + * expr.c (expand_expr, case COND_EXPR): Protect the condition from + being evaluated more than once. + (do_jump, case TRUTH_ANDIF_EXPR, TRUTH_ORIF_EXPR): Likewise. + +Mon Jun 26 18:52:36 1995 Philippe De Muyter (phdm@info.ucl.ac.be) + + * fixincludes (string.h): Fix return value for mem{ccpy,chr,cpy,set} + and str{len,spn,cspn} on sysV68. + +Mon Jun 26 06:54:50 1995 Michael Meissner (meissner@cygnus.com) + + * i386/osfrose.h (LONG_DOUBLE_TYPE_SIZE): Go back to making long + double == double. + +Thu Jun 22 19:14:41 1995 Pat Rankin (rankin@eql.caltech.edu) + + * make-cc1.com (if DO_LINK): Skip c-parse.* processing when + only relinking. + (gas_message): Update to reflect current version, and give + a different message if/when no version of gas is found.xo + +Thu Jun 22 18:52:37 1995 Richard Earnshaw (rearnsha@armltd.co.uk) + + * arm/lib1funcs.asm (___modsi3): Correctly set SIGN register for + modulo involving negative numbers. + +Thu Jun 22 18:32:27 1995 Uwe Seimet (seimet@chemie.uni-kl.de) + + * xm-atari.h (HZ): Now 100 and don't define if already defined. + +Thu Jun 22 18:26:12 1995 Jeffrey A Law (law@snake.cs.utah.edu) + + * calls.c (expand_call): Correctly handle returning BLKmode + structures in registers when the size of the structure is not + a multiple of word_size. + * stmt.c (expand_return): Likewise. + + * pa-gux7.h (LIB_SPEC): Undefine before redefining. + * pa-hpux.h (LIB_SPEC): Likewise. + * pa-hpux7.h (LIB_SPEC): Likewise. + + * genmultilib: Work around hpux8 /bin/sh case bug. + + * pa.h (LIB_SPEC): Define to avoid -lg. + +Thu Jun 22 18:19:09 1995 Jason Merrill + + * expr.c (expand_expr, TARGET_EXPR): Use original_target. + + * collect2.c (locatelib): Fix parsing of LD_LIBRARY_PATH. + +Thu Jun 22 18:15:54 1995 Paul Eggert + + * configure: Create an empty Makefile.sed first, to work + around a Nextstep 3.3 bug. + +Thu Jun 22 18:03:44 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * Makefile.in (STAGESTUFF): Add stamp-crt. + (crtbegin.o, crtend.o): Now depend on stamp-crt. + (stamp-crt): New rule, to actually build crt{begin,end}.o. + + * collect2.c (main): Unlink export_file before we return. + +Thu Jun 22 14:25:56 1995 Michael Meissner (meissner@cygnus.com) + + * rs6000.h (STRIP_NAME_ENCODING): Store NAME and strlen(NAME) into + local variables; cast result of alloca to avoid compiler warnings. + +Tue Jun 20 18:25:29 1995 Douglas Rupp (drupp@cs.washington.edu) + + * alpha/config-nt.sed, i386/config-nt.sed: Edit to add + a missing $(exeext) for CCCP. + +Tue Jun 20 18:18:00 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * protoize.c (default_include): Use name and two ints to be + compatible with definition of INCLUDE_DEFAULTS. + +Mon Jun 19 19:24:29 1995 Ted Lemon + + * mips/netbsd.h (ASM_DECLARE_FUNCTION_NAME): Don't emit function label. + +Mon Jun 19 18:34:55 1995 Jason Merrill + + * fixincludes: Don't define wchar_t under C++. + +Mon Jun 19 17:12:41 1995 Paul Eggert + + * cccp.c (collect_expansion): Work around enum bug in vax + ultrix 4.3 pcc. + * tree.c (simple_cst_equal): Likewise. + +Mon Jun 19 16:53:00 1995 Douglas Rupp (drupp@cs.washington.edu) + + * winnt/spawnv.c: New file. + +Mon Jun 19 16:30:29 1995 Glenn Brown + + * caller-save.c (save_call_clobbered_regs): If AUTO_INC_DEC, mark + register indicated by REG_INC notes as live so they will be saved. + +Mon Jun 19 16:21:12 1995 Jeffrey A Law (law@snake.cs.utah.edu) + + * pa.h (PRINT_OPERAND_ADDRESS, case LOW_SUM): Fix logic bug + in last change. + +Mon Jun 19 14:11:49 1995 Jim Wilson + + * integrate.c (integrate_decl_tree): Only set DECL_ABSTRACT_ORIGIN + if the decl returned by pushdecl is the one we started with. + + * mips.h (current_function_name): Delete declaration. + (ASM_DECLARE_FUNCTION_NAME): Don't set current_function_name. + * gnu.h (ASM_DECLARE_FUNCTION_NAME): Likewise. + * mips.c (current_function_decl): Delete declaration. + (function_prologue): New variable fnname. Use it instead of + current_function_name. + (function_epilogue): Likewise. + +Mon Jun 19 13:13:15 1995 Richard Kenner + + * alpha.h (ASM_OUTPUT_ASCII): Always reset line count when + starting new line. + + * scan-decls.c (scan_decls): Fix typo when resetting PREV_ID_START. + + * i386/config-nt.sed, alpha/config-nt.sed: Change version to 2.7.1. + +Mon Jun 19 13:06:14 1995 DJ Delorie (dj@delorie.com) + + * msdos/top.sed: Support new build variables. + * msdos/configur.bat: Make options.h and specs.h. + Change realclean to maintainer-clean. + +Fri Jun 16 06:54:03 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * Version 2.7.0 Released. + + * obstack.c: Always enable this code for now. + + * alpha.c (alpha_builtin_saveregs): Use ptr_mode and conversions + when need so works for both OSF and NT. + * va-alpha.h (__va_tsize): Round to long long not long. + +Thu Jun 15 17:54:52 1995 Bdale Garbee + + * configure (a29k-*-coff): Synonym for a29k-*-udi. + +Thu Jun 15 17:51:21 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * function.c (assign_parms): Do all conversions in CONVERSION_INSNS. + +Thu Jun 15 17:36:49 1995 Michael Meissner + + * reg-stack.c (record_reg_life): Call record_reg_life_pat with 0 + for douse argument so that USE's created to mark variables within + blocks don't get marked as set. + +Thu Jun 15 06:28:15 1995 Dennis Glatting (dennisg@CyberSAFE.COM) + + * configure: Change one sed command to work around m68k-next bug. + +Wed Jun 14 22:14:39 1995 Jason Merrill + + * collect2.c (main): Don't turn off auto_export because of -g. + (main): Ignore the argument to -o. + + * alpha.h (LINK_SPEC): Don't pass -init __main anymore. + * alpha/osf12.h (LINK_SPEC): Ditto. + * mips/iris5.h (LINK_SPEC): Ditto. + + * collect2.c (main): Place o_file after an initial .o (like crt0.o). + If we have LD_INIT_SWITCH, use init and fini functions for + executables, too. Specify the unique function names. + (write_c_file_stat): Fix the case of destructors but no constructors. + Don't include the generic-named functions for executables. + (write_c_file): If we have LD_INIT_SWITCH, always use + write_c_file_stat. + + * collect2.c (main): Also add _GLOBAL__D? to export list. + + * ginclude/iso646.h: Do nothing if compiled as C++. + +Wed Jun 14 17:39:10 1995 Roland McGrath (roland@gnu.ai.mit.edu) + + * c-common.c (format_char_info, case 'm'): Set type to void. + (check_format_info): If type is void, ignore operand. + +Wed Jun 14 17:04:10 1995 Paul F. Kunz (Paul_Kunz@SLAC.Stanford.EDU) + + * expr.c (expand_builtin_apply_args): Put back original + register save and restore order. + +Wed Jun 14 16:56:22 1995 Michael Meissner + + * rs6000/eabi.h (INVOKE__main): Define, so __eabi is called after + main's arguments are saved. + + * rs6000.c (output_prolog): Don't call __eabi here, let + compiler call it after the arguments to main are saved. + (output_{prolog,epilog}): Don't use functions under V.4 to save + and restore floating point registers. + +Wed Jun 14 16:52:12 1995 Philippe De Muyter (phdm@info.ucl.ac.be) + + * m68k/mot3300.h (PCC_BITFIELD_TYPE_MATTERS): Defined. + +Wed Jun 14 16:48:53 1995 Jerry Frain (jerry@tivoli.com) + + * Makefile.in (stage[1-4]): Correctly link `as', `ld', and `collect2'. + +Wed Jun 14 05:52:04 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * objc-act.c (hack_method_prototype): Set DECL_CONTEXT of parms. + + * expmed.c (emit_store_flag): Always set LAST. + + * c-decl.c (start_function): New parameter for attributes. + * c-tree.h (start_function): Likewise. + * c-lang.c (finish_file): Pass extra parm to start_function. + * objc-act.c (build_module_descriptor, really_start_method): Likewise. + * c-parse.in (fndef, nested_function, notype_nested_function): + Likewise. + + * function.c (assign_parms): Use convert_to_mode instead of + gen_lowpart when converting incoming parm. + +Tue Jun 13 19:10:32 1995 Richard Kenner + + * rs6000.md (decrement_and_branch): Finish last fix; update matching + constraint. + +Tue Jun 13 18:32:51 1995 Torbjorn Granlund + + * fold-const.c (fold): When converting a COND_EXPR to an ABS_EXPR, + get the types right for ABS_EXPR to work. + +Mon Jun 12 17:09:55 1995 Michael Tiemann (tiemann@axon.cygnus.com) + + * reorg.c (fill_simple_delay_slots): Set MAYBE_NEVER according to + code of TRIAL_DELAY, not TRIAL. + +Mon Jun 12 15:02:37 1995 Doug Evans + + * configure: Restore code to make ld symlink if ! use_collect2. + + * gcc.c (link_command_spec): Undo patch of May 11. + -nostdlib implies -nostartfiles again. + * dsp16xx.h (CROSS_LINK_SPEC): Likewise. + * i386/freebsd.h (LINK_SPEC): Undo patch of May 24. + Don't pass "-e start" if nostdlib. + * i386/sun.h (LINK_SPEC): Likewise. + * m68k/sun2o4.h (LINK_SPEC): Likewise. + * m68k/sun3.h (LINK_SPEC): Likewise. + * m68k/vxm68k.h (LINK_SPEC): Likewise. + * mips/netbsd.h (LINK_SPEC): Likewise. + * config/netbsd.h (LINK_SPEC): Likewise. + * rs6000/mach.h (LINK_SPEC): Likewise. + * sparc.h (LINK_SPEC): Likewise. + * sparc/vxsparc.h (LINK_SPEC): Likewise. + + * gcc.c (link_command_spec): New argument -nodefaultlibs. + +Sun Jun 11 20:47:53 1995 Stephen L Moshier (moshier@world.std.com) + + * Makefile.in (fix-header.o): Depends on xsys-protos.h. + +Sun Jun 11 15:07:58 1995 Tim Carver (timc@ibeam.intel.com) + + * reload1.c (emit_reload_insns): Don't call HARD_REGNO_NREGS + on psuedo when clearing reg_last_reload_reg. + +Sun Jun 11 14:07:05 1995 Philippe De Muyter (phdm@info.ucl.ac.be) + + * m68k.md ({add,sub}di{_mem,3}): Patterns merged. + +Sun Jun 11 13:43:26 1995 Torbjorn Granlund + + * m68k.md (cmpdi matcher): Set cc_status before returning. + + * config/xm-freebsd.h (DONT_DECLARE_SYS_SIGLIST): Define. + +Sun Jun 11 13:38:49 1995 Jason Merrill + + * fixincludes (math.h): Keep declaration of abs on HPUX. + +Sun Jun 11 12:31:42 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * stor-layout.c (variable_size): Do nothing if SIZE is constant. + + * stmt.c (expand_asm_operands): See if output operand permits + register. If not, mark output addressable, call expand_operand + on it, and give error if not MEM. + + * function.c (assign_parms): Handle promotions of both + passed and nominal modes separately and insert needed conversions. + (promoted_input_arg): Return 0 if nominal and passed modes differ. + + * stmt.c (all_cases_count, case INTEGER_TYPE): Fix typo in checking + for integer bounds. + +Sat Jun 10 08:55:25 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * libgcc2.c (_floatdidf): Correctly set float sizes. + + * c-decl.c (c_decode_option, case "-Wall"): Don't set extra_warnings. + + * Makefile.in (cpplib.o, fix-header.o): Update dependencies. + (cpperror.o, cppexp.o, cpphash.o): New rules, to show .h dependencies. + +Fri Jun 9 18:06:10 1995 Doug Evans + + * cse.c (cse_basic_block): Fix test for whether block ends with a + barrier. Return next insn, not 0, if block ends in a barrier. + +Fri Jun 9 17:58:29 1995 Paul Eggert + + * fold-const.c (lshift_double): Replace `&' with `%' to fix typo. + ([lr]shift_double): Truncate shift count only if SHIFT_COUNT_TRUNCATED. + Remove unnecessary `count >= prec' test. + + * cexp.y (left_shift): Ignore integer overflow. + + * cexp.y (skip_evaluation): New variable. + (&&, ||, ?:): Increment it in unevaluated subexpressions. + (/, %, integer_overflow): Suppress diagnostics if skip_evaluation != 0. + (yyerror): Clear skip_evaluation. + +Fri Jun 9 17:49:05 1995 Torbjorn Granlund + + * m68k.md (tstdi): Rewrite. + +Fri Jun 9 17:28:55 1995 Per Bothner + + * scan-decls.c (scan_decls): Handle declarations with + multiple comma-separated declarators. + +Thu Jun 8 19:16:12 1995 Richard Earnshaw (rearnsha@armltd.co.uk) + + * arm.md (mov[sd]f expands): Don't allow fp constants in pseudos + when TARGET_SOFT_FLOAT. + +Thu Jun 8 19:11:43 1995 Jim Wilson + + * expmed.c (store_split_bit_field): When adjust arg in + BYTES_BIT_ENDIAN case, use number of bits in arg for MEM operands + and BITS_PER_WORD for other operands. + (extract_fixed_bit_field): Undo last change. + + * unroll.c (verify_addresses): New function. + (find_splittable_givs): Use it instead of memory_address_p. + +Thu Jun 8 18:58:18 1995 Torbjorn Granlund + + * expmed.c (expand_divmod): Always check result of emit_store_flag. + +Thu Jun 8 12:02:34 1995 David D Zuhn (zoo@armadillo.com) + + * cpplib.c (cpp_push_buffer): Include filename in error message. + +Thu Jun 8 11:53:45 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * function.c (assign_parms): Don't call promote_mode on arg + unless PROMOTE_FUNCTION_ARGS defined. + + * rs6000.md (decrement_and_branch): Ensure label is operand 0. + + * rs6000.md (aux_truncdfsf2): New pattern. + (movsf): Use it instead of invalid SUBREG and truncdfsf2. + + * varasm.c (assemble_name): Disable warn_id_clash around + get_identifier call. + +Wed Jun 7 17:22:25 1995 Philippe De Muyter (phdm@info.ucl.ac.be) + + * configure (gdb_needs_out_file_path): New variable. + (m68k-motorola-sysv): Set gdb_needs_out_file_path if not using gas. + (.gdbinit): If gdb_needs_out_file_path is set, add a 'dir' command + for $(out_file). + +Wed Jun 7 17:17:19 1995 Torbjorn Granlund + + * fold-const.c (fold): When folding `<' type nodes, make true_value + and false_value have correct types. + +Wed Jun 7 05:06:42 1995 Jason Merrill + + * collect2.c (COFF scan_prog_file): Use the AIX duplicate entry. + +Tue Jun 6 18:43:09 1995 Jeffrey A Law (law@snake.cs.utah.edu) + + * pa.h (FUNCTION_ARG_CALLEE_COPIES): Define. + +Tue Jun 6 18:21:18 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (expand_expr, case PLACEHOLDER_EXPR): Consider two types + identical if their TYPE_MAIN_VARIANTs are the same. + + * c-decl.c (start_decl): Set DECL_COMMON before calling + decl_attributes. + + * a29k.c (print_operands): Cast args to bcopy to char *. + + * c-decl.c (duplicate_decls): Don't clear DECL_CONTEXT of + new decl if it is a function. + +Tue Jun 6 17:57:44 1995 Eberhard Mattes (mattes@azu.informatik.uni-stuttgart.de) + + * gcc.c (do_spec_1, case 'g'): Handle %O as suffix if MKTEMP_EACH_FILE. + +Tue Jun 6 17:53:05 1995 Michael Meissner + + * rs6000.c (expand_block_move): Update source and destination pointers + inside the loop moving the bytes, not outside. + +Tue Jun 6 14:58:37 1995 Andreas Schwab + + * m68k.h (CONDITIONAL_REGISTER_USAGE): Don't mark pic reg as fixed. + * m68k.c (finalize_pic): Emit USE insn at start and end of function. + +Tue Jun 6 13:46:57 1995 Jim Wilson + + * sh.c (print_operand): Check for annulled branches. + (output_movedouble): Handle SUBREG addresses. + (output_branch): Handle annulled branches. + (sh_expand_prologue): Correct number of saved registers for + varargs functions. + * sh.h: Add some comments. + * sh.md: Add some comments. Cleanup formatting. + (type attribute): Add pstore and call. + (return define_delay): Reorganize to make clearer. + (call/sfunc define_delay): Define. + (cbranch define_delay): Define to have annul-true delay slot. + (subsi3): Use arith_reg_operand for operand 2. + (shift patterns): Use const_int_operand instead of immediate_operand + for shift counts. + (push): Add pstore constraint case. + (movsi_i): Move t/z constraint pair to the front of the list. + (calli, call_valuei): Add "call" attribute. + +Mon Jun 5 19:23:13 1995 Jim Wilson + + * sched.c (attach_deaths): In last change, use find_reg_note instead + of find_regno_note. + +Mon Jun 5 19:17:31 1995 Tom Quiggle (quiggle@lovelace.engr.sgi.com) + + * mips/iris5.h (MACHINE_TYPE): Say "IRIX 5.x", not "5.0". + (NO_DOLLAR_IN_LABEL): Undefine. + * mips.h (sdb_begin_function_line): New declaration. + (PUT_SDB_FUNCTION_END): New definition. + +Mon Jun 5 18:56:10 1995 Michael Meissner + + * rs6000.c (expand_block_move): Don't do block moves where we clobber + fixed numbers of regs, instead move just 1-8 bytes at a time. + + * Makefile.in (STAGESTUFF): Copy files produced by -da and + -save-temps to the stage subdirectories. + +Mon Jun 5 08:18:46 1995 Torbjorn Granlund + + * combine.c (reg_dead_at_p): When scanning backwards, stop at BARRIER. + + * m68k.c (print_operand): Handle 'R' for registers. + * m68k.md (cmpdi): Rewrite to avoid bogus matching constraints. + + * optabs.c (expand_binop): In last change, don't defererence TARGET + if it is 0. + + * pa.md (movsicc): Use MATCH_DUP for operand 4 and 5. + +Mon Jun 5 08:14:56 1995 Jeffrey A Law (law@cs.utah.edu) + + * pa.c (hppa_encode_label): Allocate stuff on permanent_obstack + rather than via malloc. + + * c-common.c (decl_attributes): Fix typo in size passed to alloca. + +Mon Jun 5 08:10:55 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * alpha.md: Use "some_operand" for patterns valid only during + reload and meant to handle adding more PLUS operators during + register elimination. + +Mon Jun 5 07:31:53 1995 Stephen L Moshier (moshier@world.std.com) + + * cse.c (simplify_unary_operation, case FLOAT, UNSIGNED_FLOAT): + Truncate to requested mode. + +Sat Jun 3 22:08:51 1995 Jim Wilson + + * sched.c (attach_deaths): Don't add a REG_DEAD note if a REG_UNUSED + note is already present. + +Sat Jun 3 18:36:57 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * pa.h (hppa_builtin_saveregs): Add declaration. + +Sat Jun 3 18:11:26 1995 Jason Merrill + + * Makefile.in (scan-decls.o): Depends on cpplib.h. + +Fri Jun 2 19:23:47 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * optabs.c (expand_binop): Don't use non-REG TARGET in 2-word case. + +Thu Jun 1 19:30:30 1995 Tor Egge (tegge@flipper.pvv.unit.no) + + * m88k.h (RETURN_POPS_ARGS): New argument. + * m88k/dolphin.ld: Added start of comment. + +Thu Jun 1 19:12:28 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * configure (a29k-*-bsd*): Fix typo in last change. + +Thu Jun 1 18:51:53 1995 Jim Wilson + + * expmed.c (extract_fixed_bit_field): For REG case, compute total_bits + from mode instead of assuming BITS_PER_WORD. + +Thu Jun 1 18:34:31 1995 Michael Meissner + + * rs6000.h (FIXED_R13): Default to 0. + ({FIXED,CALL_USED}_REGISTERS): Use FIXED_R13 for register 13. + * sysv4.h (FIXED_R13): Define to be 1. + +Wed May 31 20:57:26 1995 Torbjorn Granlund + + * m68k.md ([su]mulsi3_highpart): Pass correct number of arguments to + const_uint32_operand. + * m68k.c (const_uint32_operand): Reject negative numbers. + + * expmed.c (expand_mult_highpart): Use wide_op1 for all multiplies. + (expand_divmod): Undo Nov 12 change. Instead, add special case + for division by MIN_INT in signed TRUNC_DIV_EXPR case. + +Wed May 31 20:44:21 1995 Philippe De Muyter (phdm@info.ucl.ac.be) + + * m68k.md (one_cmpldi2): New pattern. + ({a,l}shrdi{3,_const}): Allow 63 as shift count. + +Wed May 31 14:56:31 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * varasm.c (assemble_start_function, assemble_variable): + Make sure first_global_object_name is in permanent obstack. + + * reload1.c (alter_reg): Clean up setting of RTX_UNCHANGING_P + when making a MEM. + + * reorg.c (struct resources): New field unch_memory. + (CLEAR_RESOURCES, mark_target_live_regs, dbr_schedule): Clear it. + (mark_{referenced,set}_resources, redundant_insn): Set it. + (fill_simple_delay_slots): Likewise. + (resource_conflicts_p): Test it. + + * unroll.c (copy_loop_body): Fix typo in call to sets_cc0_p. + + * integrate.c (output_inline_function): Don't call expand_function_end. + + * calls.c (prepare_call_address): Only call use_reg on + static_chain_rtx if it is a REG. + + * configure (a29k-*-bsd*): Use t-a29k. + * t-a29k: New file. + * a29k/t-a29kbare (LIBGCC1_TEST): New null definition. + * a29k/t-vx29k (LIBGCC1_TEST): Likewise. + +Wed May 31 14:17:42 1995 Jeffrey A Law (law@snake.cs.utah.edu) + + * configure (hppa*-*-bsd*): Do not run fixincludes. + (hppa*-*-osf*): Likewise. + (hppa*-*-lites*): Likewise. + + * pa.h (PRINT_OPERAND_ADDRESS): Use "RR'" rather than "R'" for + symbolic addresses. + * pa.md (symbolic HIGH patterns): Likewise. + (symbolic LO_SUM pattern): Likewise. + +Wed May 31 14:11:53 1995 Michael Meissner + + * rs6000.md (all movstri recognizers): Eliminate updating the pointers. + * rs6000.c (expand_block_move): Don't pass argument of # bytes to + increment pointers by to movstrsi expanders. + + * rs6000.c (rs6000_override_options): Fix typo with -mstring handling. + + * rs6000.h (TARGET_SWITCHES): Set MASK_STRING_SET explicitly + if -mno-string, so that it can override the processor default. + +Wed May 31 07:31:53 1995 Jason Merrill + + * c-common.c (truthvalue_conversion, BIT_AND_EXPR): Make sure that + the result has boolean_type_node. + +Tue May 30 19:03:21 1995 J.T. Conklin + + * stddef.h: Undefine _BSD_XXX_T_ if _GCC_XXX_T is defined on BSD + Net/2 derived systems. + +Tue May 30 08:17:37 1995 Philippe De Muyter (phdm@info.ucl.ac.be) + + * m68k.md (decrement_and_branch_until_zero): Operand 0 constraint + changed from "+g" to "+d*am". + (similar anonymous HImode pattern): Likewise. + + * m68k.md (tstdi): Use tst/subx #0 instead of neg/negx. + Allow "a" and ">" for operand 0. + +Mon May 29 19:24:43 1995 Niklas Hallqvist (niklas@appli.se) + + * m68k.md (addsi_lshrsi_31): Use match_dup, not constraint "1", + for matching inputs. + +Mon May 29 12:39:58 1995 Allen Briggs + + * i386/isc.h ({STARTFILE,LIB,CPP}_SPEC): Handle -Xp like -posix. + * i386/x-isc3 (X_CFLAGS): Add -Xp. + +Mon May 29 12:28:41 1995 J.T. Conklin (jtc@cygnus.com) + + * configure (sparc-*-netbsd): Add missing asterisk at end. + +Mon May 29 08:55:48 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * combine.c (recog_for_combine): New parm PADDED_SCRATCHES; set it. + (try_combine): Accumulate number of scratches and update max_scratch. + (simplify_set): Add extra parm to recog_for_combine. + + * romp.md (call): Put USE for r0 in CALL_INSN; call call_internal + to emit insn. + (call_internal): New name for anonymous call. + (call_value, call_value_internal): Likewise. + + * winnt/xm-winnt.h: Protect most definitions with #ifndef. + * alpha/xm-winnt.h: Include alpha/xm-alpha.h, then winnt/xm-winnt.h. + (POSIX): Undefine. + * xm-alpha.h: Don't include alloca.h for winnt. + +Sun May 28 18:34:01 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * configure: Make sed commands more uniform. + + * Makefile.in: Properly use $(srcdir) for files that have it + in their reference as a target of a rule. + (libgcc1.a): Add missing RANLIB_TEST use. + + * stmt.c (expand_computed_goto): Call do_pending_stack_adjust. + +Sun May 28 18:08:41 1995 Torbjorn Granlund + + * m68k.md (divmodhi4, udivmodhi4): Use "dmsK" for operand 2. + +Fri May 26 17:01:22 1995 Paul Eggert + + * fixincludes: Fix bogus recursive in NEWS-OS 4.0C. + +Fri May 26 08:02:14 1995 Michael Meissner (meissner@cygnus.com) + + * c-typeck.c (initializer_constant_valid_p): For the CONSTRUCTOR + case, if the type is a record, recurse, just like for unions. + +Thu May 25 07:56:14 1995 Paul Eggert + + * fixincludes: Add `sel', `tahoe', `r3000', `r4000' to the + list of pre-ANSI symbols that need to be surrounded with __ __. + Allow white space between `#' and `if' when looking for lines to patch. + + * objc/sarray.h (PRECOMPUTE_SELECTORS, struct soffset): + Use #ifdef __sparc__, not sparc. + + * m68k.md (addsi_lshrsi_31, ashldi_const, ashrdi_const, lshrdi_const): + Replace `mov' with `move'. + +Thu May 25 07:35:37 1995 Allen Briggs + + * libgcc2.c (L_eh, i386): Remove in-line comments in assembly + code--the '#' character is not valid for the SYSV as. + +Thu May 25 07:28:54 1995 Pat Rankin (rankin@eql.caltech.edu) + + * Makefile.in (BC_ALL): Restore it from May 22 change; vms uses it. + (STAGESTUFF): Use it. + +Thu May 25 07:11:56 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * alpha.c (alpha_emit_set_const): Don't call expand_binop for + other than add if SImode and can't create pseudos. + +Wed May 24 21:38:24 1995 Jim Wilson + + * sched.c (reemit_notes): New function. + (schedule_block): Call reemit_notes twice. Reorganize code for + handling SCHED_GROUP_P insns, so that reemit_notes works. + + * sh/sh.c (shiftcosts, genshifty_op): Add SH3 support. + * sh/sh.md (ashlsi3, lshrsi3): Add SH3 support. + (ashlsi3_d, ashrsi3_d, lshrsi3_d): New patterns for SH3. + (ashrsi2_31): Remove r/!r constraint. + +Wed May 24 17:00:47 1995 Jason Merrill + + * tree.c (type_list_equal): Call simple_cst_equal before checking + types. + +Wed May 24 16:49:49 1995 Douglas Rupp (drupp@cs.washington.edu) + + * Makefile.in (libgcc2.a): Handle case of separate srcdir. + +Wed May 24 16:22:01 1995 Paul Eggert + + * configure: Define $(MAKE) if `make' doesn't. + +Wed May 24 15:50:51 1995 Doug Evans + + * dsp16xx.h (CROSS_LINK_SPEC): ENDFILE_SPEC moved to -nostartfiles. + * i386/freebsd.h (LINK_SPEC): Don't pass "-e start" if nostartfiles + rather than nostdlib. + * i386/sun.h (LINK_SPEC): Likewise. + * m68k/sun2o4.h (LINK_SPEC): Likewise. + * m68k/sun3.h (LINK_SPEC): Likewise. + * m68k/vxm68k.h (LINK_SPEC): Likewise. + * mips/netbsd.h (LINK_SPEC): Likewise. + * config/netbsd.h (LINK_SPEC): Likewise. + * rs6000/mach.h (LINK_SPEC): Likewise. + * sparc.h (LINK_SPEC): Likewise. + * sparc/vxsparc.h (LINK_SPEC): Likewise. + + * m88k/m88k.h (FUNCTION_ARG_BOUNDARY): Use GET_MODE_BITSIZE. + +Wed May 24 15:44:04 1995 Jason Merrill + + * fold-const.c (fold): Make sure that a folded TRUTH_NOT_EXPR + retains the same type. + + * c-common.c (truthvalue_conversion): Also accept TRUTH_NOT_EXPR. + +Wed May 24 15:41:51 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * cplus-dem.c (strstr, strncmp, strlen): Remove declarations. + + * tree.c (type_list_equal, simple_cst_list_equal, index_type_equal): + Check for simple_cst_equal return value of -1. + +Wed May 24 10:05:24 1995 Michael Meissner + + * libgcc1-test.c (start, _start): Provide declarations, so that + the GNU linker doesn't give a warning message about defaulting the + start address. + + * rs6000/sysv4.h (STRIP_NAME_ENCODING): Redefine back to the + original defination, rather than the defination used in rs6000.h. + (ASM_OUTPUT_SOURCE_LINE): Use STRIP_NAME_ENCODING. + * rs6000.h (STRIP_NAME_ENCODING): Skip leading '*'. + + * rs6000.h (MASK_STRING_SET, TARGET_STRING_SET): Add target + flags bit for whether -mstring was actually used. + (TARGET_SWITCHES): Add MASK_STRING to all power targets. Set + MASK_STRING_SET for -mstring and -mno-string. + (TARGET_DEFAULT): Add MASK_STRING. + + * rs6000.c (rs6000_override_options): Add MASK_STRING to + all power targets. Make an explicit -mstring/-mno-string override + the -mcpu=processor default. + + * rs6000/eabile.h (CPP_SPEC): Copy from sysvle.h to provide the + appropriate little endian defaults. + + * rs6000/sysv4.h (ASM_OUTPUT_SOURCE_LINE): Use assemble_name to + output the canonical name. + +Wed May 24 01:21:15 1995 Jason Merrill + + * rs6000.h (STRIP_NAME_ENCODING): Define. + (RS6000_OUTPUT_BASENAME): Use it. + +Tue May 23 19:54:21 1995 Doug Evans + + * gcc.c (link_command_spec): Move ENDFILE_SPEC from -nostdlib + to -nostartfiles. + +Tue May 23 17:01:50 1995 Jim Wilson + + * alpha.md (negsi2-2): Change output pattern to #. + + * mips.c (embedded_pic_offset): Output RTL to initialize + embedded_pic_fnaddr_rtx. + (mips_finalize_pic): Delete. + * mips.h (mips_finalize_pic): Delete declaration. + (FINALIZE_PIC): Delete. + (INIT_EXPANDERS): Clear embedded_pic_fnaddr_rtx. + * mips.md (get_fnaddr): Add = to output contraint. + + * sh.c (shift_amounts): Correct entry for shifts by 29. + * sh.md (sett): New pattern. + (movsi_i): Change source constraint for move to T reg to be 'z'. + + * mips/ecoff.h (STARTFILE_SPEC): Define to null string. + * mips/elfl.h, mips/elfl64.h: Correct typo in comment. + + * mips/elflorion.h, mips/elforion.h (MIPS_CPU_DEFAULT): Delete. + * mips.c (override_options): Delete #ifdef MIPS_CPU_DEFAULT code. + Add #ifdef MIPS_CPU_DEFAULT_STRING code before the first + mips_cpu_string test. + +Tue May 23 07:22:36 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * romp.c (hash_rtx): Avoid warning on int-to-pointer conversion. + (output_fpops): Cast args to bcopy to char *. + + * cpplib.c (initialize_builtins): Add missing parm to timestamp call. + + * Makefile.in (install-libobjc): Don't depend on libobjc.a. + + * c-parse.in: Objc shift/reduce conflicts now 48. + (parm): Use setspecs/restore here. + (parmlist_or_identifiers): Not here. + +Mon May 22 19:30:30 1995 Doug Evans + + * h8300.md (movsf_h8300h): Add missing post-inc case to constraints. + +Mon May 22 14:38:36 1995 Michael Meissner + + * rs6000.c (rs6000_override_options): Do SUBTARGET_OVERRIDE_OPTIONS + here. + * rs6000.h (OVERRIDE_OPTIONS): Not here. + + * rs6000.c (expand_block_move): Handle moves without string + instructions by generating a series of loads and stores. + (output_prolog): Support -mno-toc on V.4 and eabi systems. + + * rs6000/sysv4.h (TARGET_SWITCHES): Add -mtoc and -mno-toc. + (SUBTARGET_OVERRIDE_OPTIONS): Add some warnings for incompatible + switches. + (TOC_SECTION_FUNCTION): Make -mno-toc like -mrelocatable in that + we don't put the minimal toc pointer in the global toc section. + (LINK_SPEC): Use -oformat to set link output format, not -m. + + * rs6000/t-eabigas (MULTILIB_OPTIONS, MULTILIB_DIRNAMES): Build + libgcc.a variants with -mno-toc support. + * rs6000/t-ppcgas (MULTILIB_OPTIONS, MULTILIB_DIRNAMES): Ditto. + +Mon May 22 07:10:52 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * cplus-dem.c (mystrstr): Replacement for strstr. + + * configure: Split up long sed command. + * Makefile.in (SYMLINK): Deleted; unused. + (oldobjext): Deleted; no longer used. + (FLAGS_TO_PASS): Include objext and exeext. + (STAGESTUFF, protoize.o, unprotoize.o): Use $(objext), not .o. + (test_protoize_simple, compare{,3}, gnucompare{,3}): Likewise. + (STAGESTUFF, specs, gcc-cross, collect2): Add missing $(exeext). + (libgcc1.null, libgcc[12].a, stage[1-4]): Likewise. + (xgcc, cc1, cc1obj, enquire): Use $@ instead of filename for -o value. + (collect2, mips-tfile, mips-tdump, gen*): Likewise. + (bi-arity, bi-opcode, bi-opname, cccp, cppmain): Likewise. + (protoize, unprotoize, gen-protos, fix-header): Likewise. + (crtbegin.o, crtend.o): Don't use -o; move output to proper + filename (using objext) instead. + (BI_ALL, BC_ALL, bytecode): Deleted; unused. + (bi-*.o, cexp.o, stamp-{proto,fixinc}): Remove unneeded $(srcdir). + (getopt{,1}.o, SYSCALLS.c.X): Likewise. + (install-driver): New target. + (install-normal): Depend on it. + (install-common): Don't depend on xgcc. + (maketest): Deleted; no longer used. + (stage[1-4]): Use name collect-ld, not real-ld. + (risky-stage[1-4]): Use stage[1-4] as dependencies; don't copy. + * alpha/config-nt.bat, i386/config-nt.bat: Make {,h,t}config.h + and tm.h by writing a single #include line. + Update way specs.h and options.h are written. + * alpha/config-nt.sed, i386/config-nt.sed: Set new variables + into Makefile. + Build winnt.obj. + Edit CCCP definition. + * alpha/x-winnt, i386/x-winnt (oldobjext): Deleted. + Add rules for .c.obj, .adb.obj, and .ads.obj. + (LIB2FUNCS_EXTRA, spawnv.o): New rules. + * i386/x-winnt (objext): Now .obj, not .o. + + * gcc.c (HAVE_OBJECT_SUFFIX): New macro. + (process_command): Convert x.o to x.foo for OBJECT_SUFFIX of ".foo". + (do_spec_1): Avoid shadow variable "i" and always use for loop var. + + * c-decl.c (finish_decl_top_level): Removed; no longer used. + * objc-act.c: Numerous formatting changes. + (NULLT): Deleted; all uses changed to NULL_TREE. + (get_{static,object}_reference, objc_add_static_instance): + Use push_obstacks instead of saving obstacks manually. + (build_{selector,class}_reference_decl): Likewise. + (build_objc_string_decl, build_protocol_reference): Likewise. + (comp_{method,proto}_with_proto): Likewise. + (create_builtin_decl, synth_module_prologue): Set DECL_ARTIFICIAL + for internal objects. + (build_{selector,class}_reference_decl, add_objc_decls): Likewise. + (generate_objc_symtab_decl, build_module_descriptor): Likewise. + (build_protocol_reference): Likewise. + (build_objc_string_decl, synch_forward_declarations): Likewise. + Delete call to end_temporary_allocation. + (generate_static_references, generate_strings): Likewise. + (build_selector_translation_table, generate_category): Likewise. + (generate_{ivars,protocol}_list, build_protocol_reference): Likewise. + (build_objc_string_object): If next_runtime, put everything in + permanent obstack. + (objc_add_static_instance): Use build_decl instead of start_decl + and finish_decl_top_level. + (build_{class_reference,objc_string}_decl): Clear DECL_CONTEXT. + (start_class): Exit with FATAL_EXIT_CODE, not 1. + (add_objc_decls): Don't set DECL_IN_SYSTEM_HEADER. + + * tree.c (valid_machine_attribute): Handle attribute on + pointer-to-function types. + +Sun May 21 17:16:37 1995 J. T. Conklin + + * mips/netbsd.h (HAVE_STRERROR): Remove. + * mips/xm-netbsd.h: New file. + * mips/t-mips-netbsd: Deleted. + * configure (mips-dec-netbsd): Use xm-netbsd.h and t-libc-ok. + +Sun May 21 17:16:37 1995 Arne H. Juul (arnej@pvv.unit.no) + + * mips/netbsd.h: Use __start as entry point. Ifdef some + paths on CROSS_COMPILE. + +Sun May 21 08:39:26 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * c-parse.in (datadef, fndef, ivar_decl, mydecls): + Restore declspec_stack since setspecs is used. + (parmlist_or_identifiers): Use setspecs before parsing parms + and restore after parsing parms. + +Sun May 21 01:04:52 1995 Jeffrey A. Law + + * pa.c (hppa_encode_label): New variable "permanent" to + where/how memory is allocated for the new label. All + callers changed. + +Sat May 20 16:53:30 1995 Mike Meissner + + * rs6000.md (insv, extz): Fail if the structure is QI or HI reg to + avoid paradoxical subreg's being created in RTL phase, which uses + SImode to load from memory if structure is later moved to stack. + +Sat May 20 06:44:59 1995 Philippe De Muyter (phdm@info.ucl.ac.be) + + * m68k.md (udivmodhi4): Output "divu" instead of "divs". + +Sat May 20 06:11:32 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * reload.c (push_reload): Don't reload inside a SUBREG + when SUBREG_WORD is nonzero. + + * c-decl.c (shadow_tag_warned): Don't warn about useless keyword + if in system header file. + + * tree.c (simple_cst_equal): Don't look at language-specific + nodes since we don't know what's in them. + + * cpperror.c: #include config.h before any other .h file. + * collect2.c: Likewise. + + * i386/config-nt.bat: Add missing ^M on two lines. + Add case for Fortran; fix typo in Ada case. + * alpha/config-nt.bat: Add case for Fortran; fix typo in Ada case. + + * m68k/t-next (LIBGCC1, CROSS_LIBGCC1): Make not, not "libgcc1.null". + (OTHER_FIXINCLUDES_DIRS, LIMITS_H_TEST): Delete from here. + * m68k/x-next (OTHER_FIXINCLUDES_DIR, LIMITS_H_TEST): Move to here. + +Fri May 19 19:30:20 1995 Stan Cox (gcc@dg-rtp.dg.com) + + * crtstuff.c: Added reference to INIT_SECTION_PREAMBLE for systems that + do something which must be undone prior to __do_global_ctors. + +Fri May 19 19:27:08 1995 Alan Modra + + * i386/linux-aout.h (CPP_SPEC): Add defines for -fPIC. + * i386/linux-oldld.h (CPP_SPEC): Likewise. + +Fri May 19 17:46:28 1995 Philippe De Muyter (phdm@info.ucl.ac.be) + + * collect2.c (strstr): Deleted. + * cplus-dem.c (strstr): Define ifndef POSIX. + +Fri May 19 11:16:51 1995 Per Bothner + + * cpplib.c (collect_expansion): Don't escape '@' inside string. + +Fri May 19 06:59:21 1995 Pat Rankin (rankin@eql.caltech.edu) + + * vmsconfig.com (process_objc_lib, configure_makefile): New routines. + (bc_all.list, ./vax.md, objc-objs.opt, objc-hdrs.list): New files + created at config time. + (bc_all.opt, ./md.): No longer created. + * make-cc1.com: Handle revised filenames from vmsconfig.com; + (DO_OBJCLIB): New variable, plus code to compile objc/*.{c,m}. + +Wed May 17 16:15:31 1995 Torbjorn Granlund + + * i960.c (i960_output_ldconst): New code for XFmode. + Also, move SFmode code to immediately after DFmode code. + (S_MODES, D_MODES): Handle XFmode. + (XF_MODES): Was TF_MODES, handle XFmode instead of TFmode. + (hard_regno_mode_ok): Replace TFmode with XFmode. + (i960_output_long_double): New function. + + * i960.h (DATA_ALIGNMENT): Define. + (ROUND_TYPE_ALIGN): Align XFmode scalars at 128 bit boundaries. + (ROUND_TYPE_SIZE): Round up the size of XFmode objects to 128 bits. + (CONST_DOUBLE_OK_FOR_LETTER_P): Use CONST0_RTX and CONST1_RTX + so that all FP modes are recognized. + (ASM_OUTPUT_LONG_DOUBLE): Define. + + * i960.md: Change all TFmode patterns to have XFmode. + (movxf recognizer, frame version): Use movt, ldt, and stt. + (movxf recognizer, non-frame version): Delete. + (extenddfxf2): Delete * before f constraint. + (extendsfxf2): Likewise. + +Wed May 17 17:53:35 1995 Jim Wilson + + * unroll.c (unroll_loop): Increment copy_start_luid if copy_start + is loop_start. + +Wed May 17 17:44:57 1995 Lee Iverson + + * fold-const.c (invert_truthvalue, case CLEANUP_POINT_EXPR): New case. + +Tue May 16 18:51:16 1995 Michael Meissner + + * rs6000/rs6000.h (TARGET_SWITCHES): Add -mstring to enable string + instructions, and -mno-string to disable them. + (MOVE_MAX): Don't test TARGET_MULTIPLE anymore. + (MAX_MOVE_MAX): Set to 8, not 16. + (expand_block_move): Add declaration. + + * rs6000/rs6000.c (expand_block_move): New function to expand + block moves when -mstring is used. + + * rs6000/rs6000.md (movti): Use TARGET_STRING, not TARGET_MULTIPLE. + (load_multiple, store_multiple): Ditto. + (string insns): Add 8, 6, 4, 2, and 1 register variants for using + the native string instructions if -mstring. + + * rs6000/sysv4.h (CPP_SPEC): If little endian, define + _LITTLE_ENDIAN and set littleendian assertion. If big endian, + define _BIG_ENDIAN and set bigendian assertion. + * rs6000/sysv4le.h (CPP_SPEC): Copy from sysv4.h, and change + default to little endian. + + * rs6000/rs6000.c (override_options): Check for -mmultiple and + -mstring on little endian systems here. + * rs6000/sysv4.h (SUBTARGET_OVERRIDE_OPTIONS): Don't do the check + here. + +Tue May 16 18:36:41 1995 Douglas Rupp (drupp@cs.washington.edu) + + * alpha.c: Changed WINNT to _WIN32. + * alpha/config-nt.bat, i386/config-nt.bat: Added commands to + generate specs.h and options.h. + * i386/config-nt.sed: Changed link32 to link. + * winnt/ld.c (main): Removed call to free. + * configure.bat: Added line to echo usage on invalid input. + * gcc.c (fix_argv): Removed call to free. + * gcc.c, getpwd.c, protoize.c, sdbout.c: Changed WINNT to _WIN32. + * toplev.c: Likewise. + +Tue May 16 18:04:47 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * toplev.c (pfatal_with_name, fatal_io_error, vfatal): + Use FATAL_EXIT_CODE instead of magic number. + * cccp.c, cpplib.c, cpplib.h: Use FATAL_EXIT_CODE instead + of FAILURE_EXIT_CODE. + * fix-header.c, gen-protos.c: Likewise. + * cpperror.c, cppmain.c: Likewise. + Include config.h #ifndef EMACS. + * xm-alpha.h, xm-rs6000.h, xm-vms.h (FAILURE_EXIT_CODE): Remove. + +Tue May 16 17:46:57 1995 Adam Fedor + + * objc/archive.c (__objc_write_class): Write class version. + (__objc_write_selector, objc_{write,read}_selector): Handle null + selector. + + * objc/sarray.h (struct sarray): Make capacity size_t. + * objc/sarray.c (sarray_realloc): Make array index variables size_t. + +Tue May 16 06:59:08 1995 Paul Eggert + + * dsp16xx.c (print_operand_address): Fix misspellings in messages. + * i370/mvs.h (FUNCTION_PROFILER): Likewise. + * mips-tdump.c (type_to_string): Likewise. + * print-tree.c (print_node): Likewise. + + * protoize.c (edit_fn_definition): Fix mispelled local `have_flotsam'. + + * objc/sendmsg.c (__objc_init_install_dtable): Fix misspelling + in name of local label `already_initialized'. + + * winnt/winnt.h (STDC_VALUE): Was misspelled. + + * m68k/ccur-GAS.h (FUNCTION_BOUNDARY): Was misspelled. + + * 1750a.h (DEFAULT_PCC_STRUCT_RETURN): Was misspelled. + +Mon May 15 23:41:25 1995 Jeffrey A. Law + + * pa.h (ASM_OUTPUT_EXTERNAL_LIBCALL): Make sure to encode section + info for all libcalls. + +Mon May 15 20:58:00 1995 Jason Merrill + + * collect2.c (strstr): Define ifndef POSIX. + + * defaults.h (SUPPORTS_WEAK): Provide default. + * aoutos.h, sparc/sunos4.h: Don't support weak symbols. + * netbsd.h, svr4.h, i386/freebsd.h, i386/osfrose.h, + m88k/m88k.h: Define ASM_WEAKEN_LABEL instead of WEAK_ASM_OP. + * c-pragma.h: Check ASM_WEAKEN_LABEL instead of WEAK_ASM_OP. + HANDLE_PRAGMA_WEAK is never defined in a tm.h file. + * c-decl.c (duplicate_decls): Propagate DECL_WEAK. + * tree.h (DECL_WEAK): New macro. + (tree_decl): Add weak_flag. + * varasm.c (assemble_start_function): Declare the symbol weak if + appropriate. + (assemble_variable): Ditto. + (assemble_alias): Ditto. Mark the decl as written. + (declare_weak): Check for weak declaration after definition. + Set DECL_WEAK. + (weak_finish): Use ASM_WEAKEN_LABEL. + * libgcc2.c: The C++ free-store management functions are weak + aliases on targets that always support them. + +Mon May 15 19:01:43 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * configure (out_object_file): New variable; put value in Makefile. + * Makefile.in (out_object_file): Use in place of aux-output.o. + + * fold-const.c (const_binop): Don't pass OVERFLOW to force_fit_type + if type is unsigned. + +Mon May 15 18:48:26 1995 Paul Eggert + + * install.sh (transformbasename): Fix misspelling. + + * tahoe.h (CHECK_FLOAT_VALUE): Fix misspelling of OVERFLOW parameter. + + * i386.h (VALID_MACHINE_{DECL,TYPE_ATTRIBUTE): Fix typo. + + * fx80.h (CHECK_FLOAT_VALUE): Fix misspelled use of parameter. + + * a29k.c (spec_reg_operand): Fix misspelling of `default:'. + +Mon May 15 18:36:41 1995 Philippe De Muyter (phdm@info.ucl.ac.be) + + * m68k.md (b{eq,ne,ge,lt}0_di): Fixed for non-MOTOROLA syntax. + * m68k/xm-mot3300.h (alloca): Extern decl added for non-GNU compiler. + +Mon May 15 13:14:29 1995 Per Bothner + + * cppexp.c (cpp_reader): Test for '#' (start of assertion) *after* + skipping hspace, not before. + +Mon May 15 08:13:54 1995 Pat Rankin (rankin@eql.caltech.edu) + + * vmsconfig.com: Construct options.h and specs.h to #include + all "*/lang-{options|specs}.h" files found. + +Sun May 14 21:32:49 1995 Doug Evans + + * alpha/alpha.md (movsicc, case NE): Don't generate unrecognizable + insn. + (movdicc, case NE): Likewise. + +Sun May 14 15:44:54 1995 Jim Wilson + + * unroll.c (unroll_loop): Make local_regno have size + max_reg_before_loop. Don't do local register optimization if + copy_end has no INSN_LUID. + +Sun May 14 10:38:23 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * objc-act.c (start_method_def): Mark _self as possibly unused. + + * configure: Create specs.h and options.h from */lang-specs.h + and */lang-options.h. + Set lang_specs_files and lang_options_file variables in Makefile. + * Makefile.in (lang_{specs,options}_files): New variables. + (gcc.o): Depends on $(lang_specs_files). + (toplev.o): Depends on $(lang_options_file); merge two dep lists. + (distclean): Remove spes.h and options. + * gcc.c (default_compilers): Remove entries for Ada, C++, Chill, + and Fortran; #include specs.h instead. + * toplev.c (lang_options): Remove entries for Ada, C++, and Fortran; + include options.h instead. + +Sat May 13 23:11:21 1995 DJ Delorie + + * configure (i[345]86-go32-msdos, i[345]86-*-go32): New targets. + +Sat May 13 10:58:38 1995 Jim Wilson + + * loop.c (record_giv): When computing replaceable, use + back_branch_in_range_p instead of looking for branches to named + labels. + * loop.h (back_branch_in_range_p): Declare. + * unroll.c (back_branch_in_range_p): No longer static. + +Sat May 13 06:47:11 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * combine.c (simplify_shift_count, case LSHIFTRT): Don't merge + shifts of different modes if first is any right shift. + +Sat May 13 05:39:09 1995 Richard Earnshaw (rearnsha@armltd.co.uk) + + * configure (arm-semi-aout): New configuration. + * config.sub: Add support for semi-hosted ARM. + * arm/t-semi, arm/semi.h: New files. + +Fri May 12 21:51:22 1995 Doug Evans + + * flow.c (find_basic_blocks): Only perform n_basic_blocks sanity + check on first pass, and on second pass ensure it has the correct + value. + +Fri May 12 19:23:11 1995 Jim Wilson + + * c-typeck.c (build_binary_op): Warn when ~unsigned is compared + against unsigned, and type promotions result in an unexpected + answer. + +Fri May 12 19:10:21 1995 Roland McGrath + + * configure (*-*-gnu*): Always use ELF; set tm_file=${cpu_type}/gnu.h. + * config/i386/gnu.h: Contents replaced with old i386/gnuelf.h. + * config/i386/gnuelf.h: File removed. + +Fri May 12 17:29:57 1995 Ken Raeburn (raeburn@cygnus.com) + + * m68k/lb1sf68.asm (__IMMEDIATE_PREFIX__): Default to #. + (IMM): New macro. + (all code): Use IMM macro instead of hardcoding # for immediate + operands. + +Fri May 12 16:52:10 1995 Philippe De Muyter (phdm@info.ucl.ac.be) + + * m68k.c (output_scc_di): New function. + (extend_operator) : Allow DImode target. + * m68k.h (HARD_REGNO_MODE_OK): Don't allow d7/a0 as DImode reg pair. + * m68k.md (tstdi, cmpdi, addsi_lshrsi_31, ashldi_extsi): New patterns. + (extendqidi2, extendhidi2, extendsidi2): Allow "general_operand" + instead of "register_operand" 0. + (adddid_sexthishl32, subdid_sexthishl32, subdi_dishl32): Likewise. + (adddi_dilshr32): Operand 0 constraint changed from "ro" to "do"; + Code generation fixed. + (adddi_mem, subdi_mem): Fixed for "<" and ">" operand 0. + (adddi3, subdi3): Operand 2 constraint changed from "ao" to "*ao" + (ashldi_sexthi, ashrdi_const32): Allow only "register_operand" + instead of "general_operand" 0. + (ash[lr]di_const, ash[lr]di3): Allow also 8 and 16 as shift count. + (subreg1ashrdi_const32): Pattern deleted. + (subreghi1ashrdi_const32, subregsi1ashrdi_const32): New pattern. + (lshrsi_31): New implementation. + (scc0_di, scc_di, beq0_di, bne0_di, bge0_di, blt0_di): New patterns. + +Fri May 12 16:50:49 1995 Jeffrey A. Law + + * pa.md (bb patterns): Fix bugs in length computation exposed by + recent branch shortening and genattrtab changes. + +Fri May 12 16:22:27 1995 Ken Raeburn + + * cccp.c (enum node_type): Add T_IMMEDIATE_PREFIX_TYPE. + (special_symbol): Handle it; emit value of IMMEDIATE_PREFIX. + (IMMEDIATE_PREFIX): Default to empty string. + (initialize_builtins): Install __IMMEDIATE_PREFIX__ builtin, + parallel to __REGISTER_PREFIX__. + +Fri May 12 14:40:03 1995 Pat Rankin (rankin@eql.caltech.edu) + + * cccp.c: #if VMS, don't define `stat' macro to be VMS_stat. + Compare enums explicitly to 0 to work around VAX C bug. + (do_include): Cast alloca's value. + + * make-cc1.com (bc_loop): Process comma-separated list rather + than space-separated one; restore .h suffix stripped by vmsconfig; + (loop1): More robust handling of directory prefix on file names. + * vmsconfig.com (TPU makefile.in): Reorganize and reformat code. + Make generated .opt files have more consistent format (all comma + separated, excess whitespace eliminated); + (additional_compiler): New routine. + (process_makefile): Use it to handle cc1plus via cp/Make-lang.in. + +Fri May 12 13:35:07 1995 Doug Evans + + * arm.h: Replace ARM_REG_PREFIX with REGISTER_PREFIX. + Replace ARM_COMMENT_CHAR with ASM_COMMENT_START. + (REGISTER_PREFIX): Define. + (USER_LABEL_PREFIX, LOCAL_LABEL_PREFIX): Define. + (SECONDARY_OUTPUT_RELOAD_CLASS): Handle DFmodes only if + TARGET_HARD_FLOAT. + (PREDICATE_CODES): Add soft_df_operand. + * arm.c: Replace ARM_REG_PREFIX with REGISTER_PREFIX. + Replace ARM_COMMENT_CHAR with ASM_COMMENT_START. + (arm_asm_output_label): Use USER_LABEL_PREFIX. + (soft_df_operand): New function. + * arm.md (movsicc): New pattern. + (movsfcc, movdfcc, *movsicc_insn, *movsfcc_hard_insn): Likewise. + (*movsfcc_soft_insn, *movdfcc_insn): Likewise. + (*movdf_soft_insn): Rewrite. + (movsi matcher): Fix typo in type attribute. + +Fri May 12 10:25:40 1995 Michael Meissner (meissner@cygnus.com) + + * i386.h (TARGET_RTD): Use MASK_RTD, not MASK_REGPARM. + (TARGET_SWITCHES): Add -m{,no-}align-double switch. + (TARGET_OPTIONS): Add -mregparm= switch to set number of registers + to use for passing arguments. Add -malign-loops= switch to set + the alignment for loops. Add -malign-jumps= switch to set the + alignment for code that is jumped to. Add -malign-functions= + switch to set the initial alignment of functions. + (TARGET_REGPARM): Delete, in favor of -mregparm= + (TARGET_SWITCHES): Delete -mregparm, add -mdebug-arg switches. + (RETURN_POPS_ARGS): Call i386_return_pops_args to do the real work. + (VALID_MACHINE_DECL_ATTRIBUTE): Define as function call. + (VALID_MACHINE_TYPE_ATTRIBUTE): Define as function call. + (COMP_TYPE_ATTRIBUTES): Define as function call. + (REGPARM_MAX): Maximum number of regs to use for passing arguments. + (CUMULATIVE_ARGS): Make this a structure, not an int. + (INIT_CUMULATIVE_ARGS, FUNCTION_ARG{,_ADVANCE}): Call function. + (FUNCTION_ARG_PARTIAL_NREGS): Likewise. + (MAX_CODE_ALIGN): Maximum value to align loops/jumps to. + (BIGGEST_ALIGNMENT): Return 64 if -malign-double, 32 otherwise. + (ASM_OUTPUT_ALIGN_CODE): Use value of -malign-jumps= switch. + (ASM_OUTPUT_LOOP_ALIGN): Use value of -malign-loops= switch. + (toplevel): Declare all new functions and external variables added + in i386.c. + + * i386.c (i386_regparm_string, i386_regparm): New variables + for -mregparm= switch to set the number of registers to use for + passing arguments. + (i386_align_loops_string, i386_align_loops): New variables for + -malign-loops= switch to set alignment to use for loops. + (i386_align_jumps_string, i386_align_jumps): New variables for + -malign-jumps= switch to set alignment to use for labels that are + jumped to. + (override_options): Support new switches. + (i386_valid_decl_attribute_p): New function to validate decl + specific attributes. Presently returns 0. + (i386_valid_type_attribute_p): New function to validate type + specific attributes. Recognize "stdcall", which says function + with fixed numbers of arguments is responsible for popping stack, + "cdecl", which says to use the normal C calling sequence, even if + -mrtd is used, and "regparm", which specifies the number of + registers to use for passing arguments. + (i386_comp_type_attributes): New function, to validate whether + attributes are compatible. + (i386_return_pops_args): New function, to return whether or not + the function pops its argument list or not, taking into account + -mrtd, and the stdcall/cdecl attributes. + (init_cumulative_args): Rewrite as a function, taking variable + argument functions, and regparm support into account. + (function_arg{,_advance,_partial_nreg}): Likewise. + (print_operand): Support %J, to print appropriate jump insn. + + * i386.md (decrement_and_branch_until_zero): Define pattern, + so that loops that count down to zero, don't have an unneeded + compare after the decrement. Add a general insn recognizer for + add to a value and compare against zero. + + * i386/go32.h, i386/winnt.h (VALID_MACHINE_DECL_ATTRIBUTE): + Delete, code folded into the mainline. + (RETURN_POPS_ARGS): Likewise. + + * i386/winnt.h (ENCODE_SECTION_INFO): The stdcall attribute is now + stored on the type field, rather than the decl. + + * i386/gas.h (ASM_OUTPUT_ALIGN_CODE, ASM_OUTPUT_LOOP_ALIGN): Use + i386_align_{loops,jumps} variables to do alignment. + * i386/osfrose.h, i386/svr3dbx.h: Likewise. + +Fri May 12 12:48:19 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * stor-layout.c (layout_type, case ARRAY_TYPE): Compute length using + MAX of length and zero if sizetype signed and neither bound constant. + + * i386/gnuelf.h, i386/linux-oldld.h, i386/lynx-ng.h, i386/v3gas.h: + Use <...> in #include instead of "...". + * m68k/lynx-ng.h, sparc/lynx-ng.h: Likewise. + + * c-parse.in (myparm): Handle attributes. + * objc-act.c (unused_list): New variable. + (build_tmp_function_decl): Call push_parm_decl with new format. + (start_class): Initialize unused_list. + (start_method_def): Call push_parm_decl with new format and + mark _cmp as possibly unused. + + * combine.c (simplify_shift_const): Don't change SHIFT_MODE + for LSHIFTRT either. + + * unroll.c (unroll_loop): Don't move reg if used in copy_end and + that is a JUMP_INSN. + +Fri May 12 12:31:37 1995 Doug Evans + + * arm/lib1funcs.asm: New file. + +Fri May 12 11:52:03 1995 Kung Hsu + + * configure (a29k-*-vxworks*): New target. + * config.sub (vxworks29k): New alias. + * a29k/t-vx29k: New file. + * a29k/vx29k.h: New file. + +Fri May 12 11:17:28 1995 Jim Wilson + + * loop.c (check_dbra_loop): When reversing loop when + no_use_except_counting is false, there must be only one biv. + +Fri May 12 07:10:00 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * unroll.c (unroll_loop): Only use local_regno for pseudos. + + * genattrtab.c (write_test_expr, case MATCH_DUP): Use operands[N] + instead of JUMP_LABEL (which may not be set). + (walk_attr_value, case MATCH_DUP): Set must_extract. + + * c-parse.in: Adjust number of shift/reduce conflicts. + (parm): Support attributes. + * c-decl.c (push_parm_decl): Pass any attributes to decl_attributes. + +Fri May 12 00:36:26 1995 Per Bothner + + * cpplib.c (skip_quoted_string): Removed - no longer needed. + (skip_if_group): Use cpp_get_token instead of skip_quoted_string. + + * cpplib.h (struct cpp_reader): Remove start_line field. + Add multiline_string_line field. + + * cpplib.c (cpp_error_with_line, cpp_warning_with_line, + cpp_pedwarn_with_line): Take extra column number parameter. + (macroexpand, cpp_get_token): Fix reporting of unterminated strings. + (line_for_error): Removed - no longer needed. + +Fri May 12 02:21:34 1995 Jim Wilson + + * mips/svr4-t.h (MD_STARTFILE_PREFIX, MD_EXEC_PREFIX, + STARTFILE_SPEC, LINK_SPEC): Define. + * configure (mips-tandem-sysv4): Use t-mips not t-svr4. + +Thu May 11 19:18:54 1995 Per Bothner + + * cpplib.c (line_for_error): Make it work; add extra parameter. + (skip_quoted_string, cpp_get_token): Update calls to line_for_error. + (macroexpand): Remember initial line so we can report it if the + call is unterminated. Also, simplify error logic slightly. + (do_include): Cast alloca return value, to avoid pcc warning. + + * cppexp.c (parse_number): Cleanup some Cygnus crud for MPW. + +Thu May 11 21:35:23 1995 Torbjorn Granlund + + From Moshier: + * i960.c (i960_output_ldconst): Let split_double handle DImode. + (i960_print_operand): Use REAL_VALUE_TO_DECIMAL for decimal strings. + (i960_output_double, i960_output_float): Likewise; also change arg + VALUE from `double' to `REAL_VALUE_TYPE'. + +Thu May 11 21:09:25 1995 Per Bothner (bothner@wombat.gnu.ai.mit.edu) + + * cpperror.c (cpp_print_containing_files): Remove some + Cygnus-local stuff. + +Thu May 11 21:06:47 1995 Doug Evans + + * gcc.c (link_command_spec): Make -nostdlib no longer imply + -nostartfiles. + +Thu May 11 18:48:57 1995 Paul Eggert + + * c-common.c (convert_and_check): Don't diagnose overflow in constant + expression merely because conversion overflowed. + +Thu May 11 18:43:59 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * c-decl.c (grokdeclarator): Use PARM_FLAG to see if should + make PARM_DECL. + * c-parse.in (nested_function, notype_nested_function): + Allow old-style arg definitions (use xdecls). + + * c-decl.c (finish_struct): Properly update DECL_PACKED. + +Thu May 11 15:24:15 1995 Jason Merrill + + * fold-const.c (fold): Also fold CLEANUP_POINT_EXPRs into + TRUTH_*_EXPRs and into the first operand. + (operand_equal_for_comparison_p): Also make sure the second operand + is integral. + +Thu May 11 14:22:03 1995 Ted Lemon + + * config/mips/netbsd.h: New file. + * config/mips/t-mips-netbsd: New file. + * config/mips/x-netbsd: New file. + + * configure (mips-dec-netbsd*): Add entry. + + * mips.h (LOCAL_LABEL_PREFIX, USER_LABEL_PREFIX): Define. + (PUT_SDB_BLOCK_START, PUT_SDB_BLOCK_END, ASM_OUTPUT_LABEL_REF, + ASM_OUTPUT_INTERNAL_LABEL, ASM_GENERATE_INTERNAL_LABEL, + ASM_OUTPUT_ADDR_VEC_ELT, ASM_OUTPUT_ADDR_DIFF_ELT): Use them. + + * mips.c (mips_output_lineno): Use LOCAL_LABEL_PREFIX. + +Thu May 11 14:22:03 1995 Stan Cox (gcc@dg-rtp.dg.com) + + * dwarfout.c (output_decl): Don't output DIE for struct or union type + with no name or with ERROR_MARK for the fields. + +Thu May 11 06:36:34 1995 Michael Meissner (meissner@cygnus.com) + + * flow.c (mark_used_regs): If a SUBREG does not have a REG in the + SUBREG_REG position, recursively call mark_used_regs, instead of + segfaulting. + +Thu May 11 06:44:34 1995 Pat Rankin (rankin@eql.caltech.edu) + + * expr.c (do_jump, case EQ_EXPR, NE_EXPR): Fix typo for complex. + +Wed May 10 12:34:46 1995 Michael Meissner + + * configure: Add support for the little endian variant of the + PowerPC System V.4 and Eabi targets. If the GNU assembler was not + specified, don't build libgcc.a variants on the PowerPC systems + that use -mrelocatable, -mlittle, and -mbig. + + * genmultilib: For MULTILIB_MATCHES arguments, map question marks + into equal signs after spliting the left and right side of + equivalent options, to all support for options like: -mcpu=403. + + * rs6000/rs6000.md (rs6000_immed_double_const): New function that + is like immed_double_const, except that it reverses the two words + in the constant if the target is little endian. + + * rs6000/rs6000.md (floatsidf2): Use rs6000_immed_double_const, + not immed_double_const. + (floatunssidf2): Ditto. + + * rs6000/rs6000.h: Add declarations for all functions in rs6000.c. + + * rs6000/sysv4.h (TARGET_SWITCHES): Add -mlittle, -mlittle-endian, + -mbig, and -mbig-endian for bi-endian support. + (ASM_SPEC): Pass -mlittle/-mbig to the assembler if it was passed + to us. + (LINK_SPEC): If explicit little or big endian support was + requested, tell the GNU linker to use the appropriate target + format. + + * rs6000/t-eabi (MULTILIB_*): Build libgcc.a variants for software + floating point. Remove mrelocatable libgcc.a variant. + + * rs6000/t-eabigas: New file, cloned from t-eabi. Build + mrelocatable libgcc.a variant in addition to the other variants. + + * rs6000/t-ppc: New file, for PowerPC System V.4 support without + the GNU assembler. + + * rs6000/t-ppcgas: New file, for PowerPC System V.4 support with + the GNU assembler. + + * rs6000/eabile.h: New file, little endian eabi config file. + * rs6000/sysv4le.h: New file, little endian V.4 config file. + +Wed May 10 14:22:28 1995 Doug Evans + + * libgcc1-test.c (main_without__main): Renamed from `main'. + * Makefile.in (libgcc1-test): Tell the user to ignore warnings. + + * configure: Support --enable-foo, --disable-foo. + +Wed May 10 10:34:00 1995 Lee Iverson + + * unroll.c: Add declarations of static functions. + (unroll_loop): Renumber regs local to loop for each unrolled iteration. + +Wed May 10 08:27:03 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * alpha.c (alpha_set_emit_const): Cleanups to work properly + when run on 32-bit host. + + * configure: Instead of symlinking tm.h and {h,t,}config.h, + make them files that #include the proper file; pass to Makefile. + Pass out_file and md_file to Makefile instead of making symlinks. + * Makefile.in (out_file, md_file, tm_file, {build,host}_xm_file): + New symbols, to be overridden by configure. + (insn-*): Use $(md_file), not md. + (aux-output.o): Use $(out_file), not aux-output.c. + ($(MD_FILE)): Rework to use new conventions. + (gen*.o, bi-*.o): Depend on $(build_xm_file), not hconfig.h. + (scan.o, fix-header.o, scan-decls.o): Likewise. + (distclean): Adjust files removed for new convention. + +Tue May 9 19:26:42 1995 Jason Merrill + + * rs6000/rs6000.h (LIBGCC_SPEC): Do link with libgcc when -shared. + + * Makefile.in (STAGESTUFF): Add underscore.c. + (underscore.c): Rename temporary files to begin with 'tmp-' so that + they will be removed by 'make mostlyclean'. + +Tue May 9 19:19:55 1995 Mike Stump + + * toplev.c (lang_options): Add new flag -ffor-scope. + +Tue May 9 19:11:47 1995 Lee Iverson (leei@ai.sri.com) + + * objc/init.c (objc_init_statics): Fix missing part of last change. + +Tue May 9 18:25:34 1995 Richard Kenner + + * i386/gnu.h, i386/linux.h, i386/linux-aout.h, i386/lynx.h: + Use <...> in #include instead of "..." to avoid recursion. + * i386/netbsd.h, i386/xm-gnu.h, i386/xm-linux.h: Likewise. + * i386/xm-lynx.h, i386/xm-freebsd.h, i386/xm-netbsd.h: Likewise. + * m68k/lynx.h, m68k/netbsd.h, m68k/xm-lynx.h: Likewise. + * m68k/xm-netbsd.h, mips/gnu.h, ns32k/netbsd.h: Likewise. + * ns32k/xm-netbsd.h, rs6000/lynx.h, rs6000/xm-lynx.h: Likewise. + * sparc/lynx.h, sparc/netbsd.h, sparc/xm-lynx.h: Likewise. + * sparc/xm-netbsd.h, vax/netbsd.h, vax/xm-netbsd.h: Likewise. + +Tue May 9 15:52:05 1995 Michael Meissner + + * config.sub: Recognize powerpcle as the little endian varient of + the PowerPC. Recgonize ppc as a PowerPC variant, and ppcle as a + powerpcle variant. Convert pentium into i586, not i486. Add p5 + alias for i586. Map new x86 variants p6, k5, nexgen into i586 + temporarily. + +Tue May 9 15:43:27 1995 Jason Merrill + + * rs6000/rs6000.h (LINK_SPEC, LIB_SPEC): Don't mess with libg + if -shared. + * rs6000/aix41ppc.h (LINK_SPEC): Ditto. + + * rs6000/powerpc.h: Don't emit .extern directives. + +Tue May 9 14:08:09 1995 Jim Wilson + + * sh/lib1funcs.asm (__ashrsi3, __ashlsi3, __lshrsi3): Use .byte + instead of .word offsets in switch table. + +Tue May 9 11:44:47 1995 Jeremy Bettis + + * objc/sendmsg.c (__objc_send_initialize): Call superclass if object + does not implement +initialize. + +Tue May 9 02:44:16 1995 Jason Merrill + + * rs6000/xm-rs6000.h (COLLECT_EXPORT_LIST): Define if not + cross-compiling. + * rs6000/xm-mach.h: #undef COLLECT_EXPORT_LIST. + * rs6000/rs6000.h (COLLECT_SCAN_OBJECTS): Lose. + + * collect2.c (collect_exit): Unlink export_file. + (prefix_from_string): Broken out from prefix_from_env. + (prefix_from_env): Call it. + (main): Under AIX, recognize -bE: and -bexport:, and don't + automatically export everything if we see one. Otherwise, scan the + objects individually and add all their symbols to an export file to be + passed to the linker. + (write_export_file): New function. + (scan_prog_file): Ignore symbols starting with '.' + + * c-common.c (declare_hidden_char_array): Mark decl artificial. + +Mon May 8 18:13:57 1995 Adam Fedor + + * objc/init.c (_objc_load_callback): Add declaration. + (__objc_exec_class): Call _objc_load_callback after every Class + or Category is added. + * objc/objc-api.h (_objc_load_callback): Add declaration. + +Mon May 8 17:56:28 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (expand_expr, case INDIRECT_REF): Set RTX_UNCHANGING_P + if both TREE_READONLY and TREE_STATIC set. + + * c-typeck.c (convert_for_assignment): Don't give errors about + adding const or volatile unless both sides point to functions. + +Mon May 8 11:48:23 1995 Michael Meissner + + * configure: If ../ld/Makefile, symlink ../ld/ld.new to collect-ld, + not real-ld. Don't test for $use_collect2 any more. + +Sun May 7 17:52:23 1995 Jason Merrill + + * calls.c (expand_call): Improve -Winline warnings. + +Sun May 7 17:28:27 1995 DJ Delorie (dj@delorie.com) + + * configure.bat: Use "go32" instead of "msdos" for future expansion. + + * i386/go32.h: Add support for win32's stdcall functions. + + * configure.bat: Add ^M to end of each line. + * i386/config-nt.bat, alpha/config-nt.bat: Likewise. + +Sun May 7 02:12:26 1995 Jason Merrill + + * tree.h (DECL_ARTIFICIAL): New macro. + + * function.c (expand_function_end): Don't warn about unused + anonymous or artificial parms. + +Fri May 5 18:41:22 1995 Jim Meyering (meyering@comco.com) + + * configure: Fix typo in name of "maintainer-clean". + +Fri May 5 14:58:01 1995 Jeffrey A. Law + + * pa.c (emit_move_sequence): Force problematical constants + into memory during the reload pass when generating PIC. + +Fri May 5 13:30:33 1995 Doug Evans + + * objc/NXConstStr.m: NXConstantString.h renamed to NXConststr.h. + +Fri May 5 07:10:15 1995 Stephen L Moshier (moshier@world.std.com) + + * real.c (emdnorm, toe64, etoe64): Significand of Intel long double + denormals is shifted down one bit. + +Fri May 5 07:04:12 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * c-typeck.c (process_init_element): Don't clear_momentary if + constructor_stack is not empty. + + * objc/Makefile (SHELL): Now /bin/sh. + + * c-typeck.c (build_binary_op): Also warn about ordered + comparison of pointer with zero if -Wall. + + * expr.c (do_jump, case EQ_EXPR, NE_EXPR): Properly compare complex. + +Thu May 4 18:01:25 1995 Philippe De Muyter (phdm@info.ucl.ac.be) + + * objc/Makefile: NXConstantString renamed to NXConstStr. + * objc/NXConstStr.m: Renamed from objc/NXConstantString.m. + * objc/NXConstStr.h: Renamed from objc/NXConstantString.h. + +Thu May 4 17:38:21 1995 J.T. Conklin + + * configure (vax-*-netbsd*): New configuration. + * vax/netbsd.h, vax/xm-netbsd.h: New files. + +Thu May 4 16:39:05 1995 Jason Merrill + + * collect2.c (main): Add check for 'collect-ld', just like + 'real-ld', except that old versions won't be looking for it in the + path. Don't look for 'real-ld' in the path anymore. Sigh. + + * collect2.c: #include demangle.h and obstack.h. + (obstack_chunk_alloc): Define. + (obstack_chunk_free): Define. + (generic): Don't define. Don't use. + (main): Initialize obstacks and demangling. + + * collect2.c (dump_file): Adjust space padding in output to + maintain tabulation with Solaris ld. Don't demangle if the + environment variable COLLECT_NO_DEMANGLE is set. + + * collect2.c (main): Redirect the output of the first link and + demangle it. Don't collect static c/dtors unless USE_COLLECT2 is + defined. Null-terminate the list of objects. + (dump_file): New function. + (file_exists): New function. + (collect_exit): Renamed from my_exit. Dump and remove the temporary + ld output file. + (collect_execute): Break out from fork_execute. Support redirection. + (fork_execute): Call it. + (fatal_perror, fatal, error): Make non-static. + (xcalloc, xmalloc): Don't use generic. + (xrealloc): Define. + (collect_wait): Break out for do_wait. Just return the exit status. + (do_wait): Call it. + + * collect2.c: Check SUNOS4_SHARED_LIBRARIES using #if, not #ifdef. + + * Makefile.in (collect2): Now uses cplus-dem.o and underscore.o. + (collect2.o): Pass MAYBE_USE_COLLECT2 to compile. + (underscore.c): Rules for creation. + + * cplus-dem.c, demangle.h: Copy from libiberty. + +Thu May 4 14:12:35 1995 Jim Wilson + + * sdbout.c (plain_type): Pass additional argument to plain_type_1. + (plain_type_1): New parameter level. Increment it when making + recursive calls. Force the type to void_type_mode before starting + a 7th level of recursion. + + * sh.c (general_movsrc_operand, general_movdst_operand): Delete + references to POST_DEC and PRE_INC. + * sh.h: Clean up whitespace, comments, etc. + (TARGET_SH, RTL_BIT, DT_BIT, C_BIT, R_BIT, TARGET_DUMP_RTL, + TARGET_DUMP_R, TARGET_CDUMP): Delete. + (TARGET_SWITCHES): Delete -mR, -mc, -mr options. + (CONST_DOUBLE_OK_FOR_LETTER_P): Delete 'G' contraint. + (FUNCTION_VALUE): Simplify. + (REG_OK_FOR_PRE_POST_P, IS_INDEX): Delete. + (BASE_REGISTER_RTX_P, INDEX_REGISTER_RTX_P): Rewrite to allow + SUBREGs. + (GO_IF_LEGITIMATE_INDEX): Delete unused REGNO argument. + (GO_IF_LEGITIMATE_ADDRESS): Use BASE_REGISTER_RTX_P instead of + REG_OK_FOR_PRE_POST_P. Don't accept PRE_INC or POST_DEC addresses. + (PREDICATE_CODES, PROMOTE_MODE): Define. + +Wed May 3 09:57:55 1995 Michael Meissner + + * rs6000/rs6000.md (non power abs insns): If not powerpc, use + sf/subfc instructions, not subf. + +Wed May 3 08:49:06 1995 Alan Modra + + * protoize.c (gen_aux_info_file): Use strerror #ifdef HAVE_STRERROR. + +Wed May 3 01:06:01 1995 Jeffrey A. Law + + * pa.c (output_call): Fix typo/thinko in last change. + (output_function_epilogue): Align the data section before + emitting deferred plabels. + + From Torbjorn: + * pa.c (before functions): Declare deferred_plabels and + n_deferred_plabels. + (output_call): When generating pic, don't use LP and RP. Use 32 bit + plabel instead. + (output_function_epilogue): Output plabels accumulated in output_call. + +Tue May 2 17:15:08 1995 Jeffrey A. Law + + * pa.c (hppa_expand_epilogue): Fix thinko in last change. + +Tue May 2 16:54:35 1995 Doug Evans + + * jump.c (jump_optimize, can_reach_end determination): A barrier can + follow the return insn. + +Tue May 2 12:39:55 1995 Mike Stump + + * fold-const.c (fold): Ensure that we don't alter the expression's + type when folding CLEANUP_POINT_EXPRs. + +Tue May 2 13:36:08 1995 Michael Meissner + + * expmed.c (emit_store_flag): When creating store flag + instructions from simpler parts, such as XOR, ABS, etc. do not + reuse pseudo registers if expensive optimizations, instead create new + pseudos for each insn result. + +Tue May 2 01:25:29 1995 Jeffrey A. Law + + * pa.c (hppa_expand_epilogue): Correctly handle restore of %rp + for functions with a stack size of exactly 8kbytes and no frame + pointer. + +Mon May 1 19:27:08 1995 Jim Wilson + + * sdbout.c (sdbout_one_type): Don't switch to text section if + in function with section attribute. + + * combine.c (combine_instrutions): Set subst_prev_insn to zero. + (try_combine, undo_all): Likewise. + (get_last_value): Return zero if subst_prev_insn set. + + * sparc.h (INIT_TARGET_OPTABS): Move INIT_SUBTARGET_OPTABS to end. + + * Makefile.in (install-dir): chmod a+rx all newly created directories. + + * expr.c (expand_expr, case SAVE_EXPR): Handle the case where + mode is VOIDmode. + +Fri Apr 28 15:39:38 1995 Per Bothner + + * cpplib.h (cpp_buffer): Note new escape combination "@ ". + * cpplib.c (macroexpand): Delete "@ " if stringifying. + (cpp_skip_hspace): Also skip "@ " if input buffer has_escapes. + (collect_expansion): Cleanup white-space handling. + (create_definition): Remove all leading spaces, not just first one. + (cpp_expand_to_buffer): Set has_escapes on resulting input buffer. + (macroexpand): Set output_escapes during whole function (and + specifically during calls of macarg). + (macroexpand): Set "@ " before and after expansion result. + (push_macro_expansion): Remove unneeded initial "@ ", not " ". + (cpp_get_token): Remove unneeded "@ " (not " ") at end of expansion. + (cpp_get_token): Handle "@ ". + + * cpplib.c (read_name_map): Add cpp_reader parameter. Access + map_list from former (instead of having it be static). + (open_include_file): Extra parameter (because of above changes). + (do_include, lookup_import): Update calls of open_include_file. + + * cpplib.c (do_include): Fix memory leak. + + * cpplib.c (delete_assertion): Also delete tokenlist. + (do_unassert): Don't delete tokenlist (handled by delete_assertion). + (cpp_cleanup): New function. Frees resources used by a cpp_reader. + * cpphash.c (cpp_hash_cleanup): New function. + (delete_macro): Enable commented-out code. + (file_cleanup): Free actual buffer. + + * cpplib.c (cpp_options): Add map_list. + + * cpplib.h (PARSE_GETC): Removed. Bogus and unused. + * cppmain.c (main): Remove commented-out code that used PARSE_GETC. + + * cpplib.c: Don't #include . Causes clashes + on Nextstep (when index/rindex are macros). + (cpp_grow_buffer, int_parse_file): Cast to U_CHAR*, rather than char*. + +Sun Apr 30 08:11:23 1995 Alan Modra (alan@spri.levels.unisa.edu.au) + + * stdarg.h, varargs.h (va_arg): Don't assume __va_rounded_size (char) + has the value of 4. + +Sun Apr 30 07:13:43 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * vax.h (NOTICE_UPDATE_CC): Correctly handle aob insns. + + * expr.c (expand_expr, case CONSTRUCTOR): Don't set target to + zero if more then one word. + Pass size and alignment to move_by_pieces_ninsns in bytes, not bits. + + * cse.c (cse_insn): Properly set IN_MEMORY for SET_DEST. + + * tree.c (substitute_in_expr): Preserve TREE_READONLY. + + * c-common.c (enum attrs): Add A_UNUSED. + (init_attributes): Initialize it. + (decl_attributes, case A_UNUSED): New case. + +Sat Apr 29 15:42:03 1995 Paul Eggert + + * cccp.c (do_include): Re-fix minor memory leak by using + alloca instead of xmalloc and free. + + * cccp.c (macarg): Except for reporting error, treat unterminated + macro call as if it were terminated, since `macroexpand' relies + on *argptr being filled in. + +Sat Apr 29 06:09:35 1995 Torbjorn Granlund + + * pa.c (output_mul_insn): Simplify, it is never called with + UNSIGNEDP set. + + * pa.md (divsi3, udivsi3, modsi3, umodsi3): Simplify. + (ashlsi3): Clean up indentation and commentary. + +Fri Apr 28 12:48:01 1995 Jason Merrill + + * integrate.c (expand_inline_function): Don't emit any notes until + after we've expanded the actual parameters. + +Fri Apr 28 11:51:06 1995 Stan Cox (gcc@dg-rtp.dg.com) + + * m88k/dgux.h: (ENDFILE_SPEC, LIB_SPEC) Fix crtbegin and crtend + (SELECT_RTX_SECTION) Put relocatable pic constants in data section + + * m88k/dguxbcs.h: (LIB_SPEC) Likewise + + * m88k/m88k.c: (symbolic_operand) Put relocatable pic constants in data + + * m88k/m88k.h: (FRAME_POINTER_REQUIRED) Add -momit-leaf-frame-pointer + + * m88k/m88k.md: (umulsidi3) Doesn't work for 88110 with mod/div changes + + * m88k/x-dgux: (GCC_FOR_TARGET) tdesc gets mixed up for crtbegin/crtend + +Fri Apr 28 06:36:47 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * c-typeck.c (pop_init_level, output_init_element): Pass + require_constant_* to digest_init. + + * alpha.c (alpha_emit_set_const): Now returns rtx and take MODE arg. + Rework to use a new pseudo for intermediate values if high opt level. + Also use expand_{bin,un}op. + * alpha.h (alpha_emit_set_const): Add declaration. + * alpha.md (mov[sd]i and splits): Change call to alpha_emit_set_const. + + * reg-stack.c (stack_result): Fix bug in last change. + +Fri Apr 28 01:08:43 1995 Doug Evans + + * objc-act.c: Update calls to start_decl, finish_struct, + pass NULLs for attributes. + +Thu Apr 27 21:13:14 1995 Doug Evans + + * sparc.md (tablejump): Only if ! TARGET_MEDANY. + (casesi): New pattern for TARGET_MEDANY case. + + * c-common.c (decl_attributes): Always continue if attribute not found. + * c-typeck.c (common_type): Call lookup_attribute instead of + value_member. + * tree.c (attribute_hash_list): New function. + (build_type_attribute_variant): Call it. + (valid_machine_attribute): Handle attributes with arguments. + (is_attribute_p): New function. + (lookup_attribute): New function. + (attribute_in_list): Deleted. + (attribute_list_contained): Check TREE_PURPOSE and TREE_VALUE. + * tree.h (valid_machine_attribute): Add prototype. + (is_attribute_p, lookup_attribute): Likewise. + * i386/winnt.h (RETURN_POPS_ARGS): Call lookup_attribute. + (ENCODE_SECTION_INFO): Likewise. + (CPP_PREDEFINES): Use __stdcall__, __cdecl__. + (VALID_MACHINE_DECL_ATTRIBUTE): Call is_attribute_p. + `args' must be NULL. + +Thu Apr 27 21:10:41 1995 David Edelsohn + + * rs6000.md (insv): New anonymous patterns to combine insert with + arbitrary ashift, ashiftrt, lshiftrt, or zero_extract. (Based on + patch from John Brooks .) + (ashlsi3): Remove extraneous operand processing. + +Thu Apr 27 18:47:24 1995 Jim Wilson + + * sh/ashlsi3.c, sh/ashrsi3.c, sh/lshrsi3.c: Delete. + * sh/lib1funcs.asm (ashiftrt_r4_*): Rewrite for efficiency. + (ashrsi3, lshrsi3, lshrsi3): Add. + * t-sh (LIB1ASMFUNCS): Add new functions. + (LIBGCC2_CFLAGS): Delete. + (LIB2FUNCS_EXTRA): Remove deleted files. + (ashlsi3.c, ashrsi3.c, lshrsi3.c): Remove rules for deleted files. + + * stmt.c (expand_return): When returning BLKmode structure, use + operand_subword instead of doing arithmetic on the register number. + Also, for structures smaller than word_mode, copy it into a word_mode + temporary and then subreg it. + + * sparc.md: Delete two define_peepholes which print `bad peephole'. + +Thu Apr 27 16:17:01 1995 Torbjorn Granlund + + * toplev.c (rest_of_compilation): Call shorten_branches even when + !optimize. + * final.c (shorten_branches): For non-optimizing compiles, break + after first pass. + +Thu Apr 27 14:22:50 1995 Michael Meissner + + * i386/linux-oldld.h: New file, that is cloned from linux-aout.h, + except that it does not pass -m i386linux to the linker. This is + to support the original GNU/Linux ld that is on most distributions. + + * configure (i[345]86-*-linux*oldld*): Use i386/linux-oldld.h as + the target file. + +Thu Apr 27 08:56:50 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * tree.c (valid_machine_attribute): Update last change. + +Thu Apr 27 08:06:33 1995 Philippe De Muyter (phdm@info.ucl.ac.be) + + * fix-header.c, cpplib.c: Don't include twice. + * cpplib.c (cpp_grow_buffer, init_parse_file): Cast {xmalloc,xrealloc} + for token_buffer to U_CHAR* instead of char*. + + * m68k/x-mot3300: New file. + * configure (m68k-motorola-sysv*): Use x-mot3300 instead of x-alloca. + +Thu Apr 27 07:04:09 1995 Paul Eggert + + * cccp.c (do_include): Fix minor memory leak. + + * cccp.c (struct argdata): Remove unused `comments' member. + (macarg): Don't set `comments' member. + + * cccp.c (collect_expansion): Assume leading white space + already removed. + Don't allocate unnecessary space for expansion. + + * cccp.c (deps_output): Don't generate overly long output lines. + Do not invoke self recursively with spacer == 0; this simplifies + the code a bit. + +Wed Apr 26 19:20:02 1995 Andrew McCallum + + * objc/Object.h: Changed Class * to Class in order to match NEXTSTEP + and OpenStep runtime. + * objc/Object.m, objc/Object.h, objc/archive.c, objc/class.c: Likewise. + * objc/encoding.c, objc/init.c, objc/objc-api.h, objc/objc.h: Likewise. + * objc/objects.c, objc/runtime.h, objc/selector.c: Likewise. + * objc/sendmsg.c, objc/typedstream.h: Likewise. + +Wed Apr 26 19:18:52 1995 Pieter Schoenmakers + + * objc/objc-api.h (objc_static_instances): New struct to record + static instances of a certain class. + (objc_module): New tag STATICS to point to the table of + objc_statics_instances. + + * objc/init.c (OBJC_VERSION): Version 7. + (objc_init_statics): New function. + (__objc_exec_class): Invoke objc_init_statics if needed. + + * objc/NXConstantString.m, objc/NXConstantString.h: New files. + * objc/Makefile (OBJC_O): Added bare-bones implementation of + NXConstantString. + + * objc-act.c (OBJC_VERSION): Version 7. + (build_objc_string_object): Build a full declaration if not using + the next runtime. + (objc_add_static_instance): New function. + (init_module_descriptor): Add reference to static instances table. + (build_module_descriptor): Add field for static instances table. + (get_objc_string_decl): New function. + (generate_static_references): New function. + (finish_objc): Call generate_static_references if needed. + + * c-tree.h (finish_decl_top_level): New declaration. + * c-decl.c (finish_decl_top_level): New function. + +Wed Apr 26 18:04:32 1995 Dirk Steinberg (Dirk.Steinberg@gmd.de) + + * stddef.h: Treat _MACHINE_ANSI_H_ like _ANSI_H_. + +Wed Apr 26 14:09:59 1995 Jim Wilson + + * sparc.h (NEGTF2_LIBCALL): Define. + (INIT_TARGET_OPTABS): Add support for all TFmode *_LIBCALL macros. + * optabs.c (init_optabs): Delete all uses of undocumented TImode and + TFmode *_LIBCALL macros. + + * combine.c (simplify_rtx, case TRUNCATE): Add. Use force_to_mode. + (force_to_mode, case AND): Allow some simplifications when GET_MODE (x) + has more bits than HOST_BITS_PER_WIDE_INT. + * mips/mips.md (truncdiqi2+[456]): Add patterns to simplify ZERO_EXTEND + of a TRUNCATE. + +Wed Apr 26 13:01:22 1995 Doug Evans + + * sparc.md (memop define_splits): Rewrite to not use memop. + Preserve MEM_IN_STRUCT_P, MEM_VOLATILE_P, RTX_UNCHANGING_P bits. + * sparc.c (memop): Deleted. + (splittable_symbolic_memory_operand): New function. + (splittable_immediate_memory_operand): New function. + +Wed Apr 26 12:54:26 1995 Jeffrey A. Law + + * configure: Add hppa1.1-hp-lites support. + +Wed Apr 26 08:04:46 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * sh.md (ashrsi2_31): Don't use dead_or_set_p after reload. + * pyr.md: Remove bad peepholes that improperly use dead_or_set_p. + + * function.c (expand_function_end): Warn about unused parms + if both -Wunused and -W. + + * tree.h (TYPE_PARSE_INFO): Delete unused field. + (TYPE_PACKED): Add new macro. + (struct tree_type): Delete unused field `parse_info'. + Add new field `packed_flag'. + * c-tree.h (finish_enum, finish_struct): Add ATTRIBUTES argument. + * c-common.c (init_attributes): Don't require decl for A_PACKED. + (decl_attributes, case A_PACKED): Set TYPE_PACKED for type. + * c-parse.in: Update number of shift/reduce conflicts. + (structsp): Pass attribute arg to finish_struct. + Support attributes on enums and pass to finish_enum. + * c-decl.c (finish_struct): Add ATTRIBUTES argument, call + decl_attributes and set DECL_PACKED from TYPE_PACKED. + (finish_enum): Add ATTRIBUTES argument, call decl_attributes, + and make enum narrow if TYPE_PACKED. + * print-tree.c (print_node): Print TYPE_PACKED. + + * c-decl.c (init_decl_processing): Don't give builtin__constant_p an + argument type. + * expr.c (expand_builtin, case BUILT_IN_CONSTANT_P): A pointer to a + string constant is a constant. + + * c-typeck.c (output_init_element): Constructor is not simple if + a bitfield is being assigned a non-integer. + + * c-typeck.c (push_init_level): Update constructor_depth when we + push spelling level. + +Tue Apr 25 19:50:06 1995 Jeffrey A. Law + + * pa.c (emit_move_sequence): Handle function label arithmetic for + PIC code generation too. + +Tue Apr 25 18:52:43 1995 Stephen R. van den Berg (berg@pool.informatik.rwth-aachen.de) + + * reg-stack.c (current_function_returns_real): Deleted (unused). + (FP_mode_reg): Trimmed to a smaller size, less overhead. + (FP_MODE_REG): New macro over which FP_mode_reg will be accessed. + (mark_regs_pat, straighten_stack): New functions. + (reg_to_stack): Amend initialisation of FP_mode_reg. + Mark FP registers mentioned in USE insns before NOTE_INSN_FUNCTION_BEG. + (get_true_reg): Eliminate FP subreg accesses in favour of the + actual FP register in use. + (record_reg_life_pat): Make it work on SUBREGs as well. Make use of + the new mark_regs_pat function. Handle USE insns if called unnested. + (record_reg_life): Don't check for QImode again, we know that it + is there. Process CALL_INSNs like all other insns, they might `use' + some FP argument registers if register passing. + (stack_result_p): Changed in stack_result and returning an rtx. + (stack_reg_life_analysis): Take a new stackentry state argument. + Use stack_result and the rtx to mark using mark_regs_pat. This ensures + that types that need multiple FP registers are handled correctly. + Delete the no_live_regs shortcut to save space. + Use stackentry state to determine filled registers. + (replace_reg): Accept COMPLEX_FLOAT as well. + (move_for_stack_reg): Optimise away some pointer dereferencing. + (subst_stack_regs): Make sure the stack is in the right order + and of the right size for register passing. + (goto_block_pat): Make sure the stack is in the right order + to return possible multi-register values from the function. + (convert_regs): Fix comment about CALL_INSN, it's no longer valid. + Make sure the stack is of the right size and in the right order + to return possible multi-register values from the function. + + * function.c (assign_parms): If STACK_REGS is defined, generate USE + insns before the function body, thus showing which registers are filled + with parameters. + * expr.c (expand_builtin_apply_args): Likewise. + Reverse order of saving registers, more compact code for i387. + (expand_builtin_apply): Likewise. + * emit-rtl.c (gen_highpart): Add comment about broken implementation. + * i386.md (untyped_call): Make it return a complex double. + + * c-parse.in (attrib): Permit null-length argument list to attributes. + + * tree.c (valid_machine_attribute): Use new function attribute_in_list, + makes sure type_attribute_variants are reused even when attributes have + parameters. + Assign any new type to TREE_TYPE (decl). + (attribute_in_list): New function. + (attribute_list_contained): Use it. + * tree.h (attribute_in_list): New declaration. + +Tue Apr 25 18:25:53 1995 Jim Wilson + + * expr.c (struct move_by_pieces): Add to_struct and from_struct fields. + (move_by_pieces): Set to_struct and from_struct fields. + (move_by_pieces_1): Set MEM_IN_STRUCT_P of to1 and from1. + (expand_builtin, case BUILT_IN_MEMCPY): New variable type. + Set MEM_IN_STRUCT_P of src_mem and dest_mem. + + * Makefile.in (clean): Delete libgcc1-asm.a. + + * m68k/vxm68k.h (CPP_SPEC): Define. + + * c-decl.c (pushdecl): Don't test DECL_EXTERNAL when deciding whether + to register a duplicate decl in the current block. + + * cross64.h (INIT_ENVIRONMENT): Define as string not putenv call. + * gcc.c (main): Pass INIT_ENVIRONMENT to putenv. + + * stmt.c (expand_return): When returning BLKmode structure in + registers, copy it to a psuedo-reg instead of to hard registers. + +Tue Apr 25 15:14:58 1995 Michael Meissner + + * rs6000.h (LEGITIMIZE_ADDRESS): Don't create a DF address using two + regs if -msoft-float or -mcpu=403. + +Tue Apr 25 15:45:44 1995 Richard Henderson (richard@atheist.tamu.edu) + + * m68k.md (divhi3, udivhi3, modhi3, umodhi3): Deleted + these insns plus some surrounding trash. + (divmodhi4, udivmodhi4): Added these insns. + +Tue Apr 25 10:12:40 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * alpha.c (alpha_builtin_saveregs): Refine last change to work + for both stdarg and varargs. + + * tree.c (chain_member_purpose): Make similar to chain_member_value. + + * Makefile.in, configure: Change "realclean" to "maintainer-clean". + + * protoize.c: Removed __NetBSD__ from conditional. + Declare strerror if HAVE_STRERROR is defined; otherwise + declare sys_errlist and sys_nerr. + (my_strerror): New function. + (errno): Don't define if already defined as a macro. + + * alpha.c (current_file_function_operand): Return false if profiling. + + * expr.c (convert_move): Don't access a hard reg in an invalid + mode when doing a truncation. + + * alpha.c (add_operand): Test for exactly the constants allowed by + the constraints. + * alpha.h (CONST_OK_FOR_LETTER_P, case 'L'): Reject 0x80000000. + + * c-parse.in (initdcl, notype_initdcl): Pass attributes to + start_decl; delete call to decl_attributes. + * c-tree.h (start_decl): Two new tree parameters. + * c-decl.c (start_decl): New args for attributes; call decl_attributes. + + * c-decl.c (duplicate_decls): Don't look at TYPE_ACTUAL_ARG_TYPES + if it is not set. + + * xm-1750a.h: New file. + + * alpha.c (alpha_builtin_saveregs): Add to incoming args addr + if less than 6 named args, not less than or equal to. + +Mon Apr 24 15:25:19 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * mips-tfile.c (fatal, error): Make first arg const to avoid warning. + + * stmt.c (expand_end_bindings): Write a BARRIER after call + to abort in nonlocal handler. + + * stmt.c (expand_decl_init): Call preserve_temp_slots to keep + around any temp whose address was taken. + +Fri Apr 21 16:26:15 1995 Torbjorn Granlund + + * pa.md (call_internal_reg): Fix typos in length calculation. + (call_value_internal_reg): Likewise. + +Fri Apr 21 13:17:15 1995 Roland McGrath + + * config/gnu.h (STANDARD_INCLUDE_DIR): New macro. + * config/mips/gnu.h (STANDARD_INCLUDE_DIR): Macro moved there. + +Fri Apr 21 08:23:58 1995 Tom Quiggle (quiggle@lovelace.engr.sgi.com) + + * toplev.c (lang_options): Add -I for GNAT. + * gcc.c (default_compilers): Pass -I to gnat1. + +Fri Apr 21 07:58:06 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * tree.c (integer_all_onesp): Test to size of mode, not TYPE_PRECISION. + + * toplev.c (main): Turn on -fforce-mem for -O2. + + * fold-const.c ([lr]rotate_double): Replace; old versions were bogus. + (fold, shift and rotate): Don't call tree_int_cst_sgn on non-integer. + (fold, case LROTATE_EXPR): If constant count, convert to RROTATE_EXPR. + (fold, case RROTATE_EXPR): Sometimes commute logical op with rotate. + Delete pair of counteracting shifts. + + * combine.c (simplify_logical, case AND): If still an AND, get + new values for op0 and op1. + +Thu Apr 20 17:52:10 1995 Jim Wilson + + * sh.c: Completely rewritten. + * sh.h (FAST_BIT, CONSTLEN_2_BIT, CONSTLEN_3_BIT, CONSTLEN_0_BIT, + TARGET_FASTCODE, TARGET_CLEN3, TARGET_CLEN0, TARGET_OPTIONS): Delete. + (TARGET_SWITCHES): Delete -mclen3 and -mclen0 options. + (TARGET_DEFAULT): Is zero. + (OVERRIDE_OPTIONS): Delete code to set max_count_si and max_count_hi. + (SPECIAL_REG): New macro. + (HARD_REGNO_MODE_OK): Allow any mode in any general register. + (GO_IF_LEGITIMATE_ADDRESS): Delete constant + reg address case. + (MOVE_RATIO): Define to 2 when TARGET_SMALLCODE. + (max_si, max_hi, max_count_si, max_count_hi): Delete. + * sh.md: Delete spurious constraints from all define_expands. + (rotlsi3_1): Set T reg instead of clobbering it. + (ashrsi3): Use expand_ashiftrt instead of gen_shifty_op. + (movsi_i, movhi_i, movsf_i): Add conditions to reject patterns + needing a reload. + (movdi-2, movdf_k): Correct conditions to reject patterns needing + a reload. + ([inverse_]branch_{true,false}): Pass operands to output_branch. + (jump): Delete unnecessary braces. + (call, call_value): Don't use expand_acall. Force operand0 into + a register. + +Thu Apr 20 12:57:16 1995 Jason Merrill + + * function.c (assign_parms): Use TREE_ADDRESSABLE rather than + TYPE_NEEDS_CONSTRUCTING to decide whether a parameter needs to be + passed by invisible reference. + + * calls.c (expand_call): Ditto. Abort if we try to pre-evaluate a + parameter of TREE_ADDRESSABLE type. + +Wed Apr 19 17:50:24 1995 Torbjorn Granlund + + * pa.h (TARGET_SWITCHES): Fix typo. + +Tue Apr 18 18:06:03 1995 Per Bothner + + * expr.c (store_constructor): Use BYTES_BIG_ENDIAN rather + than BITS_BIG_ENDIAN to layout bits within bitstring. + * tree.c (get_set_constructor_bytes): Likewise. + +Tue Apr 18 17:22:46 1995 Per Bothner (bothner@wombat.gnu.ai.mit.edu) + + * config/m68k/{x-hp320,x-hp320g} (FIXPROTO_DEFINES): + Define _HPUX_SOURCE so putenv and other functions get seen. + +Tue Apr 18 03:57:35 1995 Michael Meissner (meissner@cygnus.com) + + * varasm.c (weak_decls): Make this a unique structure, instead of + a tree structure. + (handle_pragma_weak): Don't redeclare asm_out_file. Use new weak + structure to copy name and value to. Protect name and value by + copying them to the permanent obstack. + (declare_weak): Call handle_pragma_weak, instead of duplicating + the code. + (finish_weak): Rewrite to use new weak symbols list structure. + + * c-pragma.h: New file to define the c-pragma.c interfaces. + * c-pragma.c: Include it. + * varasm.c: Include it. + * c-lex.c: Include it. + * cp/lex.c: Include it. + + * varasm.c (handle_pragma_weak): No longer pass output file + stream, since weak pragmas are delayed until the end of the + compilation. + * c-pragma.c (handle_pragma_token): Call handle_pragma_weak + without file stream argument. + + * Makefile.in (varasm.o, c-lex.o, c-pragma.o): Add dependencies on + c-pragma.h. + + * config/rs6000.md (movdf): If -msoft-float, do not generate + memory to memory references, like is already done for the + -mhard-float case. Remove an extra test for -mhard-float inside + of -mhard-float code. + +Tue Apr 18 06:19:50 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * fold-const.c (size_int): Arg is unsigned HOST_WIDE_INT. + * tree.h (size_int): Likewise. + +Mon Apr 17 23:36:57 1995 Jason Merrill + + * rs6000/aix41.h: Restore March 11th changes, plus + (ASM_OUTPUT_EXTERNAL): Do add [DS] or [RW], just don't emit + anything. + * rs6000/aix3newas.h (ASM_OUTPUT_EXTERNAL): Ditto. + +Mon Apr 17 15:58:52 1995 Per Bothner + + * config/mips/x-iris (FIXPROTO_DEFINES): Add -D_LANGUAGE_C_PLUS_PLUS. + * config/mips/x-iris6: Likewise. + + * cpplib.c: Rename make_definition to cpp_define. + * cpplib.h (cpp_define): New declaration. + + * cpplib.c (special_symbol): For T_SPECLINE, calculate __LINE__ + in enclosing file buffer, not current buffer (if macro expanding). + (cpp_get_token): Fix thinko (in code for chopping unneeded space). + +Mon Apr 17 11:36:07 1995 Jim Wilson + + * abi64.h (CPP_SPECS): Define and use _ABI64 instead of + _MIPS_SIM_ABI64. + (SETUP_INCOMING_VARARGS): Set MEM_IN_STRUCT_P if big endian target. + * iris6.h (ASM_IDENTIFY_GCC, ASM_IDENTIFY_LANGUAGE): Define. + + * combine.c (get_last_value): Ignore BARRIER when scanning backwards. + (move_deaths): New variables before_dead and after_dead. Set them + to instructions that have valid INSN_CUID values and use in test. + + * combine.c (subst_prev_insn): New variable. + (try_combine): Set it. + (get_last_value): Use it. + + * reload.c (find_reloads): Recompute reg_equiv_address from + reg_equiv_memory_loc before using it. + (find_reloads_toplev, make_memloc): Likewise. + + * expr.c (expand_builtin, case BUILT_IN_MEMCPY): Call force_operand + on dest_rtx before returning it. + + * function.c (instantiate_decls): Use temporary allocation if + DECL_DEFER_OUTPUT is set. + +Sat Apr 15 23:19:03 1995 Jason Merrill + + * aoutos.h (ASM_OUTPUT_DEF): Define instead of SET_ASM_OP. + * sparc/sunos4.h (ASM_OUTPUT_DEF): Ditto. + + * varasm.c (weak_finish): Don't handle aliases. + (declare_weak): Ditto. + (assemble_alias): Handle aliases. + + * c-common.c (enum attrs): Add A_ALIAS. + (init_attributes): Ditto. + (decl_attributes): Ditto. + +Sat Apr 15 13:26:34 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * calls.c (expand_call): Call preserve_temp_slots on temps + made for BLKmode args returned in registers. + + * pa.c (override_options): Fix typo. + +Sat Apr 15 12:11:46 1995 Brendan Kehoe + + * alpha/alpha.c (output_epilog): Initialize fp_offset to 0, and + make sure it's non-zero before we try to use it to restore the + frame pointer. + +Fri Apr 14 19:45:05 1995 Jason Merrill + + * ginclude/va-{clipper,pa,pyr,sparc,spur}.h (va_arg): Reorganize + to avoid BIND_EXPRs and COND_EXPRs of aggregate type. + +Fri Apr 14 19:31:14 1995 Roland McGrath + + * config/svr4.h (ASM_OUTPUT_SECTION_NAME): Make the section + read-only executable "ax" if DECL is a FUNCTION_DECL; read-only + "a" (previously the case always) if DECL is TREE_READONLY; + otherwise writable "aw". + +Fri Apr 14 18:49:11 1995 Linus Torvalds + + * alpha.md (probe_stack): Probe with write, not read. + (allocate_stack): Update and correct stack probe code. + * alpha.c (output_prolog): Changed stack probe at function entry. + +Fri Apr 14 18:42:34 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * jump.c (delete_insn): When deleting after label, delete + a BARRIER as well. + +Fri Apr 14 14:40:48 1995 Jason Merrill + + * toplev.c (compile_file): Call weak_finish. + + * c-common.c (enum attrs): Add A_WEAK. + (init_attributes): Ditto. + (decl_attributes): Support __attribute__ ((weak)) by + calling declare_weak. + + * sparc/sunos4.h (HANDLE_PRAGMA_WEAK, WEAK_ASM_OP, SET_ASM_OP): + Define to support weak symbols with -fgnu-linker. + * aoutos.h: Ditto. + + * varasm.c (handle_pragma_weak): Add declared weak symbols to + weak_decls rather than emitting them immediately. + (declare_weak): Add the indicated declaration to weak_decls. + (weak_finish): Emit .weak directives for any weak symbols. + + * libgcc2.c: The C++ free-store management functions are weak. + +Fri Apr 14 13:00:29 1995 Michael Meissner (meissner@cygnus.com) + + * rs6000/rs6000.c (output_prolog): For eabi systems, emit main's + call to __eabi before setting up the minimal TOC used with the + -mrelocatable support. + + * rs6000/eabi.h (INVOKE__main): Don't define any more, + output_prolog will emit the call. + +Fri Apr 14 09:09:03 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * alpha.c (call_operand): Any reg is valid for NT. + (output_prologue): Never need GP for Windows/NT. + Set SYMBOL_REF_FLAG in current function decl. + +Thu Apr 13 20:19:30 1995 Jason Merrill + + * alpha/xm-alpha.h (HAVE_VPRINTF): Define. + (HAVE_PUTENV): Define. + (POSIX): Define. + +Thu Apr 13 19:57:44 1995 Doug Evans + + * emit-rtl.c (gen_sequence): If the insn has a non-null + CALL_INSN_FUNCTION_USAGE field, output it as a sequence so the + latter isn't discarded. + + * c-parse.in: Update expected conflict count. + +Thu Apr 13 08:10:20 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * configure.bat: Arg 2 is which machine (i386 or alpha). + * configure (alpha-*-winnt3*): New configuration. + * alpha.c: Don't #include stamp.h for WINNT. + (input_operand, case CONST): Allow ptr_mode and DImode. + * alpha.h (WINDOWS_NT): Provide default definition. + (ASM_OUTPUT_INT): Use output_addr_const. + (ASM_OUTPUT_ADDR_DIFF_ELT): Use .long for NT. + * alpha.md (calll, tablejump, movsi): New variants for NT. + * alpha/winnt.h, alpha/xm-winnt.h, alpha/x-winnt: New files. + * alpha/config-nt.bat, alpha/config-nt.sed: New files. + * i386/config-nt.bat: Add Ada fragments to Makefile. + * i386/config-nt.sed: Adjust for deletion of config.run in Makefile.in + Change version to 2.6.3. + Add some missing tabs. + * winnt/winnt.h (TARGET_MEM_FUNCTIONS): Define. + (LINK_SPEC): Delete "align:0x1000". + * winnt/xm-winnt.h (OBJECT_SUFFIX): Define. + * ginclude/stdarg.h, ginclude/varargs.h: Clean up code that + defines *DEFINED* symbols. + + * configure (a29k-*-sym1*): Same as a29k-*-bsd*. + * a29k.h (ASM_OUTPUT_SECTION_NAME): New macro. + +Wed Apr 12 14:36:03 1995 Jim Wilson + + * dbxout.c (dbxout_type_fields): Correct arguments to CHARS macro + in flag_minimal_debug case. + (dbxout_symbol_name): Use DECL_ASSEMBLER_NAME unconditionally. + * sdbout.c (sdbout_record_type_name): Correct indentation. + (sdbout_symbol): Use DECL_ASSEMBLER_NAME unconditionally. + (sdbout_one_type): Likewise. + +Tue Apr 11 13:24:13 1995 Per Bothner + + * fix-header.c (main): Fix loop over required_functions_list. + (fatal): Also print inc_filename. + + * cpplib.c (cpp_push_buffer): Added missing initializatuon of buf. + (cpp_file_buffer): Compare against CPP_NULL_BUFFER, not NULL. + (finclude): No longer call cpp_push_buffer - let callers do it. + (do_include): Add call to cpp_push_buffer. + (push_parse_file): Call cpp_push_buffer early, so initial + defines can use file and line from a valid cpp_buffer. + (nreverse_pending): New function. + (push_parse_file): Use nreverse_pending. + (push_parse_file): For -include files, just push them in reverse + order - we don't need to scan them now. + (cpp_error_from_errno, cpp_perror_with_name): Don't emit extra '\n'. + +Tue Apr 11 13:36:44 1995 Jim Wilson + + * configure (mips-dec-mach3): Add. + + * sh.c (shiftby_operand): Delete. + * sh.h (TARGET_SWITCHES): -m3 and -m3l also set SH2_BIT. + (OVERRIDE_OPTIONS): Don't add CPU_SH2 to CPU_SH3 when TARGET_SH3. + * sh.md (ashlsi3): Use nonmemory_operand as a predicate instead of + shiftby_operand. Don't use shiftby_operand in the output statement. + (lshrsi3): Likewise. + + * c-decl.c (poplevel): Do output inline function if + DECL_ABSTRACT_ORIGIN points to itself. + + * varasm.c (output_constant): Cast assemble_string argument to char *. + +Mon Apr 10 14:29:28 1995 Torbjorn Granlund + + * recog.c (constrain_operands, case 'E'): Make this work like + constraint character `F' when REAL_ARITHMETIC is defined. + * regclass.c (record_reg_classes, case 'E'): Likewise. + * reload.c (find_reloads, case 'E'): Likewise. + +Mon Apr 10 14:30:31 1995 Michael Meissner + + * rs6000/aix3newas.h, rs6000/aix41.h: Eliminate March 11th changes + to undefine ASM_OUTPUT_EXTERNAL{,_LIBCALL}, since this causes the + compiler not to bootstrap. + +Mon Apr 10 07:17:39 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * cppalloc.c: #include config.h. + * cppexp.c: Add declarations of xmalloc and xrealloc. + (cpp_parse_expr): Cast args to bcopy to char *. + * cpphash.c: Add declaration of xmalloc. + * cpplib.c (init_parse_options, cpp_reader): Cast args to bcopy, + bcmp, and bzero to char *. + (add_import, push_parse_file, init_parse_file): Likewise. + + * c-common.c (enum attrs): New attribute, A_NOCOMMON. + (init_attribute): Initialize it. + (decl_attributes): Implement it. + * varasm.c (make_decl_rtl): Allow section attribute if -fno-common + or variable is not to be placed in common for some other reason. + + * combine.c (simplify_set): Don't move a SUBREG to dest if it + is changing the size of a hard reg in CLASS_CANNOT_CHANGE_SIZE. + + * reload.c (find_equiv_reg): If goal is a pseudo that got memory, + a store into memory makes it invalid. + * reload1.c (reload_as_needed): Call forget_old_reloads_1 on + pattern before reg elimination. + +Mon Apr 10 00:26:14 1995 Jeffrey A. Law + + * pa.c (pa_reorg): Bump label use count for each entry in an + exploded ADDR_VEC. + +Sun Apr 9 09:22:51 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * i386.md (adddi3, subdi3): Need scratch reg whenever operand 0 in + mem and operands 1 not '0'. + (subdi3): Don't treat two non-equal MEMs as non-aliasing. + +Sat Apr 8 22:53:38 1995 Jeffrey A. Law + + * pa.c (pa_reorg): Fix typo. + +Sat Apr 8 19:36:36 1995 Michael Meissner + + * rs6000/rs6000.h (SELECT_SECTION): TREE_CODE_CLASS must be called + with a tree code, not a tree value. + +Sat Apr 8 12:41:01 1995 Mike Stump + + * cpphash.c: Don't use const on compilers that don't support it. + +Sat Apr 8 16:32:22 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (expand_increment): Handle case where INCREMENTED + has a non-trivial conversion. + +Fri Apr 7 19:33:21 1995 Phil Nelson (phil@cs.wwu.edu) + + * ns32k.h (TRAMPOLINE_TEMPLATE, TRANSFER_FROM_TRAMPOLINE): + Fix assembler syntax errors. + +Fri Apr 7 19:27:23 1995 Pat Rankin (rankin@eql.caltech.edu) + + * cccp.c (VMS_fstat, VMS_stat): New functions. + +Fri Apr 7 19:25:21 1995 Paul Eggert + + * cccp.c (collect_expansion): If traditional, set stringify + member to SHARP_TOKEN regardless of the value of + stringify_sharp_token_type. + +Fri Apr 7 07:48:35 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * cse.c (simplify_unary_operation): #ifdef POINTERS_EXTEND_UNSIGNED, + handle sign- or zero-extending addresses. + + * optabs.c (init{,_integral,_floating,_complex}_libfuncs): + Change SUFFIX to "char" to avoid confusion with prototype. + + * explow.c (convert_memory_address): No longer static. + New arg, TO_MODE. + Do something special for SYMBOL_REF, LABEL_REF, and CONST. + (memory_address): Add extra arg to call to convert_memory_address. + * rtl.h (convert_memory_address): Add extra arg. + * expr.c (expand_expr, case ADDR_EXPR): Always call + convert_memory_address when converting; add extra arg. + * stmt.c (expand_computed_goto): Convert from ptr_mode to Pmode. + + * gcc.c (OBJECT_SUFFIX): Default now ".o", not "o". + (all specs): Remove "." before %O; use %O in a few missing cases. + * i386/os2.h (OBJECT_SUFFIX): Delete from here. + * i386/xm-os2.h (OBJECT_SUFFIX): Move to here; now has period. + + * Makefile.in (STAGESTUFF): Use $(exeext) for executables. + +Fri Apr 7 03:32:29 1995 Richard Stallman + + * config.sub: Accept -lites* as op sys. + +Thu Apr 6 23:08:50 1995 Per Bothner + + * cpplib.c (bcopy, bzero, bcmp): Remove #undefs. + * cppalloc.c (xcalloc): Re-implement using calloc, + rather than malloc+bzero. + * cpplib.c (SELF_DIR_DUMMY): New macro. + (do_include): Don't pass searchptr to finclude if it is dsp, + since that is on the stack, and would cause a dangling pointer. + If handling #include_next, recognize SELF_DIR_DUMMY. + +Fri Apr 7 00:54:24 1995 Jeffrey A. Law + + * pa.h (MACHINE_DEPENDENT_REORG): Define. + * pa.md (switch_jump): New pattern for jumps which implement + a switch table. + * pa.c (pa_reorg): New function to explode jump tables. + (pa_adjust_insn_length): Account for jumps in switch tables with + unfilled delay slots. + +Thu Apr 6 14:31:10 1995 Jason Merrill + + * c-typeck.c (build_binary_op): Don't call common_type for + uncommon pointer types. + +Wed Apr 5 13:53:17 1995 Per Bothner + + Re-write fixproto/fix-header/etc to use cpplib: + * fix-header.c: Comment out support for adding missing extern "C" + using #ifdef ADD_MISSING_EXTERN_C instead of #if 0. + * fixproto: Removed case of required functions. Instead use ... + * fix-header.c (std_include_table): ... new required-functions table. + (cpp_file_line_for_message, cpp_print_containing_files, cpp_message): + New stub functions, to intercept cpplib error message. + * fixproto: Don't call $CPP, since fix-header now incorporates cpplib. + * gen-protos.c (fatal, hashf): New functions. + (main): Use hashf, instead of hash. + * scan-decls.c (scan_decls, skip_to_closing_brace): Re-write to + take a cpp_reader* as argument, not a FILE*. + * scan.h (hash): Make parameter const. + * scan.c (hash): Removed. + * scan.c (memory_full, xmalloc, xrealloc): Removed. + Use functions from cppalloc.c instead. + * Makefile.in (gen-prtos, fix-header, stmp-fixproto): Update. + +Wed Apr 5 13:24:14 1995 Per Bothner + + * cpplib.c (cpp_get_token): If traditional, return after comment, + instead of reading more, so end-of-line can be peeked at. + * cpperror.c (cpp_file_line_for_message, cpp_message): New + functions, that do the actual printing of error messages. + (cpp_print_file_and_line, cpp_error, cpp_warning, cpp_pedwarn, + cpp_error_with_line, cpp_warning_with_line, cpp_pedwarn_with_line, + cpp_pedwarn_with_file_and_line, cpp_error_from_errno, my_strerror, + cpp_perror_with_name): Re-write to use cpp_file_line_for_message + and cpp_message, and move to cpplib.c. + +Tue Apr 4 23:35:49 1995 Roland McGrath + + * config/gnu.h (GNU_CPP_PREDEFINES): Remove -D__HURD__. + +Tue Apr 4 17:15:54 1995 Jeffrey A. Law + + * pa.h (DO_GLOBAL_DTORS_BODY): Fix pointer -> integer assignment + problem. + + * reorg.c (fill_simple_delay_slots): Don't use a JUMP_INSN + a the target of another JUMP_INSN to fill a delay slot. + +Mon Apr 3 19:03:48 1995 Torbjorn Granlund + + * cse.c (simplify_unary_operation): Sign-extend constants when + they have the most significant bit set for the target. + + * m68k.md (umulsi3_highpart): Test for CONST_INT and CONST_DOUBLE, + not CONSTANT_P. + (smulsi3_highpart): Likewise. + * m68k.c (const_uint32_operand): New function. + (const_sint32_operand): New function. + * m68k.md (const_umulsi3_highpart): Use const_uint32_operand instead + of immediate_operand for op3. Delete mode. + (const_smulsi3_highpart): Analogous change. + +Mon Apr 3 19:03:48 1995 Jim Wilson + + * cse.c (simplify_binary_operation): Sign-extend constants when + they have the most significant bit set for the target. + + * combine.c (force_to_mode, case PLUS): Sign extend masks that are + negative in OP_MODE. + (simplify_and_const_int): Sign-extend constants when they have the + most significant bit set for the target. + (merge_outer_ops): Likewise. + (simplify_shift_const): Likewise. + +Mon Apr 3 18:23:48 1995 Jason Merrill + + * toplev.c (lang_options): Add -f{no-,}repo. + +Mon Apr 3 18:13:15 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * combine.c (nonzero_bits, case REG): Check POINTERS_EXTEND_UNSIGNED. + (num_sign_bit_copies, case REG): Likewise. + * explow.c (convert_memory_address): New function. + (memory_address): Call if it needed. + (promote_mode, case POINTER_TYPE): Use Pmode and pointer extension. + (allocate_dynamic_stack_space): Convert size from ptr_mode. + * expr.c (clear_storage, expand_assignment, store_{expr,constructor}): + Use ptr_mode instead of Pmode in some places. + (expand_expr, expand_builtin): Likewise. + (push_block, store_expr): Convert size to Pmode. + (expand_expr, case ADDR_EXPR): Convert from Pmode to ptr_mode. + +Mon Apr 3 18:00:52 1995 Jim Wilson + + * explow.c (allocate_dynamic_stack_space): Correct typo in last + change. + + * sh.c (gen_shifty_op, case ASHIFTRT): Return 0 if shift count is not + a constant. + +Mon Apr 3 12:17:10 1995 Michael Meissner (meissner@cygnus.com) + + * expmed.c (extract_bit_field): When converting a SUBREG into a + REG, if the system is big endian, adjust the bit offset + appropriately. + +Mon Apr 3 00:08:45 1995 Roland McGrath + + * config/i386/linux.h: Include "config/linux.h" instead of + "linux.h", to avoid recursion. + +Sun Apr 2 23:50:27 1995 Roland McGrath + + * config/i386/gnuelf.h: Include i386/linux.h instead of + i386/linuxelf.h. + +Sun Apr 2 17:35:10 1995 Jim Wilson + + * cse.c (simplify_relational_operation): Don't simplify A-B for + compare of A and B when the compare is unsigned. + +Sun Apr 2 08:23:38 1995 Paul Eggert + + * fixincludes (stdio.h): BSDI 2.0 changed the spelling of _VA_LIST_ + to _BSD_VA_LIST_. + +Sun Apr 2 07:57:28 1995 Richard Kenner + + * i386/xm-bsd386.h: New file. + * configure (i[345]86-*-bsd*): Add xm_file. + + * gcc.c (default_compilers): Pass -W and -w to gnat1. + + * winnt/winnt.h (STDC_VALUE): Add #undef. + * i386/winnt.h (LIB_SPEC): Likewise. + +Sun Apr 2 07:55:25 1995 Douglas Rupp (drupp@cs.washington.edu) + + * i386/winnt.h (RETURN_POPS_ARGS, ENCODE_SECTION_INFO): Call + chain_member_purpose, not chain_member_value. + (ASM_FILE_START, LIB_SPEC): Move to here. + * winnt/winnt.h (ASM_FILE_START, LIB_SPEC): Delete from here. + * tree.c (chain_member_purpose): New function. + +Sat Apr 1 12:19:14 1995 Jason Merrill + + * c-typeck.c (build_binary_op): New variable build_type controls + type given to expression when created. Set to integer_type_node for + comparison ops instead of result_type so result_type still holds type + in which comparison is done. When checking for comparison between + signed and unsigned, use result_type rather than (possibly shortened) + type of op0. Don't warn about equality comparison of signed operand + to unsigned constant that fits in signed type. + +Sat Apr 1 09:47:02 1995 Douglas Rupp (drupp@cs.washington.edu) + + * i386/winnt.h (CPP_PREDEFINES): Add definitions for __stdcall + and __cdecl. + * winnt/winnt.h (LIB_SPEC): Add OLDNAMES.LIB. + * winnt/xm-winnt.h: Remove unneeded #define's for non-ANSI functions. + * fixinc.winnt: Remove unneeded fixes relating to __stdcall. + + * objc/Makefile (SHELL): New definition. + +Sat Apr 1 08:25:26 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * cse.c (cse_insn): When emitting a BARRIER, don't put it after + a deleted insn. + + * reload.c (push_reload): Initialize secondary_{in,out}_icode. + + * gcc.c (print_multilib_info): Don't use LAST_PATH if not set. + +Sat Apr 1 08:15:59 1995 Pat Rankin (rankin@eql.caltech.edu) + + * vax.md (extv, extzv): Don't use immediate value for operand 1. + +Sat Apr 1 07:48:29 1995 Yury Shevchuk (sizif@botik.yaroslavl.su) + + * stmt.c (expand_asm_operands): Properly ignore invalid reg in clobber. + +Sat Apr 1 07:02:24 1995 Paul Eggert + + * cccp.c: General code cleanup. + Add prototypes for static functions. + Remove unnecessary casts to (char *); add casts to (U_CHAR *). + Add parentheses suggested by `gcc -Wparentheses'. + Rename local variables as suggested by `gcc -Wshadow'. + , , , : New includes. + , : Include only if defined(RLIMIT_STACK). + : Include, unless already does. + (HAVE_FCNTL_H, HAVE_STDLIB_H, HAVE_SYS_TIME_H): New symbols. + (HAVE_UNISTD_H, STDC_HEADERS, TIME_WITH_SYS_TIME): Likewise. + (__attribute__, PROTO, VA_START, PRINTF_ALIST, PRINTF_DCL): New macros. + (PRINTF_PROTO{,_1,_2,_3}, DO_PROTO): Likewise. + (bcopy, bzero, bcmp): If #defined by configuration file, use that. + If STDC_HEADERS is defined, use standard C functions. + If BSTRING is defined, or USG and VMS are not defined, use + the C library. Otherwise, use my_bcopy, my_bzero, my_bcmp. + (localtime): Remove no-longer-necessary explicit declaration. + (getenv, index, rindex): Don't declare explicitly if the + appropriate system header should declare it. + (fdopen): Remove no-longer-used declaration. + (vprintf): Define a subsitute macro if !defined(HAVE_VPRINTF). + (main): Replace `fdopen (dup (fileno (stdout)), "w"))' + with `stdout'. + (get_lintcmd, rescan, create_definition): Use bcmp instead of strncmp + when both operands are known to be free of null bytes. + (check_macro_name, compare_defs, collect_expansion): Likewise. + (do_assert, compare_token_lists, assertion_lookup, do_line): Likewise. + (skip_if_group, lookup): Likewise. + (rescan): Remove unused label `startagain'. + Abort instead of printing nonsense if the stack is corrupted + when there was an unterminated successful conditional. + (pcfinclude): Include explicit double-cast through GENERICPTR + to identify particularly egregious type puns. + (create_definition, do_define, check_macro_name): Use %.*s + printf format to avoid painful copying-and-casting. + (do_once): Return void, not (unused) int. + (do_ident, do_pragma, do_sccs): Accept extra arguments so that + all directive-handler's types match. + (do_sccs): Define only if SCCS_DIRECTIVE is defined. + (skip_if_group, dump_single_macro): Add `default: break;' to + keep -Wswitch happy. + (error, warning, error_with_line, vwarning_with_line, pedwarn): Use + stdarg/vararg/vfprintf instead of passing bogus char * args around. + (pedwarn_with_line, pedwarn_with_file_and_line, fatal): Likewise. + (verror, vwarning, verror_with_line, vwarning_with_line): New fcns. + (dump_single_macro): Abort if ap points to garbage. + (make_definition, make_undef, make_assertion): Parameter now char *. + (xmalloc, xrealloc, xcalloc, savestring, index0): Make sizes size_t + instead of unsigned; make pointer parameters GENERICPTR, not char *. + (xcalloc): Use bzero to clear memory instead of using own loop. + +Fri Mar 31 08:33:07 1995 Ken Raeburn (raeburn@wombat.gnu.ai.mit.edu) + + * longlong.h (umul_ppmm mc68000): Use %# instead of #. + +Fri Mar 31 06:37:54 1995 Michael Meissner (meissner@cygnus.com) + + * stor-layout.c (layout_decl): Implment -fpack-struct. + (layout_record): Ditto. + + * flags.h (flag_pack_struct): New flag variable. + + * toplev.c (flag_pack_struct): New flag variable. + (f_options): Add -fpack-struct support. + + * Makefile.in (stor-layout.o): Add flags.h dependency. + +Fri Mar 31 08:40:16 1995 Douglas Rupp (drupp@cs.washington.edu) + + * configure (i[345]86-*-winnt3*): Add tmake_file. + * i386/x-winnt (winnt.o): Deleted. + * i386/t-winnt: New file. + +Fri Mar 31 07:26:37 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * m68k/netbsd.h, m68k/hp3bsd44.h: Remove #include of machine/ansi.h. + + * configure (a29k-*-bsd): Set tmake_file to t-libc-ok. + + * stmt.c (expand_asm_operands): Properly handle output that can't + be directly written into. + + * c-parse.in (structsp): Correct error in last change. + * c-common.c (init_attributes): A_FORMAT is only for decls. + +Thu Mar 30 18:27:34 1995 Jason Merrill + + * libgcc2.c: Remove explicit 0-initializations of static variables. + +Thu Mar 30 18:22:39 1995 Fergus Henderson + + * c-typeck.c (internal_build_compound_expr): Warn if LHS of comma + expression has no side effects, or computes value which is not used. + * stmt.c (make warn_if_unused_value): No longer static. + * tree.h (warn_if_unused_value): Add declaration. + +Thu Mar 30 18:15:11 1995 Jim Wilson + + * combine.c (get_last_value): Revert back to use prev_nonnote_insn + instead of prev_real_insn. Modify test that ignores USE insns. + + * rs6000.h (SELECT_SECTION): Apply constant DECL_INITIAL test + only to DECLs. + + * explow.c (allocate_dynamic_stack_space): Test STACK_BOUNDARY against + BIGGEST_ALIGNMENT at run time instead of at compile time. + Give MUST_ALIGN macro a value, and test this value in if statements. + +Thu Mar 30 08:59:56 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * c-parse.in: Now have 27 shift/reduce conflicts. + (attribute_list): Just make chain of all attributes. + (attrib): Consistently put name as PURPOSE, args, if any, as VALUE. + (structsp): Allow attributes on any struct or union. + * c-common.c (enum attrs): New enum class. + (attrtab, attrtab_idx): New variables. + (add_attribute, init_attributes): New functions. + (decl_attributes): Major rewrite. + * tree.c (valid_machine_attribute): Now receive name and args. + +Thu Mar 30 07:20:14 1995 Paul Eggert + + * protoize.c: Use the phrase `preprocessing directive' consistently. + * cccp.c (handle_directive, do_line, skip_if_group): Likewise. + (output_line_directive): Renamed from output_line_command. + (no_line_directives): Renamed from no_line_commands. + + * cccp.c (rescan): Don't recognize preprocessing directives + within macro args. Warn if one is found. + +Thu Mar 30 06:20:36 1995 H.J. Lu (hjl@nynexst.com) + + * configure (i[345]86-*-linux*): Set xmake_file=x-linux, + tm_file=i386/linux.h, and don't set extra_parts. + (i[345]86-*-linux*aout*): New configuration. + (i[345]86-*-linuxelf): Deleted. + * config/linux{,-aout}.h, config/x-linux, config/xm-linux.h: New files. + * config/i386/linux-aout.h: New file. + * config/i386/linux.h: Extensive modifications to use ELF format + as default. + (LIB_SPEC): Don't use libc_p.a for -p. don't use libg.a + unless for -ggdb. + (LINUX_DEFAULT_ELF): Defined. + * config/i386/linuxelf.h,config/i386/x-linux: Files deleted. + * config/i386/xm-linux.h: Just include xm-i386.h and xm-linux.h. + +Wed Mar 29 19:09:36 1995 Mike Stump + + * libgcc2.c (__throw_type_match): Update to use new calling convention. + +Wed Mar 29 14:53:23 1995 Jim Wilson + + * gcc.c (process_command): Delete code modifying gcc_exec_prefix. + (main): Put it here after last use of gcc_exec_prefix. For cross + compiler, set startfile_prefixes if gcc_exec_prefix is set and + standard_startfile_prefix is a relative path. + + * combine.c (make_compound_operation, AND case): Undo July 7, 1994 + change. + + * mips/mips.md (call_internal1, call_value_internal1): Move %* from + start of assembler output to immediately before the jal. + + * mips/mips.c (function_prologue): Put SDB_DEBUGGING_INFO ifdef around + code for SDB_DEBUG support. + (mips_select_rtx_section, mips_select_section): Change rdata_section + to READONLY_DATA_SECTION and sdata_section to SMALL_DATA_SECTION. + * mips/mips.h (SMALL_DATA_SECTION): Define. + + * reorg.c (mark_referenced_resources): Make setjmp use all registers. + + * flow.c (mark_used_regs, case SUBREG): Only fall through to REG case + if operand is a REG. + + * i960/i960.h (TARGET_SWITCHES): Make -mold-align set + TARGET_FLAG_STRICT_ALIGN. + (STRICT_ALIGNMENT): Test TARGET_STRICT_ALIGN. + + * sh/sh.c (andcosts): Modify costs to match the hardware, and add + explanatory comments. + + * sparc/sol2.h (CPP_PREDEFINES): Add -D__SVR4. + +Wed Mar 29 14:30:30 1995 Michael Meissner + + * rs6000/rs6000.md (movsf): When moving to/from integer registers, + don't move floating point to memory if it is being simulated with + -msoft-float. + +Wed Mar 29 06:47:36 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * c-parse.in (initdcl): Only call decl_attributes once. + * c-common.c (decl_attributes): Clean up test for __mode__. + +Tue Mar 28 08:34:37 1995 John Hassey (hassey@dg-rtp.dg.com) + + * i386.md (adddi3): Don't treat two non-equal MEMs as non-aliasing. + +Tue Mar 28 08:20:49 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * a29k.h (CONSTANT_ADDRESS_P): Provide consistent definition. + +Tue Mar 28 07:26:41 1995 Paul Eggert + + * cccp.c (do_xifdef, do_endif): Remove unnecessary pointer comparisons. + +Mon Mar 27 20:45:15 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * calls.c (expand_call, store_one_arg): Don't set KEEP in calls + to assign_stack_temp. + * function.c (preserve_temp_slots): Clear ADDR_TAKEN on item + that we are preserving. + +Mon Mar 27 14:39:35 1995 Ian Lance Taylor + + * mips/mips.h (FIRST_PSEUDO_REGISTER): Increment. + (FIXED_REGISTERS, CALL_USED_REGISTERS): Add new register. + (MD_REG_LAST): Increment. + (ST_REG_FIRST, ST_REG_LAST): Increment. + (HILO_REGNUM): Define. + (enum reg_class): Add HILO_REG. + (REG_CLASS_NAMES): Add "HILO_REG". + (REG_CLASS_CONTENTS): Add HILO_REG initializer, and adjust ST_REGS + and ALL_REGS initializers. + (SECONDARY_RELOAD_CLASS): Remove. + (SECONDARY_INPUT_RELOAD_CLASS): Define. + (SECONDARY_OUTPUT_RELOAD_CLASS): Define. + (REGISTER_MOVE_COST): Treat HILO_REG as MD_REGS. + (REGISTER_NAMES): Add initialization line. + (DEBUG_REGISTER_NAMES): Add "accum". + * mips/mips.md: For each instruction which sets HI or LO, clobber + HILO_REGNUM with (clobber (match_scratch:MODE N "=a")). Change + each explicit reference to register 66 to register 67. + (mulsidi3): Change to define_expand. + (mulsidi3_internal): New name of old mulsidi3. + (mulsidi3_64bit): New insn. + (umulsidi3): Change to define_expand. + (umulsidi3_internal): New name of old umulsidi3. + (umulsidi3_64bit): New insn. + (madddi_64bit, umaddi_64bit): New insns. + (movdi_internal2): Add case for setting HILO_REG to zero. + (reload_indi, reload_outdi): New define_expands. + (movsi_internal1, movsi_internal2): Add cases for setting MD_REGS + to zero, and for setting a general reg to HILO_REG. + (reload_outsi): New define_expand. + * mips/mips.c (mips_reg_names): Add "accum". + (mips_sw_reg_names): Likewise. + (mips_regno_to_class): Map HILO_REGNUM to HILO_REG. + (mips_move_1word): Handle moving HILO_REGNUM to a general + register. Make sure that the normal MD_REG cases aren't used for + HILO_REGNUM. Handle moving zero to a MD_REG. + (mips_move_2words): Make sure that the normal MD_REG cases aren't + used for HILO_REGNUM. Handle moving zero to a MD_REG. + (override_options): Set mips_char_to_class for 'a' and 'b'. + (mips_secondary_reload_class): Add in_p argument. Handle + HILO_REGNUM. + +Mon Mar 27 07:16:05 1995 Warner Losh + + * gcc.c: Removed __NetBSD__ from conditional. + Declare strerror if HAVE_STRERROR is defined; otherwise + declare sys_errlist and sys_nerr. + (my_strerror): New function. + +Fri Mar 24 18:08:14 1995 Jason Merrill + + * i386/linux.h (LIB_SPEC): Don't try to link with libraries we + know only exist in archive form unless -static. + +Fri Mar 24 16:12:16 1995 Doug Evans + + * Makefile.in (multilib.h): Depend on Makefile, not config.status. + +Fri Mar 24 15:01:17 1995 Michael Meissner + + * rs6000/rs6000.h (TARGET_MULTIPLE_SET): New target_flags bit that + indicates -mmultiple or -mno-multiple was explicitly passed by the + user, and not set as part of the cpu defaults. + (TARGET_SWITCHES): Set TARGET_MULTIPLE_SET bit for both -mmultiple + and -mno-multiple. + + * rs6000/rs6000.c (rs6000_override_options): If -mmultiple or + -mno-multiple was explicitly used, don't override the setting with + the processor default. + +Wed Mar 22 21:42:13 1995 Doug Evans + + * i960/i960.c (i960_function_arg_advance): Ensure all regs marked + as used if stack is also used (for va_start). + (i960_setup_incoming_varargs): Rewrite to be similar to Intel's + version, but don't allocate reg block unless necessary. + * ginclude/va-i960.h (varargs va_start): Save g14 explicitly. + Account for arguments preceding va_alist. + +Wed Mar 22 13:24:55 1995 Torbjorn Granlund + + * pa.c (singlemove_string): Handle SFmode constants again. Simplify. + (zdepi_cint_p): Make some variables HOST_WIDE_INT. + (lhs_lshift_cint_operand): Likewise. + (output_and): Likewise. + (output_ior): Likewise. + +Wed Mar 22 12:40:09 1995 Jim Wilson + + * sh.md (udivsi3): Don't clobber register 6. + (udivsi3, divsi3, mulsi3_call): Use a pseudo-reg with regclass 'z' + for output rather than hard register 0. + (block_move_real): Don't clobber registers 4 and 5. + + * mips.c (mips_select_section): Apply constant DEC_INITIAL tests + only to VAR_DECLs. + +Wed Mar 22 03:53:17 1995 Richard Stallman + + * config.sub (rm400, rm600): New machine names. + (sinix5.*, sinix): New os aliases. + (mips-siemens): Default os to sysv4. + +Mon Mar 20 21:56:47 1995 Per Bothner + + Merged Paul Eggert's patch to cccp.c of Wed Mar 8 18:21:51 1995: + * cpplib.c (do_include): Fix type typo: pcfbuflimit is char *, not int. + + Merged Doug Evans' patch to cccp.c of Mon Feb 27 17:06:47 1995: + * cpplib.c (do_include): Check for redundant file before opening in + relative path case. Don't call fstat unnecessarily. + + Merged J.T. Conklin's patch to cccp.c of Wed Feb 22 20:29:31 1995: + * cpperror.c: Removed __NetBSD__ from conditional. + + Merged Kenner's patch to cccp.c & cexp.y of Tue Sep 20 17:49:47 1994: + * cppexp.c (struct operation): Make value by HOST_WIDE_INT. + (cpp_parse_expr): Change return type to HOST_WIDE_INT. + * cpplib (eval_if_expr): Likewise. + (do_if, do_elif): Update appropriately. + * cpplib.h (cpp_parse_expr): Removed, to avoid defining HOST_WIDE_INT. + + Merged Paul Eggert's patch to cccp.c of Mon Aug 8 19:42:09 1994: + * cpplib.c (create_definition): Warn about `#define a@', since a + diagnostic is now required (see ISO TC1's addition to subclause 6.8). + Also warn about `#define is-empty(x) (!x)'. + +Tue Mar 21 00:10:50 1995 Jeffrey A. Law + + * x-pa (CC): Add "-Dbsd4_4". + +Mon Mar 20 18:40:31 1995 Per Bothner + + * toplev.c (print_error_function): New function hook. + (default_print_error_function): New function. Default value + of print_error_function. Code moved here from report_error_function. + (report_error_function): Use print_error_function hook. + +Mon Mar 20 20:27:43 1995 Doug Evans + + * cccp.c (do_xifdef): Handle c++ comments. + (do_endif): Likewise. + +Mon Mar 20 15:31:45 1995 Jason Merrill + + * configure (i386 configurations): Prepend i386/ to t-crt*. + +Mon Mar 20 07:58:04 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * stmt.c (fixup_gotos): Add missing call from last change. + + * objc/misc.c: Put Alpha-specific decls before #include of runtime.h. + + * alpha.h (EXTRA_SECTIONS): Write zeros first time in .rdata. + +Sat Mar 18 16:37:24 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * flow.c (mark_used_regs, case SUBREG): Set reg_changes_size even + for integer modes. + (mark_used_regs): Set reg_changes_size for RHS, if necessary. + * combine.c (gen_lowpart_for_combine): Set reg_changes_size, if needed. + * reload.c (push_reload): Reload a SUBREG if paradoxical and + class is CLASS_CANNOT_CHANGE_SIZE. + * reload1.c (gen_reload): Handle paradoxical SUBREGs. + * alpha.h (SECONDARY_{INPUT,OUTPUT}_RELOAD_CLASS): Need GENERAL_REGS + for paradoxical SUBREG and FLOAT_REGS. + (SECONDARY_NEEDED_MODE): Use actual mode for 4 bytes or wider. + * alpha.md (movsi): Allow FP regs and add case for store of FP reg. + Remove cvtlq from MEM to FP reg case. + + * rtl.h (emit_insns_after): Add declaration. + * stmt.c (fixup_gotos): Do a cleanup for a block when it is exited + even if label if not defined yet. + + * function.c (pop_function_context): Fix error in last change; + reference old value of current_function_decl before we modify it. + +Fri Mar 17 21:57:44 1995 Jason Merrill + + * toplev.c (rest_of_compilation): Handle -Wreturn-type properly + for inlines we aren't compiling yet. + +Fri Mar 17 21:26:48 1995 Mike Stump + + * libgcc2.c (__register_exceptions): Handle empty tables. + +Fri Mar 17 11:48:31 1995 Douglas Rupp (drupp@cs.washington.edu) + + * i386/winnt.c (winnt_function_prologue): Deleted. + (gen_stdcall_suffix): New function. + +Thu Mar 16 17:36:52 1995 Jason Merrill + + * svr4.h (LINK_SPEC): If the user did not specify -h name, use the + output file name, if any. + * sparc/sol2.h (LINK_SPEC): Ditto. Also, if the user did not + specify -R path, add an -R for each -L. + + Move SunOS 4-specific assembler switches into the appropriate place. + * m68k/sun[23].h (ASM_SPEC): Add %{R} %{j} %{J} %{h} %{d2} + %{keep-local-as-symbols:-L}. + * i386/sun.h (ASM_SPEC): Add %{R} %{keep-local-as-symbols:-L}. + * sparc/sparc.h (ASM_SPEC): Ditto. + * gcc.c (default_compilers): Remove %{R} %{j} %{J} %{h} %{d2} + %{keep-local-as-symbols:-L} from assembler rules. + +Thu Mar 16 16:58:09 1995 Michael Meissner + + * rs6000/eabi-ctors.c: New file, handle C++ static constructors + and destructors without requiring anything else from a libc. + + * rs6000/t-eabi (LIB2FUNCS_EXTRA): Build eabi-ctors.c. + + * rs6000/eabi.asm: Do not load up register 2 if there is no .got + section. Jump to the __do_global_ctors function at the end of + processing to call C++ static constructors, and it will return to + __eabi's caller. Use normal volatile registers, instead of saving + and restoring registers 30 and 31. + + * rs6000/eabi.h (STARTFILE_SPEC): Define as null. + (LIB_SPEC): Ditto. + (ENDFILE_SPEC): Ditto. + (LIBGCC_SPEC): Always look for libgcc.a. + +Thu Mar 16 17:05:14 1995 Richard Kenner + + * stmt.c (warn_if_unused_value, case SAVE_EXPR): New case. + (warn_if_unused_value, case NOP_EXPR): OK if CALL_EXPR inside. + + * c-common.c (decl_attributes): Allow alignment for TYPE_DECLs. + + * Makefile.in (xsys-protos.h): Fix typo in -U operand. + +Thu Mar 16 13:49:10 1995 Per Bothner + + * cpplib.c, cpplib.h: New files - a C PreProcessor library. + * cpphash.c, cpphash.h, cppalloc.c, cpperror.c, cppexp.c: + New files - utility features used by cpplib. + * cppmain.c: New file - cpp replacement main program for cpplib. + * Makefile.in: New rules to build cppmain. + +Thu Mar 16 16:11:05 1995 Douglas Rupp (drupp@cs.washington.edu) + + * i386/winnt.h (FUNCTION_PROLOGUE, HAVE_probe, gen_probe): Deleted. + (ENCODE_SECTION_INFO, VALID_MACHINE_DECL_ATTRIBUTE): New macro. + +Thu Mar 16 15:58:24 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * combine.c (apply_distributive_law, case SUBREG): Fix typo when + checking for paradoxical SUBREG. + +Wed Mar 15 18:45:08 1995 Doug Evans + + * libgcc1-test.c: Renamed from cross-test.c. + * Makefile.in (LIBGCC1_TEST): Renamed from CROSS_TEST. + (all.cross): Delete $(ENQUIRE) dependency. + (libgcc1-test): Renamed from cross-test. + Delete unnecessary gcc-cross and $(LIBGCC) dependencies. + Link with -nostartfiles -nostdlib + `$(GCC_FOR_TARGET) --print-libgcc-file-name`. + (libgcc1-test.o): Renamed from cross-test.o. + Change gcc-cross dependency to xgcc since the latter is used. + +Wed Mar 15 13:49:21 1995 Jason Merrill + + * tree.c (save_tree_status): Now takes a tree 'context' instead of + a boolean 'toplevel' as an argument. If 'context' is not + current_function_decl, create a new obstack for the new function. + Also save inline_obstacks. + (restore_tree_status): No longer takes a second argument. Also + restore inline_obstacks. + (temporary_allocation): Clear inline_obstacks. + (permanent_allocation): Free up the obstacks in inline_obstacks. + + * function.h (struct function): New fields contains_functions and + inline_obstacks. + + * function.c (push_function_context_to): Now takes a tree + 'context' instead of a boolean 'toplevel' as an argument. + Also save current_function_contains_functions. + (push_function_context): Pass current_function_decl to it. + (pop_function_context_from): Takes 'context' instead of 'toplevel'. + Set current_function_contains_functions properly. + (pop_function_context): Pass current_function_decl to it. + +Wed Mar 15 14:53:09 1995 Michael Meissner + + * rs6000/rs6000.md (abssi2): Turn into a define_expand. If + TARGET_POWER, do old code that uses the abs instruction. If not, + do abs in three instructions, using a temporary register, which + enables generating more reasonable code for sne. Add a recognizer + for negative of the absolute value. Add define_splits for the + PowerPC. + (sne insn): Add a recognizer for sne on the PowerPc to use two + instructions, compared to the four generated using the absolute + value insn. + +Tue Mar 14 18:38:40 1995 J.T. Conklin + + * m68k.md ({add,sub,mul,div}[sdx]f3): Add new patterns for recognizing + SImode, HImode, and QImode operands. + +Mon Mar 13 18:59:36 EST 1995 David Edelsohn + + * rs6000.h (CPP_SPEC): Add PPC403. + (processor_type): Add PPC403. + (RTX_COSTS): Add PPC403. + * powerpc.h (CPP_SPEC): Add PPC403. + * sysv4.h (CPP_SPEC): Add PPC403. + * rs6000.c (processor_target_table): Add PPC403. + * rs6000.md (define_attr cpu and function units): Add PPC403. + +Mon Mar 13 14:40:23 1995 Michael Meissner + + * rs6000/rs6000.md (call, call_value insns): Do not put a nop + after a bl instruction on System V.4 and eABI. + + * rs6000/sysv.4 (SUBTARGET_SWITCHES): Add support for + -mno-traceback to suppress the V.4 traceback word. + (ASM_DECLARE_FUNCTION_NAME): Don't put out a traceback work if + -mno-traceback. + +Mon Mar 13 13:36:37 1995 Jason Merrill + + * t-svr4, i386/t-{crtpic,sol2}, m88k/t-svr4, sparc/t-sol2: + Use -fPIC, rather than -fpic, for building crtstuff. + +Sat Mar 11 17:27:08 1995 Jason Merrill + + * configure: Use aix3newas.h for AIX 3.2.4 and 5. + * rs6000/aix41.h: Undefine ASM_OUTPUT_EXTERNAL{,_LIBCALL}. + * rs6000/aix3newas.h: New file. Define ASM_SPEC to -u, and + undefine ASM_OUTPUT_EXTERNAL{,_LIBCALL}. + +Sat Mar 11 06:42:50 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * dbxout.c (dbxout_symbol): Properly handle decl whose DECL_NAME + points to a TYPE_DECL with a zero TYPE_NAME. + +Fri Mar 10 18:18:33 1995 Torbjorn Granlund + + * pa.h (PROMOTE_MODE): Define. + +Fri Mar 10 14:37:58 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * sdbout.c (sdbout_record_type_name): If TYPE_NAME is + a TYPE_DECL, get name from DECL_NAME. + +Fri Mar 10 14:09:26 1995 Doug Evans + + * arm/riscix.h (SUBTARGET_SWITCHES): Renamed from + ARM_EXTRA_TARGET_SWITCHES. + * arm/riscix1-1.h (SUBTARGET_SWITCHES): Likewise. + * arm.h (SUBTARGET_SWITCHES): Likewise. + (TARGET_HARD_FLOAT, TARGET_SOFT_FLOAT): Define. + (TARGET_SWITCHES): Add -msoft-float, -mhard-float. + (BYTES_BIG_ENDIAN): Delete #ifndef/#endif. + (CONDITIONAL_REGISTER_USAGE): If -msoft-float, disable fp regs. + (FUNCTION_VALUE): R16 is return reg only if !-msoft-float. + (LIBCALL_VALUE): Likewise. + * arm.md (all fp patterns): Conditionalize on TARGET_HARD_FLOAT. + (*movsf_soft_insn, *movdf_soft_insn): New patterns. + +Fri Mar 10 13:53:46 1995 Jim Wilson + + * reorg.c (steal_delay_list_from_target): Exit at the top if the + branch in SEQ is not a single set. + + * sh.md (movdi define_split, movdf define_split): Correct indentation + and formatting. Make the condition fail if an operand is a MEM + with an auto-inc address. + + * varasm.c (copy_constant): Copy operand of ADDR_EXPR if it is a + constant. + + * mips/abi64.h (SETUP_INCOMING_VARARGS): Correct arguments to + move_block_from_reg call. + + * expr.c (expand_assignment): When offset is zero, make new MEM + before setting MEM_VOLATILE_P. + + * reload.c (find_reloads, case 'o'): Accept a fully reloaded + auto-increment address. + + * combine.c (max_uid_cuid): New static variable. + (INSN_CUID): Call abort if INSN is out of range. + (combine_instructions): Set max_uid_cuid. Set uid_cuid directly + instead of through INSN_CUID. + (get_last_value): Use prev_real_insn instead of prev_nonnote_insn. + Ignore USE insns generated by combine. + +Fri Mar 10 13:47:08 1995 Rod Barman + + * m68k/fpgnulib.c (__fixdfsi): Catch values < 0.5 in magnitude. + +Fri Mar 10 12:02:33 1995 Ian Lance Taylor + + * fixincludes: Fix `typedef struct term;' on hppa1.1-hp-hpux9. + +Fri Mar 10 05:50:11 1995 Oliver Kellogg (Oliver.Kellogg@RST13.DASA.DBMAIL.d400.de) + + * 1750a.c (sectname): Reverse Init and Normal. + (print_operand_address, case PLUS): Add case for LABEL_REF. + (print_operand_address, case LABEL_REF): Split fom SYMBOL_REF. + (print_operand_address, case CODE_LABEL): New case. + (ASM_FILE_END): Delete. + * 1750a.h (FUNCTION_EPILOGUE): Restore stack before freeing local vars. + (DEFAULT_SIGNED_CHAR): Now 1. + (DATA_SECTION_ASM_OP): Use pseudo-op for read-only data (later copied). + (JUMP_TABLES_IN_TEXT_SECTION): Define. + (ASM_OUTPUT_ASCII): Split into multiple lines if long. + (ASM_OUTPUT_{CHAR,SHORT,INT,LONG_INT}): Split up. + (ASM_OUTPUT_COMMON): Call check_section. + +Thu Mar 9 12:46:53 1995 Michael Meissner + + * rs6000.md (movsf): Do not call truncdfsf2 for non PowerPC + when expanding a store to memory and -msoft-float was used. + +Thu Mar 9 08:51:35 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * c-decl.c (start_function): Handle new parameter ATTRIBUTES. + * c-tree.h (start_function): Add new parameter. + * c-lang.c (finish_file): Pass new parm to start_function. + * objc-act.c (build_module_descriptor, really_start_method): Likewise. + * c-parse.in (fndef, nested_function): Pass prefix_attributes + to start_function. + (setspecs): Save prefix_attributes in declspec_stack. + (decl rules): Restore prefix_attributes along with current_declspecs. + (setattrs): Concatenate prefix_attributes to previous value. + * c-common.c (decl_attributes): Handle prefix and suffix attributes + the same way. + + * print-tree.c (print_node): Fix typo in printing large INTEGER_CST. + + * varasm.c (assemble_variable): Consistently use DECL_SIZE for + everything. + + * c-typeck.c (convert_for_assignment): Fix typo in testing for + pointer to function type. + + * varasm.c (record_constant_1): Handle NON_LVALUE_EXPR. + Rewrite to use switch instead of if/then/elseif/else. + +Wed Mar 8 18:21:51 1995 Paul Eggert + + * cccp.c (do_include): Fix type typo: pcfbuflimit is char *, not int. + +Wed Mar 8 17:30:29 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * fold-const.c (force_fit_type): Always propagate OVERFLOW. + + * rtl.def (INLINE_HEADER): Add new "e" field. + * rtl.h (FORCED_LABELS): New field; other fields adjusted. + (gen_inline_header_rtx): New parm FORCED_LABELS. + * emit-rtl.c (gen_inline_header): Add new parm FORCED_LABELS. + * integrate.c (initialize_for_inline, output_inline_function): + Handle FORCED_LABELS. + +Wed Mar 8 13:47:20 1995 Jason Merrill (jason@cygnus.com) + + * alpha.h (WORD_SWITCH_TAKES_ARG): Add -rpath. + (LINK_SPEC): Pass through -taso and -rpath. + * alpha/osf12.h (LINK_SPEC): Ditto. + +Wed Mar 8 09:59:56 1995 Michael Meissner + + * rs6000/eabi.asm: Rewrite so that the initialized pointers go + into the .got2 section, which allows eabi.asm to be assembled with + the -mrelocatable option. Move the data picked up from the bl + instruction to before the traceback tag. + + * rs6000/sysv4.h (CPP_SPEC): Define _RELOCATABLE if -mrelocatable + switch is used. + + * libgcc2.c (__new_handler): Don't initialize the pointer variable + with the address of __default_new_handler, which may not work in + some shared library mechanisms. + (__builtin_new): If __new_handler is NULL, call the function + __default_new_handler. + +Tue Mar 7 17:34:59 1995 Ian Lance Taylor + + * i960.h (PROCESS_PRAGMA): Define. + (ROUND_TYPE_ALIGN): Pass maximum of COMPUTED and SPECIFIED to + i960_round_align. + (ROUND_TYPE_SIZE): Delete. + * i960.c (process_pragma): Uncomment, and rewrite for gcc 2. + (i960_round_size): Delete. + (i960_round_align): Don't adjust suggested alignment downward. + Restrict alignment to value set by #pragma align. + +Tue Mar 7 12:14:46 1995 Doug Evans + + * configure (sparc64-*-elf): Add crtbegin.o, crtend.o to extra_parts. + * sparc/sp64-elf.h (TARGET_VERSION): Define. + (CPP_PREDEFINES): Delete sun, sparc, unix. Delete OS assertions. + (ASM_SPEC): Define. + (LINK_SPEC): Delete solaris stuff, this is an embedded target. + (STARTFILE_SPEC, ENDFILE_SPEC): Define. + +Mon Mar 6 17:54:01 1995 Doug Evans + + * Makefile.in (install-common): Fix typo in installation of cpp. + Likewise with gcc-cross. + +Mon Mar 6 02:29:05 1995 Jeffrey A. Law + + * pa.md (movsicc): New expander. + +Fri Mar 3 13:34:20 1995 Michael Meissner (meissner@cygnus.com) + + * rs6000/sysv4.h (ASM_SPEC): If -mrelocatable was passed to + compiler, pass it on to the assembler. + +Fri Mar 3 12:11:28 1995 Ian Lance Taylor + + * fixincludes: Add fixes for VxWorks header files. + * ginclude/stddef.h: If VxWorks typedef macros are defined, invoke + them as appropriate. + +Fri Mar 3 05:48:54 1995 Paul Eggert + + * cccp.c (dump_single_macro): Fix typo: % wasn't properly + doubled in printf formats. + +Thu Mar 2 19:44:02 1995 Jason Merrill + + * expr.c (expand_expr, CLEANUP_POINT_EXPR): Force the operand out + of memory before running cleanups. + +Thu Mar 2 19:15:24 1995 Paul Eggert + + * cccp.c (rescan): Prevent accidental token-pasting to + get !=, *=, /=, ==, or ^=. + +Thu Mar 2 15:37:13 1995 Jason Merrill + + * c-typeck.c (build_binary_op): Avoid spurious warning + comparing enumerator to unsigned variable. + +Thu Mar 2 18:18:38 1995 J.T. Conklin + + * m68k.md (sqrtsf2,sqrtdf2): Use fp precision specifiers. + +Thu Mar 2 18:09:01 1995 Stephen L Moshier (moshier@world.std.com) + + * c-lex.c (yylex, case !NOT_FLOAT): Remove previous change. + +Thu Mar 2 15:26:50 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * Makefile.in (bootstrap*): Pass new STAGE_PREFIX to recursive makes. + +Wed Mar 1 14:52:16 1995 Ian Lance Taylor + + * i960/i960-coff.h (ASM_FILE_START): Define. + (CTORS_SECTION_ASM_OP, DTORS_SECTION_ASM_OP): Define. + (EXTRA_SECTIONS, EXTRA_SECTION_FUNCTIONS): Define. + (CTORS_SECTION_FUNCTION, DTORS_SECTION_FUNCTION): Define. + (INT_ASM_OP): Define. + (ASM_OUTPUT_CONSTRUCTOR, ASM_OUTPUT_DESTRUCTOR): Define. + * i960/vx960-coff.h (CPP_PREDEFINES): Define. + (CPP_SPEC): Define. + (CC1_SPEC): Default to -mca. + +Wed Mar 1 11:10:54 1995 Michael Meissner (meissner@cygnus.com) + + * rs6000/rs6000.c (output_prologue): Do not emit the word that + gives the PC relative location to the local GOT table for the + -mrelocatable option here. + * rs6000/sysv4.h (ASM_DECLARE_FUNCTION_NAME): Emit it here. + + * t-eabi (MULTILIB_OPTIONS, MULTILIB_DIRNAMES): Build -msoft-float + and -mrelocatable versions of the library. + + * rs6000/powerpc.h (CPP_PREDEFINES): Define the cpu and machine as + powerpc, not rs6000. + + * libgcc2.c (_unwind_function): Clone for powerpc, using the + PowerPC mnemonics. + + * rs6000/rs6000.md (uminsi3, umaxsi3): Silence warnings that + -2147483648 is too large to fit in a signed integer on 32-bit + hosts. + +Wed Mar 1 06:48:31 1995 Richard Kenner + + * fold-const.c (decode_field_reference): Don't check TREE_CODE + of EXP; let get_inner_reference decide if have reference. + Allow no bit reference if have AND_MASK. + (all_ones_mask_p): Use tree_int_cst_equal, not operand_equal_p. + (unextend): New function. + (fold_truthop): For constant cases, use new function, rework + conversion, and warn if comparison can never be true. + + * expr.c (store_expr): Do conversion in two steps for promoted lhs. + +See ChangeLog.9 for earlier changes. diff --git a/gcc_arm/FSFChangeLog.11 b/gcc_arm/FSFChangeLog.11 new file mode 100755 index 0000000..2bc3d59 --- /dev/null +++ b/gcc_arm/FSFChangeLog.11 @@ -0,0 +1,14493 @@ +Wed Dec 31 18:40:26 1997 Richard Kenner + + * stmt.c (expand_asm_operands): Treat ASM with no outputs as volatile. + +Wed Dec 31 08:03:45 1997 Paul Eggert + + * toplev.c (flag_verbose_asm): Default to 0, not 1. + + * i386/bsd386.h (ASM_COMMENT_START): Define to " #". + +Tue Dec 30 17:38:55 1997 Jim Wilson + + * unroll.c (find_splittable_givs): Handle givs with + dest_reg created by loop. + +Tue Dec 30 14:21:33 1997 Ian Lance Taylor + + * svr4.h (LINK_SPEC): Never specify -h. + * ptx4.h (LINK_SPEC): Likewise. + * rs6000/sysv4.h (LINK_SPEC): Likewise. + * sparc/sol2.h (LINK_SPEC): Likewise. + +Tue Dec 30 06:15:23 1997 Philippe De Muyter + + * libgcc2.c (_eh_compat): Do not include stdlib.h, but provide a + private extern declaration for malloc. + +Mon Dec 29 06:56:41 1997 Laurent Guerby + + * Makefile.in (stmp-int-hdrs): Add "touch". + +Sun Dec 28 19:36:05 1997 Stephen L Moshier + + * mips.h (CACHE_FLUSH_FUNC): New, defaults to _flush_cache. + (INITIALIZE_TRAMPOLINE): Use it. + * mips/ultrix.h (CACHE_FLUSH_FUNC): Define as cacheflush. + * mips/news4.h (CACHE_FLUSH_FUNC): Likewise. + +Sun Dec 28 08:19:13 1997 Paul Eggert + + * arm.c: Don't include assert.h. + * i960.c: Likewise. + (i960_arg_size_and_align): Rewrite to avoid assert. + * m88k.c: Don't include assert.h. + (expand_block_move): Rewrite to avoid assert. + * except.c: Don't include assert.h. + (scan_region): Rewrite to avoid assert. + (save_eh_status, restore_eh_status, scan_region): Don't bother + testing whether pointer is null. + * dwarfout.c, dwarf2out.c: Do not include assert.h. + (assert): New macro, since we can't use system assert. + +Sat Dec 27 19:08:17 1997 Stephen L Moshier + + * mips/ultrix.h (DWARF2_UNWIND_INFO): Define as 0. + +Fri Dec 26 05:57:06 1997 Philippe De Muyter + + * m68k/mot3300.h (FINALIZE_TRAMPOLINE): Macro defined. + * libgcc2.c (__clear_insn_cache): New sysV68-specific helper function + for trampolines. + +Thu Dec 25 15:22:43 1997 Richard Kenner + + * rs6000.c (function_arg_padding): All aggregates pad upward. + +Wed Dec 24 18:05:13 1997 Richard Kenner + + * sparc.c: Add prototypes for static functions. + (check_pic): Check for form of pic_pc_rtx, not it itself. + (pic_setup_code): New function, from finalize_pic. + (finalize_pic): Call pic_setup_code and insert after nonlocal_receiver. + * sparc.md (nonlocal_goto_receiver): New pattern. + +Tue Dec 23 05:54:38 1997 Richard Kenner + + * expr.c (expand_builtin_setjmp): Call builtin_setjmp_receiver. + * mips.md (builtin_setjmp_receiver): New pattern. + + * crtstuff.c (__do_global_ctors_aux): Add missing call to + FORCE_INIT_SECTION_ALIGN and go back to text section. + * i386/sol2.h (FORCE_INIT_SECTION_ALIGN): Remove loop. + + * expr.c (do_store_flag): For shift, get bit count using tree_pow2. + +Tue Dec 23 05:21:18 1997 Paul Eggert + + * genattrtab.c (main): Check HAVE_{G,S}ETRLIMIT too. + +Mon Dec 22 19:30:59 1997 Michael P. Hayes + + * sdbout.c (plain_type_1): Add missing checks for named types "char" + and "int" and check for int by size first. + +Mon Dec 22 19:13:58 1997 Manfred Hollstein + + * m68k/xm-mot3300.h (ADD_MISSING_{POSIX,XOPEN}): Define. + * m88k/xm-sysv3.h: Likewise. + + * configure.in (getrlimit, setrlimit): Call AC_CHECK_FUNCS. + * cccp.c (main): Check HAVE_{G,S}ETRLIMIT in addition to RLIMIT_STACK. + * toplev.c (main): Likewise. + + * fixincludes (target_canonical): New variable. + (size_t): Add support for Motorola's stdlib.h which fails to provide + a definition for size_t. + (str{len,spn,cspn} return value): Handle different layout on sysV88. + (fabs/hypot): Provide a fake for hypot which is broken on + m88k-motorola-sysv3; emit a prototype for fabs on m88k-motorola-sysv3. + + * m68k/mot3300.h (ASM_BYTE_OP): Don't include '\t' in definition. + (ASM_OUTPUT_ASCII): Prefix ASM_BYTE_OP by one single '\t'. + +Mon Dec 22 19:05:49 1997 Richard Henderson + + * sparc.md (jump): Don't use the annul bit around an empty loop. + +Mon Dec 22 18:52:56 1997 Robert Lipe + + * i386/x-sco5 (CLIB) Deleted. + (ALLOCA) Added. + * i386/xm-sco5.h (USE_C_ALLOCA) Added. + +Mon Dec 22 18:42:16 1997 Philippe De Muyter + + * m68k/mot3300Mcrt0.S (mcount): Function removed. + (__stop_monitor): New function. + * m68k/mot3300-crt0.S (__stop_monitor): New (empty) function. + (mcount, mcount%, monitor): Common symbols removed. + * m68k/mot3300.h (FUNCTION_PROFILER): USE_GAS and !USE_GAS versions + fixed and merged. + (EXIT_BODY): Always call __stop_monitor without tricky tests. + +Mon Dec 22 18:35:05 1997 Andreas Schwab + + * objc/Make-lang.in (runtime-info.h, libobjc_entry.o): Create in + build directory. + (libobjc.a): Update dependency list. + (libobjc.dll): Likewise. Use libobjc_entry.o from build directory. + (objc/sendmsg.o): Add -Iobjc to find runtime-info.h. + (objc.mostlyclean): Remove runtime-info.h. + +Mon Dec 22 18:27:47 1997 Paul Eggert + + * libgcc2.c (_eh_compat): New section. + * Makefile.in (LIB2FUNCS): Add _eh_compat. + +Mon Dec 22 17:52:37 1997 Marcus G. Daniels + + * objc/init.c (_objc_load_callback): Don't initialize. + +Sun Dec 21 15:06:00 1997 Paul Eggert + + * mips/xm-iris5.h (HAVE_INTTYPES_H): Force undefined. + +Sun Dec 21 14:51:51 1997 Richard Kenner + + * dwarf2out.c (add_bound_info, case COMPONENT_REF): New case. + +Sun Dec 14 06:49:05 1997 Richard Kenner + + * expr.c (expand_expr, case PLACEHOLDER_EXPR): Use placeholder_list + expression in preference to any other if correct type. + + * i386.h (INITIAL_ELIMINATION_OFFSET): Correctly test for PIC + register used. + +Sat Dec 13 06:11:32 1997 Richard Kenner + + * frame.h (__register_frame_info_table): Fix typo in declaration. + +Fri Dec 12 07:55:18 1997 Richard Kenner + + * function.c (purge_addressof_1): For (mem (address (mem ...)), + when collapsing, preserve mode of outer MEM. + + * frame.c (__register_frame_info): Renamed from __register_frame. + (__register_frame_info_table, __deregister_frame_info): Similarly. + * frame.h (__{,de}register_frame_info): Likewise. + (__register_frame_info_table): New declaration. + * crtstuff.c (__do_global_dtors{,_aux}): Rename __deregister_frame. + (frame_dummy, __do_global_ctors): Likewise for __register_frame. + * collect2.c (write_c_file_{stat,glob}): Rename __register_frame + to __register_frame_info and similarly for __deregister_frame and + __register_frame_table. + + * sched.c (remove_dependencies): Set RTX_INTEGRATED_P on dependency + we delete. Properly update prev for multiple consecutive deletions. + (priority): Skip deleted dependence. + + * integrate.c (initialize_for_inline): In DECL_RTL of a PARM_DECL, + look inside a (mem (addressof (mem ...))). + +Fri Dec 12 05:49:58 1997 Paul Eggert + + * collect2.c (write_c_file_glob): + Allocate initial frame object in static storage and pass its address. + +Thu Dec 11 18:01:31 1997 Philippe De Muyter + + * acconfig.h (NEED_DECLARATION_GETENV): Define slot added. + +Thu Dec 11 17:54:23 1997 Paul Eggert + + * crtstuff.c (__do_global_ctors): Fix typo in last change. + +Wed Dec 10 18:38:28 1997 Kaveh R. Ghazi + + * libgcc2.c (__bb_exit_func): Fix test of return value of fopen. + +Wed Dec 10 07:07:37 1997 Bernd Schmidt + * combine.c (simplify_rtx, case ABS): Don't get confused by a + VOIDmode operand. + +Tue Dec 9 17:44:14 1997 David Edelsohn + + * rs6000.h (FUNCTION_ARG_PADDING): Define. + * rs6000.c (function_arg_padding): New function. + +Tue Dec 9 08:53:56 1997 Richard Kenner + + * integrate.c (save_for_inline_copying): Make a new reg_parm_stack_loc. + +Mon Dec 8 19:23:58 1997 Pat Rankin + + * toplev.c (get_run_time): [#if VMS] Cast arg in times call. + + * vax/xm-vms.h (HAVE_UNISTD_H): Define for DEC C. + * make-cccp.com [CC]: Add /Prefix=All for DEC C. + +Mon Dec 8 08:09:17 1997 Richard Kenner + + * stmt.c (expand_decl_cleanup_no_eh): Properly return a value. + + * fold-const.c (fold_convert): Don't flag overflow when converting + pointer to integer. + +Sun Dec 7 09:42:05 1997 Pat Rankin + + * make-gcc.com (@make-l2): Pass along any command line arguments. + * make-l2.com: Add latent support to compile cp/inc/* if `cc1plus' + is specified [currently disabled]. + * make-cc1.com: When building with GNU C, use -O2. + * make-cccp.com: Likewise. + +Sun Dec 7 06:56:48 1997 Richard Kenner + + * crtstuff.c (__do_global_ctors): Add missing arg to __register_frame. + + * collect2.c (write_c_file_stat): Fix error in last change; + use __SIZE_TYPE__, not size_t. + +Sun Dec 7 05:50:43 1997 Paul Eggert + + * cccp.c (strings.h): Fix misspelling of `include' introduced + in last change to this file. + +Sat Dec 6 18:54:11 1997 Richard Kenner + + * alpha/vms.h (CPP_PREDEFINES): Remove redundant setting + of GCC version and unneeded setting of __VMS_VER. + +Fri Dec 5 07:24:36 1997 Richard Stallman + + * sparc/linux64.h (TARGET_VERSION): Write "GNU/Linux". + * sparc/linux.h, sparc/linux-aout.h, rs6000/linux.h: Likewise. + * m68k/linux.h, arm/linux.h, alpha/{linux,elf}.h: Likewise. + * listing: Change linux to gnu-linux. + +Fri Dec 5 06:23:22 1997 Paul Eggert + + Alter C startup code so that it doesn't invoke malloc on Solaris. + * frame.h (struct object): Decl moved here from frame.c. + * frame.c (struct object): Move decl to frame.h. + ("frame.h"): Include after , so that size_t is defined. + (__register_frame, __register_frame_table, __deregister_frame): + It's now the caller's responsibility to allocate storage for object. + * crtstuff.c (frame_dummy), collect2.c (write_c_file_stat): + Allocate initial frame object in static storage and pass its address. + * crtstuff.c (, "frame.h"): Include. + * Makefile.in ($(T)crtbegin.o, $(T)crtend.o, stamp-crtS): + Depend on defaults.h and frame.h. + + * Makefile.in (RTL_H, TREE_H): Add gansidecl.h. + (DEMANGLE_H): New macro. All dependencies on demangle.h + changed to $(DEMANGLE_H). + (RECOG_H): Likewise. + (libgcc2.a, stmp-multilib): Add dependencies on frame.h, gansidecl.h. + (collect.o): Add dependency on gansidecl.h. + (gcc.o, choose-temp.o, pexecute.o, prefix.o): Likewise. + (obstack.o, choose-temp.o, pexecute.o): Add dependency on $(CONFIG_H). + +Fri Dec 5 06:20:06 1997 Dean Deaver + + * arm.md (casesi_internal): Add USE of label. + +Fri Dec 5 05:59:44 1997 Richard Kenner + + * configure.in (sys/times.h): Check for this instead of times.h. + * cpplib.c, toplev.c: Properly test for and include sys/times.h. + +Thu Dec 4 12:30:40 1997 J"orn Rennecke + + * sh.c (final_prescan_insn): Use local label prefix when emitting + .uses pseudo-ops. + +Thu Dec 4 07:00:48 1997 Richard Earnshaw + + * arm.c (arm_finalize_pic): Use an offset of 4 when adjusting the + GOT address. + +Thu Dec 4 06:58:32 1997 Dean Deaver + + * genoutput.c (scan_operands): Treat format of "u" like "e". + +Thu Dec 4 06:28:33 1997 Richard Kenner + + * msdos/top.sed, winnt/config-nt.sed: Change version to 2.8.0. + + * stmt.c (pushcase_range): Clean up handling of "infinite" values. + +Wed Dec 3 09:03:35 1997 Bernd Schmidt + + * i386.c (notice_update_cc): Remove bogus Pentium GCC code. + +Wed Dec 3 08:46:32 1997 Paul Eggert + + * arm.h (CPP_ARCH_DEFAULT_SPEC): Fix misspelling: `TARGET_CPU_DEFUALT'. + (TARGET_SWITCHES): Fix misspelling: `no-apcs-rentrant'. + * pa.c (override_options): Fix misspelling: `compatable'. + * enquire.c (main): Fix misspelling in diagnostic: `mallocatable'. + * gcov.c (function_summary): Fix misspelling in diagnostic: `funcion'. + * objc/thr-decosf1.c (__objc_thread_id): Fix misspelling in code: + `pthread_getuniqe_np'. + + * tahoe.c (extensible_operand): Renamed from extendable_operand. + All callers changed. + * dwarf2.h (enum dwarf_discrim_list): Renamed from dwarf_descrim_list. + * dwarf2out.c: Fix misspellings in forward static function + declarations: `add_AT_setion_offset', `add_sibling_atttributes'. + * dwarfout.c: Fix misspellings in forward static function + declarations: `langauge_attribute', `geneate_new_sfname_entry'. + * stmt.c, tree.h (start_cleanup_deferral): + Renamed from start_cleanup_deferal. + (end_cleanup_deferral): Renamed from end_cleanup_deferal. + * toplev.c (rest_of_compilation): Rename local var from + inlineable to inlinable. + +Wed Dec 3 06:17:03 1997 Jason Merrill + + * stmt.c (expand_decl_cleanup): Update thisblock after eh_region_start. + +Wed Dec 3 06:06:38 1997 Jim Wilson + + * dwarf2out.c (gen_type_die, case POINTER_TYPE): See TREE_ASM_WRITTEN + before the recursive call. + +Wed Dec 3 05:57:29 1997 Richard Kenner + + * configure.in (AC_HEADER_{STDC,TIME}): Add calls. + (AC_CHECK_HEADERS): Add fcntl.h times.h, sys/times.h, + sys/resource.h, and sys/param.h. + (getenv): Check if need declaration. + * cccp.c: Remove obsolete ways of including headers and use autoconf + symbols instead. + Include gansidecl.h; remove things defined there. + See if getenv needs to be declared. + * cpplib.c: Likewise. + * cexp.y: Use autoconf symbols to select what include files are needed. + * genattrtab.c, toplev.c: Likewise. + +Tue Dec 2 21:44:25 1997 Richard Kenner + + * reload1.c (reload): Make copy of MEM before setting + req_equiv_mem if the address is a PLUS. + +Tue Dec 2 07:03:47 1997 Pat Rankin + + * vax/xm-vms.h (STDC_HEADERS, HAVE_STDLIB, HAVE_STRING): Define. + (mesg_implicit_function_declaration): New macro. + + * make-l2.com: Compile libgcc2.c with `-fexceptions' specified. + +Mon Dec 1 17:44:59 1997 Jeffrey A Law (law@cygnus.com) + + * dwarf2out.c (output_call_frame_info): Use ASM_OUTPUT_ASCII to + output ASCII by default; only use ASM_OUTPUT_DWARF_STRING if + flag_debug_asm is on. + (output_die, output_pubnames, output_line_info): Likewise. + +Mon Dec 1 17:15:30 1997 Philip Blundell + + * arm/linux.h (SUBTARGET_CPU_DEFAULT): Define instead + of TARGET_CPU_DEFAULT. + +Mon Dec 1 16:51:23 1997 J.J. van der Heijden + + * i386/mingw32.h (MATH_LIBRARY): Set to "-lcrtdll". + +Mon Dec 1 16:46:57 1997 Richard Kenner + + * c-aux-info.c: Add prototypes for static functions. + * c-lex.c, emit-rtl.c, rtl.c, xcoffout.c: Likewise. + + * i386.h (TARGET_SWITCHES): Add entries for "windows" and "dll". + +Mon Dec 1 16:42:20 1997 Jim Wilson + + * mips.md (fix_trunc{dfsi,sfsi,dfsi}2): Add '*' in operand 3. + +Sun Nov 30 20:25:59 1997 Richard Kenner + + * expr.c (get_inner_reference): For ARRAY_REF, if need + WITH_RECORD_EXPR, make it with the ARRAY_REF as exp. + + * expr.c (store_constructor): Use TARGET, not EXP, for + WITH_RECORD_EXPR when offset has a placeholder. + +Sun Nov 30 11:19:00 1997 J.J. van der Heijden + + * objc/Make-lang.in (libobjc.dll): Rename -dll flag to -mdll. + +Sun Nov 30 08:42:29 1997 Bruno Haible + + * stmt.c (expand_end_bindings): Cleanups and incoming gotos are + not incompatible. + +Sun Nov 30 05:45:06 1997 Michael P. Hayes + + * jump.c (jump_optimize): Use find_insert_position in two more places. + +Sat Nov 29 13:47:40 1997 Richard Kenner + + * alpha/vms.h (HAVE_STRERROR, HAVE_{LIMITS,STDDEF,TIME}_H): Define. + +Sat Nov 29 08:29:47 1997 J.J.van der Heijden + + * configure.in: Add check for kill. + * gcc.c: Define kill as raise if not HAVE_KILL. + +Sat Nov 29 06:18:08 1997 Michael P. Hayes + + * jump.c (find_insert_position): New function. + (jump_optimize): Use it when making new copy of insn after test. + +Sat Nov 29 05:54:57 1997 Douglas Rupp + + * alpha/vms.h (BIGGEST_ALIGNMENT, ENCODE_SECTION_INFO): No longer + override. + +Sat Nov 29 05:43:37 1997 Richard Kenner + + * getpwd.c (getpwd, [VMS]): Only add extra arg if VMS. + + * alpha/xm-vms.h (HAVE_VPRINTF, HAVE_PUTENV): Define. + + * cccp.c (index, rindex): Add conditional defs to strchr and strrchr.s + * cpplib.c: Likewise. + * gcov.c: Include gansidecl.h. + +Fri Nov 28 21:17:51 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * objc/objc-act.c: Include "output.h". + + * objc/Make-lang.in (objc-parse.o, objc-act.o): Also depend on + $(srcdir)/output.h. + + * objc/Object.m (+conformsTo:): Surround assignment with parentheses. + + * objc/archive.c, objc/class.c, objc/encoding.c: Finish prototyping. + * objc/init.c, objc/objc-act.c, objc/objc-api.h: Likewise. + * objc/runtime.h, objc/sendmsg.c: Likewise. + +Fri Nov 28 19:15:53 1997 Mark Kettenis + + * objc/thr-posix.c (__objc_mutex_allocate): Allocate + mutex type instead of assuming it fits in a void * type. + (__objc_mutex_deallocate): Free mutex type. + (__objc_mutex_lock): Pass mutex type instead of pointer to it. + (__objc_mutex_{try,un}lock): Likewise. + (__objc_condition_allocate): Allocate condition type instead + of assuming it fits in a void * type. + (__objc_condition_deallocate): Free condition type. + (__objc_condition_wait): Pass condition type instead of pointer to it. + (__objc_condition_{broadcast,signal}): Likewise. + +Fri Nov 28 17:07:25 1997 David Edelsohn + + * rs6000.c (function_arg_partial_nregs): Undo 11/26 change. + +Fri Nov 28 12:34:03 1997 Scott Christley + + * objc/Make-lang.in (runtime-info.h): Add comment in file. + + * objc/selector.c: Replace all occurences of sarray_get + with sarray_get_safe. + * objc/sendmsg.c: Likewise. + + * protoize.c (include_defaults): Add component element as in cccp.c. + * nextstep.h (INCLUDE_DEFAULTS): Add component element. + (ASM_COMMENT_START): Correct assembly comment string. + * objc/Make-lang.in (objc/{NXConstStr,Object,Protocol,linking): + Compile with GNU runtime. + +Fri Nov 28 12:27:50 1997 Ovidiu Predescu + + Generate platform information required by ObjC runtime. + * toplev.c (lang_options): New ObjC specific compiler flag. + * objc/Make-lang.in: Add target to generate runtime-info.h file. + * objc/objc-act.c (print_struct_values): New variable. + (generate_struct_by_value_array): New function. + (lang_init): Call generate_struct_by_value_array if requested. + (lang_decode_option): Check for new compiler flag.s + * objc/sendmsg.c (__objc_get_forward_imp): Check size of type + for determining proper forwarding function. + +Fri Nov 28 05:58:30 1997 Richard Kenner + + * regclass.c (record_address_regs): Use REG_OK_FOR_{INDEX,BASE}, + not the REGNO versions. + +Thu Nov 27 16:28:04 1997 Scott Snyder + + * dwarf2out.c (outout_call_frame_info): Ensure info has proper + alignment. + + * libgcc2.c (__throw): Initialize HANDLER. + +Thu Nov 27 16:23:25 1997 Kaveh R. Ghazi + + * tree.h, rtl.h: See if need declarations for free. + * tree.c, bc-optab.c: Get the declaration of free from stdlib.h. + +Thu Nov 27 07:21:54 1997 Jason Merrill + + * except.h: Add outer_context_label_stack. + * except.c: Likewise. + (expand_start_all_catch): Push the outer_context for the try block + onto outer_context_label_stack. + (expand_end_all_catch): Use it and pop it. + + * except.c (expand_start_all_catch): One more do_pending_stack_adjust. + + * expr.c (preexpand_calls): Don't look past a TRY_CATCH_EXPR. + +Thu Nov 27 07:15:10 1997 Michael Meissner + + * rs6000.c (SMALL_DATA_REG): Register to use for small data relocs. + (print_operand{,_address}): Use SMALL_DATA_REG for register involved in + small data relocations. + + * rs6000/linux.h (LINK_SPEC): Pass -dynamic-linker /lib/ld.so.1 if + -dynamic linker is not used. + + * rs6000.md (call insns): For local calls, use @local suffix under + System V; don't use @plt under Solaris. + +Wed Nov 26 15:12:32 1997 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (LIBGCC2_CFLAGS): Add -fexceptions. + + * toplev.c (flag_exceptions): Default value is 2. + (compile_file): If flag_exceptions still has the value 2, then + set it to 0. + +Wed Nov 26 14:58:42 1997 Michael Meissner + + * rs6000.c (output_function_profiler): Put label address in r0, and + store LR in 4(sp) for System V/eabi. + + * rs6000.h (ASM_OUTPUT_REG_{PUSH,POP}): Keep stack aligned to 16 + byte boundary, and maintain stack backchain. + + (Originally from Geoffrey Keating) + * rs6000.c (function_arg): Excess floating point arguments don't + go into GPR registers after exhausting FP registers under the + System V.4 ABI. + (function_arg_partial_nregs): Likewise. + + * rs6000.md (call insns): If -fPIC or -mrelocatable, add @plt + suffix to calls. + +Wed Nov 26 14:09:01 1997 Jason Merrill + + * dwarfout.c (output_type): If finalizing, write out nested types + of types we've already written. + + * toplev.c (main): Complain about -gdwarfn. + +Wed Nov 26 12:37:56 1997 J.J. van der Heijden + + * mingw32.h (PATH_SEPARATOR): Moved to xm-mingw32.h + * xm-mingw32.h (PATH_SEPARATOR): Moved here from mingw32.h. + + * getpwd.c (getpwd): Use VMS implementation of _WIN32 unless cygwin32. + +Wed Nov 26 12:26:44 1997 John Hassey + + * m88k/dgux.h (ASM_CPU_SPEC) : No whitespace allowed. + + * m88k.h (SUPPORTS_ONE_ONLY) : Must be svr4. + + * i386/dgux.h (ASM_OUTPUT_ALIGN): Deleted. + + * i386/dgux.c (output_file_start) : Changed ix86_isa_string + to ix86_arch_string. + + * cplus-dem.c (fancy_abort): Added. + +Wed Nov 26 06:07:50 1997 Richard Earnshaw + + * arm/coff.h (TARGET_DEFAULT): Add ARM_FLAG_APCS_32 to defaults. + + * configure.in (arm*-*-*): Recognize --with-cpu for ARM processors. + +Wed Nov 26 05:05:36 1997 Richard Kenner + + * libgcc2.c (inhibit_libc): Define #ifdef CROSS_COMPILE. + + * mips/xm-iris6.h (malloc, realloc, calloc): No longer declare. + (USG): Define here. + (xm-iris5.h): No longer include; just include xm-mips.h. + + * mips-tfile.c (parse_def): Properly recognize bitfield and + count array dimensions. + + * protoize.c: Remove declarations of void, exit, and free. + + * i386/mingw32.h (LINK_SPEC, STARTFILE_SPEC): Change -dll to -mdll. + + * configure.in: Check for sys/file.h. + * gcc.c (sys/file.h): Include if HAVE_SYS_FILE_H. + + * configure.in: Only give error on bad --with-cpu value for target. + +Sat Nov 22 19:21:55 1997 Philippe De Muyter + + * dwarf2out.c (CIE_LENGTH_LABEL, FDE_LENGTH_LABEL): New macros. + (ASM_OUTPUT_DWARF_VALUE4): New macro. + (ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL): Define if SET_ASM_OP is + defined. + (output_call_frame_info): Don't output forward label differences + if ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL is defined. + Substitute instead simple label and define this label later to be + difference of desired labels after they have been defined. + * m68k/mot3300.h (SET_ASM_OP): Define when not using gas. + + * gcc.c (process_command): Don't take address of function fatal when + calling lang_specific_driver. + +Sat Nov 22 17:08:03 1997 J. Kean Johnston + + * i386/sco5.h (SELECT_RTX_SECTION): Redefine to work with -fpic. + (LIBGCC_SPEC, LIB_SPEC): Link with correct libgcc.a. + (HAVE_ATEXIT): Define. + +Sat Nov 22 12:20:22 1997 Richard Earnshaw + + * arm.md (movsfcc{,_hard}_insn): Specify mode for all alternatives. + +Sat Nov 22 06:56:16 1997 Richard Kenner + + * function.c (instantiate_decl): Only ignore ADDRESSOF if arg is REG. + + * configure.in: Check for functions before checking which need decls. + (bcopy, bzero, bcmp, index, rindex): Add checks. + (vax-*-sysv*): Fix typo in setting of xm_file. + * aclocal.m4: Add conditional definitions of index and rindex. + * gansidecl.h (bcopy, bzero, bcmp, index, rindex): If don't + have one of these, define macro to use ANSI form. + * pa/xm-pahpux.h (bcopy, bzero, bcmp, rindex, index): No longer define. + * mips/xm-sysv.h, xm-m88k.h, m68k/xm-plexus.h: Likewise. + * m68k/xm-mot3300.h, m68k/xm-m68kv.h, m68k/xm-hp320.h: Likewise. + * winnt/xm-winnt.h, vax/xm-vms.h, m68k/xm-3b1.h: Likewise. + * i386/xm-os2.h, i386/xm-mingw32.h, alpha/xm-vms.h: Likewise. + * xm-svr4.h, xm-svr3.h: Likewise. + * clipper/xm-clix.h: Likewise. + (TARGET_MEM_FUNCTIONS): Define here. + * xm-linux.h (bcmp, bcopy, bzero, index, rindex): No longer undefine. + * xm-convex.h (bcopy, bzero): No longer define. + * vax/xm-vaxv.h, sparc/xm-pbd.h, mips/xm-iris{3,4,5}.h: Likewise. + * m68k/xm-crds.h, m68k/xm-altos3068.h, i386/xm-sun.h: Likewise. + * i386/xm-osf.h, i386/xm-aix.h, xm-i370.h, ns32k/xm-genix.h: Likewise. + +Sat Nov 22 06:46:26 1997 Paul Eggert + + * c-typeck.c, collect2.c, cpplib.c, dwarfout.c, gcov.c, protoize.c: + Don't include unless there's no . + +Fri Nov 21 06:46:50 1997 Richard Kenner + + * configure.in (i[3456]86-*-freebsd{,elf}*): Delete i386/xm-freebsd.h. + * xm-freebsd.h, i386/xm-freebsd.h: Deleted. + + * i386/xm-cygwin32.h (HAVE_RUSAGE, HAVE_FILE_H): Deleted. + * i386/xm-mingw32.h, rs6000/xm-cygwin32.h: Likewise. + + * xm-std32.h: New file, so far unused. + +Fri Nov 21 05:50:54 1997 Andreas Schwab + + * m68k.c (legitimize_pic_address): Make sure pic register marked used. + + * dwarf2out.c (output_call_frame_info): Call app_enable and + app_disable if flag_debug_asm, not if flag_verbose_asm. + +Thu Nov 20 16:37:36 1997 Richard Kenner + + * expr.c (expand_builtin_apply): Fix typo in last change. + + * expr.c (expand_assignment): If assigning to readonly field, + mark rtx as unchanging. + + * configure.in: Add checks for functions putenv, popen, and vprintf. + (i[3456]86-*-netbsd*): No longer need i386/xm-netbsd.h. + (i860-alliant-*): No longer need i860/xm-fx2800.h. + (m68k-ncr-sysv*): Use xm-svr3.h instead of m68k/xm-tower.h. + (m68k-sun-sunos*): No longer need m68k/xm-sun3.h. + (m68k-*-netbsd*): No longer need m68k/xm-netbsd.h. + (mips-dec-netbsd*): No longer need mips/xm-netbsd.h. + (ns32k-pc532-netbsd*): No longer need ns32k/xm-netbsd.h. + (sparc-*-netbsd*): No longer need sparc/xm-netbsd.h. + (vax-*-netbsd*): No longer need config/xm-netbsd.h. + * arm/xm-netbsd.h: No longer include xm-netbsd.h. + * xm-linux.h (HAVE_VPRINTF, HAVE_POPEN, HAVE_PUTENV): Deleted. + * xm-mips.h (HAVE_VPRINTF, HAVE_PUTENV): Deleted. + * i386/xm-osf.h, xm-arm.h, xm-alpha.h: Likewise. + * xm-sparc.h (HAVE_POPEN): Deleted. + * xm-sh.h (HAVE_VPRINTF): Deleted. + * mips/xm-iris4.h, mips/xm-iris5.h, xm-m88k.h: Likewise. + * m68k/xm-crds.h, m68k/xm-atari.h, m68k/xm-amix.h: Likewise. + * xm-svr3.h, xm-svr4.h, i386/xm-mingw32.h: Likewise. + * i386/xm-os2.h (HAVE_PUTENV): Deleted. + * i386/xm-dos.h, i386/xm-aix.h: Likewise. + * arm/xm-netbsd.h (HAVE_VPRINTF, HAVE_STRERROR): No longer + need undefine. + * xm-netbsd.h, i386/xm-netbsd.h, m68k/xm-netbsd.h: Deleted. + * mips/xm-netbsd.h, ns32k/xm-netbsd.h, sparc/xm-netbsd.h: Likewise. + * i860/xm-fx2800.h, m68k/xm-sun3.h, m68k/xm-tower.h: Likewise. + +Thu Nov 20 16:04:24 1997 Richard Earnshaw + + * explow.c (plus_constant_wide, case MEM): If about to call + force_const_mem, generate the rtl in a saveable obstack. + + * arm.md (movhi): Pass the full MEM to storeinthi, storehi and + storehi_bigend. + (storeinthi, storehi, storehi_bigend): Be more conservative about + when not to force a PLUS or MINUS into a REG. Use change_address + to create new MEMs. + +Wed Nov 19 15:16:04 1997 Ulrich Drepper + + * c-common.c (print_char_table): Add a and A to float formats. + (scan_char_table): Likewise. + (check_format_info): Recognize `a' as allocate flag only if used + in correct context. + +Wed Nov 19 12:56:54 1997 Andreas Schwab + + * configure.in: Fix check for . + +Tue Nov 18 19:27:01 1997 J"orn Rennecke + + * sh.md (attribute "type"): Add nil. + (movsi_ie): y/y alternative is type nil. + (movsf_ie): Replace ry/yr/X alternative by r/y/X , y/r/X and y/y/X. + (movsf_ie+1): Delete. + +Tue Nov 18 18:38:41 1997 Paul Eggert + + * cccp.c (warn_undef): Now static. + (eval_if_expression): Don't warn about undefined preprocessor symbols + in system headers. + * cexp.y (parse_c_expression): + Now takes new arg specifying whether to warn + about undefined preprocessor symbols. + (warn_undef): Now local and static; independent of warn_undef in cccp.c + (yylex): `register' -> `register int', needed for C9X. + + The following changes are only if TEST_EXP_READER is defined: + (expression_signedp): New var. + (start): Set expression_signedp to signedness of expression. + (print_unsigned_host_wide_int): New function. + (main): Use it to print value of expression, instead of hoping that + `long' is long enough. Print "u" after unsigned values. + +Tue Nov 18 18:33:30 1997 Jim Wilson + + * mips.c (save_restore_insns): If gp_offset or fp_offset are + large_int, emit two insns instead of one splitable insn. + * dwarf2out.c (dwarf2out_frame_debug): When set cfa_store_offset + from cfa_temp_value, use cfa_offset. Add assert checking that + cfa_reg is SP. + +Tue Nov 18 09:11:58 1997 Richard Kenner + + * fold-const.c (div_and_round_double): Return overflow for + divide-by-zero instead of aborting. + + * tree.c (substitute_in_expr, case TREE_LIST): Fix two typos. + +Tue Nov 18 05:03:52 1997 Jeffrey A Law + + * arm.c (output_move_double): Allocate 3 entries in otherops array. + +Tue Nov 18 02:41:01 1997 Paul Eggert + + * cccp.c (quote_string_for_make): New function. + (deps_output): Use it to fix bug with file name quoting in -M output. + +Mon Nov 17 13:28:33 1997 Philip Blundell + + * arm/lib1funcs.asm (__div0): Provide GNU/Linux implementation. + * arm/t-linux (LIB1ASMFUNCS): Use it. + +Mon Nov 17 09:13:59 1997 Andreas Schwab + + * function.c (purge_addressof_1): Make copy when substituting argument + of ADDRESSOF. + (fixup_var_refs_1): Likewise. + + * m68k.c: Include tree.h. + +Mon Nov 17 09:01:05 1997 Richard Kenner + + * getpwd.c (getpwd, [VMS]): Add extra arg of 0 to getcwd call. + + * alpha/vms.h ({OPTIMIZATION,OVERRIDE}_OPTIONS): Delete, for now. + * alpha/xm-vms.h (DIR_SEPARATOR, PATH_SEPARATOR): Delete. + +Mon Nov 17 08:52:45 1997 Richard Earnshaw + + * function.c (fixup_stack_1): Also fix-up refs via ARG_POINTER_REGNUM. + + * configure.in (arm-*-netbsd*): Doesn't need collect2. + +Mon Nov 17 08:50:01 1997 Stephen L Moshier + + * i386/isc.h (DWARF2_UNWIND_INFO): Define as 0. + +Mon Nov 17 08:42:28 1997 Michael P. Hayes + + * flow.c (propagate_block): Look for pre-inc/dec within PARALLEL. + +Mon Nov 17 03:14:46 1997 Paul Eggert + + * cpplib.c (file_size_and_mode): Remove. + (finclude): Don't assume long and off_t are same size or that + mode_t fits in int. + * cccp.c: (main, finclude, check_precompiled): Don't assume size_t + and off_t are same size. + * gcov.c (read_files): Don't assume off_t and unsigned are same size. + +Sun Nov 16 18:56:40 1997 Scott Christley + + * objc/objc-act.c (objc_demangle): New function. + (objc_printable_name): New function. + (init_objc): Change default function. + + * expr.c (expand_builtin_apply): Prefer nonlocal over block. + +Sun Nov 16 18:10:13 1997 Fila Kolodny + + * i370.c (i370_function_prolog): New function from i370.h. + * i370.h (FUNCTION_PROLOG): Just call i370_function_prolog. + +Sun Nov 16 08:40:35 1997 Bruno Haible + + * calls.c (expand_call, store_one_arg): Don't pass QImode arguments + to emit_library_call. + * expr.c (emit_push_insn, expand_assignment, store_expr): Likewise. + (expand_expr, expand_builtin): Likewise. + * function.c (put_var_into_stack, assign_parms): Likewise. + * alpha.c (alpha_builtin_saveregs): Likewise. + * clipper.c (clipper_builtin_saveregs): Likewise. + * m88k.c (m88k_builtin_saveregs): Likewise. + * pa.c (hppa_builtin_saveregs): Likewise. + * sparc.c (sparc_builtin_saveregs): Likewise. + +Sun Nov 16 07:39:08 1997 Paul Eggert + + * real.h (REAL_VALUES_IDENTICAL): New macro. + * expr.c (is_zeros_p): Don't consider -0.0 to be all zeros. + * fold-const.c (operand_equal_p): Don't consider -0.0 identical to 0.0. + * tree.c (simple_cst_equal): Likewise. + * varasm.c (immed_real_const_1): Use new REAL_VALUES_IDENTICAL macro. + +Sun Nov 16 07:29:12 1997 Richard Kenner + + * acconfig.h (NEED_DECLARATION_{,R}INDEX): New cases. + * configure.in: See if need declarations for index and rindex. + * c-typeck.c, collect2.c, cpplib.c, dwarfout.c, gcov.c, protoize.c: + Include stdlib.h, string.h, and strings.h, if they exist. + Only declare index and rindex if needed. + * collect2.c: Only declare free if needed. + + * regclass.c (record_address_regs): Refine choice of index and base + when have sum of two regs, one of which is a hard reg. + +Sun Nov 16 07:07:45 1997 Robert Lipe (robertl@dgii.com) + + * i386/sco5.h (ASM_OUTPUT_ALIGNED_BSS): Define as in sysv4 and linux + (HAVE_ATEXIT): No longer define. This confused ELF destructors. + (DBX_DEBUGGING_INFO): Define. + +Sat Nov 15 09:55:11 1997 Richard Earnshaw (rearnsha@arm.com) + + * arm.h (GO_IF_LEGITIMATE_ADDRESS): Don't accept MINUS (until reload + knows what to do with it). + +Thu Nov 13 11:07:41 1997 Michael Meissner + + * rs6000.c (num_insns_constant): Use REAL_VALUE_FROM_CONST_DOUBLE to + pick apart floating point values, instead of using CONST_DOUBLE_LOW + and CONST_DOUBLE_HIGH. + + * rs6000.md (define_splits for DF constants): Use the appropriate + REAL_VALUE_* interface to pick apart DF floating point constants in + a machine independent fashion. + +Thu Nov 13 07:30:53 1997 Richard Earnshaw (rearnsha@arm.com) + + * arm/netbsd.h (LINK_SPEC): Redefine -- pass -X. + + * arm.md (movsicc_insn): Add extra reload alternatives for better + register tying. + (movsfcc_hard_insn, movsfcc_soft_insn, movdfcc_insn): Likewise. + +Mon Nov 10 19:32:14 1997 Doug Evans + + * sparc.md (mov[sdt]f_const_insn): Fix condition to match what + instruction can handle. + +Mon Nov 10 03:02:19 1997 Jason Merrill + + * stmt.c (expand_decl_cleanup_no_eh): New fn. + + * except.c (expand_leftover_cleanups): do_pending_stack_adjust. + +Sun Nov 9 14:34:47 1997 David Edelsohn + + * rs6000.md (lshrdi3_power): Delete '&' from first alternative and + swap instruction order. + +Sun Nov 9 09:51:08 1997 Michael P. Hayes + + * machmode.def (QCmode, HCmode): New modes. + +Sun Nov 9 09:24:21 1997 J"orn Rennecke + + * combine.c (sets_function_arg_p): New function. + (combinable_i3pat): Check if combining with any but the first + argument register setting insn for a function call. + + * a29k.h (ELIGIBLE_FOR_EPILOGUE_DELAY): Avoid sheduling load from + stack slot. + +Sun Nov 9 09:17:53 1997 Richard Earnshaw (rearnsha@arm.com) + + * loop.c (strength_reduce): If initial value of BIV is equivalent to + a constant, record that as initial value. + (check_dbra_loop): Don't reverse loop if initial value isn't CONST_INT. + +Sun Nov 9 09:12:41 1997 Tristan Gingold + + * expr.c (emit_push_insn): Avoid infinite recursion + when -fcheck-memory-usage. + +Sun Nov 9 08:03:42 1997 Richard Kenner + + * cse.c (simplify_binary_operation): Fix error in last change. + +Sun Nov 9 07:56:31 1997 Pat Rankin + + * vmsconfig.com [version.opt]: Parse version string more robustly. + [@variable@]: Discard configure tokens when using Makefile.in. + [libgcc2-cxx.list]: Generate this new file for CXX_LIB2FUNCS. + [cp/input.c]: Suppress it as workaround to avoid linker warning. + [objc-parse.y]: Now lives in the objc subdirectory. + * make-cc1.com [objc-parse.{c,y}]: Ditto. + * make-cccp.com [prefix.c]: Compile additional source file. + + * cccp.c (VMS_freopen, VMS_fopen, VMS_open, VMS_fstat): Call + corresponding library routine specified via its ordinary name + rather than with a decc$ prefix. (Reverses Oct 19 change.) + + * cccp.c, cexp.y [HOST_WIDE_INT]: Manually splice long lines + of avoid backslash+newline continuation on #if directives. + +Sun Nov 9 01:54:54 1997 Jeffrey A Law (law@cygnus.com) + + * local-alloc.c (block_alloc): Don't lose if two SCRATCH expressions + are shared. + +Sat Nov 8 23:01:37 1997 Michael P. Hayes + + * cse.c (simplify_binary_operation): Don't simplify divide by zero + for targets that don't support a representation of INFINITY. + +Sat Nov 8 22:37:29 1997 Richard Earnshaw + + * Makefile.in (cse.o): Depend on expr.h. + * cse.c: Include expr.h. + (fold_rtx, case MEM): For ADDRESSOF, create new MEM. + +Sat Nov 8 19:27:56 1997 J"orn Rennecke + + * expr.c (expand_increment): When enqueing a postincrement for a MEM, + use copy_to_reg if address is not a general_operand. + +Sat Nov 8 18:39:56 1997 Jason Merrill + + * libgcc2.c (L_eh): Define __eh_pc here. + Replace __eh_type with generic pointer __eh_info. + +Sat Nov 8 07:03:47 1997 Richard Kenner + + * alpha.h (SECONDARY_OUTPUT_RELOAD_CLASS): If FLOAT_REGS, + need secondary reload for QImode and HImode even if BWX. + + * expmed.c (store_split_bit_field): Force ADDRESSOF into register. + + * cse.c (fold_rtx, case ADDRESSOF): New case (that does nothing). + + * function.c (fixup_var_refs_1, case ADDRESSSOF): Check that + new value is valid for insn. + + * stor-layout.c (get_best_mode): Refine test for field within + unit to work properly for negative positions. + + * print-rtl.c (print_inline_rtx): Save and restore sawclose and indent. + + * reload.c (find_replacement): If PLUS, MINUS, or MULT, see if + either arg contains a replacement. + +Fri Nov 7 10:22:24 1997 Jason Merrill + + * frame.c (add_fdes, count_fdes): Go back to checking pc_begin for + linked once FDEs. + +Fri Nov 7 06:50:57 1997 Richard Kenner + + * alpha.h (FUNCTION_VALUE): Take into account promotion of pointers. + + * unroll.c (back_branch_in_range_p): Refine check for INSN at loop end. + +Wed Nov 5 18:17:50 1997 Paul Eggert + + * fixinc.svr4: Replace `__STDC__ - 0 == 1' + with `defined (__STRICT_ANSI__)'. + +Tue Nov 4 18:32:44 1997 Jim Wilson + + * mips.md (insv, extzv, extv): Add change_address call. + (movsi_ulw, movsi_usw): Change QImode to BLKmode in pattern. + * mips.c (mips_expand_epilogue): Emit blockage insn before call to + save_restore_insns if no FP and GP will be restored. + + * acconfig.h (HAVE_INTTYPES_H): Undef. + * configure.in (inttypes.h): Check for conflicts between sys/types.h + and inttypes.h, and verify that intmax_t is defined. + * mips/x-iris (CC, OPT, OLDCC): Comment out. + * mips/x-iris3: Likewise. + +Tue Nov 4 17:28:31 1997 Doug Evans + + * c-lex.c (MULTIBYTE_CHARS): #undef if cross compiling. + (yylex): Record wide strings using target endianness, not host. + +Tue Nov 4 16:18:19 1997 Richard Kenner + + * Makefile.in (distdir-start): Add dependency on $(srcdir)/config.in. + +Tue Nov 4 06:14:30 1997 Paul Eggert + + * c-lex.c (yylex): Don't warn about constants like + 9223372036854775807 and 18446744073709551615U on an L32LL64 host + unless pedantic. + +Mon Nov 3 18:42:44 1997 Jim Wilson + + * i386.c (load_pic_register): Call prologue_get_pc_and_set_got. + * i386.md (prologue_{set_got,get_pc}): Add UNSPEC_VOLATILE to pattern. + (prologue_get_pc_and_set_got): New pattern. + +Mon Nov 3 13:42:21 1997 Paul Eggert + + * cccp.c, cpplib.c (compare_defs): Don't complain about arg name + respellings unless pedantic. + * cpplib.c (compare_defs): Accept pfile as new arg. + All callers changed. + +Fri Oct 31 07:10:09 1997 Jeffrey A Law (law@cygnus.com) + + * global.c (global_alloc): Free the conflict matrix after + reload has finished. + +Thu Oct 30 17:30:42 1997 Doug Evans + + * configure.in (sparc-*-elf*): Use sparc/elf.h, sparc/t-elf. + Set extra_parts. + (sparc*-*-*): Recognize --with-cpu=v9. + * sparc/elf.h: New file. + * sparc/t-elf: New file. + +Thu Oct 30 16:36:17 1997 Richard Kenner + + * stmt.c (expand_asm_operand): If error in matching constraint, + don't emit asm. + +Thu Oct 30 12:21:06 1997 J"orn Rennecke + + * va-sh.h (__va_arg_sh1): Define. + (va_arg): Use it. + SH3E doesn't use any integer registers for subsequent arguments + once a non-float value was passed in the stack. + * sh.c (machine_dependent_reorg): If optimizing, put explicit + alignment in front label for ADDR_DIFF_VEC. + * sh.h (PASS_IN_REG_P): Fix SH3E case. + (ADJUST_INSN_LENGTH): If not optimizing, add two extra bytes length. + +Tue Oct 28 21:09:25 1997 Jim Wilson + + * m68k.md (btst patterns): Add 5200 support. + +1997-10-28 Brendan Kehoe + + * global.c (global_alloc): Use xmalloc instead of alloca for + CONFLICTS, since max_allocno * allocno_row_words alone can be more + than 2.5Mb sometimes. + +Tue Oct 28 15:06:44 1997 J"orn Rennecke + + * sh/elf.h (PREFERRED_DEBUGGING_TYPE): Undefine before including + svr4.h. + +Tue Oct 28 10:19:01 1997 Jason Merrill + + From Brendan: + * dwarf2out.c (output_call_frame_info): Use l1 instead of ".". + +Mon Oct 27 16:01:14 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.h (GO_IF_LEGITIMATE_ADDRESS): Disable reg+reg. + +Mon Oct 27 16:11:52 1997 J"orn Rennecke + + * sh.c (machine_dependent_reorg): When -flag_delayed_branches, + put an use_sfunc_addr before each sfunc. + * sh.md (use_sfunc_addr, dummy_jump): New insns. + (casesi): For TARGET_SH2, emit a dummy_jump after LAB. + +Mon Oct 27 11:49:43 1997 Jason Merrill + + * dwarf2.h: Remove dwarf2out prototypes. + * tree.h: And put them here. + * m68k.c, i386.c: Don't include dwarf2.h. + +Mon Oct 27 00:02:13 1997 Paul Eggert + + Remap include files with header.gcc only if user or configuration + file specifies "-remap". + + * cccp.c (remap): New var. + (main): Set it if user specifies "-remap". + (open_include_file): Remap only if `remap' is nonzero. + + * cpplib.h (struct cpp_options): New member `remap'. + * cpplib.c (cpp_options_init): Set remap to 0. + (open_include_file): Remap only if `remap' is nonzero. + (cpp_handle_options): Set remap if user specifies "-remap". + + * i386/cygwin32.h, rs6000/cygwin32.h (CPP_SPEC): Define with -remap. + +Sun Oct 26 11:41:49 1997 Jason Merrill + + * dwarf2out.c (output_call_frame_info): The CIE pointer is now a 32 + bit PC-relative offset. The exception range table pointer is now in + the CIE. + * frame.c (dwarf_cie, dwarf_fde): Rename CIE_pointer to CIE_delta. + (count_fdes, add_fdes, get_cie): Adjust. + (cie_info, extract_cie_info, __frame_state_for): Adjust eh_ptr uses. + + From H.J. Lu: + * frame.c (count_fdes, add_fdes): Skip linked once FDE entries. + +Sat Oct 25 20:29:39 1997 Alexandre Oliva + + * Makefile.in (float.h-nat): If float.h is to be empty, ensure it is. + +Sat Oct 25 20:16:52 1997 Kaveh R. Ghazi + + * prefix.c: Use stdarg.h only ifdef __STDC__. Otherwise, + use varargs.h. Wrap header with <>, not "". + +Sat Oct 25 20:10:57 1997 Robert Lipe (robertl@dgii.com) + + * i386/sco5.h (EH_FRAME_SECTION_ASM_OP{,_ELF,_COFF}): Define. + (DWARF2_UNWIND_INFO): Likewise. + (EXTRA_SECTIONS): Add in_eh. + +Sat Oct 25 12:20:58 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.h (TARGET_SWITCHES): Add -mmult-bug and -mno-mult-bug. + (TARGET_MULT_BUG): Define. + (TARGET_DEFAULT): Default to TARGET_MULT_BUG. + * mn10300.md (mulsi3): Handle TARGET_MULT_BUG. + +Fri Oct 24 15:43:57 1997 Michael Meissner + + * rs6000.c (toplevel): Move include stdio.h before config.h. + + (Patch from H.J. Lu, Aug 27, 1997) + * rs6000/linux.h (DEFAULT_VTABLE_THUNKS): New; defined as 1. + + (Patch from Jeff Law, Oct 22, 1997) + * rs6000.c (struct machine_function): Add pic_offset_table_rtx. + (rs6000_{save,restore}_machine_status): Save/restore it. + + * rs6000.md (movsi_got_internal_mem): New pattern to work around + case where GOT value did not get a register. + (movsi_got_internal_mem splitter): Split above pattern. + + (Patch from Geoffrey Keating, Oct 21, 1997) + * rs6000.c (rs6000_stack_info): Avoid creating a stack + frame under System V ABI if we only need to save the LR. + + (Patch from Joel Sherrill, Sep 1, 1997) + * rs6000/sysv4.h (SUBTARGET_SWITCHES): Add new macro + EXTRA_SUBTARGET_SWITCHES, which defaults to nothing. + + (Patch from Geoffrey Keating, Oct 20, 1997) + * rs6000/t-ppccomm (CRTSTUFF_T_CFLAGS{,_S}): Add -msdata=none + switch. + +Fri Oct 24 15:25:50 1997 Doug Evans + + * sparc.h (ASM_SPEC): Delete. + +Fri Oct 24 13:16:24 1997 Jeffrey A Law (law@cygnus.com) + + * mn10200.c (indirect_memory_operand): Delete unused function. + * mn10200.h (EXTRA_CONSTRAINT): Handle 'R'. + * mn10200.md (bset, bclr insns): Handle output in a reg too. + + * mn10300.c (symbolic_operand, legitimize_address): New functions. + * mn10300.h (LEGITIMIZE_ADDRESS): Call legitimize_address. + (GO_IF_LEGITIMATE_ADDRESS): Don't allow base + symbolic. + +Thu Oct 23 08:03:59 1997 J"orn Rennecke + + * dbxout.c (dbxout_start_new_source_file): Use output_quoted_string + for FILENAME. + +Tue Oct 21 16:18:13 1997 Paul Eggert + + * winnt/win-nt.h (CPP_SPEC): Remove reference to obsolete + option -lang-c-c++-comments. + +Tue Oct 21 10:00:20 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.md (movqi, movhi): Avoid using address registers as + destinations unless absolutely necessary. + + * mn10200.c (expand_prologue): Fix typo. + + * mn10200.h (GO_IF_LEGITIMATE_ADDRESS): Do not allow indexed addresses. + * mn10200.md (neghi2): Provide an alternative which works if + the input and output register are the same. + + * mn10300.c (print_operand): Handle 'S'. + * mn10300.md (ashlsi3, lshrsi3, ashrsi3): Use %S for + shift amount in last alternative + + * mn10300.c (expand_epilogue): Rework to handle register restores + in "ret" and "retf" instructions correctly. + +Tue Oct 21 07:35:19 1997 Richard Earnshaw (rearnsha@arm.com) + + * arm.md (insv): Avoid writing result into a paradoxical subreg. + +Tue Oct 21 07:12:28 1997 J"orn Rennecke + + * sh/elf.h (PREFERRED_DEBUGGING_TYPE): Don't redefine. + +Mon Oct 20 12:04:04 1997 Nick Clifton + + * v850.h (CPP_SPEC): Define __v850__. + (CPP_PREDEFINES): Do not define __v850__. + + * xm-v850.h: Use __v850 rather than __v850__ to identify v850 port. + +Mon Oct 20 17:29:55 1997 Doug Evans + + * sparc.h (SPARC_V9,SPARC_ARCH64): Delete. + (DEFAULT_ARCH32_P): New macro. + (TARGET_ARCH{32,64}): Allow compile time or runtime selection. + (enum cmodel): Declare. + (sparc_cmodel_string,sparc_cmodel): Declare. + (SPARC_DEFAULT_CMODEL): Provide default. + (TARGET_{MEDLOW,MEDANY}): Renamed to TARGET_CM_{MEDLOW,MEDANY}. + (TARGET_FULLANY): Deleted. + (TARGET_CM_MEDMID): New macro. + (CPP_CPU_DEFAULT_SPEC): Renamed from CPP_DEFAULT_SPEC. + (ASM_CPU_DEFAULT_SPEC): Renamed from ASM_DEFAULT_SPEC. + (CPP_PREDEFINES): Take out stuff now handled by %(cpp_arch). + (CPP_SPEC): Rewrite. + (CPP_ARCH{,32,64,_DEFAULT}_SPEC): New macros. + (CPP_{ENDIAN,SUBTARGET}_SPEC): New macros. + (ASM_ARCH{,32,64,_DEFAULT}_SPEC): New macros. + (ASM_SPEC): Add %(asm_arch). + (EXTRA_SPECS): Rename cpp_default to cpp_cpu_default. + Rename asm_default to asm_cpu_default. + Add cpp_arch32, cpp_arch64, cpp_arch_default, cpp_arch, cpp_endian, + cpp_subtarget, asm_arch32, asm_arch64, asm_arch_default, asm_arch. + (NO_BUILTIN_{PTRDIFF,SIZE}_TYPE): Define ifdef SPARC_BI_ARCH. + ({PTRDIFF,SIZE}_TYPE): Provide 32 and 64 bit values. + (MASK_INT64,MASK_LONG64): Delete. + (MASK_ARCH64): Renamed to MASK_64BIT. + (MASK_{MEDLOW,MEDANY,FULLANY,CODE_MODEL}): Delete. + (EMBMEDANY_BASE_REG): Renamed from MEDANY_BASE_REG. + (TARGET_SWITCHES): Always provide 64 bit options. + (ARCH64_SWITCHES): Delete. + (TARGET_OPTIONS): New option -mcmodel=. + (INT_TYPE_SIZE): Always 32. + (MAX_LONG_TYPE_SIZE): Define ifdef SPARC_BI_ARCH. + (INIT_EXPANDERS): sparc64_init_expanders renamed to sparc_init_.... + (FUNCTION_{,BLOCK_}PROFILER): Delete TARGET_EMBMEDANY support. + (PRINT_OPERAND_PUNCT_VALID_P): Add '_'. + * sparc/linux-aout.h (CPP_PREDEFINES): Take out stuff handled by + CPP_SPEC. + (CPP_SUBTARGET_SPEC): Renamed from CPP_SPEC. + * sparc/linux.h: Likewise. + * sparc/linux64.h (SPARC_V9,SPARC_ARCH64): Delete. + (ASM_CPU_DEFAULT_SPEC): Renamed from ASM_DEFAULT_SPEC. + (TARGET_DEFAULT): Delete MASK_LONG64, MASK_MEDANY, add MASK_64BIT. + (SPARC_DEFAULT_CMODEL): Define. + (CPP_PREDEFINES): Take out stuff handled by CPP_SPEC. + (CPP_SUBTARGET_SPEC): Renamed from CPP_SPEC. + (LONG_DOUBLE_TYPE_SIZE): Define. + (ASM_SPEC): Add %(asm_arch). + * sparc/sol2.h (CPP_PREDEFINES): Take out stuff handled by CPP_SPEC. + (CPP_SUBTARGET_SPEC): Renamed from CPP_SPEC. + (TARGET_CPU_DEFAULT): Add ultrasparc case. + * sparc/sp64-aout.h (SPARC_V9,SPARC_ARCH64): Delete. + (TARGET_DEFAULT): MASK_ARCH64 renamed to MASK_64BIT. + (SPARC_DEFAULT_CMODEL): Define. + * sparc/sp64-elf.h (SPARC_V9,SPARC_ARCH64): Delete. + (TARGET_DEFAULT): MASK_ARCH64 renamed to MASK_64BIT. Delete + MASK_LONG64, MASK_MEDANY. + (SPARC_DEFAULT_CMODEL): Define. + (CPP_PREDEFINES): Delete. + (CPP_SUBTARGET_SPEC): Renamed from CPP_SPEC. + (ASM_SPEC): Add %(asm_arch). + (LONG_DOUBLE_TYPE_SIZE): Define. + (DWARF2_DEBUGGING_INFO): Define. + * sparc/splet.h (CPP_SPEC): Delete. + * sparc/sysv4.h (CPP_PREDEFINES): Take out stuff handled by CPP_SPEC. + (FUNCTION_BLOCK_PROFILER): Delete TARGET_EMBMEDANY support. + (BLOCK_PROFILER): Likewise. + * sparc.c (sparc_cmodel_string,sparc_cmodel): New globals. + (sparc_override_options): Handle code model selection. + (sparc_init_expanders): Renamed from sparc64_init_expanders. + * sparc.md: TARGET_ renamed to TARGET_CM_.... + TARGET_MEDANY renamed to TARGET_CM_EMBMEDANY. + (sethi_di_embmedany_{data,text}): Renamed from sethi_di_medany_.... + (sethi_di_fullany): Delete. + +Mon Oct 20 17:20:17 1997 Jim Wilson + + * mips.c (compute_frame_size): Not a leaf function if profile_flag set. + +Sun Oct 19 17:46:02 1997 Douglas Rupp + + * cccp.c (OBJECT_SUFFIX): Add default definition. + (main): Use OBJECT_SUFFIX. + (VMS_{freopen,fopen,open}): Use instead of using macro on + unprefixed name. + (VMS_fstat): Use decc$fstat explicitly, not via macro. + +Sun Oct 19 09:07:38 1997 Richard Kenner + + * prefix.c (get_key_value): Initialize prefix to null. + * Makefile.in (prefix.o): Properly pass in prefix. + + * objc/Make-lang.in (objc.distdir): Make the objc directory. + * Makefile.in (distdir-start): No longer depend on objc-parse.[cy]. + Don't copy objc files here. + (TAGS): Don't delete objc-parse.y + + * i386/mingw32.h (LIB_SPEC): Add -ladvapi32. + (STARTFILE_SPEC): If -dll, use dllcrt1.o. + (INCOMING_RETURN_ADDR_RTX): Undefine. + + * Makefile.in (float.h-nat): Avoid using /dev/null for input, + since it's not present on all systems. + + * prefix.c : New file. + * Makefile.in (xgcc, cccp, cppmain, fix-header): Add prefix.o. + (prefix.o): New rule. + * cccp.c (update_path): Add extern definition. + (struct default_include): New field `component'. + (default_include): Add initializer for new field to all entries. + (new_include_prefix): Take new arg and call update_path; + all callers changed. + Add trailing "." before doing stat of file. + * cpplib.c (update_path): Add extern definition. + (struct default_include): New field `component'. + (default_include): Add initializer for new field to all entries. + (cpp_start_read): Call update_path. + * gcc.c (upate_path): Add extern definition. + (find_a_file): For MS-DOS-based, consider a drive spec as absolute. + (add_prefix): New arg component and pass to update_path; + all callers changed. + * netbsd.h (INCLUDE_DEFAULTS): Add `component' to values. + * i386/freebsd.h, mips/netbsd.h, winnt/win-nt.h: Likewise. + * i386/mingw32 (STANDARD_INCLUDE_COMPONENT): New macro. + * vax/vms.h (INCLUDE_DEFAULTS): New macro. + * vax/xm-vms.h (INCLUDE_DEFAULTS): Delete from here. + + * sparc/sol2.h (WIDEST_HARDWARE_FP_SIZE): New macro. + + * i386.c (ix86_prologue): Conditionalize Dwarf2 calls + on #ifdef INCOMING_RETURN_ADDR_RTX. + * i386.md (allocate_stack): Fix incorrect operand number. + + * alpha.c (vmskrunch): Deleted. + (output_prolog, VMS): Use alloca for entry_label and don't + truncate to 64 characters. + * alpha/vms.h (vmskrunch): No longer define. + (ENCODE_SECTION_INFO): No longer call vmskrunch. + (ASM_DECLARE_FUNCTION_NAME): No longer override. + + * toplev.c (output_quoted_string): Call new OUTPUT_QUOTED_STRING macro. + * i386/mingw32.h (OUTPUT_QUOTED_STRING): New macro. + + * stmt.c (using_eh_for_cleanups_p): New variable. + (using_eh_for_cleanups): New function. + (expand_decl_cleanup): Don't call expand_eh_region_start_tree + unless using EH for cleanups. + + * function.c (purge_addressof_1): When dealing with a + bare (address (mem)), verify that what's inside is valid in insn. + (instantiate_virtual_regs_1, case ADDRESSOF): If have MEM, just + do instantiation inside and leave alone here. + + * fold-const.c (fold, case COND_EXPR): Allow creation + of {MIN,MAX}_EXPR, but preserve info on orginal comparison code. + + * function.h (restore_tree_status): Update prototype. + + * cse.c (cse_basic_block): Flush the hash table every 1,000 insns. + +Sat Oct 18 13:48:14 1997 J"orn Rennecke + + * longlong.h (count_leading_zeros): Add missing casts to USItype. + +Sat Oct 18 13:35:09 1997 Marc Lehmann (pcg@goof.com) + + * toplev.c (main): Don't execute "ps" under MSDOS. + +Sat Oct 18 13:26:42 1997 Richard Earnshaw (rearnsha@arm.com) + + * function.c (instantiate_virtual_regs): Don't instantiate the + stack slots for the parm registers until after the insns have had + their virtuals instantiated. + + * varargs.h (va_arg): For ARM systems, definition is endian-dependent. + * stdarg.h (va_arg): Likewise. + +Sat Oct 18 11:23:04 1997 Nick Clifton + + * final.c (end_final): Use ASM_OUTPUT_ALIGNED_DECL_LOCAL if defined. + * varasm.c (assemble_static_space): Likewise. + (assemble_variable): Use ASM_OUTPUT_ALIGNED_DECL_{COMMON,LOCAL} if def. + +Sat Oct 18 11:02:19 1997 Doug Evans + + * expr.c (use_group_regs): Don't call use_reg unless REG. + +Sat Oct 18 10:39:22 1997 Jim Wilson + + * cse.c (simplify_ternary_operation, case IF_THEN_ELSE): Collapse + redundant conditional moves to single operand. + + * expmed.c (extract_bit_field): Don't make flag_force_mem disable + extzv for memory operands. + +Sat Oct 18 09:58:44 1997 Jeffrey A Law + + * ptx4.h: Fix typo. + + * integrate.c (save_for_inline_copying): Avoid undefined pointer + operations. + (expand_inline_function): Likewise. + +Sat Oct 18 09:49:46 1997 Jason Merrill + + * tree.c (restore_tree_status): Also free up temporary storage + when we finish a toplevel function. + (dump_tree_statistics): Print stats for backend obstacks. + + * libgcc2.c (__throw): Don't copy the return address. + * dwarf2out.c (expand_builtin_dwarf_reg_size): Ignore return address. + + * tree.c (expr_tree_cons, build_expr_list, expralloc): New fns. + * tree.h: Declare them. + + * except.c (exceptions_via_longjmp): Initialize to 2 (uninitialized). + * toplev.c (main): Initialize exceptions_via_longjmp. + + * tree.c: Add extra_inline_obstacks. + (save_tree_status): Use it. + (restore_tree_status): If this is a toplevel inline obstack and we + didn't want to save anything on it, recycle it. + (print_inline_obstack_statistics): New fn. + * function.c (pop_function_context_from): Pass context to + restore_tree_status. + +Sat Oct 18 09:45:22 1997 Michael Meissner + + * profile.c (get_file_function_name): Remove declaration. + * c-lang.c (finish_file): Likewise. + +Sat Oct 18 09:35:40 1997 Tristan Gingold + + * expr.c (expand_assignment): If -fcheck-memory-usage, add call to + chkr_check_addr if size not zero. + (expand_expr, case COMPONENT_REF): Likewise. + (expand_builtin): If -fcheck_memory-usage, check memory usage + of operands for strlen, strcpy, and memcpy or don't use builtins + for memcmp and strcmp. + * expr.h (chkr_check_str_libfunc): Declare. + * optabs.c (chkr_check_str_libfunc): New variable. + (init_optabs): Initialize it. + +Sat Oct 18 09:29:21 1997 J"orn Rennecke + + * i386/cygwin32.h (ASM_COMMENT_START): Redefine. + +Sat Oct 18 09:23:54 1997 Andreas Schwab + + * frame.c (__frame_state_for): Execute the FDE insns until the + current pc value is strictly bigger than the target pc value. + + * expr.c (expand_expr, case TARGET_EXPR): If target and slot has + no DECL_RTL, then call mark_addressable again for the slot after + we give it RTL. + +Sat Oct 18 08:58:36 1997 Manfred Hollstein (manfred@lts.sel.alcatel.de) + + * m88k/dolph.h (INITIALIZE_TRAMPOLINE): Delete here. + * m88k/sysv3.h (INITIALIZE_TRAMPOLINE): Unconditionally define. + * libgcc2.c (__enable_execute_stack): Check for __sysV88__ not + __DOLPHIN__. + + * m68k/mot3300.h (ASM_OUTPUT_ALIGN): Accept any alignment. + * dwarf2out.c (output_call_frame_info): Call app_enable and + app_disable to let GNU as accept the generated comments. + + * m88k.c (m88k_begin_prologue): Remove superfluous backslash. + +Sat Oct 18 08:50:04 1997 Philippe De Muyter + + * flow.c (print_rtl_with_bb): Cast alloca return values. + +Sat Oct 18 08:47:46 1997 Douglas Rupp + + * alpha/vms.h (LITERALS_SECTION_ASM_OP, ASM_OUTPUT_DEF): + (EXTRA_SECTION_FUNCTIONS): Add literals_section. + (EXTRA_SECTIONS): Include in_literals. + +Sat Oct 18 08:40:55 1997 Nick Burrett + + * cpplib.c: (initialize_builtins): Cast all string constants for the + function install, to type U_CHAR *. + (eval_if_expression): Likewise. + * cppexp.c: (cpp_lex): Cast string, for cpp_lookup, to type U_CHAR *. + +Sat Oct 18 08:38:13 1997 Ken Raeburn + + * c-lex.c (check_newline) At `skipline', flush nextchar as well. + +Sat Oct 18 08:17:13 1997 Paul Russell + + * input.h (struct file_stack): Added indent_level. + * c-lex.c (check_newline): Add {}-count & balance warning. + +Sat Oct 18 06:54:39 1997 Richard Kenner + + * regclass.c (record_address_regs, case PLUS): Refine how to choose + which is base and index. + + * alpha.h (FUNCTION_VALUE): Use word_mode only for integral types, + not types with integral modes. + + * final.c (alter_cond): Properly conditionalize forward decl. + + * tree.h (SAVE_EXPR_NOPLACEHOLDER): New flag. + * tree.c (contains_placeholder_p, case SAVE_EXPR): Avoid + checking each SAVE_EXPR more than once. + + * rs6000.md (nonlocal_goto_receiver): Don't test pool size. + + * i386.c (load_pic_register): New function. + (ix86_prologue): Code to load PIC register moved to new function. + Don't emit blockage if not generating RTL. + * i386.md (nolocal_goto_receiver): New pattern. + + * i386.c: Major cleanup, mostly reformatting. + Include dwarf2.h. + Remove many spurious casts. + (ix86_{pro,epi}logue): Use proper mode for SET rtx. + +Fri Oct 17 17:13:42 1997 David S. Miller + + * sparc/linux64.h (LINK_SPEC): Dynamic linker is ld-linux64.so.2. + * sparc.h (FUNCTION_PROFILER): Fix format string when TARGET_MEDANY. + * sparc.c (output_double_int): Output DI mode values + correctly when HOST_BITS_PER_WIDE_INT is 64. + (output_fp_move_quad): If TARGET_V9 and not TARGET_HARD_QUAD, use + fmovd so it works if a quad float ends up in one of the upper 32 + float regs. + * sparc.md (pic_{lo_sum,sethi}_di): New patterns for PIC support + on sparc64. + +Fri Oct 17 16:27:07 1997 Doug Evans + + * sparc/sp64-elf.h (TARGET_DEFAULT): Delete MASK_STACK_BIAS. + * sparc.h (PROMOTE_MODE): Promote small ints if arch64. + (PROMOTE_FUNCTION_ARGS,PROMOTE_FUNCTION_RETURN): Define. + (SPARC_FIRST_FP_REG, SPARC_FP_REG_P): New macros. + (SPARC_{OUTGOING,INCOMING}_INT_ARG_FIRST): New macros. + (SPARC_FP_ARG_FIRST): New macro. + (CONDITIONAL_REGISTER_USAGE): All v9 fp regs are volatile now. + (REG_ALLOC_ORDER,REG_LEAF_ALLOC_ORDER): Reorganize fp regs. + (NPARM_REGS): There are 32 fp argument registers now. + (FUNCTION_ARG_REGNO_P): Likewise. + (FIRST_PARM_OFFSET): Update to new v9 abi. + (REG_PARM_STACK_SPACE): Define for arch64. + (enum sparc_arg_class): Delete. + (sparc_arg_count,sparc_n_named_args): Delete. + (struct sparc_args): Redefine and use for arch32 as well as arch64. + (GET_SPARC_ARG_CLASS,ROUND_REG,ROUND_ADVANCE): Delete. + (FUNCTION_ARG_ADVANCE): Rewrite. + (FUNCTION_ARG,FUNCTION_INCOMING_ARG): Rewrite. + (FUNCTION_ARG_{PARTIAL_NREGS,PASS_BY_REFERENCE}): Rewrite. + (FUNCTION_ARG_CALLEE_COPIES): Delete. + (FUNCTION_ARG_{PADDING,BOUNDARY}): Define. + (STRICT_ARGUMENT_NAMING): Define. + (doublemove_string): Declare. + * sparc.c (sparc_arg_count,sparc_n_named_args): Delete. + (single_move_string): Use GEN_INT, and HOST_WIDE_INT. + (doublemove_string): New function. + (output_move_quad): Clean up some of the arch64 support. + (compute_frame_size): Add REG_PARM_STACK_SPACE if arch64. + Don't add 8 bytes of reserved space if arch64. + (sparc_builtin_saveregs): Combine arch32/arch64 versions. + (init_cumulative_args): New function. + (function_arg_slotno): New static function. + (function_arg,function_arg_partial_nregs): New functions. + (function_arg_{pass_by_reference,advance}): New functions. + (function_arg_padding): New function. + * ginclude/va-sparc.h: Rewrite v9 support. + +Fri Oct 17 13:21:45 EDT 1997 Philip Blundell + + * arm/netbsd.h (TYPE_OPERAND_FMT): use % not @ to avoid + problems with comments. + +Fri Oct 17 13:00:38 EDT 1997 Richard Earnshaw (rearnsha@arm.com) + + * arm/aout.h (ASM_OUTPUT_LABEL): Define in place of ARM_OUTPUT_LABEL. + * arm/aof.h (ASM_OUTPUT_LABEL): Likewise. + * arm.h (ASM_OUTPUT_LABEL): Delete. + (ASM_OUTPUT_INTERNAL_LABEL): Call ASM_OUTPUT_LABEL directly. + * arm.c (arm_asm_output_label): Delete. + + * arm/aout.h (ASM_OUTPUT_ALIGNED_LOCAL): Do what is needed inline. + * arm.c (output_lcomm_directive): Delete. + + * arm.h (PUSH_ROUNDING): Delete; this is not what happens. + (ACCUMULATE_OUTGOING_ARGS): Define. + (PROMOTE_FUNCTION_ARGS): Define. + (INITIAL_ELIMINATION_OFFSET): Take current_function_outgoing_args_size + into account. + * arm.c (use_return_insn, output_func_epilogue, + arm_expand_prologue): Likewise. + + * arm.c (const_ok_for_arm): If HOST_WIDE_INT more than 32 bits, + insist high bits are all zero or all one. + (output_move_double): Handle case where CONST_INT is more than 32 bits. + + * arm.c (load_multiple_sequence): Support SUBREG of MEM. + (store_multiple_sequence): Likewise. + + * arm.c (arm_gen_load_multiple): New args UNCHANGING_P and IN_STRUCT_P. + Use them if we create any new MEMs; all callers changed. + (arm_gen_store_multiple): Likewise. + (arm_gen_movstrqi): Preserve RTX_UNCHANGING_P and MEM_IN_STRUCT_P + on any MEMs created. + + * arm.h (ASM_OUTPUT_MI_THUNK): Use branch instruction to jump to label. + (RETURN_ADDR_RTX): Use NULL_RTX rather than casting zero. + (output_move_double): Correct typo in prototype. + + * arm.md (movsfcc): If not TARGET_HARD_FLOAT, ensure operand[3] valid. + + * arm/netbsd.h (CPP_PREDEFINES): Always predefine __arm__. + * arm/xm-netbsd.h (SYS_SIGLIST_DECLARED, HAVE_STRERROR): Define these. + + * arm/t-netbsd (CROSS_LIBGCC1, LIB1ASMSRC, LIB1ASMFUNCS) Don't define + these any more. + * configure.in (arm-*-netbsd*): Pick up t-netbsd before arm/t-netbsd. + +Thu Oct 16 19:31:22 1997 Jim Wilson + + * v850.c (ep_memory_offset): New function. + (ep_memory_operand, substitute_ep_register, v850_reorg): Call it. + + * v850.h (CONST_OK_FOR_*): Add and correct comments. + (CONSTANT_ADDRESS_P): Add comment. + (EXTRA_CONSTRAINT): Define 'U'. + * v850.md: Add comments on bit field instructions. + (addsi3): Delete &r/r/r alternative. Add r/r/U alternative. + (lshrsi3): Use N not J constraint. + + * v850.md (v850_tst1+1): New define_split for tst1 instruction. + + * v850.c (reg_or_0_operand): Call register_operand. + (reg_or_int5_operand): Likewise. + * v850.h (MASK_BIG_SWITCH, TARGET_BIG_SWITCH): New macros. + (TARGET_SWITCHES): Add "big-switch". + (ASM_OUTPUT_ADDR_VEC_ELT, ASM_OUTPUT_ADDR_DIFF_ELT, CASE_VECTOR_MODE, + ASM_OUTPUT_BEFORE_BASE_LABEL): Add support for TARGET_BIG_SWITCH. + (CASE_DROPS_THROUGH): Comment out. + (CASE_VECTOR_PC_RELATIVE, JUMP_TABLES_IN_TEXT_SECTION): Define. + * v850.md (cmpsi): Delete compare mode. + (casesi): New pattern. + + * v850.h (CONST_OK_FOR_N): Delete redundant compare against zero. + * v850.md (ashlsi3): Use SImode not QImode for shift count. + (lshrsi3): Likewise. + + * v850.c (print_operand): Add 'c', 'C', and 'z' support. Delete + unreachable switch statement after 'b' support. Remove "b" from + strings for 'b' support. + * v850.md (branch_normal, branch_invert): Change %b to b%b. + +Thu Oct 16 13:08:45 1997 Doug Evans + + * configure.in (sparc-*-elf*): New target. + +Wed Oct 15 22:30:37 1997 J"orn Rennecke + + * h8300.h (REG_CLASS_CONTENTS): AP is a general register. + (REG_OK_FOR_BASE_P, ! REG_OK_STRICT case): Reject special registers. + +Wed Oct 15 22:00:57 1997 J"orn Rennecke + + * sh.md (movhi+1): Add x/r alternative. + + * sh/elf.h (HANDLE_SYSV_PRAGMA): Undefine. + + * va-sh.h (va_arg): Fix big endian bugs for small integers. + +Wed Oct 15 21:34:45 1997 David Edelsohn + + * rs6000.md (udivsi3, divsi3): Split into MQ and non-MQ cases for + PPC601. + (umulsidi3,umulsi3_highpart): Likewise. + (smulsi3_highpart_no_mq): Add !TARGET_POWER. + +Wed Oct 15 18:45:31 1997 Doug Evans + + * sparc/t-sp64 (LIBGCC2_CFLAGS): Delete. + +Wed Oct 15 17:17:33 1997 Jeffrey A Law (law@cygnus.com) + + * pa.c (following_call): Fail if the CALL_INSN is an indirect call. + +Wed Oct 1 17:52:09 1997 Douglas Rupp + + * vms.h (UNALIGNED_{SHORT,INT,DOUBLE_INT}_ASM_OP): Define. + +Wed Oct 1 16:09:42 1997 Benjamin Kosnik + + * fixincludes: Fix sys/param.h so that MAXINT will not be redefined + on HPUX. + +Wed Oct 1 08:08:21 1997 Jeffrey A Law + + * cse.c (this_insn_cc0_mode): Initialize. + +Wed Oct 1 07:22:12 1997 Richard Henderson + + * i386.h (RETURN_ADDR_RTX): Use FRAME arg, not ap. + +Tue Sep 30 19:19:58 1997 Jim Wilson + + * except.c (find_exception_handler_labels): Correct argument to free. + +Fri Sep 26 14:06:45 1997 Mike Stump + + * c-decl.c (start_struct): Ensure that structs with forward + declarations are in fact packed when -fpack-struct is given. + +Wed Sep 24 11:31:24 1997 Mike Stump + + * stor-layout.c (layout_record): Ignore STRUCTURE_SIZE_BOUNDARY if + packing structure. This allows a structure with only bytes to be + aligned on a byte boundary and have no padding on a m68k. + +Tue Sep 30 11:00:00 1997 Brendan Kehoe + + * except.c (find_exception_handler_labels): Free LABELS when done. + +Tue Sep 30 10:47:33 1997 Paul Eggert + + * cexp.y, cppexp.c (HOST_BITS_PER_WIDE_INT): + Define only if not already defined. + +Mon Sep 29 17:55:55 1997 Gavin Koch + + * c-decl.c (warn_implicit): Deleted. + (warn_implicit_int, mesg_implicit_function_declaration}): New vars. + (c_decode_option): For -Wimplicit, set both new variables. + Add -Wimplicit-function-declarations, -Wimplicit-int, + and -Werror-implicit-function-declaration. + (implicitly_declare, grokdeclarator): Use new flags. + * toplev.c (lang_options): Add new -W options. + +Mon Sep 29 17:55:15 1997 Richard Kenner + + * c-common.c (check_format_info): Add check for scanf into + constant object or via constant pointer type. + +Mon Sep 29 16:10:12 1997 Richard Henderson + + * alpha.md (beq): For registers and ints 0-255, use cmpeq+bne. + (bne): Likewise for cmpeq+beq. + +Mon Sep 29 15:58:22 1997 Doug Evans + + * reload1.c (reload_cse_simplify_set): Fix return values. + +Mon Sep 29 08:21:35 1997 Bruno Haible + + * i386.c (notice_update_cc): Use reg_overlap_mentioned_p. + +Sun Sep 28 18:59:58 1997 Jason Merrill + + * libgcc2.c (__throw): Fix thinko. + +Sun Sep 28 12:00:52 1997 Mark Mitchell + + * cplus-dem.c (demangle_template): Add new parameter. Handle new + template-function mangling. + (consume_count_with_underscores): New function. + (demangle_signature): Handle new name-mangling scheme. + +Sun Sep 28 11:19:09 1997 Richard Kenner + + * flow.c (print_rtl_with_bb): Reformat messages about BB boundaries. + + * calls.c: Include regs.h. + * profile.c: Likewise. + * Makefile.in (calls.o, profile.o): Depend on regs.h. + * except.h (expand_builtin_dwarf_reg_size): Put in #ifdef TREE_CODE. + + * tree.h (get_file_function_name): Add decl. + * dwarf2out.c (output_call_frame_info): Don't cast its result. + +Sun Sep 28 10:58:21 1997 Manfred Hollstein + + * Makefile.in (sub-makes): Pass value of LANGUAGES. + +Sun Sep 28 10:52:59 1997 Ian Dall + + * regs.h (SMALL_REGISTER_CLASSES): Default to 0. + * calls.c (prepare_call_address, expand_call): + Remove #if test on SMALL_REGISTER_CLASSES. + * combine.c (can_combine_p, combinable_i3pat, try_combine): Likewise. + * cse.c (canon_hash): Likewise. + * function.c (expand_function_start): Likewise. + * jump.c (jump_optimize): Likewise. + * local-alloc.c (optimize_reg_copy_1): Likewise. + * loop.c (scan_loop, valid_initial_value_p): Likewise. + * profile.c (output_arc_profiler): Likewise. + * reload.c (push_secondary_reload, push_reload): Likewise. + (combine_reloads): Likewise. + * reload1.c (reload, scan_paradoxical_subregs): Likewise. + (order_regs_for_reload, reload_as_needed): Likewise. + (choose_reload_regs): Likewise. + (merge_assigned_reloads): Declare unconditionally. + +Sat Sep 27 11:02:38 1997 Jason Merrill + + * c-decl.c (init_decl_processing): Add __builtin_dwarf_reg_size. + * tree.h (built_in_function): Likewise. + * expr.c (expand_builtin): Likewise. + * except.h: Likewise. + * dwarf2out.c (expand_builtin_dwarf_reg_size): New fn. + * libgcc2.c (copy_reg): New fn. + (__throw): Use it. + +Fri Sep 26 09:00:13 1997 Andreas Schwab + + * frame.c (gansidecl.h): New include, for PROTO. + * dwarf2out.c: Move inclusion of dwarf2.h down. + (dwarf2out_cfi_label): Don't declare here. + * dwarf2.h (dwarf2out_{do_frame,cfi_label,def_cfa}): New declarations. + (dwarf2out_{window_save,args_size,reg_save,return_save}): Likewise. + (dwarf2out_{return_reg,begin_prologue,end_epilogue}): Likewise. + * m68k.c (dwarf2.h): Include. + (output_function_prologue): Add dwarf2 support. + * m68k.h (INCOMING_RETURN_ADDR_RTX, DWARF_FRAME_REGNUM): New macros. + (INCOMING_FRAME_SP_OFFSET): Likewise. + + * integrate.c (copy_rtx_and_substitute, case ADDRESSOF): New case. + + * integrate.c (expand_inline_function): Make sure there is at + least one insn that can be used as an insertion point. + +Fri Sep 26 08:54:59 1997 Paul Eggert + + * c-typeck.c (build_binary_op): Warn about comparing signed vs + unsigned if -W is specified and -Wno-sign-compare is not. + * c-decl.c (warn_sign_compare): Initialize to -1. + (c_decode_option): -Wall no longer implies -Wsign-compare. + +Wed Sep 24 21:34:06 1997 Jason Merrill + + * dwarf2out.c: s/flag_verbose_asm/flag_debug_asm/ + +Wed Sep 24 19:17:08 1997 Doug Evans + + * sparc.md (get_pc_via_call): Renamed from get_pc_sp32. + (get_pc_via_rdpc): Renamed from get_pc_sp64. + * sparc.c (finalize_pic): Update call to gen_get_pc_via_call. + +Wed Sep 24 18:38:22 1997 David S. Miller + + * sparc.h (ASM_CPU_SPEC): Pass -Av9a for v8plus, ultrasparc. + (TARGET_OPTIONS): Add -malign-loops=, -malign-jumps=, + and -malign-functions=. + (sparc_align_{loops,jumps,funcs}_string): Declare. + (sparc_align_{loops,jumps,funcs}): Declare. + (DEFAULT_SPARC_ALIGN_FUNCS): New macro. + (FUNCTION_BOUNDARY): Use sparc_align_funcs. + (STACK_BIAS): Define. + (SPARC_SIMM*_P): Cast to unsigned HOST_WIDE_INT, then perform test. + (SPARC_SETHI_P): New macro. + (CONST_OK_FOR_LETTER_P): Use it. + (ASM_OUTPUT_ALIGN_CODE): Define. + (ASM_OUTPUT_LOOP_ALIGN): Define. + * sparc.c (sparc_align_{loops,jumps,funcs}_string): New globals. + (sparc_align_{loops,jumps,funcs}): New globals. + (sparc_override_options): Handle -malign-loops=, -malign-jumps=, + -malign-functions=. + (move_operand): Use SPARC_SETHI_P. + (arith_double_operand): Cast to unsigned HOST_WIDE_INT, then test. + (arith11_double_operand): Likewise. + (arith10_double_operand): Likewise. + (finalize_pic): Finish sparc64 support. + (emit_move_sequence): Use SPARC_SETHI_P. Simplify low part of + 64 bit constants if able. + (output_fp_move_quad): Don't use fmovq unless TARGET_HARD_QUAD. + (sparc_builtin_saveregs [sparc64]): Don't save fp regs if ! TARGET_FPU. + * sparc.md: Use GEN_INT instead of gen_rtx. + (get_pc_sp32): Use for sparc64 as well. + (lo_sum_di_sp{32,64}): Fix handling on 64 bit hosts. + (sethi_di_sp64_const): Likewise. + (movtf_cc_sp64): Check TARGET_HARD_QUAD. + (cmp_zero_extract_sp64): Use unsigned HOST_WIDE_INT in cast. + (ashlsi3, ashldi3, ashrsi3, ashrdi3, lshrsi3, lshrdi3): Likewise. + +Wed Sep 24 08:25:28 1997 Alexandre Oliva + + * i386.md (allocate_stack): Fix typo in last change. + +Tue Sep 23 19:02:46 1997 Doug Evans + + * sparc/linux-aout.h (COMMENT_BEGIN): Delete. + * sparc/linux.h (COMMENT_BEGIN): Likewise. + * sparc/linux64.h (COMMENT_BEGIN): Likewise. + +Tue Sep 23 14:48:18 1997 David S. Miller + + Add sparc64 linux support. + * configure.in (sparc64-*-linux*): Recognize. Add sparc/xm-sparc.h + to xm_file list on 32-bit sparc-linux. + * sparc/xm-sp64.h: New file. + * sparc/linux64.h: New file. + * sparc/xm-linux.h: Include some standard headers if not inhibit_libc. + Don't include xm-sparc.h. + * config/xm-linux.h (HAVE_PUTENV, HAVE_ATEXIT): Define. + * glimits.h (LONG_MAX): Handle sparc64. + +Tue Sep 23 08:32:51 1997 Jason Merrill + + * final.c (final_end_function): Also do dwarf2 thing if + DWARF2_DEBUGGING_INFO. + (final_start_function): Likewise. + +Tue Sep 23 06:55:40 1997 David S. Miller + + * expmed.c (expand_divmod): If compute_mode is not same as mode, + handle case where convert_modes causes op1 to no longer be CONST_INT. + +Tue Sep 23 00:58:48 1997 Jim Wilson + + * mips.c (save_restore_insns): Only set RTX_FRAME_RELATED_P if store_p. + +Mon Sep 22 18:26:25 1997 J. Kean Johnston + + * i386/sco5.h: Make ELF default file format and add -mcoff/-melf.. + (MULTILIB_DEFAULTS): Define. + (ASM_SPEC, CPP_SPEC): Handle -mcoff. + (STARTFILE_SPEC, ENDFILE_SPEC, LINK_SPEC): Likewise. + (LIBGCC_SPEC): Likewise. + (MASK_COFF, TARGET_COFF, TARGET_ELF): Define. + (SUBTARGET_SWITCHES): Add -mcoff and -melf. + * i386/t-sco5 (CRTSTUFF_T_CFLAGS): Add -fPIC. + (CRTSTUFF_T_CFLAGS_S): Tweak for COFF. + (EXTRA_PARTS, TAROUTOPTS): Delete. + (libgcc1-elf, libgcc2-elf, libgcc-elf targets): Delete. + (MULTILIB_OPTIONS): Define. + (MULTILIB_DIRNAMES, MULTILIB_EXCEPTIONS): Likewise. + (MULTILIB_MATCHE, MULTILIB_EXTRA_OPTS): Likewise. + +Mon Sep 22 14:42:11 1997 Jeffrey A Law (law@cygnus.com) + + * reg-stack.c (find_blocks): Fix thinko in last change. + +Mon Sep 22 16:22:41 1997 David S. Miller + + * combine.c (try_combine): Use NULL_RTX, not 0, in gen_rtx calls. + * cse.c (cse_main): Likewise. + * emit-rtl.c (gen_label_rtx): Likewise. + * expr.c (init_expr_once): Likewise. + * sched.c (schedule_insns): Likewise. + * varasm.c (immed_double_const): Likewise. + + * sparc.h (INCOMING_FRAME_SP_OFFSET): Define as SPARC_STACK_BIAS. + +Mon Sep 22 16:13:21 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * alpha/linux.h (HANDLE_SYSV_PRAGMA): Define. + +Mon Sep 22 16:02:01 1997 Benjamin Kosnik + + * c-common.c (decl_attributes): Add support for TYPE_UNUSED on types. + * c-decl.c (finish_decl): Set TREE_USED on decls if TREE_USED on type. + * stmt.c (expand_end_bindings): Check DECL_NAME and DECL_ARTIFICIAL + before unused variable warning. + +Mon Sep 22 14:04:18 1997 Richard Kenner + + * rtlanal.c (computed_jump_p): Fix typo in last change. + + * clipper.md (movstrsi): Use change_address instead of making new MEM. + * dsp16xx.md (movstrqi): Likewise. + * i370.md (movstrsi): Likewise. + * i860.md (movstrsi): Likewise. + * pa.md (movstrsi): Likewise. + * mips.md (movstrsi): Fix (unused) pattern in define_expand. + * pdp11.md (movstrhi): Likewise. + + * alpha.md (allocate_stack): Use virtual_stack_dynamic for result. + * i386.md (allocate_stack): Likewise. + * rs6000.md (allocate_stack): Likewise. + + * alpha.h (FLOAT_STORE_FLAG_VALUE): Different for VAX and IEEE float. + + * function.c (assign_parms): Make max_parm_reg handling more + precise and make it agree with size of parm_reg_stack_loc. + * integrate.c (save_for_inline_{nocopy,copying}): Remove + redundant assignment of max_parm_reg. + + * function.c (assign_parms): Properly set RTX_UNCHANGING_P for + copy of parm. + + * integrate.c (copy_rtx_and_substitute, case SET): Handle + a SET_DEST of the virtual fp or ap specially and undo + the adjustment into the local area as well. + (mark_stores): Don't wipe out map entries for virtual fp and ap. + + * alpha.h (FLOAT_STORE_FLAG_VALUE): Different for VAX and IEEE float. + + * emit-rtl.c (gen_lowpart): Handle ADDRESSOF. + +Mon Sep 22 13:35:56 1997 Doug Evans + + * rtlanal.c (replace_regs): Fix up lossage in last patch. + +Sun Sep 21 19:28:48 1997 Jeffrey A Law (law@cygnus.com) + + * flow.c (jmp_uses_reg_or_mem): Deleted unused function. + (find_basic_blocks): Use computed_jump_p to determine if a + particular JUMP_INSN is a computed jump. + * reg-stack.c (find_blocks): Use computed_jump_p to determine + if a particular JUMP_INSN is a computed jump. + * rtlanal.c (jmp_uses_reg_or_mem): New function. + (computed_jump_p): Likewise. + * rtl.h (computed_jump_p): Declare. + * genattrtab.c (pc_rtx): Define and initialize. + + * cse.c (simplify_relational_operation): Set h0u just like h0s. + Similarly for h1u and h1s. + +Sun Sep 21 14:13:31 1997 Doug Evans + + * function.c (instantiate_virtual_regs): Fix thinko in last patch. + +Sun Sep 21 10:33:26 1997 Paul Eggert + + * cccp.c, cpplib.c (special_symbol): If STDC_0_IN_SYSTEM_HEADERS + is defined, expand __STDC__ to 0 in system headers. + * i386/sol2.h, rs6000/sol2.h, sparc/sol2.h: + (STDC_0_IN_SYSTEM_HEADERS): New macro. + (CPP_SPEC): Remove -D__STDC__=0; it's no longer needed. + + * fixinc.math (_MATH_H_WRAPPER): Define at the end of the + wrapper, not the start, so that if #include_next gets another + instance of the wrapper, this will follow the #include_next + chain until we arrive at the real . + + * fixproto (subdirs_made): New var, to keep track of which + subdirectories we've made (in reverse order). At the end, + attempt to rmdir them all, so that we don't create any empty + directories. + +Sun Sep 21 10:02:07 1997 Richard Kenner + + * pa.c (move_operand): Respect -mdisable-indexing. + * pa.h (GO_IF_LEGITIMATE_ADDRESS): Likewise. + +Sun Sep 21 09:29:23 1997 Andreas Schwab + + * function.c (purge_addressof_1): Don't convert (MEM (ADDRESSOF (REG))) + to (SUBREG (REG)) on big endian machines. + Don't fall through to substitute the inner (REG) unchanged + when the above conversion cannot be validated. + +Sat Sep 20 16:22:06 1997 Jason Merrill + + * frame.c (__deregister_frame): Properly check for initialized object. + + * function.c (instantiate_virtual_regs): Instantiate + parm_reg_stack_locs. + +Sat Sep 20 03:07:54 1997 Doug Evans + + * sparc/sysv4.h (ASM_COMMENT_START): Delete. + * sparc.h (ASM_COMMENT_START): Define. + * sparc.c (output_function_prologue): Use it. + (sparc_flat_output_function_{epi,pro}logue): Likewise. + +Fri Sep 19 19:43:09 1997 Jeffrey A Law (law@cygnus.com) + + * loop.c (strength_reduce): Fix typo. + + * m68k/xm-mot3300.h (alloca): Properly declare if __STDC__. + * mips.h, xm-rs6000.h, rs6000/xm-sysv4.h: Likewise. + +Fri Sep 19 20:10:30 1997 Doug Evans + + * rtl.h (find_use_as_address): Delete accidentally added decl. + +Fri Sep 19 08:36:16 1997 J"orn Rennecke + + * jump.c (thread_jumps): Check can_reverse_comparison_p before + threading a reversed-condition jump. + +Fri Sep 19 08:16:12 1997 Andrew M. Bishop . + + * Add support for new -dI option for cxref, + * cccp.c (dump_includes): New variable. + (struct directive, directive_table): Remove members angle_brackets, + traditional_comments, pass_thru; all code using struct directive + now uses `type' member instead. + (IS_INCLUDE_DIRECTIVE_TYPE): New macro. + (main, handle_directive): Add support for new -dI option. + (do_ident): Avoid unnecessary alloca. + (do_pragma): Avoid unnecessary comparison to newline. + + * cpplib.h (struct cpp_options): New member dump_includes. + * cpplib.c (struct directive, directive_table): Remove members + traditional_comments, pass_thru; all code using struct directive + now uses `type' member instead. + (IS_INCLUDE_DIRECTIVE_TYPE): New macro. + (handle_directive, cpp_handle_options): Add support for new -dI option. + +Fri Sep 19 07:57:19 1997 Pat Rankin + + * vax/xm-vms.h (expand_builtin_{extract,set}_return_addr): New macros. + +Fri Sep 19 07:47:29 1997 Nick Burrett + + * cpplib.c (pcstring_used, pcfinclude): Delete unused declarations. + (check_preconditions, print_containing_files, pipe_closed): Likewise. + (dump_defn_1, dump_arg_n, make_undef): Likewise. + (trigraph_pcp): Pre-process out decl. + (quote_string): Cast CPP_PWRITTEN macro to char * for sprintf. + (output_line_command): Likewise. + (macro_expand): Likewise. + (do_line): Cast atoi argument to char *. + * genattrtab.c (simplify_by_alternatives): Pre-process out decl. + * genpeep.c (gen_exp): Remove decl. + +Fri Sep 19 07:29:40 1997 Bernd Schmidt + + * enquire.c (basic): Elminate dangling else warning. + * except.h (struct function, save_eh_status, restore_eh_status): + Don't declare. + * expr.c (clear_storage): Don't return without a value. + * function.h ({save,restore}_machine_status): Add proper prototype. + ({save,restore}_{tree,eh,stmt,expr,emit,storage}_status): Declare. + * real.h (real_value_truncate): Add proper prototype. + (target_isnan, target_isinf, target_negative, debug_real): Declare. + (assemble_real): Likewise. + * recog.c (strict_memory_address_p, memory_address_p): Don't declare. + (find_single_use_1): Add prototype. + * recog.h (init_recog, init_recog_no_volatile): Declare. + (check_asm_operands, constrain_operands, memory_address_p): Likewise. + (strict_memory_address_p, validate_replace_rtx): Likewise. + (reg_fits_class_p, find_single_use, general_operand): Likewise. + (address_operand, register_operand, scratch_operand): Likewise. + (immediate_operand, const_int_operand, const_double_operand): Likewise. + (nonimmediate_operand, nonmemory_operand, push_operand): Likewise. + (memory_operand, indirect_operand, mode_independent_operand): Likewise. + (comparison_operator, offsettable_{,nonstrict_}memref_p): Likewise. + (offsettable_address_p, mode_dependent_address_p, recog): Likewise. + (add_clobbers): Likewise. + * reload.h (strict_memory_address_p): Don't declare here. + * rtl.h (struct rtvec_def): Make num_elem an integer. + (PUT_NUM_ELEM): Delete cast to unsigned. + (rtx_unstable_p, rtx_varies_p, reg_mentioned_p): Declare. + (reg_{referenced,used_between,referenced_between}_p: Likewise. + ({reg_set,modified,no_labels}_between_p, modified_in_p): Likewise. + (reg_set_p, refers_to_regno_p, reg_overlap_mentioned_p): Likewise. + (note_stores, rtx_equal_p, dead_or_set{,_regno}_p): Likewise. + (remove_note, side_effects_p, volatile_{refs,insn}_p): Likewise. + (may_trap_p, inequality_comparison_p): Likewise. + * rtlanal.c (note_stores, reg_set_p): Don't declare. + (rtx_addr_can_trap_p): Add prototype, make static. + (reg_set_p_1): Add declaration for parameter pat. + * emit-rtl.c: Include recog.h. + * integrate.c: Likewise. + * jump.c: Likewise. + * unroll.c: Likewise. + * Makefile.in (emit-rtl.o, integrate.o, jump.o, unroll.o): Depend + on recog.h. + +Fri Sep 19 06:52:22 1997 Paul Eggert + + * enquire.c (SYS_FLOAT_H_WRAP): New macro. + Include "float.h" if SYS_FLOAT_H_WRAP is nonzero. + (f_define): New argument `req'. + (main): Output `#include_next ' if wrapping float.h. + (i_define, f_define): Don't output anything if wrapping float.h + and if the system defn is already correct. Put other value tests + inside `#ifdef VERIFY'. + (UNDEFINED): New macro. + (I_MAX, I_MIN, U_MAX, F_RADIX, F_MANT_DIG, F_DIG, F_ROUNDS): + Define even if VERIFY isn't defined, because SYS_FLOAT_H_WRAP may need + these values. Give them the value UNDEFINED if not already defined. + (F_EPSILON, F_MIN_EXP, F_MIN, F_MIN_10_EXP, F_MAX_EXP): Likewise. + (F_MAX, F_MAX_10_EXP): Likewise. + (FPROP): Prefer system float.h definition of F_ROUNDS. + Pass system values to f_define. + * Makefile.in (FLOAT_H_TEST): New var. + (float.h-nat): Make it empty if we can use the system float.h without + change. + (enquire.o): Define SYS_FLOAT_H_WRAP=1 if we can build a wrapper + around the system . Remove include/float.h before compiling. + (stmp-headers): Remove include/float.h if we would just be installing + an empty file (which is a placeholder that stands for no file). + + * fix-header.c: Don't munge headers for POSIX and XOPEN, + as this is too error-prone. + (ADD_MISSING_POSIX, ADD_MISSING_XOPEN): New macros, normally undefed. + (POSIX1_SYMBOL, POSIX2_SYMBOL): Now 0 unless ADD_MISSING_POSIX. + (XOPEN_SYMBOL, XOPEN_EXTENDED_SYMBOL): Now 0 unless ADD_MISSING_XOPEN. + (main): Ignore symbols whose flags are 0. + +Thu Sep 18 10:43:07 1997 Nick Clifton + + * v850.c (compute_register_save_size): Correct register number. + * v850.md (save_interrupt, return_interrupt): Likewise. + * v850/lib1funcs.asm (save_interrupt): Likewise. + (return_interrupt): Use stack pointer, not element pointer. + +Thu Sep 18 14:22:22 1997 Jason Merrill + + * final.c (final_scan_insn): Hand BARRIERs to dwarf2 code. + * dwarf2out.c (dwarf2out_frame_debug): Pass the whole insn along. + (dwarf2out_stack_adjust): A BARRIER resets the args space to 0. + + * except.c (end_eh_unwinder): Subtract 1 from return address. + * libgcc2.c (__throw): Likewise. + (find_exception_handler): Don't change PC here. Compare end with >. + +Thu Sep 18 14:01:20 1997 Brendan Kehoe + + * configure.in: Make sure to create the stage* and include + symbolic links in each subdirectory. + +Thu Sep 18 13:20:37 1997 J"orn Rennecke + + * sh/lib1funcs.asm (LOCAL): Define. + (whole file): Use it. + +Thu Sep 18 09:52:24 1997 Benjamin Kosnik + + * collect2.c (collect_execute): Specify name of new file when + redirecting stdout/stderr. + +Thu Sep 18 01:47:06 1997 Jeffrey A Law (law@cygnus.com) + + * pa.md (reload_peepholes): Don't allow addresses with side + effects for the memory operand. + +Wed Sep 17 18:19:53 1997 Jason Merrill + + * libgcc2.c (find_exception_handler): Subtract one from our PC when + looking for a handler, to avoid hitting the beginning of the next + region. + + * except.c (expand_builtin_set_return_addr_reg): Use force_operand. + +Wed Sep 17 18:23:09 1997 Jeffrey A Law (law@cygnus.com) + + * mips/abi64.h (LONG_MAX_SPEC): Define. + * mips.h (LONG_MAX_SPEC): Define. + (CPP_SPEC): Include long_max_spec. + (EXTRA_SPECS): Include long_max_spec. + +Wed Sep 17 14:17:26 1997 Paul Eggert + + * configure.in (AC_CHECK_HEADERS): Add inttypes.h, limits.h. + ({sparc,i[3456]86,powerpcle}-*-solaris2*): Use fixinc.math. + + * fixinc.math (PWDCMD, ORIGDIR, LINKS): Remove. + Remove duplicate test for missing $1. + Don't cd to $INPUT. + Build wrapper around system instead of copying it; + this is better if the system is updated later by a software + patch or upgrade. + + * cccp.c (HAVE_STDLIB_H, HAVE_UNISTD_H): + Do not define any more; now autoconfed. + : Include if HAVE_LIMITS_H. + (HOST_BITS_PER_WIDE_INT): Remove. + (HOST_WIDE_INT): Use intmax_t or long long if available. + (pcfinclude): Use size_t, not HOST_WIDE_INT, for cast from pointer; + this is less likely to annoy the compiler. + + * cexp.y (HAVE_STDLIB_H): Do not define any more; now autoconfed. + : Include if HAVE_LIMITS_H. + (HOST_WIDE_INT): Use intmax_t or long long if available. + (unsigned_HOST_WIDE_INT, CHAR_BIT): New macros. + (HOST_BITS_PER_WIDE_INT): Define in terms of CHAR_BIT and sizeof. + (MAX_CHAR_TYPE_MASK, MAX_CHAR_TYPE_MASK): Rewrite so that we don't use + HOST_BITS_PER_WIDE_INT in a preprocessor expression, since it now + uses sizeof. + + * cppexp.c: : Include if HAVE_LIMITS_H. + (HOST_WIDE_INT): Use intmax_t or long long if available. + (CHAR_BIT): New macro. + (HOST_BITS_PER_WIDE_INT): Define in terms of CHAR_BIT and sizeof. + * cpplib.c: : Include if HAVE_LIMITS_H. + (HOST_WIDE_INT): Use intmax_t or long long if available. + (HOST_BITS_PER_WIDE_INT): Remove. + +Wed Sep 17 14:11:38 1997 Jeffrey A Law (law@cygnus.com) + + * v850.c (construct_save_jarl): Fix thinko in last change. + +Wed Sep 17 15:04:19 1997 Doug Evans + + * sparc/sysv4.h (ASM_OUTPUT_{FLOAT,DOUBLE,LONG_DOUBLE}): Delete, + use sparc.h's copies. + * sparc.h (ASM_OUTPUT_{FLOAT,DOUBLE,LONG_DOUBLE}): Print ascii form + as well. + +Wed Sep 17 14:08:20 1997 Nick Burrett + + * explow.c (allocate_dynamic_stack_space): Make allocate_stack + pass 'target' as an extra operand. + * expr.c (expand_builtin_apply): Use allocate_dynamic_stack_space + to push a block of memory onto the stack. + * alpha.md (allocate_stack): Alter in accordance with new operand. + * i386.md (allocate_stack): Likewise. + * rs6000.md (allocate_stack): Likewise. + +Wed Sep 17 13:34:43 1997 Robert Lipe + + * i386/xm-sco5.h (sys_siglist, SYS_SYGLIST_DECLARED): Define. + +Wed Sep 17 13:27:05 1997 Richard Kenner + + * Makefile.in (native): Correct dependency to auto-config.h from + config.h. + +Tue Sep 16 10:02:02 1997 Jason Merrill + + * libgcc2.c (find_exception_handler): Not found is -1. + + * integrate.c (expand_inline_function): Move expand_start_bindings + after expanding the arguments. + + * i386.c (ix86_prologue): Pass SYMBOL_REF to + gen_prologue_{get_pc,set_got}. + * i386.md (prologue_set_got, prologue_get_pc): Adjust. + +Tue Sep 16 07:33:15 1997 Richard Kenner + + * fold-const.c (make_range): Correctly handle cases of converting + from unsigned to signed type. + + * function.c (flush_addressof): New function. + + * combine.c (num_sign_bit_copies): If asking about wider mode, + treat like paradoxical subreg. + +Tue Sep 16 00:26:52 1997 Jeffrey A Law (law@cygnus.com) + + * cse.c (simplify_relational_operation): If MODE specifies mode wider + than HOST_WIDE_INT, high word of CONST_INT is derived from sign bit + of low word. + +Tue Sep 16 00:13:20 1997 Nick Clifton + + * v850.c ({register,pattern}_is_ok_for_epilogue): New functions. + (construct_{save,restore}_jr, pattern_is_ok_for_prologue): Likewise. + * v850.h (pattern_is_ok_for_{pro,epi}logue): New predicates. + (register_is_ok_for_epilogue): Likewise. + * v850.md: Replace prologue and epilogue patterns with a + match_parallel pattern. + * v850.c (output_move_single_unsigned): Cope with zero + extending and moving between registers at the same time. + +Mon Sep 15 22:02:46 1997 Jeffrey A Law (law@cygnus.com) + + * fixinc.math: New file to fix math.h on some systems. + * configure.in (*-*-freebsd*, *-*-netbsd*): Use fixinc.math on these + systems. + +Mon Sep 15 18:58:36 1997 J"orn Rennecke + + * sched.c (update_flow_info) When looking if to set found_split_dest + or found_orig_dest, look at all parts of a PARALLEL. + + * sh.md (casesi_0): Reduce functionality, exclude insns from + mova onwards. Changed expander caller. + (casesi_worker_0): New insn. + (casesi_worker_0+[12]): New define_splits. + (casesi_worker): Need no gen_* function. + (casesi): Use casesi_worker_0 instead of casesi_worker. + * sched.c (update_flow_info): Don't pass SCRATCH to dead_or_set_p. + +Mon Sep 15 11:43:38 1997 Jason Merrill + + Support dwarf2 unwinding on PUSH_ROUNDING targets like the x86. + * dwarf2.h: Add DW_CFA_GNU_args_size. + * frame.c (execute_cfa_insn): Likewise. + * dwarf2out.c (dwarf_cfi_name, output_cfi): Likewise. + (dwarf2out_args_size, dwarf2out_stack_adjust): New fns. + (dwarf2out_frame_debug): If this isn't a prologue or epilogue + insn, hand it off to dwarf2out_stack_adjust. + (dwarf2out_begin_prologue): Initialize args_size. + * frame.h (struct frame_state): Add args_size. + * libgcc2.c (__throw): Use args_size. + * final.c (final_scan_insn): If we push args, hand off all insns + to dwarf2out_frame_debug. + * defaults.h (DWARF2_UNWIND_INFO): OK for !ACCUMULATE_OUTGOING_ARGS. + + * dwarf2out.c (dwarf2out_frame_debug): Fix typo. + Handle epilogue restore of SP from FP. + * emit-rtl.c (gen_sequence): Still generate a sequence if the + lone insn has RTX_FRAME_RELATED_P set. + + * frame.c (extract_cie_info): Handle "e" augmentation. + * dwarf2out.c (ASM_OUTPUT_DWARF_*): Provide definitions in the + absence of UNALIGNED_*_ASM_OP. + (UNALIGNED_*_ASM_OP): Only provide defaults if OBJECT_FORMAT_ELF. + (output_call_frame_info): Use "e" instead of "z" for augmentation. + Don't emit augmentation fields length. + (dwarf2out_do_frame): Move outside of #ifdefs. + * defaults.h (DWARF2_UNWIND_INFO): Don't require unaligned data + opcodes. + + * sparc.h (UNALIGNED_INT_ASM_OP et al): Don't define here after all. + * sparc/sysv4.h (UNALIGNED_INT_ASM_OP): Define here. + * sparc/sunos4.h (DWARF2_UNWIND_INFO): Define to 0. + * sparc/sun4gas.h: New file. + * configure.in: Use sun4gas.h if SunOS 4 --with-gnu-as. + + * collect2.c (write_c_file_stat, write_c_file_glob): Declare + __register_frame_table and __deregister_frame. + +Mon Sep 15 19:04:34 1997 Brendan Kehoe + + * except.c (find_exception_handler_labels): Use xmalloc instead of + alloca, since MAX_LABELNO - MIN_LABELNO can be more than 1 million + in some cases. + +Sat Sep 13 23:13:51 1997 Paul Eggert + + * cpplib.h (PARAMS): Fix misspelling of __STDC__. + (cpp_get_token): Arg is cpp_reader *, not struct parse_marker *. + + * cpplib.c (cpp_fatal, cpp_file_line_for_message): New decls. + (ppp_hash_cleanup, cpp_message, cpp_print_containing_files): Likewise. + (copy_rest_of_line): Fix typo that prevented recognition of + C++ style comments. + (output_line_command, special_symbol): Use %ld for long, not %d. + + * cppexp.c (xrealloc): Declare first arg as void *, not char *. + (cpp_lex): Cast 2nd arg of cpp_parse_escape from const char ** to + char **. + +Fri Sep 12 16:54:04 1997 Doug Evans + + * bitmap.h (bitmap_print): Don't use STDIO_PROTO. + +Fri Sep 12 13:49:58 1997 Jason Merrill + + * except.h: Prototype dwarf2 hooks. + * expr.c: Adjust. + +Thu Sep 11 18:36:51 1997 Jim Wilson + + * local-alloc.c (contains_replace_regs): New function. + (update_equiv_regs): When adding a REG_EQUIV note for a set of a MEM, + verify that there is no existing REG_EQUIV note, and add a call to + contains_place_regs. + + * m68k.h (MACHINE_STATE_{SAVE,RESTORE}): Add __HPUX_ASM__ versions. + +Wed Sep 10 21:49:38 1997 Michael Meissner + + * toplev.c (rest_of_compilation): For passes starting with + flow_analysis, use print_rtl_with_bb instead of print_rtl. + * print-rtl.c (print_rtl_single): Print a single rtl value to a + file. + * flow.c (print_rtl_with_bb): Print which insns start and end + basic blocks. For the start of a basic block, also print the live + information. + * bitmap.h (EXECUTE_IF_AND_IN_BITMAP): New macro, to iterate over + two bitmaps ANDed together. + (bitmap_print): Declare. + * bitmap.c (function_obstack): Don't declare any more. + (bitmap_obstack): Obstack for allocating links from. + (bitmap_obstack_init): New static to say whether to initialize + bitmap_obstack. + (bitmap_element_allocate): Use bitmap_obstack to allocate from. + (bitmap_release_memory): Free all memory allocated from + bitmap_obstack. + (toplevel): Conditionally include stdlib.h. + (free): Provide a declaration if NEED_DECLARATION_FREE. + + * basic-block.h (EXECUTE_IF_AND_IN_REG_SET): New macro, invoke + EXECUTE_IF_AND_IN_BITMAP. + +Wed Sep 10 17:53:33 1997 J"orn Rennecke + + * sh.c (addr_diff_vec_adjust): Properly propagate considered + address changes through alignments. + +Wed Sep 10 13:10:52 1997 Per Bothner + + * stor-layout.c (layout_type): Simplify special BOOLEAN_TYPE handling. + +Wed Sep 10 12:59:57 1997 Jason Merrill + + * expr.c (expand_builtin): Only support __builtin_dwarf_fp_regnum() + if DWARF2_UNWIND_INFO. + +Wed Sep 10 15:43:10 1997 Jason Merrill + + * cplus-dem.c (demangle_fund_type): Change "complex" to "__complex". + +Wed Sep 10 11:13:53 1997 Paul Eggert + + Handle `extern int errno;' correctly when fixing . + * fix-header.c (recognized_extern): Use name_length when comparing. + * scan-decls.c (scan_decls): Don't ignore the first CPP_NAME in a + declaration, so that we see the `extern' in `extern int errno;'. + +Wed Sep 10 11:49:20 1997 Jason Merrill + + Add support for exception handling using DWARF 2 frame unwind info. + * libgcc2.c (get_reg, put_reg, get_return_addr, put_return_addr, + next_stack_level, in_reg_window): Helper fns. + (__throw): Implement for DWARF2_UNWIND_INFO. + + * expr.c (expand_builtin): Handle builtins used by __throw. + * tree.h (enum built_in_function): Add builtins used by __throw. + * c-decl.c (init_decl_processing): Declare builtins used by __throw. + * dwarf2out.c (expand_builtin_dwarf_fp_regnum): Used by __throw. + * except.c (expand_builtin_unwind_init): Hook for dwarf2 __throw. + (expand_builtin_extract_return_addr): Likewise. + (expand_builtin_frob_return_addr): Likewise. + (expand_builtin_set_return_addr_reg): Likewise. + (expand_builtin_eh_stub): Likewise. + (expand_builtin_set_eh_regs): Likewise. + (eh_regs): Choose two call-clobbered registers for passing back values. + + * frame.c, frame.h: New files for parsing dwarf 2 frame info. + * Makefile.in (LIB2ADD): New variable. Add $(srcdir)/frame.c. + (libgcc2.a): Use it instead of $(LIB2FUNCS_EXTRA) $(LANG_LIB2FUNCS) + (stmp-multilib): Likewise. + ($(T)crtbegin.o, $(T)crtend.o): Add -fno-exceptions. + + * except.c: #include "defaults.h". + (exceptions_via_longjmp): Default depends on DWARF2_UNWIND_INFO. + (emit_throw): Don't defeat assemble_external if DWARF2_UNWIND_INFO. + (register_exception_table_p): New fn. + (start_eh_unwinder): Don't do anything if DWARF2_UNWIND_INFO. + (end_eh_unwinder): Likewise. + + * crtstuff.c: Wrap .eh_frame section, use EH_FRAME_SECTION_ASM_OP, + call __register_frame and __deregister_frame as needed. + * varasm.c (eh_frame_section): New fn if EH_FRAME_SECTION_ASM_OP. + * dwarf2out.c (EH_FRAME_SECTION): Now a function-like macro. Check + EH_FRAME_SECTION_ASM_OP. + * sparc/sysv4.h (EH_FRAME_SECTION_ASM_OP): Define. + * mips/iris6.h: (EH_FRAME_SECTION_ASM_OP): Define. + (LINK_SPEC): Add __EH_FRAME_BEGIN__ to hidden symbols. + + * dwarf2out.c (output_call_frame_info): If no support for + EXCEPTION_SECTION, mark the start of the frame info with a + collectable tag. + * collect2.c (frame_tables): New list. + (is_ctor_dtor): Recognise frame entries. + (scan_prog_file): Likewise. + (main): Pass -fno-exceptions to sub-compile. Also do collection + if there are any frame entries. + (write_c_file_stat): Call __register_frame_table and + __deregister_frame as needed. + (write_c_file_glob): Likewise. + + * defaults.h (DWARF2_UNWIND_INFO): Default to 1 if supported. + Also require unaligned reloc support. + * sparc.h (UNALIGNED_SHORT_ASM_OP, UNALIGNED_INT_ASM_OP, + UNALIGNED_DOUBLE_INT_ASM_OP): Define here. + * sparc/sysv4.h: Not here. + + * toplev.c (compile_file): Call dwarf2out_frame_{init,finish}. + * dwarf2out.c (dwarf2out_init): Don't call dwarf2out_frame_init. + (dwarf2out_finish): Don't call dwarf2out_frame_finish. + + * libgcc2.c (L_eh): Reorganize, moving code shared by different + EH implementations to the top. + (find_exception_handler): Split out. Start from 0. Compare against + end with >=. + (__find_first_exception_table_match): Use it. + * except.c (output_exception_table): Don't do anything if there's + no table. Don't output a first entry of zeroes. + (eh_outer_context): Adjust properly. + (add_eh_table_entry): Use xrealloc. + * toplev.c (compile_file): Just call output_exception_table. + +Wed Sep 10 11:49:20 1997 Jason Merrill + + * varasm.c (save_varasm_status): Take the target function context. + * function.c (push_function_context_to): Pass it in. + + * rtl.def (ADDRESSOF): Add new field for original regno. + * function.c (put_reg_into_stack and callers): Add original_regno + argument. + (gen_mem_addressof): Remember the original regno. + * rtl.def (INLINE_HEADER): Add new field for parm_reg_stack_loc. + * rtl.h (PARMREG_STACK_LOC): New macro. + (ADDRESSOF_REGNO): New macro. + * emit-rtl.c (gen_inline_header_rtx): Add parm_reg_stack_loc. + * function.c (max_parm_reg, parm_reg_stack_loc): No longer static. + (assign_parms): Allocate parm_reg_stack_loc on saveable obstack. + * integrate.c (output_inline_function): Set max_parm_reg and + parm_reg_stack_loc from inline header. + (initialize_for_inline): Pass in parm_reg_stack_loc. + +Wed Sep 10 11:30:36 1997 Stan Cox + + * i386.c (override_options): Don't set TARGET_SCHEDULE_PROLOGUE + (ix86_expand_prologue, ix86_expand_epilogue): Emit rtl by default. + +Wed Sep 10 11:30:36 1997 Jason Merrill + + * i386.c (ix86_prologue): Add dwarf2 support for !do_rtl case. + +Wed Sep 10 08:48:44 1997 Jeffrey A Law (law@cygnus.com) + + * xm-m88k.h (USG): Only define if it hasn't already been defined. + + * i386.h (CPP_CPU_DEFAULT): Avoid using #elif. + + * expr.c (do_jump_by_parts_equality_rtx): Don't clobber the + source operand when performing an IOR of the parts. + + * expr.c (emit_block_move): Always return a value. + + * expr.c (clear_storage): Use CONST0_RTX instead of const0_rtx. + when clearing non-BLKmode data. + + * final.c (shorten_branches): Remove last change for ADDR_VEC + alignment computation. During first pass, assume worst + possible alignment for ADDR_VEC and ADDR_VEC_DIFF insns. + +Wed Sep 10 09:33:19 1997 Kamil Iskra + + * explow.c (emit_stack_save, emit_stack_restore): Correctly + handle HAVE_{save,restore}_stack_* evaluating to 0. + +Wed Sep 10 09:27:45 1997 Weiwen Liu + + * Makefile.in (sdbout.o): Add dependency on insn-config.h. + +Wed Sep 10 09:24:56 1997 Nick Burrett + + * sched.c (birthing_insn_p): Rename prototype decl from birthing_insn. + * final.c (leaf_renumber_regs, alter_cond): Declare prototype only + if LEAF_REGISTERS is defined. + * reload1.c (merge_assigned_reloads): Declare prototype only if + SMALL_REGISTER_CLASSES is defined. + * loop.c (replace_call_address): Pre-process out prototype decl. + * real.c (dectoe, etodec, todec): Declare proto if DEC is defined + (ibmtoe, etoibm, toibm): Declare proto if IBM is defined + +Wed Sep 10 09:13:51 1997 Manfred Hollstein + + * configure.in (out_file): Emit definition to config.status. + +Wed Sep 10 08:37:56 1997 J"orn Rennecke + + * final.c (shorten_branches): Fix alignment calculation. + Don't count the lengths of deleted instructions. + +Wed Sep 10 08:34:11 1997 Kaveh R. Ghazi + + * cpplib.c (cpp_start_read): Make known_suffixes static. + +Wed Sep 10 08:27:05 1997 Andreas Schwab + + * m68k.c (print_operand_address) [MOTOROLA]: When compiling + with -fpic (not -fPIC) force the GOT offset to 16 bits. + +Wed Sep 10 08:22:51 1997 Christian Iseli + + * expr.c (convert_move): Add missing use of trunctqtf2. + +Wed Sep 10 08:17:10 1997 Torbjorn Granlund + + * except.c (eh_outer_context): Do masking using expand_and. + +Wed Sep 10 07:52:21 1997 Joel Sherrill + + * pa/rtems.h (subtarget_switches): Removed -mrtems subtarget_switch. + * configure.in (sh*-*-rtems*): New target. + * sh.h (TARGET_SWITCHES: Call SUBTARGET_SWITCHES. + (SUBTARGET_SWITCHES): Provide default definition. + +Wed Sep 10 06:33:47 1997 Richard Kenner + + * i386/mingw32.h ({LIB,LINK}_SPEC): Check for -mwindows, not -windows. + + * alpha/vms.h (ASM_OUTPUT_SECTION): Clear NAME if overlaid. + + * c-parse.in (unary_expr): Test DECL_C_BIT_FIELD, not DECL_BIT_FIELD. + * c-typeck.c (default_conversion): Likewise. + + * tree.c (contains_placeholder_p, substitute_in_expr): + Handle placeholders inside args of CALL_EXPR (and hence in TREE_LIST). + + * expr.c (expand_expr, case PLACEHOLDER_EXPR): Check all + expressions in placeholder_list. + +Tue Sep 9 18:10:30 1997 Doug Evans + + Add port done awhile ago for the ARC cpu. + * arc.h, arc.c, arc.md, t-arc, xm-arc.h: New files. + * arc/initfini.c, arc/lib1funcs.asm: New files. + * ginclude/va-arc.h: New file. + * ginclude/stdarg.h: Include va-arc.h ifdef __arc__. + * ginclude/varargs.h: Likewise. + * Makefile.in (USER_H): Add va-arc.h. + * configure.in (arc-*-elf*): Recognize. + * longlong.h: Add ARC support. + +Tue Sep 9 01:30:37 1997 Jason Merrill + + * mips.h (DWARF_FRAME_REGNUM): Use the same numbering regardless of + write_symbols. + +Mon Sep 8 15:15:11 1997 Nick Clifton + + * v850.h (ASM_SPEC): Pass on target processor. + (CPP_PREDEFINES): Only define if not already specified. + (TARGET_VERSION): Only define if not already specified. + (MASK_CPU, MASK_V850, MASK_DEFAULT): Bits to specify target + processor. + (EXTRA_SWITCHES): Extra entries in the switches array. + (TARGET_DEFAULT): Set default target processor. + +Tue Sep 9 09:50:02 1997 Richard Kenner + + * configure.in (alpha*-*-*): Support pca56 and ev6. + + * varasm.c (named_section): Set in section after writing directive. + * dwarf2out.c (output_call_frame_info): Call named_section. + +Mon Sep 8 16:32:43 1997 Jason Merrill + + * mips.c (function_prologue): Set up the CFA when ABI_32. + + * sparc.c (save_regs): Check dwarf2out_do_frame instead of DWARF2_DEBUG + for dwarf2 unwind info. + (output_function_prologue, sparc_flat_output_function_prologue): Same. + + * final.c (final_end_function): Check dwarf2out_do_frame instead + of DWARF2_DEBUG for dwarf2 unwind info. + (final_scan_insn): Likewise. + (final_start_function): Likewise. Initialize dwarf2 frame debug here. + (final): Not here. + + * expr.c (expand_builtin_return_addr): Only SETUP_FRAME_ADDRESSES if + count > 0. + + * varasm.c (exception_section): Check EXCEPTION_SECTION first. + +Mon Sep 8 14:58:07 1997 Jim Wilson + + * toplev.c (main): Change #elif to #else/#ifdef + + * i386/t-sol2 (TARGET_LIBGCC2_CFLAGS): Define to -fPIC. + +Mon Sep 8 08:45:19 1997 Richard Kenner + + * alpha.h (processor_type): Add EV6. + ({TARGET,MASK}_BWX): Renamed from _BYTE_OPS. + ({TARGET,MASK}_{CIX,MAX}): New macros. + (MASK_CPU_EV5): Change bit number. + (MASK_CPU_EV6, {TARGET,MASK}_SUPPORT_ARCH): New macros. + (TARGET_OPTIONS): Rename "byte" to "bwx" and add "cix" and "max". + (MINIMUM_ATOMIC_ALIGNMENT): Rename TARGET_BYTE_OPS to TARGET_BWX. + (SECONDARY_{INPUT,OUTPUT}_RELOAD_CLASS, ASM_FILE_START): Likewise. + (SECONDARY_MEMORY_NEEDED): Not needed if CIX. + (ASM_FILE_START): Only write if TARGET_SUPPORT_ARCH. + Add "pca56" and "ev6". + * alpha.c (input_operand): Rename TARGET_BYTE_OPS to TARGET_BWX. + (override_options): Likewise; also add new CPU types and subset flags. + * alpha.md: Rename TARGET_BYTE_OPS to TARGET_BWX. + (cpu attr): Add "ev6". + (ev5 function units): Use for ev6 as well, for now. + (ffsdi2): New define_expand and define_insn, for TARGET_CIX. + (sqrt[sd]f2): New patterns, for TARGET_CIX. + (s{min,max}[qh]i3): New patterns, for TARGET_MAX. + (movsi): Use ldf/lsf when appropriate, instead of lds/sts. + (mov[sd]i): Add use of ftio/itof for TARGET_CIX. + * configure.in (alpha*-dec-osf*): Set MASK_SUPPORT_ARCH for >= 4.0B. + Rename MASK_BYTE_OPS to MASK_BWX. + + * i386/mingw32.h (STANDARD_INCLUDE_DIR): New macros. + (STARTFILE_SPEC, PATH_SEPARATOR): Likewise. + + * configure.in (AC_PROG_LN_S): Remove; unneeded. + (*cygwin32*, *mingw32*): Default prefix to /usr. + (symbolic_link): Set to "cp -p" if no "ln -s"; add AC_SUBST. + (configure.lang call): Change remaining use of config.h to auto-conf.h. + + * Makefile.in (LN): Add new symbol. + (FLAGS_TO_PASS): Pass it down. + (stage[1-4]-start): Use $(LN), not "ln -s". + + * mips.h (flag_omit_frame_pointer, frame_pointer_needed, optimize): + Remove declarations: no longer needed. + * pyr.md: Remove unneeded declarations of `optimize'. + * h8300.md: Likewise. + * sparc.c (dwarf2out_cfi_label): Add declaration. + (save_regs, output_function_prologue): Remove cast for it. + (sparc_flat_{save_restore,output_function_prologue): Likewise. + ({save,restore}_regs): No longer inline. + +Mon Sep 8 03:08:35 1997 Jim Wilson + + * i960.h (LINK_SPEC): Handle -mjX and -mrp switches. + + * mips.md (nonlocal_goto_receiver): Define. + + * unroll.c (calculate_giv_inc): Handle increment with code PLUS. + + * alpha.h (PREFERRED_RELOAD_CLASS): Return NO_REGS if NO_REGS + is passed in. + * emit-rtl.c (gen_lowpart_common): Add code to convert CONST_INT to + SFmode for 64 bit hosts. + + * profile.c (output_arc_profiler): Verify next_insert_after is an + INSN before and after skipping a stack pop. Check next_insert_after + for non NULL before deferencing it. + (output_func_start_profiler): Set DECL_EXTERNAL to zero. + + * va-mips.h: Add _VA_MIPS_H_ENUM ifdef/define/endif. + + * m68k.md (iorsi_zexthi_ashl16): Disable. + + * varasm.c (mark_constants): Don't look inside CONST_DOUBLEs. + +Sun Sep 7 18:30:46 1997 Jason Merrill + + * dwarf2out.c (dwarf2out_frame_debug): Assume that in a PARALLEL + prologue insn, only the first elt is significant. + (output_call_frame_info): For exception handling, always use 4-byte + fields as specified by the dwarf2 spec. + Don't skip trivial FDEs. + +Sun Sep 7 03:35:28 1997 Paul Eggert + + * fix-header.c (std_include_table): Remove bogus entry for popen + under stdio.h with ANSI_SYMBOL. popen is a POSIX2_SYMBOL. + +Fri Sep 5 17:19:58 1997 J"orn Rennecke + + * sh.md (movsf_ie+1): Typo fix. + +Fri Sep 5 10:08:44 1997 Jeffrey A Law (law@cygnus.com) + + * v850: New directory for v850 port. + * v850/lib1funcs.asm: New file. + * t-v850, v850.c, v850.h, v850.md, xm-v850.h: New files. + * ginclude/va-v850.h: New file. + * varargs.h, stdarg.h: Include va-mn10200.h. + * configure.in (mn10200-*-*): New target. + * Makefile.in (USER_H): Add va-mn10200.h. + + * xm-svr4.h (SYS_SIGLIST_DECLARED): Define. + * mips/xm-news.h (SYS_SIGLIST_DECLARED): Define. + * mips/xm-sysv4.h (SYS_SIGLIST_DECLARED): Define. + +Fri Sep 5 03:50:15 1997 David Edelsohn + + * rs6000.md (fma patterns): Extend previous -mno-fused-madd + patch to DFmode patterns inadvertently omitted. + +Thu Sep 4 20:06:02 1997 Christian Kuehnke + + * sparc.md: Add ultrasparc scheduling support. + * sparc.h (RTX_COSTS): For MULT give v9 a cost of 25 insns. + +Wed Sep 3 20:56:24 1997 J"orn Rennecke + + * sh.h (UNALIGNED_SHORT_ASM_OP, UNALIGNED_INT_ASM_OP): Define. + +Wed Sep 3 20:52:07 1997 Joel Sherrill + + * sh/rtems.h: New file. + +Wed Sep 3 17:30:36 1997 Stan Cox + + * reg-stack.c (subst_stack_regs): Pop the stack register for a + computed goto which sets the same stack register. + +Wed Sep 3 17:30:36 1997 Jim Wilson + + * i386.c (ix86_expand_epilogue): Emit blockage instruction when pic. + +Wed Sep 3 11:25:19 1997 Jeffrey A Law (law@cygnus.com) + + * pa.md (reload peepholes): Fix typo in last change. + +Wed Sep 3 03:02:02 1997 J"orn Rennecke + + * sh.md (movsi_ie): Move t/r alternative after r/r alternative. + +Tue Sep 2 18:41:55 1997 Jeffrey A Law (law@cygnus.com) + + * cccp.c (sys_errlist): Remove special 4.4bsd declaration. + * collect2.c (sys_errlist): Likewise. + * cpplib.c (sys_errlist): Likewise. + * gcc.c (sys_errlist): Likewise. + * protoize.c (sys_errlist): Likewise. + * configure.in: Check for strerror. + * xm-freebsd.h (HAVE_STRERROR): Remove definition. + * xm-gnu.h (HAVE_STRERROR): Likewise. + * xm-linux.h (HAVE_STRERROR): Likewise. + * xm-netbsd.h (HAVE_STRERROR): Likewise. + * alpha/xm-linux.h (HAVE_STRERROR): Likewise. + * i386/xm-bsd386.h (HAVE_STRERROR): Likewise. + * i386/xm-cygwin32.h (HAVE_STRERROR): Likewise. + * i386/xm-dos.h (HAVE_STRERROR): Likewise. + * i386/xm-mingw32.h (HAVE_STRERROR): Likewise. + * pa/xm-pa.h (HAVE_STRERROR): Likewise. + * pa/xm-papro.h (HAVE_STRERROR): Likewise. + * rs6000/xm-cygwin32.h (HAVE_STRERROR): Likewise. + * rs6000/xm-sysv4.h (HAVE_STRERROR): Likewise. + + * collect2.c (SYS_SIGLIST_DECLARED): Renamed from + DONT_DECLARE_SYS_SIGLIST. + * mips-tfile.c (SYS_SIGLIST_DECLARED): Likewise. + * xm-linux.h (DONT_DECLARE_SYS_SIGLIST): Delete definition. + * xm-freebsd.h (DONT_DECLARE_SYS_SIGLIST): Likewise. + * alpha/xm-linux.h (DONT_DECLARE_SYS_SIGLIST): Delete definition. + * i386/xm-bsd386.h (DONT_DECLARE_SYS_SIGLIST): Likewise. + * i386/xm-sysv4.h (DONT_DECLARE_SYS_SIGLIST): Likewise. + * mips/xm-sysv4.h (DONT_DECLARE_SYS_SIGLIST): Likewise. + * rs6000/xm-sysv4.h (DONT_DECLARE_SYS_SIGLIST): Likewise. + * sparc/xm-sol2.h (DONT_DECLARE_SYS_SIGLIST): Likewise. + * configure.in: Check for sys_siglist declaration. + + * Makefile.in (libgcc2.a): Add missing "else true" clause. + (stage{1,2,3,4}-start): Likewise. + + * mn10200.h (INITIALIZE_TRAMPOLINE): PC relative instructions + are relative to the next instruction, not the current instruction. + +Tue Sep 2 14:15:32 1997 Jason Merrill + + * toplev.c (xrealloc): Handle null ptr. + +Tue Sep 2 13:42:38 1997 Paul N. Hilfinger + + * fixincludes: Permits spaces between # and define. Discard C++ + comments in sys/pci.h on HP/UX 10.20. + +Tue Sep 2 09:28:31 1997 Richard Kenner + + * rs6000.h (ROUND_TYPE_ALIGN): Don't blow up if no fields in record. + +Tue Sep 2 00:19:01 1997 Jason Merrill + + * expr.c (expand_expr, case COND_EXPR): It's OK to merge two + SAVE_EXPRs. + +Mon Sep 1 23:36:45 1997 Jeffrey A Law (law@cygnus.com) + + * pa.c (restore_unscaled_index_insn_codes): New function. + (record_unscaled_index_insn_codes): Likewise. + (output_function_prologue): Call restore_unscaled_index_insn_codes. + (output_function_epilogue): Free memory for unscaled_index_insn_codes. + (pa_reorg): Call record_unscaled_index_insn_codes. + +Mon Sep 1 14:46:09 1997 J"orn Rennecke + + * sh.md (casesi_jump_1, casesi_jump2): Generate expanders. + (casesi_jump): Delete. + (casesi) Use gen_casesi_jump_1 and gen_casesi_jump2 instead of + gen_casesi_jump. + +Mon Sep 1 14:36:36 1997 Paul Eggert + + * sparc/sol2.h (CPP_SPEC): Add -D__STDC__=0 unless -ansi + or -traditional, for compatibility with Sun's practice. + * i386/sol2.h (CPP_SPEC), rs6000/sol2.h (CPP_SPEC): Likewise. + * configure.in ({sparc,i[3456]86,powerpcle}-*-solaris2*): + Set fixincludes=Makefile.in. + +Mon Sep 1 14:08:23 1997 Andreas Schwab + + * Makefile.in (config.status): Depend on version.c. + +Mon Sep 1 13:48:02 1997 Richard Kenner + + * acconfig.h: Remove include of config2.h. + * configure.in: Build auto-config.h, not config.h, from autoconf data. + Add auto-conf.h in front of all other host_xm_file entries. + Make config.h, not config2.h, from host_xm_file. + * Makefile.in (auto-config.h): New rule; was config.h. + (distclean): Remove auto-config.h, not config2.h. + + * expr.c (do_jump_by_parts_equality_rtx): Try to do by IOR of + all the words. + +Mon Sep 1 13:07:36 1997 Bob Manson + + * sparc/t-vxsparc (TARGET_LIBGCC2_CFLAGS): New definition. + (LIBGCC2_CFLAGS): Deleted. + * m68k/t-vxworks68: Likewise. + * i960/t-vxworks960: Likewise. + * a29k/t-vx29k: Likewise. + +Sun Aug 31 17:12:27 1997 Paul Eggert + + * real.c (EMULONG): Correct typo in spelling of HOST_BITS_PER_LONGLONG. + +Fri Aug 29 16:13:51 1997 Jeffrey A Law (law@cygnus.com) + + * mips.md (movstrsi_internal[23]): Set insn type to "store" to + get more accurate schedules. + + * pa.md (reload_peepholes): Make sure operand is a REG before + examining REGNO. Allow general registers too. + +Thu Aug 28 12:34:56 1997 Doug Evans + + * reload1.c (reload_cse_no_longer_dead): Don't pass incremented regno + to SET_HARD_REG_BIT, it can be evaluated twice. + +Wed Aug 27 20:15:53 1997 J"orn Rennecke + + * sh/elf.h: (LINK_SPEC): Use shlelf. + (USER_LABEL_PREFIX, LOCAL_LABEL_PREFIX, ASM_FILE_START): Redefine. + * sh/lib1funcs.asm (___ashrsi3, ___ashlsi3, ___lshrsi3): + Truncate shift count. Use braf if not SH1. + * sh.c (sfunc_uses_reg): No longer static. + Check for SImode inside the USE. + (shiftcosts, expand_ashiftrt, shl_sext_kind): + Use SH_DYNAMIC_SHIFT_COST. + (sh_dynamicalize_shift_p, output_branchy_insn): New functions. + (output_ieee_ccmpeq, mova_p, cache_align_p, fixup_aligns): Likewise. + (branch_offset, short_cbranch_p, med_branch_p): Likewise. + (braf_branch_p, align_length, fixup_addr_diff_vecs): Likewise. + (addr_diff_vec_adjust, get_dest_uid, gen_far_branch): Likewise. + (split_branches, regs_used, gen_block_redirect): Likewise. + (from_compare): Can't compare non-zero DImode constant directly. + Emit special code for TARGET_SH3E floating point with code == GE. + Force 0.0 into a register for SH3E. + (print_operand): Add ','. + Emit the actual comparison instruction. + (sh_builtin_saveregs): Save floating point registers in order that + allows pre-decrement. + (find_barrier): New arguments num_mova and mova. Changed caller. + When rewinding to before a mova, also restore the last found barrier. + Branch is now known to be shortened. + Prefer barriers where no new alignment is needed. + More generic alignment for cache lines. + Add checks for pieces of code that use more table space than their + own size. + Fix up the barrier we return so that the alignment will always be + after the table. + Remove limit adjustments for table alignment. + Handle PARALLELs correctly. + (machine_dependent_reorg): Add extra pass to split insns. + Don't scan instructions twice for broken moves. + Calculate insn length, call fixup_addr_diff_vecs. + Call split_branches. + Add alignment for loops and after BARRIERs. + Initialize max_uid_before_fixup_addr_diff_vecs. + Advance mdep_reorg_phase. + Clear insn_addresses. + (output_far_jump): Use braf and/or pre-allocated scratch register + when possible. + (expand_ashiftrt): Truncate shift count. + (push_regs): Push PR last. + (sh_expand_epilogue): Pop PR first. + (code_for_indirect_jump_scratch, mdep_reorg_phase): New variables. + (uid_align, uid_align_max): Likewise. + (max_uid_before_fixup_addr_diff_vecs, sh_addr_diff_vec_mode): Likewise. + (braf_label_ref_operand): New predicate. + (initial_elimination_offset): calculate offset from + RETURN_ADDRESS_POINTER_REGNUM starting with total_saved_regs_space. + (output_branch): Expect out-of-range condbranches to have been split. + * sh.md (rotlsi3_16): Named insn. + (rotlsi3): Rewritten to use superoptimizer patterns. + (adddi3, subdi3, ashrsi2_16, ashrsi2_31): Always split. + (movsi_i, movsi_ie): replace t/z alternative with t/r alternative. + Use pcload_si and load_si insn types. + (adddi3+1, subdi3+1, ashrsi2_16+1, ashrsi2_31+1) New define_splits. + (addc, subc, ashlsi_c): New insns. + (attribute "type"): New values dyn_shift, load_si, pcload_si, fmove, + jump_ind, arith3 and arith3b. + (function_unit "fp"): Take fmove into account. + (function_unit "int"): Uses one cycle for !dyn_shift. + (function_unit "memory"): Special case for load_si and pcload_si. + (attribute "in_delay_slot): handle pcload_si. + (cmpgtdi_t, cmpgedi_t, cmpgeudi_t, cmpgtudi_t): Type arith3. + (cmpsi+1, cmpeqdi_t) Type arith3b. + (movsf_ie, alternatives f/fGH/X, f/y/X, y/f/X): Type fmove. + (extendsidi2): Delete. + (cmpeqsi_t-2): Delete. (Redundant with movt.) + (*rotlhi3_8) Name. + (iorsi3, rotlsi3_1, rotlsi3_31, rotlsi3_16, (*rotlhi3_8): Type arith. + (ashlsi3_k, ashlhi3_ki, ashrsi2_16, ashrsi2_31, lshrsi3_m): Likewise. + (lshrsi3_k, lshrhi3_m, lshrhi3_k, ashldi3_k, lshrdi3_k): Likewise. + (ashrdi3_k, xtrct_left, xtrct_right, dect, mova, movt): Likewise. + (movt): Likewise. + (ashlsi3_d, ashrsi3_d, lshrsi3_d): Type dyn_shift. + (indirect_jump_scratch, *casesi_jump_1, *casesi_jump_2): Type jump_ind. + (ashlsi3, ashlsi3_n, lshrsi3, lshrsi3_n): Use sh_dynamicalize_shift_p. + (movsf_ie+1, movsf_ie+2): Exchange. + (cmpeqdi_t-1, cmpeqdi_t, cmpgtdi_t, cmpgedi_t): New insns. + (cmpgeudi_t, cmpgtudi_t, movsi_i_lowpart, ieee_ccmpeqsf_t): Likewise. + (cmpdi, movnegt): New define_expands. + (movsi_ie): Add y,y alternative. + (sge): Use it for ! TARGET_IEEE. Use special code for TARGET_IEEE. + (sle): Use sge. + (align_4, casesi_jump): Now define_expand. + (casesi_0, addr_diff_vec_adjust, align_log): New patterns. + (*casesi_jump_[12]): Likewise. + (casesi): Use casesi_0 and casesi_jump. + (casesi_worker): Depends on the mode used for the table. + (define_delay for cbranches): Test TARGET_SH2. + Changed all callers of from_compare. + (attribute "length"): Take use of braf and scratch registers into + account. + (indirect_jump_scratch, block_branch_redirect): New patterns. + (jump): Call output_far_jump for any jump larger than 4 bytes. + (inverse_branch_true, inverse_branch_false): Remove. + (bne, blt, ble, bltu, bleu): Canonicalize. + (attribute "cpu"): Remove "sh0" alternative. + * sh.h (ADJUST_COST): Lower cost of non-address sfunc dependencies. + Adjust cost of load_si / pcload_si insns when not used for call. + (enum reg_class): Move GENERAL_REGS after FPUL_REGS. + (REG_CLASS_NAMES, REG_CLASS_CONTENTS): Likewise. + (REGISTER_MOVE_COST): Add costs for fpul <-> mac, pr moves. + Fix to match default cost in regclass. Move to T reg not costly. + When checking for GENERAL_REGS, check for R0_REGS too. + (INITIALIZE_TRAMPOLINE): Include code for constant parts. + (SHIFT_COUNT_TRUNCATED): Not true for TARGET_SH3. + (CPP_SPEC): Define __sh1__ if no specific cpu is selected. + (FUNCTION_BOUNDARY): Align to cache line boundary. + (optimize, sh_addr_diff_vec_mode, machine_dependent_reorg): Declare. + (addr_diff_vec_adjust, code_for_indirect_jump_scratch): Declare. + (short_cbranch_p, med_branch_p, braf_branch_p, align_length): Declare. + (output_ieee_ccmpeq, output_branchy_insn, sfunc_uses_reg): Declare. + (ASM_OUTPUT_ADDR_DIFF_ELT): Depends on sh_addr_diff_vec_mode. + (PREDICATE_CODES): Add braf_label_ref_operand and register_operand. + (IEEE_BIT, TAGET_IEEE, LOCAL_LABEL_PREFIX, ASSEMBLER_DIALECT): Define. + (CACHE_LOG, enum mdep_reorg_phase_e, TRAMPOLINE_ALIGNMENT): Define. + (SH_DYNAMIC_SHIFT_COST): Define. + (TARGET_SWITCHES): Remove -m0 entry. Add -mieee, -mno-ieee. + (OVERRIDE_OPTIONS): sh_cpu defaults to CPU_SH1. + Initialize sh_addr_diff_vec_mode. + (REG_ALLOC_ORDER): Move FP0 behind FP7. + Move all FP registers in front of the general registers. + (SECONDARY_OUTPUT_RELOAD_CLASS): Add case for MAC_REGS / PR_REGS. + When checking for GENERAL_REGS, check for R0_REGS too. + Fix direction of compares to {FIR,LA}ST_FP_REG. + (SECONDARY_INPUT_RELOAD_CLASS): check for fp_one_operand. + (ASM_OUTPUT_ALIGN_CODE, ASM_OUTPUT_LOOP_ALIGN, SH0_BIT): Delete. + (TARGET_SH0, PUSH_ROUNDING, TRAMPOLINE_TEMPLATE): Delete. + (TRAMPOLINE_ALIGN): Delete. + (processor_type): Remove PROCESSOR_SH0. + (ADJUST_INSN_LENGTH): Remove check for preceding BARRIER. + Adjust ADDR_DIFF_VECs. Add code for alignment instructions. + Check if insn needing a delay slot is already inside a SEQUENCE. + + * va-sh.h (__va_rounded_size): Delete. + (__LITTLE_ENDIAN_P, __SCALAR_TYPE, __PASS_AS_FLOAT): Define. + (va_arg): Unify big and little endian code. + Optimization for small integers. + + From Fred Fish: + * sh.h (INITIAL_ELIMINATION_OFFSET): Proper bracketing. + (REGNO_REG_CLASS, PREFERRED_RELOAD_CLASS): Likewise. + (SECONDARY_{OUTPUT,INPUT}_RELOAD_CLASS, LIBCALL_VALUE): Likewise. + (ROUND_ADVANCE, FUNCTION_ARG, FUNCTION_ARG_PARTIAL_NREGS): Likewise. + (FUNCTION_PROFILE, FUNCTION_EPILOGUE, RETURN_ADDR_RTX): Likewise. + (REGNO_OK_FOR_INDEX_P, EXTRA_CONSTRAINT_Q, MODE_DISP_OK_4): Likewise. + (GO_IF_LEGITIMATE_{INDEX,ADDRES}, LEGITIMIZE_ADDRESS): Likewise. + (CONST_COSTS, REGISTER_MOVE_COST, ASM_OUTPUT_CONSTRUCTOR): Likewise. + (ASM_OUTPUT_CONSTRUCTOR, ASM_OUTPUT_DESTRUCTOR): Likewise. + (ASM_OUTPUT_REG_PUSH, ASM_OUTPUT_REG_POP, ASM_OUTPUT_LABEL): Likewise. + (ASM_OUTPUT_ALIGN), ASM_DECLARE_FUNCTION_NAME): Likewise. + (ASM_GLOBALIZE_LABEL, ASM_OUTPUT_CASE_LABEL): Likewise. + (ASM_OUTPUT_ADDR_DIFF_ELT, ASM_OUTPUT_ADDR_VEC_ELT) Likewise. + (ASM_OUTPUT_DOUBLE, ASM_OUTPUT_FLOAT, ASM_OUTPUT_INT): Likewise. + (ASM_OUTPUT_SHORT, ASM_OUTPUT_CHAR, ASM_OUTPUT_BYTE): Likewise. + (ASM_OUTPUT_SKIP, FINAL_PRESCAN_INSN, PRINT_OPERAND): Likewise. + (PRINT_OPERAND_ADDRESS, HANDLE_PRAGMA, ADJUST_INSN_LENGTH): Likewise. + (PROMOTE_MODE): Likewise. + (ASM_GENERATE_INTERNAL_LABEL): Use LOCAL_LABEL_PREFIX. + (ASM_OUTPUT_INTERNAL_LABEL): Use %L. + * sh/elf.h: (ASM_OUTPUT_LABELREF): Use %U. + (ASM_GENERATE_INTERNAL_LABEL): Use LOCAL_LABEL_PREFIX. + (ASM_OUTPUT_INTERNAL_LABEL, ASM_OUTPUT_SOURCE_LINE): Use %L. + +Wed Aug 27 16:42:21 1997 Bob Manson (manson@cygnus.com) + + * t-h8300 (TARGET_LIBGCC2_CFLAGS): New definit. + (LIBGCC2_CFLAGS): Deleted. + * t-mn10200: Likewise. + +Wed Aug 27 17:10:51 1997 Jim Wilson + + * m68k.md (iorsi3_internal): Readd ! TARGET_5200 check lost in + last change. + +Wed Aug 27 15:19:55 1997 J"orn Rennecke + + * dwarfout.c (dwarfout_start_new_source_file): Strip leading '*'s + from label names. + +Wed Aug 27 14:33:38 1997 Jim Wilson + + * reload.c (find_reloads, case '0'): Reject matching a non-offsettable + address where an offsettable address is required. + +Wed Aug 27 10:38:32 1997 Jeffrey A Law (law@cygnus.com) + + * reorg.c (dbr_schedule): Allow current_function_return_rtx + to be something other than a REG. + * function.c (expand_function_end): Fix current_function_return_rtx + if it was a pseudo. + + * t-freebsd (USER_H): Include EXTRA_HEADERS and LANG_EXTRA_HEADERS. + * x-netbsd: Likewise + * x-dgux (USER_H): Include EXTRA_HEADERS and LANG_EXTRA_HEADERS + (INSTALL_HEADERS): Delete. + * x-dguxbcs: Likewise. + * x-hp3bsd44: Likewise + * x-pa: Likewise. + +Wed Aug 27 07:15:58 1997 Klaus Espenlaub + + * configure.in (AC_PROG_CC, AC_PROG_MAKE_SET): Check for gcc before + testing for flex. + +Wed Aug 27 02:24:35 1997 Jim Wilson + + * dwarfout.c (dwarfout_file_scope_decl, case TYPE_DECL): Check + TYPE_DECL_IS_STUB instead of DECL_NAME. + + * Makefile.in (install-info): Don't cd into srcdir. Add srcdir to + filenames. Use sed to extract base filename for install. + +Wed Aug 27 01:56:18 1997 Doug Evans + + * loop.c (combine_movables): Earlier insns don't match later ones. + + * c-decl.c (grokdeclarator): If array index or size calculations + overflow, issue an error. + * fold-const.c (int_const_binop): New static function. + (const_binop, size_binop): Call it. + +Tue Aug 26 17:51:56 1997 Jason Merrill + + * collect2.c (main): Check SCAN_LIBRARIES instead of LDD_SUFFIX + to decide whether to always emit init and fini handles. + +Tue Aug 26 13:51:10 1997 Jim Wilson + + * stor-layout.c (layout_record): Test DECL_PACKED instead of + TYPE_PACKED to determine alignment. + + * combine.c (try_combine): Distribute REG_DEAD notes created for + i3dest_killed similar to the ones created for i2dest_in_i2src + and for i1dest_in_i1src. + +Tue Aug 26 11:36:34 1997 Jeffrey A Law (law@cygnus.com) + + * loop.c (check_final_value): Don't miss a biv increment in a + parallel. + + * loop.c (check_dbra_loop): If the loop biv is only used + for counting, then normalize it so that the initial + value is zero. + +Tue Aug 26 06:19:48 1997 Jason Merrill + + * dwarfout.c (*_LABEL): Add initial '*'. + +Tue Aug 26 05:27:28 1997 Richard Henderson + + * alpha/elf.h (LINK_SPEC): Conditionalize on USE_GNULIBC_1. + * configure.in (alpha-*-linux-gnulibc1): New target. + (alpha-*-linux-gnu*): Don't build crtbegin/end. + +Mon Aug 25 19:11:38 1997 Bernd Schmidt + + * reload1.c (reload_cse_simplify_operands): Fix typo. + +Mon Aug 25 19:04:42 1997 Richard Kenner + + * c-typeck.c (common_type): Always prefer long double to double. + +Mon Aug 25 08:55:00 1997 Jeffrey A Law (law@cygnus.com) + + * pa.c (secondary_reload_class): (mem (mem ... )) does not need + secondary reloads. + + * pa.c (hppa_builtin_saveregs): Emit a blockage insn after the + store of the argument registers. + +Sun Aug 24 21:25:06 1997 Bernd Schmidt + + * reload1.c (reload_cse_mem_conflict_p, case MEM): Also check + for conflict with the address. + +Sat Aug 23 18:43:22 1997 Jim Wilson + + * acconfig.h (NEED_DECLARATION_CALLOC): Add. + * configure.in: Add GCC_NEED_DECLARATION call for calloc. + * rs6000/xm-rs6000.h (malloc, realloc, calloc, free): Delete + declarations. + + * m68k/m68kemb.h (LIB_SPEC): Add missing comment end before it. + * m68k/next.h (GO_IF_INDEXABLE_BASE): Fix typo in undef. + +Sat Aug 23 00:18:22 1997 Jeffrey A Law (law@cygnus.com) + + * pa.c (pa_reorg): Always put begin_brtab and end_brtab insns + around branch tables. + * pa.md (begin_brtab, end_brtab): Only emit the .begin_brtab + and .end_brtab directives if TARGET_GAS. + +Fri Aug 22 19:17:25 1997 Richard Kenner + + * function.c (instantiate_virtual_regs_1, case ADDRESSOF): + New case. + (fix_lexical_addr): Handle (addressof (mem ...)). + +Thu Aug 21 17:56:06 1997 Richard Kenner + + * reload.c (push_secondary_reload): If SECONDARY_MEM_NEEDED, + call get_secondary_mem for input before adding reload and + for output after. + (push_reload): Likewise. + +Thu Aug 21 15:57:03 1997 Jim Wilson + + * stmt.c (start_cleanup_deferal, end_cleanup_deferal): Test + block_stack before dereferencing it. + +Wed Aug 20 15:45:52 1997 Dave Love + + * dwarf2.h (enum dwarf_call_frame_info): Remove trailing comma from + list. + +Wed Aug 20 15:30:36 1997 Stan Cox + + * i386.c (ix86_prologue, ix86_epilogue): New functions. + ({function,ix86_expand}_{pro,epi}logue, ix86_expand_prologue): + Use ix86_prologue. + +Wed Aug 20 14:57:11 1997 Michael Meissner + + * rs6000.h (ISSUE_RATE): Define instead of MACHINE_issue_rate. + +Tue Aug 19 17:10:56 1997 Jason Merrill + + * cplus-dem.c: Add 'extern' to prepends_underscore. + +Tue Aug 19 15:46:30 1997 Jeffrey A Law (law@cygnus.com) + + * mips/r3900.h (SUBTARGET_CC1_SPEC): Remove some unnecessary stuff. + (MIPS_CPU_STRING_DEFAULT, MIPS_ISA_DEFAULT): Define. + +Mon Aug 18 21:49:02 1997 Jim Wilson + + * reload.c (find_reloads): Add code to convert RELOAD_FOR_OPADDR_ADDR + reloads to RELOAD_FOR_OPERAND_ADDRESS reloads. + +Mon Aug 18 17:39:02 1997 Mike Meissner + + * configure.in ({powerpc,rs6000}*-*-*, --with-cpu): Remove single + quotes around the name. + +Mon Aug 18 17:26:42 1997 Doug Evans + + * mips.md (movsi_ulw,movsi_usw,loadgp): Give unspec a mode. + +Mon Aug 18 11:05:17 1997 Jeffrey A Law (law@cygnus.com) + + * mips/r3900.h (TARGET_DEFAULT): Turn on MASK_MIPS3900. + +Sun Aug 17 14:39:18 1997 Gavin Koch (gavin@cygnus.com) + + * mips/elf.h (PREFERRED_DEBUGGING_TYPE): Only set if not already set. + * mips.c (TARGET_{SINGLE,SOFT}_FLOAT): Make sure both aren't set. + (PROCESSOR_R3900): Set flag from option. + * mips.h: Add m3900 option. + ({PROCESSOR,TARGET,MASK}_R3900): Define. + (GENERATE_{BRANCHLIKELY,MADD,MULT3): Likewise. + (debugj,MASK_DEBUG_J): Delete to make room for m3900. + (BRANCH_LIKELY_P): Redefine to include 3900. + (GAS_ASM_SPEC,CC1_SPEC): Add m3900 option. + (RTX_COSTS): Add 3900. + * mips.md: Add 3900, including three op madd and mult. + * configure.in (mipstx39{,el}-*-elf*): New cases. + * mips/r3900.h: New file. + +Fri Aug 15 07:34:12 1997 Richard Earnshaw (rearnsha@arm.com) + + * arm.md (umulsi3_highpart, smulsi3_highpart): Add extra reloading + alternatives. + +Fri Aug 15 07:34:12 1997 Torbjorn Granlund + + * arm.md (umulsi3_highpart, smulsi3_highpart): New patterns. + * arm.c (arm_rtx_costs, case TRUNCATE): New case. + +Fri Aug 15 06:40:03 1997 Richard Kenner + + * genemit.c (main): Write an include for flags.h. + * genoutput.c (main): Likewise. + + * alpha.c (override_options): Turn off byte insns for cpu=ev4 or ev5. + + * alpha.md (allocate_stack): If stupid reg allocation, add USE + for loop variable. + + * fold-const.c (fold, compare cases): Add calls to `fold' to + previous change. + +Wed Aug 13 17:32:38 1997 Jason Merrill + + * rtl.h ({SET,}ADDRESSOF_DECL): op 1 of ADDRESSOF is now the decl. + * function.c (put_var_into_stack, gen_mem_addressof, + put_addressof_into_stack): Adjust. + + * expr.c (expand_expr, case TARGET_EXPR): Call mark_addressable + again for the slot after we give it RTL. + (expand_expr, case VAR_DECL): Lose gen_mem_addressof case. + +Wed Aug 13 17:29:25 1997 J"orn Rennecke + + * c-lex.c (check_newline): Pass finput again to HANDLE_PRAGMA. + +Wed Aug 13 16:51:35 1997 Bernd Schmidt + + * reload1.c (reload_cse_simplify_operands): New function. + (reload_cse_no_longer_dead,reload_cse_delete_death_notes): Likewise. + (no_longer_dead_regs): New static variable. + (reload_cse_simplify_set): Now returns int. + Don't delete death notes on previous insns, call + reload_cse_no_longer_dead instead. + Call validate_change with nonzero value for in_group. + (reload_cse_noop_set_p): Don't delete death notes on previous insns, + call reload_cse_no_longer_dead instead. + (reload_cse_regs): Initialize no_longer_dead_regs and call + reload_cse_delete_death_notes as appropriate. + Call apply_change_group after calling reload_cse_simplify_set. + Call reload_cse_simplify_set on elements of a PARALLEL. + Call reload_cse_simplify_operands if reload_cse_simplify_set could + not simplify things. + +Wed Aug 13 16:18:42 1997 Douglas Rupp + + * vms.h (LINK_SPEC): Echo -shared, not -share, to linker. + +Wed Aug 13 12:51:11 1997 Richard Stallman + + * m68k.md: Add braces to clarify nesting. + +Wed Aug 13 12:51:11 1997 Jason Merrill + + * calls.c (expand_call): Use assign_temp and mark_addressable + instead of calling gen_mem_addressof directly. + +Wed Aug 13 12:40:15 1997 Richard Kenner + + * Makefile.in (install-man): Add missing $(exeext). + + * configure.in (alpha*-dec-osf*): Merge various cases; + split off version-specific files in new case statement. + Include osf2or3.h even for OSF1.2. + + * alpha.c (NUM_ARGS): New macro. + (CURRENT_FUNCTION_ARGS_INFO): Deleted. + (alpha_builtin_saveregs): Use new macro. + (function_arg): Deleted. + (alpha_arg_type, alpha_arg_info_reg_val): New functions. + * vms.h (enum avms_arg_type, avms_arg_info): New types. + (CUMULATIVE_ARGS, INIT_CUMULATIVE_ARGS): Update definitions + to use new types. + (SETUP_INCOMING_VARARGS): Likewise. + (FUNCTION_ARG{,_PARTIAL_NREGS}, FUNCTION_ARG_ADVANCE): Likewise. + Only update CUM in FUNCTION_ARG_ADVANCE. + +Tue Aug 12 19:27:32 1997 Philippe De Muyter + + * integrate.c (save_for_inline_copying): Use 0, not NULL_PTR, + as initial value for real_label_map. + (copy_for_inline): Likewise. + +Tue Aug 12 16:15:36 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * rtl.h (BYTECODE_LABEL): Use XSTR, not XEXP. + + * calls.c (expand_calls): Properly call any_pending_cleanups. + +Tue Aug 12 12:18:01 1997 Jason Merrill + + * function.c (purge_addressof_1): Add force argument. + (purge_addressof): If there are any ASM_OPERANDS in an insn, always + put ADDRESSOFs into the stack. + + * function.c (setjmp_protect): See through addressof. + (setjmp_protect_args): Likewise. + * calls.c (expand_call): For now, only use addressof if the type + doesn't promote. + * function.c (put_var_into_stack): Likewise. + * expr.c (expand_expr): Likewise. + * toplev.c (rest_of_compilation): Check inlineable instead of + DECL_INLINE. + * function.c (purge_addressof_1): Try recognizing the insn with + and without the SUBREG. If it doesn't work, just put the REG into + the stack. + (gen_mem_addressof): Set the mode of the MEM to the mode of the type. + (put_var_into_stack): Don't be fooled by addressof in an enclosing + scope. + +Sun Aug 10 22:19:19 1997 Richard Kenner + + * explow.c (probe_stack_range): Add USE for test_addr if -O0. + +Sun Aug 10 22:15:40 1997 Jason Merrill + + * toplev.c (rest_of_compilation): Move purge_addressof before loop. + +Sun Aug 10 15:25:51 1997 Jim Wilson + + * toplev.c (main): In -g handling code, add code to set len. + + * sdbout.c (plain_type_1, case ARRAY_TYPE): Verify that TYPE_DOMAIN + has integer TYPE_{MAX,MIN}_VALUE before using them. + + * alpha.md (extendqihi2): Use HImode not QImode in force_reg call. + +Sun Aug 10 16:47:34 1997 Nick Burrett + + * arm/aof.h (COMMON_SECTION): New macro, define common_section. + (EXTRA_SECTION_FUNCTIONS): Add COMMON_SECTION. + (EXTRA_SECTIONS): Add in_common. + (ASM_OUTPUT_COMMON): Call common_section() to indicate we've + changed areas. + +Sat Aug 9 20:04:35 1997 Jim Wilson + + * dwarf2out.c (gen_subprogram_die): Handle redefinition of an + extern inline function. + +Sat Aug 9 13:01:06 1997 Michael Meissner + + * rs6000/sysv4.h (*_SPEC): Add support for -mads and -myellowknife. + Use a common crt0.o for all embedded platforms. Use --start-group + and --end-group instead of -( and -) to allow better cut and pasting + when debugging the linker. Set default start for MVME text. + (TARGET_SWITCHES): Add -mads and -myellowknife. + +Fri Aug 8 20:12:43 1997 Per Bothner + + * dwarf2out.c (gen_enumeration_type_die): + Make code work for a tag name, without a TYPE_STUB_DECL. + (gen_struct_or_union_type_die): Likewise. + +Fri Aug 8 18:10:40 1997 Marc Lehmann + + * i386/go32.h (HAS_INIT_SECTION, HAVE_ATEXIT): New macros. + +Fri Aug 8 17:30:22 1997 H.J. Lu + + * i386.c (output_pic_addr_const, case PLUS): Emit the constant first. + +Fri Aug 8 17:07:36 1997 Stan Cox + + * m88k.c (m88k_expand_prologue): Set MEM_IN_STRUCT_P of va_list + template. + + * reg-stack.c (compare_for_stack_reg): Swap only if the source and + destination are both on the regstack. + (subst_stack_regs_pat): Put the destination at the top of the regstack. + +Fri Aug 8 17:03:21 1997 Bernd Schmidt + + * i386.md (pop): pop increments the stack pointer. + (prologue_set_stack_ptr): New pattern. + * i386.c (ix86_expand_prologue): Use prologue_set_stack_ptr + instead of subsi3. + +Fri Aug 8 17:00:36 1997 Paul Eggert + + * gansidecl.h, halfpic.h (STDIO_PROTO): Remove. + * bitmap.h, c-tree.h, output.h, reload.h, rtl.h (STDIO_PROTO): + Replace with PROTO in include files. + * bc-emit.c: Include before include files that formerly + used STDIO_PROTO. + * bc-optab.c, c-common.c, c-decl.c, caller-save.c, calls.c: Likewise. + * convex.c, i860.c, mips.c, spur.c, tahoe.c, emit-rtl.c: Likewise. + * explow.c, expmed.c, expr.c, genattrtab.c, halfpic.c: Likewise. + * jump.c, optabs.c, profile.c, recog.c, regclass.c: Likewise. + * rtlanal.c, sdbout.c, unroll.c: Likewise. + * genattrtab.c (main): Generate files that include + before including files that formerly used STDIO_PROTO. + * genemit.c (main), genextract.c (main), genopinit.c (main): Likewise. + * genoutput.c (output_prologue), genpeep.c (main): Likewise. + * genrecog.c (main): Likewise. + * halfpic.h (PROTO): Use "gansidecl.h" to define this instead. + (half_pic_finish): Declare without prototype; FILE isn't defined. + + * bitmap.c, c-aux-info.c, c-lex.c: Include "config.h" first. + * c-parse.in, c-pragma.c, 1750a.c, a29k.c, alpha.c: Likewise. + * arm.c, clipper.c, dsp16xx.c, elxsi.c, fx80.c, gmicro.c: Likewise. + * h8300.c, i370.c, i386.c, i386/winnt.c, i960.c: Likewise. + * m32r.c, m68k.c, m88k.c, mn10200.c, mn10300.c, ns32k.c: Likewise. + * pa.c, pdp11.c, pyr.c, romp.c, rs6000.c, sparc.c, vax.c: Likewise. + * we32k.c, cppmain.c, dbxout.c, flow.c, fold-const.c: Likewise. + * gcc.c, gcov.c, global.c, integrate.c, local-alloc.c: Likewise. + * loop.c, mips-tdump.c, mips-tfile.c, objc-act.c: Likewise. + * real.c, reg-stack.c, reload.c, reload1.c, reorg.c, sched.c: Likewise. + * stupid.c, tree.c, varasm.c, xcoffout.c: Likewise. + +Fri Aug 8 14:52:35 1997 Jason Merrill + + * function.c (fixup_stack_1): Stack slots can also be relative to + the frame or stack pointers. + +Fri Aug 8 14:13:49 1997 Richard Henderson + + * dwarf2out.c (reg_loc_descriptor): Fix prototype. + (concat_loc_descriptor): New function. + (loc_descriptor): Call it. + (add_AT_location_description): Also elide the descriptor if both + halves of a CONCAT are pseudos. + (add_location_or_const_value_attribute): Recognize CONCAT too. + +Fri Aug 8 06:36:29 1997 Bernd Schmidt + + * c-common.c (if_stack{,_space,_pointer}): New static variables. + (c_expand_{start_cond,start_else,end_cond}): New functions. + * c-parse.in (compstmt_count): New static variable. + (compstmt_start): New rule. + (compstmt): Use new rule. + (do_stmt_start): Update compstmt_count. + (simple_if, stmt): Use new versions of start_cond, start_else, + and end_cond. + +Thu Aug 7 15:35:25 1997 Jim Wilson + + * mips/iris6.h (TARGET_LONG64): Don't define here. + * mips.c (override_options): Set MASK_LONG64 for ABI_64. + + * mips.c (function_prologue): Don't emit ".ent", ".frame", + ".mask", ".fmask" if flag_inhibit_size_directive is true. + (function_epilogue): Don't emit ".end" if + flag_inhibit_size_directive is true. + + * mips/iris6.h (STARTFILE_SPEC, LIB_SPEC): Move + -L/usr/lib{32,64}/mips? from STARTFILE_SPEC to LIB_SPEC. + +Thu Aug 7 13:14:21 1997 Torbjorn Granlund + + * fold-const.c (fold): Optimize unsigned x <= 0x7fffffff. + +Thu Aug 7 12:46:31 1997 Richard Kenner + + * explow.c (convert_memory_address, case LABEL_REF): Copy + LABEL_REF_NONLOCAL_P. + + * expr.c (store_constructor): Use CONST0_RTX macro, not always + the integer version, when clearing a register. + + * varasm.c (output_constructor): Correctly check for + multi-word constant. + +Thu Aug 7 10:04:42 1997 Douglas Rupp + + * alpha/vms-tramp.asm: New file. + + * gcc.c (execute): Don't allow -pipe on VMS. + + * alpha.c (vmskrunch): Don't strip off trailing digits. + (vms_valid_decl_attribute_p): New function. + * alpha/vms.h (TRAMPOLINE_TEMPLATE): Add another quadword of zeros. + (TRAMPOLINE_SIZE): Now 32 bytes. + (INITIALIZE_TRAMPOLINE): Put FNADDR at offset 16, CXT at 24. + (DBX_DEBUGGING_INFO, ASM_FORMAT_PRIVATE_NAME): Always undefine. + (STARTFILE_SPEC): Likewise. + (PREFERRED_DEBUGGING_TYPE): Define to be Dwarf-2. + (VALID_MACHINE_DECL_ATTRIBUTE, ASM_OUTPUT_SECTION{,_NAME}): New macros. + (ASM_OUTPUT_ALIGN{,ED_COMMON}): Redefine. + (LINK_SPEC): Pass -share and -v. + (ENDFILE_SPEC, LIBGCC2_SPEC): Don't redefine. + +Thu Aug 7 06:21:47 1997 Bernd Schmidt + + * Eliminate most -Wswitch warnings. + * c-common.c (binary_op_error): Add default case to switch. + (shorten_compare, truthvalue_conversion): Likewise. + * c-iterate.c (collect_iteratores): Likewise. + * c-typeck.c (comptypes, build_component_ref): Likewise. + (build_binary_op, lvalue_p, build_unary_op): Likewise. + (build_modify_expr, initializer_constant_valid_p): Likewise. + (c_expand_return): Likewise. + * calls.c (calls_function_1): Likewise. + * combine.c (find_split_point, simplify_rtx): Likewise. + (simplify_if_then_else, simplify_logical): Likewise. + (extract_left_shift, make_compound_operation, force_to_mode): Likewise. + (known_cond, nonzero_bits, num_sign_bit_copies): Likewise. + (merge_outer_ops, simplify_shift_const, simplify_comparison): Likewise. + (reversible_comparison_p, mark_used_regs_combine): Likewise. + * convert.c (convert_to_integer): Likewise. + * cse.c (canon_hash, exp_equiv_p): Likewise. + (set_nonvarying_address_components, canon_reg): Likewise. + (simplify_unary_operation, simplify_plus_minus): Likewise. + (simplify_relational_operation, fold_rtx): Likewise. + (cse_process_note, count_reg_usage): Likewise. + * dbxout.c (dbxout_symbol): Likewise. + * dwarf2out.c (lookup_cfa_1, print_die): Likewise. + * emit_rtl.c (copy_rtx_if_shared, reset_used_flags): Likewise. + * explow.c (plus_constant_wide, convert_memory_address): Likewise. + (promote_mode, emit_stack_save, emit_stack_restore): Likewise. + * expmed.c (expand_divmod, emit_store_flag): Likewise. + * expr.c (queued_subexp_p, is_zeros_p, safe_from_p): Likewise. + (bc_expand_expr, preexpand_calls, convert_move): Likewise. + * final.c (get_attr_length, final_scan_insn): Likewise. + (walk_alter_subreg, alter_cond): Likewise. + * flow.c (jmp_uses_reg_or_mem, mark_used_regs): Likewise. + * fold-const.c (operand_equal_p, twoval_comparison_p): Likewise. + (eval_subst, invert_truthvalue, range_binop): Likewise. + (make_range, fold): Likewise. + * function.c (fixup_var_refs_1, instantiate_virtual_regs_1): Likewise. + * genattrtab.c (attr_copy_rtx, make_canonical): Likewise. + (encode_units_mask, simplify_test_exp): Likewise. + (find_and_mark_used_attributes, write_test_expr): Likewise. + (simplify_with_current_value_aux, clear_struct_flag): Likewise. + (count_sub_rtxs, gen_insn walk_attr_value): Likewise. + (copy_rtx_unchanging): Likewise. + * genconfig.c (walk_insn_part): Likewise. + * genextract.c (walk_rtx): Likewise. + * genoutput.c (scan_operands): Likewise. + * genpeep.c (match_rtx): Likewise. + * genrecog.c (add_to_sequence): Likewise. + * integrate.c (copy_for_inline, copy_rtx_and_substitute): Likewise. + (subst_constants): Likewise. + * jump.c (duplicate_loop_exit_test, comparison_dominates_p): Likewise. + (mark_jump_label, rtx_renumbered_equal_p): Likewise. + (rtx_equal_for_thread_p): Likewise. + * local-alloc.c (memref_referenced_p): Likewise. + * loop.c (record_excess_regs, reg_in_basic_block_p): Likewise. + (get_condition, replace_call_address): Likewise. + (count_nonfixed_reads, find_and_verify_loops, find_mem_givs): Likewise. + (maybe_eliminate_biv_1, invariant_p, simplify_giv_expr): Likewise. + * optabs.c (emit_float_lib_cmp): Likewise. + * print-tree.c (print_node): Likewise. + * recog.c (validate_replace_rtx_1, find_single_use_1): Likewise. + * reload.c (subst_reg_equivs, find_reloads_address_1): Likewise. + (refers_to_regno_for_reload_p, find_equiv_reg): Likewise. + * reload1.c (set_label_offsets, eliminate_regs): Likewise. + (scan_paradoxical_subregs, count_occurrences): Likewise. + * rtl.c (copy_rtx, copy_most_rtx): Likewise. + * rtlanal.c (rtx_varies_p, rtx_addr_can_trap_p): Likewise. + (reg_mentioned_p, reg_referenced_p, modified_between_p): Likewise. + (modified_in_p, refers_to_regno_p, volatile_insn_p): Likewise. + (volatile_refs_p, side_effects_p): Likewise. + (inequality_comparison_p, replace_regs): Likewise. + * sched.c (sched_analyze_2): Likewise. + * stmt.c (expand_return): Likewise. + * tree.c (staticp, unsave_expr_now, contains_placeholder_p): Likewise. + (substitute_in_expr, build_type_attribute_variant): Likewise. + (simple_cst_equal): Likewise. + * unroll.c (remap_split_bivs): Likewise. + * varasm.c (const_hash, compare_constant_1): Likewise. + (decode_rtx_const, output_addressed_constants): Likewise. + (output_constant): Likewise. + * print-tree.c (print_node): Convert switch with one case into an if. + * sched.c (memrefs_conflict_p): Likewise. + * genrecog.c (write_tree_1): Output default case for every switch. + + * profile.c (output_arc_profiler) [SMALL_REGISTER_CLASSES]: + Apply PATTERN only to insns. + +Thu Aug 7 06:13:20 1997 Robert Lipe + + * i386/t-sco5 (libgcc2-elf.a): Resync with Makefile.in. + +Wed Aug 6 19:28:05 1997 Jim Wilson + + * dwarf2out.c (build_abbrev_table): Use xrealloc not xmalloc. + +Wed Aug 6 12:57:24 1997 Jason Merrill + + * dwarf2out.c (output_call_frame_info): Always emit the info. + (dwarf2out_frame_debug): We can initialize the temp reg in the + epilogue, too. + + * rtl.def: Add ADDRESSOF. + * rtl.h (ADDRESSOF_TYPE, SET_ADDRESSOF_TYPE): New macros. + * Makefile.in (mostlyclean): Remove *.addressof. + * toplev.c (rest_of_compilation): Set DECL_DEFER_OUTPUT on + non-nested inlines. Run purge_addressof after CSE. + (various): Add .addressof RTL dump file. + * rtl.c (copy_rtx): No need to copy ADDRESSOF. + * reload1.c (eliminate_regs): Elide ADDRESSOF. + * recog.c (general_operand): (MEM (ADDRESSOF ())) is a valid operand. + So is (ADDRESSOF ()). + (memory_address_p): (ADDRESSOF ()) is a valid memory address. + * integrate.c (expand_inline_function): If the structure_value_addr + is an ADDRESSOF, we can use it as a constant. + (copy_rtx_and_substitute): Copy a '0' operand over unchanged. + * function.c (fixup_var_refs_1): Remove (ADDRESSOF (MEM ())). + (gen_mem_addressof): New fn. + (put_addressof_into_stack): New fn. + (purge_addressof_1): New fn. + (purge_addressof): New fn. + (instantiate_decl): Don't bother looking into an ADDRESSOF. + (put_var_into_stack): Call gen_mem_addressof for local REGs instead + of calling put_reg_into_stack. + * expr.c (expand_expr, case TARGET_EXPR): Put the temp in a register + if it will fit. + (expand_expr, case ADDR_EXPR): Call gen_mem_addressof to take the + address of a REG. + * explow.c (memory_address): An ADDRESSOF is a valid memory address. + * dwarfout.c (location_or_const_value_attribute): Handle ADDRESSOF. + * dwarf2out.c (add_location_or_const_value_attribute): Handle + ADDRESSOF. + * cse.c (FIXED_BASE_PLUS_P): Add ADDRESSOF. + (NONZERO_BASE_PLUS_P): Add ADDRESSOF. + (canon_hash): Ignore '0' operands. + (find_best_addr): Don't try to replace an ADDRESSOF. + (fold_rtx): If our address has a const equiv of an ADDRESSOF, use it. + * calls.c (expand_call): Put the struct value in a register if + it fits. + +Tue Aug 5 16:10:45 1997 Jason Merrill + + * mips.c (function_arg): Handle passing a struct + containing a double in a DFmode register without the PARALLEL. + +Tue Aug 5 12:27:31 1997 Doug Evans + + * configure.in (sparc-*-solaris2): Set float_format to i128. + * config/float-i128.h: New file. + +Mon Aug 4 17:45:19 1997 Richard Kenner + + * combine.c (try_combine): If have PARALLEL of independent SETs + and have cc0, ensure insn using CC0 come first. + +Mon Aug 4 15:22:41 1997 Mike Meissner + + * rs6000/sysv4.h (JUMP_TABLES_IN_TEXT_SECTION): Undef for System V + environments. + +Mon Aug 4 12:34:41 1997 Philip Blundell + + * configure.in (arm-*-aout): Set tmake_file correctly. + +Mon Aug 4 08:06:48 1997 Bernd Schmidt + + * reload.c (find_reloads_address_1): Don't pass VOIDmode for an + integer argument of push_reload. + + * rtlanal.c (may_trap_p): Fix unintended fall-through so divisions by + non-zero constants are handled properly. Return 1 for FP divisions. + +Mon Aug 4 06:52:20 1997 Andreas Schwab + + * c-common.c (check_format_info): Store each flag character only + once in the flag_chars array. + +Sun Aug 3 21:57:31 1997 Jim Meyering + + * objc/Make-lang.in (objc/*.o): Depend on $(GCC_PASSES). + +Sun Aug 3 21:54:51 1997 Nick Burrett + + * cpplib.c (cpp_start_read): Recognise suffixes 'cp' and 'c++'. + +Sun Aug 3 19:18:27 1997 Ralf Baechle + + * Makefile.in (mostlyclean): Remove libgcc1-test. + +Sun Aug 3 19:10:27 1997 Klaus Espenlaub + + * Makefile.in (T): Move to place where it can be overridden. + (install_common): Fix permissions of specs and EXTRA_PARTS files. + +Sun Aug 3 19:07:04 1997 Jan-Jaap van der Heijden + + * gcc.c (default_compilers): Add default entries for Pascal. + +Sun Aug 3 18:38:41 1997 Richard Henderson + + * alpha.c (alpha_return_addr): New function. + (output_epilog): Zero alpha_return_addr_rtx. + * alpha.h (RETURN_ADDR_RTX): Call alpha_return_addr. + +Sun Aug 3 17:27:44 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * Makefile.in (INSTALL): Build in $(srcdir). + + * config/linux.h (DEFAULT_VTABLE_THUNKS): New macro. + +Sun Aug 3 17:18:31 1997 Richard Earnshaw (rearnshaw@cambridge.arm.com) + + * expr.c (expand_builtin, case BUILT_IN_RETURN_ADDRESS): Emit warning + if return address cannot be determined. + +Sun Aug 3 17:04:00 1997 Bernd Schmidt + + * stupid.c (stupid_life_analysis): If function receives non-local + goto, don't let any registers live across calls. + + * fold-const.c (merge_ranges): Make sure that if one range is subset + of another, it will always be the second range. Correct (+,-) case to + account for this. + +Sun Aug 3 16:48:30 1997 Paul Eggert + + * c-lex.c (yylex): Remove duplicate check on high bit before + invoking int_fits_type_p. + +Sun Aug 3 16:44:41 1997 Bernd Schmidt + + * reload.c (find_equiv_reg): If goal is a pseudo that got memory, a + store into memory makes it invalid. This was handled in the single + set case, but missing in the PARALLEL case. + +Sun Aug 3 09:13:47 1997 Richard Kenner + + * expr.c (store_field): Return quickly if EXP is ERROR_MARK. + + * c-typeck.c (unary_complex_lvalue): Don't warn about COMPOUND_EXPR + or COND_EXPR if FUNCTION_TYPE. + + * alpha.h (ASM_SPEC): Add -O0. + + * expr.h (clear_storage): Now returns rtx. + (emit_block_move): Likewise; delete duplicate declaration. + * expr.c (clear_storage, emit_block_move): Return address of + dest if calling memset/memcpy. + (expand_builtin, BUILT_IN_MEM{CPY,SET}): Return value from + clear_storage or emit_block_move if present. + + * c-decl.c (start_function): Reset immediate_size_expand on + error return. + +Sat Aug 2 18:50:43 1997 Paul Eggert + + * tree.c (int_fits_type_p): Negative ints never fit unsigned + types, and unsigned ints with top-bit-set never fit signed types. + +Sat Aug 2 16:25:43 1997 Per Bothner + + * Makefile.in (EXTRA_C_OBJS): Removed. + (C_AND_OBJC_OBJS): New. Subsumes EXTRA_C_OBJS and OBJC_CCOMMON. + * objc/Make-lang.in (OBJC_CCOMMON): Removed. + +Sat Aug 2 16:11:57 1997 Doug Evans + + * configure.in: Build .gdbinit for top level build dir here. + (AC_OUTPUT): Pass oldstyle_subdirs to configure.lang. + * configure.lang: Fix building of .gdbinit for oldstyle lang subdirs. + +Sat Aug 2 13:48:15 1997 Ken Raeburn + + * cse.c (cse_insn): Ignore paradoxical SUBREGs unless we are + looking for such. + +Sat Aug 2 13:25:33 1997 Tristan Gingold (gingold@email.enst.fr) + + * calls.c (expand_call): If -fcheck-memory-usage, use pseudo-register, + check indirectly called function is executable, and set rights of + memory for aggregate as write only. + (store_one_arg): If -fcheck-memory-usage, set rights for pushed + stack argument. + * c-decl.c (init_decl_processing): Add + __builtin_aggregate_incoming_address. + * explow.c (expr_size): Call expand_expr with appropriate flag. + * expr.c (expand_builtin, case BUILT_IN_AGGREGATE_INCOMING_ADDRESS): + New case. + (expand_assignment, expand_expr, emit_push_insn, store_expr): + Insert calls to chkr_check_addr, chkr_set_right, and chkr_copy_bitmap + when -fcheck-memory-usage. + (get_push_address, get_memory_usage_from_modifier): New functions. + * expr.h: Add expand_modifier flags. + (chkr_*_libfunc): New decls. + (memory_use_mode): New declaration. + * flags.h (flag_check_memory_usage, flag_prefix_function_name): New + declaration. + * function.c (put_var_into_stack, assign_parms): If + -fcheck-memory-usage, set the rights of pushed variable. + * optabs.c (chkr_{check_addr,set_right}_libfunc): New definitions. + (chkr_{copy_bitmap,check_exec}_libfunc): Likewise. + (init_optabs): Initialize these chkr_*_libfunc. + * stmt.c (expand_computed_goto): If -fcheck-memory-usage, check that + computed address of a goto is executable. + (expand_asm, expand_asm_operands): If -fcheck-memory-usage, + disallow asm statments. + * toplev.c (flag_check_memory_usage, flag_prefix_function_name): New + variable. + (f_options): Add `check-memory-usage' and `prefix_function_name'. + (main): Disable `-fomit-frame-pointer' if `-fcheck-memory-usage' is set + and the machine can't debug without the frame pointer. + * tree.h (built_in_function): Add BUILT_IN_AGGREGATE_INCOMING_ADDRESS. + * varasm.c (make_function_rtl, make_decl_rtl): Add a prefix when + flag_prefix_function_name_usage is set. + (assemble_name): Strip the CHKR_PREFIX. + * alpha.c (alpha_builtin_saveregs): If -fcheck-memory-usage, + set rights of saved registers. + * clipper.c (clipper_builtin_saveregs): Likewise. + * m88k.c (m88k_builtin_saveregs): Likewise. + * pa.c (hppa_builtin_saveregs): Likewise. + * sparc.c (sparc_builtin_saveregs): Likewise. + +Sat Aug 2 08:01:12 1997 Richard Kenner + + * c-decl.c (grokdeclarator): Give error for `long double' and + refine text of some error messages. + + * alpha.h (FLOAT_VALUE_TYPE, INTIFY, FLOATIFY, FLOAT_ARG_TYPE): Define. + * i860.h (FLOAT_VALUE_TYPE): Fix typo; was FLOAT_TYPE_VALLUE. + + * calls.c (store_one_arg): Allow stack_slot to be SP in + ARGS_GROW_DOWNWARD case. + + * c-decl.c (parmlist_tags_warning): Only suppress warning on + union if anonymous. + + * libgcc2.c (_trampoline): Rework last change; both getpagesize + and mprotect are in cygwin32. + + * reload1.c (reload): Add IN_ADDR to IN_ADDR_ADDR when computing + needs since they conflict. + + * print-rtl.c (indent): Move to file level; was static in print_rtx. + (print_inline_rtx): New function. + * reload.c (debug_reload): Rework to make output more compact. + + * dwarfout.c (output_compile_unit_die): Add support for Pascal. + * dwarf2out.c (gen_compile_unit_die): Likewise. + + * c-typeck.c (lvalue_p, case BIND_EXPR, RTL_EXPR): Return 1 if array. + + * Makefile.in (OBJC_OBJC): Delete from here. + + * varasm.c (compare_constant_1, case STRING_CST): Compare TYPE_MODE. + (record_constant_1, case STRING_CST): Record TYPE_MODE. + + * tree.c (contains_this_placeholder_p): Delete. + (contains_placeholder_p): Now contains code from above function. + (contains_placeholder_p, case 'r'): Don't look at offset info. + * expr.c (expand_expr, case PLACEHOLDER_EXPR): Find innermost + matching and don't check contains_placeholder_p. + +Fri Aug 1 17:15:07 1997 Per Bothner + + * objc/objc-act.c (lang_init): Don't check_newline #if USE_CPPLIB. + * c-lex.c (lang_init): Remove (recently moved here). + * c-lang.c (lang_init): Restore, but add #if !USE_CPPLIB. + +Fri Aug 1 11:26:45 1997 Jeffrey A Law (law@cygnus.com) + + * pa.c (pa_reorg): Explode ADDR_DIFF_VEC insns too. + +Thu Jul 31 19:37:22 1997 Ian Lance Taylor + + * libgcc2.c (getpagesize): Don't compile if __CYGWIN32__. + +Thu Jul 31 16:04:42 1997 Stan Cox + + * i386.c (output_to_reg, output_fix_trunc): Use scratch memory, + if available, instead of dynamically extending the stack. + (put_condition_code, print_operand): Added reverse_cc to reverse the + comparison when $ah is accessed directly instead of using eflags + + * i386.md (*trunc*): Use scratch memory for output_fix_trunc. + (movsicc_1, movhicc_1) Change alternative 3 to: + jCC L1; mov; jmp L2; L1:mov; L2: + (movsfcc, movdfcc, movxfcc): Force constant operands to memory. + (movsfcc_1, movdfcc_1, movxfcc_1): Change alternative 3 as above. + +Thu Jul 31 16:04:42 1997 Jason Merrill + + * i386.h (MAX_FIXED_MODE_SIZE): Define. + +Thu Jul 31 16:04:42 1997 Robert Lipe + + * i386/sco5.h (SWITCHES_NEED_SPACES) Define. + Required by the COFF (but not ELF) linker. + +Wed Jul 30 15:03:52 1997 Per Bothner + + * demangle.h (DMGL_JAVA): New option to request Java demangling. + * cplus-dem.c: Various changes to produce Java output when passed + DMGL_JAVA. Thus "::" becomes "." and "JArray" becomes "Foo[]". + (main): Support --java and -j flags to set DMGL_JAVA. + +Wed Jul 30 08:56:08 1997 Philip Blundell + + * configure.in (arm-*-*): Replace with arm-*-aout. + * arm/aout.h (SET_ASM_OP): Define by default. + * arm/riscix.h (SET_ASM_OP: Undefine. + * arm.h (CPP_SPEC): Add %(subtarget_cpp_spec). + (SUBTARGET_CPP_SPEC): New macro. + * arm/linux.h: Include aout.h rather than arm.h directly. + (TARGET_CPU_DEFAULT): Define. + ({ASM,CPP}_SPEC): Remove. + * arm/t-linux (MULTILIB_OPTIONS): Use -mapcs-NN instead of -mN. + (LIB1ASMSRC): Use generic ARM version. + (CROSS_LIBGCC1): Define. + * arm/lib1funcs-linux.asm: Remove. + +Tue Jul 29 17:57:47 1997 Per Bothner + + * Add hooks for using autconf-style Makefile.in in language subdirs. + * configure.in (all_outputs, oldstyle_subdirs): New variables. + Pass all_outputs to AC_OUTPUT. + * configure.lang: Only iterate over oldstyle_subdirs. + + * Patches to use cpplib with cc1 #if USE_CPPLIB. + * configure.in (--enable-c-cpplib): New option. + (extra_c_flags, extra_c_objs): New variables. + * Makefile.in (EXTRA_C_OBJS): New variable. + (INTERNAL_CFLAGS): Add @extra_c_flags@. + (C_OBJS): Add $(EXTRA_C_OBJS). + * c-lex.c (generally): Replace getc and ungetc by macros GETC and + UNGETC. Avoid explicit references to finput. + (yy_get_token): New function, that calls cpp_get_token. + (init_parse): New function - calls init_lex. + (finish_parse): New function (called by compile_file). + (GET_DIRECTIVE_LINE): New macro wrapper replaces get_directive_line. + (lang_init): Don't check_newline - already know main_input_filename. + (handle_sysv_pragma): Remove FILE* parameter. + * toplev.c (finput): Remove #if USE_CPPLIB. + (compile_file): #if USE_CPPLIB don't open input file here, + do it in cpp_start_read. Call init_parse instead of init_lex. + At end, call finish_parse instead of fclose(finput). + +Mon Jul 28 15:48:29 1997 Brendan Kehoe + + * integrate.c (expand_inline_function): Use xmalloc instead of + alloca for the LABEL_MAP. + (save_for_inline_copying): Likewise. + +Mon Jul 28 11:22:16 1997 Jason Merrill + + * toplev.c (compile_file): Also emit any deferred TREE_PUBLIC inlines. + (rest_of_compilation): Use decl_printable_name instead of DECL_NAME + to identify functions in the RTL dump files. + + * dwarf2out.c (add_location_or_const_value_attribute): + leaf_renumber_regs_insn. Also eliminate_regs here. + (add_AT_location_description): Not here. Don't emit anything + for a variable that has been optimized away. + (add_const_value_attribute): Likewise. + + * dwarfout.c (location_or_const_value_attribute): + leaf_renumber_regs_insn. Also eliminate_regs here. + (location_attribute): Not here. + + * stor-layout.c (layout_type): Fix ancient code to match ancient + comment. Use mode of field for one-field structs. + +Sun Jul 27 12:09:02 1997 Richard Kenner + + * function.c (put_var_into_stack, trampoline_address): Treat + inline_function_decl like current_function_decl. + * expr.c (expand_expr, case LABEL_DECL): Likewise. + (expand_expr, case SAVE_EXPR): Handle top-level SAVE_EXPR by + moving into current function; abort if in incorrect context. + * fold-const.c (fold_range_test, fold): Avoid making SAVE_EXPR + if at top level. + + * dwarfout.c (ASM_OUTPUT_SOURCE_FILENAME): Delete default value. + + * alpha.h (TARGET_SWITCHES): Add -mno-byte. + + * expr.c (get_inner_unaligned_p): Deleted. + (expand_assignment): Remove special-case of constant array. + (expand_expr, case ARRAY_REF): Likewise, and clean up remaining code. + + * explow.c (probe_stack_range): Do probing with loop if more + than a small number. + +Fri Jul 25 15:42:34 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * configure.in: Finish fixing calculation if default thread + support is enabled. + +Fri Jul 25 15:30:09 1997 Doug Evans + + * Makefile.in (native): Depend on config.h. + (gcc.o): Depend on Makefile, not config.status. + +Fri Jul 25 10:56:50 1997 Jeffrey A Law (law@cygnus.com) + + * pa.c (pa_reorg): If TARGET_BIG_SWITCH, then do not explode + ADDR_VEC insns. Slightly rework code which explodes ADDR_VEC + insns. + * pa.h (TARGET_BIG_SWITCH): Define. + (TARGET_SWITCHES): Add "big-switch" and "no-big-switch". + (CASE_VECTOR_MODE): Use TI or DI depending on TARGET_BIG_SWITCH. + (CASE_DROPS_THROUGH): Remove definition. + (ASM_OUTPUT_ADDR_VEC_ELT): Rewrite to handle TARGET_BIG_SWITCH. + (ASM_OUTPUT_ADDR_DIFF_ELT): Likewise. + * pa.md (casesi): Rework to avoid some potential long branch + problems (also makes generated code faster!). Handle + TARGET_BIG_SWITCH. + (casesi0): Corresponding changes. + +Fri Jul 25 08:36:47 1997 Richard Kenner + + * calls.c: (expand_call): If -fstack-check and temp needed + for arg is too large, use alloca. + * expr.c (expand_expr, case MODIFY_EXPR): Don't preexpand calls + if LHS is an indirect via a constant pointer. + +Thu Jul 24 21:49:11 1997 Pat Rankin + + * bitmap.c (bitmap_operation): Reset CURRENT on deferred deletion. + +Wed Jul 23 23:52:14 1997 Chris Smith + + * convex.h (CHECK_FLOAT_VALUE): Fix OVERFLOW capitalization. + +Wed Jul 23 13:00:47 1997 Richard Earnshaw + + * configure.in (arm-*-netbsd*): Fix typo setting tmake_file. + +Wed Jul 23 06:39:35 1997 Richard Kenner + + * configure.in (alpha*): Put quotes around MASK_GAS. + +Tue Jul 22 15:24:45 1997 Brendan Kehoe + + * tree.c (array_type_nelts): Make sure the domain of TYPE is set + before we try to use it. + +Tue Jul 22 12:26:13 1997 Doug Evans + + * sparc.c (gen_v9_scc): Handle early clobber of result. + * sparc.md (seqdi_special): Don't clobber %xcc. + (snedi_special, seqdi_special_trunc, snedi_special_trunc): Likewise. + (snedi_zero, neg_snedi_zero, seqdi_zero, neg_seqdi_zero): Likewise. + (snedi_zero_trunc, seqdi_zero_trunc): Likewise. Renamed from ..._sp64. + (snedi_zero_trunc_sp32, seqdi_zero_trunc_sp32): Delete. + + * Makefile.in (Makefile): Pass xmake_file, tmake_file to + configure.frag + (distclean): Delete Make-host, Make-target. + * configure.in (host_overrides): Set to Make-host. + (dep_host_xmakefile): Loop over all elements in host_make_file. + (target_overrides): Set to Make-target. + (dep_tmake_file): Loop over all elements in tmake_file. + (configure.frag): Pass dep_host_xmake_file, dep_tmake_file. + * configure.frag: New arguments xmake_files, tmake_files. + Build Make-host, Make-target. + +Mon Jul 21 23:17:44 1997 Paul Eggert + + * objc/Make-lang.in, objc/Makefile.in: Comment out lines containing + just formfeeds. + +Mon Jul 21 14:05:46 1997 Doug Evans + + * Makefile.in (Makefile): Depend on config.status instead + of configure. + (config.status): Depend on configure. Run config.status --recheck + if out of date. + (cstamp-h.in): Use echo instead of touch. + + * reload1.c (reload_cse_mem_conflict_p): Restore handling of + (mem:BLK const0_rtx) meaning all memory is clobbered. + +Mon Jul 21 06:20:10 1997 Andreas Schwab + + * m68k.md (iorsi_zexthi_ashl16): Mark output operand as earlyclobber. + +Sun Jul 20 06:11:30 1997 Richard Kenner + + * configure.in (alpha*-*-*): Set cpu_type to alpha. + Change "alpha-" to "alpha*-" in all entries. + Set target_cpu_default for ev5 and ev56 systems. + Use symbolic names for target_cpu_default. + * alpha.c (override_options): Set default for alpha_cpu + from TARGET_CPU_DEFAULT. + * alpha.h (MASK_CPU_EV5): New macro. + + * tree.c (contains_placeholder_p): Call contains_this_placeholder_p. + (contains_this_placeholder_p): Renamed from contains_placeholder_p. + Added new arg, PL. + Rework to make more consistent, check more codes, and avoid + undefined fields. + * expr.c (expand_expr, case PLACEHOLDER_EXPR): Pick outermost + object in placeholder_list of right type without a PLACEHOLDER_EXPR. + +Sat Jul 19 18:00:01 1997 Richard Kenner + + * alpha.c (override_options): Allow processor of ev56 or 21164a. + (input_operand, case MEM): Correct test involving TARGET_BYTE_OPS. + * alpha.h (SECONDARY_{IN,OUT}PUT_RELOAD_CLASS): Don't need for + QImode or HImode if TARGET_BYTE_OPS. + (ASM_FILE_START): Write a .arch directive. + (STACK_CHECK_BUILTIN): New macro. + * alpha.md ({zero_,}extend[qh]i[dsh]i2): Rework TARGET_BYTE_OPS cases. + (mov[hq]i): Likewise. + (extend[qh]i[hsd]i2x): Add missing cases and fix typo in constraint. + (reload_{in,out}[qh]i): Disable for TARGET_BYTE_OPS. + +Fri Jul 18 23:24:57 1997 Jason Merrill + + * varasm.c (make_decl_rtl): Don't use ASM_FORMAT_PRIVATE_NAME for + local decls with TREE_PUBLIC set. + (bc_make_decl_rtl): Likewise. + +Fri Jul 18 22:16:28 1997 Doug Evans + + * configure.in: Invoke AC_CONFIG_HEADER. + Check for string.h, strings.h, stdlib.h, time.h, unistd.h. + Check for whether malloc/realloc/free need to be declared. + (links): Rename config.h to config2.h. + (AC_OUTPUT): Create cstamp-h. + * Makefile.in (config.in,cstamp-h.in): Add rules for. + (config.h,cstamp-h): Add rules for. + (distclean): Delete config2.h, cstamp-h. + (ALL_CFLAGS): Add @DEFS@. + * aclocal.m4, acconfig.h: New files. + + * Makefile.in (distclean): Delete Make-host, Make-target. + * configure.in (host_overrides): Set to host_xmake_file, don't create + Make-host. + (target_overrides): Set to tmake_file, don't create Make-target. + (language subdir support): Keep together. + + * c-decl.c (duplicate_decls): Set DECL_ABSTRACT_ORIGIN to olddecl + if inline function and not new definition. + + * configure.in: Don't loop trying to configure language subdirs. + Don't pass to configure.lang variables it doesn't use. + * configure.lang: Delete top level directory from loop. + Delete code not useful for language subdirs. + +Fri Jul 18 08:12:53 1997 Bernd Schmidt + + * toplev.c (rest_of_compilation): Call reload_cse_regs here. + * reload1.c (reload): Don't call it here. + (reload_cse_mem_conflict_p): Remove MEM_OFFSET and MEM_MODE args. + (reload_cse_mem_conflict_p, case MEM): Call anti_dependence. + (reload_cse_invalidate_mem): Update call to reload_cse_mem_conflict_p. + (reload_cse_regs): No longer static. + Call init_alias_analysis. + Ignore CLOBBER in a PARALLEL. + +Fri Jul 18 06:44:22 1997 Andreas Schwab + + * objc/Make-lang.in (objc-headers): Fix command for the new build + directory layout, don't pass srcdir variable. + * objc/Makefile.in (copy-headers): Use $(srcdir) from this + makefile, not the parent's. + +Thu Jul 17 16:03:03 1997 Doug Evans + + * configure.lang (EXTRA_HEADERS,EXTRA_PASSES,EXTRA_PARTS): Delete. + (EXTRA_PROGRAMS,EXTRA_OBJS,EXTRA_GCC_OBJS,MD_DEPS): Delete. + (version) Delete duplicate entry. + * configure.in (merged_frags): Delete unused variable. + (extra_headers_list): Move setting outside of subdir loop. + (extra_headers,extra_passes): Don't pass to configure.lang. + (extra_programs,extra_parts,extra_objs): Likewise. + (host_extra_gcc_objs,gxx_include_dir,md_cppflags): Likewise. + +Thu Jul 17 07:00:43 1997 Richard Kenner + + * expr.h (STACK_CHECK_*): Provide default values. + (probe_stack_range): New declaration. + * flags.h (flag_stack_check): Likewise. + * explow.c (allocate_dynamic_stack_space): Call probe_stack_range. + (emit_stack_probe, probe_stack_range): New functions. + * function.c (expand_function_end): If function is non-leaf and stack + checking is requested, emit needed probes. + * reload1.c (reload): If checking stack, verify frame small enough. + * stmt.c (expand_decl): If stack checking, use alloca for large vars. + * toplev.c (flag_stack_check): New variable. + (f_options): Add "stack-check". + + * reorg.c (mark_target_live_regs): Pass FIRST_PSEUDO_REGISTER to + call to EXECUTE_IF_SET_IN_REG_SET. + +Wed Jul 16 14:51:00 1997 Jason Merrill + + * i960.h (ASM_OUTPUT_ALIGNED_BSS): Define. + (ASM_OUTPUT_ALIGNED_LOCAL): Use standard method to convert ALIGN + to power-of-two of bytes. + + * sparc.h (ASM_OUTPUT_ALIGNED_BSS): Define. + * sparc/sysv4.h (ASM_OUTPUT_ALIGNED_BSS): Undef before definition. + +Wed Jul 16 14:34:09 1997 Klaus Espenlaub (kespenla@hydra.informatik.uni-ulm.de) + + * calls.c (emit_library_call_value): Initialize all argvec elements. + +Wed Jul 16 14:31:39 1997 Richard Kenner + + * global.c (global_conflicts): Pass FIRST_PSEUDO_REGISTER to + call to EXECUTE_IF_SET_IN_REG_SET. + +Wed Jul 16 10:57:03 1997 Richard Earnshaw (rearnsha@cambridge.arm.com) + + * From Rob Black (r.black@ic.ac.uk) and Mark Brinicombe + (amb@physig.ph.kcl.ac.uk): + * configure.in (arm-*-netbsd*): New configuration. + * arm/netbsd.h, arm/t-netbsd, arm/xm-netbsd.h: New files. + +Wed Jul 16 10:57:03 1997 Richard Earnshaw (rearnsha@cambridge.arm.com) + + * arm.c (tune_flags): New variable. + (target_{cpu,fpe}_name): Delete. + (arm_fpu_arch): New variable. + (arm_select): Also allow -march=... to configure just the + architecture. + (all_procs): Allow armv{2,2a,3,3m,4,4t} for use with -march=. + (arm_override_options): Handle -march=, but don't let -mcpu= + and -mtune= match the architecture names, since we can only + tune for an implementation. Rework selection of tuning options + for floating point. + (use_return_insn): Support interworking with Thumb code. + (arm_rtx_costs): Rework multiply costs so that cost is based on + the tune, not the architecture. + (f_register_operand): New function. + (output_return_instruction): Support interworking with Thumb code. + (output_func_epilogue): Support interworking with Thumb code. + Remove redundant calculation of code_size. Use floating-point + load-multiples if permitted. + (emit_sfm): New function. + (arm_expand_prologue): Use floating-point store-multiples if + permitted. + + * arm.h (CPP_CPU_ARCH_SPEC): Handle -march=... + (TARGET_OPTIONS): Add arch= and fp=. Delete fpe=. + (enum processor_type): Add PROCESSOR_NONE, for use in all_procs table. + (FP_DEFAULT): Default floating point architecture for generic + back-end. + (PREDICATE_CODES): Add f_register_operand. + + * arm.md (*push_fp_multi): New pattern. + + +Tue Jul 15 22:08:47 1997 Jim Wilson + + * Makefile.in (exeext): Set to build_exeext not exeext. + * configure.in (exeext): Delete redundant set and AC_SUBST call. + Change remaining AC_SUBST to use build_exeext instead of exeext. + +Tue Jul 15 15:48:25 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * configure.in: Fix calculation if default thread support is enabled. + +Tue Jul 15 13:38:46 1997 Mike Meissner + + * rtl.h (replace_regs): Declare. + +Mon Jul 14 16:18:19 1997 Jason Merrill + + * i960.h (ASM_OUTPUT_MI_THUNK): Define. + + * dwarf2out.c (gen_subprogram_die): Remove unreachable and redundant + code. + +Mon Jul 14 14:22:45 1997 Jeffrey A Law (law@cygnus.com) + + * calls.c (emit_library_call): Use right index into argvec array + when iterating over arguments which need to be pushed on the stack. + (emit_library_call_value): Likewise. + +Mon Jul 14 08:17:41 1997 Richard Kenner + + * gcc.c (convert_filename): Fix typo. + +Mon Jul 14 08:10:12 1997 Andreas Schwab + + * configure.in: Clear headers and lib2funcs before re-reading + config-lang.in. + + * m68k/linux.h (LINK_SPEC): Fix last change. + +Mon Jul 14 08:03:38 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * configure.in (sparc-*-linux-gnu{*,libc1*}): Add sparc/t-linux. + * sparc/t-linux: New file. + + * alpha/elf.h (LINK_SPEC): Fix typo. + * configure.in (alpha-*-linux-gnu*): Set tmake_file. + * alpha/t-linux: New file. + +Mon Jul 14 07:41:37 1997 Philippe De Muyter + + * m68k.c (output_{and,ior,xor}si3): New functions from patterns bodies. + * m68k.h (output_{and,ior,xor}si3): New extern declarations. + * m68k.md (adddi3, subdi3): Allow constant operand. + (anddi3, iordi3, xordi3): New patterns. + ({and,ior,xor}si3_internal): Use corresponding output_???si3 function. + +Mon Jul 14 07:33:11 1997 Fila Kolodny + + * configure.in (*-*-gnu*): Add crt{begin,end}S.o to extra_parts. + +Mon Jul 14 07:26:36 1997 Craig Burley + + * varasm.c (assemble_variable): If low part of size + doesn't fit in an int, variable is too large. + +Mon Jul 14 06:51:37 1997 Mike Meissner + + * bitmap.{h,c}: New files. + * Makefile.in (OBJS): Add bitmap.o. + (BASIC_BLOCK_H): New make variable for basic-block.h, bitmap.h. + ({flow,combine,regclass,local-alloc,reload1,reorg,sched}.o): Use + BASIC_BLOCK_H variable instead of basic-block.h. + * basic-block.h (*REG_SET): Delete old implementation; use bitmap.h. + (regset_{size,bytes}): Delete. + (regs_live_at_setjmp): Declare. + (EXECUTE_IF_SET_AND_RESET_IN_REG_SET): Delete. + * flow.c (init_regset_vector): Make global; don't take basic block + times # of pseduos as argument. + (life_analysis): Change all init_regset_vector calls. + Use free_regset_vector to release arrays only flow uses at end. + (allocate_for_life_analysis): Change init_regset_vector call. + Don't set regset_{size,bytes}. + (free_regset_vector): Call FREE_REG_SET to release any + memory allocated by each vector. + (propagate_block): Call FREE_REG_SET on dead/live. + (mark_used_regs): Don't use REGSET_ELT_TYPE anymore. + * output.h (allocate_for_life_analysis): Add declaration. + (regno_uninitialized, regno_clobbered_at_setjmp): Likewise. + (dump_flow_info, flow_analysis): Likewise. + * regclass.c (init_reg_sets): Invoke INIT_ONCE_REG_SET. + (allocate_reg_info): Invoke MAX_REGNO_REG_SET. + (regset_release_memory): Free basic_block_live_at_start storage. + * reorg.c (mark_target_live_regs): Delete unused variables. + * sched.c (schedule_block): Free space associated with + reg_pending_sets and old_live_regs. + (schedule_insns): Free bb_{dead,live}_regs on first pass. + (sched_analyze_insn): Use EXECUTE_IF_SET_IN_REG_SET and then clear. + * toplev.c (rest_of_compilation): Call regset_release_memory. + +Mon Jul 14 00:14:13 1997 Jason Merrill + + * toplev.c (main): Prefer DWARF 2 or stabs with -ggdb. + * ns32k/tek6000.h (PREFERRED_DEBUGGING_TYPE): DBX_DEBUG. + * alpha.h (PREFERRED_DEBUGGING_TYPE): SDB_DEBUG. + * mips.h (PREFERRED_DEBUGGING_TYPE): SDB_DEBUG. + +Sun Jul 13 15:11:08 1997 Richard Kenner + + * stupid.c (stupid_mark_refs): If setting reg set only in this + insn and not referenced, make REG_UNUSED note. + +Sun Jul 13 14:03:19 1997 Michael Meissner + + * gcc.c (process_command): If -save-temps and -pipe were specified + together, don't do -pipe. + +Sun Jul 13 12:27:03 1997 Doug Evans + + * gcc.c (main): Handle blank in version_string when comparing + with compiler_version. + +Sat Jul 12 01:53:55 1997 Jason Merrill + + * sparc.c (output_function_prologue): Fix offset from CFA. + (sparc_flat_output_function_prologue): Likewise. + +Fri Jul 11 09:49:15 1997 Jeffrey A Law (law@cygnus.com) + + * mips.c (epilogue_reg_mentioned_p): Delete unused function. + (mips_epilogue_delay_slots): Likewise. + (function_epilogue): Greatly simplify. + (mips_expand_epilogue): If we have a null prologue/epilogue, + then use a normal return insn. Emit blockage insns before + stack pointer adjustments. + (mips_can_use_return_insn): Renamed from simple_epilogue_p. All + callers changed. Do not use return insns if $31 is live in the + function or if generating profiling information. + * mips.h (DELAY_SLOTS_FOR_EPILOGUE): Delete. + (ELIGIBLE_FOR_EPILOGUE_DELAY): Likewise. + * mips.md (return): Remove expander and change the pattern to + look like a standard "return" insn. + (return_internal): Show use of $31 explictly. + (epilogue expander): Enable. + +Thu Jul 10 13:04:53 1997 Doug Evans + + * cccp.c (INO_T_EQ): Return 0 for MSDOS. + + * Makefile.in (CC): Use autoconf value. + +Tue Jul 8 18:08:00 1997 Jim Wilson + + * dwarf2out.c (gen_subprogram_die): When handling declarations, test + DECL_CONTEXT not decl_class_context before equate_decl_number_to_die. + +Tue Jul 8 16:47:13 1997 Michael Meissner + + * rs6000.md (movsi define_split): Use unsigned HOST_WIDE_INT, + not unsigned. + +Sat Jul 7 00:01:41 1997 Jim Meyering + + * i386/t-sol2 (crt[1in].o): Also depend on $(GCC_PASSES). + +Fri Jul 4 11:45:39 1997 Jason Merrill + + * dwarf2out.c (DWARF_CIE_HEADER_SIZE, DWARF_FDE_HEADER_SIZE, + size_of_cfi, size_of_fde, calc_fde_sizes, next_fde_offset, + cie_size): Lose. + (ASM_OUTPUT_DWARF_STRING): Move earlier. + (INCOMING_FRAME_SP_OFFSET): Provide default. + (initial_return_save): Adjust for CFA offset. + (dwarf2out_frame_debug): Lookup initial CFA offset when setting up. + (output_call_frame_info): Use label subtraction for length fields. + Add pointer to exception region information in for_eh case. + (dwarf2out_do_frame): New fn. + (dwarf2out_frame_init): Use INCOMING_FRAME_SP_OFFSET. + (dwarf2out_frame_finish): Don't bother emitting .debug_frame for + non-Irix targets. Just emit .eh_frame. + (output_die): Refer to an FDE with label subtraction. + * i386.h (INCOMING_FRAME_SP_OFFSET): Define. + * defaults.h (DWARF2_UNWIND_INFO): Define if + INCOMING_RETURN_ADDR_RTX is provided. + * final.c (final): Don't call dwarf2out_frame_debug unless we are + doing dwarf 2. + +Thu Jul 3 17:37:52 1997 Jim Wilson + + * fp-bit.c (unpack_d): Check fraction not sign to distinquish QNaN. + +Wed Jul 2 09:48:03 1997 Michael Meissner + + * loop.c (strength_reduce): Make sure register does not exceed the + table size when looking up the last UID. + +Wed Jul 2 07:47:44 1997 Nick Burrett + + * genoutput.c (process_template): Place increment expression + outside of putchar function call. + +Wed Jul 2 06:56:52 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * sparc/linux.h (LIBGCC_SPEC): Removed. + (CC1_SPEC): Add %{profile:-p}. + ({CPP,LIB,LINK}_SPEC): Choose glibc 1 or 2 depending on USE_GNULIBC_1. + * configure.in (sparc-*-linux-gnulibc1*): New configuration. + + * configure.in (powerpc-*-linuxgnu*): Default thread_file is posix. + Set xmake_file to x-linux. Add extra_parts. + * rs6000/linux.h (LINK_SPEC): Defined. + + * m68k/linux.h (LINK_SPEC): Pass -shared for -shared. + ({CPP,LINK}_SPEC): Choose for glibc 1 or 2 depending on USE_GNULIBC_1. + * configure.in (m68k-*-linux-gnu*): Default thread_file is `posix'. + (m68k-*-linux-gnulibc1): New configuration. + + * alpha/elf.h (LINK_SPEC): Change ld-gnu.so.1 to ld-linux.so.2. + * configure.in (alpha-*-linux-gnu*): Default thread_file is `posix'. + +Wed Jul 2 06:12:37 1997 Richard Kenner + + * alpha.md (divsi3, modsi3, udivsi3): Comment out. + (extendsfsd2_no_tp): Add alternative with output in MEM, input in REG. + + * configure.in (*-linux*): Add "-gnu" to names to match. + + * libgcc2.c (_trampoline): Add stdcall attribute to VirtualProtect + on i386. + + * objc/objc.gperf: Renamed from gperf. + +Wed Jul 2 05:42:19 1997 Andreas Schwab + + * objc/Make-lang.in ($(srcdir)/objc/objc-parse.c): Fix command + to use the right file names. + +Tue Jul 1 23:25:42 1997 Richard Kenner + + * reorg.c (redundant_insn): If INSN or possible match has REG_UNUSED + note, don't have match. + +Tue Jul 1 18:36:24 1997 Doug Evans + + * mips.c (mips_output_external): Don't output .extern's for + variables in user specified sections unless they're .sbss/.sdata. + +Tue Jul 1 18:30:26 1997 Jim Wilson + + * cse.c (find_best_addr): Add missing rtx_cost arguments. + + * fp-bit.c (float_to_usi): Move code for negative numbers before code + for infinity. Modify infinty code to only handle positive infinities. + +Tue Jul 1 11:16:41 1997 Robert Lipe + + * fixinc.sco: Restore pwd after copy. + Convert declaration of abs in math.h to prototype. + Fix static functions in sys/stat.h for C++. + +Tue Jul 1 10:55:47 1997 Michael Meissner + + * rs6000.md ({add,ior,xor}si3): Change to use define_expand wrapper + and split add/ior/xor of large constants early. + (andsi3): Remove 6/29 code to do and of large constants. + (nor, nand, eqv, maskir): Add names to all logical define_insns. + +Tue Jul 1 09:03:35 1997 Jeffrey A Law (law@cygnus.com) + + * h8300.h (BIGGEST_FIELD_ALIGNMENT): Remove definition. + * mips.h (BIGGEST_FIELD_ALIGNMENT): Likewise. + +Mon Jun 30 14:58:00 1997 Jeffrey A Law (law@cygnus.com) + + * sh.c (sh_expand_epilogue): Emit blockage insn before cutting + back stack. + +Sun Jun 29 11:27:07 1997 Michael Meissner + + * rs6000.h (TARGET_FLAGS): Add -m{,no-}update to suppress + creating load/store with update instructions, and also + -m{,no-}fused-madd to suppress the generation of fused add and + multiply instructions. Move debug flags to TARGET_OPTIONS. + (GO_IF_LEGITIMATE_ADDRESS): Don't allow PRE_{INC,DEC} if -mno-update. + (GO_IF_MODE_DEPENDENT_ADDRESS): Ditto. + (rs6000_debug_{name,stack,arg}): Add declarations. + (toc_initialized): Likewise. + (got_no_const_operand): Likewise. + (PREDICATE_CODES): Add got_no_const_operand. + (toc_section): Make toc_initialized a global. + (RTX_COSTS): Set appropriate costs for add, logical operators that + are really two instructions. + + * rs6000.c (rs6000_debug_{name,stack,arg}): Add definitions. + (rs6000_override_options): Process debug flags. + (toc_initialized): Global to say toc initialized. + (small_data_operand): Use #if TARGET_ELF, not #ifdef TARGET_SDATA. + (rs6000_init_expanders): Likewise. + (SMALL_DATA_RELOC): Likewise. + (got_no_const_operand): Recognize SYMBOL_REF and LABEL_REF. + (rs6000_makes_calls): System V profiling doesn't count as a call. + (rs6000_stack_info): Likewise. + (rs6000_output_load_toc_table): Take register number argument to + determine register to load. Generate correct code if more than + one toc table is done in System V due to profiling or non-local + gotos. If System V toc is not initialized, initialize it now. + (rs6000_allocate_stack_space): Move code from output_prolog to + allocate stack space. Take -mno-update into account. + (output_prolog): Call rs6000_allocate_stack_space. Only set + rs6000_pic_func_labelno if not profiling. + (output_function_profiler): Implement System V profiling. + (and_operand): Don't call reg_or_short_operand. + (rs6000_finalize_pic): If not optimizing, insert a USE of the GOT + register as the last insn. + + * rs6000.md (load/store update): Take -mno-update into account. + If -msoft-float, support SF load/store with update to GPR regs. + (allocate_stack): Take -mno-update into account. + (add/subtract + multiply instructions): Take -mno-fused-madd into + account. + (nonlocal_goto_receiver): Specify register # to load. + ({add,and,ior,xor}si3): Recognize operation done with full 32 bit + constant, splitting latter if need be. + (andsi3 define_split): Fix up splitting andsi3 of large constant. + ({ior,xor}si3 define_split): Use GEN_INT to create integer rtx + values. + (movsi_got{,_internal}): Split the load of a CONST into load of + the SYMBOL_REF/LABEL_REF and an add. + (movsi): Know that addsi3 can handle large values now for NT. + + * sysv4.h (TARGET_SDATA): Remove explicit bit for -msdata. + (SUBTARGET_OVERRIDE_OPTIONS): Likewise. + (ASM_OUTPUT_ALIGNED_LOCAL): Likewise. + (SUBTARGET_SWITCHES): Indicate -m{,no-}sdata doesn't set any flags. + (ASM_SPEC): Only pass -m{,no-}reg-names if assembling .s/.S files. + (CC1_SPEC): If -msdata, invoke compiler with -msdata=default. + (PROFILE_BEFORE_PROLOGUE): Likewise. + (RS6000_MCOUNT): Define as "_mcount". + (toc_section): Make toc_initialized a global. + +Fri Jun 27 19:01:11 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * config/t-linux-gnulibc1: New file. + * configure.in (i[3456]86-*-linux*): Default thread_file is `posix'. + (i[3456]86-*-linux*gnulibc1): New case. + * config/linux.h (LIB_SPEC): Choose for glibc 1 or 2 depending + on USE_GNULIBC_1. + * i386/linux.h (CPP_SPEC, LINK_SPEC): Likewise. + +Fri Jun 27 19:00:52 1997 Ralf Baechle + + * config/linux.h (PREFERRED_DEBUGGING_TYPE): Undefine before define. + +Fri Jun 27 18:35:04 1997 Alan Modra + + * configure.in: Clean up Make-{host,target,hooks} in all + subdirs, not just '.'. + * Makefile.in (distclean): Delete */Make-{host,target,lang,hooks}. + +Fri Jun 27 18:27:11 1997 Fila Kolodny + + * config/xm-gnu.h (fcntl.h): Only include if not building libgcc.a. + +Fri Jun 27 18:17:44 1997 Doug Evans + + * configure.frag: Rewrite. + + * objc/Make-lang.in (OBJC_CCOMMON): Object files don't go in srcdir. + (OBJC_OBJS): Likewise. + (OBJC_O): Likewise. + (objc-parse.o, objc-act.o): Fix rules. + (objc/libobjc files): Fix rules. + +Fri Jun 27 13:23:38 1997 Andrew Cagney + + * fp-bit.c (float_to_si): Correct return value when Inf. + +Fri Jun 27 10:47:09 1997 Scott Christley + + * Makefile.in (DLLTOOL): Define. + * objc/Make-lang.in (libobjc_entry.o, libobjc_s.a, libobjc.dll): + New targets. + (objc.install-normal): Install Objective-C runtime as a DLL. + (objc.mostlyclean): Clean up files used to build DLL. + * objc/libobjc.def: New file. + * objc/libobjc_entry.c: New file. + + * objc/sendmsg.c (search_for_method_in_list): No longer static. + + * Makefile.in (GCC_THREAD_FILE): Renamed from OBJC_THREAD_FILE. + * configure.lang (GCC_THREAD_FILE): Likewise. + * configure.in (--enable-threads): New parameter. + * objc/Make-lang.in (OBJC_THREAD_FILE): New definition.e + * objc/config-lang.in: Print message about ObjC thread file. + + * cccp.c (INO_T_EQ): Define for Win32 but not Cygwin32. + * i386/mingw32.h: New file. + * i386/xm-mingw32.h: New file. + * configure.in (i[3456]86-*-mingw32): New target. + * protoize.c (link): Eliminate definition on Win32. + + * objc/thr-posix.c (__objc_thread_yield): Use sched_yield instead. + +Fri Jun 27 10:36:41 1997 J"orn Rennecke + + * stor-layout.c (layout_record, PCC_BITFIELD_TYPE_MATTERS): + Round up when calculating possible end address. + +Wed Jun 25 19:54:29 1997 Jim Wilson + + * unroll.c (final_giv_value): Verify that bl->initial_value is + invariant before trying to use it. + +Wed Jun 25 18:13:05 1997 Michael Meissner + + * rs6000/sysv4.h (WCHAR_TYPE{,_SIZE}): Make wchar_t long as per + ABI spec. + +Wed Jun 25 16:56:16 1997 Jason Merrill + + * sparc.h (INCOMING_RETURN_ADDR_RTX): Define. + (DBX_REGISTER_NUMBER): Fix frame pointer regno for -mflat. + * sol2.h (DBX_REGISTER_NUMBER): Likewise. + * sparc.c (save_regs): Emit dwarf2 frame debug info. + (output_function_prologue, sparc_flat_save_restore, + sparc_flat_output_function_prologue): Likewise. + + * dwarf2.h (enum dwarf_call_frame_info): Add DW_CFA_GNU_window_save. + * dwarf2out.c (dwarf_cfi_name, output_cfi): Support it. + (dwarf2out_cfi_label): Make non-static. + (initial_return_save): Support PLUS. + (dwarf2out_window_save, dwarf2out_return_save, + dwarf2out_return_reg): New fns. + + * dwarf2out.c (SECTION_FORMAT): Use PUSHSECTION_FORMAT, if defined. + (DEBUG_INFO_SECTION): Rename from DEBUG_SECTION. + (DEBUG_LINE_SECTION): Rename from LINE_SECTION. + * mips/iris6.h: Likewise. + +Wed Jun 25 16:25:41 1997 Scott Christley + + * Makefile.in (GCC_PASSES): Don't define with $(exeext). + * configure.in ({cc,stage_prefix}_set_by_configure): Eliminate extra + comma and don't pass value to configure.lang. + * objc/Make-lang.in (objc-runtime): Add objc-headers. + + * configure.in: Execute configure.frag in a shell. + + * configure.in (cross_overrides, build_overrides): Default to + /dev/null to help platforms where sed cannot handle empty filenames. + + * Reorganize thread implementation to make a clearly defined + front-end/back-end interface. + * objc/thr-{decosf1,irix,mach,os2,posix,pthreads,single}.c: Completely + rework according to new interface. + * objc/thr-{solaris,win32}.c: Likewise. + * objc/thr.c: Likewise. + * objc/thr.h: Define front-end/back-end interface functions and + structures. + +Wed Jun 25 16:14:10 1997 Ovidiu Predescu + + * Complete implementation of +load. + * objc/init.c (objc_send_load): New function. + (objc_class_tree): New structure. + (create_tree_of_subclasses_inherited_from): New function. + (__objc_tree_insert_class): New function. + (objc_tree_insert_class): New function. + (objc_preorder_traverse): New function. + (objc_postorder_traverse): New function. + (__objc_tree_print): New function. + (__objc_destroy_class_tree_node): New function. + (class_is_subclass_of_class): New function. + (__objc_exec_class): Allocate class tree list and load hash table. + (__objc_send_message_in_list): Rewrite using hash table. + (__objc_send_load): Remove calls to _objc_load_callback. + (objc_send_load): Make static. Create Tree of classes resembling + class hierarchy for all modules. Call __objc_send_load on all of + the modules in __objc_module_list. + (__objc_create_classes_tree): New function. + + * objc/encoding.h (method_get_sizeof_arguments): Fix typo. + * objc/objc-api.h (OBJC_ERR_BAD_STATE): New error code. + On NeXT redefine object_copy and object_dispose to avoid + a conflict with those defined in system library. + * objc/selector.c (__objc_register_instance_methods_to_class): New + function. + * objc/runtime.h: Likewise. Add missing function prototypes. + +Wed Jun 25 15:09:01 1997 Richard Kenner + + * Makefile.in (Makefile): Execute configure.frag from srcdir. + + * Makefile.in (configure): Target is $(srcdir)/configure. + +Tue Jun 24 15:18:14 1997 Jim Wilson + + * m68k.h (LIMIT_RELOAD_CLASS): Define. + + * recog.c (constrain_operands): When checking earlyclobbers, use + operands_match_p instead of rtx_equal_p. + + * dwarfout.c (field_byte_offset): Check for object_offset_in_bits + greater than bitpos_int and recompute object_offset_in_bytes if true. + + * mips.md (movdi_internal): Add x/J alternative. + (movdi_internal2): Add x/J alternative; change a/I to a/J. + (movsi_internal1, movsi_internal2): Change x/I alternative to x/J. + +Tue Jun 24 08:49:56 1997 Jeffrey A Law (law@cygnus.com) + + * pa.h (ASM_OUTPUT_SECTION_NAME): Fix typo. + +Mon Jun 23 22:48:00 1997 Jim Wilson + + * unroll.c (find_splittable_givs): Set splittable_regs_updates to + biv_count for reduced givs. + +Mon Jun 23 10:51:53 1997 Jeffrey A Law (law@cygnus.com) + + * mn10200.c, mn10200.h, mn10200.md: New files for mn10200 port. + * lib1funcs.asm, divmod.c, udivmod.c, udivmodsi4.c: Likewise. + * t-mn10200, xm-mn10200.h, va-mn10200.h: Likewise. + * Makefile.in (USER_H): Add va-mn10200.h. + * varargs.h, stdarg.h: Include va-mn10200.h. + * configure.in (mn10200-*-*): New target. + +Sun Jun 22 06:47:19 1997 Andreas Schwab + + * combine.c (force_to_mode): Don't do anything for ASM_OPERANDS insn. + +Sun Jun 22 06:29:28 1997 J. Kean Johnston + + * ginclude/stdarg.h: Protect va_list definition from SCO headers. + * ginclude/varargs.h: Likewise. + +Sat Jun 21 20:56:23 1997 Scott Christley + + * Make ObjC a front-end language. + * Makefile.in (LANGUAGES, COMPILERS, .PHONY, stmp-int-hdrs): Remove + specific references to ObjC compiler and source files. + ({mostly,dist,maintainer,}clean, install-normal): Likewise + (OBJC_OBJS, OBJC, OBJECTIVE-C, cc1obj, objc-runtime): Rules deleted. + (libobjc.a, sublibobjc.a, objc-parse.{o, c, y}): Rules deleted. + (objc-headers, install-libobjc): Rules deleted. + * objc/Make-lang.in: New file; from rules deleted above. + * objc/config-lang.in: New file. + * objc/Makefile.in: Changes to support ObjC as a front-end language; + renamed from Makefile.in. + * objc-act.{c,h}, objc-parse.{c,y}, objc-tree.def: Moved to objc dir. + +Sat Jun 21 07:54:36 1997 Robert Lipe + + * fixinc.sco (math.h): Correct the collision of "exception". + +Sat Jun 21 06:51:40 1997 Peter Gerwinski + + * rs6000.c (output_epilog): Name is "GNU Pascal", not all caps. + +Sat Jun 21 06:29:19 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * gcc.c (main): Check for and read ${libdir}/gcc-lib/specs to + override the default specs. + +Fri Jun 20 17:20:15 1997 Jim Wilson + + * mips.c (output_block_move): When loading addresses into registers, + add checks for ABI_N32 and ABI_64. + (mips_expand_prologue): Add check for SImode in code splitting + tsize_rtx when it is large_int. + +Fri Jun 20 09:07:31 1997 Russell King + + * configure.in (arm-*-linuxaout): New target. + * arm/lib1funcs-linux.asm, arm/linux-gas.h: New files. + * arm/linux.h, arm/t-linux, arm/xm-linux.h: New file. + * xm-linux.h: Undef some macros before defining them. + +Thu Jun 19 21:18:20 1997 Jim Wilson + + * dwarf2out.c (output_line_info): Always use DW_LNE_set_address instead + of DW_LNS_fixed_advance_pc for line number addresses. + (size_of_line_info): Adjust size calculation as per above change. + (text_end_label): Make it static. + +Thu Jun 19 14:55:49 1997 Brendan Kehoe + + * toplev.c (xmalloc): Only give the fatal msg if SIZE is non-zero. + +Sun Apr 27 23:19:13 1997 Ulrich Drepper + + * libgcc2.c (__eh_type): Remove `extern' to make this a definition. + +Wed Jun 18 18:10:16 1997 Per Bothner + + * dbxout.c (dbxout_type_fields): Skip field if DECL_IGNORED_P. + +Wed Jun 18 18:04:33 1997 Mike Stump + + * except.c (end_eh_unwinder): If we have a return instruction, we + have to make sure we use it and don't fall off the end of the + function in the unwinder. + +Wed Jun 18 14:27:58 1997 Mike Stump + + * flow.c (find_basic_blocks): Fix end case bug. + +Tue Jun 17 18:35:57 1997 Mike Stump + + * libgcc2.c (__eh_pcnthrow): Add support -fno-sjlj-exceptions + -fPIC exception handling on the SPARC. + * sparc.h (DONT_ACCESS_GBLS_AFTER_EPILOGUE): Likewise. + * libgcc2.c (__eh_ffetmnpc): Remove. + +Mon Jun 16 20:28:51 1997 Jason Merrill + + * collect2.c (extract_string): Null-terminate. + +Mon Jun 16 14:38:44 1997 Michael Meissner + + * combine.c (set_nonzero_bits_and_sign_copies): Use REG_SET macros + instead of doing bit operations directly. + (try_combine,reg_dead_at_p): Ditto. + * caller-save.c (save_call_clobbered_regs): Ditto. + * reload1.c (reload): Ditto. + * local-alloc.c (update_equiv_regs,block_alloc): Ditto. + * sched.c (schedule_block): Dito. + +Sun Jun 15 20:46:12 1997 Jim Wilson + + * dwarf2out.c (dwarf2out_frame_debug): Handle IOR. + (struct limbo_die_struct): Define. + (TYPE_DECL_IS_STUB): Call decl_ultimate_origin if DECL_ABTRACT_ORIGIN + is set. + (limbo_die_count): Delete. + (libmo_die_list): Define. + (new_die): Add die to limbo_die_list instead of incrementing + limbo_die_count. + (add_AT_location_description): Renamed from add_location_attribute. + New parameter attr_kind. + (add_location_or_const_value_attribute, gen_subprogram_die, + add_bound_info): Change call to add_AT_location_description. + (add_bound_info): Add call to contains_placeholder_p. Ignore + MAX_EXPR and VAR_DECL. + (add_subscript_info): Ignore the index type if it is an unnamed + integral type. + (scope_die_for): Move check for function-local tags after code setting + containing_scope, and add check for non-NULL containing_scope + (add_type_attribute): If unnamed type, use TREE_TYPE instead. + (gen_enumeration_type_die, gen_struct_or_union_type_die): Call + add_child_die if die_parent is NULL. + (gen_subprogram_die): Ifdef out DW_AT_static_link code. + (decls_for_scope): Delete decrement of limbo_die_count. + (dwarf2out_finish): Add code to traverse the limbo_die_list, and + call add_child_die if die_parent is NULL. Delete limbo_die_count code. + * mips.c (mips_expand_prologue): If tsize_rtx is large_int, emit two + insns instead of one splitable insn, setting RTX_FRAME_RELATED_P. + +Fri Jun 13 19:33:35 1997 Brendan Kehoe + + * fixincludes: Also fix AIX NULL macro in sys/{dir,param,types}.h. + +Thu Jun 12 22:53:12 1997 Jim Wilson + + * m68k.md (mov[qhs]i): Remove pair of constraints which allow + offsetable memory addresses to be moved to the same for TARGET_5200. + +Thu Jun 12 15:33:01 1997 Jeffrey A Law (law@cygnus.com) + + * pa.h (SELECT_RTX_SECTION): Place symbolic operands into the + data section. + + * pa.c (emit_move_sequence): Rewrite code to handle arithmetic + involving plabels. + +Wed Jun 11 08:57:14 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * tree.c (unsave_expr_now): Avoid recursing into the parts of + the tree that are RTL. + +Thu Jun 12 09:43:55 1997 Jeffrey A Law (law@cygnus.com) + + * reorg.c (emit_delay_sequence): Call set_new_first_and_last_insn + after the new sequence insn has been spliced into the insn chain. + +Wed Jun 11 23:10:49 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.md (call, call_value): Use "call" instead of "calls" + for calls to named functions. + +Wed Jun 11 00:22:34 1997 Jim Wilson + + * configure, configure.in: Restore changes from Feb 15 to Apr 13 + lost during conversion to autoconf. + +Tue Jun 10 18:23:35 1997 Mike Stump + + * stmt.c (expand_decl_cleanup): Avoid core dumping when exceptions + aren't on. + +Tue Jun 10 18:22:30 1997 Jason Merrill + + * collect2.c (extract_string): New fn. + (main): Use it. + +Tue Jun 10 17:40:15 1997 Jim Wilson + + * expr.c (emit_group_load): Add case using gen_lowpart. + +Tue Jun 10 17:14:58 1997 Michael Meissner + + * rs6000.c (rs6000_override_options): If -mcpu=403, set -mstrict-align. + + * rs6000/t-ppc{,gas} (MULTILIB_EXTRA_OPTS): Build libraries with + -mstrict-align. + + * configure.in ({powerpc,rs6000}*-*-*): Add embedded targets to + --with-cpu=n support. + +Tue Jun 10 07:06:12 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * flow.c (mark_used_regs): Fix typo in Jun 4 change. + +Mon Jun 9 20:26:26 1997 Jim Wilson + + * Makefile.in (MAYBE_USE_COLLECT2): Renamed from MAYBE_USE_COLLECT. + +Mon Jun 9 19:42:21 1997 Jason Merrill + + * fold-const.c (fold): Don't do COND_EXPR -> MIN_EXPR folding if it + loses information that might be needed by a later use as an lvalue. + +Mon Jun 9 19:10:50 1997 Alexandre Oliva + + * configure.in: Don't override a user's setting for prefix + on platforms that use the native prefix. + +Mon Jun 9 19:00:49 1997 Brendan Kehoe + + * integrate.c (expand_inline_function): Use the mode of FNDECL's + result rtl, not the result type itself, in setting ARRIVING_MODE. + + * reload1.c (reload): Use xmalloc instead of alloca for the label + offsets in OFFSETS_AT and OFFSETS_KNOWN_AT. + +Mon Jun 9 15:16:52 1997 Mike Stump + + * flow.c (find_basic_blocks): Eliminate more dead code, enables + dead throws to be eliminated. + +Mon Jun 9 17:15:50 1997 Stephen L Moshier + + * alpha.c (check_float_value): Underflow and overflow constants + are different for FLOAT_VAX and default targets. + +Mon Jun 9 16:48:21 1997 Scott Christley + + * Makefile.in (Makefile): Process language fragments. + * configure.frag: New file. + * configure.in: Move language fragment processing to configure.lang.e + + * Makefile.in (GCC_PASSES): Prevent all compilers from being + built when only the C compiler is needed. + + * configure.in (cross_overrides, build_overrides): Use absolute + path to GCC top-level source directory. + + * configure.in: Save target alias for language directories. + + * configure.in (with-gxx-include-dir): New parameter for + setting the g++ header file directory. + * Makefile.in (gxx_include_dir): Use autoconf variable. + + * configure.in: Add parameter for setting local prefix. + + * configure.lang: New file. + * configure.in: Move language subdirectory Makefile processing + into configure.lang. + +Mon Jun 9 16:44:47 1997 Jim Wilson + + * sched.c (attach_deaths): Fix typo in Jun 4 change. + +Mon Jun 9 15:13:00 1997 Marc Lehmann (pcg@goof.com) + + * varasm.c (assemble_end_function): Switch back to function + section after outputting constant pool. + +Mon Jun 9 14:47:22 1997 Paul Eggert + + * tree.c (change_main_variant): Remove unused function. + (build_array_type): Remove obsolete references to + change_main_variant. + * c-decl.c (complete_array_type): Likewise. + + * c-common.c (c_build_type_variant): Don't futz with main type + variant of array since C Standard requires main type variant of + array-of-const also be array-of-const. + + * Makefile.in: Comment out lines containing just formfeeds. + + * Makefile.in (distclean): Remove config.bak. + (maintainer-clean): Output warning. + Do not remove `configure'. + +Mon Jun 9 14:44:17 1997 J.T. Conklin + + * configure.in (*-*-netbsd): Restore changes of Apr 13th lost in + autoconf conversion: tmake_file now t-netbsd; delete xmake_file. + +Mon Jun 9 14:39:29 1997 Richard Kenner + + * expr.c (expand_builtin, case BUILT_IN_FRAME_ADDRESS): + Use correct function name in error message. + + * Makefile.in (diff): Exclude bi-parser.h. + + * i386.h (CC1_CPU_SPEC): Renamed, was CC1_SPEC. + (CC1_SPEC): New macro. + (EXTRA_SPECS): Add "cc1_cpu". + * i386/linux.h (CC1_SPEC): New macro. + +Mon Jun 9 13:23:06 1997 Philippe De Muyter + + * m68k/next.h (TARGET_DEFAULT): Use MASK_68040, + not MASK_68040_ALSO. + * m68k/mot3300.h, m68k/ccur-GAS.h (TARGET_DEFAULT): Likewise. + + * m68k.h (MACHINE_STATE_{SAVE,RESTORE}): Test #ifdef __mcf52000__, + not if (TARGET_52000); fixed for mc68000 case. + + * m68k/mot3300.h (CPP_SPEC): Define __mc68020__ if no -m[c]68000 + command-line option given. + +Mon Jun 9 09:19:17 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * Makefile.in (target_alias): Substitute with target_alias. + + * final.c (final_scan_insn): Use single_set to check cc_status.flags. + +Mon Jun 9 09:09:07 1997 Andreas Schwab + + * c-common.c (check_format_info): Correct handling of the 'a' flag + which adds another pointer level. + +Sun Jun 8 00:34:25 1997 Jeffrey A Law (law@cygnus.com) + + * pa.md (conditional branch insns): Get length right for branches + to targets which can not be reached with a "bl" instruction. + * pa.c (output_cbranch): Handle branches to targets which can not + be reached with a "bl" instruction. + + * pa.md (alternate dbra pattern): Remove incorrect pattern. + +Sat Jun 7 23:30:25 1997 Jeffrey A Law (law@cygnus.com) + + * pa.c (struct defer_plab): Renamed to struct deferred_plabel. + Remove "symbol" field and replace with "name" field. + (output_function_epilogue): Don't output deferred plabels here. + (output_deferred_labels): New function. Output them here instead. + (output_call): Rewrite long call support. + * pa.h (ASM_FILE_END): Define. + (LEGITIMATE_CONSTANT_P): Never accept a function_label_operand. + * pa.md (HIGH and LO_SUM of function address): Remove patterns. + +Fri Jun 6 16:09:04 1997 Mike Stump + + * libgcc2.c (__eh_ffetmnpc): Add support for machines that cannot + access globals after throw's epilogue when -fno-sjlj-exceptions is + used. + * rs6000.c (DONT_ACCESS_GBLS_AFTER_EPILOGUE): Likewise. + * mips.h (DONT_ACCESS_GBLS_AFTER_EPILOGUE): Likewise. + (INITIAL_ELIMINATION_OFFSET): Fix RETURN_ADDRESS_POINTER_REGNUM + for 64 bit words, with 32 bit pointers and variable endianness. + +Fri Jun 6 17:27:58 1997 Mike Meissner + + * regclass.c (allocate_reg_info): Fix off by one error. + +Fri Jun 6 17:17:41 1997 Doug Evans + + * basic-block.h (EXECUTE_IF_SET_IN_REG_SET): Fix setting of scan_rs_. + (EXECUTE_IF_SET_AND_RESET_IN_REG_SET): Likewise. + (EXECUTE_IF_AND_IN_REG_SET): Likewise. + (EXECUTE_IF_AND_COMPL_IN_REG_SET): Likewise. + +Fri Jun 6 15:42:59 1997 Stan Cox + + * i386.c (notice_cc_update): Set CC_FCOMI is this is a float compare. + +Fri Jun 6 15:12:38 1997 Jim Wilson + + * basic-block.h (REG_SET_TO_HARD_REG_SET): Fix typo. + + * sched.c (update_flow_info): When add extra REG_DEAD note for original + dest, handle case where last insn both uses and sets dest. + +Thu Jun 5 22:19:36 1997 Brendan Kehoe + + * fixinc.irix: Add declaration of __vfork to unistd.h. + + * i960/vx960-coff.h (CPP_SPEC): Always define CPU, even if they + use -ansi; the VxWorks headers assume it's always present. + * sparc/vxsparc.h (CPP_SPEC): Define, adding the CPU definition to + what came from sparc.h. + (CPP_PREDEFINES): Don't define it here. + +Thu Jun 5 13:40:33 1997 Mike Meissner + + * basic-block.c (OBSTACK_ALLOC_REG_SET): Rename from + OBALLOC_REG_SET. Add obstack pointer parameter. + + * flow.c (function_obstack): Add declaration. + (life_analysis): Don't allocate the space to hold to vector of + regsets here. + (init_regset_vector): Add pointer parameter and delete space + paramter. Use OBSTACK_ALLOC_REG_SET to allocate. Change callers. + (propagate_block): Use ALLOCA_REG_SET instead of bare alloca. + + * sched.c (schedule_block): Fix typo in yesterday's changes. + * reorg.c (mark_target_live_regs): Ditto. + +Thu Jun 5 09:44:49 1997 Jeffrey A Law (law@cygnus.com) + + * sh.c (trap_exit, sp_switch): New variables. + (print_operand, case '@'): If trap_exit is nonzero, then use + a trapa instead of an rte/rts to exit the current function. + (sh_expand_prologue): Switch stacks at function entry as needed. + (sh_expand_epilogue): Similarly at function exit. + (function_epilogue): Clear trap_exit and sp_switch too. + (sh_valid_machine_decl_attribute): New function. + * sh.h (VALID_MACHINE_DECL_ATTRIBUTE): Define. + (sp_switch): Declare. + * sh.md (sp_switch_1, sp_switch_2): New named patterns. + +Wed Jun 4 18:11:14 1997 Michael Meissner + + * basic-block.h (REGSET_ELT_BITS): Make this explicitly unsigned, so + that division and modulus of REGSET_ELT_BITS uses a pure shift. + (*_REG_SET): New macros to abstract the register set interface. + + * caller-save.c (save_call_clobbered_regs): Use new *_REG_SET + macros. + * flow.c (life_analysis,propagate_block,insn_dead_p): Ditto. + (regno_uninitialized,regno_clobbered_at_setjmp,mark_set_1): Ditto. + (mark_used_regs,dump_flow_info,global_conflicts): Ditto. + global.c (mark_elimination): Ditto. + * reorg.c (mark_target_live_regs): Ditto. + * sched.c (sched_{analyze_{1,insn},note_set}): Ditto. + (birthing_insn_p,attach_deaths,unlink_notes,schedule_block): Ditto. + + * sched.c (sometimes structure): Delete offset, bit fields, replace + with regno. + (new_sometimes_live): Take regno argument, not offset and bit. + Change all callers. + +Tue Jun 3 19:18:36 1997 Brendan Kehoe + + * fixincludes: Fix AIX NULL macro use of void*. + +Tue Jun 3 15:21:04 1997 Jason Merrill + + * sparc.h (ASM_OUTPUT_MI_THUNK): Handle -fpic. + +Mon Jun 2 16:53:53 1997 Michael Meissner + + * loop.c (n_times_{set,used}): Make type int, not short. + (scan_loop): n_times{set,used} are now int pointers. + + * sched.c (sched_reg_n_deaths): Remove unused variable. + (struct sometimes): Make fields int sized, not short. + (schedule_insns): Don't set sched_reg_n_deaths, nobody uses it. + + * regclass.c (allocate_reg_info): Allocate space for reg_renumber, + but don't set unless new argument RENUMBER_P is set. If this is first + call for function and we need to grow space, use free/xmalloc instead + of realloc since we will be initializing the whole array. If number + of registers is < 0, just free up space. + (reg_scan): Update allocate_reg_info call. + * regs.h (allocate_reg_info): Change prototype. + * flow.c (allocate_for_life_analysis): Update allocate_reg_info call. + * local-alloc.c (local_alloc): Call allocate_reg_info to allocate + and initialize the reg_renumber array. + * stupid.c (stupid_life_analysis): Likewise. + +Mon Jun 2 14:50:06 1997 Dave Miller + + * sparc.md (v9 eq/ne cond move patterns): Add early clobber + constraint to destination. + +Fri May 30 11:00:44 1997 Michael Meissner + + * regs.h (reg_info): New structure to group the arrays indexed by + register number created by reg_scan and flow_analysis that are + globally visiable. + (reg_n_info): Pointer to the register information array. + (reg_n_{refs,sets,deaths,calls_crossed}): Delete variables. + (reg_changes_size): Likewise. + (REG_N_{REFS,SETS,DEATHS,CALLS_CROSSED}): New macros to reference + reg_n_info. + (REG_{CHANGES_SIZE,{FIRST,LAST,LAST_NOTE}_UID}): Likewise. + (allocate_reg_info): Add declaration. + + * basic-block.h (reg_basic_block): Delete. + (REG_BASIC_BLOCK): Use reg_n_info structure. + + * caller-save.c: Change all references to the above arrays to use + the corresponding macro to access the reg_n_info array. + * combine.c, cse.c, flow.c, global.c, jump.c, local-alloc.c: Likewise. + * loop.c, regclass.c, reload1.c, sched.c, stupid.c, unroll.c: Likewise. + + * regclass.c (allocate_reg_info): New function to allocate the + reg_info array and initialize the appropriate fields. + (reg_scan): Call it. + * flow.c (allocate_for_life_analysis): Call allocate_reg_info to do + the actual allocation. + +Thu May 29 15:42:59 1997 Stan Cox + + * i386.md (movsfcc_1, movdfcc_1, movxfcc_1): Use singlemove_string + for float conditional move when destination and operands all differ. + + * i386.h (ASM_OUTPUT_REG_{PUSH,POP}): add %% before register name. + + * go32.h (ASM_OUTPUT_ALIGN): Use .p2align, not byte alignments. + +Wed May 28 20:44:00 1997 Mike Stump + + * except.c (push_eh_entry): Eliminate start of exception region + label, as it isn't used. Rename end_label to outer_context. + (expand_eh_region_start_for_decl): Likewise. + (expand_leftover_cleanups): Likewise. + (expand_start_all_catch): Likewise. + * except.h (eh_entry): Likewise. + * except.c (expand_eh_region_end): Likewise. Jump around the nop + that we insert, so that we can optimize it away, if it is unused, + also so that flow analysis can tell if we fall through to the end + of a function or not so that it can know if a function that returns + a value, in fact does or not. + +Wed May 28 10:50:09 1997 Jeffrey A Law (law@cygnus.com) + + * pa.md (jump): Handle out of range unconditional jump + when not optimizing. + +Thu May 22 00:57:07 1997 Jeffrey A Law (law@cygnus.com) + + * reload1.c (reload_cse_record_set): Ignore values for SREG if + their mode is narrower than DEST_MODE. + + * pa.h (DFMODE_RETURN_STRING): Define. + (SFMODE_RETURN_STRING): Likewise. + (ASM_DECLARE_FUNCTION_NAME): Use them. + +Wed May 21 23:32:02 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.md (reload_insi): Handle SUBREG properly. + +Tue May 20 22:32:13 1997 Jason Merrill + + * dwarf2out.c (dwarf2out_def_cfa): Set cfa_reg at the top. + +Tue May 20 16:57:50 1997 Brendan Kehoe + + * cplus-dem.c (do_type): Handle `J'. + (demangle_fund_type): Print "complex" for it. + +Mon May 19 21:01:53 1997 Jim Wilson + + * m68k.c (output_move_qimode): Add coldfire support. + * m68k.h (PUSH_ROUNDING): Add coldfire support. + * m68k.md (scc{,0}_di, seq, sne, sgt, sgtu, slt, sltu, sge, sgeu, + sle, sleu): Add coldfire support. + +Mon May 19 17:53:34 1997 Mike Meissner + + * rs6000.c: (rs6000_pic_func_labelno): New variable. + (rs6000_output_load_toc_table): Use it. + (output_prolog): Store current value. + +Sun May 18 16:32:08 1997 Michael Meissner + + * dbxcoff.h (ASM_OUTPUT_SOURCE_LINE): Use macros + ASM_{GENERATE,OUTPUT}_INTERNAL_LABEL to create/output line + number label. + +Sun May 18 13:55:12 1997 John Vickers (john@rhizik.demon.co.uk) + + * m68k.h (TARGET_SWITCHES): Add new target name, cpu32. + +Sun May 18 13:50:10 1997 Pat Rankin + + * cccp.c (VMS_write, VMS_read): Delete. + (safe_write): If MAX_WRITE_LEN is defined, limit + incremental write attempts to that amount. + (safe_read): Analogous situation for MAX_READ_LEN. + * cpplib.c (safe_read): Likewise. + * vax/xm-vms.h (MAX_WRITE_LEN, MAX_READ_LEN): Define. + + * vax/xm-vms.h (get_dynamic_handler_chain_libfunc): New macro. + (protect_cleanup_actions_with_terminate): New macro. + +Sun May 18 08:50:25 1997 Andreas Schwab + + * m68k/linux.h (ASM_COMMENT_START): Define. + * m68k/linux-aout.h (ASM_COMMENT_START): Define. + + * reload1.c (reload_cse_regno_equal_p): Check for value using more + than one register on a big endian machine. + +Sun May 18 08:39:59 1997 Vince Del Vecchio + + * loop.c (maybe_eliminate_biv_1): In (set (cc0) ) case, + swap compare operands when mult_val < 0 in one additional place. + +Sun May 18 08:33:30 1997 Richard Kenner + + * dwarf2out.c (ASM_COMMENT_START): Add default definition. + + * Makefile.in (maintainer-claean): Delete configure. + +Sun May 18 08:31:59 1997 Scott Christley + + * configure.in: New file. + * Makefile.in: Change to utilize autoconf variables. + * configure: Now an output file. + +Sun May 18 07:48:31 1997 J.T. Conklin + + * m68k.md (mov[qhs]i,movstrict[qs]i, mulsi3): Use 'Q' constraint + for TARGET_5200. + * m68k.h (EXTRA_CONSTRAINT): New macro. + + * m68k.h (TARGET_SWITCHES): Add 68020-60. + Mask out bits which indicate a particular processor when a different + processor is selected. + (MASK_68040_ALSO): Remove. + (MASK_68040): Change to be a single bit. + + * m68k.h (TARGET_ALIGN_INT, MASK_ALIGN_INT): New macros. + (BIGGEST_ALIGNMENT): Determine according to TARGET_ALIGN_INT. + (TARGET_SWITCHES): Add align-int and no-align-int. + + * m68k.md (mov[qhs]i}): Add pair of constraints which allow + offsetable memory addresses to be moved to the same for TARGET_5200. + + * m68k.c (output_move_strict{hi,qi}): New functions. + * m68k.h (output_move_strict{hi,qi}): Declare. + * m68k.md (movstrict*): Changed into define_expands. + Split insns into m68k and coldfire specific versions with appropriate + constraints. + +Sun May 18 07:26:40 1997 Philippe De Muyter + + * libgcc2.c (atexit): Cast malloc and realloc calls. + +Sat May 17 16:26:51 1997 Bernd Schmidt + + * final.c (profile_function): Call function_section, not + text_section. + +Sat May 17 16:01:00 1997 Philippe De Muyter + + * cse.c (notreg_cost): New function, extracted from COST macro. + (COST): Use notreg_cost. + +Sat May 17 15:13:23 1997 Richard Kenner + + * cse.c (cse_insn): Don't record a SRC that's a MEM and the same + as a REG_EQUIV note if DEST is set more than once. + +Fri May 16 14:50:57 1997 Jeffrey A Law (law@cygnus.com) + + * pa.c (output_move_double): Handle loading a general register + from a scaled indexed memory address. + * pa.md (movdf, movdi): Allow scaled loads into general registers. + +Fri May 16 13:31:08 1997 Mike Stump + + * rs6000.c (rs6000_stack_info): Only do eabi setup for "main", + when main is the global main, not some nested routine that + happens to be called main. + +Thu May 15 17:19:50 1997 Mike Stump + + * except.c (expand_start_all_catch): If the machine needs to + perform any actions at the start of an expcetion handler that + hasn't already been done, use gen_exception_receiver to emit it. + (expand_leftover_cleanups): Likewise. + * alpha.md (exception_receiver): Use it. + * pa.h (exception_receiver): Use it. + +Thu May 15 08:36:59 1997 Jeffrey A Law (law@cygnus.com) + + * dbxout.c (dbxout_function_end): Don't subtract one from + the end of function scoping stab. + +Wed May 14 23:27:09 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.md (adddi3, subdi3): Remove expanders and patterns. + +Wed May 14 18:51:35 1997 Mike Stump + + * function.c (expand_function_end): Make sure we finish off any + leftover exception handlers. + +Tue May 13 14:07:01 1997 Mike Stump + + * expr.c (expand_builtin_setjmp): Remove setting of + current_function_has_nonlocal_goto, as this isn't a goto. + +Tue May 13 14:47:40 1997 Richard Earnshaw (rearnsha@cambridge.arm.com) + + * arm.h (CPP_SPEC): Fix typo invoking cpp_endian. + * arm/t-semi (LIB2FUNCS_EXTRA): Build fp-bit.c when compiling + with -msoft-float. + * arm.c: Add prototypes for all static functions. + (output_multi_immediate, int_log2): Make static. + + * arm.h (*_SPEC): Remove all references to mle/mbe. + * arm/coff.h (MULTILIB_DEFAULTS): Likewise. + * arm/t-bare (MULTILIB_OPTIONS): Change options mbe/mle to mbig-endian + and mlittle-endian. + (MULTILIB_MATCHES): Nothing matches that matters. + +Mon May 12 20:42:20 1997 Mike Stump + + * except.c (expand_start_all_catch): If need nonlocal_goto_receiver, + add one at the start of exception handler. + (expand_leftover_cleanups): Likewise. + +Mon May 12 17:36:28 1997 Jeffrey A Law (law@cygnus.com) + + * mips.c (move_operand): Accept any general operand after reload + has started. + +Fri May 9 14:29:33 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.md (udivmodhi4, divmodhi4): Remove expander, give + corresponding pattern [u]divmodhir4 name. Clear MDR register + in the udivmodhi4 pattern itself. + (clear_mdr): Delete pattern. + +Thu May 8 18:20:30 1997 Richard Earnshaw (rearnshaw@cambridge.arm.com) + + * arm/aout.h (ASM_OUTPUT_LONG_DOUBLE): Delete call to + arm_increase_location. + (ASM_OUTPUT_{DOUBLE,FLOAT,INT,SHORT,CHAR,BYTE,ASCII,SKIP}): Likewise. + (ASM_OUTPUT_ALIGN): Delete all code refering to arm_text_location. + + * arm.c (arm_increase_location, get_prologue_size): Delete. + (arm_naked_function_p): Add declaration. + (arm_pic_register): Define. + (all_procs): Delete entries for arm{60,620,70,7d,7di,700i,710c}; add + entries for arm{7m,7500fe,8}, strongarm and strongarm110. + (arm_override_options): Rework so that configure can properly set + the default processor type. Add a warning that PIC code is not yet + supported. + (legitimate_pic_operand_p, legitimize_pic_address): New functions. + (is_pic, arm_finalize_pic): New functions. + (arm_adjust_cost): New function. + (const_pool_offset, arm_backwards_branch, short_branch): Delete. + (arm_insn_not_targeted): Delete. + (add_constant): If generating AOF syntax, then handle pic specially. + (output_ascii_pseudo_op): Delete calls to arm_increase_location. + (function_really_clobbers_lr): Calls followed by a barrier don't + clobber the link register. + (output_func_prologue): Handle AOF syntax pic code. + (output_func_epilogue): Handle cases where lr_save_eliminated is set. + Delete call to arm_increase_location. + (arm_asm_output_label): Simplify, since we no-longer need to cache the + label's address. + (aof_pic_entry): New function to keep track of pic symbols. + (aof_dump_pic_table): New function. + + * arm.h (TARGET_CPU_arm*, TARGET_CPU_strongarm*, TARGET_CPU_generic): + define. + (CPP_ARCH_DEFAULT_SPEC): Set up based on setting of TARGET_CPU_DEFAULT. + (CPP_SPEC): Split up into sub-rule calls. + (CPP_CPU_SPEC): Add default definition. + (CPP_APCS_PC_SPEC, CPP_APCS_PC_DEFAULT_SPEC): Add definitions. + (CPP_FLOAT_SPEC, CPP_FLOAT_DEFAULT_SPEC): Add definitions. + (CPP_ENDIAN_SPEC, CPP_ENDIAN_DEFAULT_SPEC): Add definitions. + (CC1_SPEC): Map legacy -m[236] onto -mcpu=.. and -mapcs-{26,32} as + appropriate. Similarly for -mbe and -mle to -m{big,little}-endian. + (EXTRA_SPECS): Define. + (enum processor_type): New types for arm8 and strongarm. + (CONDITIONAL_REGISTER_USAGE): Handle flag_pic. + (LEGITIMIZE_ADDRESS): Likewise. + (ADJUST_COST): Define. + (PIC_OFFSET_TABLE_REGNUM): Define. + (FINALIZE_PIC): Define. + (LEGITIMATE_PIC_OPERAND_P): Define. + (OUTPUT_INT_ADDR_CONST): Define. + (ASM_OUTPUT_MI_THUNK): Delete calls to arm_increase_location. + (MASK_RETURN_ADDR): Use TARGET_APCS_32 not TARGET_6. + + * arm.md (attr cpu): Add new cpu types for arm8 and strongarm. + (attr ldsched): New attribute, set if processor has a load_delay slot. + (function_unit core): Rework to handle load delay slots. + (function_unit loader): New function unit. + (movsi): Handle pic. + (pic_load_addr): New expand. + (*pic_load_addr_based_insn, pic_add_dot_plus_eight): New patterns. + (peepholes to cause flow to return to a label after a function call): + Delete, these have been disabled for a while now. + + * arm/riscix.h (CPP_SPEC): Rewrite using new sub-components. + (SUBTARGET_CPU_DEFAULT): Set to TARGET_CPU_arm2. + * arm/riscix1-1.h (CPP_SPEC): Rewrite using new sub-components. + (SUBTARGET_CPU_DEFAULT): Set to TARGET_CPU_arm2. + * arm/semi.h: (CPP_SPEC): Delete. + (PROCESSOR_DEFAULT): Delete. + (CPP_APCS_PC_DEFAULT_SPEC): Define. + * arm/semiaof.h (CPP_SPEC): Delete. + (CPP_APCS_PC_DEFAULT_SPEC): Define. + * arm/t-semi (LIBGCC1_TEST): Don't build it. + (MULTILIB_{OPTIONS,DIRNAMES,EXCEPTIONS}): Build a suitable set of + cross libraries. + (LIBGCC): Set to stmp-multilib. + (INSTALL_LIBGCC): Set to install-multilib. + +Thu May 8 15:20:46 1997 Stan Cox + + * i386.c (output_float_compare): For pentiumpro use fcomip + followed by a float stack pop for "compare;pop;pop" cases. + +Thu May 8 13:20:20 1997 Chris Torek + + * fold-const.c (fold, truth_andor): Disable optimization for + side effects on RHS. + +Wed May 7 15:43:57 1997 Mike Stump + + * except.c (start_dynamic_handler): Fix so we can use __builtin_setjmp, + and default to using __builtin_setjmp instead of setjmp. + * expr.c (expand_builtin_setjmp): New routine, split out from + existing inline code from expand_builtin. + (expand_builtin): Split out code into expand_builtin_setjmp. + * expr.h (expand_builtin_setjmp): Add declaration. + * libgcc2.c (__sjthrow): Default to using __builtin_setjmp instead + of setjmp. + (__sjpopnthrow): Likewise. + * optabs.c (init_optabs): Likewise. + +Wed May 7 18:01:24 1997 Samuel Figueroa + + * rs6000.md (insv): Only combine insert with shift if + remaining source bits >= destination field size. + +Tue May 6 15:48:52 1997 Jason Merrill + + * dwarf2out.c (dwarf2out_begin_prologue): Increment + current_funcdef_number here. + (dwarf2out_end_epilogue): Not here. + +Mon May 5 18:52:32 1997 Jeffrey A Law (law@cygnus.com) + + * h8300.c (notice_update_cc): Use CC_SET_ZN and CC_SET_ZNV. + (shift_one, shift_two): Set CC_NO_CARRY as needed. Remove + references to CC_OVERFLOW_0. + (emit_a_shift): Similarly. + * h8300.h (CC_OVERFLOW_0): Remove. + * h8300.md: Use set_zn and set_znv for cc0 tracking. + (bCC): Restore the comparison is CC_OVERFLOW_UNUSABLE is set and + the comparison needs the overflow bits. + + * mn10300.c (notice_update_cc): Use CC_SET_ZN and CC_SET_ZNV. + * mn10300.h (CC_NO_CARRY): Define. + * mn10300.md: Use "set_zn" and "set_znv" to more accurately + describe cc0 status. + +Fri May 2 17:00:33 1997 Jason Merrill + + * dwarf2out.c: Reorganize, moving .debug_frame support to the top + of the file, and compile it if INCOMING_RETURN_ADDR_RTX is defined + even if DWARF2_DEBUGGING_INFO isn't. + (EH_FRAME_SECTION): New macro. + (output_call_frame_info): Handle .eh_frame variant. + (dwarf2out_def_cfa): Update cfa_*{reg,offset}. + (dwarf2out_frame_debug): Move cfa_*{reg,offset} to file scope. + (dwarf2out_end_epilogue): Increment current_funcdef_number here. + (dwarf2out_decl): Not here. + (dwarf2out_frame_init, dwarf2out_frame_finish): New fns. + (dwarf2out_init, dwarf2out_finish): Call them. + (output_die): Add missing 'case 8:' + (dwarf2out_decl): Revert other context_die = NULL change. + (add_bound_info): Restore default case. + +Fri May 2 15:30:16 1997 Doug Evans + + * m32r.h (LIT_NAME_P): New macro. + (SMALL_NAME_P): Use it. + (ASM_OUTPUT_ALIGNED_COMMON): Don't output to scommon if -msdata=none. + * m32r.c (addr24_operand): Handle literals. + (m32r_output_function_prologue): Use IMMEDIATE_PREFIX. + (m32r_output_function_epilogue): Likewise. Use shorter add insn if + able. + +Fri May 2 14:40:44 1997 David Edelsohn + + * rs6000.h (RS6000_ALIGN): Macro renamed from ALIGN. + * rs6000.c (rs6000_stack_info): Use it. + +Fri May 2 14:15:54 1997 Ian Lance Taylor + + * reload1.c (reload_cse_noop_set_p): When checking the values + equivalent to sreg, make sure the mode is right. + +Fri May 2 12:53:03 1997 Jeffrey A Law (law@cygnus.com) + + * reload1.c (reload_cse_invalidate_regno): Properly set + the mode for invalidate_regno_rtx. + +Thu May 1 14:57:35 1997 Jeffrey A Law (law@cygnus.com) + + * pa.md (call_internal_symref): Fix typo. + +Thu May 1 14:44:17 1997 Jim Wilson + + * mips.c (mips_asm_file_start): Use new macro TARGET_FILE_SWITCHING. + (mips_asm_file_end): Likewise. + * mips.h (TARGET_FILE_SWITCHING): Define. + (NO_DBX_FUNCTION_END): Define. + +Thu May 1 09:08:40 1997 Andreas Schwab + + * m68k.c (output_addsi3): Replace "\\;" by "\n\t" in + assembler templates. + +Thu May 1 09:00:42 1997 Richard Kenner + + * integrate.c (subst_constants, case SUBREG): Cancel changes once + done with result. + +Wed Apr 30 19:45:56 1997 Jim Wilson + + * mips.c (override_options): Set mips_split_addresses only if + TARGET_SPLIT_ADDRESSES is set. + * mips.h (MASK_SPLIT_ADDR, TARGET_SPLIT_ADDRESSES): New macros. + (TARGET_SWITCHES): Add -msplit-addresses, -mno-split-addresses. + * configure (mips*-*-ecoff*, mips*-*-elf*): Set MASK_SPLIT_ADDR + bit in target_cpu_default2. + + * flags.h (current_function_is_thunk): Add extern to declaration. + + * dbxout.c (dbxout_function): Test NO_DBX_FUNCTION_END at run time + instead of compile time. + + * unroll.c (set_dominates_use): In second loop, add check for copy_end. + + * mips.md (paradoxical_extendhidi2, paradoxical_extendqidi2): New + patterns. + +Wed Apr 30 02:23:24 1997 Jason Merrill + + * output.h (named_section): Add reloc argument. + (DECL_READONLY_SECTION): New macro. + * varasm.c (named_section): Add reloc argument, pass it to + ASM_OUTPUT_SECTION_NAME. + (UNIQUE_SECTION, UNIQUE_SECTION_P): Provide defaults. + (function_section): Pass reloc argument to named_section. + (variable_section, exception_section): Likewise. + (output_constant_def_contents): Likewise. + (assemble_start_function): Use UNIQUE_SECTION_P. UNIQUE_SECTION is + now a statement. + (assemble_variable): Likewise. + * mips/iris6.h (ASM_OUTPUT_SECTION_NAME): Add reloc arg, + use DECL_READONLY_SECTION. + * psos.h, ptx4.h, a29k.h, alpha/elf.h, arm/coff.h, h8300.h: Likewise. + * i386/go32.h, i386/sco5.h, m68k/coff.h, mips/elf64.h: Likewise. + * mips/netbsd.h, pa.h, rs6000/sysv4.h, sh.h, sparc/sysv4.h: Likewise. + * config/svr4.h (SELECT_SECTION): Use DECL_READONLY_SECTION. + (ASM_OUTPUT_SECTION_NAME): Likewise, add reloc argument. + (MAKE_DECL_ONE_ONLY): Just set DECL_WEAK. + (UNIQUE_SECTION, UNIQUE_SECTION_P): Define. + * i386/cygwin32.h (UNIQUE_SECTION_P): Define. + (SUPPORTS_ONE_ONLY): Define. + (MAKE_DECL_ONE_ONLY): Lose. + (ASM_OUTPUT_SECTION_NAME): Add reloc arg, use DECL_READONLY_SECTION. + * i386/winnt.c (i386_pe_unique_section): Add reloc arg, + use DECL_READONLY_SECTION. + + * mips/iris6.h (CTORS_SECTION_ASM_OP): Change aligment based on ABI. + (DTORS_SECTION_ASM_OP): Likewise. + +Tue Apr 29 16:08:07 1997 Jeffrey A Law (law@cygnus.com) + + * pa/lib1funcs.asm (divnorm, modnorm, exitdiv): Fix code to + negate SImode values. + +Tue Apr 29 12:54:14 1997 Mike Stump + + * except.c (expand_eh_region_start_tree): Add DECL argument so we + can better track why the region was made for error reporting. + * except.h (expand_eh_region_start_tree): Likewise. + * tree.h (expand_dhc_cleanup): Likewise. + (expand_dcc_cleanup): Likewise. + * except.c (expand_eh_region_start_for_decl): New routine. + * except.h (expand_eh_region_start_for_decl): Likewise. + * stmt.c (expand_decl_cleanup): Add DECL to call of + expand_eh_region_start_tree. + (expand_dcc_cleanup): Likewise. + (expand_dhc_cleanup): Likewise. + (expand_start_case): Switches introduce conditional contexts. + (expand_start_case_dummy): Likewise. + (expand_start_case_dummy): Likewise. + (expand_end_case): Likewise. + +Tue Apr 29 11:45:09 1997 Jason Merrill + + * dwarf2out.c (dwarf2out_decl): Undo earlier change. + (constant_size): Likewise. + (gen_subprogram_die): Handle NULL context_die. + + * mips/iris6.h (ASM_OUTPUT_CONSTRUCTOR): Fix for -mabi=64. + (ASM_OUTPUT_DESTRUCTOR): Likewise. + +Mon Apr 28 09:10:19 1997 Jeffrey A Law (law@cygnus.com) + + * h8300.c (push_order, pop_order): Add missing initializer entries. + +Fri Apr 25 19:39:43 1997 J"orn Rennecke + + * h8300.c (output_adds_subs): Check for adding 0. + +Fri Apr 25 14:52:31 1997 Jim Wilson + + * configure (i[3456]86-*-freebsdelf*, i[3456]86-*-freebsd*): Use + t-freebsd instead of x-freebsd. + * i386/t-freebsd: Renamed from x-freebsd. + +Fri Apr 25 12:16:20 1997 Stan Cox + + * go32.h (DBX_*): Use definitions from config/dbxcoff.h instead. + +Fri Apr 25 11:55:54 1997 Jason Merrill + + * i386/cygwin32.h (MULTIPLE_SYMBOL_SPACES): Define. + +Thu Apr 24 18:32:56 1997 Jason Merrill + + * i386/winnt.c (i386_pe_unique_section): New fn. + * i386/cygwin32.h (UNIQUE_SECTION): Define. + (MAKE_DECL_ONE_ONLY): Define. + (ASM_OUTPUT_SECTION_NAME): Support DECL_ONE_ONLY. + + * c-decl.c (implicitly_declare): Don't set DECL_ARTIFICIAL. + +Thu Apr 24 17:11:23 1997 Jim Wilson + + * m68k.h (MACHINE_STATE_SAVE, MACHINE_STATE_RESTORE): Add + TARGET_5200 support. + +Thu Apr 24 16:39:25 1997 Richard Kenner + + * stmt.c (pushcase_range): Check for null range first. + +Wed Apr 23 23:06:28 1997 Ian Lance Taylor + + * reload1.c (reload_cse_record_set): Use push_operand to check for + changes to the stack pointer. + +Wed Apr 23 19:56:01 1997 Jason Merrill + + * calls.c (expand_call): If we're in a thunk, pass through invisible + references instead of making a copy. + * flags.h: Add current_function_is_thunk. + * function.c: Likewise. + (init_function_start): Initialize it. + (push_function_context_to): Save it. + (pop_function_context_from): Restore it. + * function.h (struct function): Add is_thunk. + +Wed Apr 23 17:47:25 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.c (secondary_reload_class): Handle more cases where we + need secondary reloads. + (impossible_plus_operand): Accept anything that involves addition + of the stack pointer. + * mn10300.md (reload_insi): Always load the stack pointer into + the destination (which is always an address register). + * mn10300.h (STORE_FLAG_VALUE): Remove definition. + * xm-mn10300.h: Declare malloc, realloc, calloc and free. + +Wed Apr 23 14:28:30 1997 Mike Stump + + * expr.h (sjthrow_libfunc): Add support for setjmp/longjmp based + exception handling. + ({sjpopnthrow,terminate,setjmp,longjmp}_libfunc): Likewise. + (get_dynamic_handler_chain_libfunc): Likewise. + * expr.c (expand_expr, case TRY_CATCH_EXPR): Likewise. + (expand_expr, case POPD{C,H}C_EXPR): Likewise. + * stmt.c (mark_block_as_eh_region): Likewise. + (mark_block_as_not_eh_region): Likewise. + (is_eh_region, conditional_contex, expand_start_bindings): Likewise. + (expand_end_bindings, expand_{decl,dcc,dhc}_cleanup): Likewise. + (expand_cleanups): Likewise. + * tree.h (mark_block_as_eh_region): Likewise. + (mark_block_as_not_eh_region, is_eh_region): Likewise. + conditional_context, expand_dhc_cleanup): Likewise. + * except.c (exception_via_longjmp): Likewise. + (protect_cleanup_actions_with_terminate): Likewise. + (current_function_d{h,c}c, add_partial_entry): Likewise. + (get_dynamic_{handler,cleanup}_chain): Likewise. + (start_dynamic_{cleanup, handler}): Likewise. + (expand_eh_region_start{,_tree}, expand_eh_region_end): Likewise. + (emit_throw, expand_leftover_cleanups): Likewise. + (expand_{start,end}_all_catch, protect_with_terminate): Likewise. + ({start,end}_eh_unwinder, init_eh_for_function): Likewise. + ({save,restore}_eh_status, exception_optimize): Likewise. + * optabs.c ({sjthrow,sjpopnthrow,terminate,setjmp}_libfunc): Likewise. + ({longjmp,get_dynamic_handler_chain}_libfunc): Likewise. + (init_optabs): Likewise. + * except.h: Likewise. + * libgcc2.c (__default_terminate): Likewise. + (__terminate, __get_dynamic_handler_chain, __sjthrow): Likewise. + (__sjpopnthrow): Likewise. + * toplev.c (f_options): Likewise. + * tree.def (TRY_CATCH_EXPR, POPDHC_EXPR, POPDCC_EXPR): Likewise. + * pa.h (JMP_BUF_SIZE): Define. + * sparc.h (JMP_BUF_SIZE): Define. + + * expr.h (cleanups_this_call): Transform uses of cleanups_this_call + into uses of the cleanups managed by the block code + (expand_start_bindings and friends). Remove defer_cleanups_to and + expand_cleanups_to, and use start_cleanup_deferal and + end_cleanup_deferal instead. Add exception_region, + target_temp_slot_level, conditional_code, + last_unconditional_cleanup and cleanup_ptr to struct nesting to + facilitate conditional cleanups. + * expr.c (cleanups_this_call, init_expr): Likewise. + ({save,restore}_expr_status, store_expr): Likewise. + (expand_expr, {defer,expand}_cleanups_to): Likewise. + (do_jump, case TRUTH_{AND,OR}IF_EXPR): Likewise. + (do_jump, case COND_EXPR): Likewise. + * stmt.c (struct nesting): Likewise. + (expand_return, expand_start_bindings, expand_end_bindings): Likewise. + (expand_cleanups, {start,end}_cleanup_deferal): Likewise. + * tree.h (start_cleanup_deferal): Likewise. + (end_cleanup_deferal): Likewise. + * calls.c (expand_call): Likewise. + * function.h (struct function): Likewise. + * except.c (asynchronous_exceptions): Support + -fasynchronous_exceptions. + (can_throw): Likewise. + * toplev.c (f_options): Likewise. + + * flags.h (flag_short_temps): Remove support for short temps. + * calls.c (expand_call): Likewise. + * toplev.c (flag_short_temps): Likewise. + + * stmt.c (expand_start_target_temps): Add for convenience. + (expand_end_target_temps): Likewise. + * except.c (jumpif{,not}_rtx): Likewise. + + * stmt.c: Remove all traces of empty_cleanup_list. + +Wed Apr 23 17:26:40 1997 Ian Lance Taylor + + * reload1.c (reload_cse_mem_conflict_p): Don't assume that a + SUBREG can not conflict with a MEM. + +Wed Apr 23 09:48:58 1997 Oliver Kellogg (oliver.kellogg@space.otn.dasa.de) + + * 1750a.md (cmphi): Fixed when next CC user is unsigned. + (mov[hq]i-[23]): New patterns for mem-indirect moves. + (movhf,movtqf): Corrected. + * 1750a.c (memop_valid): Memory indirection now valid. + (nonindirect_operand): Remove. + (print_operand): Fix the 'J' output modifier. + * 1750a.h (FRAME_POINTER_REQUIRED): Not required. + (INITIAL_FRAME_POINTER_OFFSET,FIX_FRAME_POINTER_ADDRESS): Undefine. + (FUNCTION_PROLOGUE,FUNCTION_EPILOGUE): Honor -fomit-frame-pointer. + (ELIMINABLE_REGS,CAN_ELIMINATE,INITIAL_ELIMINATION_OFFSET): Defined. + (PREFERRED_RELOAD_CLASS): Corrected. + (CONST_COSTS,ADDRESS_COST,REGISTER_MOVE_COST,MEMORY_MOVE_COST): + Slight adjustments. + (ASM_APP_ON,ASM_APP_OFF): Corrected. + * ms1750.inc (DUCR.M,DUC.M): Defined. + +Wed Apr 23 09:41:35 1997 Andreas Schwab + + * reload.c (push_reload): Fix last arg of call to find_dummy_reload. + +Wed Apr 23 09:29:14 1997 Richard Kenner + + * configure (i[3456]86-next-*, m68k-next-nextstep{2,3}*): + Remove out_file and add extra_objs. + * config/nextstep.c: Add includes for config.h, stdio.h, and flags.h. + * {i386,m68k}/t-next (nextstep.o): New rule. + * m68k/next.h: Remove include of machmode.h. + * {i386,m68k}/next.c: Files deleted. + +Tue Apr 22 20:45:29 1997 Jason Merrill + + * sparc.h (DBX_CONTIN_LENGTH): Shrink to 1000. + +Tue Apr 22 18:21:20 1997 Jim Wilson + + * dwarf2out.c (gen_variable_dir): Add test for DW_AT_declaration to + the old_die if statement, and delete assertion for it. + (decl_ultimate_origin): Remove last change. + +Tue Apr 22 10:22:27 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.c (expand_prologue): End the current sequence before + counting the tst insns in the current function. Start a new + one before emitting any prologue instructions. + + * mn10300.h (REGISTER_MOVE_COST): Bump up cost of moves in the + same class. + + * mn10300.md (untyped_call): New expander. + +Mon Apr 21 16:30:21 1997 Richard Kenner + + * cse.c (fold_rtx, case PLUS): When seeing if negative of constant + is around, make sure not dealing with largest negative. + +Mon Apr 21 13:57:53 1997 Jim Wilson + + * mips/t-ecoff: Set TARGET_LIBGCC2_CFLAGS instead of LIBGCC2_CFLAGS. + + * m68k.c (output_addsi3): New function. From addsi3 pattern. + * m68k.h (output_addsi3): Add declaration. + * m68k.md (movqi+2): Add address registers. + (movxf+1): Disable for TARGET_5200. + (movxf+2): New pattern for TARGET_5200. + (addsi3): Add define_expand. Move code to output_addsi3. + (addsi3_internal): Renamed from addsi3. Disable for TARGET_5200. + (addsi3_5200): New pattern for TARGET_5200. + +Sun Apr 20 10:45:35 1997 Richard Kenner + + * fold-const.c (operand_equal_p): Constants are not equal if there + has been an overflow. + + * toplev.c (compile_file): Shorten "branch-probabilities" in + output of times. + + * alpha/vms.h (MOD[SD]I3_LIBCALL): Call ots$rem, not ots$mod. + (DWARF2_DEBUGGING_INFO): Define. + + * alpha.c (alpha_need_linkage): Call get_identifier. + + * rs6000.c (rs6000_output_load_toc_table): New function. + (output_prolog): Call it instead of doing it directly. + * rs6000.md (nonlocal_goto_receiver): New pattern. + + * dwarf2out.c: Major cleanup; mostly reformatting. + Include expr.h. + Undefine inline ifndef __GNUC__; never define to include static. + Add "static" to header of all inlined functions. + Add declarations for all static functions, with prototypes. + (addr_const_to_string): Use HOST_WIDE_INT_PRINT_* macros. + (add_AT_*, new_{die,loc_descr,cfi): Don't check for xmalloc + returning zero. + (modified_type_die): Add missing parm on recursive call. + ({reg,based}_loc_descriptor): Add missing arg to call to new_loc_descr. + (add_const_value_attribute): Use REAL_VALUE_TYPE for fp calculations. + (output_call_frame_info): Add missing arg to output_cfi call. + (dwarf2out_def_cfa): Local variable OLD_REG must be unsigned long. + * Makefile.in (dwarf2out.o): Includes expr.h. + + * dwarf2out.c: Cast first arg in all calls to bzero to char *. + (decl_ultimate_origin): Return NULL if equal to decl. + (constant_size): Never return more than 4. + (value_format, case 8): New case. + (dwarf2out_frame_debug): Use HARD_FRAME_POINTER_REGNUM. + (based_loc_descr): Likewise. + (add_bound_info): Delete default case. + Add cases for CONVERT_EXPR and NON_LVALUE_EXPR; treat like NOP_EXPR. + Change NOP_EXPR to recursive call. + (add_type_attribute): Ignore unnamed subtype of integral or FP. + (gen_subprogram_die): Use reg_loc_descriptor. + (dwarf2out_decl): Ignore nested functions. + + * fix-header.c, protoize.c, gcov.c: Use symbolic codes for exit. + + * final.c (profile_function): Only call ASM_OUTPUT_REG_{PUSH,POP} + if defined. + + * expr.c ({move,clear}_by_pieces_1, expand_assignment): Ensure + we have unshared rtx before changing flags. + (store_{constructor,field}): Likewise. + (expand_expr, case COMPONENT_REF): Likewise. + (store_expr): Check if TEMP and TARGET are same with rtx_equal_p. + + * emit-rtl.c (change_address, init_emit): Delete forward references. + (rtl_obstack, stack_depth, max_stack_depth): Delete extern decls. + +Fri Apr 18 18:25:52 1997 Jim Wilson + + * function.c (instantiate_decls): For DECL_INCOMING_RTL, use max + of type size and mode size in instantiate_decl call. + + * fixincludes (sys/lc_core.h): Fix OSF1/4.x namespace pollution. + +Wed Apr 16 19:36:53 1997 Jason Merrill + + * dwarf2out.c (add_bound_info): Use a DIE instead of a location + expression for variable bounds. Trust a MEM rtx even when + optimizing. + (DWARF_FRAME_RETURN_COLUMN): Default to FIRST_PSEUDO_REGISTER. + + * expr.c (expand_expr, case RTL_EXPR): If there is no sequence, + don't set it to const0_rtx. + * tree.c (array_type_nelts): Don't return any SAVE_EXPRs. + +Mon Apr 14 18:12:57 1997 David Edelsohn + + * rs6000.h (RS6000_ITRUNC, RS6000_UITRUNC): Prepend underscores. + (RS6000_MCOUNT): New macro. + (ASM_FILE_START): Use RS6000_MCOUNT. + * rs6000.c (output_function_profiler): Use RS6000_MCOUNT. + * rs6000/aix31.h (RS6000_{ITRUNC,UITRUNC,MCOUNT}): New macros. + +Mon Apr 14 14:37:27 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.c (can_use_return_insn): Include outgoing argument + area in size computation. + (expand_prologue): Likewise. No longer diddle with sequences. + Put register saves just before outgoing argument area. + (expand_epilogue): Similarly. + (impossible_plus_operand): New function. + * mn10300.h (FRAME_POINTER_REQUIRED): Never require a frame pointer. + (ACCUMULATE_OUTGOING_ARGS, OUTGOING_REG_PARM_STACK_SPACE): Define. + (impossible_plus_operand): Declare. + * mn10300.md (reload_insi): New expander to handle pathological + reload cases. + (addsi3): Fix CC status. + + * mn10300.h (FUNCTION_VALUE): Return addresses in $a0. + (FUNCTION_VALUE_REGNO_P): Corresponding changes. + * mn10300.md (call_value_internal): Allow output to be in an + address register. + + * calls.c (emit_library_call): Handle saving of stack slots when + ACCUMULATE_OUTGOING_ARGS is defined. + (emit_library_call_value): Likewise. + +Mon Apr 14 14:48:15 1997 Jim Wilson + + * sh.md (xtrct_left, xtrct_right): New patterns. + + * combine.c (get_last_value_validate): New argument insn. + Add check for memory reference clobbered by later store. + (record_value_for_reg, get_last_values): Pass in new argument. + +Mon Apr 14 14:03:18 1997 Mike Meissner + + * configure (powerpc --with-cpu=x): Add embedded powerpcs and 604e. + + * rs6000.c (rs6000_override_options): Recognize -mcpu=801, -mcpu=823, + and -mcpu=604e. + +Sun Apr 13 18:43:16 1997 Ian Lance Taylor + + * reload1.c (invalidate_regno_rtx): New static variable. + (reload_cse_invalidate_regno): Check whether any earlier registers + have a multi-register value which includes the register we are + invalidating. + (reload_cse_regs): Initialize invalidate_regno_rtx. + + * reload1.c (reload_cse_record_set): When setting reg_values for a + copy from one register to another, use gen_lowpart_common to + adjust the value correctly if the mode changes. + +Sun Apr 13 17:24:48 1997 Doug Evans + + * expr.c (move_block_from_reg): Try using integral mov operation first. + + * calls.c (expand_call): When copying unaligned values into a register, + zero out the register first rather than emitting a clobber. + + * integrate.c (copy_rtx_and_substitute): If FRAME_GROWS_DOWNWARD + and regno == VIRTUAL_STACK_VARS_REGNUM, round size of stack slot up + before calling assign_stack_temp. + +Sun Apr 13 15:29:38 1997 Ulrich Drepper + + * enquire.c (fake_f_rep): Add missing element name in cast. + +Sun Apr 13 15:20:05 1997 J"orn Rennecke + + * stor-layout.c (layout_record, PCC_BITFIELD_TYPE_MATTERS): + Fix sign bug in last change. + +Sun Apr 13 15:03:38 1997 J.T. Conklin + + * m68k.md (movstricthi): Remove extraneous comparisons. + + * configure (*-*-netbsd): tmake_file now t-netbsd; delete xmake_file. + * config/t-netbsd: New file. + * config/x-netbsd: Removed. + +Sun Apr 13 14:51:25 1997 Richard Earnshaw (rearnsha@armltd.co.uk) + + * cse.c (canon_reg, cse_insn): Don't examine insn_n_dups if + recog_memoized fails to find a match. + +Sun Apr 13 14:17:26 1997 Ian Lance Taylor + + * reload1.c (reload_cse_noop_set_p): Add insn parameter. Change + all callers. If deleting the instruction, remove any earlier + REG_DEAD note for DREG. + (reload_cse_simplify_set): If simplifying, remove any earlier + REG_DEAD note for the new source register. + +Sun Apr 13 14:12:08 1997 Pat Rankin + + * libgcc2 (L_bb, L_exit): Use 0 rather than NULL for null pointers. + +Sun Apr 13 12:53:03 1997 Andreas Schwab + + * m68k/linux.h (ASM_SPEC): Define. + (STRUCT_VALUE_REGNUM, STATIC_CHAIN_REGNUM, INITIALIZE_TRAMPOLINE): + Remove definitions, undoing the change of Mar 20 1996. + + * m68k.c (output_move_qimode): Optimize pushing one byte if source + operand does not use stack pointer. + + * m68k.md (rotl[shq]i3, rotl[hq]i3+1): Don't directly modify operand. + + * m68k.md (tstdi): Add missing parallel around the pattern. + +Sun Apr 13 12:51:00 1997 Paul Eggert + + * cccp.c, cpplib.c (do_include): Diagnose #import and + #include_next if pedantic and if not in a system header. + (do_warning): #warning now causes an error if -pedantic-errors + is given; this is needed since #warning isn't ANSI. + + * toplev.c (lang_options): Add -Wundef, -Wno-undef. + * c-decl.c (c_decode_option): Ignore -Wundef, -Wno-undef. + + * cccp.c, cexp.y (warn_undef): New variable. + * cpplib.h (struct cpp_options): New member warn_undef. + (CPP_WARN_UNDEF): New macro. + + * cccp.c (main), cpplib.c (cpp_handle_options): Set warn_undef + from -Wundef and -Wno-undef. + + * cppexp.c (cpp_lex) New arg skip_evaluation. + (cpp_parse_expr): Pass skip_evaluation to cpp_lex. + Abort if cpp_lex returns NAME. + + * cexp.y (exp), cppexp.c (cpp_lex): Optionally warn about undefined + identifiers that evaluate to 0. + +Sun Apr 13 11:43:16 1997 Joel Sherrill + + * configure (hppa1.1-*-rtems*): New target. + * mips/rtems.h: New file. + +Sun Apr 13 09:48:26 1997 Richard Kenner + + * gcov.c (print_usage, open_files): Use FATAL_EXIT_CODE. + * collect2.c (fatal_perror, fatal, collect_wait): Likewise. + + * sparc.c (eligible_for_delay_slot): Clean up and make to agree + precisely with patterns in MD file. + * sparc.md (*return_addsi): Change condition to exclude both ints. + (*return_adddi): Likewise. + (*return_subsi): New pattern. + + * recog.c (validate_replace_rtx_1, case MINUS): New case. + +Sun Apr 13 08:20:24 1997 Thomas Bushnell + + * i386/gnu.h (TARGET_VERSION): Redefine. + +Sun Apr 13 08:15:31 1997 Bernd Schmidt + + * c-typeck.c (lookup_field): Don't recurse unless FIELD is + a RECORD_TYPE or UNION_TYPE. + + * final.c (profile_function): Save the static chain register + around the call to the profiler function. + + * loop.c (invariant_p, case REG): Pointers into frame are not + invariants if function has nonlocal gotos. + * reload1.c (reload): If function has nonlocal label, mark all + caller-saved regs as used. + +Fri Apr 11 16:49:06 1997 Doug Evans + + * m32r.h (REG_ALLOC_ORDER): Restore to original setting. + + * m32r.h (UPPER16_P): Fix calculation. + * m32r.c (two_insn_const_operand): New function. + (m32r_print_operand): Handle 'X'. + * m32r.md (movsi): Tweak. + (*movsi_insn): Output hex value of constants too. + (movsi define_split): Add. + (andsi3,orsi3,xorsi3): Output hex value of constants too. + +Thu Apr 10 18:39:33 1997 Jim Wilson + + * sh.md (sne): Modified to use negc instead of xor. + (sne+1): New define_split for new sne pattern. + * sh.c (output_stack_adjust): Reorganize code for readability. + If size is negative, negate and subtract it instead of adding it. + +Wed Apr 9 13:51:07 1997 J"orn Rennecke + + * sh.c (output_stack_adjust): When splitting an adjustment into two + parts, make sure the stack is aligned at all times. + +Tue Apr 8 12:34:38 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.h (RETURN_ADDR_RTX): Define. + +Mon Apr 7 19:19:57 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.c (count_tst_insns): New function. + (expand_prologue): Load zero into data and/or address registers + if any are free and the function has optimizable tst insns. + (output_tst): If a suitable register is known to have the + value zero, use it instead of searching for a suitable register. + * mn10300.h (zero_dreg, zero_areg): Declare. + (FRAME_POINTER_NEEDED): Frame pointers are not needed if the + outgoing argument size is zero. + * mn10300.md (movXX): Optimize loading zero into an address + register if possible. Optimize loading a DF/DI mode value + into an address register from a constant memory address. + (addsi3): Provide alternative which doesn't require a matching + inout operand. + (return): Optimize consecutive return instructions. + +Mon Apr 7 17:30:35 1997 J"orn Rennecke + + * mips/iris5.h (SUBTARGET_CC1_SPEC): Define. + (LINK_SPEC, STARTFILE_SPEC): Support -static. + * mips/iris6.h (SUBTARGET_CC1_SPEC): Define. + (STARTFILE_SPEC, LINK_SPEC): Support -static. + * mips.h: (SUBTARGET_CC1_SPEC): Define. + (CC1_SPEC): Add subtarget_cc1_spec. + (EXTRA_SPECS): Add subtarget_cc1_spec. + +Sun Apr 6 12:24:53 1997 Richard Earnshaw (rearnsha@armltd.co.uk) + + * arm.md (incscc): Use a match_operand with cc_register to match + the condition code register. + (decscc, *condbranch, *condbranch_reversed, *mov_scc): Likewise. + (*mov_negscc, *mov_notscc, *cond_return): Likewise. + (*cond_return_inverted, *ior_scc, *cond_move): Likewise. + (insv): New expand. + (andsi_notsi_si): Renamed from *andsi_notsi_si. + (andsi_not_shiftsi_si): New insn. + (*minmax_arithsi): Don't match this insn if operand1 is an + eliminable register. + ({sin,cos}*): Delete, since the ARM always emulates these its + faster to call a library function. + (movsicc, *movsicc_insn): Make operand0 an s_register_operand, + and operand3 an arm_not_operand. Use cc_register to match the + condition code register. + (mov[sd]fcc*): Make operand[0,2] s_register_operands, and operand3 + the nonmemory_operand. Use cc_register to match the condition + code register. + (*ifcompare_plus_move): Move before *ifcompare_arith_move. Just do + a split for the output. + (*ifcompare_move_plus): Similarly, but relative + to *ifcompare_move_arith. + (*if_plus_move, *if_move_plus): New patterns. + (*ifcompare_arith_arith): Simplify the alternatives down to just one, + and split the insn before output. + (*if_arith_arith, *if_arith_move, *if_move_arith): New patterns. + (*ifcompare_move_not, *ifcompare_not_move): Simplify and split the + insn before output. + (*if_move_not, *if_not_move): New patterns. + (*ifcompare_shift_move, *ifcompare_move_shift): Simplify and split the + insn before output. + (*if_shift_move, *if_move_shift): New patterns. + (*ifcompare_shift_shift): Simplify and split the insn before output. + (*if_shift_shift): New pattern. + (*ifcompare_not_arith, *ifcompare_arith_not): Simplify and split the + insn before output. + (*if_not_arith, *if_arith_not): New patterns. + (*ifcompare_neg_move, *ifcompare_move_neg): Simplify and split the + insn before output. + (*if_neg_move, *if_move_neg): New patterns. + +Sat Apr 5 20:17:43 1997 Michael Meissner + + * rs6000/sol-ci.asm (_environ): Don't make _envrion a common + variable, the lastest assembler doesn't let common variables also + be a weak symbol. + +Fri Apr 4 18:30:12 1997 Jim Wilson + + * rs6000.md (adddi3): Use non_short_cint_operand instead of + non_add_cint_operand. + +Thu Apr 3 15:08:39 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.c (can_use_return_insn): Add size of fixed stack space + for function calls into the size of the frame. + (expand_prologue, expand_epilogue): Likewise. + (initial_offset): Corresponding changes.. + * mn10300.h (OUTGOING_REG_PARM_STACK_SPACE): No longer define. + (STACK_POINTER_OFFSET): Define. + * mn10300.md (call, call_value expanders): Don't adjust the stack + pointer here anymore. + + * mn10300.md (ashlsi3): Remove some alternatives which are no longer + needed or desired. + +Thu Apr 3 15:06:53 1997 Jim Wilson + + * local-alloc.c (no_conflict_p): Reject sequences with foreign insns. + + * combine.c (move_deaths): Handle partial REG_DEAD note for + multi-reg hard register. + + * function.c (expand_function_start): Emit queue after expanding + each dynamic parameter type. + + * mips.c (mips_move_2words): Add SIGN_EXTEND support for SYMBOL_REF, + LABEL_REF, and CONST operands. + + * dwarf2out.c: Delete comment referring to README.DWARF. + +Wed Apr 2 17:21:23 1997 Jim Wilson + + * rs6000.md (ashrdi3_power): Mark alternative 0 as early_clobber + output. + + * rs6000.md (abssi3_nopower define_split): Switch operands of MINUS. + (nabssi3_nopower define_split): Likewise. + +Tue Apr 1 19:30:01 1997 Mike Stump + + * libgcc2.c (find_exception_table): Fix to logic to deal with + functions that are in their own section, such as template + instantiations, that cause overlapping EH tables. + +Tue Apr 1 17:16:22 1997 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (USER_H): Add va-mn10300.h + + * ginclude/stdarg.h: Include va-mn10300.h. + * ginclude/varargs.h: Likewise. + * ginclude/va-mn10300.h: New file. + * mn10300.c (expand_prologue): If current_function_varargs is nonzero, + flush d0/d1 back into stack. + (mn10300_builtin_saveregs): New function. + (function_arg, function_arg_partial_nregs): New functions. + (initial_offset): Tweak now that the RP save area is allocated + and deallocated around each call again. + * mn10300.h (FIRST_PARM_OFFSET): Now 4. + (FRAME_POINTER_REQUIRED): Require frame pointer for all non-leaf fcns. + (REG_PARM_STACK_SPACE): Now 8 bytes. + (FUNCTION_ARG_REGNO_P): Update for new parameter passing conventions. + (CUMULATIVE_ARGS, INIT_CUMULATIVE_ARGS): Likewise. + (FUNCTION_ARG_ADVANCE, FUNCTION_ARG): Likewise. + (FUNCTION_ARG_PARTIAL_NREGS): Likewise. + (TRAMPOLINE_TEMPLATE): Don't clobber d0 anymore. + (TRAMPOLINE_SIZE, INITIALIZE_TRAMPOLINE): Corresponding changes. + (EXPAND_BUILTIN_SAVEREGS): Define. + * mn10300.md (call, call_value patterns): Allocate and deallocate + stack slot for return pointer around each call. + + * mn10300.h (RTX_COSTS): Refine. + (CASE_VALUES_THRESHHOLD, NO_FUNCTION_CSE): Likewise. + * mn10300.c (output_tst): New function. + * mn10300.md (movdi, movdf): Improve code to load constants into regs. + (tst insns): Use output_tst to optimize some cases. Add versions to + encourage more zero extensions instead of sign extensions of HImode + and QImode values. + (divsi3, udivsi3): Remove patterns. Replaced by... + (divmodsi4, udivmodsi4): New expanders/patterns. + (andsi3): Optimize "and" operations with certain constants. + +Tue Apr 1 09:14:29 1997 J"orn Rennecke + + * sh.h: (ADJUST_COSTS): Define. + +Fri Mar 28 17:46:13 1997 Jim Wilson + + * Makefile.in (LANGUAGES): Add gcov. + (OBJS): Add profile.o. + (STAGESTUFF): Add gcov. + (profile.o, gcov.o, gcov): Add rules to build them. + (install-common): Install gcov. + * combine.c (distribute_notes): Handle REG_BR_PROB and REG_EXEC_COUNT + REG_NOTES. + * sparc.h (OVERRIDE_OPTIONS): Check profile_arc_flag. + * final.c (LONG_TYPE_SIZE): Define. + (count_instrumented_arcs): New variable. + (end_final, profile_after_prologue, leaf_function_p): Add support + for profile_arc_flag. + (add_bb): Only call CC_STATUS_INIT if HAVE_cc0. + * flags.h (profile_arc_flag, flag_test_coverage, + flag_branch_probabilities): Declare. + * function.c (expand_function_end): Output NOTE_REPEATED_LINE_NUMBER + for last line of function. + * integrate.c (expand_inline_function): Output + NOTE_REPEATED_LINE_NUMBER after inlined call. + * jump.c (jump_optimize, follow_jumps, mark_jump_label): Disable some + optimizations when flag_test_coverage and there is a line number note + in the way. + (invert_jump): Add REG_BR_PROB when flag_branch_probabililties. + * libgcc2.c (__bb_exit_func): Support gcov style output. + * reorg.c (mostly_true_jump): Use REG_BR_PROB notes when + flag_branch_probabilities. + * rtl.c (note_insn_name): Add NOTE_REPEATED_LINE_NUMBER. + (reg_note_name): Add REG_BR_PROB and REG_EXEC_COUNT. + * rtl.h (enum reg_note): Add REG_BR_PROB and REG_EXEC_COUNT. + (REG_BR_PROB_BASE): Define. + (NOTE_REPEATED_LINE_NUMBER): Define. + * sched.c (update_flow_info): Handle REG_EXEC_COUNT and REG_BR_PROB + notes. + * toplev.c (branch_prob_dump, profile_arc_flag, flag_test_coverage, + flag_branch_probabilities, branch_prob_dump_file, branch_prob_time): + New variables. + (f_options): Add profile-arcs, test-coverage, and + branch-probabilities. + (compile_file): Set branch_prob_time. Pass flag_test_coverage to + init_emit_once. Handle branch_prob_dump. Call init_branch_prob. + Call end_branch_prob. Call output_func_start_profiler. + (rest_of_compilation): Handle branch_prob_dump. Call new + branch_prob pass. + (main): Set branch_prob_dump. + * gcov.c, profile.c, gcov-io.h, gcov.texi: New files. + +Thu Mar 27 16:52:52 1997 Stan Cox + + * i386.h (CPP_CPU_DEFAULT): Define if TARGET_CPU_DEFAULT is not set. + * i386.h (STACK_BOUNDARY): Define to always be 32. + + From J"orn Rennecke + * i386.md: (zero_extendhisi2+[12]): Use true_regnum instead of + REGNO for operand 0. + (zero_extendqisi2+3): Use reg_overlap_mentioned_p instead of REGNO + comparison; use true_regnum instead of REGNO for rtx generation. + +Wed Mar 26 12:34:21 1997 Ian Lance Taylor + + * reload1.c (reload): Call reload_cse_regs. + (reg_values): New static variable. + (reload_cse_invalidate_regno): New static function. + (reload_cse_mem_conflict_p): New static function. + (reload_cse_invalidate_mem): New static function. + (reload_cse_invalidate_rtx): New static function. + (reload_cse_regs): New static function. + (reload_cse_regno_equal_p): New static function. + (reload_cse_noop_set_p): New static function. + (reload_cse_simplify_set): New static function. + (reload_cse_check_clobbered): New static variable. + (reload_cse_check_src): New static variable. + (reload_cse_check_clobber): New static function. + (reload_cse_record_set): New static function. + +Wed Mar 26 07:34:06 1997 Ulrich Drepper + + * ginclude/stdarg.h (__va_copy): New definition. + +Tue Mar 25 13:43:36 1997 Michael Meissner + + * gcc.c (init_spec): If -v, print out that the default spec values + were being used. Fix prototype to reflect no arguments. + (set_spec): If specs has not been set, set it up with the default + specs. + (read_specs): Move to later in the file so that startfile_prefixes + has been declared. Process "%include " to include another + specs file, aborting if the file can't be found. Process + "%include_noerr : to include another specs file, giving no + error if the file can't be found. Process "%rename var1 var2" to + rename a specs variable. Take new argument that indicates whether + we are processing the main file. Only process % commands if this + is not the main specs file. Change callers. + (main): Do not call init_spec if a specs file was found. + (set_spec,read_specs,do_spec_1): If DEBUG_SPECS is defined, print + debug information. + +Tue Mar 25 14:43:58 1997 Doug Evans + + * expr.c (emit_push_insn): Delete emission of CLOBBER + when doing partial push, no longer necessary. + + * c-decl.c (grokdeclarator): Pedwarn qualified void function return + type. + +Tue Mar 25 14:28:15 1997 Richard Earnshaw (rearnsha@armltd.co.uk) + + * reload.c (find_dummy_reload): New parameter earlyclobber. If set + then don't use IN for the reload if it also appears elsewhere in + the insn. All callers changed. + +Tue Mar 25 13:20:18 1997 J.T. Conklin + + * m68k/lb1sf68.asm (udivsi3): Fix hunk from previous patch that + did not apply correctly. + + * m68k.md (tablejump): Use extl to explicitly sign extend + index registeron TARGET_5200. + * m68k/{apollo68.h,coff.h,linux.h,mot3300.h,pbb.h} + (ASM_RETURN_CASE_JUMP): Likewise. + + * m68k.md (mulsi3): Changed into define_expand. Split insn into + m68k and coldfire specific versions with appropriate constraints. + + * m68k.md (movqi): Disable use of address registers for + TARGET_5200. + + * m68k/lb1sf68.asm (__modsi3, __umodsi3): Use mulsl instruction + instead of __mulsi3 function call on the coldfire. + + * m68k.md (bne0_di): Fix typo in last change. + + * m68k.md (xorsi3_5200): Correct constraints. + + * m68k.c (output_move_{si,hi,qi}mode): New functions. + * m68k.h (output_move_{si,hi,qi}mode): Declare. + + * m68k.md (move{si,hi,qi,di}): Changed into define_expands. Split + insns into m68k and coldfire specific versions with appropriate + constraints. + +Tue Mar 25 12:18:41 1997 Richard Kenner + + * Makefile.in (GCC_PASSES): Revert previous change; use cc1$(exeext). + +Mon Mar 24 16:12:20 1997 Doug Evans + + * m32r/*: New files. + * config.sub: Add m32r. + * configure: Add m32r. + * longlong.h: Add m32r support. + * ginclude/{stdarg.h,varargs.h}: Add m32r support. + * ginclude/va-m32r.h: New file. + +Mon Mar 24 15:53:15 1997 Joel Sherrill + + * rs6000/rtems.h: Change to a near clone of the powerpc-eabi target. + * configure (powerpc*-*-rtems): Move before GNU/Linux configuration. + +Mon Mar 24 14:26:37 1997 Gavin Koch + + * ginclude/va-mips.h: For little endian, eabi, objects + less than __va_reg_size are passed in registers. + +Fri Mar 21 00:48:02 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.c (print_operand): Handle 'N'. + + * mn10300.c (expand_epilogue): Correctly handle functions + with large frames, but no callee register saves. + + * mn1300.md (movdf, movdi): Handle overlapping moves. + + * pa.c (compute_movstrsi_length): Handle residuals correctly. + +Thu Mar 20 13:53:30 1997 Michael Meissner + + * rs6000.c (easy_fp_constant): If -mrelocatable, consider all fp + constants to be hard. + +Mon Mar 20 13:53:30 1997 Jim Wilson + + * rs6000.md (movdf/movsf define_splits): Add SUBREG support. + + * rs6000.c (fp_reg_or_mem_operand): Delete. + * rs6000.h (PREDICATE_CODES): Remove fp_reg_or_mem_operand. + (fp_reg_or_mem_operand): Delete declaration. + * rs6000.md (movsf_hardfloat): Use nonimmediate_operand instead + of fp_reg_or_mem_operand. + +Thu Mar 20 08:52:27 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.md (cmpsi): Handle comparing a register with + itself by adding zero to the reg. Z bit for such an insn is + inverted. + * mn10300.c (notice_update_cc): Handle CC_INVERT. + + * pa.c (emit_move_sequence): Don't lose for a secondary reload + to the SAR register if the input is a MEM with an offset that won't + fit in 14bits. + +Wed Mar 19 17:10:44 1997 Andreas Schwab + + * m68k/linux.h (ASM_OUTPUT_MI_THUNK): Define. + +Wed Mar 19 16:59:34 1997 Paul Eggert + + * cccp.c, cpplib.c (do_error, do_warning): Fix memory leak. + + * cccp.c (output_line_directive): Do not output negative line + numbers when analyzing directives like `#line 0'. + + * cexp.y (parse_number, yylex), cccp.c (rescan), cpplib.c + (cpp_get_token): Unless -lang-c89 is specified, allow C9X-style + hexadecimal floating-point numbers as preprocessor numbers. + * cccp.c (c89): New decl. + (main): Set it to 1 if -lang-c89. + * cpplib.h (struct cpp_options): New member c89. + (CPP_C89): New macro. + * cpplib.c (unsafe_chars): `p' is unsafe before `-' or `+', since it + might generate a C9X-style hexadecimal floating-point number. + (cpp_handle_options): Set c89 option to 1 if -lang-c89. + +Tue Mar 18 17:05:57 1997 Stan Cox + + * i386.h (STACK_BOUNDARY): Determine according to TARGET_ALIGN_DOUBLE. + + * i386.c (override_options) Make the default alignment 4 for 486, + otherwise 2. + + * i386/freebsd-elf.h (CPP_SPEC): Remove TARGET_CPU_DEFAULT reference. + * i386/linux{,-aout,-oldld}.h (CPP_SPEC): Likewise. + + * i386/go32.h (DBX_DEBUGGING_INFO, PREFERRED_DEBUGGING_TYPE, + NO_STAB_H, ASM_FILE_START, DBX_BLOCKS_FUNCTION_RELATIVE, + DBX_FUNCTION_FIRST, DBX_OUTPUT_MAIN_SOURCE_FILE_END, + ASM_OUTPUT_SOURCE_LINE): Added to support stabs. + (ASM_OUTPUT_SECTION_NAME): Support section attribute. + +Tue Mar 18 16:12:28 1997 Jim Wilson + + * final.c (shorten_branches): Split all insns before computing insn + lengths. + (final_scan_insn, case default): If HAVE_ATTR_length defined, call + abort for any insn that has a '#' output template. + + * expr.c (emit_group_load): Call operand_subword instead of creating + an explicit SUBREG. + + * reload1.c (reload_reg_free_before_p, case + RELOAD_FOR_OPERAND_ADDRESS): Conflicts with RELOAD_FOR_OPADDR_ADDR + reloads. + + * configure (alpha-dec-osf[23456789]*): Use install-headers-cpio + for osf4. + + * gcc.c (init_spec): Delete parameter. Always initialize extra_specs. + (process_command, main): Change all callers. + + * combine.c (if_then_else_cond): Call copy_rtx to prevent sharing. + +Tue Mar 18 14:59:12 1997 Ian Lance Taylor + + * function.c (assign_parms): Add a REG_EQUIV note to the + instruction which copies a parameter into a pseudo-register + whenever there is an associated stack slot, even if the parameter + actually arrived in a register. + +Tue Mar 18 14:24:48 1997 Doug Evans + + * configure (alpha-dec-osf[23]): Separate osf[23] case. + * alpha.h (LIB_SPEC): -lprof1 requires -lpdf for OSF 4. + * alpha/osf2or3.h: New file. + +Tue Mar 18 11:32:10 1997 Jeffrey A Law (law@cygnus.com) + + * m68k.c (m68k_last_compare_had_fp_operands): New variable. + * m68k.h (m68k_last_compare_had_fp_operands): Declare it. + * m68k.md (tst*, cmp*): Turn into define_expand/define_insn pairs. + Keep track of whether test/compare has fp operands. + (seq, sne, sgt, slt, sge, sle): Turn into define_expand/define_insn + pairs. Make expanders FAIL if TARGET_68060 and last comparison/test + had fp operands. + +Tue Mar 18 04:29:29 1997 Richard Earnshaw + + * arm.md (movhi): Handle generation of large constants during + and after reload. + +Mon Mar 17 17:30:24 1997 Brendan Kehoe + + * gmicro.h (RETURN_POPS_ARGS): Make sure FUNDECL is non-nil + before we try to use it. + * m68k.h (RETURN_POPS_ARGS): Likewise. + * ns32k.h (RETURN_POPS_ARGS): Likewise. + * pyr.h (RETURN_POPS_ARGS): Likewise. + +Mon Mar 17 17:13:44 1997 J"orn Rennecke + + * stor-layout.c (layout_record, PCC_BITFIELD_TYPE_MATTERS): + Only add padding if a bit field would otherwise span more units + of alignment than its base type. + +Mon Mar 17 17:03:55 1997 J.T. Conklin + + * m68k.md (beq0_di, bne0_di, bge0_di, blt0_di): Use cmpw #0 + instead of tstl when testing address registers on the 68000. + + * m68k/lb1sf68.asm: Fix prologues/epilogues to deal with the lack + of predecrement/postincrement addressing modes in the coldfire + moveml instruction. + +Mon Mar 17 17:00:14 1997 Scott Christley + + * Fix long standing bug where first method call for a class could + result in a garbled stack or produce an incorrect return value. + * objc/sendmsg.c (__objc_block_return): Remove function. + (__objc_word_return, __objc_double_return): Remove functions. + (__objc_get_forward_imp): New function. + (__objc_init_dispatch_tables): Install zero instead of + __objc_init_install_dtable. + (__objc_init_install_dtable): No longer call the method but + allow objc_msg_lookup return it for normal execution. + (obj_msg_lookup): Differentiate between when a method isn't + implemented and when the dispatch table needs to be installed. + Return the IMP when the dispatch table is installed versus + having __objc_init_install_dtable call it. + (get_imp): Install dispatch table if needed and return IMP + from the newly installed dispatch table. + (__objc_responds_to): Install dispatch table if needed before + checking if method is implemented. + +Mon Mar 17 16:29:38 1997 Richard Kenner + + * tree.c (build_{index,range}_type): Ensure expressions for min + and max value are in same obstack as type. + +Mon Mar 17 15:44:18 1997 Pat Rankin + + * cccp.c [#if VMS] (O_RDONLY, O_WRONLY): Delete (redundant). + (BSTRING): Delete (obsolete; usage occurs prior to definition). + (do_include): Handle old VAX C style includes better. + +Mon Mar 17 13:46:47 1997 Paul Eggert + + * cexp.y, cppexp.c (parse_number): Invalid integer constants are + errors if pedantic. + * cexp.y (yylex): Invalid multibyte characters are errors if pedantic. + * cppexp.c (cpp_lex): Likewise. + * cppexp.c (cpp_parse_escape): Character constants that do not fit are + errors if pedantic. + + * c-parse.in (expr_no_commas): Do not store temporary + skip_evaluation increments on yacc value stack. + +Sun Mar 16 19:54:49 1997 Richard Kenner + + * expr.c (expand_expr, case PLACEHOLDER_EXPR): Refine which + object is picked. + +Sun Mar 16 15:45:45 1997 Jeffrey A Law (law@cygnus.com) + + * loop.c (strength_reduce): Adjust BENEFIT appropriately if an + autoincrement memory reference will eliminate add insns. + +Sun Mar 16 08:41:40 1997 Scott Christley + + * i386.md (untyped_call): Re-enable code. + * objc/sendmsg.c (__objc_block_return): New function. + (__objc_word_return, __objc_double_return): New functions. + (__objc_init_install_dtable): Call appropriate return function + based upon method type. + * objc/thr-pthreads.c: Correct include path. + +Sat Mar 15 07:58:33 1997 Scott Christley + + * objc-act.c (OBJC_VERSION): Increment version. + * objc/init.c (OBJC_VERSION): Likewise. + +Sat Mar 15 07:58:00 1997 Ovidiu Predescu + + * Implement +load. + * objc/init.c (objc_send_load, __objc_send_load): New functions. + (__objc_send_message_in_list): New function. + (__objc_force_linking): New function. + (__objc_exec_class): Don't call _objc_load_callback here. + * objc/linking.m: New file. + * objc/sendmsg.c (class_add_method_list): Check for the +load method + when adding a methods list to a class. + * objc/Makefile (OBJC_O): Add linking.m. + + * Allow methods defined in categories to override methods that are + defined in the class implementation. + * objc/sendmsg.c (__objc_install_methods_in_dtable): New function. + (class_add_method_list): Don't check anymore for duplicate methods. + + * config/nextstep.h (INCLUDE_DEFAULTS): Define to something useful + when cross-compiling. + + * The static instances list moved from the objc_module struct to + objc_symtab struct, at the end of defs array. This now allows the NeXT + gdb to work with binaries generated for the GNU ObjC runtime. + * objc-act.c (build_objc_symtab_template): Make sure + defs in objc_symtab is a NULL terminated array. + (init_def_list): Attach statics to end of def list. + (init_objc_symtab): Take statics list into account. + (init_module_descriptor, build_module_descriptor): Don't add statics. + (generate_static_references): Indicate that statics are used. + (finish_objc): Process statics in the beginning. + * objc/objc-api.h (objc_module): Eliminate statics variable. + * objc/init.c (__objc_exec_class): Access statics from their + new place in the defs variable. + +Sat Mar 15 07:29:15 1997 J"orn Rennecke + + * reload.c: Include expr.h. + (find_reloads_address, find_reloads_address_1): New argument INSN. + (find_reloads_address_1): Reload inside of p{re,ost}_{in,de}c + instead of entire p{re,ost}_{in,de}c where appropriate. + * Makefile.in (reload.o): Added expr.h to dependencies list. + +Sat Mar 15 07:17:12 1997 Richard Henderson + + * reload.h (eliminate_regs): Add STORING arg. + * reload1.c (eliminate_regs): Likewise. + (eliminate_regs, case SET): Pass that we are storing to recursive call. + (eliminate_regs, case SUBREG): If storing and same number of words, + use larger mode. + * caller-save.c, dbxout.c, dwarfout.c, dwarf2out.c, reload.c, sdbout.c: + Change all calls to eliminate_regs. + +Fri Mar 14 14:18:49 1997 Ian Lance Taylor + + * cplus-dem.c: Add prototypes for all static functions. + (mystrstr): Make static. Make arguments and result const. + (cplus_match): Remove; not used. + +Fri Mar 14 10:15:35 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.c (const_costs): Remove unused function. + * mn10300.h (CONST_COSTS): Rework to generate better code. + + * mn10300.c (print_operand): Handle 'H' and 'L' output + modifers for high/low part of a 64bit value. + * mn10300.h (CONST_DOUBLE_OK_FOR_LETTER_P): Handle 'G' + (LEGITIMATE_CONSTANT_P): Allow any constant. + * mn10300.md (movdi, movdf): Implement. + (adddi3, subdi3): New expanders and patterns. + + * mn10300.c (print_operand): Handle 'A' modifier for an + address which can't be simple register indirect. + * mn10300.h (EXTRA_CONSTRAINT): Handle 'R' for bit ops. + * mn10300.md: Add patterns to test, set and clear bitfields. + + * mn10300.c (can_use_return_insn): New function. + (expand_epilogue): Emit a RETURN insn if possible. + * mn10300.md (return): New pattern. + + * mn10300.h (CONST_OK_FOR_LETTER_P): Handle 'N'. + * mn10300.md (andsi3): Catch "and 255,dn" and "and 65535,dn" + which were not turned into zero_extend patterns. + + * mn10300.h (GO_IF_LEGITIMATE_ADDRESS): Handle symbolic + constant as an index/base too. + + * mn10300.md (movsi): Allow SP to be loaded/saved with + reg+d8 addresses. + + * mn10300.md (cmpsi): Allow second operand to be a constant. + (subsi3): Likewise. + + * mn10300.md (sign extension patterns): Fix thinko when + extending from memory. + + * mn10300.md (tst peepholes): Add peepholes for test/branch + based on N bit being set/clear and the data value being tested dies. + +Tue Mar 11 17:07:51 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.c (expand_prologue): Rework so that eliminating + the frame pointer produces faster/smaller code. + (expand_epilogue): Likewise. + (initial_offset): New function for argument pointer and frame pointer + elimination. + * mn10300.h (FIRST_PSEUDO_REGISTER): Bump to 10. + (FIXED_REGISTERS): Add argument pointer register, it's a fake fixed + register. + (CALL_USED_REGISTERS, REG_ALLOC_ORDER): Corresponding changes. + (REGNO_REG_CLASS, REG_CLASS_CONTENTS): Likewise. + (REG_OK_FOR_BASE_P, REGISTER_NAMES): Likewise. + (reg_class, REG_CLASS_NAMES): Delete unwanted DATA_OR_SP_REGS class. + (PREFERRED_OUTPUT_RELOAD_CLASS): Define. + (FIRST_PARM_OFFSET): No longer include register save area in + computation. + (STACK_POINTER_REGNUM): Is now register 9. + (ARG_POINTER_REGNUM): Is now register 8. + (FRAME_POINTER_REQUIRED): Refine. + (ELIMINABLE_REGS, INITIAL_ELIMINATION_OFFSET): Define. + (CAN_DEUG_WITHOUT_FP): Define. + * mn10300.md (return_internal): Break into two patterns. + + * mn10300.h (CONST_OK_FOR_LETTER_P): Handle 'M' too. + (REGISTER_MOVE_COST): Fix errors and refine. + + * mn10300.c (notice_update_cc): SET_ZN_C0 insns leave the + overflow bit in an unuseable state. Rename CC_SET to CC_TST. + * mn10300.md (cc attributes): "set" is gone, replaced by + "tst". Update attributes on various insns. + + * mn10300.md: Improve sign and zero extension instructions. + (ashlsi3): Improve. Handle address registers too. + (add peephole): Combine two consecutive adjustments of a register + into a single adjustment. + +Tue Mar 11 17:18:40 1997 Brendan Kehoe + + * cplus-dem.c (gnu_special): Call demangled_fund_type for other + __t* symbols. + +Mon Mar 10 16:10:34 1997 Richard Kenner + + * emit-rtl.c (subreg_lowpart_p): Return 0 if SUBREG_REG is VOIDmode. + * combine.c (simplify_rtx, case SUBREG): Fix direction of test when + calling operand_subword; use inline code intead of subreg_lowpart_p. + +Fri Mar 7 09:22:28 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.c (expand_{pro,epi}logue): Rework to avoid + unnecessary "add" operations. + (expand_epilogue): Likewise. + * mn10300.h (STARTING_FRAME_OFFSET): Is zero after the last + round of prologue/epilogue changes. + (FIRST_PARM_OFFSET): Is now 16 (-4 for REG_PARM_STACK_SPACE + 20 for + register save area). + (REG_PARM_STACK_SPACE): Define as 4 bytes. + (OUTGOING_REG_PARM_STACK_SPACE): Define so caller allocates it. + * mn10300.md (call{,_value} expander): Don't emit insns to adjust the + stack here anymore. + + * mn10300.md (bCC patterns): Just use "bCC target". + +Tue Mar 4 13:21:41 1997 Jim Wilson + + * rs6000.md (movsi): Don't emit a USE insn for LABEL_REFs. + +Thu Mar 6 16:29:13 1997 Jim Wilson + + * dwarf2out.c (modified_type_die): Initialize item_type to NULL. + Move equate_type_number_to_die call before use of sub_die, and move + recursive modified_type_die calls on item_type after it. + + * dwarfout.c (root_type_1, write_modifier_bytes_1): New functions. + (root_type): Call root_type_1. + (write_modifier_bytes): Call write_modifier_bytes_1. + (output_type, case POINTER_TYPE): Set TREE_ASM_WRITTEN before + recursive call. + +Wed Mar 5 14:30:49 1997 Torbjorn Granlund + + Partially undo Jan 11 changes (nor takes only register ops): + * mips.md (*norsi3_const, *nordi3_const): Delete bogus patterns. + * mips.c (complemented_arith_operand): Delete function. + (print_operand): Don't handle `e' for CONST_INT. + * mips.h (PREDICATE_CODES): Delete complemented_arith_operand. + +Tue Mar 4 16:38:13 1997 Brendan Kehoe + + * i386.c (i386_return_pops_args): Make sure FUNDECL is non-nil + before we try to use it. + * i386/{isc,next,sco,sco5,scodbx}.h (RETURN_POPS_ARGS): Likewise. + +Mon Mar 3 20:17:54 1997 Gavin Koch + + * ginclude/va-mips.h: __mips_single_float should have + the same effect on vararg lists as __mips_soft_float. + +Mon Mar 3 18:12:01 1997 Michael Meissner + + * rs6000.h (DBX_CONTIN_LENGTH): Undo 2/26 change. + +Mon Mar 3 13:08:20 1997 Jeffrey A Law (law@cygnus.com) + + * combine.c (simplify_rtx): Do nothing with (truncate:mode) if + mode is a partial integer mode. + +Sun Mar 2 17:41:18 1997 Ulrich Drepper + + * ginclude/varargs.h: Add definition of __va_copy. + * va-alpha.h, va-clipper.h, va-h8300.h, va-i860.h: Likewise. + * va-i960.h, va-m88k.h, va-mips.h, va-pa.h, va-ppc.h: Likewise. + * va-sh.h, va-sparc.h, va-spur.h: Likewise. + +Sun Mar 2 13:25:49 1997 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * c-typeck.c (process_init_element): Warn and truncate if upper + bound of index is out of range. + +Fri Feb 28 16:08:47 1997 Michael Meissner + + * rs6000/sol-c0.c (_start): Disable loading up r13 and r2 with the + SDA base registers for now. + + * rs6000.md (movsi): Emit a USE insn when putting the + label of constants into the TOC, so that the constant is still + emitted when expensive optimizations are used. + +Thu Feb 27 17:54:42 1997 Karl Heuer + + * fixinc.ptx: Fix sed expression looking for in pwd.h. + +Thu Feb 27 12:11:16 1997 Dennis Glatting + + * fixincludes: Remove more cases of __const__ from math.h on NeXT. + +Wed Feb 26 14:52:27 1997 Michael Meissner + + * reload.c (debug_reload): Remove extra argument to fprintf. + * rs6000.c (output_toc): Make fprintf calls type correct. + + * rs6000.h (DBX_CONTIN_LENGTH): Define as 4000 to avoid AIX + assembler line limit. + +Mon Feb 24 17:56:17 1997 Brendan Kehoe + + * fixincludes: Fix need of prototypes for C++ in rpc/xdr.h on SunOS4. + +Mon Feb 24 17:33:57 1997 Michael Meissner + + * rs6000/xm-sysv4.h (HAVE_STRERROR): Define. + +Sun Feb 23 17:18:28 1997 Jim Wilson + + * rs6000.md (floatsidf2_loadaddr): Correct syntax for cau instruction. + (load_multiple, store_multiple): Call change_address instead of + creating MEM from scratch. + +Thu Feb 20 16:39:15 1997 Jim Wilson + + * unroll.c (unroll_loop): Add check for naive loop that ends with + conditional branch that does not branch back to loop start. + + * reload1.c (reload): Move assign_stack_local call into main loop. + +Thu Feb 20 11:40:46 1997 Jeffrey A Law (law@cygnus.com) + + * pa.md (zero extension patterns): Turn into define_expand and + define_insn pair. + +Wed Feb 19 17:05:38 1997 Jeffrey A Law (law@cygnus.com) + + * pa.c (emit_move_sequence): Don't copy 0.0 (double precision) + directly to memory, go through a reg if reload hasn't started. + * pa.md (main movdf pattern): Don't allow 0.0 (double precision) + to be copied directly to memory. + + * pa/pa-hpux10.h (MD_EXEC_PREFIX): Define appropriately for hpux10. + (MD_STARTFILE_PREFIX): Similarly. + + * pa.h (ASM_OUTPUT_SECTION_NAME): Surround the section name + with '$' if not using GAS. + +Wed Feb 19 16:43:47 1997 J"orn Rennecke + + * sched.c (schedule_insns): If there was no first scheduling pass, + split instructions after reload. + (update_flow_info): Tolerate some idiosyncrasies after reload. + +Wed Feb 19 11:13:51 1997 Jeffrey A Law (law@cygnus.com) + + * combine.c (find_split_point): Don't turn a SIGN_EXTEND into + a series of shifts if either mode is a partial integer mode. + +Mon Feb 17 08:06:02 1997 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * rs6000.c ({,non_}short_cint_operand): Use (unsigned HOST_WIDE_INT). + (non_add_cint_operand, includes_rshift_p): Likewise. + * rs6000.h (CONST_OK_FOR_LETTER_P): Likewise. + (LEGITIMATE_ADDRESS_INTEGER_P, LEGITIMIZE_ADDRESS): Likewise. + +Sun Feb 16 07:55:19 1997 J"orn Rennecke (amylaar@cygnus.co.uk) + + * libgcc2.c (__negdi2, __lshrdi3, __ashldi3, __ashrdi3, __ffsdi2): + Use ANSI style definition with full prototype. + (__muldi3, __udiv_w_sdiv, __udivmoddi4, __divdi3, __moddi3) : Likewise. + (__udivmoddi4, __udivdi3, __cmpdi2, __ucmpdi2) : Likewise. + (__fixunstfdi, __fixtfdi, __fixunsxfdi, __fixxfdi) : Likewise. + (__fixunsdfdi, __fixdfdi, __floatdixf, __floatditf) : Likewise. + (__floatdidf, __floatdisf, __fixunsxfsi, __fixunsdfsi) : Likewise. + (__gcc_bcmp, __eprintf, gopen, gclose, __bb_init_file) : Likewise. + (__bb_init_trace_func, __clear_cache, mprotect) : Likewise. + (__enable_execute_stack, cacheflush, exit) : Likewise. + (find_exception_table, __find_first_exception_table_match) : Likewise. + +Sun Feb 16 07:52:02 1997 Oliver Kellogg (oliver.kellogg@space.otn.dasa.de) + + * 1750a.md (mulqihi3): Corrected. + (tst{hf,tqf}): Simplified. + (movqi): Removed redundant alternative. + (addqi-3,addqi-2,addqi-1): Set/Reset Bit patterns by C. Nettleton. + (many patterns): Introduced operand output modifiers d,t,b,B,w. + * 1750a.c (print_operand): New operand output modifiers d,t,b,B,w. + (simple_memory_operand): Removed. + (one_bit_set_p, which_bit): Added from C. Nettleton's m1750 config. + +Sun Feb 16 07:43:37 1997 Paul Eggert + + * cccp.c (special_symbol): Don't treat "L" in "L'...'" as identifier. + (check_macro_name, collect_expansion, rescan): Likewise. + * cpplib.c (special_symbol, check_macro_name, collect_expansion): + Likewise. + + * cexp.y (parse_c_expression): Don't check for null lexptr + or *lexptr == 0. If yyparse returns nonzero value, abort. + + * cexp.y (yylex): Use is_space, not is_hor_space, to find keyword end. + (is_space): New decl. + (is_hor_space): Removed. + * cccp.c (is_space): Now external. + (is_hor_space): Now static. + +Sun Feb 16 04:55:11 1997 Jason Merrill + + * toplev.c, tree.h (decl_printable_name): Change arguments. + * c-common.c (declare_function_name): Reflect above change. + * final.c (final_start_function): Likewise. + * function.c (init_function_start): Likewise. + * toplev.c (decl_name): Likewise. + (announce_function): Likewise. + (v_message_with_decl): Likewise. + * dwarf2out.c (dwarf2_name): New fn, uses decl_printable_name. + (add_pubname): Use it. + (add_name_and_src_coords_attributes): Use it, add + DW_AT_MIPS_linkage_name if appropriate. + (output_aranges): Use DW_AT_MIPS_linkage_name if present. + +Sat Feb 15 18:45:30 1997 J.T. Conklin + + * m68k.md (cmpsi): Added insn with appropriate constraints for + TARGET_5200; changed condition of existing insn to !TARGET_5200. + +Sat Feb 15 18:26:50 1997 Philippe De Muyter + + * m68k/hp320.h (PRINT_OPERAND_FLOAT): Removed. + (ASM_OUTPUT_{FLOAT,DOUBLE,LONG_DOUBLE}_OPERAND): Defined. + (PRINT_OPERAND): Turned off: use default. + * m68k/news.h (PRINT_OPERAND): Turned off: use default. + (ASM_OUTPUT_{FLOAT,DOUBLE,LONG_DOUBLE}_OPERAND): Defined. + * m68k/tower-as.h (PRINT_OPERAND): Turned off: use default. + (ASM_OUTPUT_{FLOAT,DOUBLE}_OPERAND): Defined. + * m68k/crds.h (PRINT_OPERAND): Turned off: use default. + (ASM_OUTPUT_{FLOAT,DOUBLE}_OPERAND): Defined. + (SGS_NO_LI,STRUCTURE_SIZE_BOUNDARY,IMMEDIATE_PREFIX): Defined. + (NEED_PROBE): Defined instead of HAVE_probe and gen_probe. + (FUNCTION_{PRO,EPI}LOGUE): Do not access FPA registers. + * m68k.c (output_function_prologue): Add CRDS and MOTOROLA probe code. + (print_operand): Do not output '.' if CRDS. + + * gcc.c (set_spec): Fix comment-in-comment typo. + +Sat Feb 15 17:54:23 1997 H.J. Lu (hjl@gnu.ai.mit.edu) + + * Makefile.in (COMPILERS): Moved before GCC_PASSES. + (GCC_PASSES): Use $(COMPILERS) instead of cc1$(exeext). + +Sat Feb 15 17:25:44 1997 Andreas Schwab + + * gcc.c (process_command): Allocate space for terminating null. + +Sat Feb 15 17:21:34 1997 Pat Rankin + + * vax.h (FUNCTION_PROLOGUE): Adjust size by STARTING_FRAME_OFFSET. + * vax/vms.h (FUNCTION_PROLOGUE): Delete. + +Sat Feb 15 08:48:14 1997 Douglas B. Rupp (rupp@gnat.com) + + * configure: Fix setting of CC in no-symlink case. + +Sat Feb 15 08:42:17 1997 Oliver Kellogg (oliver.kellogg@space.otn.dasa.de) + + * expmed.c (expand_divmod): Prefer divmod in same mode over div + in wider mode. + +Sat Feb 15 08:27:50 1997 J"orn Rennecke (amylaar@cygnus.co.uk) + + * fold-const.c (fold): Don't assume a nonexplicit constant cannot + equal an explicit one. + + * i386.md (zero_extendqi[hs]i2+3): Ensure operating on REG. + +Sat Feb 15 08:11:04 1997 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * configure (i[3456]86-*-solaris2*): Correct tm.h filename in + stabs case. + + * a29k.h (STORE_FLAG_VALUE): Write so works on both 32 and 64-bit host. + +Fri Feb 14 16:03:37 1997 Robert Lipe + + * i386/t-sco5 (libgcc{1,2}-elf.a): correct target dependencies. + +Fri Feb 14 16:00:23 1997 H.J. Lu + + * config/svr4.h (DBX_OUTPUT_MAIN_SOURCE_FILE_END): Set + current-section variable to text. + +Wed Feb 12 16:07:34 1997 Brendan Kehoe + + * fixinc.irix: New file. + * configure (mips-sgi-irix[56]): Set fixincludes to fixinc.irix. + +Wed Feb 12 15:40:20 1997 Jim Wilson + + * Makefile.in (LIBGCC2_DEBUG_CFLAGS): New macro. + (LIBGCC2_CFLAGS): Use it. + + * dwarfout.c (output_type): Do early exit only if TYPE_CONTEXT is NULL + or if TYPE_CONTEXT is another type (e.g. a nested type). + +Tue Feb 11 15:53:51 1997 J"orn Rennecke + + * sh.c (calc_live_regs): Exclude RETURN_ADDRESS_POINTER_REGNUM. + Need not save MACL/MACH when not live or in leaf function. + +Mon Feb 10 14:46:32 1997 Jeffrey A Law (law@cygnus.com) + + * stmt.c (group_case_nodes): Recognize more opportunities to + group case nodes. + +Sun Feb 9 14:05:48 1997 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * function.c (assign_stack_temp): Clear MEM flags from reuse. + +Sat Feb 8 17:37:47 1997 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * local-alloc.c (update_equiv_regs): Fix error in last change. + +Fri Feb 7 12:42:34 1997 Mike Stump + + * pa.h (RETURN_ADDR_RTX): Fix to ignore export stubs. + * pa.c (return_addr_rtx): Define. + +Fri Feb 7 13:56:56 1997 Doug Evans + + * cse.c (invalidate_from_clobbers): Delete unnecessary test for + (clobber nil). + + * toplev.c (main): Delete redundant settings of flag_no_inline + and warn_inline if not optimizating. + +Fri Feb 7 10:45:02 1997 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (stmp-multilib-sub): Add missing "else true" + clauses to work around make bug on some systems. + +Fri Feb 7 08:19:43 1997 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * fold-const.c (const_binop): Don't call size_int if low < 0. + + * function.c (instantiate_virtual_regs_1, case USE, CLOBBER): + Fix error in last change. + +Thu Feb 6 17:09:17 1997 Mike Stump + + * except.c (find_exception_handler_labels): Initialize label array + with zeroes. + +Wed Feb 5 22:11:55 1997 Jeffrey A Law (law@cygnus.com) + + * pa.md (post_ldwm): Fix typos. + +Wed Feb 5 15:57:42 1997 Doug Evans + + * m68k/vxm68k.h (WCHAR_TYPE,WCHAR_TYPE_SIZE,SIZE_TYPE): Fix. + (PTRDIFF_TYPE): Define. + +Wed Feb 5 11:19:13 1997 Ian Lance Taylor + + * reload1.c (alter_reg): Don't ask assign_stack_local to round up + to a multiple of BIGGEST_ALIGNMENT, unless a register appears in a + paradoxical subreg. + +Tue Feb 4 19:29:40 1997 Jim Wilson + + * reload.c (find_reloads_address_1, case POST_INC): Don't use + ADDR_TYPE here. + +Tue Feb 4 12:33:45 1997 Jeffrey A Law (law@cygnus.com) + + * flow.c (life_analysis): Delete obvious no-op moves + which use SUBREGs. + +Mon Feb 3 20:00:35 1997 Jim Wilson + + * jump.c (find_cross_jump): Don't allow old-style and volatile asms + to match. + +Mon Feb 3 15:51:31 1997 Doug Evans + + * sparc/sol2.h (ASM_SHORT,ASM_LONG): Set to .uahalf/.uaword. + * sparc/sysv4.h (ASM_LONG): Define. + (ASM_OUTPUT_{FLOAT,DOUBLE,LONG_DOUBLE}): Use ASM_LONG. + +Mon Feb 3 13:01:46 1997 Ian Lance Taylor + + * reload.h (enum reload_type): Add RELOAD_FOR_INPADDR_ADDRESS and + RELOAD_FOR_OUTADDR_ADDRESS. + * reload.c (ADDR_TYPE): New macro. + (push_secondary_reload): Check for new reload types. + (combine_reloads): Likewise. + (find_reloads): Likewise. Convert INPADDR_ADDRESS and + OUTADDR_ADDRESS to OPADDR_ADDR. Check OPADDR_ADDR when looking + for merges. + (find_reloads_address): When reloading an address, use the + ADDR_TYPE macro to get the type of the new reload. + (find_reloads_address_1): Likewise. + (reload_when_needed_name): Add new reload types. + * reload1.c (reload): Add in_addr_addr and out_addr_addr fields to + insn_needs struct. Use them for new reload types, and when + computing in_max and out_max. + (reg_used_in_inpaddr_addr): New static array. + (reg_used_in_outaddr_addr): New static array. + (mark_reload_reg_in_use): Handle new reload types. + (clear_reload_reg_in_use, reload_reg_free_p): Likewise. + (reload_reg_free_before_p, reload_reg_reaches_end_p): Likewise. + (reloads_conflict, merge_assigned_reloads): Likewise. + (emit_reload_insns): Likewise. + (choose_reload_regs): Save arrays for new reload types. + +Sun Feb 2 19:43:17 1997 Scott Christley + + * objc/selector.c (__sel_register_typed_name): Eliminate compiler + warnings with explicit cast. + + * Add condition mutex support to the objc runtime. + * objc/thr-mach.c (objc_condition_{,de}allocate): New functions. + (objc_condition_{wait,broadcast,signal}): New functions. + * objc/thr-pthreads.c (objc_condition_{,de}allocate): New functions. + (objc_condition_{wait,broadcast,signal}): New functions. + * objc/thr-solaris.c (objc_condition_{,de}allocate): New functions. + (objc_condition_{wait,broadcast,signal}): New functions. + * objc/thr.h: Prototypes for new functions. + + * objc/init.c (__objc_runtime_mutex): Eliminate leading underscore + from name of objc mutex and thread structures. + * objc/runtime.h: Likewise. + * objc/thr-{decosf1,irix,mach,os2,posix,pthreads,single}.c: Likewise. + * objc/thr-{solaris,win32}.c: Likewise. + * objc/thr.{c,h}: Likewise. + + * Major reorganization of objc error handling. + * objc/Object.m (-error:): Call objc_error function instead of + using function pointer. + * objc/archive.c: Replace call to abort or __objc_fatal functions + with call to objc_error function throughout the complete file. + * objc/class.c (objc_get_class): Replace call to abort function + with call to objc_error function. + * objc/encoding.c (objc_sizeof_type, objc_alignof_type): Replace + call to abort function with call to objc_error function. + (objc_skip_typespec): Likewise. + * objc/init.c (init_check_module_version): Replace call to + abort function with call to objc_error function. + * objc/misc.c (objc_verror): New function. + (objc_fatal): Remove function. + (objc_set_error_handler): New function. + (_objc_error_handler): New global variable. + (__alpha__): Remove unneeded code. + (objc_error): Allow user specified error handler function to + trap and handle the objc error. Added an error code parameter + which indicates the specific error that occured. + (objc_malloc, objc_atomic_malloc): Replace call to objc_fatal + function with call to objc_error function. + (objc_valloc, objc_realloc, objc_calloc): Likewise. + * objc/objc-api.h: Declare error handling functions and typedef + for user specified error handler function. Define error codes + used by the runtime library. + * objc/runtime.h: Remove error handling declarations. + * objc/sendmsg.c (__objc_forward): Replace call to abort function + with call to objc_error function. + +Sun Feb 2 19:42:52 1997 Thomas Baier + + * objc/hash.c (hash_delete): Step through the hash nodes + versus using hash_next to increase efficiency. + * objc/archive.c (__objc_finish_read_root_object): Use hash + table instead of list. + +Sun Feb 2 08:25:05 1997 Ovidiu Predescu + + * objc-act.c (encode_aggregate_within): New function. + (encode_aggregate): Generates encodings for unions similar + to those for structs except surrounded by parenthesis instead + of braces. + +Sun Feb 2 07:15:54 1997 Mat Hostetter (mat@lcs.mit.edu) + + * c-decl.c (start_function): Fix improper installation of last change. + +Sun Feb 2 06:50:55 1997 Andreas Schwab + + * m68k.c (output_scc_di): Add missing CC_STATUS_INIT. + +Sun Feb 2 06:39:55 1997 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * c-typeck.c (process_init_element): When popping levels, don't + blow up if constructor_max_index not set due to previous error. + + * combine.c (find_split_point, case SET): Fix error in last change. + +Sun Feb 2 06:28:56 1997 Paul Eggert + + * cccp.c (rescan): Insert a space after `.' as well, + to prevent accidental token-pasting (e.g. `.x' -> `.10'). + +Sun Feb 2 06:08:14 1997 Oliver Kellogg (oliver.kellogg@space.otn.dasa.de) + + * 1750a.c (modregno_adjust): Fixed case when reg_renumber invalid. + +Sat Feb 1 19:11:08 1997 J.T. Conklin + + * m68k.md (movqi): Enable use of clr and st insns on TARGET_5200. + * m68k.c (output_move_simode_const): Likewise. + +Sat Feb 1 18:54:00 1997 Douglas B. Rupp (rupp@gnat.com) + + * gcc.c (process_command): Fix improper use of strncpy. + +Fri Jan 31 15:35:08 1997 Mike Stump + + * libgcc2.c: Remove extern for malloc and realloc. + +Fri Jan 31 17:08:11 1997 Ian Lance Taylor + + * local-alloc.c (update_equiv_regs): If register which is equivalent + to some value is only used in one place, and we can't substitute value + for use, move register assignment to just before use. + +Fri Jan 31 15:57:25 1997 Stan Cox + + * i386.md (idiv,imul,fpmul): Added new functional units for pentiumpro. + + * i386.c (pentiumpro_cost): Added new cost structure for pentiumpro. + (override_options): Set ix86_cost to appropriate cost structure. + +Thu Jan 30 09:34:26 1997 J.T. Conklin + + * m68k.md (stack adjust peepholes): Use lea instead of + add.w when adding 16 bit constants on all but TARGET_68040. + +Thu Jan 30 08:58:08 1997 Ralf Baechle + + * function.c (TRAMPOLINE_ALIGNMENT): Provide default. + (expand_function_end): Use TRAMPOLINE_ALIGNMENT instead + of FUNCTION_BOUNDARY. + * varasm.c (TRAMPOLINE_ALIGNMENT): Provide default. + (assemble_trampoline_template): Use TRAMPOLINE_ALIGNMENT instead + of FUNCTION_BOUNDARY. + +Wed Jan 29 18:16:02 1997 J"orn Rennecke + + * sh.h (REG_CLASS_CONTENTS): Add rap to GENERAL_REGS and its + superclasses. + + * sh.md (movsi_i, movsi_ie, movhi_i, movhi+1): Use type pcload for + immediate operands where appropriate. + (movsf_ie+1): Fail when loading anything but a MEM into + a floating point reguister. + +Wed Jan 29 16:00:31 1997 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * varasm.c (force_const_mem): Set MARK instead of clearing it. + (output_constant_pool): Only mark constant pool if -O. + Check mark flag unconditionally. + (mark_constant_pool): Start by clearing all mark flags. + + * tree.c (copy_node): Clear TREE_ASM_WRITTEN. + + * flow.c (regno_uninitialized): Return 0 if reg is used for args. + +Wed Jan 29 15:23:59 1997 Ian Lance Taylor + + * combine.c (try_combine): Clear reg_n_refs if i2dest is not + mentioned in newi2pat. + +Tue Jan 28 16:00:23 1997 Stan Cox (coxs@dg-rtp.dg.com) + + From Robert Lipe + * i386/sco5.h (SCO_DEFAULT_ASM_COFF): Remove bytecode stuff. + (ASM_OUTPUT_ASCII): Use .ascii in both ELF and COFF modes. + (ASM_OUTPUT_SECTION_NAME): Handle alternate sections for COFF. + The OpenServer 5.0.0 assembler gives an error for section + names over 6 characters long, so we catch the "obvious" case + and shorten it. + + * m88k.h (ASM_OUTPUT_SECTION_NAME): Undefine; fails + for exception sections. The 88k ABI specifies 'section' + instead of '.section'. + +Mon Jan 27 13:32:46 1997 J"orn Rennecke + + * sh.c (shl_and_kind): Fix typo. + * sh.md (and_shl_scratch): Fix typo for length 8. + +Mon Jan 27 08:56:03 1997 Jeffrey A Law (law@cygnus.com) + + * fixincludes (sys/time.h): Fix incorrect forward structure + declaration on hpux10.20. + +Mon Jan 27 09:05:35 1997 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * combine.c (simplify_rtx): Don't do anything with if_then_else_cond + result if both one arm and the input are a comparison. + (simplify_{rtx,if_then_else,logical,shift_const}): Don't + test STORE_FLAG_VALUE with #if; properly test for just sign bit. + (num_sign_bit_copies, if_then_else_cond): Likewise. + * expmed.c (emit_store_flag): Properly test for STORE_FLAG_VALUE + of just sign bit. + * fold-const.c (fold): Don't make COND_EXPR when both expr and + one part are comparisons. + * a29k.h (STORE_FLAG_VALUE): Make negative. + +Fri Jan 24 16:42:26 1997 Ian Lance Taylor + + * varasm.c (struct pool_constant): Add mark field. + (force_const_mem): Clear mark field in new constant pool entry. + (output_constant_pool): Call mark_constant_pool. + (mark_constant_pool, mark_constants): New static functions. + +Thu Jan 23 15:04:17 1997 Ian Lance Taylor + + * cse.c (COST): Get the right cost for a SUBREG of a register when + truncation is free. + +Thu Jan 23 11:19:40 1997 Mike Stump + + * Makefile.in (objc-headers): Don't try and install the headers if + the objc directory has been removed. + +Wed Jan 22 13:26:25 1997 Brendan Kehoe + + * i960.c (process_pragma): Call ungetc on the last character + that was read by the while loop, to make sure the parser sees it. + +Tue Jan 21 17:20:30 1997 Michael Meissner + + * rs6000.c (output_toc): Move STRIP_NAME_ENCODING to common + code, so the test for vt's works with -mminimal-toc. + +Tue Jan 21 16:03:35 1997 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * function.c (mark_all_temps_used): Set KEEP as well. + +Tue Jan 21 12:16:15 1997 Doug Evans + + * stor-layout.c (layout_record): Correct test for whether field spans + its unit of alignment in case where field_size == type_align. + +Mon Jan 20 20:27:54 1997 Ian Lance Taylor + + * mips.md (probe): Comment out. + +Sun Jan 19 20:54:45 1997 John F. Carr + + * integrate.c (expand_inline_function): Handle a PARALLEL containing + a RETURN the same as a RETURN. + +Sun Jan 19 20:35:28 1997 Pat Rankin + + * vmsconfig.com: Change all hardcoded references of "vax" to + use variable expansion instead. + (arch_indx, arch): New variables. + + * vax.c (not_qsort): Don't declare alloca. + * vax/xm-vms.h: Declare alloca here. + Do most of the VAX C-specific set up for DEC C. + #if DEC C, undefine QSORT_WORKAROUND and qsort. + * make-gcc.com, make-cccp.com, make-cc1.com: Support building + with GNU C vs VAX C vs DEC C from the DCL command line. + +Sun Jan 19 17:20:50 1997 Oliver Kellogg (oliver.kellogg@space.otn.dasa.de) + + * 1750a.md (movh[if]-1): Corrected. + (movtqf-1): Deleted. + * 1750a.c (add_1_to_mem): Deleted. + (output_operand_address): Added output modifier 'A'. + +Sun Jan 19 17:17:54 1997 Philippe De Muyter + + * m68k.md (ashrdi_const, ashrdi3): Allow 31 as shift count. + + * m68k.h (CONST_OK_FOR_LETTER_P): Recognize 'N', 'O' and 'P'. + * m68k.md (rotl[shq]i3, strict_low_part rotl): Allow 'N', 'O' + or 'P' operands. + +Sun Jan 19 17:09:17 1997 Andreas Schwab + + * m68k.md (addsi3): Fix previous change: {add,sub}qw should + be {add,sub}ql. For other uses of {add,sub}q don't check for address + register and always use {add,sub}ql. + +Sun Jan 19 15:05:42 1997 Peter Seebach + + * c-decl.c (start_decl): Add code for -Wmain. + (c_decode_option): Add -fhosted, -ffreestanding, and -Wmain. + * toplev.c (lang_options): Likewise. + * c-tree.h (warn_main, flag_hosted): New variables. + +Sun Jan 19 14:35:41 1997 Alex Garthwaite (alex@samwise.cis.upenn.edu) + + * fixinc.svr4: Fix problems with symlinks to ".". + +Sun Jan 19 14:21:46 1997 Craig Burley + + * loop.c (check_final_value): Handle insns with no luid's. + +Sun Jan 19 08:57:26 1997 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * alpha.md (arg_home): Add CLOBBER of MEM and USE of arg regs. + * vms.h (SETUP_INCOMING_VARARGS): Delete duplicate definition. + + * toplev.c (set_float_handler): Set up signal catcher on first call + in case a front end has disabled it. + + * cccp.c, cexp.y: #define __attribute__ to be null if + compiling with GCC older than 2.7, not 2.6. + + * toplev.c (main): If PREFERRED_DEBUGGING_TYPE used and set + to NO_DEBUG, say debugging not supported. + * mips/sni-svr4.h (PREFERRED_DEBUGGING_TYPE): Undefine. + + * i386/xm-cygwin32.h (DIR_SEPARATOR): Define. + + * explow.c (convert_memory_address, case SYMBOL_REF): + Copy CONSTANT_POOL_ADDRESS_P. + * integrate.c (save_constants): Make (address (const ..)) to record + both modes. + (copy_for_inline, copy_rtx_and_substitute, restore_constants): Use + both modes when restoring constant pool entry for ADDRESS. + + * alpha.h (MINIMUM_ATOMIC_ALIGNMENT): New macro. + + * function.c (instantiate_virtual_regs_1, case USE, case CLOBBER): + Properly handle case of shared MEM whose replacement is not valid. + +Sat Jan 18 14:08:31 1997 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * tree.c (get_unwidened): Don't crash if FIELD_DECL not layed out. + + * varasm.c (const_hash): Treat NON_LVALUE_EXPR like CONVERT_EXPR. + (compare_constant_1, copy_constant, bc_assemble_integer): Likewise. + (const_hash, compare_constant_1): Use switch, not if-then-else. + +Fri Jan 17 17:10:20 1997 Ian Lance Taylor + + * mips.h (STACK_POINTER_OFFSET): Don't define. + +Thu Jan 16 14:51:03 1997 Bob Manson + + * cplus-dem.c: Fix indenting; note that this file also lives in + libiberty. + (do_type, case 'M'): Check for a template as well as a class. + +Thu Jan 16 15:08:26 1997 Michael Meissner + + * gcc.c (cross_compile): Change to be a char * like all of the + other specs. + (process_command): Change how cross_compile is tested. + (main): Likewise. + (struct spec_list): Merge with the format used by EXTRA_SPECS. + Add name length field to speed up repeated calls to strcmp. Add + flag to say spec was allocated. Add pointer to char * so that + static spec fields can be updated. + (extra_specs): Use struct spec_list as type. + (static_specs): Static list of predefined specs. + (init_specs): New function, initialize the specs list. Link in + the default specs and any specs defined via EXTRA_SPECS. + (set_spec): No longer special case predefined specs. + (process_command,validate_all_switches): Ditto. + (process_command): Call init_specs for -dumpspecs. + (do_spec_1): Use name length field to avoid calling strncmp when + it is going to fail. + (main): Call init_spec. Don't handle EXTRA_SPECS here. + +Thu Jan 16 17:07:54 1997 Eddie C. Dost + + * configure: Add sparc-linux{,aout} support. + * ginclude/va-sparc.h: Likewise. + * sparc/linux.h: New file. + * sparc/linux-aout.h: New file. + * sparc/xm-linux.h: New file. + +Thu Jan 16 16:19:13 1997 Jim Wilson + + * configure (sparc-*-aout*): Add libgloss.h to tm_file. + (sparclite-*-coff*): Change "= to =". + +Thu Jan 16 12:53:15 CST 1997 Joel Sherrill + + * rs6000/rtems.h: Change from being sysv4 based to being eabi based. + +Thu Jan 16 13:40:51 1997 Jim Wilson + + * mips.h (LINKER_ENDIAN_SPEC): Define. + (LINK_SPEC): Add linker_endian_spec. + (EXTRA_SPECS): Add linker_endian_spec. + +Thu Jan 16 08:02:13 1997 Jeffrey A Law (law@cygnus.com) + + * mn10300.md (bCC, inverted bCC): Use bCC .+X instead of bCC 0f. + +Wed Jan 15 14:06:28 1997 Ian Lance Taylor + + * reload.h (reload_address_base_reg_class): Declare. + (reload_address_index_reg_class): Declare. + * reload1.c (reload_address_base_reg_class): Define. + (reload_address_index_reg_class): Define. + (init_reload): Initialize reload_address_{base,index}_reg_class. + * reload.c (find_reloads_address): Use + reload_address_base_reg_class rather than BASE_REG_CLASS. Use + reload_address_index_reg_class rather than INDEX_REG_CLASS. + (find_reloads_address_1): Likewise. + +Tue Jan 14 15:26:33 1997 Ian Lance Taylor + + * reload.c (REGNO_MODE_OK_FOR_BASE_P): Define if not defined. + (REG_MODE_OK_FOR_BASE_P): Define if not defined. + (find_reloads_address): Use REG[NO]_MODE_OK_FOR_BASE_P rather than + REG[NO]_OK_FOR_BASE_P. + (find_reloads_address_1): Likewise. + Add mode parameter; change all callers. + + * reload1.c (eliminate_regs_in_insn): Handle more cases when + eliminating the frame pointer to the hard frame pointer. + + * varasm.c (force_const_mem): Copy a CONST_INT rtx like a CONST rtx. + + * varasm.c (assemble_end_function): Call + output_after_function_constants. + (after_function_constants): New static variable. + (output_after_function_constants): New static function. + (output_constant_def): Check CONSTANT_AFTER_FUNCTION_P. + +Mon Jan 13 16:44:40 1997 David Edelsohn + + * rs6000/aix41.h (CPP_PREDEFINES): Add -D_AIX41. + +Sun Jan 12 20:54:01 1997 Jim Wilson + + * libgloss.h (LINK_SPEC): Delete. + (STARTFILE_SPEC): Delete spurious newline. + +Sat Jan 11 00:13:03 1997 Torbjorn Granlund + + * mips.md (norsi3, nordi3): Use canonical RTL. Prepend `*' to pattern + name. Don't match immediates. + (norsi3_const, nordi3_const): New patterns. + (anddi3, iordi3, xordi3): Test TARGET_64BIT, not mips_isa + in length attribute calculation. + * mips.c (complemented_arith_operand): New function. + (print_operand): Handle `e' for CONST_INT. + * mips.h (PREDICATE_CODES): Add complemented_arith_operand. + +Fri Jan 10 14:11:53 1997 David Edelsohn + + * rs6000/aix41.h (SUBTARGET_SWITCHES): Add threads and pe. + (CPP_SPEC): Add mpe and mthreads cases. + (LIB_SPEC): Add mpe and mthreads cases to variant from rs6000.h. + (STARTFILE_SPEC): Add mpe and mthreads support. + +Fri Jan 10 07:12:26 1997 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * i386/cygwin32.h (LINK_SPEC): New definition. + + * Makefile.in (FLAGS_TO_PASS): Add STAGE_PREFIX, set by configure. + * configure: Initialize exeext. + Update STAGE_PREFIX in Makefile. + + * dwarfout.c (dwarfout_line): Push to LINE_SECTION after calling + lookup_filename. + +Thu Jan 9 12:06:04 1997 Jim Wilson + + * i386.md (addsidi3_2): Add & to operand 0 of alternative 5. + +Thu Jan 9 12:06:04 1997 Stan Cox + + From Linus Torvalds and Mat Hostetter: + * i386.c (i386_sext16_if_const): Added to sign extend HImode constant. + (i386_aligned_reg_p): Added to tell if an rtx is aligned. + (i386_cc_probably_useless_p): Don't trust cc bits. + * i386.h (TARGET_ZERO_EXTEND_WITH_AND): Don't do this for p6. + * i386.md (cmpsf_ccfpeq+2): Use SImode test instruction. + (movhi+1): Use movz instead of mov on p6. + (addsi3): Add 128 by subtracting -128. + (zero_extendhisi2): Use SImode move if aligned. + ({add,sub,and,ior,xor}hi3): Likewise. + +Tue Jan 7 16:58:27 1997 Jason Merrill + + * c-parse.in (extension): New rule for __extension__. + (extdef, unary_expr, decl, component_decl): Use it. + +Mon Jan 6 15:44:37 1997 Oliver Kellogg (oliver.kellogg@space.otn.dasa.de) + + * 1750a.c: Now includes regs.h. + ({movcnt,mod}_regno_adjust): Corrected typos. + * 1750a.md (movhi): Corrected case of moving constant to memory. + +Mon Jan 6 08:00:57 1997 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * mips.h: Delete redundant definitions of compiler and library fns. + + * dwarfout.c (type_attribute): Ignore any subtype for now. + + * fold-const.c (operand_equal_p): Rework to consider two + expressions that have embedded identical SAVE_EXPRs as + equivalent; also handle some more cases. + +Sun Jan 5 23:54:34 1997 Jeffrey A Law (law@cygnus.com) + + * pa.md (pic_load_label): Fix test for using just an + ldo rather than an addil;ldo sequence to load the label's + address. + +Sun Jan 5 07:26:47 1997 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (expand_expr, case COMPONENT_REF): Fix error in last + change: don't suppress conversion if just EXPAND_SUM. + +Sat Jan 4 18:44:01 1997 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * tree.h (struct tree_decl): saved_insns.i is HOST_WIDE_INT. + + * fold-const.c (const_binop): Rework to only make constants in + one place; always use size_int if small enough and of sizetype. + (size_int): Call force_fit_type. + (fold): Avoid ever changing type of input tree. + + * expr.c (get_inner_reference): Fix type error. + (expand_expr, case COMPONENT_REF): Don't convert if modifier + is EXPAND_CONST_ADDRESS, EXPAND_SUM, or EXPAND_INITIALIZER. + * tree.c (staticp, case COMPONENT_REF, BIT_FIELD_REF): Not + static if bitfield. + + * expr.c (expand_expr, case COMPONENT_REF): If taking value + from a CONSTRUCTOR, must mask/sign-extend if bitfield. + (expand_builtin, case BUILT_IN_LONGJMP): Pass type, not IDENTIFIER, + to second arg of RETURN_POPS_ARGS. + + * expr.c (expand_expr, case COND_EXPR): Add additional cases + to "singleton" cases. + * tree.c (integer_pow2): Mask value to width of type. + (tree_log2): New function. + + * expmed.c (store_fixed_bit_field): If not SLOW_UNALIGNED_ACCESS, + treat everything as maximally aligned. + + * combine.c (find_split_point, case SET): If SET_SRC is NE and + STORE_FLAG_VALUE is -1, see if we can convert into NEG of shift. + (force_to_mode, case NE): Make condition stricter. + + * calls.c (emit_library_call_value): Remove redundant check for + outmode != VOIDmode. + +Sat Jan 4 08:12:16 1997 J.T. Conklin + + * Optimizations from John Vickers (john@rhizik.demon.co.uk): + * m68k.c (output_function_{pro,epi}logue): Use addq/subq when + adjusting stack pointer by small displacements. + * m68k.md (addsi3, addhi3): Use two addqw (or subqw) insns when + adding (or subtracting) small integer constants (8 < N <= 16) to + both address and data registers. + +Sat Jan 4 07:06:07 1997 Kamil Iskra + + * loop.c (basic_induction_var): Return 0 if SUBREG is not a + promoted variable. + +Sat Jan 4 06:22:36 1997 Doug Rupp (rupp@gnat.com) + + * alpha.c (vmskrunch): Try to not chop trailing uppercase letters. + * alpha/vms.h (ENDFILE_SPEC): Use "gnu", not "gnu_cc". + + * cccp.c (PRINTF_PROTO): Use __printf__ in __attribute__, not printf. + * cexp.y (PRINTF_PROTO): Likewise. + +Fri Jan 3 09:01:00 1997 Craig Burley + + * alpha.md (cmov): Fix operand numbers in case involving DF target, + DF comparison, and SF source. + +Fri Jan 3 08:19:46 1997 Paul Eggert + + * cpplib.c (macroexpand): Delete any no-reexpansion marker following + identifier at beginning of an argu concatenated with what precedes it. + +Fri Jan 3 07:59:21 1997 Ken Rose (rose@netcom.com) + + * reorg.c (fill_slots_from_thread): Skip moved insn in all three cases. + +Fri Jan 3 07:51:44 1997 Bob Manson + + * function.c ({push,pop}_function_context_to): Save and restore + current_function_args_info. + * function.h (struct function): New field args_info. + +Fri Jan 3 06:55:09 1997 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * jump.c (rtx_equal_for_thread_p): Return 0 for floating-point. + + * reload.c (find_reloads): If replaced a PLUS or MULT with a + simple operand, start over again. + + * va-alpha.h: Check for __VMS__, not VMS. + +Thu Jan 2 08:52:51 1997 Richard Kenner + + * configure: Finish restoring change of default of objc threads to + "single" for Linux-based GNU systems. + +Mon Dec 30 17:03:46 1996 Jeffrey A Law (law@cygnus.com) + + * pa.c (fmpy_operands): Remove. No longer needed. + (combinable_add, combinable_copy, combinable_fmpy): Likewise. + (combinable_fadd, combineable_fsub): Likewise. + (pa_reorg): Call pa_combine_instructions. + (pa_combine_instructions): Combine instructions to make things + like fmpyadd and fmpysub. + (pa_can_combine_p): Helper function for pa_combine_instructions. + * pa.md (pa_combine_type): New attribute. Set it appropriately + for various insns. + (define_delays): Use a separate define_delay for unconditional + branches. + (fmpyadd, fmpysub peepholes): Remove, no longer needed. + (fmpyadd, fmpysub insns): Add variant with fadd/fsub first, + then the fmpy. + +Mon Dec 30 14:43:51 1996 Jim Wilson + + * reg-stack.c (subst_stack_regs_pat): Set src_note explicitly, instead + of using invalid aggregate initialization. + + * print-tree.c (print_node): Don't try to print nonexistent + TYPE_ATTRIBUTES field of a decl node. + +Mon Dec 30 10:30:25 1996 Richard Stallman + + * config.sub: Handle hiuxmpp as system type. + +Thu Dec 26 13:33:27 1996 Michael Meissner + + * rs6000.md (init_v4_pic): Explicitly set the length. + +Mon Dec 23 19:39:38 1996 Jim Wilson + + * mips.h (FUNCTION_ARG_REGNO_P): Correct for TARGET_SOFT_FLOAT and + TARGET_FLOAT64 cases. + + * integrate.c (function_cannot_inline_p): Reject function with + PARALLEL result. + (expand_inline_function): Abort if function result not handled. + +Sat Dec 21 04:02:46 1996 Jason Merrill + + * mips.c (save_restore_insns): Mark large frame setup insns + as frame-related. + (mips_expand_prologue): Likewise. + + * dwarf2out.c (dwarf2out_frame_debug): Support MIPS large frames. + (add_bound_info): Use default lower bounds. + Handle simple variable bounds with a DIE ref. + Don't generate a NULL loc descr. + (add_subscript_info): Always add lower bound. + (gen_formal_parameter_die): Always equate_decl_number_to_die. + (gen_variable_die): Likewise. Don't use the old die for automatic + variables. + +Wed Dec 18 10:23:46 1996 Jeffrey A Law (law@cygnus.com) + + * mn10300.c (notice_update_cc): Enable this code. + * mn10300.h (CC_OVERFLOW_UNUSABLE): Define. + * mn10300.md (tstsi): Use "set_zn_c0" instead of "set" for cc status. + (addsi3 pattern): Break "inc" into two different alternatives + since "inc dn" sets cc0, but "inc an" does not. + (multiply and divide patterns): Fix cc status. + (bCC, inverted bCC): Restore any comparison which needs the + overflow bits when CC_OVERFLOW_UNUSABLE is set. + (zero and sign extensions): Fix cc status. + (movm_store): Likewise. + +Tue Dec 17 15:02:44 1996 Jim Wilson + + * sched.c (update_flow_info): When add REG_DEAD notes for dest of + last insn, add check for global_regs. + +Tue Dec 17 11:07:26 1996 Michael Meissner + + * rs6000/win-nt.h (HAS_INIT_SECTION): Delete, so that __main is + called from main. + +Mon Dec 16 15:28:44 1996 Jim Wilson + + * combine.c (nonzero_bits): Ifdef out calls to num_sign_bit_copies. + Add dummy define/undef for num_sign_bit_copies. + + * dwarfout.c (location_or_const_value_attribute, case CONCAT): Add. + + * combine.c (simplify_comparison): Use mode_width as shift count + only if it is less than or equal to HOST_BITS_PER_WIDE_INT. + +Mon Dec 16 10:10:11 1996 Jeffrey A Law (law@cygnus.com) + + * mn10300.c (expand_epilogue): Restore registers in the + "ret" instruction instead of a separate movm instruction. + Support possible stack deallocation in "ret" instruction too. + * mn10300.md (return_internal): Use "ret" instead of "rets"; + restore registers and deallocate stack as needed. + (load_movm): Delete unused pattern. + + * mn10300.h (SMALL_REGISTER_CLASSES): Define. + +Fri Dec 13 14:46:54 1996 J"orn Rennecke + + * sh.md (dect): Rewrite pattern so that it can be combined. + +Fri Dec 13 13:14:51 1996 Ian Lance Taylor + + * varasm.c (output_constant_pool): If ASM_OUTPUT_POOL_EPILOGUE is + defined, call it. + +Thu Dec 12 20:04:55 1996 Jason Merrill + + * rtl.h (RTX_FRAME_RELATED_P): New macro. + (struct rtx_def): Add frame_related bitfield. + * final.c (final_scan_insn): Call dwarf2out_frame_debug. + Don't call dwarf2out_begin_function. + (final): Initialize dwarf2out_frame_debug. + * dwarf2out.c (dwarf2out_begin_function): Remove. + (dwarf2out_init): Use INCOMING_RETURN_ADDR_RTX. + (DWARF_CIE_DATA_ALIGNMENT): Generalize. + (DWARF_FRAME_REGNUM): Don't add 1. + (decode_cfi_rtl): Lose. + (dwarf2out_def_cfa): Now takes reg and offset directly. + (reg_save): Likewise. + (dwarf2out_reg_save): Now takes offset. + (initial_return_save): Grok INCOMING_RETURN_ADDR_RTX. + Replaces dwarf2out_return_save. + (dwarf2out_cfi_label): New fn. + (add_fde_cfi): Use it. + (dwarf2out_frame_debug): New fn. + * mips.h (DWARF_FRAME_REGNUM): Tweak r31. + (INCOMING_RETURN_ADDR_RTX): Define. + * mips.c (mips_expand_prologue): Set RTX_FRAME_RELATED_P as needed. + (save_restore_insns): Likewise. + * i386.c (ix86_expand_prologue): Likewise. + * i386.h (INCOMING_RETURN_ADDR_RTX): Define. + (DWARF_FRAME_RETURN_COLUMN): Define. + + * dwarf2out.c (add_AT_long_long): Renamed from add_AT_double fo + clarity. + (print_die): Adjust. + (add_AT_float): New fn. + (add_const_value_attribute): Support fp values. + (size_of_die): Use blocks for long_long and fp values. + (value_format, output_die): Likewise. + (output_loc_operands): Don't support DW_OP_const8?. + +Thu Dec 12 19:49:09 1996 Ian Lance Taylor + + * varasm.c (CONSTANT_POOL_BEFORE_FUNCTION): Define if not + defined. + (assemble_start_function): Check CONSTANT_POOL_BEFORE_FUNCTION + to decide whether to call output_constant_pool. + (assemble_end_function): Likewise. + + * calls.c: Check SMALL_REGISTER_CLASSES at run time, not just + compile time. + * combine.c, cse.c, function.c, jump.c, local-alloc.c: Likewise. + * loop.c, reload.c, reload1.c: Likewise. + * dsp16xx.h (SMALL_REGISTER_CLASSES): Define with value. + * h8300.h (SMALL_REGISTER_CLASSES): Likewise. + * i386.h (SMALL_REGISTER_CLASSES): Likewise. + * pdp11.h (SMALL_REGISTER_CLASSES): Likewise. + * sh.h (SMALL_REGISTER_CLASSES): Likewise. + +Thu Dec 12 15:25:39 1996 Michael Meissner + + * rs6000.md (sysv call insns): If flag_pic add @plt suffix. + + * rs6000.md (fix_truncdfsi2_store): Fix offsets > 32k. + + * rs6000/t-ppccomm: New file for common parts of embedded and + System V target Makefile support. + + * rs6000/t-ppcos: New file for System V OS target Makefile + support. + + * rs6000/t-solaris: Delete, merge into rs6000/t-ppcos. + + * rs6000/t-{ppc,ppcgas}: Only keep the multilib specific parts, + moving the rest to rs6000/t-ppccomm. + + * configure (powerpc*-*-*): For embedded and System V + configurations, add rs6000/t-ppccomm. + For GNU/Linux and Solaris, use t-ppcos. + + * ginclude/ppc-asm.h (cr*, f*): Add new macros for register names. + + * rs6000/sol-c0.c (_start): Fix uninitialized data bug. + + * rs6000.md (init_v4_pic): Add @local to call. + (icbi,dcbst,sync,isync): Delete PowerPC cache control insns. + + * rs6000/sysv4.h (ASM_SPEC): On explicit -mcall-solaris, pass + -msolaris to the assembler. + + * rs6000.c (rs6000_sync_trampoline): Delete. + (rs6000_trampoline_template): Aix & System V don't need template now. + (rs6000_initialize_trampoline): For System V, call the function + __trampoline_setup to set up the trampoline. + + * rs6000.h (TRAMPOLINE_TEMPLATE): Delete here. + * rs6000/win-nt.h (TRAMPOLINE_TEMPLATE): Add it here. + + * rs6000/tramp.asm: New file, setup trampolines properly on System + V systems, properly flushing the caches. + +Thu Dec 12 10:53:10 1996 Jeffrey A Law (law@cygnus.com) + + * reorg.c (fill_slots_from_thread): Don't call eligible_for_delay + with an insn with asm operands. + + * expmed.c (emit_store_flag_force): Fix typos/thinkos. + +Thu Dec 12 08:09:20 1996 J"orn Rennecke + + * i386.c (i386_return_pops_args): Libcalls ignore TARGET_RTD. + +Thu Dec 12 07:56:03 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * tree.h (maybe_get_identifier): New declaration. + + * calls.c (emit_library_call): Don't pass VOIDmode to type_for_mode. + + * va-alpha.h: Add definitions for VMS; they differ from Unix. + + * Makefile.in (stamp-objlist): Handle first character of object + file being a digit. + + * 1750a.h (function_arg, {movcnt,mod}_regno_adjust): Add decls. + (branch_or_jump): Likewise. + (FUNCTION_ARG): Remove cast of function_arg result to rtx. + * 1750a.md: Remove unneeded casts to char *. + +Thu Dec 12 05:55:27 1996 Richard Earnshaw (rearnsha@armltd.co.uk) + + * arm.c (arm_gen_constant, case [IX]OR): Don't invert constant if + loading into temporary. + +Wed Dec 11 18:57:21 1996 Brendan Kehoe + + * toplev.c (rest_of_compilation): Make sure unwinder RTL is saved. + + * collect2.c (write_c_file): Wrap the ctor/dtor lists and fns + with `extern "C" { ... }'. + +Wed Dec 11 17:46:48 1996 John F. Carr + + * tree.h (tree_decl): Reorder field declarations to reduce size + on 64 bit machines. + + * combine.c (try_combine): When splitting an insn, check for the + new I2 setting a SUBREG. + +Wed Dec 11 17:00:47 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * alpha.c (print_operand): Use HOST_WIDE_INT_PRINT_DEC instead of + using "%ld". + (output_prolog): Don't print useless comment for VMS. + + * alpha.c (output_prolog): SIZE is now HOST_WIDE_INT. + * alpha.md (mov[hq]i unnamed): Split up for TARGET_BYTE_OPS and not. + + * function.c (fixup_var_refs_1, case ZERO_EXTRACT): Don't call + fixup_memory_subreg if no longer SUBREG of MEM. + +Wed Dec 11 14:10:48 1996 Jeffrey A Law (law@cygnus.com) + + * mn10300.c: New file for Matsushita MN10300 port. + * mn10300.h, mn10300.md, t-mn10300, xm-mn10300.h: Likewise. + * config.sub: Recognize mn10300 as a basic machine type. + * configure: Similarly. + * ginclude/stdarg.h: mn10300 is little endian. + * ginclude/varargs.h: Likewise. + +Wed Dec 11 09:09:10 1996 Nagai Takayuki + + * libgcc2.c (cacheflush): Add SONY NEWS-OS 4.2 version. + +Wed Dec 11 09:01:39 1996 J"orn Rennecke + + * calls.c (emit_library_call, emit_library_call_value): + Don't pass an identifier node as function type for + library functions, but rather build a function type that + has a return type with the correct mode. + * i386.c (i386_return_pops_args): Don't test for IDENTIFIER_NODE. + * i386/isc.h (obsolete RETURN_POPS_ARGS): Test first argument + for IDENTIFIER_NODE. + * i386/next.h (RETURN_POPS_ARGS): Likewise. + * i386/sco.h (RETURN_POPS_ARGS): Likewise. + * i386/sco5.h (RETURN_POPS_ARGS): Likewise. + * i386/scodbx.h (RETURN_POPS_ARGS): Likewise. + * m68k.h (RETURN_POPS_ARGS): Likewise. + * ns32k.h (RETURN_POPS_ARGS): Likewise. + * pyr.h (RETURN_POPS_ARGS): Likewise. + * gmicro.h (RETURN_POPS_ARGS): Likewise; fix typo. + +Tue Dec 10 17:36:47 1996 J.T. Conklin + + * Add optimizations from John Vickers (john@rhizik.demon.co.uk) + * m68k.h (TARGET_CPU32): New macro. + * m68k.md (add[hs]i3): Only use two addq.w or subq.w instructions + when adding or subtracting constants 8 < N < 16 on TARGET_CPU32. + Use lea instead of add.w when adding 16 bit constants to address + registers on all but TARGET_68040. + * m68k.c (output_function_{pro,epi}logue): Use lea instead of add.w + when adjusting stack pointer on all but TARGET_68040. + +Tue Dec 10 15:55:23 1996 Ian Lance Taylor + + * optabs.c (emit_unop_insn): Treat ZERO_EXTEND like SIGN_EXTEND. + +Tue Dec 10 13:47:24 1996 Joern Rennecke + + * combine.c (combinable_i3pat): Bring back to sync with can_combine_p. + + * sh.h (ADJUST_INSN_LENGTH): Don't break from loop when LOOP_BEG found. + Calculate padding in new variable pad. + +Mon Dec 9 18:00:38 1996 Jason Merrill + + * dwarf2out.c (output_uleb128): Output value in human-readable comment. + (output_sleb128): Likewise. + (various): Adjust. + (output_call_frame_info): Only output info if it's interesting. + (add_src_coords_attributes): New fn. + (add_name_and_src_coords_attributes): Split out from here. + (gen_enumeration_type_die): Add src coordinates. + (gen_struct_or_union_type_die): Likewise. + (dwarf2out_finish): Call output_call_frame_info for all targets. + +Thu Dec 5 11:25:30 1996 Jason Merrill + + * dwarf2out.c (add_pure_or_virtual_attribute): Only add + AT_containing_type if -g2 or higher. + + * dwarf2out.c (gen_struct_or_union_type_die): Make sure that + the type for AT_containing_type has been generated. + (gen_decl_die): Likewise. + + * dwarf2out.c (type_tag): Check DECL_IGNORED_P. + (add_pure_or_virtual_attribute): Check DECL_VINDEX instead. + (scope_die_for): Likewise. + * dwarfout.c (type_tag): Likewise. + +Wed Dec 4 22:51:38 1996 Jason Merrill + + * dwarf2out.c (decode_cfi_rtl): Support getting a CONST_INT. + (dwarf2out_begin_function): Adjust. + (reg_save): Divide offset by the alignment. + (output_cfi): Support having more than one advance_loc. + (output_call_frame_info): Re-initialize current_label. + (dwarf2out_begin_prologue): Initialize current_label to NULL. + (lookup_cfa, lookup_cfa_1): New fns. + (dwarf2out_def_cfa): Call lookup_cfa. + (dwarf2out_finish): Don't generate CIE CFIs. + (dwarf2out_init): Generate them here. + (DWARF_FRAME_RETURN_COLUMN): Use PC_REGNUM. + + (add_pure_or_virtual_attribute): Note virtual context. + (gen_formal_parameter_die): Return the die. + (gen_formal_types_die): Set AT_artificial on `this'. + (gen_subprogram_die): Add AT_accessibility. + (gen_variable_die): Likewise. + (gen_field_die): Likewise. Don't generate location attribute for + union members. + (gen_struct_or_union_type_die): Note where our vtable lives. + (gen_decl_die): Handle anonymous union fields. + (dwarf2out_decl): Always output `bool'. + +Mon Dec 2 03:55:15 1996 Jason Merrill + + * final.c (final_end_function): Don't call dwarf2out_end_function. + + * dwarf2out.c (output_line_info): Emit special opcodes for each line + entry, even if the line number doesn't change. + (pend_type, output_pending_types_for_scope): New fns. + (gen_struct_or_union_type_die): Use them to defer generating member + dies if we're in the middle of some other context. + (gen_type_die): Still put nested types in the right place. + (dwarf2out_decl): Call output_pending_types_for_scope. + + * dwarf2out.c (dw_fde_struct): Replace end_prologue, begin_epilogue + with current_label. + (DWARF_CIE_INSN_SIZE, DWARF_CIE_SIZE): Remove. + (DWARF_CIE_HEADER_SIZE): The size without the initial insns. + (size_of_cfi): Revert. + (decode_cfi_rtl, add_fde_cfi, dwarf2out_def_cfa, reg_save, + dwarf2out_reg_save, dwarf2out_return_save): New fns. + (dwarf2out_begin_function): Use them to generate CFIs. + (dwarf2out_finish): Use them to generate E CFIs. + Don't set next_fde_offset. + (calc_fde_sizes): Initialize cie_size. + (output_call_frame_info): Don't generate CIE CFIs. + (dwarf2out_end_function): Remove. + + * tree.c (maybe_get_identifier): New fn. + * varasm.c (assemble_name): Use it instead of get_identifier. + +Fri Nov 29 15:13:39 1996 Stan Cox + + * jump.c (jump_optimize): Don't move initialization if there is a + label between it and the jump for if (foo) bar++ to bar += (foo !=0) + +Wed Nov 27 16:21:14 1996 Stan Cox + + * Remove change of Oct 4. + * i386.h (outer_function_chain): Remove. + (current_function_calls_alloca): Remove. + (rtx_equal_function_value_matters): Remove. + (N_REGS_USED, N_ALLOCATABLE_REGISTERS): Remove. + * i386.md (adddi3_1, subdi3_1): Remove. + (adddi3, subdi3): Revert. + (movsf, movsf_mem, movsf_normal, movdf, movdf_mem, movdf_mem+1): + Likewise. + (movxf, movxf_mem, movxf_mem+1, addsidi3_1, addsidi3_2): Likewise. + (adddi3_1, subsidi3, subdi3_1): Likewise. + (addsidi3_1, addsidi3_2, subsidi3): Likewise. + (addsidi3_1, addsidi3_2, adddi3, subsidi3): Disable the problem + reload alternatives. + +Wed Nov 27 16:21:14 1996 J"orn Rennecke + + * i386.md (ashldi3_non_const_int, ashrdi3_non_const_int): + Use a hidden branch to handle shifts > 32 bit. + (lshrdi3_non_const_int): Likewise. + (floatdixf2): Don't use unnecessary XFmode operation. + +Wed Nov 27 15:23:41 1996 Jason Merrill + + * varasm.c (assemble_variable): Don't emit DWARF. + + * toplev.c (rest_of_type_compilation): Don't emit DWARF. + (main): Just let -gdwarf mean DWARF v1; remove -gdwarf-1. + + * dwarfout.c (decl_class_context): New fn. + (output_global_subroutine_die): Fix declaration case. + (output_global_variable_die): Likewise. + (output_type): Note when we are in a class defn. If we're a nested + type and our context hasn't been written, do that. Do early exit + for nested types. + (output_decl): Output the class context for fns and vars. + Don't emit detailed parm info for a fn declaration. + Use TYPE_DECL_IS_STUB, is_redundant_typedef. + (type_ok_for_scope): Support emitting nested types later. + (is_redundant_typedef): New fn. + (TYPE_DECL_IS_STUB): New macro. + (output_compile_unit_die): Check use_gnu_debug_info_extensions. + (output_local_subroutine_die, output_global_subroutine_die, + dwarfout_begin_function, dwarfout_end_function, dwarfout_line, + generate_macinfo_entry, dwarfout_init, dwarfout_finish): Likewise. + + * dwarf2out.c (decl_class_context): Static. + (lookup_type_die): Use TYPE_SYMTAB_POINTER. + (equate_type_number_to_die): Likewise. + (gen_subprogram_die): If we're in class context, it's a decl. + (gen_variable_die): Likewise. + (gen_decl_die): Output the containing type. + (dwarf2out_init): Lose type_die_table code. + +Wed Nov 27 08:30:54 1996 Brendan Kehoe + + * Makefile.in (DRIVER_DEFINES): New macro, with the macro + definitions for the driver. + (gcc.o): Make rule use $(DRIVER_DEFINES). + * gcc.c (process_command) [LANG_SPECIFIC_DRIVER]: Call + lang_specific_driver, passing along the addr of FATAL for errors + along with our ARGC and ARGV. + +Wed Nov 27 08:21:13 1996 Philippe De Muyter + + * m68k.md (iorsi_zexthi_ashl16): New pattern. + (ashrsi_16): New name for old unnamed pattern. + + * objc/misc.c (stdlib.h): Define __USE_FIXED_PROTOTYPES__ before + including stdlib.h. + +Wed Nov 27 08:17:34 1996 Joern Rennecke + + * i386.md (decrement_and_branch_until_zero+[3-8]): Add missing + CC_STATUS_INIT. + (decrement_and_branch_until_zero+[5-8]): Delete redundant assignment. + +Wed Nov 27 07:56:27 1996 J.T. Conklin + + * m68k.md ({and,ior,xor}si3_internal): Removed !TARGET_5200 from + conditionals now that entire insn is disabled when !TARGET_5200. + +Wed Nov 27 07:52:32 1996 Oliver Kellogg + + * 1750a.md (movhi pattern): Fixed MEM to MEM move problem. + +Tue Nov 26 14:50:54 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (move_by_pieces): Abort only if length positive at end. + * function.c (frame_offset, get_frame_size): Make HOST_WIDE_INT. + * function.h (struct function): Make frame_offset be HOST_WIDE_INT. + (get_frame_size): Add definition. + * reload1.c (reload): Make starting_frame_size be HOST_WIDE_INT. + +Mon Nov 25 16:55:14 1996 Jason Merrill + + * dwarf2out.c (dwarf2out_finish): Don't emit call frame info + for non-MIPS targets. + (is_redundant_typedef): New fn. + (modified_type_die): Refer to typedef DIEs where appropriate. + (gen_typedef_die): Support DECL_ORIGINAL_TYPE. + (gen_type_die): Likewise. Use is_redundant_typedef. + (gen_subprogram_die): Don't force a spec DIE for local class methods. + +Mon Nov 25 15:09:12 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * gcc.c (handle_braces): Rework last change. + +Mon Nov 25 13:49:51 1996 Jim Wilson + + * configure (build_exeext, exeext): New variables. Use sed to insert + build_exeext value into Makefile exeext rule. + (*-*-cygwin32): Set exeext. + * i386/x-cygwin32 (exeext): Delete. + * rs6000/x-cygwin32 (exeext): Delete. + + * dwarf.h (enum dwarf_location_atom): Add OP_MULT. + * dwarfout.c (output_mem_loc_descriptor, case MULT): Add. + * dwarfout2.c (mem_loc_descriptor, case MULT): Add. + + * dwarfout.c (dwarf_fund_type_name, case FT_unsigned_int64): Fix typo. + +Sun Nov 24 21:42:01 1996 J.T. Conklin + + * m68k.md (andsi3): Changed into define_expand. + (andsi3_internal): Rename from old andsi3, changed condition + to !TARGET_5200. + (andsi2_5200): New insn. + (iorsi3): Change into define_expand. + (iorsi2_internal): Rename from old iorsi3, changed condition + to !TARGET_5200. + (iorsi2_5200): New insn. + (xorsi3): Change into define_expand. + (xorsi2_internal): Rename from old xorsi3, changed condition + to !TARGET_5200. + (xorsi2_5200): New insn. + +Sun Nov 24 21:31:32 1996 John F. Carr + + * i386.h (N_ALLOCATABLE_REGISTERS): Remove extra backslash at + end of macro definition. + + * cpplib.c (LOCAL_INCLUDE_DIR): Remove default definition. + (include_defaults_array): Do not use LOCAL_INCLUDE_DIR or + TOOL_INCLUDE_DIR if they are not defined. + * cccp.c: Likewise. + + * Makefile.in (cppmain.o): New rule. + +Sun Nov 24 19:14:50 1996 Andreas Schwab + + * fold-const.c (merge_ranges): In (+,-) case, if lower bounds are + the same the result is always false. + +Sun Nov 24 18:48:31 1996 Richard Kenner + + * c-typeck.c (build_indirect_ref): Don't give warning for + dereferencing void * if evaluation is being skipped. + + * c-decl.c (poplevel): Don't call output_inline_function if + DECL_SAVED_INSNS is not set. + + * gcc.c (give_switch): Add new arg, INCLUDE_BLANKS. + (handle_braces): All callers changed. + Add support for new construct: %{S*^}. + +Sun Nov 24 18:44:48 1996 Paul Eggert + + * c-parse.in (unary_expr, expr_no_commas): Increment skip_evaluation + when analyzing an expression that is known not to be evaluated. + (sizeof, alignof): New rules. + * c-tree.h (skip_evaluation): New variable. + * c-common.c (skip_evaluation): Likewise. + (overflow_warning, unsigned_conversion_warning): Don't warn about + potential runtime errors when skipping evaluation. + * c-typeck.c (build_binary_op): Likewise. + (build_conditional_expr): op1 now always nonnull. + +Sun Nov 24 17:06:58 1996 Bernd Schmidt (crux@Pool.Informatik.RWTH-Aachen.DE) + + * toplev.c (rest_of_compilation): Call regscan before each + jump threading pass. + +Sun Nov 24 16:37:18 1996 Dave Love + + * configure (objc_thread_file): Set conditionally in each case so + may be overidden with `--enable-objcthreads=posix'. + Change GNU/Linux default to `single'. + +Fri Nov 22 17:53:15 1996 Jason Merrill + + * varasm.c (assemble_variable): Output DWARF in the third case, too. + + * dwarf2out.c (decls_for_scope): Only add DIEs with no parents to + our scope. + (gen_subroutine_type_die): Parm types go under the fn type DIE. + + * Makefile.in ($(T)crt{begin,end}.o): Move CRTSTUFF_T_CFLAGS after + general flags. + + * mips/t-iris6 (CRTSTUFF_T_CFLAGS): Define. + * mips.c (compute_frame_size): Fix fp_save_offset. + + * dwarf2out.c (new_die): If we get a NULL parent, inc limbo_die_count. + (decls_for_scope): Decrement limbo_die_count as appropriate. + (dwarf2out_finish): Check for good limbo_die_count. + (size_of_cfi): If regno too big for DW_CFA_offset, use offset_extended + instead. + (output_call_frame_info): Add disabled code for specifying ABI. + (dwarf2out_begin_function): Note all saved regs. + + * dwarf2out.c (gen_subprogram_die): Have a DIE for each fn at + toplevel. + (scope_die_for): Only use the NULL for fns and tags. + +Tue Nov 21 15:53:51 1996 Joern Rennecke + + * sh.c (output_stack_adjust): New argument TEMP. Changed all callers. + If the adjust cannot be done with one, but can be done with two + CONST_OK_FOR_I constants, do it that way. + +Thu Nov 21 14:25:55 1996 Ian Lance Taylor + + * fixincludes: Include in even if not C++ if + stderr needs to be defined. + +Wed Nov 20 15:38:13 1996 Jason Merrill + + * toplev.c (rest_of_type_compilation): Do output function-scope tags + for DWARF 2. + * c-decl.c (pushtag): Set TYPE_CONTEXT on the tag. + * toplev.c, varasm.c: s/dwarf2out_file_scope_decl/dwarf2out_decl/g. + * dwarf2out.c (add_prototyped_attribute): Use a value of 1. + (gen_subprogram_die): Support AT_static_link. + (dwarf2out_decl): Rename from dwarf2out_file_scope_decl. + Give nested fns and tags a die_parent of NULL. + (decls_for_scope): Fix the die_parent for nested fns and tags. + (scope_die_for): If we get a context of NULL, just return it. + +Tue Nov 19 18:21:11 1996 Jason Merrill + + * dwarf2out.c (gen_subprogram_die): Support block extern decls. + (gen_variable_die): Likewise. + (gen_decl_die): Emit block extern function decls. + + * c-decl.c (implicitly_declare): Set DECL_ARTIFICIAL. + +Tue Nov 19 16:50:32 1996 Michael Meissner + + * configure (powerpc*-{sysv,elf,eabi{,aix,sim}}): Set + extra_headers to ppc-asm.h. + (powerpc*-{linux,solaris,rtems,vxworks}): Likewise. + (powerpc*-{winnt,pe,cygwin32}): Likewise. + + * rs6000/t-{ppc,ppcgas,solaris,winnt} (EXTRA_HEADERS): Don't set here. + +Mon Nov 18 14:51:46 1996 Jason Merrill + + * dwarf2out.c (DWARF_CIE_INSN_SIZE): New macro. + (DWARF_CIE_HEADER_SIZE): Use it. + (DWARF_FRAME_RETURN_COLUMN, DWARF_FRAME_REGNUM): New macros. + (output_call_frame_info, dwarf2out_begin_function): Use them. + For the MIPS, output the first CFA insn in the CIE. + * dwarf2.h (enum dwarf_call_reg_usage): Lose. + (dwarf_macinfo_record_type): Fix spelling. + * mips/mips.h (DWARF_FRAME_REGNUM, DWARF_FRAME_RETURN_COLUMN): Define. + + * dwarf2out.c (base_type_die): Just generate the DIEs as needed, + rather than building up some table. + (init_base_type_table): Lose. + (add_subscript_info): Use add_type_attribute. Don't give an upper + bound for an array of unknown size. + (gen_unspecified_parameters_die): Remove DWARF-1 kludge. + (dwarf2out_init): Lose call to init_base_type_table. + (is_c_family, is_fortran): New fns. + (gen_compile_unit_die): Recognize GNU F77. + (gen_array_type_die): Use AT_declaration for an array of unknown size. + (modified_type_die): Take TYPE_MAIN_VARIANT before passing it + to build_type_variant, so we ignore named variants. + (dwarf2out_file_scope_decl): Don't generate DIEs for built-in structs, + either; they will be emitted if they are used. + From wilson: + (gen_array_type_die): Force the element type out first on IRIX 6. + +Sun Nov 17 20:23:11 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (get_inner_reference): Fix error in previous change. + +Sat Nov 16 06:08:27 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * emit-rtl.c (operand_subword): Avoid confusion if sizeof (float) + is less than a full word. + + * alpha.h (MASK_BYTE_OPS): Now define as 1024. + * alpha/vms.h (TARGET_DEFAULT): Use symbolic values. + + * expr.c (get_inner_reference): Add new arg PALIGNMENT and compute it. + (expand_assignment, do_jump): Pass new arg to get_inner_reference. + (expand_expr, case COMPONENT_REF): Likewise. + * fold-const.c (optimize_bit_field_compare, decode_field_reference): + Likewise. + * tree.h (get_inner_reference): Add new arg. + + * Add support for Alpha/VMS, mostly from + Klaus Kaempf (kkaempf@progis.de) + * configure (alpha-dec-vms*): New target. + * alpha.c (override_options): Handle VAX format floating-point. + (print_operand, case ',', '-'): New cases. + (alpha_builtin_saveregs): Handle VMS convention. + (alpha_sa_{mask,size}, alpha_pv_save_size, alpha_using_fp): + New versions for VMS. + (output_{pro,epi}logue, function_arg): Likewise. + (direct_return): Never true on VMS. + (check_float_value): Return 0 for VMS. + (vmskrunch, alpha_{need,write}_linkage): New function. + * alpha.h ({MASK,TARGET}_{OPEN_VMS,FLOAT_VAX}): New macros. + (TARGET_SWITCHES): Add float-vax and float-ieee. + ({FUNCTION,LIBCALL}_VALUE, FUNCTION_VALUE_REGNO_P): R1 and R33 + are also return registers. + (ASM_OUTPUT_DOUBLE): Support both floating-point formats. + (PRINT_OPERAND_FUNCT_VALID_P): Add ',' and '-'. + * alpha.md ({div,mod}[sd]i3): Only for VMS. + (fp operations): Add modifiers for multiple floating-point formats. + (call patterns): Handle new calling sequence for VMS. + (tablejump): Make new pattern for VMS. + (nonlocal_goto_receiver, arg_home): New patterns. + * alpha/t-vms, alpha/vms.h, alpha/xm-vms.h: New files. + +Fri Nov 15 17:38:20 1996 Doug Evans + + * sdbout.c (current_file): New global. + (PUT_SDB_SRC_FILE): New PUT_SDB_FOO macro. + (sdbout_init): Initialize current_file ifdef MIPS_DEBUGGING_INFO. + (sdbout_{start_new,resume_previous}_source_file): New functions. + * toplev.c (debug_{start,end}_source_file): Call them if SDB_DEBUG. + * mips.h (PUT_SDB_SRC_FILE): Define. + +Fri Nov 15 16:11:25 1996 Jason Merrill + + * dwarfout.c (dwarfout_line): Don't emit line number info for + functions outside of .text. + +Fri Nov 15 15:52:42 1996 Stan Cox + + * i386/386bsd.h (COMMENT_BEGIN): Delete. + * i386/freebsd.h (COMMENT_BEGIN): Likewise. + * i386/netbsd.h (COMMENT_BEGIN): Likewise. + * i386/unix.h (COMMENT_BEGIN): Likewise. + +Fri Nov 15 13:22:42 1996 Jim Wilson + + * fold-const.c (unextend): Rewrite type conversions to avoid overflow. + +Fri Nov 15 12:11:28 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * combine.c (try_combine): Properly copy an rtvec. + * emit-rtl.c (gen_rtvec_vv): New function. + (copy_rtx_if_shared): Call it. + * integrate.c (copy_for_inline): Likewise. + * reload1.c (eliminate_regs): Likewise. + * rtl.h (gen_rtvec_vv): Declare. + * genattrtab.c (simplify_cond): Make TESTS an array of rtunions. + * genextract.c (main): Use loop, not bcopy, to set recog_operands + from an rtvec. + * rtl.c (rtvec_alloc): Clear rtwint instead of rtvec. + + * machmode.h (HOST_PTR_PRINTF): Handle char * wider than long. + (HOST_WIDE_INT_PRINT_{DEC,UNSIGNED,HEX,DOUBLE_HEX}): New macros. + * final.c (asm_fprintf): Use "ll" prefix for a long long HOST_WIDE_INT. + (output_{asm_insn,addr_const}): Use HOST_WIDE_INT_PRINT_*. + * print-tree.c (print_node{,_brief}, case INTEGER_CST): Likewise. + * print-rtl.c (print_rtx, case 'w'): Use HOST_WIDE_INT_PRINT_DEC. + + * unroll.c (iteration_info): Fix code so that it knows iteration_var + is a HOST_WIDE_INT, not a long. + + * fold-const.c (operand_equal_p): Do comparison with REAL_VALUES_EQUAL. + (make_range): Properly decide when to get TREE_TYPE of arg0. + Handle EXP being an INTEGER_CST at end. + (fold_range_test): Handle return of 0 from make_range. + (fold, case TRUTH_AND_EXPR): Handle first arg of 0. + (fold, case TRUTH_OR_EXPR): Handle first arg of 1. + + * c-common.c (decl_attributes, case A_ALIAS): Add missing parens. + +Fri Nov 15 06:37:54 1996 Andreas Schwab + + * fold-const.c (range_binop): Set SNG1 to zero if ARG1 is a + not a lower or upper bound. + +Thu Nov 14 23:08:25 1996 Jason Merrill + + * flags.h (debug_info_type): Add DWARF2_DEBUG. + * toplev.c (main): Support DWARF2_DEBUG. Add -gdwarf-1, -gdwarf-2 + options. Check debug level after choosing type. + (debug_{start,end}_source_file, debug_{define,undef}): New functions. + (compile_file): Support dwarf2 separately from dwarf1. + (rest_of_type_compilation, rest_of_compilation): Likewise. + * final.c (final_start_function): Likewise. + (final_end_function, final_scan_insn, output_source_line): Likewise. + * varasm.c (assemble_variable): Likewise. + * dwarfout.c: Don't check DWARF_VERSION. + * dwarf2out.c: s/dwarfout/dwarf2out/g. Check DWARF2_DEBUGGING_INFO. + * c-lex.c (check_newline): Use debug_* instead of calling *out + functions directly. + * svr4.h (DWARF2_DEBUGGING_INFO): Define. + * mips/iris6.h (PREFERRED_DEBUGGING_TYPE): DWARF2_DEBUG. + (DWARF2_DEBUGGING_INFO): Define instead of DWARF_DEBUGGING_INFO. + (LINK_SPEC): Pass -w through. + * mips.h (PREFERRED_DEBUGGING_TYPE): Don't check `len'. + +Thu Nov 14 17:25:47 1996 Jeffrey A Law (law@cygnus.com) + + * h8300.c (dosize): Don't clobber static chain reg if needed by + current function. + +Wed Nov 13 17:05:19 1996 Jason Merrill + + * Makefile.in (stage?-start): Keep a copy of EXTRA_MULTILIB_PARTS + in the build directory. + +Tue Nov 12 23:17:17 1996 Jeffrey A Law (law@cygnus.com) + + * pa.c (print_operand, case 'Y'): Fix comparisons to handle + NaNs properly in all cases. + +Tue Nov 12 18:47:24 1996 Jim Wilson + + * expr.c (emit_group_store): For REG case, call gen_lowpart if + modes are different. + +Tue Nov 12 18:24:40 1996 Doug Rupp (rupp@gnat.com) + + * gcc.c (exit): If VMS, define as __posix_exit. + (option_map): Add define-macro and undefine-macro. + +Tue Nov 12 17:55:10 1996 Torbjorn Granlund + + * alpha.c (input_operand): If TARGET_BYTE_OPS accept HImode and QImode. + * alpha.h (MASK_BYTE_OPS): New define. + (TARGET_BYTE_OPS): New define. + (TARGET_SWITCHES): Handle -mbyte. + (LOAD_EXTEND_OP): When MODE is not SImode, return ZERO_EXTEND. + * alpha.md (zero_extendqidi2): Handle TARGET_BYTE_OPS. + (zero_extend{hidi,qisi,hisi}2): Likewise. + (extendqisi2): Use extendqidi2x if TARGET_BYTE_OPS. + (extendqidi2): Likewise. + (extendqidi2x): New pattern. + (extendhisi2): Use extendhidi2x if TARGET_BYTE_OPS. + (extendhidi2): Likewise. + (extendhidi2x): New pattern. + (movhi): Handle TARGET_BYTE_OPS. + (movhi matcher): Output ldwu and stw. + (movqi): Handle TARGET_BYTE_OPS. + (movqi matcher): Output ldbu and stb. + +Tue Nov 12 16:53:37 1996 Rob Savoye + + * configure (hppa1.1-pro*, i960-*-coff*,m68k-*-aout*): Add libgloss.h. + (m68k-*-coff*, mips*-*-elf*, sparc*-*-aout*, sparc*-*-coff*): Likewise. + * config/libgloss.h: New file. + +Tue Nov 12 16:21:45 1996 Joern Rennecke + + * jump.c (jump_optimize): Fix bug in Sep 23 change. + +Tue Nov 12 16:15:31 1996 Andrew Cagney (cagney@tpgi.com.au) + + * global.c (prune_references): Add missing symmetic CONFLICTP call. + +Tue Nov 12 14:34:40 1996 Philippe De Muyter + + * m68k.c (output_function_{pro,epi}logue): Save and restore + fp-registers only if TARGET_68881. + + * m68k/mot3300.h (ASM_OUTPUT_INTERNAL_LABEL): Prefix labels with "L%". + (ASM_GENERATE_INTERNAL_LABEL, ASM_OUTPUT_CASE_LABEL): Likewise. + (ASM_OUTPUT_ADDR_VEC_ELT, ASM_OUTPUT_ADDR_DIFF_ELT): Likewise. + + * m68k/mot3300.h (TARGET_DEFAULT): Use MASK_68040_ALSO, not MASK_68040. + * m68k/next.h, m68k/ccur-GAS.h (TARGET_DEFAULT): Likewise. + + * fixproto (std_files): Add sys/socket.h. + + * m68k.md (movqi): Emit 'st' for INTVAL & 255 == 255, not INTVAL == -1. + (seq,sne,sgt,sgtu,slt,sltu,sge,sgeu,sle,sleu): Allow "m" as operand 0. + +Tue Nov 12 14:17:45 1996 Paul Eggert + + * c-decl.c (grokdeclarator): Generate a warning if -Wimplicit, + unless a warning was already generated by -Wreturn-type. + +Tue Nov 12 14:11:02 1996 Pat Rankin + + * Make qsort callback routines conform to the ANSI/ISO standard. + * c-decl.c (field_decl_cmp): Use `const void *' arguments. + * global.c (allocno_compare): Likewise. + * reload1.c (hard_reg_use_compare, compare_spill_regs): Likewise. + (reload_reg_class_lower): Likewise. + * stupid.c (stupid_reg_compare): Likewise. + * local-alloc.c (qty_compare_1, qty_sugg_compare_1): Likewise. + (QTY_CMP_PRI, QTY_CMP_SUGG): New macros. + (qty_compare_1, qty_sugg_compare_1): Use them. + +Tue Nov 12 13:20:25 1996 Jim Wilson + + * fold-const.c (merge_ranges): In (+,-) case, treat subset specially + if lower bounds are the same. + +Tue Nov 12 13:10:01 1996 J.T. Conklin + + * m68k.md (addsi3): If TARGET_5200, use the lea insn to add small + constants to address registers. + (negsi2): Change into define_expand. + (negsi2_internal): Rename from old negsi2, changed condition + to !TARGET_5200. + (negsi2_5200): New insn. + (one_cmplsi2): Change into define_expand. + (one_cmplsi2_internal): Rename from old one_cmplsi2, changed + condition to !TARGET_5200. + (one_cmplsi2_5200): New insn. + (negdi2_5200): Corrected constraints. + (one_cmpldi2): Changed condition to !TARGET_5200. + + * m68k.c (m68k_align_loops_string, m68k_align_jumps_string): New vars. + (m68k_align_funcs_string, m68k_align_loops): Likewise. + (m68k_align_jumps, m68k_align_funcs): Likewise. + (override_options): New function. + * m68k.h (TARGET_OPTIONS): Added alignment options. + (MAX_CODE_ALIGN, ASM_OUTPUT_LOOP_ALIGN, ASM_OUTPUT_ALIGN_CODE): + New macros. + (FUNCTION_BOUNDARY): Use value derrived from m68k_align_funcs + instead of constant. + + * m68k.c (output_function_{pro,epi}logue): Fix typo in last change. + +Tue Nov 12 09:26:51 1996 Torbjorn Granlund + + * i386.md (parallel inc/dec and branch-if-zero/nonzero): Use `+' in + constraint. + +Mon Nov 11 15:12:22 1996 Jason Merrill + + * libgcc2.c: Also define WEAK_ALIAS if ASM_OUTPUT_WEAK_ALIAS. + * mips/iris6.h (ASM_OUTPUT_WEAK_ALIAS): Define. + * varasm.c (assemble_alias): Use ASM_OUTPUT_WEAK_ALIAS. + + * dwarf2out.c (TYPE_USED_FOR_FUNCTION): Lose. + (gen_compile_unit_die): Only append -g with -g2 or better. + (scope_die_for): Don't emit any type info with -g1. + (gen_subprogram_die): Likewise. + (gen_decl_die): Likewise. + (dwarfout_file_scope_decl): Likewise. + (dwarfout_init): Likewise. + + * mips/iris6.h (TYPE_ASM_OP): Define. + (SIZE_ASM_OP): Define. + (ASM_WEAKEN_LABEL): Define. + (BSS_SECTION_ASM_OP): Define. + (ASM_OUTPUT_ALIGNED_LOCAL): Don't use ASM_DECLARE_OBJECT_NAME. + (ASM_OUTPUT_ALIGNED_BSS): Define. + (ASM_DECLARE_OBJECT_NAME): Redefine to emit .size directive. + (ASM_FINISH_DECLARE_OBJECT): Define. + (ASM_OUTPUT_DEF): Don't define. + +Fri Nov 8 20:38:51 1996 Jim Wilson + + * function.c (expand_function_end): Handle BLKmode structures returned + in registers. + +Fri Nov 8 20:27:07 1996 Jason Merrill + + * stor-layout.c (layout_record): Check for VAR_DECL instead + of TREE_STATIC. + + * varasm.c (assemble_variable): Do write out DWARF for + record-scope variables. + * toplev.c (rest_of_type_compilation): Do write out DWARF for + record-scope types. + + * dwarf2out.c (gen_enumeration_type_die): Set TREE_ASM_WRITTEN on a + complete enum type. + (gen_struct_or_union_type_die): Don't recurse between nested classes. + (gen_type_die): Write out nested classes by writing out their context. + +Fri Nov 8 17:40:27 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * emit-rtl.c (change_address): If MEMREF isn't changing, + return the old one. + + * expr.c (expand_assignment): Remove bogus resetting of alignment + to inner alignment. + (expand_expr, case COMPONENT_REF): Likewise. + +Fri Nov 8 16:31:31 1996 Stan Cox + + * reg-stack.c (compare_for_stack_reg, subst_stack_regs_pat): + Add support for float conditional move. + +Thu Nov 7 07:46:07 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * stor-layout.c (layout_record): Treat constant size as variable if + it overflows. + * fold-const.c (const_binop, case *_DIV_EXPR): Don't do special + sizetype case if a constant overflows. + (size_binop): Use integer_{zero,one}p instead of explicit test. + * tree.c (integer_{zero,one,all_ones,pow2}p, real_{zero,one,two}p): + Return 0 if TREE_CONSTANT_OVERFLOW. + +Wed Nov 6 17:53:33 1996 Torbjorn Granlund + + * i386.md (parallel inc and branch-if-zero/nonzero): Add two + new pattern variants. Change incrementing pattern to use incl/jnz. + +Wed Nov 6 09:46:10 1996 Stan Cox + + * i386.c (override_options): Set defaults for -march and -mcpu. + (output_float_compare): Use cc_status.flags to mark if this + comparison can be done with fcomi. + (output_fp_cc0_set): A conditional move may be in a PARALLEL. + + * i386.h (CC_FCOMI): Define + + * i386.md (sgt,sgtu,sge,sle,bgt,blt,bge,ble): Use CC_FCOMI + (movsicc_1,movhicc_1): Use correct size suffix. + (movsfcc_1,movdfcc_1): Cleanup default move case. + +Wed Nov 6 09:46:10 1996 J"orn Rennecke + + * i386.h (HARD_REGNO_MODE_OK): If long double isn't XFmode, can't + allow XFmode. + +Tue Nov 5 22:49:56 1996 J"orn Rennecke + + * sh.md (define_split for and_shl_scratch): + Use rtx_equal_p on the operands to find out which alternative is used. + * sh.c (gen_shl_and): Try to generate shorter constant for and. + +Mon Nov 4 19:13:52 1996 Jason Merrill + + * dwarf2out.c: Clean up unused variables. + Use ASM_{GENERATE,OUTPUT}_INTERNAL_LABEL, shorten label names. + (loc_descriptor): Use reg_loc_descriptor. + (TYPE_DECL_IS_STUB): New macro. + (gen_decl_die): Use it. + (dwarfout_file_scope_decl): Use it. + +Mon Nov 4 10:23:46 1996 Michael Meissner + + * ginclude/va-ppc.h (__va_regsave_t,va_start,va_end): Wrap macro + and structures inside #ifndef __VA_PPC_H__ to allow reinclusion. + + * rs6000.h (LEGITIMATE_SMALL_DATA_P): Don't allow -fpic or TARGET_TOC. + (LEGITIMATE_LO_SUM_ADDRESS_P, LEGITIMIZE_ADDRESS): Likewise. + + * rs6000.md (movsi): Don't call elf_{high,low} if -fpic. + + * rs6000/cygwin32.h (STARTFILE_SPEC): Eliminate empty %{}. + +Sun Nov 3 15:56:35 1996 Michael Meissner + + * rs6000/sysv4.h (TARGET_TOC): Plain -fpic does not require a TOC. + ({MINIMAL_TOC,CONST}_SECTION_ASM_OP): -fpic should be treated like + -mrelocatable in these cases. + (ASM_OUTPUT_INT, ASM_OUTPUT_SECTION_NAME): Likewise. + (ASM_OUTPUT_ALIGNED_LOCAL): Use sdata_section, not sbss_section. + +Fri Nov 1 19:57:13 1996 Jason Merrill + + * dwarf2out.c (based_loc_descr): Use DBX_REGISTER_NUMBER. The + "frame base" is just the frame or stack reg without an offset. + (gen_subprogram_die): Likewise. + (dwarfout_begin_function): Use DBX_REGISTER_NUMBER. + +Fri Nov 1 09:50:05 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * fold-const.c (make_range): Don't merge unsigned case with range + containing upper bound; instead merge just with zero and convert + a range with no upper bound to opposite one with no lower bound. + (merge_ranges): In (+,-) case, don't treat subset specially if + the upper bounds are the same; fix typo in others case here. + +Thu Oct 31 20:12:13 1996 Jeffrey A Law (law@cygnus.com) + + * fold-const.c (make_range, case PLUS_EXPR): Correct + normalization of an unsigned range that wraps around zero. + +Thu Oct 31 21:06:37 1996 Jason Merrill + + * mips/t-iris6 (EXTRA_MULTILIB_PARTS): Define. + (EXTRA_PARTS): Don't define. + + * dwarf2out.c (gen_struct_or_union_type_die): Use AT_specification + for nested types defined outside their containing class. Lose + is_complete. + (gen_enumeration_type_die): Lose is_complete. + (gen_type_die): Lose is_complete. + (add_name_and_src_coords_attributes): Tweak. + (gen_subroutine_type_die): Use scope_die_for. + (gen_ptr_to_mbr_type_die): Likewise. + (gen_subprogram_die): Support AT_artificial. + (gen_variable_die): Likewise. + (dwarfout_file_scope_decl): Lose finalizing. + +Thu Oct 31 18:43:18 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * pa.c (emit_move_sequence): Refine previous change. + +Thu Oct 31 13:25:32 1996 Jim Wilson + + * crtstuff.c: Put HAS_INIT_SECTION ifdefs around Irix6 support. + + * tree.c (decl_function_context): Handle QUAL_UNION_TYPE. + + * calls.c (expand_call): Disable special handling for const calls + that return a PARALLEL rtx. + * expr.c (expand_expr, case CONSTRUCTOR): Don't use a PARALLEL + target. + +Thu Oct 31 11:45:00 1996 Michael Meissner + + * rs6000/t-{ppcgas,ppc,solaris} (EXTRA_MULTILIB_PARTS): Add + {e,s}crt{i,n,0}.o. + ({stmp,install}-crt): Delete, no longer used. + ({,INSTALL_}LIBGCC): Remove {stmp,install}-crt rule. + +Thu Oct 31 02:49:58 1996 Torbjorn Granlund + + * i386.md (parallel inc and branch-if-zero/nonzero): + Check for -1, not zero. + +Wed Oct 30 15:50:49 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * fold-const.c (range_binop): Strip NOPs from result and + verify it's an INTEGER_CST. + (make_range, case BIT_NOT_EXPR): Fix typo in constant for PLUS_EXPR. + + * stor-layout.c (layout_record): Use HOST_WIDE_INT for size. + + * stmt.c (expand_asm_operands): Disallow matching constraints + on output and validate the numbers on inputs. + +Tue Oct 29 16:21:59 1996 Michael Meissner + + * gcc.c (process_command,main): Process -specs=file and -specs + file after reading the main specs file to allow the user to + override the default. + (DEFAULT_WORD_SWITCH_TAKES_ARG): Add specs to list. + (option_map): Likewise. + +Tue Oct 29 15:49:18 1996 Jason Merrill + + * Makefile.in (stmp-multilib): Pass $flags to s-m-sub in + MULTILIB_CFLAGS. + (stmp-multilib-sub): Build EXTRA_MULTILIB_PARTS. + ($(T)crt*.o): Add $(T), lose stamp-crt rule, use MULTILIB_CFLAGS. + (install-multilib): Install EXTRA_MULTILIB_PARTS. + +Mon Oct 28 20:09:39 1996 J"orn Rennecke + + * sh.md (shl_sext_ext): Don't accept simple left/right shift variant. + * sh.c (EXT_SHIFT_SIGNED): New macro. + (shl_sext_kind, gen_shl_sext): try left shift - sign extend - + left shift - arithmetic right shift in case 2. + +Mon Oct 28 14:55:42 1996 Jim Wilson + + * configure (sh-*-*): Set float_format to sh. + * config/float-sh.h: New file. + +Mon Oct 28 14:26:08 1996 Ian Lance Taylor + + * mips/mips.h (RTX_COSTS): Add cases for SIGN_EXTEND and ZERO_EXTEND. + + * m68k/lb1sf68.asm: Change # to IMM in udivsi3 __mcf5200__. + + * combine.c (simplify_rtx): Add some optimizations for TRUNCATE. + (expand_compound_operation): Add some optimizations for ZERO_EXTEND. + +Mon Oct 28 14:11:20 1996 Gavin Koch + + * varasm.c (make_decl_rtl,assemble_variable): + Allow named sections for uninitialized variables. + +Mon Oct 28 13:08:51 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * pa.c (emit_move_sequence): If reload in progress, replace + reference to pseudo with reference to corresponding MEM. + + * c-typeck.c ({un,}signed_type): If can't do anything, call + signed_or_unsigned_type. + (signed_or_unsigned_type): If already right signedness, return. + +Mon Oct 28 13:05:26 1996 Stephen Williams (steve@icarus.com) + + * i960.h: Add specification for -Jx types. + * i960/t-960bare: Include multilib support for Jx types. + +Mon Oct 28 10:06:00 1996 Michael Meissner + + * rs6000/t-{ppc{,gas},solaris} (install-crt): Depend on + installdirs, not install-dir. + + * rs6000/sysv4.h (TARGET_TOC): -fpic does not use a TOC area. + +Mon Oct 28 09:07:42 1996 J"orn Rennecke + + * reload1.c (delete_output_reload): Don't use delete_insn + when deleting all stores into a replaced pseudo. + + * sh.md (movsf_ieq, movsf_ie): Merged the former into the latter. + Changed matching define_split appropriately. + (movsf): Changed appropriately. + (reload_insf) Define. + * sh.h (SECONDARY_INPUT_RELOAD_CLASS): Define. + +Mon Oct 28 08:38:23 1996 J"orn Rennecke + + * dsp16xx.h (ASM_OUTPUT_BYTE): Adjust definition to actual type of + VALUE, which is HOST_WIDE_INT. + +Mon Oct 28 07:36:07 1996 Ulrich Drepper + + * ginclude/stddef.h: Make sure file is processed if some of the + known __need_* macros is defined. + +Sun Oct 27 21:37:59 1996 J.T. Conklin + + * m68k.c (output_function_prologue): Adjust SP then use movmel with + plain address indirect mode for TARGET_5200. + (output_function_epilogue): Disable moveml and use several movel's + instead for TARGET_5200. + (output_function_{pro,epi}logue): Use lea instruction to adjust + stack pointer for short displacements for TARGET_5200. + +Sun Oct 27 15:27:45 1996 Jeffrey A Law (law@cygnus.com) + + * fold-const.c (merge_ranges): Fix thinko/typo. + +Sat Oct 26 22:07:04 1996 Ian Lance Taylor + + * expr.c (convert_modes): Before returning a const_double for a + large unsigned value, zero extend an integer value if necessary. + +Sat Oct 26 15:24:55 1996 Philippe De Muyter + + * m68k/x-mot3300 (XCFLAGS): Disable native assembler's jump + optimization for expr.o and cp/decl.o. + +Sat Oct 26 14:04:09 1996 Ben Harris + + * m68k.c (output_function_prologue): Add REGISTER_PREFIX to stack + probe instruction. + +Sat Oct 26 13:59:05 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * explow.c (allocate_dynamic_stack_space): Delete reference to + nonexistant macro ALLOCATE_OUTGOING_ARGS. + + * next.h (CPP_PREDEFINES): Add -D_NEXT_SOURCE. + +Sat Oct 26 13:50:49 1996 Mark Mitchell (mitchell@centerline.com) + + * configure (i486-ncr-sysv4*): Use i386/sysv4gdb if stabs and gas. + +Sat Oct 26 12:20:35 1996 John F. Carr + + * configure: Support --with-cpu=* for SPARC. Or target default + values instead of adding them. + * sparc.c (cpu_default): Add entries for v8 and supersparc. + * sparc.h: Define TARGET_CPU values for v8 and supersparc. + +Sat Oct 26 11:38:01 1996 Kamil Iskra + + * collect2.c (dump_file): Call fclose for opened files. + +Sat Oct 26 11:29:29 1996 J"orn Rennecke (amylaar@cygnus.co.uk) + + * jump.c (jump_optimize): Fix second error in last change. + + * svr3.h: Fix typo which makes comment text be non-comment. + +Fri Oct 25 16:18:39 1996 Michael Meissner + + * rs6000/t-winnt (LIBGCC1): Don't build libgcc1. + (EXTRA_PARTS): Build crti.o, crtn.o. + (stmp-crt): Remove old multilib support. + +Thu Oct 24 15:09:14 1996 Jim Wilson + + * fold-const.c (make_range, case PLUS_EXPR): Normalize an unsigned + range that wraps around 0. + +Thu Oct 24 14:37:17 1996 Ian Lance Taylor + + * mips.md: Change predicates for 64 bit arithmetic operations + so that they accept sign extended registers as operands. + (extendsidi2): Accept hi or lo as input. + * mips.c (movdi_operand, se_register_operand, + se_reg_or_0_operand, se_uns_arith_operand, se_arith_operand, + se_nonmemory_operand, se_nonimmediate_operand): New functions. + (mips_move_2words): Handle a SIGN_EXTEND source. + (print_operand): Handle a SIGN_EXTEND operand. + (mips_secondary_reload_class): Handle a SIGN_EXTEND rtx. + * mips.h: Declare new mips.c functions. + (PREDICATE_CODES): Add new functions. + +Thu Oct 24 07:41:14 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * fold-const.c (make_range, comparison cases): When making range + for unsigned to merge in, use full range. + + * stor-layout.c (GET_MODE_ALIGNMENT): Delete definition; duplicate. + +Thu Oct 24 07:28:53 1996 J"orn Rennecke + + * reload1.c (emit_reload_insns): Check for second_reloadreg + in SECONDARY_OUTPUT_RELOAD_CLASS / PRESERVE_DEATH_INFO_REGNO_P case. + +Wed Oct 23 14:27:43 1996 Mike Stump + + * crtstuff.c (__do_global_dtors_aux): Allow finalization code to + be run more than once. + * libgcc2.c (__do_global_dtors): Ditto. + +Wed Oct 23 20:42:23 1996 Joern Rennecke + + * sh.c (dump_table): handle SFmode and DFmode. + (broken_move): handle simple PARALLEL. + (machine_dependent_reorg, pc-relative move generation): Likewise. + * sh.h (CONST_DOUBLE_OK_FOR_LETTER_P): always true for 'F' . + (LEGITIMATE_CONSTANT_P): accept SFmode and DFmode. + * sh.md (movdf_k, movsf_i, movsf_ie): new alternative for + pc-relative load. + (movsf_ieq): new define_insn with matching define_split. + (movsf): use it where appropriate. + (consttable_sf, consttable_df): new define_insns. + +Wed Oct 23 17:48:32 1996 Andreas Schwab + + * svr4.h (MAKE_DECL_ONE_ONLY): Fix typo in use of macro parameter. + +Wed Oct 23 17:46:13 1996 Pat Rankin + + * cexp.y (yylex): Cast string literal to U_CHAR* for lookup() call. + +Wed Oct 23 14:50:04 1996 Jason Merrill + + * stmt.c (expand_return): Expand cleanups. Make sure we get pseudo + and provide target in non-BLKmode case. Get proper return type of fn. + +Wed Oct 23 14:16:06 1996 Ian Lance Taylor + + * reload.c (find_reloads): Handle any unary operator. + * recog.c (constrain_operands): Likewise. + + * mips.md: Remove extendsidi2 define_expand. + Rename extendsidi2_internal define_insn to extendsidi2, and add a + register to register case. + +Wed Oct 23 14:08:31 1996 Jim Wilson + + * a29k.c (a29k_makes_calls): New global variable. + (compute_regstack_size, a29k_compute_reg_names): New functions. + (output_prolog): Much code moved to two new functions. + Use a29k_makes_calls instead of makes_calls. + * a29k.h (ASM_DECLARE_FUNCTION_NAME): Call a29k_compute_reg_names. + + * calls.c (expand_call): In target code, move PARALLEL case above + target != case. + + * mips.c (block_move_load_store, block_move_sequence): Delete. + (block_move_loop): New parameter orig_dest. Call change_address to + create new MEM instead of gen_rtx. + (expand_block_move): New local orig_dest. Pass it to block_move_loop. + Call change_address to create new MEM instead of gen_rtx. + +Wed Oct 23 10:30:32 1996 J"orn Rennecke + + * loop.c (combine_givs): When combining a DEST_REG giv with its + only use, always set the benefit of the combined giv to that of + the DEST_REG giv. + + * emit-rtl (gen_lowpart_common): When converting a floating + point value into an integer, use WORD as (first) word. + + * combine.c (can_combine_p): When SMALL_REGISTER_CLASSES is defined, + avoid substituting a return register into I3. + + * optabs.c (emit_libcall_block): Before adding an REG_EQUAL note, + check that it will really apply to a single instruction. + (expand_binop, expand_fix): Likewise. + +Wed Oct 23 10:20:52 1996 Stephen L Moshier (moshier@world.std.com) + + * real.c (exact_real_inverse): New function, if REAL_ARITHMETIC. + * fold-const.c (exact_real_inverse): Likewise, if no REAL_ARITHMETIC. + (fold, case RDIV_EXPR): Turn divide by constant into multiplication + by the reciprocal, if optimizing and result is exact. + * real.h (exact_real_inverse): Declare. + +Wed Oct 23 00:12:52 1996 Torbjorn Granlund + + * expr.h (emit_store_flag_force): Declare. + +Tue Oct 22 18:32:20 1996 Jim Wilson + + * unroll.c (unroll_loop): Always reject loops with unbalanced blocks. + +Tue Oct 22 18:27:06 1996 Ian Lance Taylor + + * config/fp-bit.c (float_to_usi): Correct thinko: avoid negative shift. + (df_to_sf): Remember any discarded nonzero bits in the low order + guard bit. + + * ginclude/va-mips.h: Add support for -mips1 and -msoft-float when + using -mabi=eabi. + * mips/abi64.h (SETUP_INCOMING_VARARGS): When MIPS EABI, handle + TARGET_SINGLE_FLOAT or ! TARGET_FLOAT64 correctly when saving + floating point registers to the stack. + * mips/mips.c (mips_function_value): If TARGET_SINGLE_FLOAT, use + GP_RETURN for floating point types larger than 4 bytes. + +Tue Oct 22 09:43:49 1996 Geoffrey Noer + + * rs6000/cygwin32.h (LIB_SPEC): Add -lkernel32 all of the time, + and {user,gdi,comdlg}32 if -mwindows. + +Tue Oct 22 05:24:05 1996 Jason Merrill + + * dwarf2out.c (scope_die_for): Don't skip lexical blocks. + (gen_lexical_block_die): Call push_decl_scope. + (gen_subprogram_die): Never refer to the function symbol. + (dwarfout_begin_prologue): Likewise. + +Mon Oct 21 20:22:49 1996 Torbjorn Granlund + + * expmed.c (emit_store_flag_force): New function. + * optabs.c (expand_binop): Use it. + + * expr.c (do_store_flag): Don't check if target is 0 in code + emitting store flag as compare-branch. + +Mon Oct 21 17:58:33 1996 Ian Lance Taylor + + * mips.c (override_options): Correct typo (MASK_64BIT should + have been TARGET_64BIT). + +Mon Oct 21 13:58:54 1996 Jim Wilson + + * unroll.c (loop_comparison_code): New static variable. + (unroll_loop): Add check for loop_comparison_code + (loop_iterations): Set loop_comparison_code. + + * sh.c (gen_shl_sext): Add missing parameter to shl_sext_kind call. + + * mips.h (INITIAL_FRAME_POINTER_OFFSET): Delete. + + * loop.c (strength_reduce): Add check for ! bl->reversed to + auto_inc_opt code. + +Mon Oct 21 12:28:15 1996 J"orn Rennecke + + * jump.c (jump_optimize): Fix bug in Oct. 14 change. + +Mon Oct 21 07:59:16 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (store_expr): Disable optimization of using convert + if exp's type is a subtype. + + * c-typeck.c (build_array_ref): If -Wchar-subscripts, also warn + in case when pointer is being indexed. + +Mon Oct 21 07:39:31 1996 J"orn Rennecke + + * jump.c (jump_optimize): Use emit_store_flag even if branches + are cheap, if the store is even cheaper. + +Sun Oct 20 20:01:09 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * reload1.c (reload_reg_free_p, reloads_conflict): RELOAD_OTHER + and RELOAD_FOR_OTHER_ADDRESS conflict. + + * i386.md (ffs[sh]i2): Add missing CC_STATUS_INIT. + +Fri Oct 18 13:32:13 1996 Michael Meissner + + * rs6000.md (float conversion insns): Generate correct code + if the bit 15 of rs6000_fpmem_offset is non-zero. + +Thu Oct 17 23:22:03 1996 Jason Merrill + + * dwarfout.c (data_member_location_attribute): Support binfos. + (output_inheritance_die): New fn. + (output_type): Use it. + + * dwarf2out.c (value_format): Split out from... + (output_value_format): Here. + (build_abbrev_table): Use value_format. + (size_of_locs): New fn. + (size_of_die): Don't assume a loc needs a 2-byte length. + (value_format, output_die): Likewise. + +Thu Oct 17 14:46:14 1996 Ian Lance Taylor + + * mips.c (override_options): In 64 bit EABI mode, set TARGET_LONG64. + +Thu Oct 17 11:34:51 1996 Bob Manson + + * expr.c (do_jump): Conditionalize cleanups for the COND_EXPR case, + similarly to the way TRUTH_ANDIF_EXPR and TRUTH_ORIF_EXPR are + handled. + +Thu Oct 17 01:20:16 1996 Jim Wilson + + * m68k.h (MASK_68040_ALSO): New macro. + (TARGET_SWITCHES): Option -m68020-40 includes MASK_68040_ALSO. + +Wed Oct 16 16:25:38 1996 Jason Merrill + + * dwarf2out.c (scope_die_for): Also support decls, add asserts. + (modified_type_die): Modified types all go under comp_unit_die. + (add_type_attribute): Just pass context_die through. + (various): Revert useless lookup_type_die change. + (gen_subprogram_die): Use scope_die_for. Call push_decl_scope. + (gen_inlined_subroutine_die): Call push_decl_scope. + (gen_struct_or_union_type_die): Likewise. + (gen_decl_die): Don't call push_decl_scope. + + * mips/iris6.h (*_SPEC): Replace enumeration of !mabi= with !mabi*. + (ASM_OUTPUT_{CON,DE}STRUCTOR): Enable. + (STARTFILE_SPEC): Support -mips4, -shared. + (ENDFILE_SPEC): Likewise. + (LIB_SPEC): Support -shared, avoid warning 84. + (LIBGCC_SPEC): Define. + (LINK_SPEC): Support -shared, remove -woff 84. + * mips/t-iris6 (EXTRA_PARTS): Add crtstuff. + * crtstuff.c: Support Irix 6. + * configure: Don't use collect2 for Irix 6. + * libgcc2.c (__main): Don't use any of this stuff if HAS_INIT_SECTION. + +Wed Oct 16 11:46:37 1996 Mike Stump + + * elxsi.h (CHECK_FLOAT_VALUE): Removed. + +Wed Oct 16 14:19:38 1996 Jim Wilson + + * iris6.h (CPP_PREDEFINES): Add -D_LONGLONG. + (CPP_SPECS): Remove -D_LONGLONG. + +Wed Oct 16 03:34:42 1996 Torbjorn Granlund + + * i386.md (parallel inc/dec and branch-if-zero/nonzero): New patterns. + +Tue Oct 15 22:28:11 1996 Ian Lance Taylor + + * mips.h (enum mips_abi_type): Add ABI_EABI. + (CPP_SPEC): Define __mips_soft_float if -msoft-float, and + __mips_eabi if -mabi=eabi. + (INITIAL_ELIMINATION_OFFSET, CUMULATIVE_ARGS, + GO_IF_LEGITIMATE_ADDRESS, CONSTANT_ADDRESS_P, LEGITIMATE_CONSTANT, + LEGITIMIZE_ADDRESS): Add support for MIPS EABI. + * mips/abi64.h (STACK_BOUNDARY, MIPS_STACK_ALIGN, + FUNCTION_ARG_PADDING, RETURN_IN_MEMORY, SETUP_INCOMING_VARARGS): + Add support for MIPS EABI. + (FUNCTION_ARG_PASS_BY_REFERENCE): Define. + (FUNCTION_ARG_CALLEE_COPIES): Define. + * mips.c (mips_const_double_ok, function_arg_advance, + function_arg, function_arg_partial_nregs, override_options, + compute_frame_size): Add support for MIPS EABI. + (function_arg_pass_by_reference): New function. + * ginclude/va-mips.h: Add support for MIPS EABI. + +Tue Oct 15 19:10:08 1996 Jason Merrill + + * toplev.c (rest_of_type_compilation): Don't write out + DWARF for function-scope types yet. + (compile_file): Do send vars with no RTL to the DWARF code. + +Tue Oct 15 17:54:43 1996 Doug Evans + + * loop.c (strength_reduce): Avoid taking PATTERN of a label. + +Tue Oct 15 16:52:33 1996 Ian Lance Taylor + + * mips/iris6.h: (SUBTARGET_CPP_SIZE_SPEC): Define. + (SUBTARGET_CPP_SPEC): Remove definitions of __SIZE_TYPE__ and + __PTRDIFF_TYPE__, now in SUBTARGET_CPP_SIZE_SPEC. + +Tue Oct 15 11:19:17 1996 Lee Iverson + + * mips.h (CPP_SPEC): Restore -D_LANGUAGE_C for Objective C. + +Mon Oct 14 18:03:35 1996 Jason Merrill + + * dwarf2out.c (gen_decl_die): Do generate dies for classes with -g1. + (dwarfout_file_scope_decl): Likewise. + +Mon Oct 14 16:31:44 1996 Joern Rennecke + + * jump.c (jump_optimize): Check for if (...) { x = a; goto l; } x = b; + +Mon Oct 14 14:19:49 1996 Jason Merrill + + * dwarf2out.c (modified_type_die): Don't bother with AT_address_class. + (add_data_member_location_attribute): Handle getting a binfo. + (add_location_or_const_value_attribute): Handle a decl with no RTL. + (add_pure_or_virtual_attribute): Add AT_vtable_elem_location. + (add_name_and_src_coords_attributes): Only use DECL_ASSEMBLER_NAME + for staticp things. + (gen_subprogram_die): Set up AT_inline for abstract decls. + (gen_inheritance_die): New fn. + (gen_member_die): Also emit info for base classes. + +Sat Oct 12 00:07:00 1996 Doug Evans + + * fold-const.c (make_range): Handle NULL operand 0 like in BIND_EXPRs. + +Fri Oct 11 15:42:22 1996 Jason Merrill + + * toplev.c (rest_of_compilation): If we did a + save_for_inline_copying, reset DECL_ABSTRACT_ORIGIN for the + function when we're done. + + * toplev.c (main): DWARF works with C++ now. + + * dwarf2out.c (gen_subprogram_die): Disable MIPS_AT_has_inline + support for now. + +Fri Oct 11 14:31:10 1996 Torbjorn Granlund + + * dwarfout.c: (output_bound_representation): Fix typo in prototype. + +Fri Oct 11 12:19:21 1996 Ian Lance Taylor + + * mips.h ({,SUBTARGET_}MIPS_AS_ASM_SPEC): Define. + ({GAS,TARGET,SUBTARGET}_ASM_SPEC): Define. + (SUBTARGET_ASM_{OPTIMIZING,DEBUGGING}_SPEC): Define. + (ASM_SPEC): Rewrite to use above specs. + (SUBTARGET_CPP{,_SIZE}_SPEC): Define. + (CPP_SPEC): Use above specs. Don't define _LANGUAGE_C if C++ or + Objective C. + ({,SUBTARGET_}EXTRA_SPECS): Define. + * mips/dec-bsd.h ({CPP,ASM}_SPEC): Don't define. + * mips/dec-osf1.h (CPP_SPEC): Don't define. + (SUBTARGET_CPP_SIZE_SPEC): Define. + * mips/elf64.h (CPP_SPEC): Don't define. + (SUBTARGET_CPP_SPEC): Define. + * mips/gnu.h (TARGET_DEFAULT): Define. + (ASM_SPEC): Don't define. + * mips/iris3.h (CPP_SPEC): Don't define. + (SUBTARGET_CPP_SPEC): Define. + * mips/iris4loser.h (ASM_SPEC): Don't define. + (SUBTARGET_MIPS_AS_ASM_SPEC): Define. + (SUBTARGET_ASM_OPTIMIZING_SPEC): Define. + * mips/iris5.h (CPP_SPEC): Don't define. + (SUBTARGET_CPP_SPEC): Define. + * mips/iris6.h ({CPP,ASM}_SPEC): Don't define. + (SUBTARGET_{CPP,ASM,MIPS_AS_ASM,ASM_DEBUGGING}_SPEC): Define. + * mips/netbsd.h ({CPP,ASM}_SPEC): Don't define. + (SUBTARGET_CPP_SPEC): Define. + * mips/osfrose.h ({CPP,ASM,ASM_FINAL}_SPEC): Don't define. + (SUBTARGET_CPP{,_SIZE}_SPEC): Define. + * mips/sni-svr4.h (CPP_SPEC): Don't define. + (SUBTARGET_CPP_SIZE_SPEC): Define. + +Thu Oct 10 17:58:49 1996 Jason Merrill + + * mips/iris6.h (ASM_OUTPUT_SECTION_NAME): Define. + (DWARF_OFFSET_SIZE): Define. + + * dwarf2out.c (most everywhere): Support SGI/MIPS -mabi=64 by fixing + code which assumed pointers are 4 bytes long, parameterizing many + sizes on DWARF_OFFSET_SIZE and using DELTA instead of DELTA4, + DATA instead of DATA4, FORM_ref instead of FORM_ref4. + (DWARF_ROUND, UNALIGNED_DOUBLE_INT_ASM_OP): New macros. + (UNALIGNED_WORD_ASM_OP, ASM_OUTPUT_DWARF_DELTA): Likewise. + (ASM_OUTPUT_DWARF_DATA, DW_FORM_data, DW_FORM_ref): New macros. + (gen_variable_die): Only equate_decl_number_to_die if + decl is TREE_STATIC. + (get_AT): Fix thinko. + + * dwarf2out.c (constant_size): New fn. + (size_of_die): Use it instead of assuming 4 bytes. + (output_value_format, output_die): Likewise. + (build_abbrev_table): Need new abbrev if size of constant differs. + (dwarf_attr_name): Add new SGI/MIPS extensions. + (gen_subprogram_die): Support DW_AT_MIPS_has_inlines. + (gen_inlined_subroutine_die): Likewise. + +Thu Oct 10 16:38:58 1996 Ian Lance Taylor + + * mips.md (mov[sd]fcc): Use register_operand, not reg_or_0_operand, + for source predicates. + +Thu Oct 10 15:19:38 1996 Michael Meissner + + * rs6000.md (floatsidf2_load): For large stack frames, do not + generate an illegal memory reference. + (movdi, movdf define_splits): Fix code so that it works for either + big or little endian hosts generating code for either big or + little endian targets. + + (from Jim Wilson) + * rs6000.c (rs6000_save_toc_p): Delete global variable. + (rs6000_{save,restore}_machine_status): Do not save/restore it. + (rs6000_init_expanders): Do not initialize it. + (rs6000_stack_info): Always create TOC save space. + + * rs6000.md (NT indirect call insns): Do not set + rs6000_save_toc_p. + + * rs6000.h (rs6000_save_toc_p): Delete declaration. + +Wed Oct 9 18:06:54 1996 Ian Lance Taylor + + * mips.h (EMPTY_FIELD_BOUNDARY): Define as 32. + * mips/abi64.h (EMPTY_FIELD_BOUNDARY): Don't define. + + * mips/abi64.h (TARGET_DEFAULT, TARGET_LONG64, CPP_PREDEFINES, + CPP_SPEC): Move from here... + * mips/iris6.h: ...to here. + +Wed Oct 9 16:43:51 1996 Jim Wilson + + * configure (i[3456]86-dg-dgux): Use install-headers-cpio. + + * expr.c (store_constructor): Delete unnecessary increment. + +Wed Oct 9 16:29:22 1996 Gavin Koch + + * cccp.c (do_include): Treat ENOTDIR like ENOENT when an open fails. + +Wed Oct 9 16:26:57 1996 Paul Eggert + + * gcc.c (default_compilers): -ansi no longer implies -$ to cpp. + * c-lex.c (yylex): Treat `$' just like `_', except issue a + diagnostic if !dollars_in_ident or if pedantic. + * c-decl.c (dollars_in_ident): DOLLARS_IN_IDENTIFIERS is now Boolean. + (c_decode_option): -fdollars-in-identifiers is now independent + of -ansi, of -traditional, and of DOLLARS_IN_IDENTIFIERS. + * cexp.y (initialize_random_junk): Ignore DOLLARS_IN_IDENTIFIERS. + * cccp.c (dollars_in_ident): Remove; replaced by is_idchar['$']. + (main): Initialize is_idchar and is_idstart directly when given -$. + Ignore DOLLARS_IN_IDENTIFIERS. + (rescan): Diagnose $ in identifier if pedantic. + (initialize_char_syntax): Assume $ is allowed in identifier; + `main' will change this if -$ is given. + * cpplib.h (DOLLARS_IN_IDENTIFIERS): Remove. + * cpplib.c (cpp_options_init): Ignore DOLLARS_IN_IDENTIFIERS. + (parse_name): Diagnose $ in identifier if pedantic. + (cpp_handle_options): -traditional no longer messes with + dollars_in_ident. + * i386/dgux.h, m68k/apollo68.h (DOLLARS_IN_IDENTIFIERS): Remove. + * m88k.h, mips.h, nextstep.h, pa.h (DOLLARS_IN_IDENTIFIERS): Remove. + * vax/ultrix.h, vax/vms.h (DOLLARS_IN_IDENTIFIERS): Remove. + * convex.h (OVERRIDE_OPTIONS): Don't need to set + dollars_in_ident any more, since -ansi doesn't change it. + +Wed Oct 9 07:35:47 1996 Doug Evans + + * Allow prefix attributes in more places. + * c-parse.in: Update number of shift/reduce conflicts. + ({typed_declspecs,reserved_declspecs,declmods}_no_prefix_attr): New. + (current_declspecs): Initialize to NULL_TREE. + (fndef): Pass current_declspecs, not $1, to start_function. + (old_style_parm_decls): Renamed from xdecls. + (datadecl, declmods): Add references to new rules. + (setspecs): Call split_specs_attrs. + (absdcl1): Remove case with setattrs. + * c-common.c (split_specs_attrs): New function. + +Wed Oct 9 05:48:43 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * sdbout.c: Include defaults.h. + * Makefile.in (sdbout.o): Make dependency list match included files. + + * fold-const.c (range_test): Function deleted. + (range_binop, make_range, build_range_check): New functions. + (merge_ranges, fold_range_test): Likewise. + (fold_truthop): No longer call range_test. + (fold, case TRUTH_{AND,OR}{,IF}_EXPR): Call fold_range_test. + +Tue Oct 8 22:03:32 1996 Torbjorn Granlund + + * configure: Set cpu_type for pyramid. + +Tue Oct 8 21:54:04 1996 Jason Merrill + + * final.c (final_start_function): Call dwarfout_begin_prologue. + + * dwarf2out.c (pubname_*, arange_*): New data for .debug_pubnames + and .debug_aranges sections. + (add_pubname): New fn. + (size_of_pubnames): Reimplement. + (output_pubnames): Likewise. + (add_arange): New fn. + (size_of_aranges): Include function sections. + (output_aranges): Likewise. + (gen_variable_die): Call add_pubname. + (add_name_and_src_coords_attributes): Use DECL_ASSEMBLER_NAME for now. + (decl_start_label): Renamed from function_start_label. + (gen_subprogram_die): If weak or one_only, use a local label for + AT_low_pc. Call add_pubname and add_arange. + (dwarfout_begin_prologue): New fn. Start up FDE here. + (dwarfout_begin_function): Not here. + (get_AT): Split out. Look in specification and abstract_origin DIEs. + (get_AT_low_pc, get_AT_string, get_AT_flag, get_AT_unsigned, + get_AT_hi_pc): Use it. + (dwarfout_finish): Variables can produce pubnames, too. + +Tue Oct 8 19:35:40 1996 Torbjorn Granlund + + * m88k/dgux.h (CPP_SPEC): Avoid newline in the string. + + * final.c (final): Update insn_current_address before calling + final_scan_insn. + +Tue Oct 8 17:52:02 1996 Jim Wilson + + * unroll.c (unroll_loops): Set local_regno only if set_dominates_use + returns true. + (set_dominates_use): New function. + +Tue Oct 8 16:01:37 1996 Doug Evans + + * c-typeck.c (decl_constant_value): Delete test for ! TREE_PUBLIC. + +Tue Oct 8 10:36:44 1996 Jeffrey A Law (law@cygnus.com) + + * pa.c (hppa_legitimize_address): Remove test code accidentally left + in during last change. + +Mon Oct 7 19:55:02 1996 Jim Wilson + + * sched.c (schedule_block): Before scheduling, add code to make all + call used regs not fixed or global live when we see a CALL_INSN. + During scheduling, change existing code to use same test. + + * varasm.c (bss_section): Delete unused parameters. + +Mon Oct 7 16:24:21 1996 Jason Merrill + + * dwarf2.h: Add new SGI/MIPS attributes. + + * dwarf2out.c (*_separate_line_info_*): Parallel line number + information for functions defined in sections other than .text. + (size_of_line_info): Support it. + (output_line_info, dwarfout_line): Likewise. + (gen_compile_unit_die): Don't add high/low_pc or stmt_list + attributes here. + (dwarfout_finish): Add them here if appropriate. + (remove_AT): Free removed attribute properly. + (gen_type_die): Don't assume a nested type is complete. + (dwarfout_finish): Don't emit line info if it would be empty. + + * dwarfout.c (output_block): Don't emit a DIE for a body block. + (output_decls_for_scope): Don't increment next_block_number for the + outer block. + (output_decl): Start from the outer block, not + the first inner block since there can be more than one in C++. + (type_tag): Handle C++ TYPE_NAME. + (output_type): Fix handling of TYPE_METHODS. + (output_decl): Don't output a DIE for artificial typedefs. + +Mon Oct 7 15:47:29 1996 Michael Meissner + + * rs6000.md (movdi define_splits): Fix previous change to work + on both little and big endian hosts. + +Sun Oct 6 16:52:34 1996 Jeffrey A Law (law@cygnus.com) + + * pa.h (combinable_fsub): Don't return without a value. + +Sun Oct 6 14:05:39 1996 Michael Meissner + + * rs6000.md (mov{df,di} define_splits): Use split_double to + properly split CONST_DOUBLEs. + (movdi): Likewise. + +Sat Oct 5 08:43:14 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * i386/cygwin32.h (LIB_SPEC): Add support for -mwindows. + Always pass -lkernel32. + (LIBGCC_SPEC): Don't delete. + (STARTFILE_SPEC): Remove always-true conditionalization. + (LONG_DOUBLE_TYPE_SIZE): Use default. + +Fri Oct 4 17:22:53 1996 Jason Merrill + + * toplev.c (rest_of_type_compilation): Don't emit DWARF for member + types of a type we haven't emitted yet. + (compile_file): Still emit DWARF for pending tagged types. + + * final.c (final_scan_insn): Do emit DWARF labels for level 1 blocks. + + * dwarf2out.c (gen_subprogram_die): Start from the outer block, not + the first inner block since there can be more than one in C++. + (gen_lexical_block_die): Keep track of the block depth. + (gen_block_die): Don't emit a DIE for a body block. + (gen_inlined_subroutine_die): Don't emit anything for an + abstract instance. + (decls_for_scope): Don't increment next_block_number for the + outer block. + +Fri Oct 4 15:27:55 1996 J"orn Rennecke + + * sh.h (PRESERVE_DEATH_INFO_REGNO_P): Define. + + * sh.c (sfunc_uses_reg): New function. + (noncall_uses_reg, machine_dependent_reorg, final_prescan_insn): + Handle special functions like function calls for purposes of relaxing. + (noncall_uses_reg): Added some missing cases of registers + being used in non-call instructions. + +Fri Oct 4 10:51:40 1996 Jason Merrill + + * dwarf2out.c: Tear out backchaining brain damage. + (remove_AT, remove_children): New functions. + (modified_type_die): Call gen_type_die instead of backchaining. + (gen_subprogram_die): Don't generate a new specification DIE for + member functions defined in the class; use the declaration DIE instead. + (gen_struct_or_union_type_die): Support DW_AT_declaration. + (gen_type_die): Don't set TREE_ASM_WRITTEN on incomplete structs. + (gen_decl_die): Revert previous change; it's much simpler to emit + the class from rest_of_type_compilation. + +Fri Oct 4 09:54:21 1996 J"orn Rennecke + + * Make sure we have enough registers for the insns we recognize. + * i386.h (flag_omit_frame_pointer, outer_function_chain): Declare. + (current_function_calls_alloca): Likewise + (rtx_equal_function_value_matters): Likewise + (N_REGS_USED, N_ALLOCATABLE_REGISTERS): Define. + + * i386.md (adddi3_1, subdi3_1): Insns renamed from adddi3 and subdi3; + added missing earlyclobbers. + (adddi3_1): Removed duplicates from commutativity. + (adddi3, subdi3): New define_expands. + (movsf, movsf_mem, movsf_normal, movdf, movdf_mem , movdf_mem+1): Take + number of used vs. available registers into account. + (movxf, movxf_mem, movxf_mem+1, addsidi3_1, addsidi3_2): Likewise. + (adddi3_1, subsidi3, subdi3_1): Likewise. + (addsidi3_1, addsidi3_2, subsidi3): Need no generate function. + + * i386.c (asm_output_function_prefix): Don't use + ASM_DECLARE_FUNCTION_NAME if it is not defined. + +Fri Oct 4 07:01:55 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * stor-layout.c (layout_decl): Don't turn off DECL_BIT_FIELD + if DECL's alignment is less than its type. + +Thu Oct 3 19:42:30 1996 Jason Merrill + + * toplev.c (rest_of_type_compilation): Also do this for DWARF. + (compile_file): Don't try to write out DWARF for vars with no RTL. + +Thu Oct 3 18:31:28 1996 Doug Evans + + * ginclude/{stdarg.h,varargs.h}: Use #include "", not #include <>. + +Wed Oct 2 17:29:53 1996 Ian Lance Taylor + + * fixincludes: Add a hack to the big sed script to work around a + bug in the sed implementation on HP/UX 10.20. + +Wed Oct 2 16:53:56 1996 Jason Merrill + + * dwarf2out.c (modified_type_die): Don't generate redundant DIEs. + (gen_{array,pointer,reference,ptr_to_mbr}_type_die): Likewise. + (gen_{subroutine,string,set}_type_die): Likewise. + + * dwarf2out.c: Undo text_end_label, add_src_coords changes. + (addr_const_to_string): Fix typos. + (decl_class_context, get_AT_unsigned): New functions. + (gen_subprogram_die): Only emit src coords info for a specification + if they changed. + (gen_variable_die): Support DW_AT_declaration and DW_AT_specification. + (gen_decl_die): Avoid generating redundant DIEs for member functions + and variables. + +Wed Oct 2 11:22:50 1996 Jeffrey A Law (law@cygnus.com) + + * pa.h (EXTRA_CONSTRAINT): Loosen conditions for match of + 'Q' and 'T' while reload is running. + * pa.c (hppa_legitimize_address): Rework to generate more + indexed and scaled indexed addressing. + * pa.md (scaled indexed store): Add define_splits to undo + pessimizations created by hppa_legitimize_address for integer stores. + + * pa.c (remove_useless_addtr_insns): New function. + (pa_reorg): Delete code to remove useless add,tr insns. + Instead call remove_useless_addtr_insns. + (output_function_prologue): Call remove_useless_addtr_insns + to catch any add,tr insns created by reorg. + + * pa.c (secondary_reload_class): Remove duplicate/useless code. + + * pa.h (PARSE_LDD_OUTPUT): Handle output from hpux10.20 "chatr". + +Tue Oct 1 17:23:32 1996 Jason Merrill + + * dwarf2out.c (text_end_label): New static. + (size_of_line_info): The final entry is smaller. + (output_aranges): Use TEXT_SECTION instead of TEXT_BEGIN_LABEL and + text_end_label instead of TEXT_END_LABEL. + (gen_compile_unit_die): Likewise. + (output_line_info): Likewise. Use a fixed advance for the last entry. + (dwarfout_init): Don't output starting labels. + (dwarfout_finish): Set up text_end_label. Don't output ending labels. + + (add_pure_or_virtual_attribute): Don't say pure virtual for now. + (type_tag): Handle C++ TYPE_NAME. + (gen_formal_parameter_die): Support DW_AT_artificial. + (gen_formal_types_die): Do emit the type for 'this'. + (gen_member_die): Fix handling of TYPE_METHODS. + (gen_decl_die): Do output a DIE for member function declarations. + Don't output a DIE for artificial typedefs. + + (add_member_attribute): Remove, not in DWARF-II. + (gen_array_type_die): Remove ref to add_member_attribute. + (gen_set_type_die, gen_entry_point_die, gen_enumeration_type_die, + gen_subprogram_die, gen_variable_die, gen_field_die, + gen_pointer_type_die, gen_reference_type_die, gen_ptr_to_mbr_type_die, + gen_string_type_die, gen_struct_or_union_type_die, + gen_subroutine_type_die, gen_typedef_die): Likewise. + + (get_AT_flag): New fn. + (add_src_coords_attributes): Split out... + (add_name_and_src_coords_attributes): From here. + (gen_subprogram_die): Support DW_AT_declaration and + DW_AT_specification. + + (gen_compile_unit_die): Don't emit full pathname for source file; + comment claimed that SGI required it, but they don't emit it either. + Append -g to producer rather than replacing it. + +Tue Oct 1 14:19:23 1996 Jim Wilson + + * gcc.c (used_arg): When call xmalloc for mswitches, pass 1 if + n_switches is zero. + +Mon Sep 30 17:46:26 1996 J"orn Rennecke + + * sh.c (gen_shl_and, gen_shl_sext): Use gen_lowpart to + generate rtx in the appropriate mode for zero/sign-extension. + Don't generate a zero bit shift. + (gen_shl_sext) Directly use gen_ashift instead of gen_ashrsi3. + +Mon Sep 30 17:17:56 1996 Ian Lance Taylor + + * fixinc.svr4: In math.h, redefine exception to __math_exception + for C++, to avoid conflict with . + * fixincludes: Likewise. + Fix check for class in math.h to not match fp_class. + +Mon Sep 30 17:15:19 1996 Jim Wilson + + * iris6.h (ASM_SPEC): Add -w. + (STARTFILE_SPEC): Add mips3 to n32 pathnames. + Add -L/usr/lib32/mips for n32 cases. + (ENDFILE_SPEC): Add mips3 to n32 pathnames. + +Mon Sep 30 13:20:31 1996 Ian Lance Taylor + + * genopinit.c (gen_insn): Look through the modes in reverse order, + to avoid stopping early on CC when EXTRA_CC_MODES is used. + + * fixincludes: Add extern "C" to on HP/UX. + +Sun Sep 29 12:39:18 1996 Michael Meissner + + * c-typeck.c (pointer_diff): Do not do default conversions when + doing the minus expression, in case restype is a short type. + +Sun Sep 29 11:22:10 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * tree.c (build_complex): Add new argument, TYPE. + * tree.h (build_complex): Likewise. + * c-lex.c (yylex): Add new arg, TYPE, to call to build_complex. + * fold-const.c (const_binop): Likewise. + (fold, case CONJ_EXPR, COMPLEX_EXPR): Likewise. + * varasm.c (copy_constant, case COMPLEX_CST): Likewise. + * expr.c (expand_expr, case COMPONENT_REF): Don't try to directly + load a complex. + * recog.c (register_operand): Don't reject subreg of complex mode. + * emit-rtl.c (mark_user_reg): New function. + * function.c (assign_parms): Use it. + * stmt.c (expand_decl): Likewise, and simplify code. + + * tree.c (contains_placeholder): Return 1 for PLACEHOLDER_EXPR. + + * expr.c (store_expr): memset/bzero gets ptr_mode, not Pmode. + + * stmt.c (expand_asm_operands): Fix errors in previous patches. + + * x-linux: Simplify, but ensure headers aren't changed. + + * getpwd.c: No longer include direct.h for _WIN32. + + * configure (i[3456]86-*-isc*): Remove bogus echo. + (m68k-apple-aux*): a-ux.h renamed from aux.h. + (CC): Escape "$" char in "no-symlink" case for bash/cygwin32 bug. + + * Makefile.in (installdirs): Renamed from install-dir. + Create $(prefix) and $(exec_prefix) if doesn't exist. + (install-float): Reflect new name for installdirs. + (install-{common,info,man,libgcc,multilib,libobjc}): Likewise. + (install-{include-dir,assert-h,collect2}): Likewise. + + * reload1.c (gen_reload): Handle SUBREG in PLUS specially too. + Change calls to emit_move_insn to recursive calls. + + * stmt.c (fixup_gotos): When running undefined labels, if no cleanup + actions for this block, don't clear BEFORE_JUMP. + +Fri Sep 27 13:48:21 1996 Michael Meissner + + * c-decl.c (init_decl_processing): Create short int types before + creating size_t in case a machine description needs to use + unsigned short for size_t. + +Fri Sep 27 12:28:54 1996 Stan Cox + + * gcc.c (do_spec_1): Allow -A in %[Spec]. + + * i386.h (CPP_CPU_SPEC): New. Added for defining the submodel. + + * i386.c (asm_output_function_prefix, function_prologue, + ix86_expand_prologue): Make the routine that sets the GOT (when pic + is enabled) a function, to assist debugging. + + * i386.md (gen_prologue_get_pc): Call the function created above. + (divdf3): Added. + + * i386/dgux.h (CPP_PREDEFINES, CPP_SPEC): Reference CPP_CPU_SPEC. + Use svr4 assembler directive .backalign instead of .align. + (align to x bytes if it takes no more than y bytes to do so.) + + * i386/{aix386ng.h,dgux.h} (CPP_SPEC): Use %[cpp_cpu]. + * i386/{freebsd-elf,gas,isc,linux-aout}.h: Likewise. + * i386/{linux-oldld,linux,osfelf,osfrose,sco,sco4}.h: Likewise. + * i386/{sco4dbx,sco5,sol2,sysv3}.h: Likewise. + +Thu Sep 26 17:58:34 1996 Torbjorn Granlund + + * m68k.md (mulsidi3 matcher): Change predicate const_int_operand + to const_sint32_operand. Get rid of bogus range condition. + +Thu Sep 26 17:12:00 1996 Jim Wilson + + * Makefile.in (stmp-int-hdrs): Don't cd to srcdir before copying + header files to objdir. + +Wed Sep 25 21:22:57 1996 Jeffrey A Law (law@cygnus.com) + + * h8300.h (FIRST_PSEUDO_REGISTER, ARG_POINTER_REGNUM): Bump up by one. + (FIXED_REGISTERS): Add entry for MAC register. + (CALL_USED_REGISTERS, REG_ALLOC_ORDER): Likewise. + (HARD_REGNO_NREGS): Handle MAC register. + (HARD_REGNO_MODE_OK, REGNO_OK_FOR_BASE_P, REGISTER_NAMES): Likewise. + (enum reg_class): New MAC_REGS register class. + (REG_CLASS_CONTENTS, REGNO_REG_CLASS): Corresponding changes. + (REG_CLASS_FROM_LETTER): Likewise. + (REGISTER_MOVE_COST): Make copies to/from MAC register expenseive. + (CONDITIONAL_REGISTER_USAGE): Define. + * h8300.md (movsi_h8300hs): Renamed from movsi_h8300h. + Handle moves to/from the MAC register. + (mac): Two new patterns to use the mac instruction. + + * h8300.c (notice_update_cc): Fix CC_SET case. + (restore_compare_p): Remove unused function. + * h8300.md: Handle "set" vs "set_zn_c0" correctly. + (bCC patterns): No longer need to call restore_compare_p. + + * h8300.c (get_shift_alg): Fix HImode ASHIFTRT by 13 or 14 bits. + +Wed Sep 25 18:52:19 1996 Joern Rennecke + + * sh.md (insv): New pattern. + +Wed Sep 25 16:47:26 1996 Doug Evans + + * sparc/t-sunos41 (MULTILIB_{OPTIONS,DIRNAMES,MATCHES}): Create + multilib versions of -fpic and -fPIC. + (TARGET_LIBGCC2_CFLAGS): Comment out. + + * sparc.c (print_operand): Handle new codes H/L. + * sparc.md (lo_sum_di_sp32): Add little endian support. + (adddi3_sp32,subdi3_sp32,mulsidi3_sp32,const_mulsidi3): Likewise. + (umulsidi3_sp32,const_umulsidi3,smacdi,umacdi,anddi3_sp32): Likewise. + (iordi3_sp32,xordi3_sp32,negdi2_sp32): Likewise. + +Wed Sep 25 15:32:35 1996 Jim Wilson + + * expmed.c (store_bit_field): Don't make flag_force_mem disable insv + for memory operands. + + * function.c (instantiate_decl): Always store addr back into x. + +Tue Sep 24 19:37:00 1996 Jim Wilson + + * reload.c (push_secondary_reload): Do strip paradoxical SUBREG + even if reload_class is CLASS_CANNOT_CHANGE_SIZE. Change reload_mode + to mode in SECONDARY_MEMORY_NEEDED and get_secondary_mem calls. + + * reload1.c (emit_reload_insns): For output part of RELOAD_OTHER, + emit after RELOAD_FOR_OUTPUT, in reverse order of reload number, + but not separately. + +Tue Sep 24 18:13:07 1996 Michael Meissner + + * expr.c (emit_group_load): Allow target to be smaller than source. + +Tue Sep 24 17:40:39 1996 Doug Evans + + * m68k/a-ux.h: Renamed from aux.h because of MSDOS. + +Tue Sep 24 08:33:53 1996 David S. Miller (davem@caip.rutgers.edu) + + * tree.c (copy_node): Fix error in last change. + +Tue Sep 24 08:29:03 1996 James G. Smith + + * gcc.c (used_arg): Fix multilib_matches parsing to not corrupt + entry parameter. + +Tue Sep 24 08:22:18 1996 J"orn Rennecke + + * loop.c (get_condition): Use rtx_equal_p to compare rtx. + +Tue Sep 24 08:14:01 1996 Christian Iseli + + * integrate.c (expand_inline_function): Avoid creating paradoxical + subreg wider than BITS_PER_WORD as inlined function result. + +Tue Sep 24 08:00:15 1996 Paul Eggert + + * cccp.c (struct directive, directive_table, handle_directive): + pass_thru now 1 for #define and 2 for #pragma. + (handle_directive): When deciding whether to suppress comment at end + of directive, ignore tabs and spaces after comment. Remove redundant + limit test. With -dD -C, copy comment when isolating definition. + (skip_to_end_of_comment): With -C, don't copy newline at end + of C++ comment. + + * fixinc.ptx, fixinc.svr4, fixincludes: Insert newlines just before + end of 'sed' command strings if last 'sed' command is 'a' or 'i'. + +Tue Sep 24 07:28:58 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * toplev.c (PREFERRED_DEBUGGING_TYPE): If no debugging formats are + supported, set to NO_DEBUG. + (main): Don't do setting of PREFERRED_DEBUGGING_TYPE here. + +Mon Sep 23 22:45:15 1996 Sean McNeil + + * rs6000/vxppc.h, sparc/vxsim.h: New files. + * configure (powerpc-*-vxworks*, sparc-*-vxsim*): New targets. + * objc/objc.h (BOOL): Define BOOL as int for VxWorks. + +Mon Sep 23 21:23:27 1996 Klaus K"ampf (kkaempf@progis.de) + + * explow.c (promote_mode, case REFERENCE_TYPE): New case. + +Mon Sep 23 21:15:43 1996 Andreas Schwab + + * c-decl.c (finish_struct): Check PCC_BITFIELD_TYPE_MATTERS value. + + * dbxout.c (dbxout_symbol): Fix forgotten case in last change: + check DECL_ARTIFICIAL also when using the short cut way. + +Mon Sep 23 15:55:24 1996 David S. Miller (davem@caip.rutgers.edu) + + * tree.c (copy_node): Abort if don't know size of node. + + * tree.c (build1): Clean up initialization of OBSTACK. + +Mon Sep 23 15:35:33 1996 Jason Merrill + + * Makefile.in (stmp-multilib): Depend on $(LANG_LIB2FUNCS). + + * dbxout.c (dbxout_function): Don't check DECL_SECTION_NAME before + calling dbxout_function_end. + +Mon Sep 23 14:41:12 1996 J"orn Rennecke + + * combine.c (can_combine_p): Even if SMALL_REGISTER_CLASSES, + know lifetime not extended if all_adjacent set. + + * stmt.c (expand_asm_operands): Handle '+' constraint. + * cse.c (fold_rtx): Fold inside ASM_OPERANDS. + + * expr.c (expand_increment): If postincrement for MEM can't use add + directly, load address in reg and enqueue increment and store of reg. + + * loop.c (check_dbra_loop): Don't assume label must be second part of + if_then_else in condjump. + + * jump.c (jump_optimize): In no-nop move deletion, don't test + PRESERVE_DEATH_INFO_REGNO_P; instead test if optimization is performed. + Check for REG_UNUSED note on to-be deleted insn before searching for + preceding instruction to delete note from. + If PRESERVE_DEATH_INFO_REGNO_P is true for SREG, replace INSN with USE. + + * reload1.c (reload): Initialize the previous_offset fields + in reg_eliminate before calling setup_save_areas. + + * reload1.c (emit_reload_insns): Declare and set this_reload_insn. + + * expr.c (var_rtx): New function. + (expand_expr, case COND_EXPR): Also use target if same as singleton. + +Mon Sep 23 14:22:34 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * recog.c (constrain_operands): Don't test clobbered constraints. + + * reload1.c (emit_reload_insns): For output part of RELOAD_OTHER, + put in front of anything previous for that output, but not separately. + +Sun Sep 22 21:06:46 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * c-common.c (decl_attribtes, case A_SECTION): Allow for static + local variable. + +Sun Sep 22 11:30:27 1996 Christian Iseli (christian.iseli@di.epfl.ch) + + * expr.c (convert_move): Replace explicit checks for FP extend ops + with use of can_extend_p. + Add missing tests for FP trunc operations. + +Sun Sep 22 11:20:02 1996 Pat Rankin + + * dwarfout.c (DWARF_VERSION): Define as 1 if not already defined. + * dwarf2out.c (DWARF_VERSION): Likewise. + +Sun Sep 22 11:12:20 1996 Joern Rennecke + + * c-decl.c (pushdecl): Check new declaration actually conflicts before + warning about implicit external vs. static declarations. + + * loop.c (combine_givs): Improve combining DEST_REG giv with only use. + +Sun Sep 22 10:50:03 1996 Scott Christley + + * Create consistent mechanism for memory allocation and release + so that garbage collection routines can be easily subsititued + for the ANSI standard malloc, realloc, free, etc. + * objc/archive.c: Replace use of __objc_xmalloc and free + with objc_malloc and objc_free. + * objc/hash.c: Replace use of __objc_xcalloc and free + with objc_calloc and objc_free. + * objc/init.c: Replace use of free with objc_free. + * objc/misc.c (objc_malloc): Renamed from __objc_xmalloc. + (objc_realloc): Renamed from __objc_realloc. + (objc_atomic_malloc, objc_valloc): New functions. + (objc_calloc): Renamed from __objc_calloc. + (objc_free): New function. + * objc/objc-api.h (_objc_malloc): New function pointer. + (_objc_atomic_malloc, _objc_valloc): Likewise. + (_objc_realloc, _objc_calloc, _objc_free): Likewise + * objc/objc-list.h: Replace use of __obj_xmalloc and free + with objc_malloc and objc_free. + * objc/objects.c: Likewise. + * objc/sarray.c: Replace use of __objc_xmalloc and free + with objc_malloc and objc_free. + * objc/sarray.h (__objc_xmalloc, __objc_xrealloc): Delete. + * objc/selector.c: Replace use of __objc_xcalloc, __objc_xrealloc, + and __objc_xmalloc with objc_calloc, objc_realloc, and objc_malloc. + * objc/thr-decosf1.c: Replace use of __objc_xmalloc and free + with objc_malloc and objc_free. + * objc/thr-irix.c, objc/thr-mach.c, objc/thr-os2.c: Likewise. + * objc/thr-posix.c, objc/thr-pthreads, objc/thr-single: Likewise. + * objc/thr-solaris.c, objc/thr-win32.c, objc/thr.c: Likewise. + +Sun Sep 22 05:26:01 1996 Jason Merrill + + * configure: Set up LANG_LIB2FUNCS and LANG_EXTRA_HEADERS. + * Makefile.in (libgcc2.a): Include LANG_LIB2FUNCS. + (USER_H): Add LANG_EXTRA_HEADERS. + (LANG_LIB2FUNCS): New macro. + (LANG_EXTRA_HEADERS): New macro. + (stmp-int-hdrs): Don't hardwire ginclude. + (stamp-objlist): Don't depend on Makefile. + +Sat Sep 21 18:00:10 1996 Stephen L Moshier (moshier@world.std.com) + + * alpha.md (alpha_swapped_comparison_operator pattern): Fix asm + operand typo in last change. + +Sat Sep 21 07:11:51 1996 J"orn Rennecke + + * defaults.h (ASM_OUTPUT_LABELREF): Provide default definition + if not already defined. + * 1750a.h (USER_LABEL_PREFIX): Define instead of ASM_OUTPUT_LABELREF. + * a29k.h, alpha.h, convex.h, dsp16xx.h, elxsi.h, fx80.h: Likewise. + * gmicro.h, h8300.h, i386/sun386.h, i860.h, i960.h, ns32k.h: Likewise. + * pdp11.h, pyr.h, romp.h, sh.h, sparc.h, spur.h, tahoe.h: Likewise. + * vax.h, we32k.h: Likewise. + * i386/att.h (USER_LABEL_PREFIX): Redefine, not ASM_OUTPUT_LABELREF. + * i386/bsd.h, i386/lynx.h, i386/sco5.h, i860/fx2800.h: Likewise. + * m68k/3b1.h, m68k/mot3300.h, m68k/tower-as.h, m68k/tower.h: Likewise. + * ptx4.h, sparc/pbd.h, svr3.h, svr4.h: Likewise. + * i386/osfrose.h, m88k.h (USER_LABEL_PREFIX): Redefine. + * nextstep.h (USER_LABEL_PREFIX): Redefine. + (ASM_OUTPUT_LABELREF) Use USER_LABEL_PREFIX. + * arm/aout.h, mips.h (ASM_OUTPUT_LABELREF): Delete. + * rs6000/lynx.h (USER_LABEL_PREFIX): Undefine. + * rs6000.h, rs6000/win-nt.h (USER_LABEL_PREFIX): Define. + +Thu Sep 19 00:05:53 1996 Jason Merrill + + * configure: Move i[3456]86-*-gnu* case after linux and don't + treat linux-gnu like other gnu systems. + +Wed Sep 18 20:51:09 1996 Jason Merrill + + * cplus-dem.c (demangle_template): Fix handling of address args. + (gnu_special): Handle type_info stuff. + +Wed Sep 18 17:57:55 1996 Patrik Lantto (patrik@opq.se) + + * jump.c (jump_optimize): Insert conditional move after jump + insn instead of before. + +Wed Sep 18 17:33:36 1996 Richard Henderson + + * alpha.h (PREDICATE_CODES): Add alpha_swapped_comparison_operator. + * alpha.c (alpha_swapped_comparison_operator): New function. + (print_operand): Support unsigned codes for %D, %c, and %d. + * alpha.md: Add pattern for b%c with swapped comparisons with 0. + Delete three unnamed cmp patterns that are strict subsets of it. + + * alpha.c (alpha_emit_set_long_const): Save one instruction + when -O2 and high word == low word. + +Tue Sep 17 22:46:15 1996 Jason Merrill + + * i386/unix.h (ASM_OUTPUT_MI_THUNK): Handle functions + returning an aggregate. + + * varasm.c (supports_one_only): New function. + (make_decl_one_only): Likewise. + * svr4.h (MAKE_DECL_ONE_ONLY): Define. + * tree.h (DECL_ONE_ONLY): New macro. + + * varasm.c (assemble_variable): Fix setting of + first_global_object_name. + (assemble_start_function): Likewise. + +Tue Sep 17 19:42:39 1996 Doug Evans + + * i386/t-cygwin32 (winnt.o): Compile properly. + +Tue Sep 17 15:47:20 1996 Ian Lance Taylor + + * Add support for R5000, and finish MIPS4 support. + * mips.h (enum processor_type): Add PROCESSOR_R5000. + (gen_conditional_move): Declare. + (CONDITIONAL_REGISTER_USAGE): Mark ST_REGS as fixed if not + HARD_FLOAT, or if mips_isa < 4. + (FIRST_PSEUDO_REGISTER): Change to 76. + (FIXED_REGISTERS): Add condition code registers. + (CALL_USED_REGISTERS): Likewise. + (ST_REG_LAST): Change to 74. + (RAP_REG_NUM): Change to 75. + (ST_REG_P): Look for any condition code register. + (REG_CLASS_CONTENTS): Update for new condition code registers. + (RTX_COSTS): Add cases for R5000. + (REGISTER_MOVE_COST): Add cases for condition code registers. + (PREDICATE_CODES): Add "const_float_1_operand". + (EXTRA_CC_{MODES,NAME}, SELECT_CC_MODE): Remove. + (REGISTER_NAMES): Add entries for new condition code registers. + (DEBUG_REGISTER_NAMES): Likewise. + (ADDITIONAL_REGISTER_NAMES): Remove FPSW_REGNUM. + * mips.md (cpu attribute): Add R5000. + (function units): Add cases for the R5000. + ({madd,msub,nmadd,nmsub}.d): Only available if TARGET_DOUBLE_FLOAT. + (recip.d, recip.s, rsqrt.d, rsqrt.s): New define_insn patterns. + (movcc): New pattern to move condition code values. + (reload_incc, reload_out_cc): New define_expand patterns. + (lwxc1, ldxc1, swxc1, sdxc1): Several new define_insn patterns. + (various): Replace CC_FP with CC. + (branch_fp_ne, branch_fp_eq): Match any condition code register. + (branch_fp_ne_rev, branch_fp_eq_rev): Remove. + (seq_df, slt_df, sle_df): Match any condition code register. + (sgt_df, sge_df, seq_sf, slt_sf, sle_sf, sgt_sf, sge_sf): Likewise. + (sne_df, sne_sf): Remove. + (FP conditional moves): Match any condition code register. + Require TARGET_HARD_FLOAT and, if appropriate, TARGET_DOUBLE_FLOAT. + (movsicc): Just call gen_conditional_move. + (movdicc, movsfcc, movdfcc): New define_expand patterns. + * mips.c (mips_reg_names): Add condition code registers. + (mips_sw_reg_names, mips_regno_to_class): Likewise. + (const_float_1_operand): New function. + (mips_move_1word): Treat CCmode as SImode. Handle move from + ST_REG to GR_REG if mips_isa >= 4. Only permit move from GR_REG + to ST_REG is mips_isa < 4. + (gen_conditional_branch): Rewrite. Just use CCmode, not extra + condition modes. + (gen_conditional_move): New function. + (override_options): Recognize vr5000. Look for just CCmode, not + extra condition modes. If mips_isa >= 4, permit CCmode in GR_REGS + and FP_REGS. + (print_operand): Handle %Z. + (mips_secondary_reload_class): Require a data register to copy a + value out of a condition code register. Require a floating point + register to copy a value into a condition code register. + +Tue Sep 17 15:10:29 1996 Joern Rennecke + + * sh.md: New define_splits to recombine output from LEGITIMIZE_ADDRESS. + * sh.h (LEGITIMIZE_ADDRESS): Typo fixes (x -> X). + +Mon Sep 16 23:00:35 1996 Jim Wilson + + * configure (build_broken_install): Renamed from host_broken_install. + Set from build not host. + (build_install_headers): Renamed from host_install_headers. Set from + build not host. + +Mon Sep 16 22:38:55 1996 Stu Grossman (grossman@critters.cygnus.com) + + * configure (m68k-*-coff*): Use dbx debug format by default. + * gcc.c (link_command_spec): Move -T to end of link command line. + * m68k/m68kemb.h (LINK_SPEC, SUBTARTGET_SWITCHES): Delete. + (LIB_SPEC): Define to just -lc. + (STARTFILE_SPEC): Define to empty. + +Mon Sep 16 13:12:27 1996 J"orn Rennecke + + * sh.c (ext_shift_insns, ext_shift_amounts): New arrays. + (gen_ashift_hi, gen_shifty_hi_op, shl_and_kind): New functions. + (rtx_equal_function_value_matters): Declare. + (shl_and_length, shl_and_src_length, gen_shl_and): New functions. + (shl_sext_kind, shl_sext_length, gen_shl_sext): Likewise. + * sh.md (ashlhi3_k, lshrhi3_m): New patterns. + (lshrhi3, shl_sext_ext, shl_sext_sub): + New insn patterns with matching define_split. + (and_shl_scratch): Likewise, but also with unnamed variants. + +Sat Sep 14 17:05:07 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * gcc.c (convert_filename): Don't start looking for '.' until + after last directory separator. + + * i386.md (clrstrsi): Correct check for constant size. + + * Based on code by sac@cygnus.com. + * i386/cygwin32.h (CHECK_STACK_LIMIT): Make consistent with MD file. + * i386.c ({function,ix86_expand}_prologue): Use __alloca to allocate + stack if desired and beyond CHECK_STACK_LIMIT in size. + * i386.h ({MASK,TARGET}_STACK_PROBE): New macros. + (TARGET_SWITCHES): Add -mstack-arg-probe. + * i386.md (allocate_stack{,_worker}): New patterns. + +Fri Sep 13 18:23:18 1996 Joel Sherrill + + * sparc/lb1spc.asm (.div, .rem): Fixed typo so sign is returned + correctly. TOPBITS was 2 and should have been 4. + +Thu Sep 12 21:51:56 1996 Jim Wilson + + * mips.md (call_value_multiple_internal0): Change from define_insn to + define_expand. + +Thu Sep 12 19:22:14 1996 Doug Evans + + * sparc.md (move_pic_label_si): Operand one is label_ref now. + * sparc.c (emit_move_sequence): Pass label_ref to + gen_move_pic_label_si to not lose flags. + +Wed Sep 11 12:10:08 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * Makefile.in (GCC_PASSES): Add $(exeext) to names. + (FLAGS_TO_PASS): Add CLIB. + (c-pragma.o): Add dependencies on except.h, function.h, defaults.h. + +Tue Sep 10 22:25:03 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * configure (i[3456]86-*-cygwin32): Use xm-cygwin32.h and xm-i386.h. + Set fixincludes to Makefile.in and objc_thread_file to win32. + * i386/xm-cywin32.h: Don't include xm-i386.h. + * i386/x-cygwin32, rs6000/x-cygwin32 (STMP_FIXPROTO, exeext): New defs. + + * gcc.c (HAVE_EXECUTABLE_SUFFIX): New macro. + (convert_filename): New function. + (process_command, case 'o'): Call it. + (process_command, default case): Likewise; delete old code. + +Tue Sep 10 21:08:43 1996 Torbjorn Granlund + + * i386.md (decrement_and_branch_until_zero matcher): Fix typo. + +Tue Sep 10 19:04:19 1996 Jim Wilson + + * mips.c (mips_move_2words): Rewrite 32 bit shifts as 16 bit shifts. + +Tue Sep 10 10:39:07 1996 Jeffrey A Law (law@cygnus.com) + + * pa/pa-gas.h (DBX_DEBUGGING_INFO): Remove all #define + and #undef statements related to debugging information. + * pa/pa-hpux.h, pa-hpux7.h: Likewise + * pa.c (override_options): Disable "-g" and issue a warning + if it's used when !TARGET_GAS. + +Mon Sep 9 17:57:49 1996 Doug Evans + + * sparc.h ({MASK,TARGET}_FPU_SET): Define. + (TARGET_SWITCHES): Record if -m{,no-}fpu passed. + * sparc.c (sparc_override_options): Don't clobber explicit + -m{,no-}fpu setting with cpu default. + +Mon Sep 9 15:57:57 1996 Joel Sherrill + + * configure (mips64orion-*-rtems*): New target. + * mips/rtems64.h: New file. + +Sat Sep 7 22:07:53 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (store_field): If storing a record on big endian targets, + set up so we store the high-order bits. + (expand_expr, case COMPONENT_REF): Likewise for loads. + +Thu Sep 5 14:59:47 1996 J"orn Rennecke + + * sh.h (LEGITIMIZE_ADDRESS): Define nonempty. + +Thu Sep 5 10:43:36 1996 Jeffrey A Law (law@cygnus.com) + + * pa.md (mov{si,di,sf}): Handle 'R' constraints as needed. + +Wed Sep 4 17:13:28 1996 Bob Manson + + * except.c: (add_partial_entry): New routine. + (expand_start_try_stmts): Moved from cp/except.c. + (expand_start_all_catch): Move functionality of expand_end_try_stmts + here. + +Wed Sep 4 12:30:02 1996 Mike Stump + + * except.c (emit_unwinder): Ensure CLOBBER and USE insns come last, + if present. + +Tue Sep 3 12:01:43 1996 Ian Lance Taylor + + * configure (sh-*-elf*): New target. + * sh/elf.h: New file. + +Fri Aug 30 17:52:26 1996 Jim Wilson + + * dwarf2out.c (gen_formal_types_die): Delete extra argument from + gen_type_die call. + +Fri Aug 30 15:40:40 1996 James G. Smith + + * mips/elf64.h: Allow MULTILIB_DEFAULTS to be defined + before this file is included. + +Fri Aug 30 15:00:06 1996 Stan Cox + + * i386.md: (movsicc,movhicc): Allow reload from memory. + + * i386.c (override_options): Don't thread the prologue if profiling. + +Fri Aug 30 15:00:06 1996 James Hawtin + + * i386/t-sol2 (gcrt1.o): Added for profiling Solaris 2 + * i386/sol2.h (STARTFILE_SPEC): New. + * i386/gmon-sol2.c, i386/sol2-gc1.asm: New files. + +Thu Aug 29 22:08:03 1996 Jim Wilson + + * except.c (add_eh_table_entry): Multiply realloc size by sizeof int. + +Thu Aug 29 15:15:31 1996 Jeffrey A Law (law@cygnus.com) + + * pa.md (fcmp patterns): Don't try to eliminate useless add,tr + insns here. + * pa.c (pa_reorg): Do elimination of useless add,tr insns here instead. + (print_operand, case 'y'): Remove this code. + +Wed Aug 28 16:19:34 1996 Doug Evans + + * toplev.c (print_single_switch): Ultrix fprintf returns 0 for success. + + * toplev.c (main): Rewrite -g parsing. + +Mon Aug 26 16:15:49 1996 Fred Fish + + * Makefile.in (objc-parse.y): Fix typo in name of temp file. + +Mon Aug 26 14:08:37 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * function.c (mark_all_temps_used): Fix error in last change. + +Sun Aug 25 22:27:19 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * function.c (mark_all_temps_used): New function. + +Fri Aug 23 11:34:57 1996 Michael Meissner + + * rs6000/sysv4.h (SUBTARGET_OVERRIDE_OPTIONS): Fixes to make -fPIC + really the same as -mrelocatable. + (ASM_SPEC): Pass -K PIC to the assembler if -fpic/-fPIC. + + * rs6000/sol2.h (ASM_CPU_SPEC): Remove passing -K PIC to the + assembler if -fpic/-fPIC. + + * bi-{arity,opcode,opname}.c (fancy_abort): Define, so that + -Dabort=fancy_abort works again. + +Thu Aug 22 11:39:34 1996 Michael Meissner + + * rs6000/t-ppcgas ({stmp,install}-crt): Only build and install the + eabi ecrt[in].o object files in eabi multilib directories, only + build and install the solaris scrt[in0].o object files in solaris + directories. + (MULTILIB_MATCHES): Remove matches for solaris, linux to other + switches. + +Tue Aug 20 18:49:55 1996 Michael Meissner + + * rs6000/sysv4.h (ASM_OUTPUT_SECTION_NAME): If -mrelocatable or + -mrelocatable-lib, don't make read-only sections. + +Mon Aug 19 18:42:13 1996 Doug Evans + + * sparc.h ({MASK,TARGET}_LITTLE_ENDIAN): Define. + (LIBGCC2_WORDS_BIG_ENDIAN): Add little endian support. + * sparc/sp64-elf.h ({CPP,ASM,LINK}_SPEC): Add little endian support. + (SUBTARGET_SWITCHES): Recognize -m{big,little}-endian. + ({BYTES,WORDS}_BIG_ENDIAN): Likewise. + * sparc/splet.h (SUBTARGET_SWITCHES): Recognize -m{big,little}-endian. + ({CPP,ASM,LINK}_SPEC): Add little endian support. + ({BYTES,WORDS}_BIG_ENDIAN): Likewise. + * sparc/t-splet (MULTILIB_{OPTIONS,DIRNAMES}): Likewise. + + * sparc/lynx-ng.h (CPP_SPEC): Use %(cpp_cpu). + +Sat Aug 17 15:23:39 1996 Geoffrey Noer + + * i386/cygwin32.h (CPP_PREDEFINES): Define _WIN32, not WIN32. + Define only __CYGWIN32__, not CYGWIN32 or __CYGWIN32. + * rs6000/cygwin32.h (CPP_PREDEFINES): Likewise. + * cccp.c (absolute_filename): Drive specifiers make the pathname + absolute in cygwin32. + * choose-temp.c: Delete !defined(_WIN32) condition when including + sys/file.h (NO_SYS_FILE_H is still used). + * gcc.c: Change ifndef _WIN32 to ifndef NO_SYS_FILE_H when deciding + whether to include sys/file.h. + (execute): -pipe is supported for cygwin32. + * getopt.c: Change win32 test from WIN32 to _WIN32. + * pexecute.c: Update test for win32 (&& ! cygwin32). + * protoize.c: Likewise. + (kill): Delete decl. + * toplev.c: Update test for win32 (&& ! cygwin32). + * ginclude/stdarg.h: Change __WIN32__ to _WIN32. + * ginclude/varargs.h: Likewise. + * ginclude/va-ppc.h: Likewise. + +Fri Aug 16 16:02:09 1996 Michael Meissner + + * rs6000.c (rs6000_got_register): Make sure pic_offset_table_rtx + allocated, even if current_function_uses_pic_offset_table set. + +Fri Aug 16 15:56:04 1996 J. Kean Johnston + + * i386/sco5.h (CLASS_LIKELY_SPILLED_P): Deleted. + (STARTFILE_SPEC): Insert crtbegin.o in correct place, and correct + versions of values-X?.o. + (SWITCH_TAKES_ARG): Extend DEFAULT_SWITCH_TAKES_ARG, not replace. + (CPP_SPEC): Add -Di386, and correctly include extra directories. + Define HAVE_ATEXIT in ELF mode for global destructors. + +Thu Aug 15 16:42:44 1996 Doug Evans + + * sparc.c (label_ref_operand): New function. + (emit_move_sequence): Pass label_ref to gen_move_label_di to not + lose flags. + * sparc.md (move_label_di): Operand one is label_ref now. + * genattrtab.c (write_test_expr): Allow label_ref in match_dup. + + * sys-protos.h (gethostid): Make return type `int' ifdef __alpha__. + * gen-protos.c: Delete support for SYS_PROTO_OVERRIDES. + * alpha.h (SYS_PROTO_OVERRIDES): Delete. + +Thu Aug 15 17:36:09 1996 Mike Stump + + * libgcc2.c (__throw): New routine. + (__eh_pc): New data object for exception handling. + + * except.c (eh_saved_pc): New object so we can call + assemble_external. + (expand_internal_throw_indirect): Call assemble_external for __eh_pc. + (end_eh_unwinder): Likewise. + (init_eh): Initialize eh_saved_pc. + +Thu Aug 15 13:02:42 1996 Mike Stump + + * arm.h (RETURN_ADDR_RTX): Define. + + * expr.c (expand_builtin_return_addr): Fix order of parameters. + +Wed Aug 14 19:48:00 1996 Torbjorn Granlund + + * stmt.c (expand_return): In code for doing scc with jumps, + stick to default handling if we have corresponding scc pattern. + +Wed Aug 14 10:31:28 1996 Jeffrey A Law (law@cygnus.com) + + * pa.c (override_options): Treat TARGET_FAST_INDIRECT_CALLS + just like TARGET_NO_SPACE_REGS. + (output_millicode_call): Likewise. + * pa.h (TARGET_FAST_INDIRECT_CALLS): Define. + (TARGET_SWITCHES): Add "fast-indirect-calls". + * pa.md (TARGET_FAST_INDIRECT_CALLS): Treat just like + TARGET_NO_SPACE_REGS in various call/millicode call patterns. + + * pa.c (print_operand): Use the right comparison operator + for reversed EQ and NE comparisons. + + * pa.h (OUTPUT_MI_THUNK): Define. + +Wed Aug 14 11:40:49 1996 Michael Meissner + + * ginclude/va-ppc.h: Add Windows NT support. + * ginclude/{varargs,stdarg}.h: For PowerPC Windows NT, include + va-ppc.h, instead of using the default handling. + +Tue Aug 13 18:30:10 1996 Ian Lance Taylor + + * fixincludes: Remove duplicate volatile from sig_atomic_t in AIX + sys/signal.h + +Tue Aug 13 16:51:37 1996 Jim Wilson + + * i960-coff.h (LIB_SPEC): Undef. + + * sh.h (PROFILE_BEFORE_PROLOGUE): Define. + +Tue Aug 13 11:36:02 1996 Michael Meissner + + * gcc.c (set_spec,process_command): Dump and load the compiler + version number in the specs file. + + * rs6000.c (output_toc): Fix last change, so that it doesn't use + an uninitialized variable if -mminimal-toc. + (output_prolog): Increment probe_labelno after last use. + + * rs6000/t-ppcgas (MULTILIB_*): Build far fewer multilib + libraries. Build all libraries with -mrelocatable-lib and + -mno-eabi. Build special GNU/Linux and Solaris libraries. + * rs6000/eabi{,aix,le}.h (MULTILIB_DEFAULTS): Adapt to changes in + t-ppcgas. + * rs6000/(linux,sol2,sysv4,sysv4le).h (MULTILIB_DEFAULTS): Likewise. + +Tue Aug 13 11:36:02 1996 Jeffrey A Law (law@cygnus.com) + + * rs6000.c (handle_mac_pragma): Initialize "psize". + +Mon Aug 12 18:14:35 1996 Jim Wilson + + * gcc.c (used_arg): Initialize cnt to zero. + +Mon Aug 12 14:03:16 1996 Jim Wilson + + From Mike Stump: + * sh.c (regno_reg_class): Change entry 23 from NO_REGS to GENERAL_REGS. + (initial_elimination_offset): New variable live_regs_mask. Add + code to handle RETURN_ADDRESS_POINTER_REGNUM. + * sh.h (RAP_REG, RETURN_ADDRESS_POINTER_REGNUM): Define. + (ELIMINABLE_REGS): Add RETURN_ADDRESS_POINTER_REGNUM support. + (RETURN_ADDR_RTX): Define. + (REGISTER_NAMES): Add rap. + + * iris5.h (DOLLARS_IN_IDENTIFIERS): Undefine. + + * m68kemb.h (LIB_SPEC): Always emit -lc. + +Mon Aug 12 12:30:25 1996 Michael Meissner + + * rs6000.c (rs6000_got_register): Test variable + current_function_uses_pic_offset_table to see whether or not a GOT + register has been created already. + + * Makefile.in (multilib.h): Move to stamp-mlib. + (stamp-mlib): Use move-if-change to conditionally update + multilib.h. Pass MULTILIB_EXTRA_OPTS to genmultilib. + (STAGESTUFF): Add stamp-mlib. + (mostlyclean): Delete tmp-mlib.h. + + * genmultilib: Take fifth argument for options to all multilib builds. + Restructure output so we pass synonym switches and extra arguments + separately, and not exponentially slow down genmultilib. + + * gcc.c (toplevel): Rearrange multilib support so we support passing + synonyms separately from normal switches. Add support for passing + additional switches for all multilib builds. Dump and restore value + of MULTILIB_DEFAULTS. + (setspec, process_command, main): Likewise. + (used_arg,default_arg,print_multilib_info): Likewise. + +Mon Aug 12 07:46:47 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (expand_builtin, case BUILT_IN_SETJMP): Add test + and call for nonlocal_goto_receiver pattern. + * stmt.c (expand_end_bindings): Likewise. + + * stmt.c (expand_asm_operands): Fix off-by-one error when + scanning constraints. + +Sun Aug 11 22:48:02 1996 Jason Merrill + + * expr.c (store_expr): Handle COND_EXPR cleanups like expand_expr. + +Sun Aug 11 22:42:36 1996 J"orn Rennecke + + * optabs.c (expand_abs): When OP0 and TARGET are the same + pseudo register, it is safe to use TARGET. + + * local-alloc.c (reg_equiv_replace): New variable. + (update_equiv_regs): Set reg_equiv_replacement for all REG_EQUIV + notes encountered or generated. + +Sun Aug 11 22:27:14 1996 Scott Christley + + * objc/hash.c (hash_is_key_in_hash): Function somehow got lost. + +Sun Aug 11 21:43:15 1996 Andreas Schwab + + * ginclude/stddef.h (__need_wint_t): Move #undef to right place. + +Sun Aug 11 17:46:22 1996 J"orn Rennecke + + * c-decl.c (finish_struct): If pedantic, also warn if struct/union + has no named members. + +Sun Aug 11 17:32:52 1996 Joel Sherrill + + * i386/rtems.h: Renamed from i386/i386-rtems.h + * i960/rtems.h: Renamed from i960/i960-rtems.h + * m68k/rtems.h: Renamed from m68k/m68k-rtems.h + * rs6000/rtems.h: Renamed from rs6000/powerpc-rtems.h + * sparc/rtems.h: Renamed from sparc/sparc-rtems.h + * config/t-rtems: New file. + * configure (i386-*-rtems*): Added t-rtems to tmake_file. + Renamed i386/i386-rtems.h to i386/rtems.h. + (i960-*-rtems*): Added t-rtems to tmake_file. + Renamed i960/i960-rtems.h to i960/rtems.h. + Added original tm.h file and dbxcoff.h. + (m68k-*-rtems*): Added t-rtems to tmake_file. + Renamed m68k/m68k-rtems.h to m68k/rtems.h. + (powerpc-*-rtems*): Added t-rtems to tmake_file. + Renamed rs6000/powerpc-rtems.h to rs6000/rtems.h. + (sparc-*-rtems*): Added t-rtems to tmake_file. + Renamed sparc/sparc-rtems.h to sparc/rtems.h. + +Fri Aug 9 16:05:13 1996 Stan Cox + + * i386.md: (untyped_call) Avoid SIGFPE. + + * i386.c (output_float_compare): Don't try to initialize + aggregate local variable; use assignment statements instead. + + * i386.h (RTX_COSTS): rtx_cost should pass two parameters. + + * i386/go32.h (ASM_OUTPUT_SECTION_NAME): New. + +Fri Aug 9 16:00:11 1996 Jim Wilson + + * winnt.c (gen_stdcall_suffix): Round parameter size to PARM_BOUNDARY. + +Thu Aug 8 17:42:35 1996 Michael Meissner + + * rs6000.c (output_toc): If we are emitting a reference to a + vtable, don't put in the section name, just use the symbol. + +Wed Aug 7 19:03:36 1996 Jim Wilson + + * sh.md (casesi_jump): New pattern. + (casesi): Generate RTL to match it. + +Wed Aug 7 14:10:07 1996 Jason Merrill + + * ginclude/stddef.h (NULL): Use __null for G++. + +Tue Aug 6 17:37:53 1996 Michael Meissner + + * rs6000/sysv4.h (STACK_BOUNDARY): Always define as 64. + (ABI_STACK_BOUNDARY): Define as 64/128 based on the -mno-eabi + switch. + + * rs6000.c (rs6000_stack_info): Use ABI_STACK_BOUNDARY, not + STACK_BOUNDARY. Define ABI_STACK_BOUNDARY as STACK_BOUNDARY #ifndef. + +Tue Aug 6 14:29:43 1996 Doug Evans + + * gen-protos.c (overrides): New static local. + (add_hash,parse_fn_proto): New static functions. + (main): Add prototypes from SYS_PROTO_OVERRIDES to hash table before + parsing sys-protos.h. Reserve entry 0 in std_protos. + * alpha.h (SYS_PROTO_OVERRIDES): Define. + +Mon Aug 5 16:53:36 1996 Doug Evans + + * sparc/t-splet (MULTILIB_OPTIONS): Add mbroken-saverestore. + (MULTILIB_DIRNAMES): Add brknsave. + + * stor-layout.c (layout_record): Correct overflow test for 0 sized + fields. + +Mon Aug 5 16:12:19 1996 Jim Wilson + + * alpha.c (alpha_output_filename): When emitting stabs, don't + disable them if using GNU as. + (alpha_output_lineno): Likewise, when not using GNU as. + + * sh.c (arith_reg_operand): Reject SUBREG of an invalid hard reg. + + * sparc/lite.h (aoutos.h): Don't include it. + * configure (sparclite-*-aout*): Add aoutos.h to tm_file. + +Sat Aug 3 23:13:55 1996 Jeffrey A Law (law@cygnus.com) + + * combine.c (rtx_equal_for_field_assignment_p): Check for + get_last_value returning (CLOBBER (CONST_INT 0)). + +Sat Aug 3 20:19:14 1996 Jim Wilson + + * i960.md (subsi3+1): Handle case where first operand is constant + but second operand is not. + + * m68k/vxm68k.h (WCHAR_TYPE_SIZE): Undef, then define to 16. + +Fri Aug 2 15:46:19 1996 Jeffrey A Law (law@cygnus.com) + + * pa/pa-hpux.h (LINK_SPEC): Don't link in PA1.1 specific + libraries when creating shared libraries. + * pa/pa-hpux9.h, pa/pa-hpux10.h: Likewise. + +Fri Aug 2 13:36:42 1996 Stan Cox + + * i386.c (output_float_compare): fcomi should be followed by the + correct conditional jump instead of fcom/pfstsw/and/jne + (override_options): Added -mbranch-cost to set BRANCH_COST. + + * i386.md (sgt+1,slt+1,sge+1,sle+1,bgt+1,blt+1,bge+1,ble+1,bleu+4) + Added TARGET_CMOVE check for fcomi. + (movsicc_1+1,movhicc_1+1): Added to handle the general case. + + * i386.h (i386_branch_cost, i386_branch_cost_string): Added. + +Fri Aug 2 11:53:55 1996 Brendan Kehoe + + * sparc/vxsparc.h (CPP_PREDEFINES): Add `-DCPU=SPARC'. + +Thu Aug 1 23:56:01 1996 Jeffrey A Law (law@cygnus.com) + + * pa.h (ASM_OUTPUT_INT): Remove all hacks for exception table. + +Thu Aug 1 10:08:14 1996 Torbjorn Granlund + + * m68k.h (RTX_COSTS, case PLUS): Get operand order right. + +Wed Jul 31 15:06:46 1996 Doug Evans + + * sparc.md (negtf2,abstf2): Fix v9 case. + +Wed Jul 31 09:49:25 1996 Jeffrey A Law (law@cygnus.com) + + * pa.h (ASM_OUTPUT_INT): Use an 'E%' prefix for items in + the exception table if TARGET_GAS && ! TARGET_PORTABLE_RUNTIME. + +Tue Jul 30 15:37:31 1996 Jim Wilson + + * i386/cygwin32.h (dbxcoff.h): Include. + (DBX_DEBUGGING_INFO, SDB_DEBUGGING_INFO, PREFERRED_DEBUGGING_TYPE): + Move definitions before include of dbxcoff.h. + (ASM_OUTPUT_SOURCE_LINE, DBX_OUTPUT_MAIN_SOURCE_FILE_END): Delete. + (DBX_BLOCKS_FUNCTION_RELATIVE, DBX_FUNCTION_FIRST): Delete. + +Tue Jul 30 15:03:53 1996 Torbjorn Granlund + + * i960.md (eq reg (const_int 0)): New pattern. + +Tue Jul 30 11:15:44 1996 Jeffrey A Law (law@cygnus.com) + + * pa.h (RETURN_ADDR_RTX): Offset is -20 from the frame, not +20! + +Mon Jul 29 12:16:17 1996 Jeffrey A Law (law@cygnus.com) + + * pa.h (GO_IF_LEGITIMATE_ADDRESS): Fix thinko in last change. + +Fri Jul 26 18:19:47 1996 Doug Evans + + * dwarfout.c (output_bound_representation): Fix typo. + +Thu Jul 25 16:00:10 1996 Mike Stump + + * expr.c (do_jump, case TRUTH_ORIF_EXPR): Ensure end of an + exception region comes after its start. + (do_jump, case TRUTH_ANDIF_EXPR): Likewise. + +Thu Jul 25 13:36:42 1996 Stan Cox + + * i386.c (output_float_compare): Added support for Pentium Pro + fcomi instruction which sets EFLAGS instead of FPU Status Word. + +Wed Jul 24 21:48:08 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * cse.c (canon_hash, cse_insn): MEM is not unchanging if it is + in the frame (since the temp slot might be reused). + +Wed Jul 24 17:34:06 1996 J"orn Rennecke (amylaar@cygnus.com) + + * sh.md (branch_true, branch_false, inverse_branch_true): Express + tests of the T bit as comparisons against zero, rather than one. + (inverse_branch_false, beq, bne, bgt, blt, ble, bge, bgtu): Likewise. + (bltu, bgeu, bleu, casesi): Likewise. + +Wed Jul 24 15:58:06 1996 Stan Cox + + * i386.md: (mov{sf,df,xf}cc{,_1}): New patterns for P6 FP cmove. + * i386.c (put_condition_code, print_operand, output_fp_cc0_set): + Support fcmov suffixes. + +Wed Jul 24 10:53:38 1996 Jeffrey A Law (law@cygnus.com) + + * pa.c (move_operand): Relax "mode" test. Allow scaled + indexed addressing modes. + (output_fp_move_double): Tweak output strings to work with updated + 'F' and 'M' output modifiers. + (print_operand): Collapse 'F' and 'M' into a single hunk of code. + For auto-increment modes output "s,ma" and "s,mb". + For scaled indexing modes output "x,s" + For other addresses, output nothing for 'M' and "s" for 'F'. + * pa.h (EXTRA_CONSTRAINT): Don't accept scaled indexed addresses + for 'Q' and 'T'. Do accept scaled indexed addresses for 'R'. + (GO_IF_LEGITIMATE_ADDRESS): Accept scaled indexed addresses + for SFmode and DFmode. + * pa.md: Remove all scaled indexed load patterns. + (movsi patterns): Accept scaled indexed addresses in some + cases. Update output strings for updated 'M' and 'F' output modifiers. + (movhi, movqi, movsf, movdf, movdi patterns): Likewise. + +Tue Jul 23 23:10:41 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * tree.h (struct tree_int_cst): Add field for TREE_CST_RTL. + * varasm.c (decode_addr_const, output_constant_def): AllowINTEGER_CST. + +Tue Jul 23 16:42:09 1996 Jim Wilson + + * sh.c (reg_unused_after): Handle JUMP_INSN inside a sequence. + +Tue Jul 23 16:33:25 1996 Mike Stump + + * Make exception handling work better when optimizations are on. + * except.c, except.h: New files. + * Makefile.in (OBJS): Add except.o. + (except.o): Add. + (stmt.o, final.o): Add except.h. + * rtl.c (note_insn_name): Add NOTE_INSN_EH_REGION_{BEG,END}. + * rtl.h: Likewise. + * arm.h (MASK_RETURN_ADDR): Define. + * pa.h (MASK_RETURN_ADDR, RETURN_ADDR_RTX): New macros. + * sparc.h (DOESNT_NEED_UNWINDER): Define if not doing a flat function. + * mips.h (RETURN_ADDR_RTX): Improve. + * vax.h (RETURN_ADDR_RTX): Improve. + * toplev.c (rest_of_compilation): Use find_handler_labels. + (main, interim_eh{,_hook}): Remove interim_eh_hook support. + (flag_exceptions): New flag; also add to table. + (compile_file): Emit the exception table in the backend now. + * final.c (final_scan_insn): Support ASM_OUTPUT_EH_REGION_{BEG,END}. + (final_scan_insn): Redo handler labels, implement + NOTE_INSN_EH_REGION_BEG and NOTE_INSN_EH_REGION_END and use them + instead of CODE_LABELs. + (final): Add call to check_handler_labels. + * libgcc2.c (L_eh): Add support for EH_TABLE_LOOKUP. + * sparc.md (return): Add a reference to the return address register. + * flow.c (find_basic_blocks): Add support for handler_labels. + * loop.c (find_and_verify_loops): Likewise. + * jump.c (jump_optimize): Likewise. + Add call to check_handler_labels. Add call to exception_optimize. + * sched.c (sched_analyze): Smuggle exception region notes around. + (unlink_notes, reemit_notes, schedule_block): Likewise. + (sched_analyze): Add extra element since we remove two at a time. + * integrate.c (save_for_inline_copying): Add support for exception + regions. + (expand_inline_function): Likewise. + (function_cannot_inline_p): Don't inline functions that have EH + regions before NOTE_INSN_FUNCTION_BEG. + (finish_inline): Use FIRST_FUNCTION_INSN, not NEXT_INSN. + * function.c (expand_start_all_catch): New function. + * function.h: Add exception handling support information. + * expr.c (expand_expr, {defer,expand}_cleanups_to, do_jump): Transform + interim_eh_hook into calls to expand_ehregion_{start,end}. + * stmt.c (expand_{decl_cleanup,cleanups}): Likewise. + (init_stmt_for_function): Call init_eh. + (save_stmt_status): Call save_eh_status. + (restore_stmt_status): Call restore_eh_status. + * expr.h (throw_libfunc): Add. + * optabs.c (throw_libfunc): Initialize. + * print-rtl.c (print_rtx): Add support for exception regions. + * rs6000.c (EXCEPTION_SECTION): Define. + * output.h (exception_section): Declare. + * varasm.c (exception_section): Define. + * i386.c, i960.c, rs6000.c: Include except.h for function.h. + * c-pragma.c, emit-rtl.c, expr.c, final.c, flow.c: Include except.h. + * function.c, integrate.c, jump.c, loop.c, objc-act.c: Likewise. + * stmt.c, stor-layout.c, toplev.c, tree.c, varasm.c: Likewise. + +Tue Jul 23 12:32:54 1996 Michael Meissner + + * rs6000.c (rs6000_replace_regno): Set pic_offset_table_rtx so + that other phases will use the PIC register instead of the + placeholder. + + * rs6000.md (movsi_got*): Eliminate -fPIC code, keep -fpic code. + (movsi): Only call movsi_got if -fpic, not -fPIC. + + * sysv4.h (OVERRIDE_OPTIONS): Improve error messages. Always set + -msdata=data by default, even if -fpic/-fPIC/-mrelocatable. Treat + -fPIC the same as -mrelocatable-lib and vica versa. + + * t-ppcgas: (MULTILIB_*): Use -mreloctable-lib, instead of + -mrelocatable. Map Solaris into mcall-sysv-noeabi case. Build + -mrelocatable-lib libraries under non-eabi case. When linking, if + -fpic, -fPIC, or -shared, link in the -mrelocatable-lib libraries. + +Mon Jul 22 19:34:20 1996 Jim Wilson + + * iris6.h (ASM_SPEC): Change {% to %{. + + * dwarf2out.c (output_call_frame_info): Change FDE CIE offset to + be section name rather than 0. + (gen_subprogram_die): Only emit DW_AT_external if origin is NULL. + Only call equate_decl_number_to_die if origin is NULL. + (dwarfout_begin_function): In code that computes offset of frame + pointer, change 4 to UNITS_PER_WORD. + + * combine.c (undo_all): Clear previous_undos field. + +Mon Jul 22 19:10:45 1996 Ian Lance Taylor + + * configure: Don't change target_alias to target in Makefile. + +Sat Jul 20 09:28:38 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * dwarfout.c (output_bound_representation): Treat default case + as variable bounds, then look inside for SAVE_EXPR. + + * mips.h (INITIALIZE_TRAMPOLINE): Use `_flush_cache'; flush data + cache too. + +Sat Jul 20 09:24:13 1996 Marco Walther (Marco.Walther@mch.sni.de). + + * configure (mips-sni-sysv4): New target. + * mips/sni-gas.h, mips/sni-svr4.h, mips/x-sni-svr4: New files. + +Fri Jul 19 17:44:13 1996 Stan Coxs + + * i386.md: (leave): Clobbers esp and ebp. + + * i386.h: (TARGET_USE_Q_REG): Support inline strlen on PentiumPro + +Fri Jul 19 15:56:18 1996 Ian Lance Taylor + + * m68k/t-m68kbare (MULTILIB_OPTIONS): Add m5200. + (MULTILIB_EXCEPTIONS): Define. + * m68k/lb1sf68.asm: Add MCF5200 support. + * m68k.md (adddi_sexthishl32): Set condition to !TARGET_5200. + (subdi_sexthishl32, ashrdi3, ashrhi3): Likewise. + (negdi2): Change into define_expand. + (negdi2_internal): Rename from old negdi2; condition now !TARGET_5200. + (negdi2_5200): New insn. + * m68k.c (output_function_prologue): Don't use add.w if TARGET_5200. + (output_function_epilogue): Likewise. + + * m68k.md (movqi): Remove complex cases which move between address reg + and memory; rely on secondary reloads instead. + +Fri Jul 19 12:22:50 1996 Brendan Kehoe + + * fixproto (std_files): Add utime.h. + +Fri Jul 19 10:59:46 1996 Jeffrey A Law (law@cygnus.com) + + * m68k/m68kemb.h: Remove '\' at EOF. + +Fri Jul 19 09:59:00 1996 Joel Sherrill + + * m68k/coff.h (STARTFILE_SPEC): Add #undef before definition. + +Fri Jul 19 09:44:45 1996 J.T. Conklin + + * m68k.h (LEGITIMATE_INDEX_P): Coldfire does not have scale + by 8 addressing modes. + + * m68k-none.h: Use MASK_* macros instead of explicit constants. + +Fri Jul 19 09:08:53 1996 Philippe De Muyter + + * m68k.md (negdi2): Undo last change: don't apply neg to address regs. + +Fri Jul 19 09:03:01 1996 Robert Wilhelm (rwilhelm@Physik.TU-Muenchen.DE) + + * toplev.c (main): Correct typo in error message. + +Thu Jul 18 20:29:33 1996 Jim Wilson + + * Makefile.in (OBJS): Add dwarf2out.o. + (dwarf2out.o): New rule. + * dwarf2.h, dwarf2out.c: New files. + * dwarfout.c: Check DWARF_VERSION macro. + + * mips/iris6.h (DWARF_DEBUGGING_INFO, PREFERRED_DEBUGGING_TYPE): + Move after header files are included. + (iris5.h): Include instead of iris5gas.h. + (MACHINE_TYPE): Change 5.x to 6.x. + (DEBUG_SECTION, LINE_SECTION): Add debug_ to name, fix attributes. + (SFNAMES_SECTION, SRCINFO_SECTION, MACINFO_SECTION, PUBNAMES_SECTION, + ARANGES_SECTION): Fix attributes. + (DWARF_VERSION, MIPS_DEBUGGING_INFO, ASM_DECLARE_FUNCTION_NAME, + ASM_DECLARE_FUNCTION_SIZE, FUNCTION_NAME_ALREADY_DECLARED, + FRAME_SECTION, ABBREV_SECTION): Define. + (DBX_DEBUGGING_INFO, SDB_DEBUGGING_INFO, MIPS_DEBUGGING_INFO, + DWARF_DEBUGGING_INFO, PREFERRED_DEBUGGING_INFO): Delete undefs at + end of file. + * mips.c (function_{pro,epi}logue): Use FUNCTION_NAME_ALREADY_DECLARED. + +Thu Jul 18 19:24:19 1996 David Mosberger-Tang + + * alpha/elf.h (INT_ASM_OP): Change from ".long" to ".quad". + +Thu Jul 18 19:20:58 1996 Ulrich Drepper + + * stddef.h: Undefine __need_wint_t. + +Thu Jul 18 19:06:35 1996 J.T. Conklin + + * longlong.h (mc680x0): Define umul_ppmm, udiv_qrnnd, sdiv_qrnnd + for the '020, '030, '040, and '332. Define count_leading_zeros + for the '020, '030, '040, and '060. + + * m68k.md: Add TARGET_5200 to conditions which determine whether + the extbl instruction is emitted. + (mulsi3): Enable pattern with TARGET_5200. + + * m68k.md (add patterns): Don't use two addqw instructions when + adding small (8 < N <= 16) integers to address registers on 68040. + +Thu Jul 18 18:06:15 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * configure: Write target_alias in Makefile. + (i[3456]86-*-sco3.2v4*): Set truncate_target. + * Makefile.in (target_alias): New and used for all current uses + of `target'. + +Thu Jul 18 17:46:02 1996 Dave Love + + * gcc.c (default_compilers): Extra Fortran extensions. + +Wed Jul 17 10:28:10 1996 Torbjorn Granlund + + * expmed.c (expand_mult_highpart): Revert last change. + +Tue Jul 16 12:51:59 1996 Doug Evans + + * sparc/sparc-rtems.h: #include "sparc/sparc-aout.h" -> sparc/aout.h. + +Mon Jul 15 14:42:06 1996 Jim Wilson + + * mips/iris6.h (LINK_SPEC): Add -woff 84. + +Fri Jul 12 17:34:01 1996 Michael Meissner + + * rs6000/eabi.asm (__eabi): Convert pointers in the Global Offset + Table if -mrelocatable. Move loops into separate subroutines for + ease of debugging. Reorganize code somewhat. + + * rs6000/rs6000.c (small_data_operand): Allow small data under + Solaris. + + * rs6000/sol-c0.c (_start): Initialize r13 to point to the small + data operand. + + * rs6000/sol-c{i,n}.asm (_init, _fini): Enable shared library + support. + + * rs6000/sysv4.h (SUBTARGET_OVERRIDE_OPTIONS): Default to + -msdata=data, even if -fpic or -mrelocatable. Allow -mrelocatable + and -mno-eabi. + (CPP_SYSV_SPEC): If -fpic, define __PIC__ and __pic__ to 1. If + -fPIC, define them to 2. + (CPP_ENDIAN_SPEC): Push definition of macros for specific endian + targets to new specs. + (CPP_ENDIAN_DEFAULT_SPEC): Define to use CPP_ENDIAN_BIG_SPEC. + (CPP_ENDIAN_{LITTLE,BIG,SOLARIS}_SPEC): New specs for little + endian mode, big endian mode, and Solaris, which can't define + _LITTLE_ENDIAN. Define __LITTLE_ENDIAN__ in all cases for little + endian systems. Define __BIG_ENDIAN__ in all cases for big endian + systems. + (SUBTARGET_EXTRA_SPECS): Add new specs. + + * rs6000/{eabile,sysv4le}.h (CPP_ENDIAN_DEFAULT_SPEC): Define to + use CPP_ENDIAN_LITTLE_SPEC. + + * rs6000/sol2.h (CPP_ENDIAN_LITTLE_SPEC): Define as + CPP_ENDIAN_SOLARIS_SPEC so that _LITTLE_ENDIAN is not define. + +Fri Jul 12 17:34:01 1996 David Edelsohn + + * rs6000.c (function_arg): Add IBM AIX XL compiler broken FP arg + passing compatibility mode. + * rs6000.h (TARGET_XL_CALL): Define default. + * aix3newas.h (TARGET_XL_CALL, SUBTARGET_SWITCHES): Define. + * aix41.h (TARGET_XL_CALL, SUBTARGET_SWITCHES): Define. + +Fri Jul 12 15:04:43 1996 Doug Evans + + * arm.h (ASM_OUTPUT_MI_THUNK): Handle fns returning structures. + + * ptx4.h ({ASM,LINK}_SPEC): %{V} %{v:%{!V:-V}} -> %{v:-V}. + * svr4.h ({ASM,LINK}_SPEC): Likewise. + * dsp16xx/dsp16xx.h ({ASM,LINK}_SPEC): Likewise. + * i386/dgux.h (LINK_SPEC): Likewise. + * i386/sol2.h (LINK_SPEC): Likewise. + * m88k/dgux.h ({LINK,ASM_CPU}_SPEC): Likewise. + * sparc/sol2.h ({ASM,LINK}_SPEC): Likewise. + * sparc/sp64-elf.h ({ASM,LINK}_SPEC): Likewise. + * sparc/sysv4.h (ASM_SPEC): Likewise. + +Thu Jul 11 17:29:33 1996 Michael Meissner + + * rs6000.h (GOT_TOC_REGNUM): New macro for r2, which is used as a + marker for the GOT/TOC register to be allocated later. + (MACHINE_DEPENDENT_REORG): Call rs6000_reorg. + (rs6000_reorg): Add declaration. + + * rs6000.c (rs6000_got_register): Return REG 2, not a pseudo + register in order to work with inlined functions. + (rs6000_replace_regno): New function to replace a register with a + new pseudo register. + (rs6000_finalize_pic): Loop through all insns, replacing any + GOT_TOC_REGNUM registers with new pseudo register, and adding + initialization of GOT register if it was created. + (rs6000_reorg): New function to check whether the GOT_TOC register + marker was removed. + +Thu Jul 11 10:12:50 1996 Jeffrey A Law (law@cygnus.com) + + * h8300.h (OK_FOR_U): If generating H8/S code, accept + SYMBOL_REF and SYMBOL_REF + CONST_INT. + + * h8300.c ({shift,rotate}_one): Emit tabs between opcode and + operands to be consistent with the rest of the compiler. + (shift_two, rotate_two): Define. + (get_shift_alg): Accept new argument "assembler2_p" for + rotate/shift by two insns. All callers changed. Rework + to generate more efficient code on the H8/300, H8/300H, and H8/S. + Try to simplify somewhat. + (emit_a_shift): Use shift-by-two insns when they're available. + Emit tabs between opcode and operands to be consistent with + the rest of the compiler. + +Wed Jul 10 19:32:17 1996 Jim Wilson + + * mips/iris6.h (ASM_SPEC): Correct typos in Jun 18 change. + +Wed Jul 10 18:56:38 1996 Ian Lance Taylor + + * sh.c (machine_dependent_reorg): When looking for instruction that + sets register in LOG_LINKS, skip link if REG_NOTE_KIND is not zero. + +Wed Jul 10 15:02:18 1996 Michael Meissner + + * rs6000.c (rs6000_got_register): New function to return a pseudo + register to hold the pic register. Abort if reload is in progress + or done. + (num_insns_constant): Allow SFmode and DFmode. + + * rs6000.h (CONST_DOUBLE_OK_FOR_LETTER_P): Redo 'G' so that it + means a constant that takes exactly two insns. + (rs6000_got_register): Add declaration. + + * rs6000.md (movsi_got): Move setup of pic register to + rs6000_got_register. + (movsf): If -msoft-float, don't force constants to memory. + (mov{sf,df} insns): If soft floating point, allow any constant to + be loaded. Add define_splits that allow the 604 to use both + integer units for loading constants. Make sure insn length is + correct. + +Tue Jul 9 17:05:10 1996 Michael Meissner + + * rs6000.c (easy_fp_constant): All FP constants are considered + hard for -fpic and hardware floating point, so that the GOT + register is created. + +Tue Jul 9 15:21:27 1996 Jim Wilson + + * x-iris6 (FIXPROTO_DEFINES): Add -D_SGI_SOURCE. + +Mon Jul 8 18:00:33 1996 Jim Wilson + + * sh.h (enum reg_class): Add new class GENERAL_FP_REGS. + (REG_CLASS_NAMES, REG_CLASS_CONTENTS): Likewise. + + * cse.c (note_mem_written): Varying structure memory access with + AND address can alias scalars. + * sched.c ({true,anti,output}_dependence): Likewise. + + * sh.c (calc_live_regs): For pragma_interrupt case, exclude call + clobbered regs that are fixed, explicitly add MACH_REG and MACL_REG. + + * calls.c (expand_call): For assign_stack_temp call in PARALLEL case, + get mode from type instead of using BLKmode. + * function.c (aggregate_value_p): If hard_function_value returns + a non-REG, then return 0. + + * mips.c (function_arg): Add explicit checks for FIELD_DECLs. + (mips_function_value): Add explicit checks for FIELD_DECLs, and save + them in the array FIELDS. When returning structure with 1 float field, + enclose it in a PARALLEL and set the PARALLEL mode correctly. + * mips.md (call_value): Call gen_call_value_multiple_internal0 + only if there are multiple return values. Strip the PARALLEL off + if there is only one return value. + +Mon Jul 8 16:27:33 1996 Jeffrey A. Law + + * First cut at support for the H8/S. + * h8300.c (h8300_init_once): Handle the H8/S (treat it + like the H8/300H). + (dosize, adds_subs_operand, one_insn_adds_subs_operand): Likewise. + (output_adds_subs, const_costs, print_operand): Likewise. + (output_simode_bld, h8300_adjust_insn_length): Likewise. + (push_order, pop_order): Reverse. + (function_prologue): Try to use ldm.l and stm.l insns + on the H8/S. Minor cleanups. + (function_epilogue): Likewise. + (asm_file_start): Emit ".h8300s" when compiling for the H8/S. + * h8300/h8300.h (CPP_SPEC): Handle the H8/S. + (TARGET_H8300S): New target. + (TARGET_SWITCHES): Add "-ms" and "-mno-s". + (BITS_PER_WORD): Handle the H8/S (treat it like the H8/300H). + (UNITS_PER_WORD, POINTER_SIZE, PARM_BOUNDARY): Likewise. + (BIGGEST_ALIGNMENT, BIGGEST_FIELD_ALIGNMENT): Likewise. + (INITIALIZE_TRAMPOLINE, MOVE_MAX, Pmode): Likewise. + * h8300.md: Handle H8/S just like H8/300H + throughout the entire file. + * t-h8300 (MULTILIB_OPTIONS): Build "-ms" libraries too. + (MULTILIB_DIRNAMES): Put H8/S libraries in "h8300s" directory. + * h8300/lib1funcs.asm: Emit ".h8300s" pseudo-op when generating + h8300s object files. Otherwise treat the H8/S just like the H8/300H. + * ginclude/stdarg.h: Handle the H8/S. + * ginclude/varargs.h: Likewise. + +Mon Jul 8 14:50:58 1996 Doug Evans + + * sparc/sol2.h (LINK_SPEC): Don't pass `-z text' if + -shared -mimpure-text. + +Sun Jul 7 18:03:46 1996 Torbjorn Granlund + + * m68k/lb1sf68.asm (__udivsi3): Use faster tstw instead of btst. + +Thu Jul 4 11:44:39 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (get_inner_reference): Delete using alternate mode for + bitfield; we don't make bitfields anymore if not needed. + +Wed Jul 3 18:23:17 1996 Stephen L Moshier (moshier@world.std.com) + + * c-common.c (record_function_format): Define as static. + + * collect2.c (at SUNOS4_SHARED_LIBRARIES): Fix reference to unistd.h. + +Wed Jul 3 17:35:20 1996 Gavin Koch + + * c-typeck.c (default_conversion): Add bitfield promotions. + +Wed Jul 3 17:09:22 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * gcc.c (default_compilers): Add null entries for languages we + heard of. + (main): If found one of those entries, say compiler not installed. + +Wed Jul 3 12:52:53 1996 Jeffrey A. Law + + * pa.c (fmpy_operands): Define. + (combinable_{fmpy,add,fsub}): New function. + * pa.md (parallel_addb, parallel_movb): New patterns. + (fmpyadd, fmpysub): New patterns. + + * pa.c (fmpy{add,sub}operands): Tighten checks. Allow SFmode. + +Tue Jul 2 18:57:15 1996 Jeffrey A. Law + + * pa.c (ireg_or_int5_operand): New function. + (output_parallel_movb, output_parallel_addb): Likewise. + (combinable_copy, combinable_add, following_call): Likewise. + (pa_adjust_insn_length): Handle parallel unconditional branches. + (output_movb): Handle case were destination is %sar. + * pa.h: Declare new functions. + * pa.md (parallel_branch): New "type" attribute. + (delay slot descriptions): Don't allow "parallel_branches" in + delay slots. Fill "parallel_branches" like "branch" insns. + (movb patterns): Handle %sar as destination register. + + * expr.c (compare): If function pointers need canonicalization + before comparisons, canonicalize them. + (do_store_flag): Do not use an sCC insn for a function pointer + comparison if function pointers need canonicalization before + comparing. + +Tue Jul 2 17:56:37 1996 Michael Meissner + + * rs6000/sysv4.h ({START,END}FILE_LINUX_SPEC): If -mnewlib is not + used, use the crtbegin/crtend that 2.7.2 used. + +Sat Jun 29 07:10:02 1996 Michael Meissner + + * rs6000.h (INIT_EXPANDERS): Define, call rs6000_init_expanders. + (RS6000_VARARGS_OFFSET): fpmem area no longer next to outgoing + argument area. + (STARTING_FRAME_OFFSET, STACK_DYNAMIC_OFFSET): Likewise. + (frame_pointer_needed): Add external declaration. + (rs6000_{save,restore}_machine_status): Ditto. + (rs6000_init_expanders): Likewise. + + * rs6000.c (rs6000_{save,restore}_machine_status): New functions + to save and restore the globals needed on a per function basis. + (rs6000_init_expanders): Initialize globals needed on a per + function basis, and set up so the above save/restore functions are + called when processing nested functions. + (output_epilog): Don't initialize per function globals here. + (rs6000_stack_info): Change where fpmem save area is to below local + variables, and not just below the outgoing argument area. + + * rs6000.md (floatsidf2*, fix_truncdfsi2*): Rewrite conversion + routines to track new location of the fpmem save area. Allocate a + new base register temp for the routines in case the stack frame is + more than 32k in size. + +Sat Jun 29 05:44:37 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * explow.c (convert_memory_address, case PLUS): Fix error in + last change. + +Fri Jun 28 23:30:48 1996 Jeffrey A. Law + + * reload1.c (choose_reload_regs): Properly mark spill registers + as in use for inherited reloads. + +Fri Jun 28 18:37:20 1996 Stephen L Moshier + + * objc/sarray.c (ifdef __alpha__): Don't declare `free'. + * objc/thr-decosf1.c (objc_thread_id): Use pthread_getunique_np + to obtain a thread ID value. + (objc_mutex_allocate): Cast mutex->owner to _objc_thread_t. + (objc_mutex_{deallocate,unlock}): Likewise. + (objc_mutex_{try,un,}lock): Declare thread_id as _objc_thread_t. + + * real.c (asctoeg): `0.0eX' is zero, regardless of the exponent X. + +Fri Jun 28 18:33:13 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * vax.md (rotl): Remove extraneous `$'. + + * combine.c (previous_num_undos): Deleted variable. + (MAX_UNDO): Deleted macro. + (struct undo): New field, next. + (struct undobuf): Deleted num_undos and undo. + New fields undos, frees, and previous_undos. + (SUBST, SUBST_INT): Rework to allocate memory and chain undo entries. + (combine_instructions): Initialize undobuf.{undos,previous_undos}, + not undobuf.num_undo and previous_num_undos. + (try_combine): Likewise. + (undo_all, gen_rtx_combine): Rework to use new data structures. + +Fri Jun 28 16:48:25 1996 Scott Christley + + * objc/sendmsg.c (__objc_block_forward): New function. + (get_imp, objc_msg_lookup): Use different forwarding function + when the returning a floating point value. + +Fri Jun 28 16:25:25 1996 Andreas Schwab + + * configure: Allow multiple makefile frags. + (i[3456]86-*-linux*oldld*): Add i386/t-crtstuff as target frag. + (i[3456]86-*-linux*aout*, i[3456]86-*-linux*): Likewise. + (m68k-*-linux*aout*): Add t-linux-aout as target frag. + (m68k-*-linux*): Add t-linux as target frag. + * Makefile.in (Makefile): xmake_file and tmake_file now already + contain the $(srcdir)/config prefix. + + * config/t-linux (BOOT_CFLAGS): Removed, no longer necessary. + (CRTSTUFF_T_CFLAGS): Don't define. + (CRTSTUFF_T_CFLAGS_S): Define this instead. + * config/t-linux-aout (BOOT_CFLAGS): Removed. + * m68k/t-linux: Remove variables now in t-linux. + +Fri Jun 28 15:06:05 1996 John F. Carr + + * alpha.c (alpha_emit_conditional_move): Emit correct code when + incoming comparison code is NE. + +Fri Jun 28 14:35:45 1996 J.T. Conklin + + * c-decl.c (init_decl_processing): Register __builtin_memset + and memset as builtin functions. + * expr.c (expand_builtin, case BUILTIN_MEMSET): Open code memset + where val == 0. + +Fri Jun 28 14:10:03 1996 Richard Henderson + + * alpha/linux.h (FUNCTION_PROFILER): _mcount has non-standard linkage. + * alpha/elf.h (LINK_SPEC): Bring emulation name into sync + with Cygnus snapshot. + + * alpha.h ({MASK,TARGET}_BUILD_CONSTANTS): New macros. + (TARGET_SWITCHES): New target option build-constants. + * alpha.c (alpha_emit_set_long_const): New function. + * alpha.md (movdi): Call it. + * expmed.c (expand_mult_highpart): Use op1 not wide_op1 in + expansion of mul_highpart. + + * alpha.c (output_{pro,epi}log): Flag_inhibit_size_directive + should supress .ent, .end, and accompanying directives. + (alpha_output_lineno): Fix polarity on GAS test. + * alpha.h (NO_DBX_FUNCTION_END): New macro. + * dbxout.c (dbxout_function): Respect NO_DBX_FUNCTION_END. + * alpha/elf.h: New file. + * alpha/linux.h (INITIALIZE_TRAMPOLINE): New definition. + * alpha/xm-linux.h (HAVE_STRERROR): Define. + * configure (alpha*-linux*ecoff*): New target, was alpha-*-linux*. + (alpha-*-linux*): Use elf.h. + * crtstuff.c (init_dummy): Only i386-linux (at most) + needs ___brk_addr hack. + +Thu Jun 27 20:23:30 1996 Jon Buller (jonb@metronet.com) + + * ns32k.c (split_di): New; from i386.c. + * ns32k.md (adddi3, subdi3, negdi3): New patterns. + +Thu Jun 27 19:42:50 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * combine.c (force_to_mode, case NE): Fix typo and logical error. + (simplify_comparison): Don't swap args if op1 is CONST_INT. + +Thu Jun 27 18:49:35 1996 Jim Wilson + + * expmed.c (extract_bit_field): Check TRULY_NOOP_TRUNCATION before + making a SUBREG of a REG. + +Thu Jun 27 11:03:59 1996 Ian Lance Taylor + + * mips.h (CC1_SPEC): Put spaces between the -mips* cases. + * mips/osfrose.h (CC1_SPEC): Likewise. + + * sh.c (output_branch): Don't call ADJUST_INSN_LENGTH if insn is + inside sequence. + +Wed Jun 26 19:09:43 1996 Jeffrey A. Law + + * pa.h (CMP_PSI): Delete. + (FUNCTION_POINTER_COMPARISON_MODE): Likewise. + * pa.md (cmppsi): Delete expander. + (canonicalize_funcptr_for_compare): Renamed from plabel_dereference, + turned into an expander + anonymous pattern. + +Tue Jun 25 22:36:11 1996 Doug Evans + + * gcc.c (PEXECUTE_VERBOSE): Define. + (execute): Pass PEXECUTE_VERBOSE to pexecute if -v. + +Tue Jun 25 12:23:54 1996 Michael Meissner + + * rs6000.h (FINALIZE_PIC): Define to call rs6000_finalize_pic. + (rs6000_finalize_pic): Add declaration. + (svr4_traceback): Delete unused declaration. + + * rs6000.md (movsi_got): Don't emit gen_init_v4_pic insn. + (V.4 call insns): Do not use @plt for PIC calls. + + * rs6000.c (print_operand_address): Handle LABEL_REF just like + SYMBOL_REF. + (rs6000_finalize_pic): Define, emit the gen_init_v4_pic insn + before all other insns if needed for V.4 PIC calls. + + * eabi-ci.asm (_GLOBAL_OFFSET_TABLE_): Do not provide a default + definition, since it interferes with the linker generated version. + +Tue Jun 25 01:17:50 1996 Jeffrey A. Law + + * h8300.c (function_prologue): Update "monitor" prologues. + (function_epilogue): Similarly. + + * pa.h (PARSE_LDD_OUTPUT): Handle dynamic libraries that are + loaded "statically". + +Mon Jun 24 19:48:36 1996 Joel Sherrill + + * configure ({i386,i960,m68k,powerpc,sparc}-rtems): New targets. + * i386/go32-rtems.h, i386/i386-rtems.h: New files. + * i960/i960-rtems.h: New file. + * m68k/m68k-rtems.h: New file. + * rs6000/powerpc-rtems.h: New file. + * sparc/sparc-rtems.h: New file. + +Mon Jun 24 23:09:22 1996 Paul Eggert + + * cccp.c: (create_definition): Diagnose `#define #' only once. + +Mon Jun 24 11:42:58 1996 Jim Wilson + + * i386/cygwin32.h, rs6000/cygwin32.h (CPP_PREDEFINES): For consistency, + change to define WIN32, WINNT, and CYGWIN32. + +Mon Jun 24 10:46:50 1996 Michael Meissner + + * rs6000.md (floatsidf2*): Move the xor of the argument into the + define_insn, since it confuses inline function expands. + +Fri Jun 21 20:40:17 1996 Jim Wilson + + * mips.md (call_internal1, call_value_internal1): Delete obsolete code. + (call_internal2, call_value_internal2, call_value_multiple_internal2): + Delete obsolete code. Explicitly load SYMBOL_REF into register. + (call_value): Change Pmode to SImode in gen_call_value_internal0 call. + +Thu Jun 20 12:20:33 1996 Michael Meissner + + * configure (*-aix*): If building a cross compiler, use t-xnewas + instead of t-newas. + + * rs6000.c (num_insns_constant_wide): Fix typo if HOST_WIDE_INT + has more than 32 bits. + +Wed Jun 19 17:50:33 1996 Richard Henderson + + * combine.c (move_deaths): New parameter maybe_kill_insn. + Don't move note if reg killed by maybe_kill_insn. + (try_combine): Pass new arg to move_deaths. + +Wed Jun 19 10:44:47 1996 Brendan Kehoe + + * toplev.c (flag_keep_static_consts): Define. + (f_options): Add "keep-static-consts" entry. + (compile_file): Check it in addition to !optimize for emitting + static const variables. + +Tue Jun 18 23:37:20 1996 Doug Evans + + * i386/cygwin32.h (ASM_OUTPUT_SOURCE_LINE): Local symbols begin with L. + +Tue Jun 18 12:00:11 1996 Jason Merrill + + * varasm.c (asm_output_aligned_bss): Don't emit a skip of size 0. + +Tue Jun 18 06:24:28 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * integrate.c (expand_inline_function): Add missing call to + force_operand when getting structure_value_addr into reg. + + * alpha.c (override_options): Allow EV4/5 or 21064/21164 for cpu. + Clean up handling of floating-point options. + * alpha.h (TARGET_SWITCHES): Have all -mieee options turn + on MASK_IEEE_CONFORMANT. + (TARGET_DEFAULT): Use symbolic value. + * alpha.md: When not involving named pattern, update condition + to include alpha_tp != ALPHA_TP_INSN. + Don't do float_extend as part of other pattern when ALPHA_TP_INSN. + (extendsfsd2): Split into two patterns, depending on + value of alpha_tp. + + * mips/iris6.h (ASM_SPEC): Treat -o32 as -32 and -n64 same as -64. + * mips.c (override_options): Likewise. + + * genattrtab.c (fatal): Declare A1 and A2 as char *. + + * function.c (find_temp_slot_from_address): Check for overlap + from BASE_OFFSET if X is PLUS of virtual_stack_vars_rtx and const. + + * flow.c (flow_analysis): Fix typo in last change. + + * expr.c (expand_builtin, case BUILT_IN_{SET,LONG}JMP): Properly + handle case when ptr_mode != Pmode. + + * combine.c (try_combine): Don't use split if dest of new I2 + is used between I2 and I3. + + * c-typeck.c (pointer_int_sum): Convert integer to both signedness + and precision of sizetype. + * explow.c (convert_memory_address, case PLUS, MULT): Don't commute + operation with extension if not adding small integer. + + * Makefile.in (BOOT_LANGUAGES): New variable. + (bootstrap): Use it to select languages for stage1. + * configure (extra_host_objs): New variable. + Separate files needed for target and host and concatenate list. + (extra_gcc_objs): Use setting for host, not target. + (objc_thread_file): Start with it as null, then don't include "thr-". + Print name of file after others and in same format. + (alpha-*-winnt*, i[3456]86-*-winnt): oldnames.o is in extra_host_objs. + (all_boot_languages): New variable. + Set from boot_language variable in config-lang.in. + Defines value of BOOT_LANGUAGES in Makefile. + (Makefile): Set target to the canonical form of target. + +Mon Jun 17 22:37:07 1996 Mike Meissner + + * rs6000/win-nt.h (ASM_DECLARE_FUNCTION_NAME): Put function + descriptor in .reldata, not .text. + +Mon Jun 17 16:05:34 1996 Brendan Kehoe + + * ginclude/stddef.h (wint_t): Don't wrap with #ifndef __cplusplus. + +Mon Jun 17 15:03:20 1996 Jim Wilson + + * mips.c (mips_split_addresses): New variable. + (simple_memory_operand): Add comment about mode check. Add check + for LO_SUM. + (call_insn_operand): OP is now an addresses instead of a MEM. + (move_operand, mips_check_split): New functions. + (mips_count_memory_refs): Add check for LO_SUM. + (mips_move_1word): Add HIGH support. + (mips_address_cost): Delete check for HIGH. + (output_block_move): Handle LO_SUM addresses. + (override_options): Set mips_split_addresses. + (print_operand_address): Add LO_SUM support. + * mips.h (mips_split_addresses, mips_check_split, move_operand): + New declarations + (GO_IF_LEGITIMATE_ADDRESS): Reject constant addresses when + mips_split_addresses is TRUE. Add LO_SUM support. + (LEGITIMIZE_ADDRESS): Add LO_SUM support. + (PREDICATE_CODES): Modify call_insn_operand support. Add + move_operand. + * mips.md (memory): Change r4100/r4300 support. + (imuldiv): Add r4300 support. + (high, low): New patterns. + (movsi, movdi): Add LO_SUM support. + (movsi_internal1, movsi_internal2): Use move_operand instead of + general_operand. + (movstrsi_internal, movstrsi_internal2): Delete R constraint. + (call, call_value): Pass address instead of MEM to call_insn_operand. + Call gen_call_{value_}internal0 instead of internal1. + (call_internal0, call_value_internal0, call_multiple_internal0): + New patterns. + (call_internal1, call_internal2, call_value_internal1, + call_value_internal2, call_value_multiple_internal2): Add explicit + MEM before target address. + +Sun Jun 16 23:05:16 1996 Jeffrey A. Law + + * configure (hppa*-hp-hpux10*): Use new pa-hpux10 configuration file. + (hppa*-hp-hpux*): Use hpux9 configuration files by default. + * pa/pa-hpux10.h: New file. + * pa/pa-ghpux9.h: Deleted. No longer used. + +Sat Jun 15 04:35:51 1996 Roland McGrath + + * i386/gnu.h (LINK_SPEC): Remove -rpath /lib/ option. + Ignore -ibcs option. + +Thu Jun 13 14:49:41 1996 Jim Wilson + + * gen-protos.c (main): Change argv[i] to argv[0][i]. + +Thu Jun 13 10:46:24 1996 Doug Evans + + * gcc.c (pfatal_pexecute): Delete code to check errno < sys_nerr. + +Wed Jun 12 21:47:10 1996 Eliot Dresselhaus + + * alpha.c (alpha_cpu, alpha_cpu_string): New variables. + (override_options): Process -mcpu= value. + (alpha_adjust_cost): Handle adjustments for EV5. + * alpha.h (enum processor_type): New enum. + (alpha_cpu, alpha_cpu_string): New declarations. + (target_options): Add "cpu=". + (RTX_COSTS): Adjust values for EV5. + * alpha.md: Add scheduling rules for EV5. + +Tue Jun 11 17:51:03 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * c-common.c (check_format_info): Change text of message about use + of `0' with precision. + +Tue Jun 11 15:14:10 1996 Stan Cox + + * i386.h (TARGET_SCHEDULE_PROLOGUE): New. Allows prologue to + be emitted as asm or rtl. + + * i386.c (function_prologue): Emit prologue as asm. + (override_options): Don't emit rtl for prologue if -fpic. + +Tue Jun 11 14:41:01 1996 Michael Meissner + + * rs6000/eabi.asm (__eabi): Fix normal code so that it properly + loads up r2/r13 if needed again. + + * rs6000/sysv4.h (CPP_ENDIAN_SPEC): Call cpp_endian_default, not + cpp_endian_default_spec. + +Mon Jun 10 15:10:56 1996 Jeffrey A. Law + + * local-alloc.c (update_equiv_regs): Ignore insns that read or + write registers that are likely to be spilled. + + * pa.h (cmp_type): Add CMP_PSI. + (FUNCTION_POINTER_COMPARISON_MODE): Define. + * pa.md (cmppsi): New expander. + (plabel_dereference): New pattern + +Mon Jun 10 14:56:14 1996 Michael Meissner + + * rs6000/sol2.h (SKIP_ASM_OP): Delete, Solaris accepts .space, + like rest of PowerPC V4 ports. + + * rs6000/sysv4.h (ASM_OUTPUT_ALIGNED_LOCAL): Emit .lcomm if not + using the .sbss area. If using the .sbss area, put out + appropriate .size directive. + +Mon Jun 10 14:53:38 1996 Doug Evans + + * Move fork/exec/wait handling into file of its own. + * pexecute.c: New file. + * Makefile.in (pexecute.o): Add rule. + (xgcc): Link in pexecute.o. + (protoize,unprotoize): Likewise. + * gcc.c (_WIN32): Don't include process.h or declare spawnv{,p}. + (pexecute,pwait): Add prototypes. + (PEXECUTE_{FIRST,LAST,SEARCH}): Define. + (execv,execvp): Delete decls. + (perror_exec): Delete. + (pfatal_pexecute): New function. + (pexecute support): Delete. + (execute): -pipe not supported if _WIN32 or OS2. + Update call to pexecute. Fatal error if pexecute fails. Call pwait. + * protoize.c: Include gansidecl.h. + (my_execvp): Delete. + (choose_temp_base,pexecute,pwait): Declare. + (PEXECUTE_{FIRST,LAST,SEARCH}): Define. + (execvp): Delete decl. + (usage): Fix typo. + (gen_aux_info_file): Rewrite to use pexecute/pwait. + + * gcc.c (do_spec_1): Allow leading text in version string. + Delete support for default minor number = 0. + +Mon Jun 10 11:49:53 1996 Scott Christley + + * objc/Makefile (libobjc.a): Don't delete the library. + + * objc/thr.h (objc_set_thread_callback): New function. + (objc_thread_callback): Typedef for the hook function. + * objc/thr.c (__objc_thread_detach_function): Clear thread storage. + Call the thread hook function when first becoming multi-threaded. + (objc_set_thread_callback): New function. + + * objc/selector.c (__sel_register_typed_name): Additional parameter + that indicates whether name and type parameters are constant or not. + * objc/runtime.h (__sel_register_typed_name): Likewise. + * objc/init.c (__sel_register_typed_name): Likewise. + + * objc/init.c (__objc_init_protocols): Need to unlock mutex. + +Mon Jun 10 11:44:44 1996 Kaveh R. Ghazi + + * sparc/t-sol2 (gmon.o): Depend on stmp-int-hdrs. + (crt1.o, crti.o, crtn.o, gcrt1.o): Depend on $(GCC_PASSES). + +Mon Jun 10 11:29:46 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * flow.c (flow_analysis, find_basic_blocks): Ignore + nonlocal_label_list for CALL_INSN that has a REG_RETVAL. + + * c-common.c (decl_attributes, case A_T_UNION): Don't look at fields + of union if there aren't any. + +Sat Jun 8 22:13:33 1996 Stan Cox + + * i386.c (ix86_expand_prologue): Keep pic register load ahead + of reference which may use a pic register. + +Sat Jun 8 22:13:33 1996 Jim Wilson + + * i386.md (strlensi_unroll4, strlensi_unroll5): Use + not =& for + constraint for input/output operand 2. + +Sat Jun 8 22:13:33 1996 J"orn Rennecke (amylaar@meolyon.hanse.de) + + * i386.h (CONST_COSTS): Even integer constants have a cost. + (RTX_COSTS): Take costs of subexpressions into account. + If a multiply is actually a shift, use the cost of the shift. + * i386/unix.h (SHIFT_DOUBLE_OMITS_COUNT): New macro. + * i386/{gas, next, seq-gas}.h (SHIFT_DOUBLE_OMITS_COUNT): Redefine + as zero. + * i386.c (print_operand): new letter 's'. + +Sat Jun 8 15:13:33 1996 Jim Wilson + + * mips.c (override_options): Add vr4100 and vr4300 support. + * mips.h (enum processor_type): Likewise. + (MASK_4300_MUL_FIX, TARGET_4300_MUL_FIX): New macros. + (TARGET_SWITCHES): Add -mfix4300 option. + * mips.md (cpu, memory, imuldiv, adder, mult, divide): Add + vr4100 and vr4300 support. + (muldf3, mulsf3): Add vr4300 support. + (muldf3_internal, muldf_r4300, mulsf3_internal, mulsf_r4300): New + patterns. + +Sat Jun 8 14:35:23 1996 David Edelsohn + + * toplev.c (main): Re-enable -gxcoff+. + +Sat Jun 8 14:20:14 1996 J.T. Conklin + + * m68k/lb1sf68.asm (__{eq,ne,gt,lt,ge,le}{df,sf}2): Removed + extraneous comments, constants, labels, etc. + + * m68k/altos3068.h (TARGET_DEFAULT): Use MASK_* macros + instead of explicit constants in definitions or conditionals. + * m68k/{apollo68, aux, ccur-GAS, dpx2, hp320, hp3bsd}.h: Likewise. + * m68k/{hp3bsd44, isi-nfp, isi, linux-aout, linux}.h): Likewise. + * m68k/{lynx-ng, lynx, m68k-none, m68k-psos, m68kv4}.h): Likewise. + * m68k/{mot3300, netbsd, news, next, pbb, plexus, sun2o4}.h): Likewise. + * m68k/{sun3, sun3n, tower}.h): Likewise. + +Sat Jun 8 13:55:23 1996 Matthias Pfaller (leo@marco.de) + + * ns32k.md (define_insns for ffs[qhs]i2): Deleted. + (define_expand for ffssi2): New pattern. + +Sat Jun 8 13:44:14 1996 Stephen L Moshier (moshier@world.std.com) + + * reload.c (find_equiv_reg): Set need_stable_sp if GOAL is the + stack pointer. + +Sat Jun 8 13:36:05 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * function.c (fixup_var_refs_1, case SIGN_EXTEND): Handle + paradoxical SUBREGs as first operand. + (fixup_var_regs_1, case SET): Handle paradoxical SUBREGs as + first operand of a ZERO_EXTRACT in SET_DEST. + + * c-common.c (enum attrs): Add A_FORMAT_ARG. + (init_attribute): Initialize it. + (decl_attributes, case A_FORMAT): Clean up error messages. + (decl_attributes, case A_FORMAT_ARG): New case. + (struct international_format_info): New structure and typedef. + (international_format_list): New variable. + (record_international_format): New function. + (init_format_info): Call it for gettext, dcgettext, and dcgettext. + (check_format_info): See if format arg is call to + internationalization function. + +Fri Jun 7 20:04:40 1996 Jim Wilson + + * gcc.c (MULTILIB_SELECT): Delete definition. + (multilib_select): Delete static initializer. + (multilib_obstack, multilib_raw): New global variables. + (multilib.h): Include inside multilib_raw definition. + (main): Set multilib_select from multilib_raw. + * genmultilib: Change output to be a sequence of short strings + separated by commas rather than a single long macro definition. + + * cse.c (simplify_binary_operation, case MULT): Check for case + where width is larger than HOST_BITS_PER_WIDE_INT, and upper most + bit is set. We can not generate a simple shift in this case. + + * gsyms.h (enum sdb_type): Add T_LNGDBL if EXTENDED_SDB_BASIC_TYPES. + (enum sdb_masks): Add EXTENDED_SDB_BASIC_TYPES masks. + * sdbout.c (gsyms.h): Include if CROSS_COMPILE is defined. + (plain_type_1): Use TYPE_PRECISION instead of TYPE_SIZE. + Add check for LONG_DOUBLE_TYPE_SIZE if EXTENDED_SDB_BASIC_TYPES. + * i960.h (EXTENDED_SDB_BASIC_TYPES): Define. + (PUT_SDB_TYPE): Delete now unnecessary shifting and masking. + + * i960.h (i960_output_move_{double,quad}): Declare. + +Fri Jun 7 19:22:09 1996 Scott Christley + + * Makefile.in (OBJC_THREAD_FILE): New variable. + * configure (objc_thread_file): Set new variable to appropriate + values based upon target operating system; default is `thr-single'. + * objc/Makefile (OBJC_THREAD_FILE): Add target and dependency. + (thr.o): Remove OS specific thread files as dependencies. + * objc/thr-decosf1.c: Now compiles as a separate source file, so + include appropriate Objective-C headers. + * objc/thr-{mach,os2,posix,irix,single,solaris,win32}.c: Likewise. + * objc/thr.c: Remove inclusion of source files. + * objc/thr.h (__objc_thread_exit_status): Declare global variable. + * objc/thr-pthreads.c: New file. + +Fri Jun 7 19:04:04 1996 J.T. Conklin + + * m68k.h (TARGET_SWITCHES): Treat -m68302 like -m68000 and -m68332 + like -m68020; remove -mno-68302 and -mno-68332. + +Fri Jun 7 12:06:12 1996 Per Bothner + + * expr.c (safe_from_p): Allow Chill-style variable-sized arrays. + +Thu Jun 6 23:11:11 1996 Jeffrey A. Law + + * h8300.c (h8300_monitor_function_p): New function. + (h8300_os_task_function_p): Likewise. + (os_task, monitor): Variables to note if the current + function is an os_task or monitor. + (function_prologue): Set monitor and/or os_task as needed. Handle + os_task and monitor functions. + (function_epilogue): Clear monitor and os_task. Handle os_task and + monitor functions. + (h8300_valid_machine_decl_attribute): Accept "OS_Task" and + "monitor". + +Thu Jun 6 20:01:54 1996 Per Bothner + + * gen-protos.c (progname): New variable (needed by cppalloc.c). + (main): Set progname. + + * cpplib.h (struct parse_file): Removed. + (CPP_FATAL_LIMIT, CPP_FATAL_ERRORS, CPP_OUT_BUFFER): New macros. + * cpphash.c (cpp_lookup): Change struct parse_file -> cpp_reader. + + * cpplib.c (init_parse_option): Renamed to cpp_options_init. + (push_parse_file): Renamed to ... + (cpp_start_read): Change to return 1 on success, 0 on failure. + (init_parse_file): Renamed to cpp_reader_init. + * cppmain.c (main): Use CPP_SET_WRITTEN and cpp_fatal. + Use renamed function names, and return protocols. + * fix-header.c (read_scan_file): Likewise. + + * cpperror.c (cpp_message): Generalize for "fatal" errors. + (cpp_fatal): New function (just calls cpp_message). + * cpplib.c (cpp_start_read, cpp_handle_options, cpp_finish, + parse_goto_mark, parse_move_mark): Use cpp_fatal rather than fatal. + + * fix-header.c (check_macro_names): Fix struct parse_file->cpp_reader. + * cpplib.c (newline_fix): Remove unused function. + +Thu Jun 6 19:47:26 1996 Jim Wilson + + Changes to support parameters and return values in multiple + non-contiguous locations. + * calls.c (expand_call): Handle NIL in PARALLEL. Handle PARALLEL + parameter in REG. Handle PARALLEL return value in VALREG. + (emit_library_call, emit_library_call_value): Abort for PARALLEL. + (store_one_arg): Delete code for handling EXPR_LIST. + * expr.c (emit_group_load, emit_group_store): New functions. + (use_group_regs): New function. + (emit_push_insn): Handle PARALLEL parameter in REG. + (expand_assignment): Handle PARALLEL to_rtx. + (store_expr): Handle PARALLEL target. + * expr.h (emit_group_load, emit_group_store, use_group_regs): New + declarations. + * function.c (assign_parms): Handle PARALLEL parameter in ENTRY_PARM. + * stmt.c (expand_value_return): Handle PARALLEL return_reg. + + * mips/abi64.h (TYPE_DEPENDENT_REG): Delete. + * mips.c (function_arg): Return PARALLEL for structure with + aligned double fields. + (type_dependent_reg): Delete. + (mips_function_value): Return PARALLEL for structure + with two floating point fields. + * mips/mips.md (call_value): Handle PARALLEL in operands[0]. + (call_value_multiple_internal2): New pattern. + * pa.h (FUNCTION_ARG): General PARALLEL instead of EXPR_LIST. + * rs6000.c (init_cumulative_args): Change EXPR_LIST to PARALLEL + in comments. + (function_arg): Generate PARALLEL instead of EXPR_LIST. + +Thu Jun 6 18:21:27 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * function.c (assign_parms): Tighten up code that makes REG_EQUIV + notes for parms. + + * fold-const.c (fold): Don't do anything with evaluated SAVE_EXPR. + +Thu Jun 6 17:54:07 1996 J.T. Conklin + + * m68k.h (TARGET_SWITCHES): Group all floating point options. + When an fp option is selected, unset bits used for other mutually + exclusive fp options. + (OVERRIDE_OPTIONS): Remove special case for SUPPORT_SUN_FPA; + bits used for 68881 and SKY are now cleared by TARGET_SWITCHES. + + * m68k.md (movsi_const0, movhi): Favor clr with TARGET_5200. + (add[qhs]3): Don't use two addqw/subqw insns to add small integers to + an address register with TARGET_68060. + (stack push peephole): Use moveq.l with TARGET_5200 (when appropriate). + + * m68k.h (MASK_5200, TARGET_5200): New macros. + (TARGET_SWITCHES): Add "m5200". + (LEGITIMATE_INDEX_P): Add TARGET_5200 to conditional expression. + * m68k.c (const_method): Do not synthesize long constants + with byte or word operations with TARGET_5200. + * m68k.md: Disable byte and word arithmetic, rotate, integer + divide, dbcc, etc. insns for TARGET_5200. + * m68k-none.h: (CPU_FPU_SPEC, CPP_SPEC, ASM_SPEC): Support m5200. + +Thu Jun 6 17:32:32 1996 Paul Eggert + + * fixproto (subdirs): Work around Solaris 2.5 + /usr/xpgr/bin/sed problem with \+\+. + +Thu Jun 6 15:06:27 1996 Jim Wilson + + * c-decl.c (grokdeclarator): Call pop_obstacks after creating + TYPE_DECL. + + * loop.c (strength_reduce): If HAVE_cc0 defined, disable auto_inc_opt + if it would put an insn between a cc0 setter/user pair. + +Thu Jun 6 13:06:54 1996 Michael Meissner + + * rs6000/sysv4.h (LIBGCC2_WORDS_BIG_ENDIAN): If __sun__ is + defined, treat that as little endian. + +Wed Jun 5 20:04:53 1996 Jim Wilson + + * i960.h (ROUND_TYPE_ALIGN): Add check for TYPE_PACKED. + + * sh.h (SHORT_IMMEDIATES_SIGN_EXTEND): Define. + * sh.md (branch_true): Add comment about T-bit compares. + +Tue Jun 4 23:08:34 1996 Per Bothner + + * cpplib.h, cpplib.c: Remove support for !STATIC_BUFFERS. + * cpplib.h: Use unsigned char rather than U_CHAR. + * cpplib.h (cpp_reader): Add destructor #ifdef __cplusplus. + (cpp_cleanup): New prototype. + * cpplib.c (special_symbol, do_once, do_include, cpp_get_token): + Compare cpp_buffer against CPP_NULL_BUFFER, not NULL. + + * cpplib.c (dump_special_to_buffer): New function. + (initialize_builtins): Use it. + +Wed Jun 5 19:10:22 1996 Jeffrey A. Law + + * pa/pa.h (TEXT_SPACE_P): Fix thinko in last change. + +Wed Jun 5 16:25:51 1996 Michael Meissner + + * rs6000.h (ASM_DEFAULT_SPEC): Default to "", not -mpwr. + + * sysv4.h (SUBTARGET_SWITCHES): Add -mshlib. + (LINK_PATH_SPEC): Add -compat-bsd support from Solaris. + (LINK_SPEC): Eliminate %{b} and %{G}, since they conflict with GCC + switches. Defer shared library support to LINK_SHLIB_SPEC. Defer + target selection to LINK_TARGET_SPEC. + (LINK_SHLIB_SPEC): Provide two different versions, depending on + whether shared libraries are default or not. Make shared + libraries not default until linker is fixed. + (LINK_OS_*_SPEC): New specs for OS specific linker switches. + (SUBTARGET_EXTRA_SPECS): Add new specs. + + * {sol2,sysv4}.h (LINK_SPEC): Move Solaris link into general link spec. + + * {sysv4,sysv4le,eabile}.h (LINK_TARGET_SPEC): Only pass -oformat + to the linker if the user is changing the default endian format. + + * {sol2,linux,eabisim,eabilesim}.h (LINK_OS_DEFAULT_SPEC): Define + to use the appropriate OS link spec. + +Wed Jun 5 16:35:10 1996 Ian Lance Taylor + + * ginclude/stddef.h: Fix typo: TYPE_ptrdiff_t to _TYPE_ptrdiff_t. + +Wed Jun 5 15:52:57 1996 Per Bothner + + * varasm.c (output_constructor): Handle RANGE_EXPR in array index. + +Wed Jun 5 13:45:54 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * sparc.md (*call_{address,symbolic}_struct_value_sp32): Allow + operand 2 to be const0_rtx. + +Tue Jun 4 16:43:44 1996 Jason Merrill + + * varasm.c (make_decl_rtl): Don't update DECL_ASSEMBLER_NAME for + local statics. + + * c-decl.c (start_decl): Always set DECL_COMMON on statics. + * varasm.c (assemble_variable): Only treat vars with DECL_COMMON + as common. + +Tue Jun 4 14:55:49 1996 Jeffrey A. Law + + * pa.c (reloc_needed): New function. + * pa.h (TEXT_SPACE_P): Variables/constants with initializers + requiring relocs never live in the text space. + +Tue Jun 4 14:10:46 1996 Ian Lance Taylor + + * sh.c (fp_zero_operand): Do not accept minus zero. + + * sh.h (ASM_OUTPUT_LOOP_ALIGN): Define. + (ASM_OUTPUT_ALIGN_CODE): Define. + (ADJUST_INSN_LENGTH): Add in bytes that may be added by + alignment. + * sh.c (output_branch): Run ADJUST_INSN_LENGTH in reverse to get + correct length. Just call abort rather than returning "bad". + (find_barrier): Adjust limits for possible alignment. + +Tue Jun 4 09:35:05 1996 Michael Meissner + + * rs6000/t-solaris: New target config file for PowerPC Solaris + without gas. + + * rs6000/t-ppc: Eliminate all multilib varients except for + software floating point. + + * configure (powerpcle-*-solaris*): If not --with-gnu-as, use + t-solaris, not t-ppc. + + * rs6000/sol2.h (MULTILIB_DEFAULTS): Add correct defaults for + Solaris. + + * rs6000/sysv4.h (ASM_OUTPUT_SECTION_NAME): Clone from svr4.h, omit + @progbits, since Solaris assembler doesn't like it. + (LIB_SOLARIS_SPEC): If -msolaris-cclib, add libabi.a. + ({START,END}FILE_SOLARIS_SPEC): If -msolaris-cclib, use explicit + pathnames for the Solaris compiler start/end files. + (ASM_SPEC): Pass -mno-regnames to the assembler. + +Mon Jun 3 19:40:10 1996 Jim Wilson + + * mips/abi64.h (CPP_SPEC): Make -mabi=n32 the default. + * mips/iris6.h (MIPS_ISA_DEFAULT, MIPS_ABI_DEFAULT, MULTILIB_DEFAULTS, + ASM_SPEC, STARTFILE_SPEC, ENDFILE_SPEC, LINK_SPEC): Likewise. + * mips.md (tablejump_internal4+1): Fix typo in condition. + * mips/x-iris6 (CC, OLDCC): Define to be `cc -32'. + +Mon Jun 3 07:57:35 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * tree.def ([LR]SHIFT_EXPR): Remove `a' from printed names. + + * sparc.md (call): Mask unimp operand to 12 bits, just like Sun. + + * expr.c (store_field): Fix typo in last change; update TARGET addr. + + * c-decl.c (start_struct): Set TYPE_PACKED from flag_pack_struct. + (start_enum): Likewise but from flag_short_enums. + (finish_enum): Test TYPE_PACKED, not flag_short_enums. + * stor-layout.c (layout_decl): Test DECL_PACKED and TYPE_PACKED + instead of flag_pack_struct. + (layout_record): Likewise. + +Sun Jun 2 19:41:14 1996 Jim Wilson + + * mips.md (tablejump_internal3, tablejump_internal4): New patterns. + (tablejump): Use them for PIC code. + +Fri May 31 17:26:53 1996 Stan Cox + + * i386.c (ix86_expand_epilogue): Don't generate references to an + exposed vacated stack. + * i386.md (epilogue_set_stack_ptr): New. + +Fri May 31 15:07:49 1996 Jim Wilson + + * mips/abi64.h: Add -mabi=n32 support. + (ABI_64BIT): Delete. + (TARGET_LONG64, CPP_SPEC, STACK_BOUNDARY, MIPS_STACK_ALIGN, + GP_ARG_LAST, FP_ARG_LAST, SUBTARGET_CONDITIONAL_REGISTER_USAGE, + MAX_ARGS_IN_REGISTER, FUNCTION_ARG_PADDING, RETURN_IN_MEMORY, + SETUP_INCOMING_VARARGS): Modify. + (REG_PARM_STACK_SPACE): Ifdef out. + (TARGET_DEFAULT, SUBTARGET_TARGET_OPTIONS): Define. + * mips/iris6.h: Add -mabi=n32 support. + (TARGET_DEFAULT, ASM_OUTPUT_INTERNAL_LABEL, + ASM_GENERATE_INTERNAL_LABEL): Delete. + (MULTILIB_DEFAULTS, ASM_SPEC, EXTRA_SECTION_FUNCTIONS, + ASM_OUTPUT_ALIGNED_LOCAL, STARTFILE_SPEC, ENDFILE_SPEC, LINK_SPEC): + Modify. + (MIPS_ABI_DEFAULT, LOCAL_LABEL_PREFIX): Define. + * mips.c: Add -mabi=n32 support. + (mips_const_double_ok, mips_move_1word, mips_move_2words, + function_arg, override_options, mips_asm_file_start, + compute_frame_size, save_restore_insns, function_prologue, + mips_expand_prologue, function_epilogue, mips_function_value): Modify. + (mips_abi, mips_abi_string): Define + * mips.h: Add -mabi=n32 support. + (ABI_64BIT): Delete. + (TARGET_OPTIONS, INITIAL_ELIMINATION_OFFSET, GO_IF_LEGITIMATE_ADDRESS, + CONSTANT_ADDRESS_P, LEGITIMATE_CONSTANT_P, LEGITIMIZE_ADDRESS, + ASM_OUTPUT_ADDR_DIFF_ELT): Modify. + (enum mips_abi_type, SUBTARGET_TARGET_OPTIONS): Define. + (mips_abi, mips_abi_string): Declare. + * mips.md (jump, tablejump_internal1, tablejump_internal2): Add + -mabi=n32 support. + * mips/t-iris6 (MULTILIB_OPTIONS): Add -mabi=n32 support. + * mips/xm-irix6.h (HOST_BITS_PER_LONG): Use _MIPS_SZLONG not 64. + * ginclude/va-mips.h (va_start): Add -mabi=n32 support. + +Fri May 31 14:45:30 1996 Michael Meissner + + * rs6000/sysv4.h (SUBTARGET_SWITCHES): Add -msolaris-cclib to use + the Sun compiler's crt files instead of ours. + ({START,END}FILE_SOLARIS_SPEC): If -msolaris-cclib, use the Sun + compiler's crt files instead of ours. + (SUBTARGET_OVERRIDE_OPTIONS): Don't set -msdata=data for Solaris. + (SBSS_SECTION_ASM_OP): For Solaris, don't use @nobits. + (CPP_OS_SOLARIS_SPEC): Remove -Asystem(unix) and -Asystem(svr4). + + * rs6000/t-ppc{,gas} (MULTILIB*): Add Solaris specific multilibs. + + * rs6000/eabi{,le}sim.h (*_DEFAULT_SPEC): Rather than using + duplicate definitions, just use %(...) so that there is only one + place in the specs file where the switches are defined. + * rs6000/{linux,sol2}.h (*_DEFAULT_SPEC): Ditto. + + * rs6000/sol2.h (CPP_PREDEFINES): Use the standard one in sysv4.h. + (RS6000_ABI_NAME): Default is solaris. + (ASM_OUTPUT_ALIGNED_LOCAL): Don't redefine. + + * rs6000/sol-c{i.asm,n.asm,c0.c}: Provide more things that Solaris + needs for program startup. + +Thu May 30 21:57:34 1996 Mike Stump + + * tree.def (OFFSET_REF): Remove. + * expr.c (expand_expr, case OFFSET_REF): Likewise. + * tree.c (substitute_in_expr): Remove OFFSET_REF code. + +Wed May 29 14:54:44 1996 Michael Meissner + + * rs6000/eabi.asm (__eabi): If not -mrelocatable, don't assemble + relocatable functions, so that it can be assembled with the + Solaris assembler. + + * rs6000/sysv4.h (CPP_SYSV_SPEC): Define _RELOCATABLE if + -mrelocatable-lib as well as -mrelocatable. + + * rs6000.c (rs6000_file_start): New function to print some more + information to the asm file. + * rs6000/{sysv4,win-nt,rs6000}.h (ASM_FILE_START): Call it. + +Tue May 28 15:21:24 1996 Michael Meissner + + * rs6000.h (FIRST_PSEUDO_REGISTER): Bump to 77. + ({FIXED,CALL_USED}_REGISTERS): Add support for fpmem pseudo register. + (REG_ALLOC_ORDER, HARD_REGNO_{NREGS,MODE_OK}): Likewise. + (REGISTER_MOVE_COST, reg_class, REG_CLASS_{NAMES,CONTENTS}): Likewise. + (REGNO_REG_CLASS, PREFERRED_RELOAD_CLASS): Likewise. + (CLASS_{MAX_NREGS,CANNOT_CHANGE_SIZE,MAX_NREGS}): Likewise. + (rs6000_stack, {,DEBUG_}REGISTER_NAMES): Ditto. + (FPMEM_{REGNO_P,REGNUM}): New macros for fpmem register. + (rs6000_fpmem_{offset,size}): New global variables. + (RS6000_VARARGS_OFFSET): Fpmem temporary storage is located + between outgoing arg area and varargs save area. + (STARTING_FRAME_OFFSET, STACK_DYNAMIC_OFFSET): Likewise. + (PREDICATE_CODES): Add fpmem_operand. + ({count_register,fpmem}_operand): Add declarations. + + * rs6000.c ({rs6000,alt}_reg_names): Add support for fpmem 'register'. + (rs6000_fpmem_{offset,size}): New global variables. + (fpmem_operand): Return true for fpmem registers. + (gpc_reg_operand): The fpmem register is not general purpose. + (includes_rshift_p): Add casts to silence warnings from Solaris + PowerPC host compiler. + (print_operand): Add 'v' operand type for the upper 16 bits of + signed constants, to placate the Solaris assembler. + ({rs6000,debug}_stack_info): Add support for fpmem 'register'. + (output_epilog): Likewise. + + * rs6000.md (addsi3,movsi,movsf,movdi): Use %v for constants with + the upper 16 bits, to get the sign correct for PowerPC Solaris. + (float{,uns}sidf2,fix_truncdfsi2): Rewrite to use 'register' 76 + for the memory location used to convert between float and integer. + + * sysv4.h (ASM_OUTPUT_{CON,DE}STRUCTOR): Use code laid down in + .init and .fini for making constructors and destructors under + Solaris. + (ASM_SPEC): Do not pass -u to the assembler. + (CC1_SPEC): -mrelocatable implies -meabi. + + * sol2.h (RS6000_ABI_NAME): Default ABI is Solaris, not System V.4. + (ASM_OUTPUT_ALIGNED_LOCAL): Don't define Solaris specific method. + +Mon May 27 06:39:13 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (expand_builtin, case BUILT_IN_{LONG,SET}JMP): + Convert block address from ptr_mode to Pmode. + +Sun May 26 20:05:43 1996 Doug Evans + + * gcc.c (MSDOS pexecute): Call xmalloc, not malloc. + +Sun May 26 08:31:54 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * configure (vax-*-{sysv}): tm_file and xm_file now list. + (vax-*-ultrix): tm_file is now list. + (we32k-att-sysv*): xm_file now list. + * vax/xm-netbsd.h: Deleted. + * vax/netbsd.h: No longer include vax.h and config/netbsd.h. + * vax/ultrix.h, vax/vaxv.h: No longer include vax.h. + * vax/xm-vaxv.h: No longer include xm-vax.h. + * xm-we32k.h: No longer include xm-svr3.h. + + * configure: Separately set target_cpu_default for two + case statements and then combine if both set. + (alpha-*-winnt3): tm_file and xm_file are now list. + Set target_cpu_default to 64. + * winnt/config-nt.bat: Make .h files properly for Alpha. + * alpha.h (WINDOWS_NT): No longer defined and used. + (MASK_WINDOWS_NT, TARGET_WINDOWS_NT): New macros. + (ASM_OUTPUT_ADDR_DIFF_ELT): Use TARGET_WINDOWS_NT. + * alpha.c (output_prolog): Test TARGET_WINDOWS_NT, not WINDOWS_NT. + * alpha.md: Likewise. + * alpha/config-nt.sed: Properly set tm_file and {build,host}_xm_file. + * alpha/win-nt.h: Don't include alpha.h + (WINDOWS_NT): No longer define. + * alpha/xm-winnt.h: Don't include xm-alpha.h and winnt/xm-winnt.h. + +Fri May 24 12:34:22 1996 Doug Evans + + * configure (cpu_type): Add case for arm. + (sparclet-*-aout*): Delete extra_headers. + + * varasm.c (asm_output_bss): New argument DECL. + Use ASM_DECLARE_OBJECT_NAME if defined. + (asm_output_aligned_bss): Likewise. + (assemble_variable): Pass DECL to ASM_OUTPUT{,_ALIGNED}_BSS. + * arm/aout.h (ASM_OUTPUT_ALIGNED_BSS): Update. + * h8300.h (ASM_OUTPUT_BSS): Update. + * i386/linux.h (ASM_OUTPUT_ALIGNED_BSS): Update. + * i386/sysv4.h (ASM_OUTPUT_ALIGNED_BSS): Update. + * m68k/coff.h (ASM_OUTPUT_ALIGNED_BSS): Update. + * m68k/linux.h (ASM_OUTPUT_ALIGNED_BSS): Update. + * m68k/m68k-aout.h (ASM_OUTPUT_BSS): Update. + * rs6000/sysv4.h (ASM_OUTPUT_ALIGNED_BSS): Update. + * rs6000/win-nt.h (ASM_OUTPUT_ALIGNED_BSS): Update. + * sparc/sysv4.h (ASM_OUTPUT_ALIGNED_BSS): Update. + +Thu May 23 19:55:52 1996 Jim Wilson + + * combine.c (set_nonzero_bits_and_sign_copies): Set reg_sign_bit_copies + to one not zero to indicate value is unknown. + +Thu May 23 18:39:24 1996 J.T. Conklin + + * config/netbsd.h (SWITCH_TAKES_ARG): Add -R. + (LINK_SPEC): Add %{R*}. + + * m68k/lb1sf68.asm: Construct exception masks at compile time + instead of or'ing in bits at run time. + +Thu May 23 15:53:06 1996 Ian Lance Taylor + + * sh.md: Add new instruction types fp and fpdiv. Set new + instruction types where appropriate. Add function unit fp. + Claim that store instructions use function unit memory. + +Thu May 23 00:36:19 1996 Jeffrey A. Law + + * h8300.h (CONSTANT_ADDRESS_P): Don't accept CONST or HIGH on H8/300H. + * h8300.md: Use "m" rather than "o" constraint everywhere appropriate. + Cleanup use of "i" and "n" constraints. + +Wed May 22 17:43:37 1996 Jim Wilson + + * fixincludes (pthread.h): Add extern to __page_size* declarations + for AIX 4.1.x. + + * combine.c (nonzero_bits): Don't assume arg pointer has same + alignment as stack pointer. + +Wed May 22 16:09:05 1996 Michael Meissner + + * rs6000/sysv4.h (LINK_START_DEFAULT_SPEC): Spell macro correctly. + (LIB_DEFAULT_SPEC): Provide default version. + +Wed May 22 11:23:57 1996 J"orn Rennecke (amylaar@meolyon.hanse.de) + + * i386.md (return_pop_internal): new pattern. + (pop): disable emitting of bogus move instruction. + * i386.c (ix86_expand_epilogue): use gen_return_pop_internal to + simultanously return and pop args; removed stray semicolon. + * config/linux-aout.h, config/linux.h (SET_ASM_OP): Added for + __attribute__ ((alias ())) support. + +Wed May 22 08:06:42 1996 Richard Kenner + + * combine.c (init_reg_last_arrays, setup_incoming_promotions): + Correct prototypes. + +Tue May 21 13:42:17 1996 Jeffrey A. Law + + * h8300.md (div and mode patterns): Rewrite. + + * pa.c (basereg_operand): Never accept a CONST_INT. + +Tue May 21 12:26:40 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * pa/pa-hpux9.h, pa-osf.h (LINK_SPEC): Provide version for Snake. + +Tue May 21 07:20:48 1996 Pat Rankin + + * vax.h (TARGET_NAME): Define unless already defined. + (TARGET_VERSION): Print TARGET_NAME. + * vax/vms.h (TARGET_NAME): Always redefine. + (TARGET_VERSION): Delete; retain vax.h definition. + +Mon May 20 14:00:44 1996 Jim Wilson + + * sh.c (output_file_start): Delete misplaced semicolon. + +Mon May 20 11:58:15 1996 Jeffrey A. Law + + * reorg.c (relax_delay_slots): Call update_block before + redirecting a branch past a redundant insn. + +Sun May 19 16:40:53 1996 Philippe De Muyter + + * Makefile.in (libobjc.a, sublibobjc.a): 'specs' added to + dependencies. + +Sun May 19 12:25:48 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * configure: Add new switch to provide default for cpu_type; + delete numerous settings of it in main switch. + (hppa): Reflect rerrangements below; use new configure features. + * pa/pa-gas.h, pa/pa-pro-end.h: New files. + * pa/pa1.h, pa/pa1-osf.h, pa/pa1-ghpux.h, pa/pa1-oldas.h: Deleted. + * pa/pa1-ghpux9.h, pa/pa1-hpux9.h, pa/pa1-hpux.h: Deleted. + * pa/pa1-ghiux.h, pa/pa1-hiux.h, pa/pa-ghpux.h: Deleted. + * pa/pa-gux7.h, pa/pa-ghiux.h: Deleted. + * pa/pa-hiux.h: No longer include pa-hpux.h. + * pa/pa-hpux.h: No longer include pa.h. + (TARGET_DEFAULT): Unset before setting. + (LINK_SPEC): Provide option for pa1. + * pa/pa-hpux7.h: No longer include pa.h. + (HP_FP_ARG_DESCRIPTOR_REVERSED): Don't define here. + * pa/pa-hpux9.h, pa/pa-oldas.h: No longer include pa-hpux.h. + (TARGET_DEFAULT): Don't need to set here. + * pa/pa-osf.h: No longer include pa.h. + (TARGET_DEFAULT): Don't define; identical to default. + * pa/pa-pro.h: No longer include pa.h. + Move definitions after include to new file pa-pro-end.h. + * pa.h (TARGET_SWITCHES): Include TARGET_CPU_DEFAULT. + (TARGET_CPU_DEFAULT): Provide default value. + (CPP_SPEC): Test TARGET_CPU_DEFAULT too. + + * Makefile.in (function.o): Includes bc-emit.h. + (reg-stack.o): Includes insn-flags.h. + * expr.h (function_value): Deleted; no such function. + (bc_build_calldesc, bc_runtime_type_code): New declarations. + * c-decl.c: Add prototypes for all static functions. + * c-iterate.c: Likewise. + * dbxout.c: Likewise. + (adspath): Delete; never used and has numerous parse errors. + * dwarfout.c: If not GNUC, make `inline' null; otherwise, leave alone. + Add `static' to inline functions. + Add prototypes for static function. + * expr.c (bc_runtime_type_code): Delete redundant declaration. + * function.c: Include bc-emit.h. + ({save,restore}_machine_status): Add prototype for args. + (bc_runtime_type_code, bc_build_calldesc): Delete redundant decls. + (bc_emit_trampoline, bc_end_function): Likewise. + * reg-stack.c: Include insn-flags.h. + Add prototypes for static functions. + (gen_jump, gen_movdf, gen_movxf): Delete redundant declarations. + (find_regno_note, emit_jump_insn_before, emit_label_after): Likewise. + (swap_rtx_condition): Now static. + * sdbout.c: Add prototypes for static functions. + (sdbout_parms, sdbout_reg_parms): Delete extra parm to plain_type. + +Sun May 19 11:50:10 1996 John Carr + + * alpha.c (alpha_emit_conditional_move): Compare to 0 in correct mode. + +Sat May 18 20:17:27 1996 Jim Wilson + + * sh.c (prepare_move_operands): If source is r0, and dest is reg+reg + MEM, then copy source to a pseudo-reg. + * sh.md (untyped_call): New pattern. + + * unroll.c (copy_loop_body): When update split DEST_ADDR giv, + check to make sure it was split. + (find_splittable_givs): Fix reversed test of verify_addresses result. + +Sat May 18 10:26:04 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * tree.c (unsave_expr_now): Avoid use of NULL_RTX since no rtl.h. + + * configure: Set cpu_default, tm_file, and xm_file early. + Remove redundant settings of those, tmake_file, and xmake_file. + Use ${tm_file} and ${xm_file} to refer to the main files. + Sort some entries for consistency and reformat some others. + (rs6000, powerpc): Remove bogus test on host == target. + (alpha-*-linux): xm-linux.h no longer includes xm-alpha. + (alpha-*-osf*): Remove redundant setting of target_cpu_default. + (*-convex-*): Use target_cpu_default instead of separate .h files. + (clipper-intergraph-clix*): clix.h no longer includes any files. + (i860, i960, pdp11): Reflect removal of includes listed below. + * alpha/xm-linux.h: No longer include xm-alpha.h. + * clipper/clix.h: No longer include clipper.h and svr3.h. + * convex.h: Provide a default for TARGET_DEFAULT. + Take "or" of TARGET_DEFAULT and TARGET_CPU_DEFAULT everywhere. + * convex/convex{1,2,32,34,38}.h: Deleted. + * i860/bsd-gas.h: No longer include bsd.h. + * i860/bsd.h: No longer include i860.h. + * i860/fx2800.h: No longer include i860/sysv4.h. + (OUTPUT_TDESC): No longer define. + (ASM_FILE_END): Move redefinition to here. + * i860/mach.h: No longer include i860.h. + * i860/paragon.h, i860/sysv3.h: No longer include i860.h and svr3.h. + * i860/sysv4.h: No longer include i860.h and svr4.h. + (ASM_FILE_END): Delete redefinition from here. + * i860/xm-fx2800.h: No longer include xm-i860.h. + * i860/xm-paragon.h, i860/xm-sysv{3,4}.h: Deleted. + * i960/i960-coff.h: No longer include i960.h and dbxcoff.h. + * i960/vx960-coff.h: No longer include i960-coff.h. + * i960/vx960.h: No longer include i960.h. + * pdp11/2bsd.h: No longer include pdp11.h. + + * i370/i370.h: Renamed from mvs.h. + * i370/i370.c: Renamed from mvs370.c. + * i370/t-i370: Renamed from t-mvs. + * i370/xm-i370.h: Renamed from xm-mvs.h. + * configure (i370-*-mvs*): Use default names for all files. + + * c-parse.in: Update number of shift/reduce conflicts for objc. + +Sat May 18 08:20:17 1996 Dennis Glatting (dennisg@plaintalk.bellevue.wa.us) + + * m68k/next.h (FINALIZE_TRAMPOLINE): Add missing backslashes. + +Fri May 17 19:57:20 1996 Pat Rankin + + * vax/xm-vms.h (dbxout_resume_previous_source_file): New macro. + +Fri May 17 14:20:13 1996 Mike Stump + + * expr.c (expand_expr, cond TARGET_EXPR): Make TARGET_EXPRs + redoable for UNSAVE_EXPR. + * stmt.c (expand_decl_cleanup): Wrap the cleanup in an UNSAVE_EXPR + to that we can redo it. + * tree.c (unsave_expr_now): Handle TARGET_EXPRs fully now. + * tree.def (TARGET_EXPR): Add a fourth field so that TARGET_EXPRs + are redoable. + + * expr.c (expand_expr, cond UNSAVE_EXPR): Move from the C++ + frontend to the backend where it belongs. + * tree.c (unsave_expr{,_now}): Likewise. + * tree.def (UNSAVE_EXPR): Likewise. + * tree.h (unsave_expr{,_now}): Likewise. + +Fri May 17 15:04:40 1996 Michael Meissner + + * rs6000.md (lshrsi3 insns): Add special case code for shifting by + 0 to avoid bad code generated with no optimization. + +Fri May 17 13:50:55 1996 Jason Merrill + + * i386/unix.h (ASM_OUTPUT_MI_THUNK): Define. + * i386/{att.h,bsd.h,sun386.h} (ASM_OUTPUT_MI_THUNK): Delete. + +Fri May 17 13:34:28 1996 Ian Lance Taylor + + * fp-bit.c (_fpdiv_parts): Correct sign handling when + dividing zero or infinity by something. + +Fri May 17 12:36:36 1996 Doug Evans + + Standardize option output in assembler files. + * Makefile.in (toplev.o): Pass -DTARGET_NAME. + * arm/aout.h (ASM_OUTPUT_OPTIONS): Delete. + (ASM_FILE_START): Delete option output support. + * arm.c (output_option, output_options, m_options): Delete. + * m88k.c (output_file_start): Delete option output support. + * m88k.h (ASM_COMMENT_START): Define. + * mips.c (target_switches, print_options): Delete. + (mips_asm_file_start): Put output of -G,Cpu,ISA here. + * mips.h (ASM_COMMENT_START): Change from "\t\t#" to " #". + * rs6000.c (output_option, m_options, output_options): Delete. + * rs6000.h (ASM_OUTPUT_OPTIONS): Delete. + (ASM_COMMENT_START): Define. + (ASM_FILE_START): Delete option output support. + * rs6000/sysv4.h (ASM_FILE_START): Likewise. + * rs6000/win-nt.h (ASM_FILE_START): Likewise. Delete duplicate. + * sh.c (output_option, m_options, output_options): Delete. + (output_file_start): Delete option output support. + * sh.h (ASM_FILE_START): Likewise. + (ASM_COMMENT_START): Define. + * dwarfout.c (*): flag_verbose_asm renamed to flag_debug_asm. + * flags.h (flag_debug_asm): Declare. + * toplev.c (print_version): New function. + (print_single_switch): New arguments pos, max, indent, sep, term. + (print_switch_values): New arguments pos, max, indent, sep, term. + Update call to print_single_switch. Output options passed and + options enabled. + (MAX_LINE): New macro. + (flag_debug_asm): Define. + (compile_file): Output options to assembler file. + (main): Recognize -dA. Call print_version. Update call to + print_switch_values. + (line_position): Deleted. + +Fri May 17 10:50:44 1996 Stan Cox (coxs@dg-rtp.dg.com) + + * i386.c (function_prologue, ix86_expand_prologue, + function_epilogue, ix86_expand_epilogue): Generate prologue and + epilogue as RTL (prior to scheduling) instead of emitting asm. + (override_options): If only -march is given, make it the default -mcpu. + * i386.h (FUNCTION_BEGIN_EPILOGUE): Renamed from FUNCTION_EPILOGUE. + * i386.md (return, return_internal, prologue, prologue_set_got, + prologue_get_pc, epilogue, leave, pop): New patterns for emitting + asm from prologue and epilogue RTL. + * m88k/t-dgux (T_CFLAGS): Delete. + * m88k/x-dgux (X_CFLAGS): New. + +Fri May 17 09:54:23 1996 Jim Meyering (meyering@asic.sc.ti.com) + + * Makefile.in (stamp-crt{,S}): Use -o to avoid conflicts if + both of these are built in parallel. + +Fri May 17 08:55:19 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expmed.c (store_split_bit_field): Don't assume the alignment + of VALUE is the same as the record. + + * configure: Write #define TARGET_CPU_DEFAULT into tm.h + instead of defining MAYBE_TARGET_DEFAULT in Makefile. + (alpha-*-linux): Set target_cpu_default to 4 and xmake_file to none. + (alpha-*-osf*): Set target_cpu_default to 4 if --gas. + * Makefile.in (gcc.o, toplev.o, $(out_object_file)): + Remove MAYBE_TARGET_DEFAULT. + + * combine.c (insn_cuid): New function. + (INSN_CUID): Sometimes call it. + +Fri May 17 08:12:37 1996 Scott Christley + + * objc/sendmsg.c (objc_get_uninstalled_dtable): New function. + * objc/objc-api.h (objc_get_uninstalled_dtable): New declaration. + + * objc/thr-os2.c, objc/thr-posix.c, objc/thr-mach.c: New files. + * objc/THREADS.MACH: New file. + + * objc/sendmsg.c (nil_method): Deleted from here. + * objc/nil_method.c: New file. + * Makefile (OBJC_O): Add dependency for nil_method.c. + + * objc/hash.c (hash_is_key_in_hash): New function. + * objc/hash.h: Include objc/objc.h here instead of in objc/hash.c + to get BOOL typedef. + +Fri May 17 08:01:48 1996 Doug Rupp (rupp@gnat.com) + + * msdos/configur.bat: If Ada subdirectory present, adjust Makefile. + +Fri May 17 07:40:04 1996 Ulrich Drepper (drepper@cygnus.com) + + * stddef.h: If need_wint_t defined, nothing in this file is needed. + (_WINT_T, __WINT__TYPE__, wint_t): Define under certain circumstances. + +Thu May 16 18:53:25 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * fold-const.c (fold, case EQ_EXPR): When folding VAR++ = CONST, + mask the new const if VAR is a bitfield reference; also for VAR--. + +Thu May 16 18:29:03 1996 Doug Evans + + * varasm.c (function_section): Delete flag_function_sections support. + (assemble_start_function): Put it here. Use UNIQUE_SECTION if defined. + +Wed May 15 13:35:11 1996 Michael Meissner + + * rs6000.{h,c,md} (rs6000_pic_register): Delete all uses, use + pic_offset_table_rtx instead. + + * rs6000.md (move_to_float): Rewrite so that it uses the register + allocator to allocate the stack temp, instead of calling + rs6000_stack_temp. + (fix_truncdfsi2): Likewise. + + * rs6000.c (rs6000_stack_temp): Delete, no longer used. + +Wed May 15 10:39:27 1996 Jeffrey A. Law + + * h8300.h (DBX_OUTPUT_MAIN_SOURCE_FILE_END): Define. + +Sat May 11 07:42:59 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (store_field): Support BLKmode bitfield if aligned on + byte boundary using emit_block_move. + (expand_expr, case COMPONENT_REF): Likewise. + +Fri May 10 18:33:39 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * configure (alpha-*-linux): Reverse order in tm_file list. + Delete xmake_file. + * alpha/x-linux: Deleted. + * alpha/linux.h (ASM_FINAL_SPEC): Add #undef. + * alpha/xm-linux.h: Remove bogus trailing #endif. + + * loop.c (maybe_eliminate_biv_1): Disable all but two cases + of biv elimination with givs and restrict those two cases to + an ADD_VAL that is an address. + + * flow.c (mark_set_1, mark_used_regs): Clean up usages + of ALL_NEEDED; change to SOME_NOT_NEEDED and set properly. + +Fri May 10 11:37:38 1996 Jason Merrill + + * toplev.c (compile_file): Don't warn about artificial functions + declared static and not defined. + +Thu May 9 22:03:28 1996 Doug Evans + + * varasm.c (assemble_start_function): ASM_DECLARE_FUNCTION_NAME + needn't consider bytecodes. + (assemble_variable): ASM_DECLARE_OBJECT_NAME needn't + consider bytecodes. + * toplev.c (rest_of_decl_compilation): Likewise with + ASM_FINISH_DECLARE_OBJECT. + * arm/aof.h (ASM_DECLARE_{FUNCTION,OBJECT}_NAME): Delete bytecode + support. + * vax/vms.h (ASM_DECLARE_OBJECT_NAME): Likewise. + +Thu May 9 19:36:13 1996 Jim Wilson + + * sh.h (SET_ASM_OP): Define. + +Thu May 9 13:31:58 1996 Michael Meissner + + * rs6000/sysv4.h (SUBTARGET_{SWITCHES,OPTIONS}): Add support for + finer grain control on -msdata, so that eabi people can specify to + compile sdata code to only use r13 instead of r2/r13. Make + -mrelocatable-lib turn off -msdata, just like -m relocatable does. + (SUBTARGET_OVERRIDE_OPTIONS): Ditto. + (ENCODE_SECTION_INFO): Move to rs6000.c. + (ASM_SPEC): -msdata=eabi sets -memb also. + (CC1_SPEC): -mno-sdata gets converted to -msdata=none. + + * rs6000.c (rs6000_sdata{,_name}): Add support for finer grain + control on -msdata. + (output_options, small_data_operand, print_operand): Likewise. + (rs6000_select_section): Likewise. + (rs6000_encode_section_info): Move here from sysv4.h, section + names are stored as STRING nodes, not IDENTIFIER. + +Wed May 8 21:04:49 1996 Doug Evans + + * function.c (aggregate_value_p): Return 1 if TREE_ADDRESSABLE. + * pa.h (RETURN_IN_MEMORY): No longer test for TREE_ADDRESSABLE. + +Tue May 7 13:42:57 1996 Jeffrey A. Law + + * h8300.c: Include obstack.h. + (bit_memory_operand): New function. + (print_operand): Append ":16" to a memory reference to + the tiny data area. + (h8300_tiny_data_p): New function. + (h8300_valid_machine_decl_attribute): Accept "tiny_data". Fix typo. + (h8300_encode_label): New function. + (h8300_adjust_insn_length): References to the tiny data section + are two bytes shorter than normal accesses on the H8/300H. + * h8300.h (OK_FOR_U): Fix thinko. + (ENCODE_SECTION_INFO): Encode info for tiny data variables. + (STRIP_NAME_ENCODING): Define. + * h8300.md (movqi insn): Fix length for a constant load. + (movstrictqi, movhi, movstricthi): Likewise. + (memory btst patterns): Add register to the constraints to keep + reload happy. + + * h8300.h (OK_FOR_U): (const (plus (symbol_ref) (const_int))) + is valid U operand if SYMBOL_REF_FLAG is set on SYMBOL_REF. + * h8300.md (memory btst patterns): New patterns. + + * h8300.c (h8300_eightbit_data_p): Renamed from h8300_tiny_data_p. + (h8300_eightbit_data_p): Check for the "eightbit_data" + attribute instead of "tiny_data". + (h8300_valid_machine_decl_attribute): Likewise. + * h8300.h (ENCODE_SECTION_INFO): Call h8300_eightbit_data_p + instead of h8300_tiny_data_p. + + * h8300.h (READONLY_DATA_SECTION): Define. + (EXTRA_SECTIONS): Add in_readonly_data. + (READONLY_DATA_SECTION_ASM_OP): Define. + (EXTRA_SECTION_FUNCTINOS): Add readonly_data. + +Tue May 7 09:26:24 1996 Jason Merrill + + * varasm.c (make_decl_rtl): Update DECL_ASSEMBLER_NAME for local + statics. Remove reference to flag_no_common. + +Mon May 6 21:38:36 1996 Paul Eggert + + * cpplib.c (skip_comment, handle_directive): Don't use uninit vars. + +Mon May 6 18:47:36 1996 Doug Evans + + * dbxout.c (dbxout_function): When deciding to call dbxout_function_end + change test from flag_function_sections to DECL_SECTION_NAME != NULL. + + * varasm.c (named_section): Accept any decl. + +Mon May 6 16:41:08 1996 Stan Cox (coxs@dg-rtp.dg.com) + + * final.c (final_scan_insn): Modify conditional moves whose cc is + nonstandard. + + * c-common.c (decl_attributes): Chain multiple attributes correctly. + +Mon May 6 15:41:43 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * stmt.c (expand_decl): Don't deduce alignment of SIZE from + DECL_ALIGN; use TYPE_ALIGN instead. + + * function.c (assign_parms): Set RTX_UNCHANGING_P in stack_parm + if parm is read-only. + + * c-common.c (truthvalue_conversion, case ADDR_EXPR): Don't + treat address of external decl as always nonzero. + +Mon May 6 11:33:57 1996 Jason Merrill + + * c-decl.c (start_decl): Check -fno-common here. + * varasm.c (assemble_variable): Instead of here. + * final.c (end_final): Likewise. + * c-common.c (init_attributes, decl_attributes): Add A_COMMON. + +Mon May 6 11:12:39 1996 Mike Stump + + * expr.c (expand_increment): Add third parameter to know when to + ignore the result value. + (store_constructor): Likewise + (expand_expr, case {PRE,POST}{INC,DEC}REMENT_EXPR): Likewise. + * tree.c (stabilize_reference): Always ignore the first operand of + COMPOUND_EXPRs. + +Mon May 6 13:14:45 1996 Jim Wilson + + * sh.c (gen_shifty_op): Truncate VALUE to avoid out of bounds array + access. + + * expr.c (expand_expr, case INDIRECT_REF): Delete obsolete code + to special case a SAVE_EXPR operand. + +Mon May 6 10:00:12 1996 Pat Rankin + + * vax.h (ASM_OUTPUT_MI_THUNK): Define. + +Mon May 6 09:49:10 1996 Andreas Schwab + + * m68k/linux.h: Use the new trampoline definition. + (TRAMPOLINE_TEMPLATE, TRAMPOLINE_SIZE): Deleted. + (INITIALIZE_TRAMPOLINE): Changed. + (FINALIZE_TRAMPOLINE, CLEAR_INSN_CACHE): New. + +Mon May 6 09:43:55 1996 Patrick J. LoPresti (patl@lcs.mit.edu) + + * rtlanal.c (rtx_addr_varies_p): Scan operands of type `E'. + +Mon May 6 09:04:40 1996 H.J. Lu (hjl@gnu.ai.mit.edu) + + * x-linux{,-aout} (BOOT_CFLAGS, STMP_FIXPROTO, STMP_FIXPROTO): Deleted. + * config/t-linux (BOOT_CFLAGS, STMP_FIXPROTO, STMP_FIXPROTO): New, + moved from x-linux. + * t-linux-aout: New file. + * configure (i[3456]86-*-linux*oldld*, i[3456]86-*-linux*aout*): + Set tmake_file to t-linux-aout. + +Sun May 5 22:13:22 1996 H.J. Lu (hjl@gnu.ai.mit.edu) + + * Makefile.in (gxx_include_dir): Change to $(prefix)/include/g++. + (old_gxx_include_dir): New - defined as $(libdir)/g++-include. + (cccp.o, cpplib.o): Also pass OLD_GPLUSPLUS_INCLUDE_DIR (set + from $(old_gxx_include_dir)). + * cccp.c (include_defaults_array): For C++, also search + OLD_GPLUSPLUS_INCLUDE_DIR. + * cpplib.c (default_include): Likewise. + * configure: Remove no-longer-needed support for --gxx-include-dir. + +Sun May 5 21:59:53 1996 Andreas Schwab + + * c-lex.c (check_newline): Fix #pragma parsing; issue error message + for directive that starts with `p' but isn't `pragma'. + +Sun May 5 13:13:40 1996 Jeremy Bettis + + * objc/hash.c (hash_value_for_key): Prevent endless loop when 0 was + stored in a hashtable. + +Sun May 5 13:09:54 1996 Satoshi Adachi (adachi@wisdom.aa.ap.titech.ac.jp) + + * m68k/newsgas.h (SET_ASM_OP, ASM_WEAKEN_LABEL): Define. + +Sun May 5 12:48:08 1996 Stephen L Moshier (moshier@world.std.com) + + * tree.c (build_real_from_int_cst): Remove spurious test for + REAL_IS_NOT_DOUBLE. + +Sat May 4 12:17:58 1996 Richard Earnshaw (rearnsha@armltd.co.uk) + + * arm.h (ASM_OUTPUT_MI_THUNK): Moved here from aout.h. Rewrite to be + independent of the selected assembler, and to use optimal number of + instructions. + * arm/aout.h (ASM_OUTPUT_MI_THUNK): Delete. + + * arm/aout.h (ASM_OUTPUT_OPTIONS): Define. + (ASM_FILE_START): Call ASM_OUTPUT_OPTIONS. + (BSS_SECTION_OP): Define. + (ASM_OUTPUT_ALIGN): Don't output anything if byte alignment is wanted. + (ASM_OUTPUT_ALIGNED_BSS): Define. + * arm.h (target_cpu_name): Delete. + (TARGET_SWITCHES): Delete "be" and "le". + (TARGET_OPTIONS): Delete "cpu-", add "tune=". + (struct arm_cpu_select): New struct. + (PROCESSOR_DEFAULT, TARGET_CPU_DEFAULT): Define. + (EXTRA_CC_MODES, EXTRA_CC_NAMES): Add CC_Cmode. + (CANONICALIZE_COMPARISON): Define. + * arm.c (arm_select): Declare and initialize. + (all_procs): Add arm7100. + (arm_override_options): Parse arm_select structure to determine + selected architecture and tuning parameters. + (output_option, output_options): New functions. + (arm_canonicalize_comparison): New function. + (arm_gen_movstrqi): Don't add a writeback of the index registers for + the last instructions. + (arm_select_cc_mode): Detect case where mode is carry out of unsigned + arithmetic. + (output_lcomm_directive): Use bss_section (), and use alignment + rather than rounding. + (get_arm_condition_code): Handle CC_Cmode. + (final_prescan_insn): Avoid boundary case where we would occasionally + inline MAX_INSNS_SKIPPED+1 insns. Allow call_insns to be inlined in + APCS_32 mode if they are the last insn in the block. + * arm.md (*addsi3_compareneg): Delete potentially unsafe insn. + (*addsi3_compare_op[12]): New insns. + (*compare_addsi2_op[01]): New insns. + (*addsi3_carryin, *addsi3_carryin_alt[12]): New insns. + (*cmp_ite1): Use arm_add_operand instead of arm_rhs_operand. + * semi.h (PROCESSOR_DEFAULT): Default to PROCESSOR_ARM6. + +Fri May 3 10:52:11 1996 1996 Stan Cox (coxs@dg-rtp.dg.com) + + * i386.md (movesicc, movehicc) Pentium Pro conditional move insns. + + * i386.h (TARGET_PENTIUMPRO, TARGET_CMOVE, BRANCH_COST, + ASM_OUTPUT_FUNCTION_PREFIX): New macros for conditional move. + + * i386.c (asm_output_function_prefix, function_prologue): Setup + pic on Pentium Pro so a return will match the call. + (print_operand, put_condition_code): Output conditional move suffixes. + +Fri May 3 10:52:11 1996 Jason Merrill + + * i386/{att.h,gas.h,bsd.h,sub386.h} (ASM_OUTPUT_MI_THUNK): Define. + +Wed May 1 17:54:51 1996 Doug Evans + + * sparc.h (ASM_OUTPUT_MI_THUNK): Fix for sparc64, optimize. + +Wed May 1 13:28:32 1996 Jason Merrill + + * i386/linux.h (ASM_OUTPUT_ALIGNED_BSS): Define. + * i386/sysv4.h: Likewise. + * sparc/sysv4.h: Likewise. + +Wed May 1 01:44:47 1996 Jeffrey A. Law + + * h8300.c (h8300_adjust_insn_length): Adjust the cost of + shifts by small constant values. + * h8300.md: Remove names from many patterns which don't need them. + (compare insns): Don't underestimate lengths. + (andqi3 expander): Remove constrains. + (andhi3): Don't underestimate length. + (andsi3): Don't underestimate length. Improve code when upper + or lower half of destination is being cleared. + (indirect_jump_h8300, indirect_jump_h8300h): Simplify. + (shift insns): Remove useless "I" constraint. + + * h8300.md (bcs type): Remove "bcs" type attribute and all references. + (bcs insns): Delete. No longer needed. + (setcc from bitfield): Rewrite to use zero_extract. Provide + QImode, HImode and SImode variants. + +Tue Apr 30 18:13:09 1996 Jason Merrill + + * svr4.h (SELECT_SECTION): If RELOC is true, put it in data. + +Tue Apr 30 17:26:30 1996 Jason Merrill + + * fold-const.c (fold): Don't call convert to recreate tree nodes + we already have. + +Tue Apr 30 16:52:41 1996 Jeffrey A. Law + + * h8300.c (one_insn_adds_subs_operand): New function. + (h8300_adjust_insn_length): New function. + * h8300.h (ADJUST_INSN_LENGTH): Define. + * h8300.md: Remove obsolete comments. + (move patterns): Tweak constraints. + (tst patterns): Use "register_operand" for predicate. + (adds pattern): Use one_insn_adds_subs_operand to get length + computation correct. + (subs pattern): Similarly. + (movstrhi): Remove unused expander. + (fancy*, pxor, and-not patterns): Remove. No longer needed. + +Tue Apr 30 13:35:06 1996 Michael Meissner + + * rs6000/sol-c0.c (_start): Temporarily display calling + __do_global_ctors, since the Solaris linker doesn't handle the + relocations properly. + +Mon Apr 29 13:03:12 1996 Doug Evans + + * sparc/vxsparc.h: sparc-aout.h renamed to aout.h. + +Mon Apr 29 00:35:15 1996 Jeffrey A. Law + + * h8300.c (names_small): Remove "BAD" postfix from %r7 byte registers. + (rtx_equal_function_value_matters): Remove extra declaration. + (output_simode_bld): New function. + * h8300.h (NO_FUNCTION_CSE): Do define this. + (reg_class): Remove LONG_REGS, SP_REG, SP_AND_G_REGS. + (REG_CLASS_{NAMES,CONTENTS,FROM_LETTER}): Corresponding changes. + (REGNO_REG_CLASS): Corresponding changes. + (output_simode_bld): Declare. + * h8300.md: Nuke comments for stuff which has been fixed. + (all patterns): Remove references to register class "a" (SP_REGS) + which no longer exists. + (many patterns): Accept auto-inc auto-dec addresses in more cases. + (zero_extendqisi2): New pattern for the H8/300. + (zero_extendhisi2): Only use zero_extendhisi2_h8300 when not + optimizing. + (extendhisi2): Only use extendhisi2_h8300 when not optimizing. + (extendqisi2): New pattern for the H8/300. + (bitfield related patterns): Completely rewrite. + (fancy_bclr, fancy_btst): Deleted. + (addhi3 pattern for h8300): Handle case where we can't make matching + constraints (works around hard to fix reload problem). + (stack_pointer_manip): Delete. + (and not patterns): New combiner patterns. + + * pa.h (DBX_OUTPUT_MAIN_SOURCE_FILE_END): Make sure the + final $CODE$ subspace is in the $TEXT$ space. + +Sun Apr 28 14:52:21 1996 Jason Merrill + + * svr4.h (ASM_OUTPUT_SECTION_NAME): If no decl is specified, + make the section read/write data. + +Sat Apr 27 10:28:59 1996 Michael Meissner + + * rs6000/t-ppcgas (MULTILIB_EXCEPTIONS): Don't allow -mrelocatable + and -mcall-sysv-noeabi. + + * rs6000/sysv.h (SUBTARGET_OVERRIDE_OPTIONS): The -mcall-aix + option sets -meabi. Don't allow -mrelocatable without -meabi. + +Fri Apr 26 16:10:46 1996 Doug Evans + + * sparc.md (*smacsi,*smacdi,*umacdi): Fix constraint on + operand 0. + +Fri Apr 26 14:36:33 1996 Michael Meissner + + * i960/t-{960bare,vxworks960} (MULTILIB*): Add + soft-float multilib support. + +Fri Apr 26 06:38:56 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * stor-layout.c (layout_decl): Turn off DECL_BIT_FIELD for BLKmode + that's properly aligned and a multiple of a byte. + +Thu Apr 25 22:43:19 1996 Doug Evans + + * i386/gas.h (ASM_OUTPUT_ALIGN): #if 0 out again. + Undoes change of Apr. 9. + * i386/go32.h (ASM_OUTPUT_ALIGN): Define. + +Thu Apr 25 14:05:33 1996 Richard Kenner (kennervlsi1.ultra.nyu.edu) + + * calls.c (expand_call): In inlining case, if BEFORE_CALLS is + zero, start looking at first insn (one more place). + + * expr.c (expand_builtin, case BUILT_IN_SETJMP): CLOBBER the + static chain after label at setjmp point. + +Thu Apr 25 09:02:24 1996 Michael Meissner + + * rs6000.c (print_operand{,_address}): Correct compile error if + TARGET_EABI is not defined. Also, just call small_data_operand, + without testing the ABI. + (rs6000_select_section): Ditto. + + * rs6000/sysv4.h (CC1_SPEC): For -mcall-solaris, don't pass + -mno-main-init. + +Wed Apr 24 18:26:48 1996 Brendan Kehoe + + * collect2.c (handler): Delete export_file when we get a signal. + +Wed Apr 24 14:54:44 1996 Jeffrey A. Law + + * pa/pa1-ghpux.h (LINK_SPEC): Define. Link in PA1.1 libraries + by default. + * pa/{pa1-ghpux9.h, pa1-hpux.h, pa1-hpux9.h}: Likewise. + +Wed Apr 24 11:12:06 1996 Michael Meissner + + * configure (powerpc{,le}-*-eabi*): Use t-ppc{,gas}, instead of + t-eabi{,gas}. + (powerpc-*-linux,powerpcle-*-solaris): Add definitions. + (MULTILIB_DIRNAMES): Pick shorter names for the multilib + directories. + (MULTILIB_*): Do not build -msdata versions of the library. Build + both system V and eabi versions of the libraries. + + * rs6000/t-ppc{,gas} (MULTILIB*): Don't build -msdata versions of + the libraries. Split -mcall-sysv libraries into + -mcall-sysv-{eabi,noeabi} varients. + (LIB2FUNCS_EXTRA): Add eabi.S, eabi-ctors.c. + (eabi.S): Use eabi.S, not eabi.s for eabi.asm. + (crt files): Add support for Solaris crt files. + + * rs6000/sol{2.h,-c0.c,-ci.asm,-cn.asm}: New files for Solaris. + + * rs6000/linux.h: New file for Linux-based GNU system support. + + * rs6000/eabi-ci.asm (ppc-asm.h): Include. + (.got section): Correct attribute. + + * rs6000/eabi-c{i,n}.asm (.init,.finit): Add support for System V + style .init/.fini sections, that constructors and destructors + place a bl in the appropriate section. + + * rs6000/eabi-ctors.c (__do_global_{c,d}tors): Call __init, and + __fini to handle constructors/destructors in the .init, .fini + sections. + + * rs6000/{eabi,sysv}.h: Move most eabi configuration stuff from + eabi.h to sysv.h. + + * rs6000/sysv.h (TARGET_*): Convert -mcall-xxx from switch into option. + Add -mcall-{solaris,linux,sysv-eabi,sysv-noeabi} options. + Add -m{,no-}eabi options to control whether we adhere to + the System V spec or the EABI spec. Add -m{,no-}regnames to + control whether registers are printed out as %r0 instead of 0. + (SUBTARGET_OVERRIDE_OPTIONS): Add support for new -mcall options. + (FP_ARG_MAX_REG): Use new macros for ABI conformance. + (RS6000_REG_SAVE): Likewise. + (STACK_BOUNDARY,BIGGEST_ALIGNMENT): If eabi, align to 8 byte + boundary, otherwise 16 byte. + (EXTRA_SECTIONS): Add .init, .fini sections. + (*_SPEC): Reorganize so that the different targets all have sub + specs that go in the specs file. Add support for linux and + Solaris targets. + + * rs6000/{sysv4,eabi}*.h (*_SPECS): Only override the default + spec, all other specs moved to sysv4.h. + (RS6000_ABI_NAME): Use RS6000_ABI_NAME to set the default ABI + name, not TARGET_DEFAULTS. + + * rs6000/xm-sysv4.h (alloca): Properly declare alloca if compiler + is not GCC. + (DONT_DECLARE_SYS_SIGLIST): Define. + + * rs6000.c (rs6000_abi_name): New global for getting the results + of -mcall-xxx. + (rs6000_reg_names): New global for holding the normal register names. + (alt_reg_names): Alternate register names for -mregnames. + (rs6000_override_options): If -mregnames, copy alt_reg_names into + rs6000_reg_names. + (input_operand): Recognize ABI_SOLARIS. + (small_data_operand, init_cumulative_args): Likewise. + (function_arg{,_boundary,_advance,_partial_nregs}): Likewise. + (function_arg_pass_by_reference, setup_incoming_varargs): Likewise. + ({rs6000,debug}_stack_info, output_{prolog,epilog}): Likewise. + (print_operand): %$ prints '.' on Solaris, '$' elsewhere. + (print_operand{,_address}): If not eabi, use @sdarel for small + data references. + (rs6000_stack_info): Only emit __eabi call if TARGET_EABI. + + * rs6000.h (*_SPECS): Move the System V specs to svr4.h. + (ABI_SOLARIS): New ABI, mostly like System V. + (EXTRA_CONSTRAINT): Use ABI_SOLARIS like ABI_V4. + (RETURN_ADDRESS_OFFSET, (LEGITIMATE_SMALL_DATA_P): Likewise. + (RETURN_IN_MEMORY): On Solaris, small structures are returned in regs. + (REGISTER_NAMES): Use rs6000_reg_names array, instead of string + literals. + (DEBUG_REGISTER_NAMES): Define. + (ADDITIONAL_REGISTER_NAMES): Add sp, toc aliases. + (PRINT_OPERAND_PUNCT_VALID_P): Recognize $ as a punctuation char. + + * rs6000.md (got & call patterns): Use ABI_SOLARIS to mean the + same as ABI_V4. + (branch patterns): Use %$ for the current location, not just $. + + * va-ppc.h: Add Solaris support. + +Tue Apr 23 20:02:13 1996 Doug Evans + + * sparc.c (output_function_prologue): In -mbroken-saverestore + case, %sp = %fp - size. + * sparc/t-splet (TARGET_LIBGCC2_CFLAGS): Delete. + * sparc.md (isa attribute): Add sparclet. + (*smacsi,*smacdi,*umacdi): Use match_operand, not match_dup + for third arg. + (*mulsidi3_sp32,const_mulsidi3,*umulsidi3_sp32,const_umulsidi3): Use + smuld,umuld for sparclet. + +Tue Apr 23 16:28:28 1996 Michael Meissner + + * m68k/m68kemb.h: Add {LINK,STARTFILE,LIB,SUBTARGET}_SPEC, so + gcc will use libgloss for supported target boards {idp,mvme,bcc}. + +Tue Apr 23 16:00:28 1996 Per Bothner + + * expr.c (store_constructor): Fix test for missing array elements. + +Tue Apr 23 11:21:09 1996 Stephen L Moshier (moshier@world.std.com) + + * i386/sco5.h (BSS_SECTION_ASM_OP): Use `data' directive. + (ASM_OUTPUT_ALIGNED_LOCAL): Generate an `lcomm' directive. + (TARGET_DEFAULT): Include TARGET_IEEE_FP. + (CPP_PREDEFINES): Include Di386. + +Mon Apr 22 12:00:46 1996 David Edelsohn + + * rs6000.h (BIGGEST_FIELD_ALIGNMENT): Delete. + (ADJUST_FIELD_ALIGN, ROUND_TYPE_ALIGN): Define. + * sysv4.h (BIGGEST_FIELD_ALIGNMENT): Delete. + (ADJUST_FIELD_ALIGN, ROUND_TYPE_ALIGN): Undefine. + * win-nt.h (ADJUST_FIELD_ALIGN, ROUND_TYPE_ALIGN): Undefine. + +Sun Apr 21 17:52:36 1996 Jim Wilson + + * m68k/coff.h (ASM_OUTPUT_SECTION): Test DECL before + dereferencing it. + + * cse.c (cse_process_notes): Handle SUBREG like ZERO_EXTEND. + +Sun Apr 21 12:57:12 1996 Doug Evans + + * arm/aout.h (ASM_OUTPUT_MI_THUNK): Define. + +Sun Apr 21 09:50:09 1996 Stephen L Moshier (moshier@world.std.com) + + * choose-temp.c: Include sys/types.h before sys/file.h for sco3.2v5. + +Sun Apr 21 08:42:13 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * alpha.c (check_float_value): Cast args of bcopy to avoid warnings. + +Sat Apr 20 21:22:21 1996 David Edelsohn + + * stor-layout.c (layout_record): Use ADJUST_FIELD_ALIGN to modify + alignment of fields within records. + +Sat Apr 20 19:55:33 1996 Niels Moller + + * c-parse.in (typespec): Made equivalent + to (id ). + (non_empty_protocolrefs): New nonterminal. + +Sat Apr 20 08:34:02 1996 J"orn Rennecke (amylaar@meolyon.hanse.de) + + * stmt.c (check_for_full_enumeration_handling): Call case_tree2list + before checking for case expressions not corresponding to enumerators. + (mark_seen_cases): If SPARSENESS == 2, exploit AVL order. + Else, convert tree to list. + Set xlo to -1 if SPARSENESS == 1 search failed. + (expand_end_case): Avoid calling case_tree2list on list. + +Fri Apr 19 16:54:57 1996 Michael Meissner + + * rs6000/win-nt.h (BIGGEST_FIELD_ALIGNMENT): Set to 64, not + 32 that AIX uses. + +Fri Apr 19 16:40:38 1996 Stan Cox + + * i386.md (movqi): Handle QImode values in %si and %di. + +Thu Apr 18 20:56:56 1996 Jim Wilson + + * sh.md (lshrsi3): Change gen_ashlsi3_d to gen_lshrsi3_d. + +Thu Apr 18 15:49:28 1996 Per Bothner + + * sparc.h (ASM_OUTPUT_MI_THUNK): Define. + +Thu Apr 18 15:19:26 1996 Jeffrey A. Law + + * h8300.md: Remove "type" attribute from all patterns except those + which have varying length branches. Eliminate obsolete "type" + attributes. Add "length" and "cc" attributes to insns without them; + fix some length computations. Remove patterns which are commented out. + + * h8300.md (zero extension expanders and insns): Simplify, fix various + length problems, provide optimized versions for the h8300 and h8300h. + (sign extension expanders and insns): Likewise. Make them + nearly identical to zero_extension patterns and insns. + +Wed Apr 17 18:50:16 1996 Jeffrey A. Law + + * pa.h (SELECT_SECTION): Define. Never place a something + into the read-only data section if it requires a reloc. + + * pa.md (rotlsi3): Delete unnecessary and incorrect pattern. + +Wed Apr 17 17:15:40 1996 Michael Meissner + + * rs6000.md (movdi): Never FAIL, even if operand[1] is not a + general operand, due to being in volatile memory. + +Wed Apr 17 15:20:10 1996 Brendan Kehoe + + * c-lex.c (check_newline): Rewrite to use tokens. + (handle_sysv_pragma): Take a token instead of a character. + * i960.c (process_pragma): Take the IDENTIFIER_POINTER tree + node instead of a character. + * sh.c (handle_pragma): Likewise. + * config/nextstep.c (handle_pragma): Likewise. + * h8300.c (handle_pragma): Likewise. + * i960.h (HANDLE_PRAGMA): Expect/pass 2nd arg of NODE, not CH. + * sh.h (HANDLE_PRAGMA): Likewise. + * config/nextstep.h (HANDLE_PRAGMA): Likewise. + * h8300.h (HANDLE_PRAGMA): Likewise. + +Wed Apr 17 14:28:43 1996 Doug Evans + + * choose-temp.c: Don't include sys/file.h ifdef NO_SYS_FILE_H. + #include . + (choose_temp_base): Make tmp,usrtmp, static locals. + +Wed Apr 17 08:41:02 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * alpha.c (alpha_emit_conditional_move): Fix some bugs in previous + change and do some cleanup. + +Tue Apr 16 18:53:05 1996 Jim Wilson + + * reload.c (push_reload): Add extra reload for inside of SUBREG if + it is CONSTANT_P. + + * expr.c (do_store_flag): Rewrite last change to avoid compiler + warnings. + + * reload.c (push_reload): When reuse an old reload, set the modes + to be the larger of the old and new modes. + + * i960/t-960bare (xp-bit.c): Fix typo in source file name. + +Tue Apr 16 18:09:16 1996 Jeffrey A. Law + + * h8300.md (andhi3): If 2nd operand is a CONST_INT that meets 'J' + constraint, then only two bytes are needed for this insn. Improve + code generated for the h8300h when both operands are registers. + (iorhi3, xorhi3): Likewise. Rework to be nearly identical to andhi3. + (andsi3): If 2nd operand is a CONST_INT that meets the 'J' + constraint, then only two bytes are need for this insn. + Improve code generated for the h8300h regardless of the + type of the 2nd operand. Make this pattern work on the h8300 too. + (iorsi3, xorsi3): Likewise. Rework to be nearly identical to andsi3. + (iorqi3_internal): Make this pattern look more like andqi3_internal. + (one_cmplhi2, one_cmplsi2): Fix length computation for H8300H. + +Tue Apr 16 17:43:25 1996 J"orn Rennecke (amylaar@meolyon.hanse.de) + + * i386.md (addsidi3_2): Handle non-MEM overlap case. + +Tue Apr 16 16:59:49 1996 Richard Henderson + + * function.c (expand_function_end): Allow TRAMPOLINE_TEMPLATE + to be omitted on systems for which it is not cost effective. + * varasm.c (assemble_trampoline_template): No such function + if no TRAMPOLINE_TEMPLATE. + * m68k.h: Greatly simplify the run-time trampoline code: + (TRAMPOLINE_TEMPLATE, TRANSFER_FROM_TRAMPOLINE): Delete define. + (TRAMPOLINE_SIZE, INITIALIZE_TRAMPOLINE): Changed. + (TRAMPOLINE_ALIGN): No point aligning to cache line. + (FINISH_INIT_TRAMPOLINE): New define. + * m68k/next.h: Instead of redefining INITIALIZE_TRAMPOLINE, + make use of the new FINISH_INIT_TRAMPOLINE. + * m68k/{m68k.h,next.h,aux.h} (FINISH_INIT_TRAMPOLINE): + Rename to FINALIZE_TRAMPOLINE. + * m68k/{linux.h,m68kv4.h}: Override trampoline macros. + +Tue Apr 16 16:02:50 1996 David Edelsohn + + * combine.c (make_field_assignment): Allow XOR in final case. + +Tue Apr 16 11:33:53 1996 J.T. Conklin + + * m68k.h (TARGET_SWITCHES): Don't remove MASK_68060 with -msoft-float. + + * m68k.h (MULL_COST, MULW_COST, RTX_COSTS): Add costs for TARGET_68060. + * m68k.md (ashlsi_16, lshrsi_16): Disable pattern for TARGET_68060; + this special case is not faster for that cpu. + +Tue Apr 16 10:54:55 1996 Eliot Dresselhaus + + * alpha.c (alpha_emit_conditional_move): New function. + * alpha.h (alpha_emit_conditional_move): Declare it. + * alpha.md (cmov* define_expands): Use it. + +Tue Apr 16 09:06:17 1996 Andreas Schwab + + * function.h (struct function): New field returns_pointer. + * function.c (push_function_context_{to,from}): Save and restore + current_function_returns_pointer. + + * config/svr4.h (ENDFILE_SPEC): Add missing `%s'. + + * configure (m68k-*-linux*aout*): Set tmake_file to m68k/t-linux-aout. + (m68k-*-linux*): Set extra_parts. + * m68k/t-linux (INSTALL_ASSERT_H): New definition. + (CRTSTUFF_T_CFLAGS_S, TARGET_LIBGCC2_CFLAGS): New definitions. + * m68k/t-linux-aout: New file. + * m68k/linux.h (LIB_SPEC): Deleted. + (BSS_SECTION_ASM_OP, ASM_OUTPUT_ALIGNED_BSS): Define. + + * m68k.h (TRAMPOLINE_ALIGNMENT): Specify alignment in bits, not bytes. + +Tue Apr 16 08:53:17 1996 Philippe De Muyter + + * final.c (final_scan_insn): Allow removal of redundant test and + compare instructions that use clobbers. + +Tue Apr 16 06:22:00 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * c-decl.c (clear_limbo_values): New function. + (pushdecl): Call it for function body blocks. + + * objc/thr-decosf1.c (_objc_thread_id): Correct return type from + int to _objc_thread_id. + + * expr.c (expand_builtin, case BUILT_IN_LONGJMP): Make a decl + for __dummy, so we can call make_function_rtl on it. + + * expr.c (expand_assignment): Don't pre-evaluate RHS if a CALL_EXPR + with a variable-size return. + +Mon Apr 15 17:38:45 1996 Ian Lance Taylor + + * fixincludes: Fix undefined VOIDFUNCPTR in VxWorks 5.2 . + +Mon Apr 15 15:12:16 1996 Jim Wilson + + * expr.c (do_store_flag): Before calling exact_log2, remove any + sign extension bits. + + * reload1.c (emit_reload_insns): Call reload_reg_reaches_end_p for + every reg of multi-reg spill register. Invalidate old info for multi + reg spill registers when only part survives to the end. + +Mon Apr 15 14:49:12 1996 Mike Stump + + * function.c (preserve_temp_slots): Only preserve temporaries that + happen to be at the current level. + +Mon Apr 15 14:08:12 1996 Doug Evans + + * gansidecl.h: New file. + * choose-temp.c: New file. + * Makefile.in (xgcc): Depend on and link in choose-temp.o. + (collect2): Likewise. + (choose-temp.o): Add rule for. + * collect2.c: #include "gansidecl.h". + (const,PROTO): Delete. + (P_tmpdir): Delete. + (choose_temp_base): Declare as extern, delete internal copy. + (main): Update call to choose_temp_base. + * cpphash.c: #include "gansidecl.h". + (NULL,const,volatile): Delete. + * demangle.h: #include "gansidecl.h". + (PROTO,PTR,const): Delete. + * expr.h (const): Delete. + * fix-header.c: #include "gansidecl.h". + (const): Delete. + * gcc.c: #include "gansidecl.h". + (PROTO,VPROTO,PVPROTO,VPROTO,VA_START,NULL): Delete. + (GENERIC_PTR,NULL_PTR,P_tmpdir): Delete. + (choose_temp_base): Declare as extern, delete internal copy. + (concat): Rewrite to take a variable number of arguments. + (choose_temp_base_try,concat[346]): Delete. + (translate_options,set_spec,process_command,do_spec_1, + is_directory,main): Always use concat, not concat[346]. Pass + NULL_PTR as trailing arg to concat. + * genattr.c (main): Delete printing of "#define PROTO". + * machmode.h: #include "gansidecl.h". + (PROTO): Delete. + (HAVE_MACHINE_MODES): Move definition to standard place. + * recog.h: #include "gansidecl.h". + (PROTO,const): Delete. + * rtl.h: #include "gansidecl.h". + (PROTO,VPROTO,PVPROTO,VPROTO,VA_START,STDIO_PROTO): Delete. + (NULL,GENERIC_PTR,NULL_PTR): Delete. + * tree.h: Likewise. + +Mon Apr 15 08:49:20 1996 Tom May (ftom@netcom.com) + + * cse.c (invalidate_skipped_set): Ignore CLOBBER after calling + note_mem_written, not before. + +Mon Apr 15 08:22:03 1996 Philippe De Muyter + + * m68k.md (tstdi): Optimized for "d" case. + (movqi): Allow moving "i" into "a". + (zero_extendsidi2): Alternatives merged. + (extendplussidi): Fixed when operands 0 and 1 share a register. + (adddi_sexthishl32): Constraints reordered for better reload. + (adddi3,subdi_sexthishl32,subdi3,negdi2): Likewise. + (ashldi_sexthi): Accept "m" as operand 0. + (ashldi_const32): Alternatives merged. + (ashift patterns): Output "lsl" instead of "asl". + (beq0_di): If condition codes already set, output only branch insn. + (bne0_di,bge0_di,blt0_di): Likewise. + * m68k.c (notice_update_cc, case ASHIFT{,RT}, LSHIFTRT, ROTATE{,RT}): + Don't set CC_NO_OVERFLOW. + * m68k.h (TARGET_SWITCHES): Fix typo in "c68000" entry. + +Mon Apr 15 08:06:17 1996 Stephen L Moshier (moshier@world.std.com) + + * real.c (eadd1): Check for overflow on X plus X. + +Mon Apr 15 08:02:24 1996 J.T. Conklin + + * i386/netbsd.h (HAVE_SYSV_PRAGMA): Removed definition. + * config/netbsd.h (HAVE_SYSV_PRAGMA): Define. + (SET_ASM_OP): Define. + +Mon Apr 15 07:28:54 1996 Fila Kolodny + + * configure: Add definition for host= into Makefile. + * build-make (CC): Pass -b $(host), not target. + +Mon Apr 15 05:12:39 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (bc_expand_increment): Change declaration to return void. + + * toplev.c (max_label_num_after_reload): New variable. + (rest_of_compilation): Set it. + * reorg.c (find_dead_or_set_registers): Only kill spill regs after + label made before jump2. + + * combine.c (expand_field_assignment): Take SUBREG_WORD into + account when have STRICT_LOW_PART. + (make_extraction): Make a STRICT_LOW_PART at any low-order word. + +Mon Apr 15 03:43:11 1996 Jeffrey A. Law + + * flags.h (flag_function_sections): Declare. + * toplev.c (flag_function_sections): Define. + (compile_file): Add warnings when -ffunction-sections is + used with -g, or profiling. Disable -ffunction-sections + when profiling is used. Add warning when -ffunction-sections + is used on a target that doesn't support it. + * varasm.c (named_section): Make a copy of the section name + in case the original is in temporary storage. + (function_section): Set DECL_SECTION_NAME for each function + if flag_function_sections is on and the target supports it. + * dbxout.c (dbxout_function_end): New function. + (dbxout_function): Call dbxout_function_end if using extensions + and flag_function_sections is on. + * sparc/sysv4.h (ASM_OUTPUT_SECTION_NAME): Prefix a function + section's name with ".text%" when -ffunction-sections. + +Sun Apr 14 19:37:43 1996 Doug Evans + + * toplev.c (main): Delete redundant test for -p used with -fbytecode. + +Sun Apr 14 19:01:59 1996 John F. Carr + + * c-decl.c (finish_enum): Don't crash if no type can represent all + enumeration values. + +Sun Apr 14 18:56:40 1996 J.T. Conklin + + * m68k.md (ftruncdf2): Enable for m68060 systems. + +Sun Apr 14 18:49:30 1996 David L. Reese (david.reese@east.sun.com) + + * fold-const.c (range_test): Don't convert hi_cst or lo_cst + to unsigned when folding signed range tests. + +Sun Apr 14 08:56:27 1996 Stephen L Moshier + + * real.h (ereal_from_{int,uint}): Add new arg, MODE. + (REAL_VALUE_FROM{,_UNSIGNED}_INT): New arg, MODE. + * real.c (ereal_from_{int,uint}): New arg, MODE. + * cse.c (simplify_unary_operation): Add new arg to REAL_VALUE_FROM_INT. + * fold-const.c (fold_convert): Likewise. + * tree.c (real_value_from_int_cst): New arg, TYPE. + Pass mode to REAL_VALUE_FROM_INT. + (build_real_from_int_cst): Properly deal with truncation. + +Sun Apr 14 08:21:29 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * combine.c (try_combine): When substituting in output of I2, + ensure dest isn't clobbered in I2. + + * combine.c (combine_instructions): In initial scan of insns, + handle a REG_INC note's affect on sign bit copies and nonzero bits. + (set_nonzero_bits_and_sign_copies): Treat a zero SET arg as a CLOBBER. + +Sun Apr 14 07:52:28 1996 Manor Askenazi + + * objc/encoding.c (objc_skip_typespec): Don't abort for _C_UNDEF. + +Sat Apr 13 20:35:36 1996 Richard Henderson (richard@atheist.tamu.edu) + + * configure (m68k-apple-aux*): Rework to take advantange + of list of tm.h files and support all four gas/gld options. + * m68k/auxas.h, m68k/auxgas.h, m68k/auxgld.h, m68k/auxld.h: New files. + * m68k/auxstd.h, m68k/auxgnu.h: Deleted. + +Sat Apr 13 20:18:11 1996 Stephen L Moshier + + * alpha.c (check_float_value): New function. + * alpha.h (CHECK_FLOAT_VALUE): Define. + (ASM_OUTPUT_FLOAT): Print the value in hex. + +Sat Apr 13 15:08:45 1996 Doug Evans + + * configure: New target arm{,el}-*-coff*. + (cpu_default): Sort alphabetically. + * arm/coff.h: New file. + * arm/t-bare: New file. + * arm/arm.c (use_return_insn): Don't use return for naked functions. + (arm_valid_machine_decl_attribute): New function. + (arm_naked_function_p): New function. + (output_func_prologue): Naked functions don't have prologues. + (arm_expand_prologue): Likewise. + (output_func_epilogue): Likewise with epilogues. + +Sat Apr 13 11:31:32 1996 Jeffrey A. Law + + * h8300.c (adds_subs_operand): Fix thinko in last change. + + * h8300.md (subhi3): Turn into a define_expand. + (subhi3 using adds_subs): New pattern. + (H8300 subhi): Derived from old subhi pattern. Simplified. + (H8300H subhi): Likewise. + (subsi using adds_subs): New pattern. Only used on H8300H. + (subsi_h8300): Allow "a" registers as destination. + (subsi_h8300h): Allow "a" registers as destination. Simplify. + + * h8300.md (bcs_qiqi, bcs_hihi, bs_hiqi): Fix thinkos + in last change. + +Sat Apr 13 08:59:48 1996 Fila Kolodny + + * i370/mvs.h (ASM_DECLARE_FUNCTION_NAME): Don't write anything to + asm file, because everything is handled in FUNCTION_PROLOGUE. + +Sat Apr 13 07:55:38 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * alpha.c (alpha_emit_set_const_1): Renamed from + alpha_emit_set_const and static. + Remove change of Nov 26; again use normal mechanism for SImode. + (alpha_emit_set_const): New function. + +Fri Apr 12 18:19:39 1996 Jeffrey A. Law + + * h8300.c (adds_subs_operand, output_adds_subs): New functions. + * h8300.md (addhi3): Turn into a define_expand. + (addhi3 using adds_subs): New pattern. + (H8300 addhi): Derived from old addhi pattern. Simplified. + (H8300H addhi): Likewise. + (addsi using adds_subs): New pattern. Only used on H8300H. + (addsi_h8300): Allow "a" registers as destination. + (addsi_h8300h): Simplify. Allow "a" registers as destination. + + * h8300.md (bcs): New attribute type. + (default_length): Compute correct length for bcs insns. + (bcs_qiqi, bcs_hihi, bs_hiqi): Use new type and update + to account for correct length computation. + + * h8300.md (movhi_internal): Demand at least one operand to be reg. + (movsi_h8300{{,h}): Optimize loading certain constants. + + * h8300.h (NO_FUNCTION_CSE): Comment out. + (FUNCTION_ARG_REGNO_P): Properly define for TARGET_QUICKCALL. + (RETURN_IN_MEMORY): Don't return small structs in regs. + + * h8300.c (const_costs): -4 and 4 are cheap on the h8300h. + (notice_update_cc): Remove references to "value2" field. + + * h8300.c (dosize): Remove unused "fped" argument. All callers + changed. Handle add/sub of 5-8 bytes efficiently on the h8300h. + + * h8300.c (print_operand): Handle new 'R' case for accessing + the 8-bit area. Make code for 'Y' fall into code for 'R' when + operand is not a register. Update some comments. + (h8300_tiny_data_p): New function. + (h8300_valid_machine_decl_attribute): Handle "tiny_data" attribute. + * h8300.h (OK_FOR_U): Handle memory references into 8-bit area. + (ENCODE_SECTION_INFO): Mark SYMBOL_REFs which refer to 8-bit area. + * h8300.md (many patterns): Use 'R' rather than 'X' for + operands that may be memory accesses into the 8-bit area. + (btst pattern): New pattern to set the cc0 (zbit) based on + data in the 8-bit area. + + * h8300.md (one_cmplsi2): Fix length computation for h8300h. + +Fri Apr 12 14:34:39 1996 Doug Evans + + * arm.md (*ldmsi,*stmsi): Use (mem (match_operand ...)) + to avoid using indirect_operand (reload problems). + * arm/semi.h (CPP_PREDEFINES): Define __semi__ instead of semi. + * arm/aout.h (ASM_GENERATE_INTERNAL_LABEL): Use LOCAL_LABEL_PREFIX. + (ASM_OUTPUT_ADDR_{VEC,DIFF_ELT}): Likewise. + +Fri Apr 12 09:43:30 1996 Jason Merrill + + * dbxout.c (dbxout_typedefs): Don't emit incomplete types yet. + (dbxout_symbol): Use DECL_ARTIFICIAL to recognize C++ implicit + typedefs. + +Thu Apr 11 21:56:26 1996 Doug Evans + + * i386/t-winnt (winnt.o): Rewrite based on .c.o rule. + (oldnames.o,spawnv.o): Add rules for. + +Thu Apr 11 07:25:06 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * calls.c (expand_call): In inlining case, if BEFORE_CALLS is + zero, start looking at first insn. + + * expr.c (preexpand_calls, case CALL_EXPR): Rework to properly + avoid expanding functions returning variable size objects. + + * integrate.c (expand_inline_function): When comparing types + of formal and actual, use TYPE_MAIN_VARIANT. + +Thu Apr 11 00:48:29 1996 Jeffrey A. Law + + * h8300/lib1funcs.asm (modnorm): New function(s). Like divnorm, + but gets the sign bit right for modulo operations. + (__modhi3, modsi3): Use modnorm. + + * h8300.c (dosize): On h8300h, do 4 byte adjusts using adds and subs. + * h8300.h (LONG_LONG_TYPE_SIZE): Always make this 32bits. + Reverses change from Apr 2, 1996. + +Wed Apr 10 18:39:52 1996 Doug Evans + + * sparc.h (ASM_OUTPUT_INTERNAL_LABELREF): Delete. + (FUNCTION_PROFILER): Use ASM_GENERATE_INTERNAL_LABEL instead. + + * sparc.c (sparc_override_options): 90c701 renamed to tsc701. + (eligible_for_epilogue_delay_slot): Don't allow anything if + -mbroken-saverestore. + (output_function_prologue): Only use trivial save's if + -mbroken-saverestore. + * sparc.h (CPP_SPEC): Handle -mcpu={sparclet,tsc701}. + (ASM_SPEC): Likewise. + ({MASK,TARGET}_BROKEN_SAVERESTORE): Define. + (enum processor_type): 90C701 renamed to TSC701. + * sparc.md (attr cpu): 90c701 renamed to tsc701. + * sparc/splet.h (SUBTARGET_SWITCHES): Recognize -mbroken-saverestore. + +Wed Apr 10 17:56:02 1996 Stan Cox + + * m88k/dgux.h (EXTRA_SPECS): Define. + (ASM_SPEC,CPP_SPEC,STARTFILE_SPEC): Use EXTRA_SPECS. + * m88k/dguxbcs.h (ASM_SPEC,CPP_SPEC,STARTFILE_SPEC): Use EXTRA_SPECS. + * m88k/m88k.c (output_ascii) Output literal HT. + +Wed Apr 10 17:28:37 1996 James Carlson (carlson@xylogics.com) + + * configure: Work around AIX bug when defining SUBDIRS. + +Wed Apr 10 17:22:42 1996 Paul Eggert + + * cexp.y (parse_number): Don't reject long long constants unless + pedantic. + +Wed Apr 10 17:19:56 1996 Stephen L. Moshier (moshier@world.std.com) + + * real.c (e64toe): Properly distinguish between NaN and infinity + bit patterns for real-words-big-endian targets. + +Wed Apr 10 17:17:26 1996 Richard Earnshaw (rearnsha@armltd.co.uk) + + * real.c (endian): Add two explicit casts. + (e64toe): Support ARM extended precision fp format. + Check negative infinities properly for NaNs. + (toe64): Support ARM extended precision fp format. + +Tue Apr 9 12:53:31 1996 Doug Evans + + * i386/gas.h (ASM_OUTPUT_ALIGN): Define and use .balign. + +Tue Apr 9 12:48:45 1996 Stephen L Moshier (moshier@world.std.com) + + * sparc.c (fp_zero_operand): Exclude -0.0. + +Tue Apr 9 07:11:24 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * alpha.c: Fix typo in last change. + + * tree.c (substitute_in_expr): Don't return new expression if + nothing changed. + (substitute_in_type): Deleted, not used. + * tree.h (substitute_in_type): Delete declaration. + +Mon Apr 8 16:30:18 1996 Jeffrey A. Law + + * flow.c (find_auto_inc): Also make sure there aren't + any sets of the incremented register between the memory + reference and increment insn. + +Mon Apr 8 15:41:14 1996 John Polstra (jdp@polstra.com) + + * configure (i[3456]86-*-freebsdelf*): New target. + * i386/freebsd-elf.h: New file. + * i386/x-freebsd (USER_H): New define; to null. + +Mon Apr 8 14:44:41 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * c-decl.c (finish_function): Always warn if main doesn't return int. + +Mon Apr 8 13:01:37 1996 Michael Meissner + + * rs6000.c (got_operand): New function, returns true if the + operand can go in V.4's GOT. + (rs6000_pic_register): New variable. + (output_epilog): Reset rs6000_pic_register. + + * rs6000.h (rs6000_pic_register, got_operand, flag_pic): Add decls. + (PREDICATE_CODES): Add got_operand. + + * rs6000.md (movsi): Add support for V.4's -fpic and -FPIC. + (init_v4_pic): Initialize the V4 pic register if needed. + (call patterns): If -fpic/-fPIC, call function with @plt suffix. + + * t-eabigas (MULTILIB_DIRNAMES): Remove errant pic directory. + + * rs6000.c (output_prolog): Correctly store & restore the + arguments to main in their correct save location, when calling the + start function. + +Mon Apr 8 13:01:37 1996 David Reese + + * rs6000.c (print_operand): Use reg_names to print registers. + +Fri Apr 5 00:40:19 1996 Jeffrey A. Law + + * h8300.c (h8300_valid_machine_decl_attribute): Use underscores, + not dashes in attributes. + (h8300_funcvec_function_p): Corresponding changes. + (h8300_interrupt_function_p): Likewise. + + * pa.h (INIT_CUMULATIVE_INCOMING_ARGS): Initialize "indirect" + field to zero. + +Thu Apr 4 12:52:11 1996 Jim Wilson + + * loop.c (combine_givs): Use new macro GIV_SORT_CRITERION. + New variable giv_array. Loop over giv_array instead of following + next_iv links. + (giv_sort): New function. + * sh.h (GIV_SORT_CRITERION): Define. + + * c-typeck.c (push_init_level): When output alignment for structure + field, add check to verify it is the next field to be output. + +Thu Apr 4 12:19:26 1996 David Mosberger-Tang + + * alpha.c: Don't include stamp.h for Linux-based GNU systems. + +Thu Apr 4 12:17:08 1996 Richardg Kenner (kenner@vlsi1.ultra.nyu.edu) + + * objc/Makefile: Rename thread* to thr*. + * objc/thread.c: Rename thread-* to thr-*. + * objc/thr-decosf1.c: Renamed from thread-decosf1.c + * objc/thr-irix.c: Renamed from thread-irix.c. + * objc/thr-single.c: Renamed from thread-single.c. + * objc/thr-solarius.c: Renamed from thread-solaris.c. + * objc/thr-win32.c: Renamed from thread-win32.c. + * objc/objc-api.h: Include thr.h, not thread.h. + * objc/runtime.h, objc/sarray.h: Likewise. + + * i386.md (ashldi3_const_int): Don't recognize if won't match + constraint of operand 2. + +Thu Apr 4 11:40:55 1996 Michael Meissner + + * config/fp-bit.c (EXTENDED_FLOAT_STUBS): If EXTENDED_FLOAT_STUBS + is defined, define all of the XF/TF functions that might be + generated that we don't have code for yet. + + * i960/t-(vxworks960,960bare): (LIB2FUNCS_EXTRA): Make and + compile xp-bits.c that defines EXTENDED_FLOAT_STUBS. + + From: steve chamberlain + * i386/x-cygwin32 (LANGUAGES): Delete. + * i386/xm-cygwin32.h (EXECUTABLE_SUFFIX): Set to .exe. + * rs6000/xm-cygwin32.h (EXECUTABLE_SUFFIX): Set to .exe. + +Wed Apr 3 14:10:16 1996 Jim Wilson + + * expr.c (emit_push_insn): Clobber register only if it is non-zero. + +Wed Apr 3 11:31:55 1996 Jeffrey A. Law + + * h8300.h (h8300_funcvec_function_p): Declaration moved here. + * h8300.c (h8300_funcvec_function_p): Declaration removed from here. + * h8300.md (tstqi): Tweak to work like other tstXX patterns. + (cmphi): Turn into a define_expand. Add two anonymous + matterns to match the output of the cmphi expander. + (cmpsi): Accept constants as the second input operand. + +Tue Apr 2 13:52:30 1996 Jeffrey A. Law + + * h8300.md (movqi_internal): Remove useless alternative(s). Fix + lengths and simplify by reordering remaining alternatives. + (movstrictqi, movhi_internal, movstricthi): Likewise. + (movsi_h8300h, movsf_h8300h): Likewise. + + * h8300/h8300.c (extra_pop): Remove unused variable. + (current_function_anonymous_args): Likewise. + (function_prologue): Remove incorrect varargs/stdarg + related code. + (function_epilogue): Likewise. + (function_arg): Never pass unnamed arguments in registers. + * h8300.h (LONG_LONG_TYPE_SIZE): Use 64bits when ints are 32bits. + (SETUP_INCOMING_VARARGS): Remove definition. + +Mon Apr 1 16:59:48 1996 Ian Lance Taylor + + * fixincludes: Fix signal prototype on SunOS to avoid pedantic C++ + error. + +Mon Apr 1 16:16:34 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + * expr.c (get_inner_reference): When finding mode to access bitfield + that ends up properly aligned, use mode class of its type unless + type's mode was BLKmode. + +Mon Apr 1 13:45:30 1996 Jeffrey A. Law + + * h8300.c (interrupt_handler): Renamed from pragma_interrupt. + All references changed. + (function_prologue): Set interrupt_handler if the current + function has the "interrrupt-handler" attribute. + (small_call_insn_operand): New function. + (h8300_interrrupt_function_p): New function. + (h8300_funcvec_function_p): New function. + (h8300_valid_machine_decl_attribute): New function. + * h8300.h (VALID_MACHINE_DECL_ATTRIBUTE): Define. + * h8300.md (call insns): Handle calls through the + function vector. Indirect calls and calls through + the function vector have a length of two bytes. + +See ChangeLog.10 for earlier changes. + +Use a consistent time stamp format in ChangeLog entries. +Not everyone has Emacs 20 yet, so stick with Emacs 19 format for now. + +Local Variables: +add-log-time-format: current-time-string +End: diff --git a/gcc_arm/FSFChangeLog.12 b/gcc_arm/FSFChangeLog.12 new file mode 100755 index 0000000..ecb2919 --- /dev/null +++ b/gcc_arm/FSFChangeLog.12 @@ -0,0 +1,1244 @@ +Sat May 2 20:39:22 1998 Richard Kenner + + * fold-const.c (fold): When commutting COND_EXPR and binary operation, + avoid quadratic behavior if have nested COND_EXPRs. + +Tue Apr 28 17:30:05 1998 Richard Kenner + + * mips.h (HOST_WIDE_INT): Define if not already. + (compute_frame_size, mips_debugger_offset): Return HOST_WIDE_INT. + (DEBUGGER_{AUTO,ARG}_OFFSET): Cast second arg to HOST_WIDE_INT. + * /mips.c (mips_debugger_offset): Now returns HOST_WIDE_INT. + Likewise for internal variable frame_size. + + * final.c (alter_subreg): Make new SUBREG if reload replacement + scheduled inside it. + + * dwarf2out.c (add_bound_info, case SAVE_EXPR): Pass + SAVE_EXPR_RTL address through fix_lexical_addr. + +Mon Apr 27 18:57:18 1998 Jim Wilson + + * mips/sni-svr4.h (CPP_PREDEFINES): Add -Dsinix and -DSNI. + +Mon Apr 20 14:48:29 1998 Michael Meissner + + * rs6000.md (mov{sf,df} define_splits): When splitting move of + constant to int reg, don't split insns that do simple AND and OR + operations; just split each word and let normal movsi define split + handle it further. + +Sun Apr 19 20:21:19 1998 Michael P. Hayes + + * real.h (C4X_FLOAT_FORMAT): New macro. + * real.c (c4xtoe, etoc4x, toc4x): New functions. + +Sun Apr 19 20:17:32 1998 Niklas Hallqvist + + * m68k.c (notice_update_cc): Use modified_in_p to check for update. + +Sun Apr 19 18:48:07 1998 K. Richard Pixley + + * fixincludes: Discard empty C++ comments. + Special case more files with C++ comments nested in C comments. + +Sun Apr 19 18:30:11 1998 Andreas Schwab + + * m68k.md ({add,sub}di3): Optimize for constant operand. + +Sun Apr 19 18:27:11 1998 Alan Modra + + * i386.c (output_387_binary_op): Swap operands when popping if result + is st(0). + +Sun Apr 19 17:58:01 1998 Peter Jeremy + + * expr.c (do_jump_by_parts_equality_rtx): Now public. + * expmed.c (do_cmp_and_jump): New function. + (expand_divmod): Use do_cmp_and_jmp instead of emit_cmp_insn and + emit_jump_insn. + +Sun Apr 19 07:48:37 1998 Richard Kenner + + * c-typeck.c (build_c_cast): Check underlying type when seeing + if discarding const or volatile. + + * c-decl.c (pushdecl): Avoid duplicate warning about implicit redecl. + + * configure.in (stab.h): Check for it. + (i386-*-vsta): Include xm-i386.h too. + * dbxout.c (stab.h): Include based on autoconf results. + * vax/xm-vms.h (NO_STAB_H): Deleted. + * alpha/xm-vms.h, xm-mips.h, i386/xm-mingw32.h, i386/go32.h: Likewise. + * i386/xm-cygwin32.h: Likewise. + * i386/xm-vsta.h (NO_STAB_H): Likewise. + (i386/xm-i386.h): No longer include. + + * mips.c: Cleanups and reformatting throughout. + ({expand,output}_block_move): Use HOST_WIDE_INT for sizes. + (mips_debugger_offset, compute_frame_size): Likewise. + (save_restore_insns, mips_expand_{pro,epi}logue): Likewise. + (siginfo): Deleted. + (override_options): Don't set up to call it; don't call setvbuf. + +Mon Apr 13 06:40:17 1998 Richard Kenner + + * configure.in (sparc-*-vxsim*): Include xm-siglist.h and + define USG and POSIX. + +Sun Apr 12 21:59:27 1998 Jeffrey A. Law + + * calls.c (expand_call): Fix typo in STRICT_ARGUMENT_NAMING. + +Sun Apr 12 21:42:23 1998 D. Karthikeyan + + * m68k.h (TARGET_SWITCHES): Add missing comma. + +Sun Apr 12 21:33:33 1998 Eric Valette + + * configure.in (i[34567]86-*-rtemself*): New configuration. + * i386/rtemself.h: New file. + +Sun Apr 12 21:08:28 1998 Jim Wilson + + * loop.c (loop_optimize): Reset max_uid_for_loop after + find_and_verify_loops call. + (strength_reduce): In auto_inc_opt code, verify v->insn has valid + INSN_LUID. + +Sun Apr 12 20:54:59 1998 Richard Earnshaw (rearnsha@arm.com) + + * configure.in (sparc-*-solaris2*): Add xm-siglist.h to xm_file. + Add USG and POSIX to xm_defines. + +Sun Apr 12 20:47:37 1998 Pat Rankin + + * cccp.c (eprint_string): New function. + (do_elif, do_else, verror): Use it instead of fwrite(,,,stderr). + (error_from_errno, vwarning): Likewise. + ({verror,vwarning,pedwarn}_with_line): Likewise. + (pedwarn_with_file_and_line, print_containing_files): Likewise. + +Sun Apr 12 20:40:44 1998 Richard Henderson + + * configure.in (alpha*-*-linux-gnu*): Add alpha/t-crtbe. + Add crt{begin,end}.o in extra_parts and delete crt{begin,end}S.o.o + * alpha/t-crtbe, alpha/crt{begin,end}.asm: New files. + + * alpha.h (PRINT_OPERAND_PUNCT_VALID_P): Accept '(' for s/sv/svi. + * alpha.c (print_operand): Handle it. + * alpha.md (fix_trunc[ds]fdi2): Use it. Add earlyclobber pattern + for ALPHA_TP_INSN. + +Sun Apr 12 13:09:46 1998 Scott Christley + + * objc/encoding.c (objc_sizeof_type, _C_VOID): New case. + +Sun Apr 12 13:04:55 1998 Nikolay Yatsenko (nikolay@osf.org) + + * configure.in (i[34567]86-*-osf1*): New entry. + * i386/osf1-c[in].asm: New files for OSF/1. + * i386/osf1elf{,gdb}.h, i386/[xt]-osf1elf, i386/xm-osf1elf.h: Likewise. + +Sun Apr 12 10:03:51 1998 Noel Cragg + + * fixincludes: Remove specification of parameters when renaming + functions in Alpha DEC Unix include files. + +Sun Apr 12 07:33:46 1998 Richard Kenner + + * mips.c (large_int): Use HOST_WIDE_INT, not int. + (print_operand): Use HOST_WIDE_INT_PRINT_* macros. + + * toplev.c (main): Sort order of handling of -d letters. + Use `F' instead of `D' for addressof_dump. + + * libgcc2.c (_eh_compat): Deleted. + * Makefile.in (LIB2FUNCS): Delete _eh_compat. + + * configure.in (alpha*-*-linux-gnu*): Don't include alpha/xm-linux.h. + + * c-common.c (check_format_info): Properly test for nested pointers. + + * pa.md (casesi0): Add missing mode for operand 0. + + * function.c (purge_addressof_1, case MEM): If BLKmode, put ADDRESSOF + into stack. + + * c-parse.in (label): Give warning if pedantic and label not integral. + + * c-decl.c (grokdeclarator): Don't warn about return type if in + system header. + + * reload.c (reload_nongroup): New variable. + (push{_secondary,}_reload): Initialize it. + (find_reloads): Compute it. + (debug_reload): Print it. + * reload.h (reload_nongroup): Declare. + * reload1.c (reload): Use reload_nongroup instead of local computation. + Check caller_save_spill_class against any nongroup reloads. + (reloads_conflict): No longer static. + +Sun Apr 12 05:52:18 1998 John David Anglin + + * vax.md (call patterns): Operand 1 is always a CONST_INT. + +Sat Apr 11 16:01:11 1998 Richard Kenner + + * convert.c (convert_to_{pointer,integer,real,complex}): Use switch. + Add missing integer-like types. + Simplify return of zero in error case. + (convert_to_pointer): Remove dubious abort. + (convert_to_integer, case POINTER_TYPE): Make recursive call. + (convert_to_integer, case COND_EXPR): Always convert arms. + * tree.c (type_precision): Deleted. + + * cccp.c (do_warning): Give pedantic warning if -pedantic and not + in system file. + * cpplib.c (do_warning): Likewise. + + * function.c (target_temp_slot_level): Define here. + (push_temp_slots_for_target, {get,set}_target_temp_slot_level): New. + * stmt.c (target_temp_slot_level): Don't define here. + * expr.h (temp_slot_level): New declaration. + +Fri Apr 10 16:35:48 1998 Paul Eggert + + * c-common.c (decl_attributes): Support strftime format checking. + (record_function_format, {check,init_function}_format_info): Likewise. + (enum format_type): New type. + (record_function_format): Now static; takes value of type + enum format_type instead of int. + (time_char_table): New constant. + (struct function_format_info): format_type member renamed from is_scan. + (check_format_info): Use `warning' rather than sprintf followed by + `warning', to avoid mishandling `%' in warnings. + Change a `pedwarn' to `warning'. + * c-tree.h (record_function_format): Remove decl. + +Thu Apr 2 17:34:27 1998 Manfred Hollstein + + * regclass.c (memory_move_secondary_cost): Protect uses of + SECONDARY_{INPUT,OUTPUT}_RELOAD_CLASS with #ifdef tests. + +Thu Apr 2 07:06:57 1998 Andreas Schwab + + * m68k.c (standard_68881_constant_p): Don't use fmovecr on 68060. + +Thu Apr 2 06:19:25 1998 Ken Raeburn + + * Makefile.in (version.c): Put "cvs log" output in build directory. + + * reload.h (MEMORY_MOVE_COST): Define here if not already defined. + (memory_move_secondary_cost): Declare. + * regclass.c (MEMORY_MOVE_COST): Don't define default here. + (memory_move_secondary_cost) [HAVE_SECONDARY_RELOADS]: New function. + (regclass, record_reg_classes, copy_cost, record_address_regs): + Pass register class and direction of move to MEMORY_MOVE_COST. + (top_of_stack) [HAVE_SECONDARY_RELOADS]: New static array. + (init_regs) [HAVE_SECONDARY_RELOADS]: Initialize it. + * reload1.c (MEMORY_MOVE_COST): Don't define default here. + (emit_reload_insns, reload_cse_simplify_set): Pass register class + and direction of move to MEMORY_MOVE_COST. + * 1750a.h (MEMORY_MOVE_COST): Add extra ignored arguments. + * a29k.h, alpha.h, arc.h, arm.h, dsp16xx.h, i386.h, m32r.h: Likewise. + * m88k.h, rs6000.h: Likewise. + * mips.h (MEMORY_MOVE_COST): Likewise. + Add memory_move_secondary_cost result to cpu-specific cost. + +Mon Mar 30 13:56:30 1998 Jim Wilson + + * mips/ultrix.h (SUBTARGET_CPP_SPEC): Define. + +Wed Mar 25 16:09:01 1998 Michael Meissner + + * rs6000.h (FUNCTION_ARG_PADDING): Cast result to be enum direction. + (function_arg_padding): Declare. + + * rs6000.c: Include stdlib.h if we have it. + (function_arg_padding): Change return type to int, cast enum's to int. + + (From Kaveh R. Ghazi ) + * rs6000.c (rs6000_override_options): Change type of `i', `j' and + `ptt_size' from int to size_t. + (rs6000_file_start): Likewise for `i'. + (rs6000_replace_regno): Add default case in enumeration switch. + (output_epilog): Remove unused variable `i'. + (rs6000_longcall_ref): Remove unused variables `len', `p', `reg[12]'. + + * rs6000.h (ADDITIONAL_REGISTER_NAMES): Add missing braces around + initializer. + (get_issue_rate, non_logical_cint_operand): Add prototype. + (rs6000_output_load_toc_table): Likewise. + + * rs6000.md (udivmodsi4): Add explicit braces to avoid ambiguous + `else'. + +Wed Mar 25 02:39:01 1998 Paul Eggert + + * configure.in (i[[34567]]86-*-solaris2*, powerpcle-*-solaris2*, + sparc-*-solaris2*): Use fixinc.svr4 if Solaris 2.0 through 2.4. + +Mon Mar 23 07:27:19 1998 Philippe De Muyter + + * m68k.md (ashldi_const): Allow shift count in range ]32,63]. + (ashldi3): Allow constant shift count in range ]32,63]. + (ashrdi_const, ashrid3, lshrdi_const, lshrdi3): Likewise. + + * m68k.md (zero_extend[qh]idi2, iordi_zext): New patterns. + (zero_extendsidi2): Avoid useless copy. + (iorsi_zexthi_ashl16): Avoid "0" constraint for operand 2. + (iorsi_zext): New name for old unnamed pattern; indentation fixes. + +Mon Mar 23 07:12:05 1998 Richard Kenner + + * final.c (only_leaf_regs_used): If pic_offset_table_rtx used, + make sure it is a permitted register. + +Sun Mar 22 06:57:04 1998 Richard Kenner + + * expmed.c (extract_bit_field): Don't confuse SUBREG_WORD with + endian adjustment in SUBREG case. + Don't abort if can't make SUBREG needed for extv/extzv. + +Sat Mar 21 08:02:17 1998 Richard Gorton + + * alpha.md (zero_extendqi[hsd]i2): Use "and", not "zapnot". + +Sat Mar 21 07:47:04 1998 Richard Kenner + + * unroll.c (verify_addresses): Use validate_replace_rtx. + (find_splittable_givs): If invalid address, show nothing same_insn. + +Fri Mar 20 10:24:12 1998 Philippe De Muyter + + * fold-const.c (fold, case CONVERT_EXPR): Replace sign-extension of + a zero-extended value by a single zero-extension. + +Thu Mar 19 14:59:32 1998 Andrew Pochinsky + + * sparc.h (ASM_OUTPUT_LOOP_ALIGN): Fix error in last change. + +Thu Mar 19 14:48:35 1998 Michael Meissner + + * gcc.c (default_arg): Don't wander off the end of allocated memory. + + * rs6000/sysv4.h (RELATIVE_PREFIX_NOT_LINKDIR): Undef for System V + and EABI. + +Thu Mar 19 06:17:59 1998 Richard Kenner + + * Makefile.in (toplev.o): Depend on Makefile. + +Wed Mar 18 17:40:09 1998 Michael P. Hayes + + * expr.c (convert_move): Add [QH]Imode/P[QH]Imode conversions. + * machmode.def (PQImode, PHImode): New modes. + +Wed Mar 18 17:11:18 1998 Andreas Schwab + + * m68k.md (movsf+1): Optimize moving a CONST_DOUBLE zero. + +Wed Mar 18 17:07:54 1998 Ken Raeburn + + * regclass.c (init_reg_sets): Delete init of reg-move cost tables. + (init_reg_sets_1): Put it here. + +Wed Mar 18 16:43:11 1998 Jim Wilson + + * i960.md (tablejump): Handle flag_pic. + + * profile.c (branch_prob): If see computed goto, call fatal. + + * calls.c (expand_call): Fix typos in n_named_args computation. + +Wed Mar 18 05:54:25 1998 Richard Kenner + + * fold-const.c (operand_equal_for_comparison_p): See if equal + when nop conversions are removed. + + * expr.c (expand_expr, case COND_EXPR): If have conditional move, + don't use ORIGINAL_TARGET unless REG. + + * function.c (fixup_var_refs_insns): Also delete insn storing pseudo + back into arg list. + + * combine.c (gen_binary): Don't make AND that does nothing. + (simplify_comparison, case AND): Commute AND and SUBREG. + * i386.h (CONST_CONSTS, case CONST_INT): One-byte integers are cost 0. + +Mon Mar 16 15:57:17 1998 Geoffrey Keating + + * rs6000.c (small_data_operand): Ensure any address referenced + relative to small data area is inside SDA. + +Sun Mar 15 16:01:19 1998 Andrew Pochinsky + + * sparc.h (ASM_OUTPUT_LOOP_ALIGN): Write nop's. + +Sun Mar 15 15:53:39 1998 Philippe De Muyter + + * libgcc2.c (exit): Don't call __bb_exit_func if HAVE_ATEXIT. + +Sun Mar 15 15:44:41 1998 Paul Eggert + + * cccp.c: Fix bugs relating to NUL in input file name, + e.g. with `#line 2 "x\0y"'. + (PRINTF_PROTO_4): New macro. + (struct {file_buf,definition,if_stack}): New member nominal_fname_len. + (main, expand_to_temp_buffer): Store length of input file names. + (finclude, create_definition, do_line, conditional_skip): Likewise. + (skip_if_group, macroexpand): Likewise. + (make_{definition,undef,assertion}): Likewise. + (special_symbol, do_include): Use stored length of input file names. + (do_define, do_elif, do_else, output_line_directive, verror): Likewise. + (error_from_errno, vwarning, verror_with_line): Likewise. + (vwarning_with_line, pedwarn_with_file_and_line): Likewise. + (print_containing_files): Likewise. + (do_line): Fix off-by-1 problem: 1 too many bytes were being allocated. + (quote_string, pedwarn_with_file_and_line): New arg specifies length. + All callers changed. + +Sun Mar 15 15:38:16 1998 Andreas Schwab + + * c-typeck.c: Collect pending initializers in AVL tree instead of list. + (add_pending_init, pending_init_member): New functions. + (output_init_element): Use them. + (output_pending_init_elements): Rewritten to exploit AVL order. + +Sun Mar 15 05:10:49 1998 Richard Kenner + + * gnu.h (GNU_CPP_PREDEFINES): Deleted; not valid in traditional C. + * {i386,mips}/gnu.h (CPP_PREDEFINES): Don't call GNU_CPP_PREDEFINES. + + * flow.c (insn_dead_p): A CLOBBER of a dead pseudo is dead. + + * alpha.h (REG_ALLOC_ORDER): Put $f1 after other nonsaved. + + * sparc.c (sparc_type_code): Fix error in previous change. + +Sat Mar 14 05:45:21 1998 Richard Kenner + + * i386/xm-aix.h, i386/xm-osf.h (i386/xm-i386.h): Don't include. + (USG): Don't define. + * i386/xm-isc.h (i386/xm-sysv3.h): Don't include. + * i386/xm-sco.h (i386/xm-sysv3.h): Likewise. + (BROKEN_LDEXP, SMALL_ARG_MAX, NO_SYS_SIGLIST): Don't define. + * m68k/xm-3b1.h (m68k/xm-m68k.h): Don't include. + (USG): Don't define. + * m68k/xm-atari.h (m68k/xm-m68kv.h): Don't include. + (HAVE_VPRINTF, FULL_PROTOTYPES): Don't define. + * m68k/xm-crds.h (m68k/xm-m68k.h): Don't include. + (USE_C_ALLOCA, unos, USG): Don't define. + * m68k/xm-mot3300.h (m68k/xm-m68k.h): Don't include. + (USE_C_ALLOCA, NO_SYS_SIGLIST): Don't define. + * m68k/xm-plexus.h (m68k/xm-m68k.h): Don't include. + (USE_C_ALLOCA, USG): Don't define. + * m88k/xm-sysv3.h (m88k/xm-m88k.h): Don't include. + * m68k/xm-next.h (m68k/xm-m68k.h): Don't include. + * ns32k/xm-pc532-min.h (ns32k/xm-ns32k.h): Don't include. + (USG): Don't define. + * rs6000/xm-mach.h: Don't include xm-rs6000.h. + * rs6000/xm-cygwin32.h (rs6000/xm-rs6000.h): Don't include. + (NO_STAB_H): Don't define. + * sparc/xm-linux.h (xm-linux.h): Don't include. + * sparc/xm-sol2.h (sparc/xm-sysv4.h): Don't include. + * a29k/xm-unix.h, alpha/xm-linux.h, arm/xm-linux.h: Deleted. + * arm/xm-netbsd.h, i386/xm-bsd386.h, i386/xm-gnu.h: Deleted. + * i386/xm-linux.h, i386/xm-sun.h, i386/xm-sysv3.h: Deleted. + * i386/xm-winnt.h, m68k/xm-altos3068.h, m68k/xm-amix.h: Deleted. + * m68k/xm-amix.h, m68k/xm-hp320.h, m68k/xm-linux.h: Deleted. + * m68k/xm-m68kv.h, mips/xm-iris5.h, ns32k/xm-genix.h: Deleted. + * sparc/xm-pbd.h, vax/xm-vaxv.h, xm-svr3.h, xm-linux.h: Deleted. + * configure.in: Reflect above changes. + + * xm-siglist.h, xm-alloca.h: New files. + * i386/xm-sysv4.h (i386/xm-i386.h, xm-svr4.h): Don't include. + (USE_C_ALLOCA, SMALL_ARG_MAX): Don't define. + * i386/xm-sco5.h (i386/xm-sysv3.h): Don't include. + (SYS_SIGLIST_DECLARED, USE_C_ALLOCA): Don't define. + * rs6000/xm-sysv4.h, sparc/xm-sysv4.h: Don't include xm-svr4.h. + * xm-svr4.h, i386/xm-dgux.h, mips/xm-news.h, mips/xm-sysv4.h: Deleted. + * configure.in: Reflect above changes. + + * configure.in ({,host_,build_}xm_defines): New variables. + Set to USG instead of including xm-usg.h. + Write #define lines in config.h files from xm_defines vars. + * xm-usg.h: Deleted. + +Fri Mar 13 07:10:59 1998 Richard Kenner + + * calls.c (expand_call): Fix typo in previous change. + + * sparc.c (sparc_type_code): Avoid infinite loop when have + pointer to array of same pointer. + (sparc_type_code, case REAL_TYPE): Process subtypes here too. + + * mips/bsd-4.h, mips/iris3.h, mips/news{4,5}.h: Don't include mips.h. + * mips/news5.h, mips/osfrose.h, mips/svr{3,4}-4.h: Likewise. + * mips/ultrix.h: Likewise. + * mips/cross64.h: Don't include iris6.h. + * mips/ecoff.h: Don't include mips.h or gofast.h. + * mips/elforion.h: Don't include elf64.h. + * mips/iris4.h: Don't include iris3.h. + * mips/iris4loser.h: Don't include iris4.h. + * mips/iris5gas.h: Don't include iris5.h. + * mips/elflorion.h, mips/nws3250v4.h, mips/xm-iris{3,4}.h: Deleted. + * mips/xm-nws3250v4.h, mips/xm-sysv.h: Deleted. + * mips/rtems64.h: Don't include elflorion.h. + * mips/sni-gas.h: Don't include sni-svr4.h. + * mips/svr4-t.h: Don't include svr4-5.h. + * mips/dec-osf1.h: Also include mips.h. + * mips/ecoffl.h, mips/elf.h: Also include mips.h and gofast.h. + * mips/iris5.h: Also include iris3.h and mips.h. + * xm-usg.h: New file. + * mips/xm-iris5.h: Don't include xm-mips.h; don't define USG. + * mips/xm-news.h, mips/xm-sysv4.h: Don't include xm-sysv.h. + * configure.in: Reflect above changes. + +Thu Mar 12 07:18:48 1998 Richard Kenner + + * expr.h (STRICT_ARGUMENT_NAMING): Provide default value of 0. + * calls.c (expand_call): Use value of STRICT_ARGUMENT_NAMING. + * function.c (assign_parm): Likewise. + * mips/abi64.h (STRICT_ARGUMENT_NAMING): Return 0 for ABI_32. + * sparc.h (STRICT_ARGUMENT_NAMING): Only nonzero for V9. + + * calls.c (expand_call, expand_library_call{,_value}, store_one_arg): + Rework handling of REG_PARM_STACK_SPACE to treat return value of + zero as if macro not defined; add new arg to emit_push_insn. + * expr.c (emit_push_insn): New arg, REG_PARM_STACK_SPACE. + * expr.h (emit_push_insn): Likewise. + * mips/abi64.h (REG_PARM_STACK_SPACE): Define. + +Wed Mar 11 06:58:13 1998 Andreas Schwab + + * m68k.h (CONST_OK_FOR_LETTER_P, case 'M'): Correct range check. + +Wed Mar 11 06:15:52 1998 Richard Kenner + + * expr.c (emit_push_insn): Use loop to find movstr patterns + instead of explicit tests. + + * Makefile.in (extraclean): Don't delete install1.texi. + +Tue Mar 10 14:27:51 1998 Richard Kenner + + * combine.c (make_field_assignment): Don't get confused if OTHER + has VOIDmode and don't do anything if DEST is wider than a host word. + + * vax.c (check_float_value): Cast bcopy args to char *. + +Tue Mar 10 13:56:12 1998 Jim Wilson + + * mips/abi64.h (LONG_MAX_SPEC): Check MIPS_ABI_DEFAULT and + TARGET_DEFAULT and define __LONG_MAX__ appropriately. + Add support for -mabi=X, -mlong64, and -mgp{32,64} options. + * mips.c (mips_abi): Change type to int. + * mips.h (enum mips_abi_type): Delete. + (ABI_32, ABI_N32, ABI_64, ABI_EABI): Define as constants. + (mips_abi): Change type to int. + +Mon Mar 2 08:06:58 1998 Richard Kenner + + * Version 2.8.1 released. + + * Makefile.in (mostlyclean): Remove duplicate deletion of temp + files. Delete more stamp files and [df]p-bit.c + (clean): Don't delete stamp files here. + (VERSION_DEP): New variable. + (distdir-finish): Pass a value of null for it. + (version.c): Use it. + Avoid broken pipe with cvs log. + + * objc/Make-lang.in (objc/runtime-info.h): Rename emptyfile to + tmp-runtime and delete at end. + +Sun Mar 1 05:50:25 1998 Richard Kenner + + * tree.c (build_reference_type): Handle obstacks like + build_pointer_type. + + * Makefile.in (tmp-gcc.xtar): Renamed from gcc.xtar. + (gcc.xtar.gz): Deleted; merged with `dist'. + (diff): Create gcc-$(oldversion)-$(version).diff. + (distdir): Depend on distdir-cvs. + (distdir-cvs): New rule. + (distdir-start): Depend on version.c and TAGS. + (TAGS): Use tmp-tags instead of temp. + (dist): Create gcc-$(version).tar.gz. + + * varasm.c (compare_constant_1): Fix typo in previous change. + + * objc/Make-lang.in (objc-distdir): Properly rebuild objc-parse.c. + +Sat Feb 28 16:58:08 1998 Tristan Gingold + + * stmt.c (expand_decl): If -fcheck-memory-usage, put vars in memory. + * expr.c (get_memory_usage_from_modifier): Convert + EXPAND_{CONST_ADDRESS, INITIALIZER} to MEMORY_USE_DONT. + +Sat Feb 28 08:13:43 1998 Richard Kenner + + * i860/fx2800.h (DATA_ALIGNMENT): Use POINTER_TYPE_P. + * m68k/a-ux.h (FUNCTION_VALUE): Likewise. + * expr.c (get_pointer_alignment, compare, do_store_flag): Likewise. + (expand_builtin): Likewise. + * fold-const.c (force_fit_type, fold_convert, fold): Likewise. + * function.c (assign_parms): Likewise. + * integrate.c (expand_inline_function): Likewise. + * sdbout.c (sdbout_field_types): Likewise. + * tree.c (integer_pow2p, tree_log2, valid_machine_attribute): Likewise. + * stmt.c (expand_decl): Likewise. + ({,bc_}expand_decl_init): Also test for REFERENCE_TYPE. + + * configure.in (version_dep): New variable; if srcdir is CVS working + directory, set to ChangeLog. + (version): Supply default if no version.c. + * Makefile.in (version.c): New rule. + + * gcc.c (snapshot_warning): New function. + (main): Call it for snapshots. + + * dwarf2out.c (expand_builtin_dwarf_reg_size): If reg_raw_mode + not valid for reg, use last size. Also refine range assertion. + +Sat Feb 28 05:04:47 1998 Michael P. Hayes + + * enquire.c (cprop): Don't perform exhaustive search for char_min + and char_max when bits_per_byte > 16. + +Thu Feb 26 15:12:03 1998 Christopher Taylor + + * fixincludes: Avoid using '0-~' in egrep. + +Thu Feb 26 08:04:05 1998 Tristan Gingold + + * function.c (assign_parms): Call 'chkr_set_right' when DECL_RTL + is stack_parm. + * expr.c (get_memory_usage_from_modifier): Convert + EXPAND_{SUM, CONST_ADDRESS, INITIALIZER} to MEMORY_USE_RO. + +Thu Feb 26 07:33:53 1998 Paul Eggert + + * c-lex.c (yylex): Don't munge errno before using it. + * cccp.c (error_from_errno, perror_with_name): Likewise. + * cpplib.c (cpp_error_from_errno): Likewise. + * gcc.c (pfatal_pexecute): Likewise. + * protoize.c (safe_write, find_file, process_aux_info_file): Likewise. + (rename_c_file, edit_file): Likewise. + + * c-lex.c (yylex): Remove unused variable exceeds_double. + +Thu Feb 26 07:05:14 1998 Michael P. Hayes + + * reorg.c (fill_slots_from_thread): Don't steal delay list from target + if condition code of jump conflicts with opposite_needed. + +Thu Feb 26 06:45:23 1998 Richard Kenner + + * Makefile.in (distdir-start): Don't copy CVS subdirectory of config. + + * varasm.c ({compare,record}_constant_1, case CONSTRUCTOR): + Handle the case when we have TREE_PURPOSE values. + +Thu Feb 26 05:59:01 1998 Philippe De Muyter + + * fixincludes (sys/limits.h): Fix a nested comment problem with + HUGE_VAL definition on sysV68 R3V7.1. + +Wed Feb 25 21:09:38 1998 Philippe De Muyter + + * toplev.c (TICKS_PER_SECOND): Renamed from CLOCKS_PER_SECOND. + +Wed Feb 25 20:50:08 1998 Michael P. Hayes + + * reorg.c (fill_slots_from_thread): Mark resources referenced in + opposite_needed thread. Return delay_list even when cannot get + any more delay insns from end of subroutine. + +Wed Feb 25 19:50:01 1998 Mikael Pettersson + + * gcc.c (lookup_compiler): Remove redundant test. + +Wed Feb 25 07:24:22 1998 Richard Kenner + + * vax.md (call insns): Second operand to CALL rtl is SImode. + + * configure.in (i[34567]86-*-mingw32): Support msv and crt suffix. + * i386/crtdll.h: New file. + + * sparc.c (pic_setup_code): If -O0, write USE of pic_offset_table_rtx. + + * expr.c (safe_from_p): Add new arg, TOP_P; all callers changed. + +Sat Feb 21 07:02:39 1998 Jim Wilson + + * mips/iris5.h (DWARF2_UNWIND_INFO): Define to 0. + * mips/iris5gas.h (DWARF2_UNWIND_INFO): Define to 1. + +Fri Feb 20 08:27:46 1998 Paul Eggert + + * sparc/sol2-sld.h: New file. + * configure.in (sparc-*-solaris2*): Use it when using system linker. + * toplev.c (main): Don't default to DWARF2_DEBUG with -ggdb + if LINKER_DOES_NOT_WORK_WITH_DWARF2 is defined. + +Fri Feb 20 08:21:49 1998 H.J. Lu (hjl@gnu.org) + + * alpha/elf.h (STARTFILE_SPEC, ENDFILE_SPEC): Support shared library. + (LIB_SPEC, DEFAULT_VTABLE_THUNKS): Defined #ifndef USE_GNULIBC_1. + * sparc/linux.h (DEFAULT_VTABLE_THUNKS): Likewise. + (LIB_SPEC): Add -lc for -shared #ifndef USE_GNULIBC_1. + * linux.h (LIB_SPEC): Likewise. + * sparc/linux64.h (LIB_SPEC): Likewise; also updated for glibc 2. + (LIBGCC_SPEC): Removed. + (CPP_SUBTARGET_SPEC): Add %{pthread:-D_REENTRANT}. + +Fri Feb 20 05:22:12 1998 Richard Kenner + + * Makefile.in (distdir-start): Add dependence on bi-parser.[ch]. + +Thu Feb 19 18:07:11 1998 Jim Wilson + + * m68k.h (TARGET_SWITCHES): For 68000, 68302, subtract MASK_68881. + For 68303, 68332, cpu32, subtract MASK_68040_ONLY. + +Wed Feb 18 09:37:29 1998 Paul Eggert + + * fixincludes (stdlib.h): Do not double-wrap the size_t typedef. + +Wed Feb 18 07:32:11 1998 Jim Wilson + + * i960.c (emit_move_sequence): Handle unaligned stores to pseudos. + * i960.md (store_unaligned_[dt]i_reg): Handle register dest. + (store_unaligned_ti_reg): Likewise. + + * m68k.h (MACHINE_STATE_{SAVE,RESTORE} [MOTOROLA]): Add %# and %/; + add : to make them into extended asms. + +Wed Feb 18 07:08:05 1998 Richard Kenner + + * reg-stack.c (compare_for_stack_reg): Only handle FP conditional + move as next insn specially. + + * reload.c (find_reloads): Always convert address reload for + non-reloaded operand to RELOAD_FOR_OPERAND_ADDRESS. + + * emit-rtl.c (hard-reg-set.h): Include. + (get_lowpart_common): Don't make new REG for hard reg in a + class that cannot change size. + * Makefile.in (emit-rtl.o): Depend on hard-reg-set.h. + +Sat Feb 14 09:59:00 1998 Richard Earnshaw (rearnsha@arm.com) + + * arm.md (movsfcc): Also validate operands[3] for hard float. + (movdfcc): Only accept fpu_add_operand for operands[3].8 + +Sat Feb 14 09:32:34 1998 Jim Wilson + + * dwarf2out.c (expand_builtin_dwarf_reg_size): New variable mode. + Convert CCmode to word_mode before calling GET_MODE_SIZE. + +Sat Feb 14 09:27:42 1998 David Edelsohn + + * rs6000.h (MY_ISCOFF): Check for U803XTOCMAGIC. + +Sat Feb 14 08:29:43 1998 Arvind Sankar + + * t-svr4 (TARGET_LIBGCC_CFLAGS): New definition. + +Sat Feb 14 07:45:16 1998 Ken Rose (rose@acm.org) + + * reorg.c (fill_slots_from_thread): New parameter, delay_list. + All callers changed. + +Sat Feb 14 07:14:02 1998 Richard Kenner + + * reload.c (debug_reload): Properly output insn codes. + + * pa.c (emit_move_sequence): If in reload, call find_replacement. + + * gansidecl.h (bcopy, bzero, {,r}index): Don't define if IN_LIBGCC2. + + * combine.c (distribute_notes, case REG_DEAD): When seeing if place + to put new note sets register, use reg_bitfield_target_p, as in + original code. + + * gcc.c (process_command): If file is for linker, set lang to "*". + (lookup_compiler): Return 0 for language of "*". + + * sched.c (attach_deaths, case SUBREG): Fix error in last change. + + * i386.md (mov[sdx]fcc): Disable for now. + (mov[sd]fcc_1): Add earlyclobber for output on last alternative. + +Sat Feb 14 06:42:50 1998 Jason Merrill + + * except.c (get_dynamic_handler_chain): Only make call once per func. + (expand_fixup_region_{start,end}): New functions. + (expand_eh_region_start_tree): Store cleanup into finalization here. + * stmt.c (expand_cleanups): Use new functions to protect fixups. + + * except.c (get_dynamic_handler_chain): Build up a FUNCTION_DECL. + * optabs.c (init_optabs): Don't init get_dynamic_handler_chain_libfunc. + * expr.h (get_dynamic_handler_chain_libfunc): Deleted. + +Sat Feb 14 06:34:41 1998 Peter Lawrence + + * optabs.c (emit_conditional_move): Don't reverse condition for FP. + +Fri Feb 13 07:22:04 1998 Richard Kenner + + * Makefile.in (mostlyclean): Only use s-* convention for stamp + files in main dir. + + * configure.in: Add support for i786 (Pentium II); same as i686. + +Thu Feb 12 20:16:35 1998 Michael Meissner + + * rs6000.md: Replace gen_rtx (CONST_INT,...) with GEN_INT. + +Thu Feb 12 10:08:14 1998 John Hassey + + * configure.in (i[3456]86-dg-dgux*): Don't need fixincludes. + +Thu Feb 12 07:27:39 1998 Mumit Khan + + * i386/cygwin32.h (NO_IMPLICIT_EXTERN_C): Define. + about system headers. + (LIB_SPEC): Add -ladvapi32 -lshell32. + +Thu Feb 12 07:19:31 1998 Richard Kenner + + * expr.c (expand_assignment): Fix typo in checking OFFSET. + + * gbl-ctors.h (atexit): Don't define unless needed. + + * combine.c (distribute_notes): Completely check for note operand being + only partially set on potential note target; adjust what notes + we make in that case. + + * i386/xm-go32.h (HAVE_{BCOPY,BZERO,INDEX,RINDEX}): Deleted. + +Wed Feb 11 08:53:27 1998 Richard Kenner + + * calls.c (emit_call_1): Size args now HOST_WIDE_INT. + (expand_call): struct_value_size now HOST_WIDE_INT. + +Tue Feb 10 09:04:39 1998 Richard Kenner + + * integrate.c (initialize_for_inline): Ensure DECL_INCOMING_RTL + is always copied. + +Tue Feb 10 06:10:49 1998 Paul Eggert + + * cccp.c (rescan): Fix bug with macro name appearing + immediately after L'x'. + +Mon Feb 9 20:45:32 1998 Andreas Schwab + + * c-common.c (format_char_info): Add new field zlen. + (print_char_table): Remove entry for 'Z' as a format character. + Initialize zlen field as appropriate. + (scan_char_table): Set zlen field to NULL in each entry. + (check_format_info): Recognize 'Z' as a length modifier, with a + warning in pedantic mode. + Avoid infinite loop when a repeated flag character is detected. + +Mon Feb 9 09:24:04 1998 Paul Eggert + + * c-parse.in (primary): Minor wording fix in diagnostic. + +Mon Feb 9 07:50:19 1998 Richard Kenner + + * c-decl.c (grokdeclarator): Remove warning on inline of varargs. + + * reload.c (find_reloads): Check for const_to_mem case before + checking for invalid reload; use force_const_mem if no_input_reloads. + + * function.c (push_function_context_to): Call init_emit last. + + * protoize.c (my_link): Define as -1 in mingw32. + (link): Remove declaration. + + * rs6000.c (setup_incoming_varargs): Always set rs6000_sysv_varargs_p. + + * integrate.c (expand_inline_function): Clear label_map with bzero. + + * unroll.c (copy_loop_body, case JUMP_INSN): Correct error in last + change: call single_set on COPY, not INSN. + +Sun Feb 8 08:07:37 1998 Richard Kenner + + * msdos/top.sed, winnt/config-nt.sed: Change version number to 2.8.1. + + * configure.in (i[3456]86-*-sco3.2v5*): Use cpio for headers. + +Sat Feb 7 07:32:46 1998 Richard Kenner + + * i386/mingw32.h (LIBGCC_SPEC, STARTFILE_SPEC, MATH_LIBRARY): + Use msvcrt, not crtdll. + +Fri Feb 6 20:32:06 1998 Geert Bosch + + * i386/xm-os2.h (EMX, USG, BSTRING, HAVE_{PUTENV,VPRINTF,STRERROR}): + Define ifdef __EMX__. + (strcasecmp): Define to be stricmp if __EMX__. + (spawnv{,p}): Don't define if EMX. + (OBJECT_SUFFIX): Don't define if EMX. + (MKTEMP_EACH_FILE): Define. + +Fri Feb 6 16:37:29 1998 Kaveh R. Ghazi + + * objc/Make-lang.in (objc.stage1): Depend on stage1-start. + (objc.stage2, objc.stage3, objc.stage4): Likewise for the + respective stageN-start targets. + (objc/sendmsg.o): Depend on objc/runtime-info.h. + +Fri Feb 6 16:27:09 1998 Bernd Schmidt + + * stmt.c (expand_asm_operands): Properly treat asm statement + statements with no operands as volatile. + +Fri Feb 6 16:03:25 1998 Greg McGary + + * c-decl.c (pushdecl): Set DECL_ORIGINAL_TYPE once only. + +Fri Feb 6 15:57:36 1998 Mumit Khan + + * i386/cygwin32.h (STRIP_NAME_ENCODING): New macro. + +Fri Feb 6 15:50:42 1998 Paul Eggert + + * libgcc2.c (__floatdi[xtds]f): Round properly even when rounding + large negative integer to plus or minus infinity. + +Fri Feb 6 15:45:16 1998 Philippe De Muyter + + * sdbout.c (plain_type_1): Return T_DOUBLE, not T_VOID, for + long double #ifndef EXTENDED_SDB_BASIC_TYPES. + +Fri Feb 6 15:23:49 1998 John David Anglin + + * vax/ultrix.h (HAVE_ATEXIT): Define. + * x-vax: File deleted. + +Fri Feb 6 14:34:19 1998 Douglas Rupp + + * gcc.c (process_command, case "-dumpversion"): Print spec_version. + +Fri Feb 6 11:01:13 1998 Josh Littlefield + + * i386/gmon-sol2.c (internal_mcount): Do set-up when program starts + and install hook to do clean-up when it exits. + * i386/sol2-c1.asm (_mcount): Make a weak instead of global symbol. + * i386/sol2dbg.h (ASM_SPEC): Support Solaris bundled assembler's -V + argument; pass -s argument to assembler. + +Fri Feb 6 09:13:21 1998 Jim Wilson (wilson@cygnus.com) + + * function.c (assign_parms): New variable named_arg, with value + depending on STRICT_ARGUMENT_NAMING. Use instead of ! last_named. + + * crtstuff.c (__frame_dummy): New function for irix6. + (__do_global_ctors): Call __frame_dummy for irix6. + * mips/iris6.h (LINK_SPEC): Hide __frame_dummy too. + +Fri Feb 6 09:08:21 1998 Mike Stump + + * rtlanal.c (dead_or_set_regno_p): Ignore REG_DEAD notes after reload. + * genattrtab.c (reload_completed): Define. + + * configure.in (i960-wrs-vxworks): Same as i960-wrs-vxworks5*. + +Fri Feb 6 08:47:38 1998 Richard Kenner + + * Makefile.in (diff): Add INSTALL, configure, and config.in; + remove objc-*. + * objc/config-lang.in (diff_excludes): Add objc-parse.[cy]. + + * i386/xm-mingw32.h (link): Delete macro. + + * alpha.c (output_prolog): Write out frame sizes as longs and + print too large sizes as zero. + + * function.c (combine_temp_slots): No need to allocate and free rtx. + Don't do anything if too many slots in the list. + (put_var_into_stack): Don't use ADDRESSOF if not optimizing. + + * function.c (purge_addressof_1): Force into mem if VOLATILE reference. + + * calls.c (expand_call): Show VAR_DECL made for structure return + address is used; remove bogus set of MEM_IN_STRUCT_P. + * expr.c (expand_expr, case SAVE_EXPR, case TARGET_EXPR): Show used. + (expand_builtin, case BUILT_IN_LONGJMP): Show __dummy used. + * function.c (put_reg_into_stack): New arg USED_P; all callers changed. + + * expr.c (expand_expr, case SAVE_EXPR): assign_temp with KEEP of 3. + * function.c (var_temp_slot_level): New variable. + (push_function_context_to, pop_function_context_from): Save/restore + it and target_temp_slot_level. + (assign_stack_temp): Implement KEEP of 3. + (push_temp_slots_for_block): New function. + (init_temp_slots): Initialize var_temp_slot_level. + * function.h (struct function, fields {var,target}_temp_slot_level): + New fields. + * stmt.c (expand_start_bindings): Call push_temp_slots_for_block. + + * function.c (struct temp_slot): SIZE, BASE_OFF_SET, and FULL_SIZE + now HOST_WIDE_INT. + (assign_{,outer_}stack_local, assign_{,stack_}temp): Size arg is + now HOST_WIDE_INT. + (assign_stack_temp): Do size computations in HOST_WIDE_INT. + (fixup_var_refs_1, optimize_bit_field, instantiate_decls): Likewise. + (instantiate_virtual_regs_1, fix_lexical_address): Likewise. + * rtl.h (assign_stack_{local,temp}): Size arg is HOST_WIDE_INT. + (assign_temp): Likewise. + * expr.h (struct args_size): Field CONSTANT is now HOST_WIDE_INT. + + * sched.c (attach_deaths, case REG): Don't check for REG_UNUSED. + (attach_deaths, case SUBREG, STRICT_LOW_PART, {ZERO,SIGN}_EXTRACT): + Don't pass set_p of 1 if partial assignment. + + * tree.h (size_in_bytes): Returns HOST_WIDE_INT. + * tree.c (size_in_bytes): Likewise. + Tighen up logic some to avoid returning a bogus value instead of -1. + + * expr.c (get_inner_reference, case ARRAY_EXPR): Make WITH_RECORD_EXPR + just for index. + (expand_expr, case PLACEHOLDER_EXPR): Refine search again; look + at each expression and look for pointer to type. + + * expr.c (safe_from_p, case ADDR_EXPR): If TREE_STATIC, no trampoline. + (expand_expr, case ADDR_EXPR): Likewise. + + * expr.c (emit_block_move): Use conservative range for movstr mode. + + * configure.in: See if "cp -p" works if "ln -s" doesn't; else "cp". + + * combine.c (try_combine.c): Pass elim_i2 and elim_i1 to + distribute_notes for i3dest_killed REG_DEAD note. + + * configure.in (mips-dec-netbsd*): Remove bogus setting of prefix. + + * c-decl.c (duplicate_decls): Set DECL_IGNORED_P in newdecl if + different bindings levels. + + * configure.in: Test ln -s by symlinking gcc.c. + + * configure.in (i[3456]86-dg-dgux): Add wildcard for version. + + * crtstuff.c (__do_global_ctors_aux): Switch back to text section + in proper place. + + * rtlanal.c (rtx_varies_p, case REG): pic_offset_table_rtx is fixed. + * genattrtab.c (pic_offset_table_rtx): Define (dummy). + * cse.c (set_nonvarying_address_components): Understand PIC refs. + + * loop.c (strength_reduce): When placing increment for auto-inc + case, do comparison in loop order. + + * i860.c (output_delayed_branch): Add missing arg to recog. + (output_delay_insn): Add missing arg to constrain_operands. + + * configure.in: Truncate target after finished comparing it with host. + + * i386.h (MAX_FIXED_MODE_SIZE): Delete. + + * c-parse.in (expr_no_comma): Clarify undefined error. + + * prefix.c (get_key_value): Don't default to PREFIX here. + (translate_name): Remove bogus addition of "$" if getenv fails; + clean up application of default value of PREFIX. + + * fold-const.c (fold_convert): Call force_fit_type even if input + already overflows. + +Fri Feb 6 07:45:01 1998 Robert Hoehne + + * i386/xm-go32.h (HAVE_{BCOPY,BZERO,BCMP,RINDEX,INDEX}): Define. + + * gcc.c (main): Treat paths starting with '$' or DOS drives + as absolute in standard_startfile_prefix. + +Thu Feb 5 21:07:12 1998 John David Anglin + + * cpplib.c (IS_INCLUDE_DIRECTIVE_TYPE): Add casts from enum to int. + * cccp.c (IS_INCLUDE_DIRECTIVE_TYPE, handle_directive): Likewise. + +Thu Feb 5 19:00:44 1998 Richard Kenner + + * expr.c (expand_expr, case CONSTRUCTOR): Correct shift count + when making signed bit field; use EXPAND_NORMAL, not 0. + +Thu Feb 5 17:42:43 1998 Manfred Hollstein + + * libgcc2.c (__clear_insn_cache): On sysV68 enable the memctl + stuff only if MCT_TEXT is #define'd. + +Thu Feb 5 17:32:01 1998 Robert Hoehne + + * Makefile.in: Changed most stamp-* to s-*. + +Tue Feb 3 19:45:50 1998 James Hawtin + + * i386/sol2.h (STARTFILE_SPEC, LIB_SPEC): Update -pg files. + * configure.in (i[3456]86-*-solaris2*): Add gcrt1.o and gmon.o + to extra_parts. + +Tue Feb 3 17:28:48 1998 Christopher C Chimelis + + * configure.in (alpha*-*-linux-gnu*): Add extra_parts for crtstuff. + +Tue Feb 3 17:18:19 1998 Richard Earnshaw + + * arm.c (find_barrier): Fix one-too-many bug if fail to find barrier. + + * arm.c (arm_reload_in_hi): Handle cases where the MEM is too + complex for a simple offset. + +Tue Feb 3 16:14:21 1998 Robert Hoehne + + * i386/xm-go32.h (EXECUTABLE_SUFFIX): Define. + + * configure.in (i[3456]86-pc-msdosdjgpp*): New entry. + +Tue Feb 3 07:33:58 1998 Richard Kenner + + * explow.c (probe_stack_range): Properly check for small + number of probes. + + * gcc.c (process_command, case 'V'): Validate arg. + + * configure.in (sbrk): Add check for needed declaration. + * acconfig.h (NEED_DECLARATION_SBRK): New entry. + * toplev.c (sbrk): Update declaration conditional. + * mips-tfile.c (sbrk, free): Likewise. + + * sparc/sysv4.h (DBX_REGISTER_NUMBER): Remove abort. + + * mips.c (mips_expand_prologue): Pass reg 25 to gen_loadgp. + * mips.md (loadgp): Add second operand for register number to add. + (builtin_setjmp_receiver): Pass new label and reg 31 to loadgp. + + * toplev.c: Include insn-codes.h, insn-config.h, and recog.h. + (compile_file): Try to emit nop to separate gcc_compiled symbol. + * Makefile.in (toplev.o): Depends on insn-{codes,config}.h, recog.h. + +Tue Feb 3 06:58:46 1998 Mark Mitchell + + * integrate.c (get_label_from_map): New function. + (expand_inline_function): Use it. + Initialize label_map to NULL_RTX instead of gen_label_rtx. + (copy_rtx_and_substitute): Use get_label_from_map. + * integrate.h (get_label_from_map): New function. + (set_label_from_map): New macro. + * unroll.c (unroll_loop, copy_loop_body): Use them. + +Mon Feb 2 16:33:01 1998 Richard Kenner + + * i386.md (mov{si,hi,sf,df,xf}cc{,_1}): Remove cases with branches. + + * rs6000/x-aix31 (INSTALL): Deleted. + * mips/x-dec-osf1, mips/x-osfrose, i386/x-osfrose: Likewise. + * arm/x-riscix: Likewise. + + * c-typeck.c (signed_or_unsigned_type): Properly handle pointer types. + +Mon Feb 2 15:33:58 1998 Michael P. Hayes + + * unroll.c (copy_loop_body): Use single_set instead of + PATTERN to detect increment of an iv inside a PARALLEL. + +Fri Jan 16 20:29:50 1998 Paul Eggert + + * toplev.c (): New include. + (get_run_time): Prefer CLK_TCK (if available) to HZ, and + prefer sysconf (_SC_CLK_TCK) (if available) to CLK_TCK. + * configure.in (sysconf): Call AC_CHECK_FUNCS. + +Wed Jan 14 20:10:51 1998 Paul Eggert + + * cccp.c: (rescan): Don't report line 0 as the possible real start + of an unterminated string constant. + Don't mishandle backslash-newlines that in are the output of + a macro expansion. Properly skip // style comments between a function + macro name and '(', as well as backslash-newlines in comments there. + (handle_directive): Handle / \ newline * between # and directive name. + In #include directives, \ does not escape ". + (do_include): For `#include "file', do not bother expanding into temp + buffer. When error encountered when expanding, do not try result. + (skip_if_group): When skipping an include directive, use include + tokenization, not normal tokenization. Backslash-newline is still + special when skipping. Handle * \ newline / correctly in comments + when skipping. + (skip_quoted_string): After \ newline, set *backslash_newlines_p + even if count_newlines is 0. + (macroexpand): Newline space is not a special marker inside a string. + (macroexpand, macarg): Do not generate \ddd for control characters + when stringifying; the C Standard does not allow this. + (macarg1): New arg MACRO. All callers changed. + Do not treat /*, //, or backslash-newline specially when processing + the output of a macro. + (discard_comments): Don't go past limit if looking for end of comment. + Discard backslash-newline properly when discarding comments. + (change_newlines): \" does not end a string. + (make_definition): Do not treat backslash-newline specially, as it + has already been removed before we get here. + + * profile.c (output_func_start_profiler): Don't fflush output + if -quiet. + * toplev.c (rest_of_compilation): Likewise. + + * i386/x-sco5 (CC): Remove trailing white space. + * x-convex (CCLIBFLAGS): Likewise. + * arm/t-semi (LIBGCC2_CFLAGS): Likewise. + +Wed Jan 7 18:02:42 1998 Richard Kenner + + * Version 2.8.0 released. + +Wed Jan 7 17:54:41 1998 J. Kean Johnston + + * i386/sco5.h ({END,START}FILE_SPEC): Link with correct crtbegin.o + and crtend.o when using -static. + +Wed Jan 7 17:49:14 1998 Jan Christiaan van Winkel + + * cppexp.c (gansidecl.h): Include. + +Wed Jan 7 17:45:07 1998 Tristan Gingold + + * expr.c (get_push_address): Use copy_to_reg instead of force_operand. + (emit_push_insn): Avoid null pointer deference if aggregate has no + types. + (expand_expr): Avoid finite but useless recursion. + (expand_builtin): Fix typo in calling function. + * function.c (assign_parms): Avoid useless call to chkr_set_right. + +Wed Jan 7 17:31:13 1998 Christian Iseli + + * combine.c (force_to_mode): Return if operand is a CLOBBER. + +Wed Jan 7 17:23:24 1998 Richard Kenner + + * x-rs6000 (INSTALL): Remove. + + * jump.c (jump_optimize): Don't use a hard reg as an operand + of a conditional move if small register classes. + +Wed Jan 7 17:09:28 1998 Jim Wilson + + * cse.c (max_insn_uid): New variable. + (cse_around_loop): Use it. + (cse_main): Set it. + +See ChangeLog.11 for earlier changes. + +Use a consistent time stamp format in ChangeLog entries. +Not everyone has Emacs 20 yet, so stick with Emacs 19 format for now. + +Local Variables: +add-log-time-format: current-time-string +End: diff --git a/gcc_arm/INSTALL b/gcc_arm/INSTALL new file mode 100755 index 0000000..a7c63d5 --- /dev/null +++ b/gcc_arm/INSTALL @@ -0,0 +1,2188 @@ +This is Info file INSTALL, produced by Makeinfo version 1.68 from the +input file install1.texi. + + This file documents the installation of the GNU compiler. Copyright +(C) 1988, 1989, 1992, 1994, 1995 Free Software Foundation, Inc. You +may copy, distribute, and modify it freely as long as you preserve this +copyright notice and permission notice. + + +File: INSTALL, Node: Installation, Up: (dir) + +Installing GNU CC +***************** + + Note most of this information is out of date and superceded by the +EGCS install procedures. It is provided for historical reference only. + +* Menu: + +* Configurations:: Configurations Supported by GNU CC. +* Other Dir:: Compiling in a separate directory (not where the source is). +* Cross-Compiler:: Building and installing a cross-compiler. +* Sun Install:: See below for installation on the Sun. +* VMS Install:: See below for installation on VMS. +* Collect2:: How `collect2' works; how it finds `ld'. +* Header Dirs:: Understanding the standard header file directories. + + Here is the procedure for installing GNU CC on a Unix system. See +*Note VMS Install::, for VMS systems. In this section we assume you +compile in the same directory that contains the source files; see *Note +Other Dir::, to find out how to compile in a separate directory on Unix +systems. + + You cannot install GNU C by itself on MSDOS; it will not compile +under any MSDOS compiler except itself. You need to get the complete +compilation package DJGPP, which includes binaries as well as sources, +and includes all the necessary compilation tools and libraries. + + 1. If you have built GNU CC previously in the same directory for a + different target machine, do `make distclean' to delete all files + that might be invalid. One of the files this deletes is + `Makefile'; if `make distclean' complains that `Makefile' does not + exist, it probably means that the directory is already suitably + clean. + + 2. On a System V release 4 system, make sure `/usr/bin' precedes + `/usr/ucb' in `PATH'. The `cc' command in `/usr/ucb' uses + libraries which have bugs. + + 3. Specify the host, build and target machine configurations. You do + this by running the file `configure'. + + The "build" machine is the system which you are using, the "host" + machine is the system where you want to run the resulting compiler + (normally the build machine), and the "target" machine is the + system for which you want the compiler to generate code. + + If you are building a compiler to produce code for the machine it + runs on (a native compiler), you normally do not need to specify + any operands to `configure'; it will try to guess the type of + machine you are on and use that as the build, host and target + machines. So you don't need to specify a configuration when + building a native compiler unless `configure' cannot figure out + what your configuration is or guesses wrong. + + In those cases, specify the build machine's "configuration name" + with the `--host' option; the host and target will default to be + the same as the host machine. (If you are building a + cross-compiler, see *Note Cross-Compiler::.) + + Here is an example: + + ./configure --host=sparc-sun-sunos4.1 + + A configuration name may be canonical or it may be more or less + abbreviated. + + A canonical configuration name has three parts, separated by + dashes. It looks like this: `CPU-COMPANY-SYSTEM'. (The three + parts may themselves contain dashes; `configure' can figure out + which dashes serve which purpose.) For example, + `m68k-sun-sunos4.1' specifies a Sun 3. + + You can also replace parts of the configuration by nicknames or + aliases. For example, `sun3' stands for `m68k-sun', so + `sun3-sunos4.1' is another way to specify a Sun 3. You can also + use simply `sun3-sunos', since the version of SunOS is assumed by + default to be version 4. + + You can specify a version number after any of the system types, + and some of the CPU types. In most cases, the version is + irrelevant, and will be ignored. So you might as well specify the + version if you know it. + + See *Note Configurations::, for a list of supported configuration + names and notes on many of the configurations. You should check + the notes in that section before proceeding any further with the + installation of GNU CC. + + There are four additional options you can specify independently to + describe variant hardware and software configurations. These are + `--with-gnu-as', `--with-gnu-ld', `--with-stabs' and `--nfp'. + + `--with-gnu-as' + If you will use GNU CC with the GNU assembler (GAS), you + should declare this by using the `--with-gnu-as' option when + you run `configure'. + + Using this option does not install GAS. It only modifies the + output of GNU CC to work with GAS. Building and installing + GAS is up to you. + + Conversely, if you *do not* wish to use GAS and do not specify + `--with-gnu-as' when building GNU CC, it is up to you to make + sure that GAS is not installed. GNU CC searches for a + program named `as' in various directories; if the program it + finds is GAS, then it runs GAS. If you are not sure where + GNU CC finds the assembler it is using, try specifying `-v' + when you run it. + + The systems where it makes a difference whether you use GAS + are + `hppa1.0-ANY-ANY', `hppa1.1-ANY-ANY', `i386-ANY-sysv', + `i386-ANY-isc', + `i860-ANY-bsd', `m68k-bull-sysv', + `m68k-hp-hpux', `m68k-sony-bsd', + `m68k-altos-sysv', `m68000-hp-hpux', + `m68000-att-sysv', `ANY-lynx-lynxos', and `mips-ANY'). On + any other system, `--with-gnu-as' has no effect. + + On the systems listed above (except for the HP-PA, for ISC on + the 386, and for `mips-sgi-irix5.*'), if you use GAS, you + should also use the GNU linker (and specify `--with-gnu-ld'). + + `--with-gnu-ld' + Specify the option `--with-gnu-ld' if you plan to use the GNU + linker with GNU CC. + + This option does not cause the GNU linker to be installed; it + just modifies the behavior of GNU CC to work with the GNU + linker. + + `--with-stabs' + On MIPS based systems and on Alphas, you must specify whether + you want GNU CC to create the normal ECOFF debugging format, + or to use BSD-style stabs passed through the ECOFF symbol + table. The normal ECOFF debug format cannot fully handle + languages other than C. BSD stabs format can handle other + languages, but it only works with the GNU debugger GDB. + + Normally, GNU CC uses the ECOFF debugging format by default; + if you prefer BSD stabs, specify `--with-stabs' when you + configure GNU CC. + + No matter which default you choose when you configure GNU CC, + the user can use the `-gcoff' and `-gstabs+' options to + specify explicitly the debug format for a particular + compilation. + + `--with-stabs' is meaningful on the ISC system on the 386, + also, if `--with-gas' is used. It selects use of stabs + debugging information embedded in COFF output. This kind of + debugging information supports C++ well; ordinary COFF + debugging information does not. + + `--with-stabs' is also meaningful on 386 systems running + SVR4. It selects use of stabs debugging information embedded + in ELF output. The C++ compiler currently (2.6.0) does not + support the DWARF debugging information normally used on 386 + SVR4 platforms; stabs provide a workable alternative. This + requires gas and gdb, as the normal SVR4 tools can not + generate or interpret stabs. + + `--nfp' + On certain systems, you must specify whether the machine has + a floating point unit. These systems include + `m68k-sun-sunosN' and `m68k-isi-bsd'. On any other system, + `--nfp' currently has no effect, though perhaps there are + other systems where it could usefully make a difference. + + `--enable-haifa' + `--disable-haifa' + Use `--enable-haifa' to enable use of an experimental + instruction scheduler (from IBM Haifa). This may or may not + produce better code. Some targets on which it is known to be + a win enable it by default; use `--disable-haifa' to disable + it in these cases. `configure' will print out whether the + Haifa scheduler is enabled when it is run. + + `--enable-threads=TYPE' + Certain systems, notably Linux-based GNU systems, can't be + relied on to supply a threads facility for the Objective C + runtime and so will default to single-threaded runtime. They + may, however, have a library threads implementation + available, in which case threads can be enabled with this + option by supplying a suitable TYPE, probably `posix'. The + possibilities for TYPE are `single', `posix', `win32', + `solaris', `irix' and `mach'. + + `--enable-checking' + When you specify this option, the compiler is built to + perform checking of tree node types when referencing fields + of that node. This does not change the generated code, but + adds error checking within the compiler. This will slow down + the compiler and may only work properly if you are building + the compiler with GNU C. + + The `configure' script searches subdirectories of the source + directory for other compilers that are to be integrated into GNU + CC. The GNU compiler for C++, called G++ is in a subdirectory + named `cp'. `configure' inserts rules into `Makefile' to build + all of those compilers. + + Here we spell out what files will be set up by `configure'. + Normally you need not be concerned with these files. + + * A file named `config.h' is created that contains a `#include' + of the top-level config file for the machine you will run the + compiler on (*note The Configuration File: + (gcc.info)Config.). This file is responsible for defining + information about the host machine. It includes `tm.h'. + + The top-level config file is located in the subdirectory + `config'. Its name is always `xm-SOMETHING.h'; usually + `xm-MACHINE.h', but there are some exceptions. + + If your system does not support symbolic links, you might + want to set up `config.h' to contain a `#include' command + which refers to the appropriate file. + + * A file named `tconfig.h' is created which includes the + top-level config file for your target machine. This is used + for compiling certain programs to run on that machine. + + * A file named `tm.h' is created which includes the + machine-description macro file for your target machine. It + should be in the subdirectory `config' and its name is often + `MACHINE.h'. + + * The command file `configure' also constructs the file + `Makefile' by adding some text to the template file + `Makefile.in'. The additional text comes from files in the + `config' directory, named `t-TARGET' and `x-HOST'. If these + files do not exist, it means nothing needs to be added for a + given target or host. + + 4. The standard directory for installing GNU CC is `/usr/local/lib'. + If you want to install its files somewhere else, specify + `--prefix=DIR' when you run `configure'. Here DIR is a directory + name to use instead of `/usr/local' for all purposes with one + exception: the directory `/usr/local/include' is searched for + header files no matter where you install the compiler. To override + this name, use the `--with-local-prefix' option below. The + directory you specify need not exist, but its parent directory + must exist. + + 5. Specify `--with-local-prefix=DIR' if you want the compiler to + search directory `DIR/include' for locally installed header files + *instead* of `/usr/local/include'. + + You should specify `--with-local-prefix' *only* if your site has a + different convention (not `/usr/local') for where to put + site-specific files. + + The default value for `--with-local-prefix' is `/usr/local' + regardless of the value of `--prefix'. Specifying `--prefix' has + no effect on which directory GNU CC searches for local header + files. This may seem counterintuitive, but actually it is logical. + + The purpose of `--prefix' is to specify where to *install GNU CC*. + The local header files in `/usr/local/include'--if you put any in + that directory--are not part of GNU CC. They are part of other + programs--perhaps many others. (GNU CC installs its own header + files in another directory which is based on the `--prefix' value.) + + *Do not* specify `/usr' as the `--with-local-prefix'! The + directory you use for `--with-local-prefix' *must not* contain any + of the system's standard header files. If it did contain them, + certain programs would be miscompiled (including GNU Emacs, on + certain targets), because this would override and nullify the + header file corrections made by the `fixincludes' script. + + Indications are that people who use this option use it based on + mistaken ideas of what it is for. People use it as if it specified + where to install part of GNU CC. Perhaps they make this assumption + because installing GNU CC creates the directory. + + 6. Make sure the Bison parser generator is installed. (This is + unnecessary if the Bison output files `c-parse.c' and `cexp.c' are + more recent than `c-parse.y' and `cexp.y' and you do not plan to + change the `.y' files.) + + Bison versions older than Sept 8, 1988 will produce incorrect + output for `c-parse.c'. + + 7. If you have chosen a configuration for GNU CC which requires other + GNU tools (such as GAS or the GNU linker) instead of the standard + system tools, install the required tools in the build directory + under the names `as', `ld' or whatever is appropriate. This will + enable the compiler to find the proper tools for compilation of + the program `enquire'. + + Alternatively, you can do subsequent compilation using a value of + the `PATH' environment variable such that the necessary GNU tools + come before the standard system tools. + + 8. Build the compiler. Just type `make LANGUAGES=c' in the compiler + directory. + + `LANGUAGES=c' specifies that only the C compiler should be + compiled. The makefile normally builds compilers for all the + supported languages; currently, C, C++ and Objective C. However, + C is the only language that is sure to work when you build with + other non-GNU C compilers. In addition, building anything but C + at this stage is a waste of time. + + In general, you can specify the languages to build by typing the + argument `LANGUAGES="LIST"', where LIST is one or more words from + the list `c', `c++', and `objective-c'. If you have any + additional GNU compilers as subdirectories of the GNU CC source + directory, you may also specify their names in this list. + + Ignore any warnings you may see about "statement not reached" in + `insn-emit.c'; they are normal. Also, warnings about "unknown + escape sequence" are normal in `genopinit.c' and perhaps some + other files. Likewise, you should ignore warnings about "constant + is so large that it is unsigned" in `insn-emit.c' and + `insn-recog.c', a warning about a comparison always being zero in + `enquire.o', and warnings about shift counts exceeding type widths + in `cexp.y'. Any other compilation errors may represent bugs in + the port to your machine or operating system, and should be + investigated and reported. + + Some commercial compilers fail to compile GNU CC because they have + bugs or limitations. For example, the Microsoft compiler is said + to run out of macro space. Some Ultrix compilers run out of + expression space; then you need to break up the statement where + the problem happens. + + 9. If you are building a cross-compiler, stop here. *Note + Cross-Compiler::. + + 10. Move the first-stage object files and executables into a + subdirectory with this command: + + make stage1 + + The files are moved into a subdirectory named `stage1'. Once + installation is complete, you may wish to delete these files with + `rm -r stage1'. + + 11. If you have chosen a configuration for GNU CC which requires other + GNU tools (such as GAS or the GNU linker) instead of the standard + system tools, install the required tools in the `stage1' + subdirectory under the names `as', `ld' or whatever is + appropriate. This will enable the stage 1 compiler to find the + proper tools in the following stage. + + Alternatively, you can do subsequent compilation using a value of + the `PATH' environment variable such that the necessary GNU tools + come before the standard system tools. + + 12. Recompile the compiler with itself, with this command: + + make CC="stage1/xgcc -Bstage1/" CFLAGS="-g -O2" + + This is called making the stage 2 compiler. + + The command shown above builds compilers for all the supported + languages. If you don't want them all, you can specify the + languages to build by typing the argument `LANGUAGES="LIST"'. LIST + should contain one or more words from the list `c', `c++', + `objective-c', and `proto'. Separate the words with spaces. + `proto' stands for the programs `protoize' and `unprotoize'; they + are not a separate language, but you use `LANGUAGES' to enable or + disable their installation. + + If you are going to build the stage 3 compiler, then you might + want to build only the C language in stage 2. + + Once you have built the stage 2 compiler, if you are short of disk + space, you can delete the subdirectory `stage1'. + + On a 68000 or 68020 system lacking floating point hardware, unless + you have selected a `tm.h' file that expects by default that there + is no such hardware, do this instead: + + make CC="stage1/xgcc -Bstage1/" CFLAGS="-g -O2 -msoft-float" + + 13. If you wish to test the compiler by compiling it with itself one + more time, install any other necessary GNU tools (such as GAS or + the GNU linker) in the `stage2' subdirectory as you did in the + `stage1' subdirectory, then do this: + + make stage2 + make CC="stage2/xgcc -Bstage2/" CFLAGS="-g -O2" + + This is called making the stage 3 compiler. Aside from the `-B' + option, the compiler options should be the same as when you made + the stage 2 compiler. But the `LANGUAGES' option need not be the + same. The command shown above builds compilers for all the + supported languages; if you don't want them all, you can specify + the languages to build by typing the argument `LANGUAGES="LIST"', + as described above. + + If you do not have to install any additional GNU tools, you may + use the command + + make bootstrap LANGUAGES=LANGUAGE-LIST BOOT_CFLAGS=OPTION-LIST + + instead of making `stage1', `stage2', and performing the two + compiler builds. + + 14. Then compare the latest object files with the stage 2 object + files--they ought to be identical, aside from time stamps (if any). + + On some systems, meaningful comparison of object files is + impossible; they always appear "different." This is currently + true on Solaris and some systems that use ELF object file format. + On some versions of Irix on SGI machines and DEC Unix (OSF/1) on + Alpha systems, you will not be able to compare the files without + specifying `-save-temps'; see the description of individual + systems above to see if you get comparison failures. You may have + similar problems on other systems. + + Use this command to compare the files: + + make compare + + This will mention any object files that differ between stage 2 and + stage 3. Any difference, no matter how innocuous, indicates that + the stage 2 compiler has compiled GNU CC incorrectly, and is + therefore a potentially serious bug which you should investigate + and report. + + If your system does not put time stamps in the object files, then + this is a faster way to compare them (using the Bourne shell): + + for file in *.o; do + cmp $file stage2/$file + done + + If you have built the compiler with the `-mno-mips-tfile' option on + MIPS machines, you will not be able to compare the files. + + 15. Install the compiler driver, the compiler's passes and run-time + support with `make install'. Use the same value for `CC', + `CFLAGS' and `LANGUAGES' that you used when compiling the files + that are being installed. One reason this is necessary is that + some versions of Make have bugs and recompile files gratuitously + when you do this step. If you use the same variable values, those + files will be recompiled properly. + + For example, if you have built the stage 2 compiler, you can use + the following command: + + make install CC="stage2/xgcc -Bstage2/" CFLAGS="-g -O" LANGUAGES="LIST" + + This copies the files `cc1', `cpp' and `libgcc.a' to files `cc1', + `cpp' and `libgcc.a' in the directory + `/usr/local/lib/gcc-lib/TARGET/VERSION', which is where the + compiler driver program looks for them. Here TARGET is the + canonicalized form of target machine type specified when you ran + `configure', and VERSION is the version number of GNU CC. This + naming scheme permits various versions and/or cross-compilers to + coexist. It also copies the executables for compilers for other + languages (e.g., `cc1plus' for C++) to the same directory. + + This also copies the driver program `xgcc' into + `/usr/local/bin/gcc', so that it appears in typical execution + search paths. It also copies `gcc.1' into `/usr/local/man/man1' + and info pages into `/usr/local/info'. + + On some systems, this command causes recompilation of some files. + This is usually due to bugs in `make'. You should either ignore + this problem, or use GNU Make. + + *Warning: there is a bug in `alloca' in the Sun library. To avoid + this bug, be sure to install the executables of GNU CC that were + compiled by GNU CC. (That is, the executables from stage 2 or 3, + not stage 1.) They use `alloca' as a built-in function and never + the one in the library.* + + (It is usually better to install GNU CC executables from stage 2 + or 3, since they usually run faster than the ones compiled with + some other compiler.) + + 16. If you're going to use C++, it's likely that you need to also + install a C++ runtime library. Just as GNU C does not distribute + a C runtime library, it also does not include a C++ runtime + library. All I/O functionality, special class libraries, etc., are + provided by the C++ runtime library. + + The standard C++ runtime library for GNU CC is called `libstdc++'. + An obsolescent library `libg++' may also be available, but it's + necessary only for older software that hasn't been converted yet; + if you don't know whether you need `libg++' then you probably don't + need it. + + Here's one way to build and install `libstdc++' for GNU CC: + + * Build and install GNU CC, so that invoking `gcc' obtains the + GNU CC that was just built. + + * Obtain a copy of a compatible `libstdc++' distribution. For + example, the `libstdc++-2.8.0.tar.gz' distribution should be + compatible with GCC 2.8.0. GCC distributors normally + distribute `libstdc++' as well. + + * Set the `CXX' environment variable to `gcc' while running the + `libstdc++' distribution's `configure' command. Use the same + `configure' options that you used when you invoked GCC's + `configure' command. + + * Invoke `make' to build the C++ runtime. + + * Invoke `make install' to install the C++ runtime. + + To summarize, after building and installing GNU CC, invoke the + following shell commands in the topmost directory of the C++ + library distribution. For CONFIGURE-OPTIONS, use the same options + that you used to configure GNU CC. + + $ CXX=gcc ./configure CONFIGURE-OPTIONS + $ make + $ make install + + 17. GNU CC includes a runtime library for Objective-C because it is an + integral part of the language. You can find the files associated + with the library in the subdirectory `objc'. The GNU Objective-C + Runtime Library requires header files for the target's C library in + order to be compiled,and also requires the header files for the + target's thread library if you want thread support. *Note + Cross-Compilers and Header Files: Cross Headers, for discussion + about header files issues for cross-compilation. + + When you run `configure', it picks the appropriate Objective-C + thread implementation file for the target platform. In some + situations, you may wish to choose a different back-end as some + platforms support multiple thread implementations or you may wish + to disable thread support completely. You do this by specifying a + value for the OBJC_THREAD_FILE makefile variable on the command + line when you run make, for example: + + make CC="stage2/xgcc -Bstage2/" CFLAGS="-g -O2" OBJC_THREAD_FILE=thr-single + + Below is a list of the currently available back-ends. + + * thr-single Disable thread support, should work for all + platforms. + + * thr-decosf1 DEC OSF/1 thread support. + + * thr-irix SGI IRIX thread support. + + * thr-mach Generic MACH thread support, known to work on + NEXTSTEP. + + * thr-os2 IBM OS/2 thread support. + + * thr-posix Generix POSIX thread support. + + * thr-pthreads PCThreads on Linux-based GNU systems. + + * thr-solaris SUN Solaris thread support. + + * thr-win32 Microsoft Win32 API thread support. + + +File: INSTALL, Node: Configurations, Next: Other Dir, Up: Installation + +Configurations Supported by GNU CC +================================== + + Here are the possible CPU types: + + 1750a, a29k, alpha, arm, cN, clipper, dsp16xx, elxsi, h8300, + hppa1.0, hppa1.1, i370, i386, i486, i586, i860, i960, m32r, + m68000, m68k, m88k, mips, mipsel, mips64, mips64el, ns32k, + powerpc, powerpcle, pyramid, romp, rs6000, sh, sparc, sparclite, + sparc64, vax, we32k. + + Here are the recognized company names. As you can see, customary +abbreviations are used rather than the longer official names. + + acorn, alliant, altos, apollo, apple, att, bull, cbm, convergent, + convex, crds, dec, dg, dolphin, elxsi, encore, harris, hitachi, + hp, ibm, intergraph, isi, mips, motorola, ncr, next, ns, omron, + plexus, sequent, sgi, sony, sun, tti, unicom, wrs. + + The company name is meaningful only to disambiguate when the rest of +the information supplied is insufficient. You can omit it, writing +just `CPU-SYSTEM', if it is not needed. For example, `vax-ultrix4.2' +is equivalent to `vax-dec-ultrix4.2'. + + Here is a list of system types: + + 386bsd, aix, acis, amigaos, aos, aout, aux, bosx, bsd, clix, coff, + ctix, cxux, dgux, dynix, ebmon, ecoff, elf, esix, freebsd, hms, + genix, gnu, linux-gnu, hiux, hpux, iris, irix, isc, luna, lynxos, + mach, minix, msdos, mvs, netbsd, newsos, nindy, ns, osf, osfrose, + ptx, riscix, riscos, rtu, sco, sim, solaris, sunos, sym, sysv, + udi, ultrix, unicos, uniplus, unos, vms, vsta, vxworks, winnt, + xenix. + +You can omit the system type; then `configure' guesses the operating +system from the CPU and company. + + You can add a version number to the system type; this may or may not +make a difference. For example, you can write `bsd4.3' or `bsd4.4' to +distinguish versions of BSD. In practice, the version number is most +needed for `sysv3' and `sysv4', which are often treated differently. + + If you specify an impossible combination such as `i860-dg-vms', then +you may get an error message from `configure', or it may ignore part of +the information and do the best it can with the rest. `configure' +always prints the canonical name for the alternative that it used. GNU +CC does not support all possible alternatives. + + Often a particular model of machine has a name. Many machine names +are recognized as aliases for CPU/company combinations. Thus, the +machine name `sun3', mentioned above, is an alias for `m68k-sun'. +Sometimes we accept a company name as a machine name, when the name is +popularly used for a particular machine. Here is a table of the known +machine names: + + 3300, 3b1, 3bN, 7300, altos3068, altos, apollo68, att-7300, + balance, convex-cN, crds, decstation-3100, decstation, delta, + encore, fx2800, gmicro, hp7NN, hp8NN, hp9k2NN, hp9k3NN, hp9k7NN, + hp9k8NN, iris4d, iris, isi68, m3230, magnum, merlin, miniframe, + mmax, news-3600, news800, news, next, pbd, pc532, pmax, powerpc, + powerpcle, ps2, risc-news, rtpc, sun2, sun386i, sun386, sun3, + sun4, symmetry, tower-32, tower. + +Remember that a machine name specifies both the cpu type and the company +name. If you want to install your own homemade configuration files, +you can use `local' as the company name to access them. If you use +configuration `CPU-local', the configuration name without the cpu prefix +is used to form the configuration file names. + + Thus, if you specify `m68k-local', configuration uses files +`m68k.md', `local.h', `m68k.c', `xm-local.h', `t-local', and `x-local', +all in the directory `config/m68k'. + + Here is a list of configurations that have special treatment or +special things you must know: + +`1750a-*-*' + MIL-STD-1750A processors. + + The MIL-STD-1750A cross configuration produces output for + `as1750', an assembler/linker available under the GNU Public + License for the 1750A. `as1750' can be obtained at + *ftp://ftp.fta-berlin.de/pub/crossgcc/1750gals/*. A similarly + licensed simulator for the 1750A is available from same address. + + You should ignore a fatal error during the building of libgcc + (libgcc is not yet implemented for the 1750A.) + + The `as1750' assembler requires the file `ms1750.inc', which is + found in the directory `config/1750a'. + + GNU CC produced the same sections as the Fairchild F9450 C + Compiler, namely: + + `Normal' + The program code section. + + `Static' + The read/write (RAM) data section. + + `Konst' + The read-only (ROM) constants section. + + `Init' + Initialization section (code to copy KREL to SREL). + + The smallest addressable unit is 16 bits (BITS_PER_UNIT is 16). + This means that type `char' is represented with a 16-bit word per + character. The 1750A's "Load/Store Upper/Lower Byte" instructions + are not used by GNU CC. + +`alpha-*-osf1' + Systems using processors that implement the DEC Alpha architecture + and are running the DEC Unix (OSF/1) operating system, for example + the DEC Alpha AXP systems.CC.) + + GNU CC writes a `.verstamp' directive to the assembler output file + unless it is built as a cross-compiler. It gets the version to + use from the system header file `/usr/include/stamp.h'. If you + install a new version of DEC Unix, you should rebuild GCC to pick + up the new version stamp. + + Note that since the Alpha is a 64-bit architecture, + cross-compilers from 32-bit machines will not generate code as + efficient as that generated when the compiler is running on a + 64-bit machine because many optimizations that depend on being + able to represent a word on the target in an integral value on the + host cannot be performed. Building cross-compilers on the Alpha + for 32-bit machines has only been tested in a few cases and may + not work properly. + + `make compare' may fail on old versions of DEC Unix unless you add + `-save-temps' to `CFLAGS'. On these systems, the name of the + assembler input file is stored in the object file, and that makes + comparison fail if it differs between the `stage1' and `stage2' + compilations. The option `-save-temps' forces a fixed name to be + used for the assembler input file, instead of a randomly chosen + name in `/tmp'. Do not add `-save-temps' unless the comparisons + fail without that option. If you add `-save-temps', you will have + to manually delete the `.i' and `.s' files after each series of + compilations. + + GNU CC now supports both the native (ECOFF) debugging format used + by DBX and GDB and an encapsulated STABS format for use only with + GDB. See the discussion of the `--with-stabs' option of + `configure' above for more information on these formats and how to + select them. + + There is a bug in DEC's assembler that produces incorrect line + numbers for ECOFF format when the `.align' directive is used. To + work around this problem, GNU CC will not emit such alignment + directives while writing ECOFF format debugging information even + if optimization is being performed. Unfortunately, this has the + very undesirable side-effect that code addresses when `-O' is + specified are different depending on whether or not `-g' is also + specified. + + To avoid this behavior, specify `-gstabs+' and use GDB instead of + DBX. DEC is now aware of this problem with the assembler and + hopes to provide a fix shortly. + +`arc-*-elf' + Argonaut ARC processor. This configuration is intended for + embedded systems. + +`arm-*-aout' + Advanced RISC Machines ARM-family processors. These are often + used in embedded applications. There are no standard Unix + configurations. This configuration corresponds to the basic + instruction sequences and will produce `a.out' format object + modules. + + You may need to make a variant of the file `arm.h' for your + particular configuration. + +`arm-*-linuxaout' + Any of the ARM family processors running the Linux-based GNU + system with the `a.out' binary format (ELF is not yet supported). + You must use version 2.8.1.0.7 or later of the GNU/Linux binutils, + which you can download from `sunsite.unc.edu:/pub/Linux/GCC' and + other mirror sites for Linux-based GNU systems. + +`arm-*-riscix' + The ARM2 or ARM3 processor running RISC iX, Acorn's port of BSD + Unix. If you are running a version of RISC iX prior to 1.2 then + you must specify the version number during configuration. Note + that the assembler shipped with RISC iX does not support stabs + debugging information; a new version of the assembler, with stabs + support included, is now available from Acorn and via ftp + `ftp.acorn.com:/pub/riscix/as+xterm.tar.Z'. To enable stabs + debugging, pass `--with-gnu-as' to configure. + + You will need to install GNU `sed' before you can run configure. + +`a29k' + AMD Am29k-family processors. These are normally used in embedded + applications. There are no standard Unix configurations. This + configuration corresponds to AMD's standard calling sequence and + binary interface and is compatible with other 29k tools. + + You may need to make a variant of the file `a29k.h' for your + particular configuration. + +`a29k-*-bsd' + AMD Am29050 used in a system running a variant of BSD Unix. + +`decstation-*' + MIPS-based DECstations can support three different personalities: + Ultrix, DEC OSF/1, and OSF/rose. (Alpha-based DECstation products + have a configuration name beginning with `alpha-dec'.) To + configure GCC for these platforms use the following configurations: + + `decstation-ultrix' + Ultrix configuration. + + `decstation-osf1' + Dec's version of OSF/1. + + `decstation-osfrose' + Open Software Foundation reference port of OSF/1 which uses + the OSF/rose object file format instead of ECOFF. Normally, + you would not select this configuration. + + The MIPS C compiler needs to be told to increase its table size + for switch statements with the `-Wf,-XNg1500' option in order to + compile `cp/parse.c'. If you use the `-O2' optimization option, + you also need to use `-Olimit 3000'. Both of these options are + automatically generated in the `Makefile' that the shell script + `configure' builds. If you override the `CC' make variable and + use the MIPS compilers, you may need to add `-Wf,-XNg1500 -Olimit + 3000'. + +`elxsi-elxsi-bsd' + The Elxsi's C compiler has known limitations that prevent it from + compiling GNU C. Please contact `mrs@cygnus.com' for more details. + +`dsp16xx' + A port to the AT&T DSP1610 family of processors. + +`h8300-*-*' + Hitachi H8/300 series of processors. + + The calling convention and structure layout has changed in release + 2.6. All code must be recompiled. The calling convention now + passes the first three arguments in function calls in registers. + Structures are no longer a multiple of 2 bytes. + +`hppa*-*-*' + There are several variants of the HP-PA processor which run a + variety of operating systems. GNU CC must be configured to use + the correct processor type and operating system, or GNU CC will + not function correctly. The easiest way to handle this problem is + to *not* specify a target when configuring GNU CC, the `configure' + script will try to automatically determine the right processor + type and operating system. + + `-g' does not work on HP-UX, since that system uses a peculiar + debugging format which GNU CC does not know about. However, `-g' + will work if you also use GAS and GDB in conjunction with GCC. We + highly recommend using GAS for all HP-PA configurations. + + You should be using GAS-2.6 (or later) along with GDB-4.16 (or + later). These can be retrieved from all the traditional GNU ftp + archive sites. + + On some versions of HP-UX, you will need to install GNU `sed'. + + You will need to be install GAS into a directory before `/bin', + `/usr/bin', and `/usr/ccs/bin' in your search path. You should + install GAS before you build GNU CC. + + To enable debugging, you must configure GNU CC with the + `--with-gnu-as' option before building. + +`i370-*-*' + This port is very preliminary and has many known bugs. We hope to + have a higher-quality port for this machine soon. + +`i386-*-linux-gnuoldld' + Use this configuration to generate `a.out' binaries on Linux-based + GNU systems if you do not have gas/binutils version 2.5.2 or later + installed. This is an obsolete configuration. + +`i386-*-linux-gnuaout' + Use this configuration to generate `a.out' binaries on Linux-based + GNU systems. This configuration is being superseded. You must use + gas/binutils version 2.5.2 or later. + +`i386-*-linux-gnu' + Use this configuration to generate ELF binaries on Linux-based GNU + systems. You must use gas/binutils version 2.5.2 or later. + +`i386-*-sco' + Compilation with RCC is recommended. Also, it may be a good idea + to link with GNU malloc instead of the malloc that comes with the + system. + +`i386-*-sco3.2v4' + Use this configuration for SCO release 3.2 version 4. + +`i386-*-sco3.2v5*' + Use this for the SCO OpenServer Release family including 5.0.0, + 5.0.2, 5.0.4, 5.0.5, Internet FastStart 1.0, and Internet + FastStart 1.1. + + GNU CC can generate COFF binaries if you specify `-mcoff' or ELF + binaries, the default. A full `make bootstrap' is recommended + so that an ELF compiler that builds ELF is generated. + + You must have TLS597 from `ftp://ftp.sco.com/TLS' installed for ELF + C++ binaries to work correctly on releases before 5.0.4. + + The native SCO assembler that is provided with the OS at no charge + is normally required. If, however, you must be able to use the GNU + assembler (perhaps you have complex asms) you must configure this + package `--with-gnu-as'. To do this, install (cp or symlink) + gcc/as to your copy of the GNU assembler. You must use a recent + version of GNU binutils; version 2.9.1 seems to work well. If you + select this option, you will be unable to build COFF images. + Trying to do so will result in non-obvious failures. In general, + the "-with-gnu-as" option isn't as well tested as the native + assembler. + + *NOTE:* If you are building C++, you must follow the instructions + about invoking `make bootstrap' because the native OpenServer + compiler may build a `cc1plus' that will not correctly parse many + valid C++ programs. You must do a `make bootstrap' if you are + building with the native compiler. + +`i386-*-isc' + It may be a good idea to link with GNU malloc instead of the + malloc that comes with the system. + + In ISC version 4.1, `sed' core dumps when building `deduced.h'. + Use the version of `sed' from version 4.0. + +`i386-*-esix' + It may be good idea to link with GNU malloc instead of the malloc + that comes with the system. + +`i386-ibm-aix' + You need to use GAS version 2.1 or later, and LD from GNU binutils + version 2.2 or later. + +`i386-sequent-bsd' + Go to the Berkeley universe before compiling. + +`i386-sequent-ptx1*' +`i386-sequent-ptx2*' + You must install GNU `sed' before running `configure'. + +`i386-sun-sunos4' + You may find that you need another version of GNU CC to begin + bootstrapping with, since the current version when built with the + system's own compiler seems to get an infinite loop compiling part + of `libgcc2.c'. GNU CC version 2 compiled with GNU CC (any + version) seems not to have this problem. + + See *Note Sun Install::, for information on installing GNU CC on + Sun systems. + +`i[345]86-*-winnt3.5' + This version requires a GAS that has not yet been released. Until + it is, you can get a prebuilt binary version via anonymous ftp from + `cs.washington.edu:pub/gnat' or `cs.nyu.edu:pub/gnat'. You must + also use the Microsoft header files from the Windows NT 3.5 SDK. + Find these on the CDROM in the `/mstools/h' directory dated + 9/4/94. You must use a fixed version of Microsoft linker made + especially for NT 3.5, which is also is available on the NT 3.5 + SDK CDROM. If you do not have this linker, can you also use the + linker from Visual C/C++ 1.0 or 2.0. + + Installing GNU CC for NT builds a wrapper linker, called `ld.exe', + which mimics the behaviour of Unix `ld' in the specification of + libraries (`-L' and `-l'). `ld.exe' looks for both Unix and + Microsoft named libraries. For example, if you specify `-lfoo', + `ld.exe' will look first for `libfoo.a' and then for `foo.lib'. + + You may install GNU CC for Windows NT in one of two ways, + depending on whether or not you have a Unix-like shell and various + Unix-like utilities. + + 1. If you do not have a Unix-like shell and few Unix-like + utilities, you will use a DOS style batch script called + `configure.bat'. Invoke it as `configure winnt' from an + MSDOS console window or from the program manager dialog box. + `configure.bat' assumes you have already installed and have + in your path a Unix-like `sed' program which is used to + create a working `Makefile' from `Makefile.in'. + + `Makefile' uses the Microsoft Nmake program maintenance + utility and the Visual C/C++ V8.00 compiler to build GNU CC. + You need only have the utilities `sed' and `touch' to use + this installation method, which only automatically builds the + compiler itself. You must then examine what `fixinc.winnt' + does, edit the header files by hand and build `libgcc.a' + manually. + + 2. The second type of installation assumes you are running a + Unix-like shell, have a complete suite of Unix-like utilities + in your path, and have a previous version of GNU CC already + installed, either through building it via the above + installation method or acquiring a pre-built binary. In this + case, use the `configure' script in the normal fashion. + +`i860-intel-osf1' + This is the Paragon. If you have version 1.0 of the operating + system, you need to take special steps to build GNU CC due to + peculiarities of the system. Newer system versions have no + problem. See the section `Installation Problems' in the GNU CC + Manual. + +`*-lynx-lynxos' + LynxOS 2.2 and earlier comes with GNU CC 1.x already installed as + `/bin/gcc'. You should compile with this instead of `/bin/cc'. + You can tell GNU CC to use the GNU assembler and linker, by + specifying `--with-gnu-as --with-gnu-ld' when configuring. These + will produce COFF format object files and executables; otherwise + GNU CC will use the installed tools, which produce `a.out' format + executables. + +`m32r-*-elf' + Mitsubishi M32R processor. This configuration is intended for + embedded systems. + +`m68000-hp-bsd' + HP 9000 series 200 running BSD. Note that the C compiler that + comes with this system cannot compile GNU CC; contact + `law@cygnus.com' to get binaries of GNU CC for bootstrapping. + +`m68k-altos' + Altos 3068. You must use the GNU assembler, linker and debugger. + Also, you must fix a kernel bug. Details in the file + `README.ALTOS'. + +`m68k-apple-aux' + Apple Macintosh running A/UX. You may configure GCC to use + either the system assembler and linker or the GNU assembler and + linker. You should use the GNU configuration if you can, + especially if you also want to use GNU C++. You enabled that + configuration with + the `--with-gnu-as' and `--with-gnu-ld' + options to `configure'. + + Note the C compiler that comes with this system cannot compile GNU + CC. You can find binaries of GNU CC for bootstrapping on + `jagubox.gsfc.nasa.gov'. You will also a patched version of + `/bin/ld' there that raises some of the arbitrary limits found in + the original. + +`m68k-att-sysv' + AT&T 3b1, a.k.a. 7300 PC. Special procedures are needed to + compile GNU CC with this machine's standard C compiler, due to + bugs in that compiler. You can bootstrap it more easily with + previous versions of GNU CC if you have them. + + Installing GNU CC on the 3b1 is difficult if you do not already + have GNU CC running, due to bugs in the installed C compiler. + However, the following procedure might work. We are unable to + test it. + + 1. Comment out the `#include "config.h"' line near the start of + `cccp.c' and do `make cpp'. This makes a preliminary version + of GNU cpp. + + 2. Save the old `/lib/cpp' and copy the preliminary GNU cpp to + that file name. + + 3. Undo your change in `cccp.c', or reinstall the original + version, and do `make cpp' again. + + 4. Copy this final version of GNU cpp into `/lib/cpp'. + + 5. Replace every occurrence of `obstack_free' in the file + `tree.c' with `_obstack_free'. + + 6. Run `make' to get the first-stage GNU CC. + + 7. Reinstall the original version of `/lib/cpp'. + + 8. Now you can compile GNU CC with itself and install it in the + normal fashion. + +`m68k-bull-sysv' + Bull DPX/2 series 200 and 300 with BOS-2.00.45 up to BOS-2.01. GNU + CC works either with native assembler or GNU assembler. You can use + GNU assembler with native coff generation by providing + `--with-gnu-as' to the configure script or use GNU assembler with + dbx-in-coff encapsulation by providing `--with-gnu-as --stabs'. + For any problem with native assembler or for availability of the + DPX/2 port of GAS, contact `F.Pierresteguy@frcl.bull.fr'. + +`m68k-crds-unox' + Use `configure unos' for building on Unos. + + The Unos assembler is named `casm' instead of `as'. For some + strange reason linking `/bin/as' to `/bin/casm' changes the + behavior, and does not work. So, when installing GNU CC, you + should install the following script as `as' in the subdirectory + where the passes of GCC are installed: + + #!/bin/sh + casm $* + + The default Unos library is named `libunos.a' instead of `libc.a'. + To allow GNU CC to function, either change all references to + `-lc' in `gcc.c' to `-lunos' or link `/lib/libc.a' to + `/lib/libunos.a'. + + When compiling GNU CC with the standard compiler, to overcome bugs + in the support of `alloca', do not use `-O' when making stage 2. + Then use the stage 2 compiler with `-O' to make the stage 3 + compiler. This compiler will have the same characteristics as the + usual stage 2 compiler on other systems. Use it to make a stage 4 + compiler and compare that with stage 3 to verify proper + compilation. + + (Perhaps simply defining `ALLOCA' in `x-crds' as described in the + comments there will make the above paragraph superfluous. Please + inform us of whether this works.) + + Unos uses memory segmentation instead of demand paging, so you + will need a lot of memory. 5 Mb is barely enough if no other + tasks are running. If linking `cc1' fails, try putting the object + files into a library and linking from that library. + +`m68k-hp-hpux' + HP 9000 series 300 or 400 running HP-UX. HP-UX version 8.0 has a + bug in the assembler that prevents compilation of GNU CC. To fix + it, get patch PHCO_4484 from HP. + + In addition, if you wish to use gas `--with-gnu-as' you must use + gas version 2.1 or later, and you must use the GNU linker version + 2.1 or later. Earlier versions of gas relied upon a program which + converted the gas output into the native HP-UX format, but that + program has not been kept up to date. gdb does not understand + that native HP-UX format, so you must use gas if you wish to use + gdb. + +`m68k-sun' + Sun 3. We do not provide a configuration file to use the Sun FPA + by default, because programs that establish signal handlers for + floating point traps inherently cannot work with the FPA. + + See *Note Sun Install::, for information on installing GNU CC on + Sun systems. + +`m88k-*-svr3' + Motorola m88k running the AT&T/Unisoft/Motorola V.3 reference port. + These systems tend to use the Green Hills C, revision 1.8.5, as the + standard C compiler. There are apparently bugs in this compiler + that result in object files differences between stage 2 and stage + 3. If this happens, make the stage 4 compiler and compare it to + the stage 3 compiler. If the stage 3 and stage 4 object files are + identical, this suggests you encountered a problem with the + standard C compiler; the stage 3 and 4 compilers may be usable. + + It is best, however, to use an older version of GNU CC for + bootstrapping if you have one. + +`m88k-*-dgux' + Motorola m88k running DG/UX. To build 88open BCS native or cross + compilers on DG/UX, specify the configuration name as + `m88k-*-dguxbcs' and build in the 88open BCS software development + environment. To build ELF native or cross compilers on DG/UX, + specify `m88k-*-dgux' and build in the DG/UX ELF development + environment. You set the software development environment by + issuing `sde-target' command and specifying either `m88kbcs' or + `m88kdguxelf' as the operand. + + If you do not specify a configuration name, `configure' guesses the + configuration based on the current software development + environment. + +`m88k-tektronix-sysv3' + Tektronix XD88 running UTekV 3.2e. Do not turn on optimization + while building stage1 if you bootstrap with the buggy Green Hills + compiler. Also, The bundled LAI System V NFS is buggy so if you + build in an NFS mounted directory, start from a fresh reboot, or + avoid NFS all together. Otherwise you may have trouble getting + clean comparisons between stages. + +`mips-mips-bsd' + MIPS machines running the MIPS operating system in BSD mode. It's + possible that some old versions of the system lack the functions + `memcpy', `memcmp', and `memset'. If your system lacks these, you + must remove or undo the definition of `TARGET_MEM_FUNCTIONS' in + `mips-bsd.h'. + + The MIPS C compiler needs to be told to increase its table size + for switch statements with the `-Wf,-XNg1500' option in order to + compile `cp/parse.c'. If you use the `-O2' optimization option, + you also need to use `-Olimit 3000'. Both of these options are + automatically generated in the `Makefile' that the shell script + `configure' builds. If you override the `CC' make variable and + use the MIPS compilers, you may need to add `-Wf,-XNg1500 -Olimit + 3000'. + +`mips-mips-riscos*' + The MIPS C compiler needs to be told to increase its table size + for switch statements with the `-Wf,-XNg1500' option in order to + compile `cp/parse.c'. If you use the `-O2' optimization option, + you also need to use `-Olimit 3000'. Both of these options are + automatically generated in the `Makefile' that the shell script + `configure' builds. If you override the `CC' make variable and + use the MIPS compilers, you may need to add `-Wf,-XNg1500 -Olimit + 3000'. + + MIPS computers running RISC-OS can support four different + personalities: default, BSD 4.3, System V.3, and System V.4 (older + versions of RISC-OS don't support V.4). To configure GCC for + these platforms use the following configurations: + + `mips-mips-riscos`rev'' + Default configuration for RISC-OS, revision `rev'. + + `mips-mips-riscos`rev'bsd' + BSD 4.3 configuration for RISC-OS, revision `rev'. + + `mips-mips-riscos`rev'sysv4' + System V.4 configuration for RISC-OS, revision `rev'. + + `mips-mips-riscos`rev'sysv' + System V.3 configuration for RISC-OS, revision `rev'. + + The revision `rev' mentioned above is the revision of RISC-OS to + use. You must reconfigure GCC when going from a RISC-OS revision + 4 to RISC-OS revision 5. This has the effect of avoiding a linker + bug. + +`mips-sgi-*' + In order to compile GCC on an SGI running IRIX 4, the "c.hdr.lib" + option must be installed from the CD-ROM supplied from Silicon + Graphics. This is found on the 2nd CD in release 4.0.1. + + In order to compile GCC on an SGI running IRIX 5, the + "compiler_dev.hdr" subsystem must be installed from the IDO CD-ROM + supplied by Silicon Graphics. + + `make compare' may fail on version 5 of IRIX unless you add + `-save-temps' to `CFLAGS'. On these systems, the name of the + assembler input file is stored in the object file, and that makes + comparison fail if it differs between the `stage1' and `stage2' + compilations. The option `-save-temps' forces a fixed name to be + used for the assembler input file, instead of a randomly chosen + name in `/tmp'. Do not add `-save-temps' unless the comparisons + fail without that option. If you do you `-save-temps', you will + have to manually delete the `.i' and `.s' files after each series + of compilations. + + The MIPS C compiler needs to be told to increase its table size + for switch statements with the `-Wf,-XNg1500' option in order to + compile `cp/parse.c'. If you use the `-O2' optimization option, + you also need to use `-Olimit 3000'. Both of these options are + automatically generated in the `Makefile' that the shell script + `configure' builds. If you override the `CC' make variable and + use the MIPS compilers, you may need to add `-Wf,-XNg1500 -Olimit + 3000'. + + On Irix version 4.0.5F, and perhaps on some other versions as well, + there is an assembler bug that reorders instructions incorrectly. + To work around it, specify the target configuration + `mips-sgi-irix4loser'. This configuration inhibits assembler + optimization. + + In a compiler configured with target `mips-sgi-irix4', you can turn + off assembler optimization by using the `-noasmopt' option. This + compiler option passes the option `-O0' to the assembler, to + inhibit reordering. + + The `-noasmopt' option can be useful for testing whether a problem + is due to erroneous assembler reordering. Even if a problem does + not go away with `-noasmopt', it may still be due to assembler + reordering--perhaps GNU CC itself was miscompiled as a result. + + To enable debugging under Irix 5, you must use GNU as 2.5 or later, + and use the `--with-gnu-as' configure option when configuring gcc. + GNU as is distributed as part of the binutils package. + +`mips-sony-sysv' + Sony MIPS NEWS. This works in NEWSOS 5.0.1, but not in 5.0.2 + (which uses ELF instead of COFF). Support for 5.0.2 will probably + be provided soon by volunteers. In particular, the linker does + not like the code generated by GCC when shared libraries are + linked in. + +`ns32k-encore' + Encore ns32000 system. Encore systems are supported only under + BSD. + +`ns32k-*-genix' + National Semiconductor ns32000 system. Genix has bugs in `alloca' + and `malloc'; you must get the compiled versions of these from GNU + Emacs. + +`ns32k-sequent' + Go to the Berkeley universe before compiling. + +`ns32k-utek' + UTEK ns32000 system ("merlin"). The C compiler that comes with + this system cannot compile GNU CC; contact `tektronix!reed!mason' + to get binaries of GNU CC for bootstrapping. + +`romp-*-aos' +`romp-*-mach' + The only operating systems supported for the IBM RT PC are AOS and + MACH. GNU CC does not support AIX running on the RT. We + recommend you compile GNU CC with an earlier version of itself; if + you compile GNU CC with `hc', the Metaware compiler, it will work, + but you will get mismatches between the stage 2 and stage 3 + compilers in various files. These errors are minor differences in + some floating-point constants and can be safely ignored; the stage + 3 compiler is correct. + +`rs6000-*-aix' +`powerpc-*-aix' + Various early versions of each release of the IBM XLC compiler + will not bootstrap GNU CC. Symptoms include differences between + the stage2 and stage3 object files, and errors when compiling + `libgcc.a' or `enquire'. Known problematic releases include: + xlc-1.2.1.8, xlc-1.3.0.0 (distributed with AIX 3.2.5), and + xlc-1.3.0.19. Both xlc-1.2.1.28 and xlc-1.3.0.24 (PTF 432238) are + known to produce working versions of GNU CC, but most other recent + releases correctly bootstrap GNU CC. + + Release 4.3.0 of AIX and ones prior to AIX 3.2.4 include a version + of the IBM assembler which does not accept debugging directives: + assembler updates are available as PTFs. Also, if you are using + AIX 3.2.5 or greater and the GNU assembler, you must have a + version modified after October 16th, 1995 in order for the GNU C + compiler to build. See the file `README.RS6000' for more details + on any of these problems. + + GNU CC does not yet support the 64-bit PowerPC instructions. + + Objective C does not work on this architecture because it makes + assumptions that are incompatible with the calling conventions. + + AIX on the RS/6000 provides support (NLS) for environments outside + of the United States. Compilers and assemblers use NLS to support + locale-specific representations of various objects including + floating-point numbers ("." vs "," for separating decimal + fractions). There have been problems reported where the library + linked with GNU CC does not produce the same floating-point + formats that the assembler accepts. If you have this problem, set + the LANG environment variable to "C" or "En_US". + + Due to changes in the way that GNU CC invokes the binder (linker) + for AIX 4.1, you may now receive warnings of duplicate symbols + from the link step that were not reported before. The assembly + files generated by GNU CC for AIX have always included multiple + symbol definitions for certain global variable and function + declarations in the original program. The warnings should not + prevent the linker from producing a correct library or runnable + executable. + + By default, AIX 4.1 produces code that can be used on either Power + or PowerPC processors. + + You can specify a default version for the `-mcpu='CPU_TYPE switch + by using the configure option `--with-cpu-'CPU_TYPE. + +`powerpc-*-elf' +`powerpc-*-sysv4' + PowerPC system in big endian mode, running System V.4. + + You can specify a default version for the `-mcpu='CPU_TYPE switch + by using the configure option `--with-cpu-'CPU_TYPE. + +`powerpc-*-linux-gnu' + PowerPC system in big endian mode, running the Linux-based GNU + system. + + You can specify a default version for the `-mcpu='CPU_TYPE switch + by using the configure option `--with-cpu-'CPU_TYPE. + +`powerpc-*-eabiaix' + Embedded PowerPC system in big endian mode with -mcall-aix + selected as the default. + + You can specify a default version for the `-mcpu='CPU_TYPE switch + by using the configure option `--with-cpu-'CPU_TYPE. + +`powerpc-*-eabisim' + Embedded PowerPC system in big endian mode for use in running + under the PSIM simulator. + + You can specify a default version for the `-mcpu='CPU_TYPE switch + by using the configure option `--with-cpu-'CPU_TYPE. + +`powerpc-*-eabi' + Embedded PowerPC system in big endian mode. + + You can specify a default version for the `-mcpu='CPU_TYPE switch + by using the configure option `--with-cpu-'CPU_TYPE. + +`powerpcle-*-elf' +`powerpcle-*-sysv4' + PowerPC system in little endian mode, running System V.4. + + You can specify a default version for the `-mcpu='CPU_TYPE switch + by using the configure option `--with-cpu-'CPU_TYPE. + +`powerpcle-*-solaris2*' + PowerPC system in little endian mode, running Solaris 2.5.1 or + higher. + + You can specify a default version for the `-mcpu='CPU_TYPE switch + by using the configure option `--with-cpu-'CPU_TYPE. Beta + versions of the Sun 4.0 compiler do not seem to be able to build + GNU CC correctly. There are also problems with the host assembler + and linker that are fixed by using the GNU versions of these tools. + +`powerpcle-*-eabisim' + Embedded PowerPC system in little endian mode for use in running + under the PSIM simulator. + +`powerpcle-*-eabi' + Embedded PowerPC system in little endian mode. + + You can specify a default version for the `-mcpu='CPU_TYPE switch + by using the configure option `--with-cpu-'CPU_TYPE. + +`powerpcle-*-winnt' +`powerpcle-*-pe' + PowerPC system in little endian mode running Windows NT. + + You can specify a default version for the `-mcpu='CPU_TYPE switch + by using the configure option `--with-cpu-'CPU_TYPE. + +`vax-dec-ultrix' + Don't try compiling with Vax C (`vcc'). It produces incorrect code + in some cases (for example, when `alloca' is used). + + Meanwhile, compiling `cp/parse.c' with pcc does not work because of + an internal table size limitation in that compiler. To avoid this + problem, compile just the GNU C compiler first, and use it to + recompile building all the languages that you want to run. + +`sparc-sun-*' + See *Note Sun Install::, for information on installing GNU CC on + Sun systems. + +`vax-dec-vms' + See *Note VMS Install::, for details on how to install GNU CC on + VMS. + +`we32k-*-*' + These computers are also known as the 3b2, 3b5, 3b20 and other + similar names. (However, the 3b1 is actually a 68000; see *Note + Configurations::.) + + Don't use `-g' when compiling with the system's compiler. The + system's linker seems to be unable to handle such a large program + with debugging information. + + The system's compiler runs out of capacity when compiling `stmt.c' + in GNU CC. You can work around this by building `cpp' in GNU CC + first, then use that instead of the system's preprocessor with the + system's C compiler to compile `stmt.c'. Here is how: + + mv /lib/cpp /lib/cpp.att + cp cpp /lib/cpp.gnu + echo '/lib/cpp.gnu -traditional ${1+"$@"}' > /lib/cpp + chmod +x /lib/cpp + + The system's compiler produces bad code for some of the GNU CC + optimization files. So you must build the stage 2 compiler without + optimization. Then build a stage 3 compiler with optimization. + That executable should work. Here are the necessary commands: + + make LANGUAGES=c CC=stage1/xgcc CFLAGS="-Bstage1/ -g" + make stage2 + make CC=stage2/xgcc CFLAGS="-Bstage2/ -g -O" + + You may need to raise the ULIMIT setting to build a C++ compiler, + as the file `cc1plus' is larger than one megabyte. + + +File: INSTALL, Node: Other Dir, Next: Cross-Compiler, Prev: Configurations, Up: Installation + +Compilation in a Separate Directory +=================================== + + If you wish to build the object files and executables in a directory +other than the one containing the source files, here is what you must +do differently: + + 1. Make sure you have a version of Make that supports the `VPATH' + feature. (GNU Make supports it, as do Make versions on most BSD + systems.) + + 2. If you have ever run `configure' in the source directory, you must + undo the configuration. Do this by running: + + make distclean + + 3. Go to the directory in which you want to build the compiler before + running `configure': + + mkdir gcc-sun3 + cd gcc-sun3 + + On systems that do not support symbolic links, this directory must + be on the same file system as the source code directory. + + 4. Specify where to find `configure' when you run it: + + ../gcc/configure ... + + This also tells `configure' where to find the compiler sources; + `configure' takes the directory from the file name that was used to + invoke it. But if you want to be sure, you can specify the source + directory with the `--srcdir' option, like this: + + ../gcc/configure --srcdir=../gcc OTHER OPTIONS + + The directory you specify with `--srcdir' need not be the same as + the one that `configure' is found in. + + Now, you can run `make' in that directory. You need not repeat the +configuration steps shown above, when ordinary source files change. You +must, however, run `configure' again when the configuration files +change, if your system does not support symbolic links. + + +File: INSTALL, Node: Cross-Compiler, Next: Sun Install, Prev: Other Dir, Up: Installation + +Building and Installing a Cross-Compiler +======================================== + + GNU CC can function as a cross-compiler for many machines, but not +all. + + * Cross-compilers for the Mips as target using the Mips assembler + currently do not work, because the auxiliary programs + `mips-tdump.c' and `mips-tfile.c' can't be compiled on anything + but a Mips. It does work to cross compile for a Mips if you use + the GNU assembler and linker. + + * Cross-compilers between machines with different floating point + formats have not all been made to work. GNU CC now has a floating + point emulator with which these can work, but each target machine + description needs to be updated to take advantage of it. + + * Cross-compilation between machines of different word sizes is + somewhat problematic and sometimes does not work. + + Since GNU CC generates assembler code, you probably need a +cross-assembler that GNU CC can run, in order to produce object files. +If you want to link on other than the target machine, you need a +cross-linker as well. You also need header files and libraries suitable +for the target machine that you can install on the host machine. + +* Menu: + +* Steps of Cross:: Using a cross-compiler involves several steps + that may be carried out on different machines. +* Configure Cross:: Configuring a cross-compiler. +* Tools and Libraries:: Where to put the linker and assembler, and the C library. +* Cross Headers:: Finding and installing header files + for a cross-compiler. +* Cross Runtime:: Supplying arithmetic runtime routines (`libgcc1.a'). +* Build Cross:: Actually compiling the cross-compiler. + + +File: INSTALL, Node: Steps of Cross, Next: Configure Cross, Up: Cross-Compiler + +Steps of Cross-Compilation +-------------------------- + + To compile and run a program using a cross-compiler involves several +steps: + + * Run the cross-compiler on the host machine to produce assembler + files for the target machine. This requires header files for the + target machine. + + * Assemble the files produced by the cross-compiler. You can do this + either with an assembler on the target machine, or with a + cross-assembler on the host machine. + + * Link those files to make an executable. You can do this either + with a linker on the target machine, or with a cross-linker on the + host machine. Whichever machine you use, you need libraries and + certain startup files (typically `crt....o') for the target + machine. + + It is most convenient to do all of these steps on the same host +machine, since then you can do it all with a single invocation of GNU +CC. This requires a suitable cross-assembler and cross-linker. For +some targets, the GNU assembler and linker are available. + + +File: INSTALL, Node: Configure Cross, Next: Tools and Libraries, Prev: Steps of Cross, Up: Cross-Compiler + +Configuring a Cross-Compiler +---------------------------- + + To build GNU CC as a cross-compiler, you start out by running +`configure'. Use the `--target=TARGET' to specify the target type. If +`configure' was unable to correctly identify the system you are running +on, also specify the `--build=BUILD' option. For example, here is how +to configure for a cross-compiler that produces code for an HP 68030 +system running BSD on a system that `configure' can correctly identify: + + ./configure --target=m68k-hp-bsd4.3 + + +File: INSTALL, Node: Tools and Libraries, Next: Cross Headers, Prev: Configure Cross, Up: Cross-Compiler + +Tools and Libraries for a Cross-Compiler +---------------------------------------- + + If you have a cross-assembler and cross-linker available, you should +install them now. Put them in the directory `/usr/local/TARGET/bin'. +Here is a table of the tools you should put in this directory: + +`as' + This should be the cross-assembler. + +`ld' + This should be the cross-linker. + +`ar' + This should be the cross-archiver: a program which can manipulate + archive files (linker libraries) in the target machine's format. + +`ranlib' + This should be a program to construct a symbol table in an archive + file. + + The installation of GNU CC will find these programs in that +directory, and copy or link them to the proper place to for the +cross-compiler to find them when run later. + + The easiest way to provide these files is to build the Binutils +package and GAS. Configure them with the same `--host' and `--target' +options that you use for configuring GNU CC, then build and install +them. They install their executables automatically into the proper +directory. Alas, they do not support all the targets that GNU CC +supports. + + If you want to install libraries to use with the cross-compiler, +such as a standard C library, put them in the directory +`/usr/local/TARGET/lib'; installation of GNU CC copies all the files in +that subdirectory into the proper place for GNU CC to find them and +link with them. Here's an example of copying some libraries from a +target machine: + + ftp TARGET-MACHINE + lcd /usr/local/TARGET/lib + cd /lib + get libc.a + cd /usr/lib + get libg.a + get libm.a + quit + +The precise set of libraries you'll need, and their locations on the +target machine, vary depending on its operating system. + + Many targets require "start files" such as `crt0.o' and `crtn.o' +which are linked into each executable; these too should be placed in +`/usr/local/TARGET/lib'. There may be several alternatives for +`crt0.o', for use with profiling or other compilation options. Check +your target's definition of `STARTFILE_SPEC' to find out what start +files it uses. Here's an example of copying these files from a target +machine: + + ftp TARGET-MACHINE + lcd /usr/local/TARGET/lib + prompt + cd /lib + mget *crt*.o + cd /usr/lib + mget *crt*.o + quit + + +File: INSTALL, Node: Cross Runtime, Next: Build Cross, Prev: Cross Headers, Up: Cross-Compiler + +`libgcc.a' and Cross-Compilers +------------------------------ + + Code compiled by GNU CC uses certain runtime support functions +implicitly. Some of these functions can be compiled successfully with +GNU CC itself, but a few cannot be. These problem functions are in the +source file `libgcc1.c'; the library made from them is called +`libgcc1.a'. + + When you build a native compiler, these functions are compiled with +some other compiler-the one that you use for bootstrapping GNU CC. +Presumably it knows how to open code these operations, or else knows how +to call the run-time emulation facilities that the machine comes with. +But this approach doesn't work for building a cross-compiler. The +compiler that you use for building knows about the host system, not the +target system. + + So, when you build a cross-compiler you have to supply a suitable +library `libgcc1.a' that does the job it is expected to do. + + To compile `libgcc1.c' with the cross-compiler itself does not work. +The functions in this file are supposed to implement arithmetic +operations that GNU CC does not know how to open code for your target +machine. If these functions are compiled with GNU CC itself, they will +compile into infinite recursion. + + On any given target, most of these functions are not needed. If GNU +CC can open code an arithmetic operation, it will not call these +functions to perform the operation. It is possible that on your target +machine, none of these functions is needed. If so, you can supply an +empty library as `libgcc1.a'. + + Many targets need library support only for multiplication and +division. If you are linking with a library that contains functions for +multiplication and division, you can tell GNU CC to call them directly +by defining the macros `MULSI3_LIBCALL', and the like. These macros +need to be defined in the target description macro file. For some +targets, they are defined already. This may be sufficient to avoid the +need for libgcc1.a; if so, you can supply an empty library. + + Some targets do not have floating point instructions; they need other +functions in `libgcc1.a', which do floating arithmetic. Recent +versions of GNU CC have a file which emulates floating point. With a +certain amount of work, you should be able to construct a floating +point emulator that can be used as `libgcc1.a'. Perhaps future +versions will contain code to do this automatically and conveniently. +That depends on whether someone wants to implement it. + + Some embedded targets come with all the necessary `libgcc1.a' +routines written in C or assembler. These targets build `libgcc1.a' +automatically and you do not need to do anything special for them. +Other embedded targets do not need any `libgcc1.a' routines since all +the necessary operations are supported by the hardware. + + If your target system has another C compiler, you can configure GNU +CC as a native compiler on that machine, build just `libgcc1.a' with +`make libgcc1.a' on that machine, and use the resulting file with the +cross-compiler. To do this, execute the following on the target +machine: + + cd TARGET-BUILD-DIR + ./configure --host=sparc --target=sun3 + make libgcc1.a + +And then this on the host machine: + + ftp TARGET-MACHINE + binary + cd TARGET-BUILD-DIR + get libgcc1.a + quit + + Another way to provide the functions you need in `libgcc1.a' is to +define the appropriate `perform_...' macros for those functions. If +these definitions do not use the C arithmetic operators that they are +meant to implement, you should be able to compile them with the +cross-compiler you are building. (If these definitions already exist +for your target file, then you are all set.) + + To build `libgcc1.a' using the perform macros, use +`LIBGCC1=libgcc1.a OLDCC=./xgcc' when building the compiler. +Otherwise, you should place your replacement library under the name +`libgcc1.a' in the directory in which you will build the +cross-compiler, before you run `make'. + + +File: INSTALL, Node: Cross Headers, Next: Cross Runtime, Prev: Tools and Libraries, Up: Cross-Compiler + +Cross-Compilers and Header Files +-------------------------------- + + If you are cross-compiling a standalone program or a program for an +embedded system, then you may not need any header files except the few +that are part of GNU CC (and those of your program). However, if you +intend to link your program with a standard C library such as `libc.a', +then you probably need to compile with the header files that go with +the library you use. + + The GNU C compiler does not come with these files, because (1) they +are system-specific, and (2) they belong in a C library, not in a +compiler. + + If the GNU C library supports your target machine, then you can get +the header files from there (assuming you actually use the GNU library +when you link your program). + + If your target machine comes with a C compiler, it probably comes +with suitable header files also. If you make these files accessible +from the host machine, the cross-compiler can use them also. + + Otherwise, you're on your own in finding header files to use when +cross-compiling. + + When you have found suitable header files, put them in the directory +`/usr/local/TARGET/include', before building the cross compiler. Then +installation will run fixincludes properly and install the corrected +versions of the header files where the compiler will use them. + + Provide the header files before you build the cross-compiler, because +the build stage actually runs the cross-compiler to produce parts of +`libgcc.a'. (These are the parts that *can* be compiled with GNU CC.) +Some of them need suitable header files. + + Here's an example showing how to copy the header files from a target +machine. On the target machine, do this: + + (cd /usr/include; tar cf - .) > tarfile + + Then, on the host machine, do this: + + ftp TARGET-MACHINE + lcd /usr/local/TARGET/include + get tarfile + quit + tar xf tarfile + + +File: INSTALL, Node: Build Cross, Prev: Cross Runtime, Up: Cross-Compiler + +Actually Building the Cross-Compiler +------------------------------------ + + Now you can proceed just as for compiling a single-machine compiler +through the step of building stage 1. If you have not provided some +sort of `libgcc1.a', then compilation will give up at the point where +it needs that file, printing a suitable error message. If you do +provide `libgcc1.a', then building the compiler will automatically +compile and link a test program called `libgcc1-test'; if you get +errors in the linking, it means that not all of the necessary routines +in `libgcc1.a' are available. + + You must provide the header file `float.h'. One way to do this is +to compile `enquire' and run it on your target machine. The job of +`enquire' is to run on the target machine and figure out by experiment +the nature of its floating point representation. `enquire' records its +findings in the header file `float.h'. If you can't produce this file +by running `enquire' on the target machine, then you will need to come +up with a suitable `float.h' in some other way (or else, avoid using it +in your programs). + + Do not try to build stage 2 for a cross-compiler. It doesn't work to +rebuild GNU CC as a cross-compiler using the cross-compiler, because +that would produce a program that runs on the target machine, not on the +host. For example, if you compile a 386-to-68030 cross-compiler with +itself, the result will not be right either for the 386 (because it was +compiled into 68030 code) or for the 68030 (because it was configured +for a 386 as the host). If you want to compile GNU CC into 68030 code, +whether you compile it on a 68030 or with a cross-compiler on a 386, you +must specify a 68030 as the host when you configure it. + + To install the cross-compiler, use `make install', as usual. + + +File: INSTALL, Node: Sun Install, Next: VMS Install, Prev: Cross-Compiler, Up: Installation + +Installing GNU CC on the Sun +============================ + + On Solaris, do not use the linker or other tools in `/usr/ucb' to +build GNU CC. Use `/usr/ccs/bin'. + + If the assembler reports `Error: misaligned data' when bootstrapping, +you are probably using an obsolete version of the GNU assembler. +Upgrade to the latest version of GNU `binutils', or use the Solaris +assembler. + + Make sure the environment variable `FLOAT_OPTION' is not set when +you compile `libgcc.a'. If this option were set to `f68881' when +`libgcc.a' is compiled, the resulting code would demand to be linked +with a special startup file and would not link properly without special +pains. + + There is a bug in `alloca' in certain versions of the Sun library. +To avoid this bug, install the binaries of GNU CC that were compiled by +GNU CC. They use `alloca' as a built-in function and never the one in +the library. + + Some versions of the Sun compiler crash when compiling GNU CC. The +problem is a segmentation fault in cpp. This problem seems to be due to +the bulk of data in the environment variables. You may be able to avoid +it by using the following command to compile GNU CC with Sun CC: + + make CC="TERMCAP=x OBJS=x LIBFUNCS=x STAGESTUFF=x cc" + + SunOS 4.1.3 and 4.1.3_U1 have bugs that can cause intermittent core +dumps when compiling GNU CC. A common symptom is an internal compiler +error which does not recur if you run it again. To fix the problem, +install Sun recommended patch 100726 (for SunOS 4.1.3) or 101508 (for +SunOS 4.1.3_U1), or upgrade to a later SunOS release. + + +File: INSTALL, Node: VMS Install, Next: Collect2, Prev: Sun Install, Up: Installation + +Installing GNU CC on VMS +======================== + + The VMS version of GNU CC is distributed in a backup saveset +containing both source code and precompiled binaries. + + To install the `gcc' command so you can use the compiler easily, in +the same manner as you use the VMS C compiler, you must install the VMS +CLD file for GNU CC as follows: + + 1. Define the VMS logical names `GNU_CC' and `GNU_CC_INCLUDE' to + point to the directories where the GNU CC executables + (`gcc-cpp.exe', `gcc-cc1.exe', etc.) and the C include files are + kept respectively. This should be done with the commands: + + $ assign /system /translation=concealed - + disk:[gcc.] gnu_cc + $ assign /system /translation=concealed - + disk:[gcc.include.] gnu_cc_include + + with the appropriate disk and directory names. These commands can + be placed in your system startup file so they will be executed + whenever the machine is rebooted. You may, if you choose, do this + via the `GCC_INSTALL.COM' script in the `[GCC]' directory. + + 2. Install the `GCC' command with the command line: + + $ set command /table=sys$common:[syslib]dcltables - + /output=sys$common:[syslib]dcltables gnu_cc:[000000]gcc + $ install replace sys$common:[syslib]dcltables + + 3. To install the help file, do the following: + + $ library/help sys$library:helplib.hlb gcc.hlp + + Now you can invoke the compiler with a command like `gcc /verbose + file.c', which is equivalent to the command `gcc -v -c file.c' in + Unix. + + If you wish to use GNU C++ you must first install GNU CC, and then +perform the following steps: + + 1. Define the VMS logical name `GNU_GXX_INCLUDE' to point to the + directory where the preprocessor will search for the C++ header + files. This can be done with the command: + + $ assign /system /translation=concealed - + disk:[gcc.gxx_include.] gnu_gxx_include + + with the appropriate disk and directory name. If you are going to + be using a C++ runtime library, this is where its install + procedure will install its header files. + + 2. Obtain the file `gcc-cc1plus.exe', and place this in the same + directory that `gcc-cc1.exe' is kept. + + The GNU C++ compiler can be invoked with a command like `gcc /plus + /verbose file.cc', which is equivalent to the command `g++ -v -c + file.cc' in Unix. + + We try to put corresponding binaries and sources on the VMS +distribution tape. But sometimes the binaries will be from an older +version than the sources, because we don't always have time to update +them. (Use the `/version' option to determine the version number of +the binaries and compare it with the source file `version.c' to tell +whether this is so.) In this case, you should use the binaries you get +to recompile the sources. If you must recompile, here is how: + + 1. Execute the command procedure `vmsconfig.com' to set up the files + `tm.h', `config.h', `aux-output.c', and `md.', and to create files + `tconfig.h' and `hconfig.h'. This procedure also creates several + linker option files used by `make-cc1.com' and a data file used by + `make-l2.com'. + + $ @vmsconfig.com + + 2. Setup the logical names and command tables as defined above. In + addition, define the VMS logical name `GNU_BISON' to point at the + to the directories where the Bison executable is kept. This + should be done with the command: + + $ assign /system /translation=concealed - + disk:[bison.] gnu_bison + + You may, if you choose, use the `INSTALL_BISON.COM' script in the + `[BISON]' directory. + + 3. Install the `BISON' command with the command line: + + $ set command /table=sys$common:[syslib]dcltables - + /output=sys$common:[syslib]dcltables - + gnu_bison:[000000]bison + $ install replace sys$common:[syslib]dcltables + + 4. Type `@make-gcc' to recompile everything (alternatively, submit + the file `make-gcc.com' to a batch queue). If you wish to build + the GNU C++ compiler as well as the GNU CC compiler, you must + first edit `make-gcc.com' and follow the instructions that appear + in the comments. + + 5. In order to use GCC, you need a library of functions which GCC + compiled code will call to perform certain tasks, and these + functions are defined in the file `libgcc2.c'. To compile this + you should use the command procedure `make-l2.com', which will + generate the library `libgcc2.olb'. `libgcc2.olb' should be built + using the compiler built from the same distribution that + `libgcc2.c' came from, and `make-gcc.com' will automatically do + all of this for you. + + To install the library, use the following commands: + + $ library gnu_cc:[000000]gcclib/delete=(new,eprintf) + $ library gnu_cc:[000000]gcclib/delete=L_* + $ library libgcc2/extract=*/output=libgcc2.obj + $ library gnu_cc:[000000]gcclib libgcc2.obj + + The first command simply removes old modules that will be replaced + with modules from `libgcc2' under different module names. The + modules `new' and `eprintf' may not actually be present in your + `gcclib.olb'--if the VMS librarian complains about those modules + not being present, simply ignore the message and continue on with + the next command. The second command removes the modules that + came from the previous version of the library `libgcc2.c'. + + Whenever you update the compiler on your system, you should also + update the library with the above procedure. + + 6. You may wish to build GCC in such a way that no files are written + to the directory where the source files reside. An example would + be the when the source files are on a read-only disk. In these + cases, execute the following DCL commands (substituting your + actual path names): + + $ assign dua0:[gcc.build_dir.]/translation=concealed, - + dua1:[gcc.source_dir.]/translation=concealed gcc_build + $ set default gcc_build:[000000] + + where the directory `dua1:[gcc.source_dir]' contains the source + code, and the directory `dua0:[gcc.build_dir]' is meant to contain + all of the generated object files and executables. Once you have + done this, you can proceed building GCC as described above. (Keep + in mind that `gcc_build' is a rooted logical name, and thus the + device names in each element of the search list must be an actual + physical device name rather than another rooted logical name). + + 7. *If you are building GNU CC with a previous version of GNU CC, you + also should check to see that you have the newest version of the + assembler*. In particular, GNU CC version 2 treats global constant + variables slightly differently from GNU CC version 1, and GAS + version 1.38.1 does not have the patches required to work with GCC + version 2. If you use GAS 1.38.1, then `extern const' variables + will not have the read-only bit set, and the linker will generate + warning messages about mismatched psect attributes for these + variables. These warning messages are merely a nuisance, and can + safely be ignored. + + If you are compiling with a version of GNU CC older than 1.33, + specify `/DEFINE=("inline=")' as an option in all the + compilations. This requires editing all the `gcc' commands in + `make-cc1.com'. (The older versions had problems supporting + `inline'.) Once you have a working 1.33 or newer GNU CC, you can + change this file back. + + 8. If you want to build GNU CC with the VAX C compiler, you will need + to make minor changes in `make-cccp.com' and `make-cc1.com' to + choose alternate definitions of `CC', `CFLAGS', and `LIBS'. See + comments in those files. However, you must also have a working + version of the GNU assembler (GNU as, aka GAS) as it is used as + the back-end for GNU CC to produce binary object modules and is + not included in the GNU CC sources. GAS is also needed to compile + `libgcc2' in order to build `gcclib' (see above); `make-l2.com' + expects to be able to find it operational in + `gnu_cc:[000000]gnu-as.exe'. + + To use GNU CC on VMS, you need the VMS driver programs `gcc.exe', + `gcc.com', and `gcc.cld'. They are distributed with the VMS + binaries (`gcc-vms') rather than the GNU CC sources. GAS is also + included in `gcc-vms', as is Bison. + + Once you have successfully built GNU CC with VAX C, you should use + the resulting compiler to rebuild itself. Before doing this, be + sure to restore the `CC', `CFLAGS', and `LIBS' definitions in + `make-cccp.com' and `make-cc1.com'. The second generation + compiler will be able to take advantage of many optimizations that + must be suppressed when building with other compilers. + + Under previous versions of GNU CC, the generated code would +occasionally give strange results when linked with the sharable +`VAXCRTL' library. Now this should work. + + Even with this version, however, GNU CC itself should not be linked +with the sharable `VAXCRTL'. The version of `qsort' in `VAXCRTL' has a +bug (known to be present in VMS versions V4.6 through V5.5) which +causes the compiler to fail. + + The executables are generated by `make-cc1.com' and `make-cccp.com' +use the object library version of `VAXCRTL' in order to make use of the +`qsort' routine in `gcclib.olb'. If you wish to link the compiler +executables with the shareable image version of `VAXCRTL', you should +edit the file `tm.h' (created by `vmsconfig.com') to define the macro +`QSORT_WORKAROUND'. + + `QSORT_WORKAROUND' is always defined when GNU CC is compiled with +VAX C, to avoid a problem in case `gcclib.olb' is not yet available. + + +File: INSTALL, Node: Collect2, Next: Header Dirs, Prev: VMS Install, Up: Installation + +`collect2' +========== + + GNU CC uses a utility called `collect2' on nearly all systems to +arrange to call various initialization functions at start time. + + The program `collect2' works by linking the program once and looking +through the linker output file for symbols with particular names +indicating they are constructor functions. If it finds any, it creates +a new temporary `.c' file containing a table of them, compiles it, and +links the program a second time including that file. + + The actual calls to the constructors are carried out by a subroutine +called `__main', which is called (automatically) at the beginning of +the body of `main' (provided `main' was compiled with GNU CC). Calling +`__main' is necessary, even when compiling C code, to allow linking C +and C++ object code together. (If you use `-nostdlib', you get an +unresolved reference to `__main', since it's defined in the standard +GCC library. Include `-lgcc' at the end of your compiler command line +to resolve this reference.) + + The program `collect2' is installed as `ld' in the directory where +the passes of the compiler are installed. When `collect2' needs to +find the *real* `ld', it tries the following file names: + + * `real-ld' in the directories listed in the compiler's search + directories. + + * `real-ld' in the directories listed in the environment variable + `PATH'. + + * The file specified in the `REAL_LD_FILE_NAME' configuration macro, + if specified. + + * `ld' in the compiler's search directories, except that `collect2' + will not execute itself recursively. + + * `ld' in `PATH'. + + "The compiler's search directories" means all the directories where +`gcc' searches for passes of the compiler. This includes directories +that you specify with `-B'. + + Cross-compilers search a little differently: + + * `real-ld' in the compiler's search directories. + + * `TARGET-real-ld' in `PATH'. + + * The file specified in the `REAL_LD_FILE_NAME' configuration macro, + if specified. + + * `ld' in the compiler's search directories. + + * `TARGET-ld' in `PATH'. + + `collect2' explicitly avoids running `ld' using the file name under +which `collect2' itself was invoked. In fact, it remembers up a list +of such names--in case one copy of `collect2' finds another copy (or +version) of `collect2' installed as `ld' in a second place in the +search path. + + `collect2' searches for the utilities `nm' and `strip' using the +same algorithm as above for `ld'. + + +File: INSTALL, Node: Header Dirs, Prev: Collect2, Up: Installation + +Standard Header File Directories +================================ + + `GCC_INCLUDE_DIR' means the same thing for native and cross. It is +where GNU CC stores its private include files, and also where GNU CC +stores the fixed include files. A cross compiled GNU CC runs +`fixincludes' on the header files in `$(tooldir)/include'. (If the +cross compilation header files need to be fixed, they must be installed +before GNU CC is built. If the cross compilation header files are +already suitable for ANSI C and GNU CC, nothing special need be done). + + `GPLUS_INCLUDE_DIR' means the same thing for native and cross. It +is where `g++' looks first for header files. The C++ library installs +only target independent header files in that directory. + + `LOCAL_INCLUDE_DIR' is used only for a native compiler. It is +normally `/usr/local/include'. GNU CC searches this directory so that +users can install header files in `/usr/local/include'. + + `CROSS_INCLUDE_DIR' is used only for a cross compiler. GNU CC +doesn't install anything there. + + `TOOL_INCLUDE_DIR' is used for both native and cross compilers. It +is the place for other packages to install header files that GNU CC will +use. For a cross-compiler, this is the equivalent of `/usr/include'. +When you build a cross-compiler, `fixincludes' processes any header +files in this directory. + + + +Tag Table: +Node: Installation351 +Node: Configurations26618 +Node: Other Dir65739 +Node: Cross-Compiler67454 +Node: Steps of Cross69284 +Node: Configure Cross70401 +Node: Tools and Libraries71037 +Node: Cross Runtime73475 +Node: Cross Headers77555 +Node: Build Cross79553 +Node: Sun Install81428 +Node: VMS Install83099 +Node: Collect293028 +Node: Header Dirs95592 + +End Tag Table diff --git a/gcc_arm/LANGUAGES b/gcc_arm/LANGUAGES new file mode 100755 index 0000000..c3d4223 --- /dev/null +++ b/gcc_arm/LANGUAGES @@ -0,0 +1,91 @@ +Right now there is no documentation for the GCC tree -> rtl interfaces +(or more generally the interfaces for adding new languages). + +Such documentation would be of great benefit to the project. Until such +time as we can formally start documenting the interface this file will +serve as a repository for information on these interface and any incompatable +changes we've made. + +Aug 31, 1998: + The interface to HANDLE_PRAGMA has changed. It now takes three arguments. + The first two are pointers to functions that should be used to read characters + from the input stream, and to push them back into the input stream respectively. + The third argument is a pointer to a null terminate string which is the first + word after #pragma. The expression supplied by HANDLE_PRAGMA should return + non-zero if it parsed and implemented the pragma. Otherwise it should return + zero, and leave the input stream as it was before the expression was evaluated. + + A new back-end definable macro has been added: INSERT_ATTRIBUTES. This macro + allows backend to add attributes to decls as they are created. + +Jun 10, 1998: + The interface to lang_decode_option has changed. It now uses and argc/argv + interface to allow for options that use more than one input string. The new + declaration is: int lang_decode_option (int argc, char** argv). It now + returns the number of input strings processed, or 0 if the option is + unknown. + +Jun 7, 1998: + Front-ends must now define lang_init_options. It is safe for this + function to do nothing. See c-lang.c. + +Apr 21, 1998: + Front ends which link with c-common or other files from the C/C++ + front-ends may need to handle TI types. Look for references to + [unsigned]int_DI_type_node in your front end. If you have references + to these variables, you'll need up update the front end. + + To update the front end you must mirror all the code which currently + deals with intDI_type_node to also handle intTI_type_node. + + +Apr 7, 1998: + The interface between toplev.c and the language front ends for opening the + source file has changed: + + o init_lex() has been renamed to init_parse (char *filename) where filename + is the name of the source file. + o The code in toplev.c which opened the source file should be moved to + the new init_parse function. + o toplev.c now calls finish_parse() instead of closing the source file + using fclose(). This should now be done in finish_parse, if necessary. + +Apr 1, 1998: + Front-ends must now define lang_print_xnode. It is safe for this + function to do nothing. See c-lang.c. + +Feb 1, 1998: + + GCC used to store structure sizes & offsets to elements as bitsize + quantities. This causes problems because a structure can only be + (target memsize / 8) bytes long (this may effect arrays too). This + is particularly problematical on machines with small address spaces. + + So: + + All trees that represent sizes in bits should have a TREE_TYPE of + bitsizetype (rather than sizetype). + + Accordingly, when such values are computed / initialized, care has to + be takes to use / compute the proper type. + + When a size in bits is converted into a size in bytes, which is expressed + in trees, care should be taken to change the tree's type again to sizetype. + + We've updated C, C++, Fortran & Objective-C to work with the new + scheme. Other languages will need to be updated accordingly. + Contact amylaar@cygnus.com for additional information. + +?? 1997: + + In an effort to decrease cache thrashing and useless loads we've changed the + third argument to the DEFTREECODE macro to be a single char. This will + effect languages that defined their own tree codes (usually in a .def file). + + Old way: + + DEFTREECODE (CLASS_METHOD_DECL, "class_method_decl", "d", 0) + + New way: + + DEFTREECODE (CLASS_METHOD_DECL, "class_method_decl", 'd', 0) diff --git a/gcc_arm/LITERATURE b/gcc_arm/LITERATURE new file mode 100755 index 0000000..260a625 --- /dev/null +++ b/gcc_arm/LITERATURE @@ -0,0 +1,101 @@ +Collected papers/sites on standards, compilers, optimization, etc. + +- Massively Scalar Compiler Project + + ftp://cs.rice.edu/public/preston/optimizer + +- Searchable article archive + + http://hypatia.dcs.qmw.ac.uk/SEL-HPC/Articles/CompilersArchive.html + +- David M Keaton's site + + http://www.dmk.com, ftp://ftp.dmk.com + c9x stuff is in ftp://ftp.dmk.com/DMK/sc22wg14/c9x + +- Some information about optimizing for x86 processors, links to + x86 manuals and documentation. + + http://www.goof.com/pcg/docs.html + http://www.announce.com/agner/assem/ + +- AMD site with optimization guide for x86 + + http://www.amd.com/K6/k6docs/pdf/21828a.pdf + +- Links related to many compiler topics + + http://www.nullstone.com/htmls/connections.htm + +- HPPA information: + + http://www.hp.com/computing/framed/technology/micropro + +- New compiler book. Online appendix includes some compiler links + + http://www.mkp.com/books_catalog/1-55860-320-4.asp + +- Various MIPS stuff: + + http://www.sgi.com/MIPS/arch/mips4docs/mipsiv_3_2.pdf (*) + http://www.sgi.com/MIPS/arch/MIPS16/MIPS16.whitepaper.pdf + http://www.sgi.com/MIPS/arch/MIPS16/mips16.pdf + http://www.sgi.com/MIPS/arch/ISA5/isa5_tech_brf.pdf + http://www.sgi.com/MIPS/arch/ISA5/MDMXspec.pdf + http://www.sgi.com/MIPS/arch/ISA5/MIPSVspec.pdf + + +- IBM Journal of Research and Development + + http://www.almaden.ibm.com/journal/ + + +- System V PowerPC ABI + + http://www.esofta.com/softspecs.html + +- C9X draft + + http://www.dkuug.dk/JTC1/SC22/WG14/www/docs/n794.htm + +- DWARF v2 spec and sample implementation + + ftp://sgigate.sgi.com/pub/dwarf/ + + +- Various m68k info (including user guides in pdf format) + + http://www.mot.com/SPS/HPESD/prod/0X0 + + +- Modula 3 Stuff + + http://www.cmass.com + http://www.cl.cam.ac.uk/m3doc/linux/cambridge.html + ftp://ftp.freebsd.org/pub/FreeBSD/distfiles/LOCAL_PORTS/m3-fbsd-m3cc-3.6.tar.gz + http://www.m3.org + +- Comp.compilers archive + + http://www.iecc.com/compilers + +- Intel Pentium design info: + + http://developer.intel.com/design/litcentr/index.htm + +- comp.std.c++ FAQ: + + http://reality.sgi.com/employees/austern_mti/std-c++/faq.html + +- EG3 maintains a list of compiler Internet resources, including FAQ's, +papers, hot list pages, potential software/shareware, all known companies, etc. + + http://www.eg3.com/ulc/compulc.htm + http://www.eg3.com/softd/compiler.htm + http://www.eg3.com/softdv/compiler.htm + + These resource pages are published as part of EG3's + Free Electronic Engineers' Toolbox at: + + http://www.eg3.com/ebox.htm + diff --git a/gcc_arm/Make-hooks b/gcc_arm/Make-hooks new file mode 100644 index 0000000..1fa9bbd --- /dev/null +++ b/gcc_arm/Make-hooks @@ -0,0 +1,21 @@ +lang.all.build: +lang.all.cross: +lang.start.encap: +lang.rest.encap: +lang.info: +lang.dvi: +lang.install-normal: +lang.install-common: +lang.install-info: +lang.install-man: +lang.uninstall: +lang.distdir: +lang.mostlyclean: +lang.clean: +lang.distclean: +lang.extraclean: +lang.maintainer-clean: +lang.stage1: +lang.stage2: +lang.stage3: +lang.stage4: diff --git a/gcc_arm/Make-host b/gcc_arm/Make-host new file mode 100644 index 0000000..e69de29 diff --git a/gcc_arm/Make-lang b/gcc_arm/Make-lang new file mode 100644 index 0000000..e69de29 diff --git a/gcc_arm/Make-target b/gcc_arm/Make-target new file mode 100644 index 0000000..b57eeca --- /dev/null +++ b/gcc_arm/Make-target @@ -0,0 +1,35 @@ +CROSS_LIBGCC1 = libgcc1-asm.a +LIB1ASMSRC = arm/lib1funcs.asm +# CYGNUS LOCAL interworking +LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX +# END CYGNUS LOCAL interworking + +# These are really part of libgcc1, but this will cause them to be +# built correctly, so... + +LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c + +fp-bit.c: $(srcdir)/config/fp-bit.c + echo '#define FLOAT' > fp-bit.c + echo '#ifndef __ARMEB__' >> fp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c + echo '#endif' >> fp-bit.c + cat $(srcdir)/config/fp-bit.c >> fp-bit.c + +dp-bit.c: $(srcdir)/config/fp-bit.c + echo '#ifndef __ARMEB__' > dp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> dp-bit.c + echo '#define FLOAT_WORD_ORDER_MISMATCH' >> dp-bit.c + echo '#endif' >> dp-bit.c + cat $(srcdir)/config/fp-bit.c >> dp-bit.c + +# CYGNUS LOCAL +MULTILIB_OPTIONS = mlittle-endian/mbig-endian mhard-float/msoft-float mapcs-32/mapcs-26 mno-thumb-interwork/mthumb-interwork fno-leading-underscore/fleading-underscore mcpu=arm7 +MULTILIB_DIRNAMES = le be fpu soft 32bit 26bit normal interwork elf under nofmult +MULTILIB_EXCEPTIONS = *mapcs-26/*mthumb-interwork* *mthumb-interwork*/*mcpu=arm7* +MULTILIB_MATCHES = mbig-endian=mbe mlittle-endian=mle mcpu?arm7=mcpu?arm7d mcpu?arm7=mcpu?arm7di mcpu?arm7=mcpu?arm70 mcpu?arm7=mcpu?arm700 mcpu?arm7=mcpu?arm700i mcpu?arm7=mcpu?arm710 mcpu?arm7=mcpu?arm710c mcpu?arm7=mcpu?arm7100 mcpu?arm7=mcpu?arm7500 mcpu?arm7=mcpu?arm7500fe mcpu?arm7=mcpu?arm6 mcpu?arm7=mcpu?arm60 mcpu?arm7=mcpu?arm600 mcpu?arm7=mcpu?arm610 mcpu?arm7=mcpu?arm620 +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib +# END CYGNUS LOCAL + +TARGET_LIBGCC2_CFLAGS = -Dinhibit_libc diff --git a/gcc_arm/Makefile.in b/gcc_arm/Makefile.in new file mode 100755 index 0000000..e180a12 --- /dev/null +++ b/gcc_arm/Makefile.in @@ -0,0 +1,2800 @@ +# Makefile for GNU C compiler. +# Copyright (C) 1987, 88, 90-98, 1999 Free Software Foundation, Inc. + +#This file is part of GNU CC. + +#GNU CC is free software; you can redistribute it and/or modify +#it under the terms of the GNU General Public License as published by +#the Free Software Foundation; either version 2, or (at your option) +#any later version. + +#GNU CC is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with GNU CC; see the file COPYING. If not, write to +#the Free Software Foundation, 59 Temple Place - Suite 330, +#Boston MA 02111-1307, USA. + +# The targets for external use include: +# all, doc, install, install-cross, install-cross-rest, +# uninstall, TAGS, mostlyclean, clean, distclean, maintainer-clean, +# stage1, stage2, stage3, stage4. + +# Suppress smart makes who think they know how to automake Yacc files +.y.c: + +# Directory where sources are, from where we are. +srcdir = @srcdir@ +VPATH = @srcdir@ + +# Variables that exist for you to override. +# See below for how to change them for certain systems. + +# List of language subdirectories. +# This is overridden by configure. +SUBDIRS =@subdirs@ + +# Selection of languages to be made. +# This is overridden by configure. +CONFIG_LANGUAGES = @all_languages@ +LANGUAGES = c $(CONFIG_LANGUAGES) + +# Selection of languages to be made during stage1 build. +# This is overridden by configure. +BOOT_LANGUAGES = c @all_boot_languages@ + +ALLOCA = +ALLOCA_FLAGS = +ALLOCA_FINISH = true + +# Various ways of specifying flags for compilations: +# CFLAGS is for the user to override to, e.g., do a bootstrap with -O2. +# BOOT_CFLAGS is the value of CFLAGS to pass +# to the stage2 and stage3 compilations +# WARN_CFLAGS are the warning flags to pass to stage2 and stage3. +# (And for stage 1 if the native compiler is GCC.) It is +# separate from BOOT_CFLAGS because people tend to override optimization +# flags and we'd like them to still have warnings turned on. They are free +# to explicitly turn warnings off if they wish. +# 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 = +# CYGNUS LOCAL nowarnings/law +CFLAGS = -g +BOOT_CFLAGS = -O2 $(CFLAGS) +WARN_CFLAGS = +# END CYGNUS LOCAL +# These exists to be overridden by the x-* and t-* files, respectively. +X_CFLAGS = +T_CFLAGS = + +X_CPPFLAGS = +T_CPPFLAGS = + +CC = @CC@ +# srcdir might be a relative pathname which won't be valid in a subdirectory, +# so we must use objdir/srcdir instead to make it safe. objdir is always +# a full pathname. +BISON = `if [ -f $(objdir)/../bison/bison ] ; then case $(srcdir) in \ + /*) echo $(objdir)/../bison/bison -L $(srcdir)/../bison/ ;; \ + *) echo $(objdir)/../bison/bison -L $(objdir)/$(srcdir)/../bison/ ;; \ + esac; else echo bison ; fi` +BISONFLAGS = +LEX = `if [ -f $(objdir)/../flex/flex ] ; then echo $(objdir)/../flex/flex ; else echo flex ; fi` +LEXFLAGS = +AR = ar +AR_FLAGS = rc +LN = @symbolic_link@ +DLLTOOL = dlltool +SHELL = /bin/sh +# on sysV, define this as cp. +INSTALL = @INSTALL@ +# Some systems may be missing symbolic links, regular links, or both. +# Allow configure to check this and use "ln -s", "ln", or "cp" as appropriate. +LN=@LN@ +LN_S=@LN_S@ +# These permit overriding just for certain files. +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +MAKEINFO = makeinfo +MAKEINFOFLAGS = +TEXI2DVI = texi2dvi +# For GNUmake: let us decide what gets passed to recursive makes. +MAKEOVERRIDES = +@SET_MAKE@ + +# Define this as & to perform parallel make on a Sequent. +# Note that this has some bugs, and it seems currently necessary +# to compile all the gen* files first by hand to avoid erroneous results. +P = + +# How to invoke ranlib. +RANLIB = ranlib +# Test to use to see whether ranlib exists on the system. +RANLIB_TEST = \ + [ -f $(RANLIB) ] \ + || ( [ "$(host_canonical)" = "$(target)" ] \ + && [ -f /usr/bin/ranlib -o -f /bin/ranlib ] ) + +# Compiler to use for compiling libgcc1.a. +# OLDCC should not be the GNU C compiler, +# since that would compile typical libgcc1.a functions such as mulsi3 +# into infinite recursions. +OLDCC = cc + +# CFLAGS for use with OLDCC, for compiling libgcc1.a. +# NOTE: -O does not work on some Unix systems! +CCLIBFLAGS = -O + +# Version of ar to use when compiling libgcc1.a. +OLDAR = ar +OLDAR_FLAGS = qc + +# Target to use when installing include directory. Either +# install-headers-tar or install-headers-cpio. +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/stdarg.h $(srcdir)/ginclude/stddef.h \ + $(srcdir)/ginclude/varargs.h $(srcdir)/ginclude/va-alpha.h \ + $(srcdir)/ginclude/va-h8300.h $(srcdir)/ginclude/va-i860.h \ + $(srcdir)/ginclude/va-i960.h $(srcdir)/ginclude/va-mips.h \ + $(srcdir)/ginclude/va-m88k.h $(srcdir)/ginclude/va-mn10200.h \ + $(srcdir)/ginclude/va-mn10300.h $(srcdir)/ginclude/va-pa.h \ + $(srcdir)/ginclude/va-pyr.h $(srcdir)/ginclude/va-sparc.h \ + $(srcdir)/ginclude/va-clipper.h $(srcdir)/ginclude/va-spur.h \ + $(srcdir)/ginclude/va-m32r.h $(srcdir)/ginclude/va-sh.h \ + $(srcdir)/ginclude/va-v850.h $(srcdir)/ginclude/va-arc.h \ + $(srcdir)/ginclude/iso646.h $(srcdir)/ginclude/va-ppc.h \ + $(CYGNUS-LOCAL-d10v) $(srcdir)/ginclude/va-d10v.h \ + $(CYGNUS-LOCAL-fr30) $(srcdir)/ginclude/va-fr30.h \ + $(CYGNUS-LOCAL-d30v) $(srcdir)/ginclude/va-d30v.h \ + $(srcdir)/ginclude/va-c4x.h $(EXTRA_HEADERS) $(LANG_EXTRA_HEADERS) \ + $(srcdir)/ginclude/proto.h $(srcdir)/ginclude/stdbool.h + +# Target to use whe installing assert.h. Some systems may +# want to set this empty. +INSTALL_ASSERT_H = install-assert-h + +# The GCC to use for compiling libgcc2.a, enquire, and libgcc1-test. +# Usually the one we just built. +# Don't use this as a dependency--use $(GCC_PASSES) or $(GCC_PARTS). +GCC_FOR_TARGET = ./xgcc -B./ -B$(build_tooldir)/bin/ + +# This is used instead of ALL_CFLAGS when compiling with GCC_FOR_TARGET. +# It omits XCFLAGS, and specifies -B./. +# It also specifies -I./include to find, e.g., stddef.h. +GCC_CFLAGS=$(INTERNAL_CFLAGS) $(X_CFLAGS) $(T_CFLAGS) $(CFLAGS) -I./include $(TCFLAGS) + +# Sed command to transform gcc to installed name. Overwritten by configure. +program_transform_name = @program_transform_name@ +program_transform_cross_name = s,^,$(target_alias)-, + +build_canonical = @build_canonical@ +host_canonical = @host_canonical@ + +# Tools to use when building a cross-compiler. +# These are used because `configure' appends `cross-make' +# to the makefile when making a cross-compiler. + +# Use the tools from the build tree, if they are available. + +# objdir is set by configure. +objdir = @objdir@ + +AR_FOR_TARGET = ` \ + if [ -f $(objdir)/../binutils/ar ] ; then \ + echo $(objdir)/../binutils/ar ; \ + else \ + if [ "$(host_canonical)" = "$(target)" ] ; then \ + echo ar; \ + else \ + t='$(program_transform_name)'; echo ar | sed -e $$t ; \ + fi; \ + fi` +AR_FLAGS_FOR_TARGET = rc +RANLIB_FOR_TARGET = ` \ + if [ -f $(objdir)/../binutils/ranlib ] ; then \ + echo $(objdir)/../binutils/ranlib ; \ + else \ + if [ "$(host_canonical)" = "$(target)" ] ; then \ + echo ranlib; \ + else \ + t='$(program_transform_name)'; echo ranlib | sed -e $$t ; \ + fi; \ + fi` +RANLIB_TEST_FOR_TARGET = \ + [ -f $(RANLIB_FOR_TARGET) ] \ + || ( [ "$(host_canonical)" = "$(target)" ] \ + && [ -f /usr/bin/ranlib -o -f /bin/ranlib ] ) + +# Dir to search for system headers. Overridden by cross-make. +SYSTEM_HEADER_DIR = /usr/include + +# Test to see whether exists in the system header files. +LIMITS_H_TEST = [ -f $(SYSTEM_HEADER_DIR)/limits.h ] + +# There may be a premade insn-attrtab.c for this machine. +# (You could rebuild it with genattrtab as usual, but it takes a long time.) +# PREMADE_ATTRTAB is the file name of the file to use. +# PREMADE_ATTRTAB_MD is the md file it corresponds to. +PREMADE_ATTRTAB_MD = Makefile # Guaranteed not to cmp equal to md. +PREMADE_ATTRTAB = + +target=@target@ +target_alias=@target_alias@ +xmake_file=@dep_host_xmake_file@ +tmake_file=@dep_tmake_file@ +out_file=$(srcdir)/config/@out_file@ +out_object_file=@out_object_file@ +md_file=$(srcdir)/config/@md_file@ +tm_file=@tm_file_list@ +build_xm_file=@build_xm_file_list@ +host_xm_file=@host_xm_file_list@ +lang_specs_files=@lang_specs_files@ +lang_options_files=@lang_options_files@ +lang_tree_files=@lang_tree_files@ +GCC_THREAD_FILE=@thread_file@ +OBJC_BOEHM_GC=@objc_boehm_gc@ +JAVAGC=@JAVAGC@ +GTHREAD_FLAGS=@gthread_flags@ +# Be prepared for gcc2 merges. +gcc_version=@gcc_version@ +gcc_version_trigger=@gcc_version_trigger@ +version=$(gcc_version) +mainversion=`sed -e 's/.*\"\([0-9]*\.[0-9]*\).*/\1/' < $(srcdir)/version.c` + +# Common prefix for installation directories. +# NOTE: This directory must exist when you start installation. +prefix = @prefix@ +# Directory in which to put localized header files. On the systems with +# gcc as the native cc, `local_prefix' may not be `prefix' which is +# `/usr'. +# NOTE: local_prefix *should not* default from prefix. +local_prefix = @local_prefix@ +# Directory in which to put host dependent programs and libraries +exec_prefix = @exec_prefix@ +# Directory in which to put the executable for the command `gcc' +bindir = @bindir@ +# Directory in which to put the directories used by the compiler. +libdir = @libdir@ +# Directory in which the compiler finds executables, libraries, etc. +libsubdir = $(libdir)/gcc-lib/$(target_alias)/$(version) +# Used to produce a relative $(gcc_tooldir) in gcc.o +unlibsubdir = ../../.. +# Directory in which to find other cross-compilation tools and headers. +dollar = @dollar@ +# Used in install-cross. +gcc_tooldir = @gcc_tooldir@ +# Since tooldir does not exist at build-time, use -B$(build_tooldir)/bin/ +build_tooldir = $(exec_prefix)/$(target_alias) +# Directory in which the compiler finds g++ includes. +gcc_gxx_include_dir= @gcc_gxx_include_dir@ +# Directory to search for site-specific includes. +includedir = $(local_prefix)/include +# assertdir is overridden in cross-make. +# (But this currently agrees with what is in cross-make.) +assertdir = $(gcc_tooldir)/include +# where the info files go +infodir = @infodir@ +# Extension (if any) to put in installed man-page filename. +manext = .1 +objext = .o +exeext = @host_exeext@ +build_exeext = @build_exeext@ + +# Directory in which to put man pages. +mandir = @mandir@ +man1dir = $(mandir)/man1 +# Dir for temp files. +tmpdir = /tmp + +# CYGNUS LOCAL texinfo +# Directory where texinfo.tex lives +texidir = $(srcdir)/../texinfo +# END CYGNUS LOCAL + +# Additional system libraries to link with. +CLIB= + +# Change this to a null string if obstacks are installed in the +# system library. +OBSTACK=obstack.o + +# Configure will set these if you need vfprintf and possibly _doprnt support. +VFPRINTF=@vfprintf@ +DOPRINT=@doprint@ + +# Specify the rule for actually making libgcc.a, +LIBGCC = libgcc.a +# and the rule for installing it. +INSTALL_LIBGCC = install-libgcc + +# Specify the rule for actually making libgcc1.a. +# The value may be empty; that means to do absolutely nothing +# with or for libgcc1.a. +LIBGCC1 = libgcc1.a + +# Specify the rule for making libgcc1.a for a cross-compiler. +# The default rule assumes that libgcc1.a is supplied by the user. +CROSS_LIBGCC1 = libgcc1.cross + +# Specify the rule for actually making libgcc2.a. +LIBGCC2 = libgcc2.a + +# Options to use when compiling libgcc2.a. +# -g1 causes output of debug info only for file-scope entities. +# we use this here because that should be enough, and also +# so that -g1 will be tested. +# +LIBGCC2_DEBUG_CFLAGS = -g1 +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 -Iinclude +LIBGCC2_INCLUDES = + +# Additional target-dependent options for compiling libgcc2.a. +TARGET_LIBGCC2_CFLAGS = + +# Things which must be built before building libgcc2.a. +# Some targets override this to stmp-int-hdrs +LIBGCC2_DEPS = + +# libgcc1-test target (must also be overridable for a target) +LIBGCC1_TEST = libgcc1-test + +# List of extra executables that should be compiled for this target machine +# that are used for compiling from source code to object code. +# The rules for compiling them should be in the t-* file for the machine. +EXTRA_PASSES =@extra_passes@ + +# Like EXTRA_PASSES, but these are used when linking. +EXTRA_PROGRAMS = @extra_programs@ + +# List of extra object files that should be compiled and linked with +# compiler proper (cc1, cc1obj, cc1plus). +EXTRA_OBJS = @extra_objs@ + +# List of extra object files that should be compiled and linked with +# the gcc driver. +EXTRA_GCC_OBJS =@host_extra_gcc_objs@ + +# List of additional header files to install. +# Often this is edited directly by `configure'. +EXTRA_HEADERS =@extra_headers_list@ + +# List of extra C and assembler files to add to libgcc1.a. +# Assembler files should have names ending in `.asm'. +LIB1FUNCS_EXTRA = + +# List of extra C and assembler files to add to libgcc2.a. +# Assembler files should have names ending in `.asm'. +LIB2FUNCS_EXTRA = + +# We do not try to build float.h anymore. Let configure select the +# appropriate pre-built float.h file for the target. +FLOAT_H=@float_h_file@ + +# Program to convert libraries. +LIBCONVERT = + +# Control whether header files are installed. +INSTALL_HEADERS=install-headers + +# Options for tar when copying trees. So HPUX can override it. +TAROUTOPTS = xpBf + +# A list of all the language-specific executables. +# This is overridden by configure. +COMPILERS = cc1$(exeext) @all_compilers@ + +# List of things which should already be built whenever we try to use xgcc +# to compile anything (without linking). +GCC_PASSES=xgcc$(exeext) cc1$(exeext) cpp$(exeext) $(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) + +# Directory to link to, when using the target `maketest'. +DIR = ../gcc + +# Guaranteed to not exist when not passing md through cpp. +# This value is overridden directly by configure. +MD_FILE = md-cpp-not-used + +# 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. +HOST_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. +HOST_PREFIX_1=loser- +HOST_CC=$(CC) +HOST_CFLAGS=$(ALL_CFLAGS) +HOST_CLIB=$(CLIB) +HOST_LDFLAGS=$(LDFLAGS) +HOST_CPPFLAGS=$(ALL_CPPFLAGS) +HOST_ALLOCA=$(ALLOCA) +HOST_MALLOC=$(MALLOC) +HOST_OBSTACK=$(OBSTACK) +HOST_VFPRINTF=$(VFPRINTF) +HOST_DOPRINT=$(DOPRINT) + +# Actual name to use when installing a native compiler. +GCC_INSTALL_NAME = `t='$(program_transform_name)'; echo gcc | sed -e $$t` + +# Actual name to use when installing a cross-compiler. +GCC_CROSS_NAME = `t='$(program_transform_cross_name)'; echo gcc | sed -e $$t` + +# Choose the real default target. +ALL=all.internal + +# Choose the real install target. +INSTALL_TARGET=install-normal + +# Setup the testing framework, if you have one +EXPECT = `if [ -f $${rootme}/../expect/expect ] ; then \ + echo $${rootme}/../expect/expect ; \ + else echo expect ; fi` + +RUNTEST = `if [ -f $${srcdir}/../dejagnu/runtest ] ; then \ + echo $${srcdir}/../dejagnu/runtest ; \ + else echo runtest; fi` +RUNTESTFLAGS = + +# End of variables for you to override. + +# Definition of `all' is here so that new rules inserted by sed +# do not specify the default target. +# The real definition is under `all.internal' (for native compilers) +# or `all.cross' (for cross compilers). +all: all.indirect + +# This tells GNU Make version 3 not to put all variables in the environment. +.NOEXPORT: + +# sed inserts variable overrides after the following line. +####target overrides +@target_overrides@ + +####host overrides +@host_overrides@ + +####cross overrides +@cross_defines@ +@cross_overrides@ + +####build overrides +@build_overrides@ + +# CYGNUS LOCAL --site +####site overrides +# END CYGNUS LOCAL +# +# Now figure out from those variables how to compile and link. + +all.indirect: $(ALL) + +# IN_GCC tells various files that system.h, toplev.c, etc are available. +INTERNAL_CFLAGS = $(CROSS) -DIN_GCC $(SCHED_CFLAGS) @extra_c_flags@ + +# This is the variable actually used when we compile. +# If you change this line, you probably also need to change the definition +# of HOST_CFLAGS in build-make to match. +ALL_CFLAGS = $(INTERNAL_CFLAGS) $(X_CFLAGS) $(T_CFLAGS) $(CFLAGS) $(XCFLAGS) \ + @DEFS@ + +# Likewise. +ALL_CPPFLAGS = $(CPPFLAGS) $(X_CPPFLAGS) $(T_CPPFLAGS) + +# Even if ALLOCA is set, don't use it if compiling with GCC. +USE_ALLOCA= ${ALLOCA} +USE_HOST_ALLOCA= ` case "${HOST_ALLOCA}" in ?*) echo ${HOST_PREFIX}${HOST_ALLOCA} ;; esac ` +USE_HOST_MALLOC= ` case "${HOST_MALLOC}" in ?*) echo ${HOST_PREFIX}${HOST_MALLOC} ;; esac ` +USE_HOST_OBSTACK= ` case "${HOST_OBSTACK}" in ?*) echo ${HOST_PREFIX}${HOST_OBSTACK} ;; esac ` +USE_HOST_VFPRINTF= ` case "${HOST_VFPRINTF}" in ?*) echo ${HOST_PREFIX}${HOST_VFPRINTF} ;; esac ` +USE_HOST_DOPRINT= ` case "${HOST_DOPRINT}" in ?*) echo ${HOST_PREFIX}${HOST_DOPRINT} ;; esac ` + +# Dependency on obstack, alloca, malloc or whatever library facilities +# are not installed in the system libraries. +# We don't use USE_ALLOCA because backquote expansion doesn't work in deps. +LIBDEPS= $(OBSTACK) $(ALLOCA) $(MALLOC) $(VFPRINTF) $(DOPRINT) + +# Likewise, for use in the tools that must run on this machine +# even if we are cross-building GCC. +# We don't use USE_ALLOCA because backquote expansion doesn't work in deps. +HOST_LIBDEPS= $(HOST_PREFIX)$(HOST_OBSTACK) $(HOST_PREFIX)$(HOST_ALLOCA) $(HOST_PREFIX)$(HOST_MALLOC) $(HOST_PREFIX)$(HOST_VFPRINTF) $(HOST_PREFIX)$(HOST_DOPRINT) + +# How to link with both our special library facilities +# and the system's installed libraries. +LIBS = $(OBSTACK) $(USE_ALLOCA) $(MALLOC) $(VFPRINTF) $(DOPRINT) $(CLIB) + +# Likewise, for use in the tools that must run on this machine +# even if we are cross-building GCC. +HOST_LIBS = $(USE_HOST_OBSTACK) $(USE_HOST_ALLOCA) $(USE_HOST_MALLOC) \ + $(USE_HOST_VFPRINTF) $(USE_HOST_DOPRINT) $(HOST_CLIB) + +HOST_RTL = $(HOST_PREFIX)rtl.o $(HOST_PREFIX)bitmap.o +HOST_RTLANAL = $(HOST_PREFIX)rtlanal.o +HOST_PRINT = $(HOST_PREFIX)print-rtl.o + +# Specify the directories to be searched for header files. +# Both . and srcdir are used, in that order, +# so that tm.h and config.h will be found in the compilation +# subdirectory rather than in the source directory. +INCLUDES = -I. -I$(srcdir) -I$(srcdir)/config -I$(srcdir)/../include + +# Always use -I$(srcdir)/config when compiling. +.c.o: + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< + +# This tells GNU make version 3 not to export all the variables +# defined in this file into the environment. +.NOEXPORT: +# +# Support for additional languages (other than c and objc). +# ??? objc can be supported this way too (leave for later). + +# These next lines are overridden by configure. +LANG_MAKEFILES = @all_lang_makefiles@ +LANG_STAGESTUFF = @all_stagestuff@ +LANG_DIFF_EXCLUDES = @all_diff_excludes@ +LANG_LIB2FUNCS = @all_lib2funcs@ +LANG_EXTRA_HEADERS = @all_headers@ + +# Flags to pass to recursive makes. +# CC is set by configure. Hosts without symlinks need special handling +# because we need CC="stage1/xgcc -Bstage1/" to work in the language +# subdirectories. +# ??? The choices here will need some experimenting with. +FLAGS_TO_PASS = \ + "AR_FLAGS_FOR_TARGET=$(AR_FLAGS_FOR_TARGET)" \ + "AR_FOR_TARGET=$(AR_FOR_TARGET)" \ + "BISON=$(BISON)" \ + "BISONFLAGS=$(BISONFLAGS)" \ + "CC=@cc_set_by_configure@" \ + "CFLAGS=$(CFLAGS)" \ + "CLIB=$(CLIB)" \ + "GCC_FOR_TARGET=$(GCC_FOR_TARGET)" \ + "LDFLAGS=$(LDFLAGS)" \ + "LEX=$(LEX)" \ + "LEXFLAGS=$(LEXFLAGS)" \ + "LN=$(LN)" \ + "LN_S=$(LN_S)" \ + "MAKEINFO=$(MAKEINFO)" \ + "MAKEINFOFLAGS=$(MAKEINFOFLAGS)" \ + "RANLIB_FOR_TARGET=$(RANLIB_FOR_TARGET)" \ + "RANLIB_TEST_FOR_TARGET=$(RANLIB_TEST_FOR_TARGET)" \ + "SHELL=$(SHELL)" \ + "STAGE_PREFIX=@stage_prefix_set_by_configure@" \ + "exeext=$(exeext)" \ + "build_exeext=$(build_exeext)" \ + "objext=$(objext)" \ + "exec_prefix=$(exec_prefix)" \ + "prefix=$(prefix)" \ + "local_prefix=$(local_prefix)" \ + "gxx_include_dir=$(gcc_gxx_include_dir)" \ + "tooldir=$(tooldir)" \ + "gcc_tooldir=$(gcc_tooldir)" \ + "bindir=$(bindir)" \ + "libsubdir=$(libsubdir)" +# +# Lists of files for various purposes. + +# Language-specific object files for C and Objective C. +C_AND_OBJC_OBJS = c-lex.o c-pragma.o c-decl.o c-typeck.o c-convert.o \ + c-aux-info.o c-common.o c-iterate.o @extra_c_objs@ + +# Language-specific object files for C. +C_OBJS = c-parse.o c-lang.o $(C_AND_OBJC_OBJS) + +SCHED_PREFIX = @sched_prefix@ +SCHED_CFLAGS = @sched_cflags@ + +# Language-independent object files. +OBJS = toplev.o version.o tree.o print-tree.o stor-layout.o fold-const.o \ + function.o stmt.o except.o expr.o calls.o expmed.o explow.o optabs.o \ + varasm.o rtl.o print-rtl.o rtlanal.o emit-rtl.o genrtl.o real.o regmove.o \ + sdbout.o dwarfout.o dwarf2out.o xcoffout.o bitmap.o alias.o \ + integrate.o jump.o cse.o loop.o unroll.o flow.o stupid.o combine.o varray.o \ + regclass.o local-alloc.o global.o reload.o reload1.o caller-save.o gcse.o \ + insn-peep.o reorg.o $(SCHED_PREFIX)sched.o final.o recog.o reg-stack.o \ + insn-opinit.o insn-recog.o insn-extract.o insn-output.o insn-emit.o \ + $(CYGNUS-LOCAL-lcm) lcm.o \ + $(CYGNUS-LOCAL-range) range.o \ + insn-attrtab.o $(out_object_file) getpwd.o $(EXTRA_OBJS) convert.o \ + mbchar.o dyn-string.o splay-tree.o graph.o sbitmap.o resource.o + +# GEN files are listed separately, so they can be built before doing parallel +# makes for cc1 or cc1plus. Otherwise sequent parallel make attempts to load +# them before rtl.o is compiled. +GEN= genemit genoutput genrecog genextract genflags gencodes genconfig \ + genpeep gengenrtl gencheck + +CCCP=@cpp_main@ + +# 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 genrtl.c genrtl.h tree-check.h \ + s-flags s-config s-codes s-mlib s-under\ + s-output s-recog s-emit s-extract s-peep s-check \ + s-attr s-attrtab s-opinit \ + 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) \ + xgcc$(exeext) cc1$(exeext) cpp$(exeext) $(EXTRA_PASSES) \ + $(EXTRA_PROGRAMS) gcc-cross$(exeext) \ + $(CCCP)$(exeext) cc1obj$(exeext) enquire$(exeext) \ + specs underscore.c \ + $(CYGNUS-LOCAL-range) *.range \ + *.greg *.lreg *.combine *.flow *.cse *.jump *.rtl *.tree *.loop \ + *.dbr *.jump2 *.sched *.cse2 *.sched2 *.stack *.gcse \ + *.[si] libcpp.a \ + $(LANG_STAGESTUFF) + + +# Members of libgcc1.a. +LIB1FUNCS = _mulsi3 _udivsi3 _divsi3 _umodsi3 _modsi3 \ + _lshrsi3 _ashrsi3 _ashlsi3 \ + _divdf3 _muldf3 _negdf2 _adddf3 _subdf3 \ + _fixdfsi _fixsfsi _floatsidf _floatsisf _truncdfsf2 _extendsfdf2 \ + _addsf3 _negsf2 _subsf3 _mulsf3 _divsf3 \ + _eqdf2 _nedf2 _gtdf2 _gedf2 _ltdf2 _ledf2 \ + _eqsf2 _nesf2 _gtsf2 _gesf2 _ltsf2 _lesf2 + +# Library members defined in libgcc2.c. +LIB2FUNCS = _muldi3 _divdi3 _moddi3 _udivdi3 _umoddi3 _negdi2 \ + _lshrdi3 _ashldi3 _ashrdi3 _ffsdi2 \ + _udiv_w_sdiv _udivmoddi4 _cmpdi2 _ucmpdi2 _floatdidf _floatdisf \ + _fixunsdfsi _fixunssfsi _fixunsdfdi _fixdfdi _fixunssfdi _fixsfdi \ + _fixxfdi _fixunsxfdi _floatdixf _fixunsxfsi \ + _fixtfdi _fixunstfdi _floatditf \ + __gcc_bcmp _varargs __dummy _eprintf \ + _bb _shtab _clear_cache _trampoline __main _exit \ + _ctors _pure + +LIB2FUNCS_EH = _eh + +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 \ + _lt_sf _le_sf _si_to_sf _sf_to_si _negate_sf _make_sf \ + _sf_to_df + +DPBIT_FUNCS = _pack_df _unpack_df _addsub_df _mul_df _div_df \ + _fpcmp_parts_df _compare_df _eq_df _ne_df _gt_df _ge_df \ + _lt_df _le_df _si_to_df _df_to_si _negate_df _make_df \ + _df_to_sf + +# The files that "belong" in CONFIG_H are deliberately omitted +# because having them there would not be useful in actual practice. +# All they would do is cause complete recompilation every time +# one of the machine description files is edited. +# That may or may not be what one wants to do. +# If it is, rm *.o is an easy way to do it. +# CONFIG_H = $(host_xm_file) $(tm_file) +CONFIG_H = +RTL_BASE_H = rtl.h rtl.def machmode.h machmode.def +RTL_H = $(RTL_BASE_H) genrtl.h +TREE_H = tree.h real.h tree.def machmode.h machmode.def tree-check.h +BASIC_BLOCK_H = basic-block.h bitmap.h sbitmap.h +RECOG_H = recog.h +EXPR_H = expr.h insn-codes.h +REGS_H = regs.h varray.h machmode.h machmode.def +# +# Language makefile fragments. + +# The following targets define the interface between us and the languages. +# +# all.build, all.cross, start.encap, rest.encap, +# info, dvi, +# install-normal, install-common, install-info, install-man, +# uninstall, distdir, +# mostlyclean, clean, distclean, extraclean, maintainer-clean, +# stage1, stage2, stage3, stage4 +# +# Each language is linked in with a series of hooks (since we can't use `::' +# targets). The name of each hooked is "lang.${target_name}" (eg: lang.info). +# Configure computes and adds these here. + +####language hooks +@language_hooks@ + +# sed inserts language fragments after the following line. +####language fragments +@language_fragments@ + +# End of language makefile fragments. +# +# The only suffixes we want for implicit rules are .c and .o, so clear +# the list and add them. This speeds up GNU Make, and allows -r to work. +.SUFFIXES: +.SUFFIXES: .c .o + +Makefile: $(srcdir)/Makefile.in config.status $(srcdir)/version.c \ + $(xmake_file) $(tmake_file) $(LANG_MAKEFILES) + $(SHELL) $(srcdir)/configure.frag $(srcdir) "$(SUBDIRS)" \ + "$(xmake_file)" "$(tmake_file)" + cp config.status config.run + LANGUAGES="$(CONFIG_LANGUAGES)" $(SHELL) config.run + rm -f config.run + +# CYGNUS LOCAL: autoconf/wilson +# Don't automatically run autoconf, since configure.in might be accidentally +# newer than configure. Also, this writes into the source directory which +# might be on a read-only file system. +#$(srcdir)/configure: $(srcdir)/configure.in +# cd $(srcdir); autoconf + +# 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 +# nothing has changed. +# It remains in the source directory and is part of the distribution. +# This follows what is done in shellutils, fileutils, etc. +# "echo timestamp" is used instead of touch to be consistent with other +# packages that use autoconf (??? perhaps also to avoid problems with patch?). +# ??? Newer versions have a maintainer mode that may be useful here. +# CYGNUS LOCAL: autoheader/jason +# Don't run autoheader automatically either. +#$(srcdir)/config.in: $(srcdir)/cstamp-h.in +#$(srcdir)/cstamp-h.in: $(srcdir)/configure.in $(srcdir)/acconfig.h +# cd $(srcdir) && autoheader +# @rm -f $(srcdir)/cstamp-h.in +# echo timestamp > $(srcdir)/cstamp-h.in +auto-host.h: cstamp-h ; @true +cstamp-h: config.in config.status + CONFIG_HEADERS=auto-host.h:config.in LANGUAGES="$(CONFIG_LANGUAGES)" $(SHELL) 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: configure version.c + @if [ ! -f config.status ] ; then \ + echo You must configure gcc. Look at the INSTALL file for details.; \ + false; \ + else \ + LANGUAGES="$(CONFIG_LANGUAGES)" $(SHELL) config.status --recheck; \ + fi + +all.internal: start.encap rest.encap +# This is what to compile if making a cross-compiler. +# Note that we can compile enquire using the cross-compiler just built, +# although we can't run it on this machine. +all.cross: native gcc-cross specs stmp-headers $(LIBGCC) \ + $(LIBGCC1_TEST) lang.all.cross +# This is what to compile if making gcc with a cross-compiler. +all.build: native xgcc$(exeext) lang.all.build +# This is what must be made before installing GCC and converting libraries. +start.encap: native xgcc$(exeext) specs $(LIBGCC1) xlimits.h lang.start.encap +# These can't be made until after GCC can run. +rest.encap: stmp-headers $(LIBGCC) 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 cpp$(exeext) $(LANGUAGES) \ + $(EXTRA_PASSES) $(EXTRA_PROGRAMS) + +# Define the names for selecting languages in LANGUAGES. +C c: cc1$(exeext) + +# Tell GNU make these are phony targets. +.PHONY: C c + +# On the target machine, finish building a cross compiler. +# This does the things that can't be done on the host machine. +rest.cross: $(LIBGCC) specs + +# Verify that it works to compile and link libgcc1-test. +# If it does, then there are sufficient replacements for libgcc1.a. +libgcc1-test: libgcc1-test.o native $(GCC_PARTS) + @echo "Testing libgcc1. Ignore linker warning messages." + $(GCC_FOR_TARGET) $(GCC_CFLAGS) libgcc1-test.o -o libgcc1-test \ + -nostartfiles -nostdlib `$(GCC_FOR_TARGET) --print-libgcc-file-name` +libgcc1-test.o: libgcc1-test.c native xgcc$(exeext) + $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(ALL_CPPFLAGS) -c $(srcdir)/libgcc1-test.c + +# Recompile all the language-independent object files. +# This is used only if the user explicitly asks for it. +compilations: ${OBJS} + +# Create a list of the language-independent object files so the language +# subdirectories needn't mention their names explicitly. +stamp-objlist: $(OBJS) + echo " $(OBJS)" | sed -e 's, \([a-z0-9]\), ../\1,g' -e 's/\.o/$(objext)/g' >stamp-objlist + +# 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.o version.o choose-temp.o pexecute.o prefix.o version.o \ + mkstemp.o $(LIBDEPS) $(EXTRA_GCC_OBJS) + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ gcc.o prefix.o version.o \ + choose-temp.o pexecute.o mkstemp.o $(EXTRA_GCC_OBJS) $(LIBS) + +# Dump a specs file to make -B./ read these specs over installed ones. +specs: xgcc$(exeext) + $(GCC_FOR_TARGET) -dumpspecs > tmp-specs + mv tmp-specs specs + +# 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: xgcc$(exeext) + cp xgcc$(exeext) gcc-cross$(exeext) + +cc1$(exeext): $(P) $(OBJS) $(C_OBJS) $(LIBDEPS) + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(C_OBJS) $(LIBS) + +# Build the version of limits.h that we will install. +xlimits.h: glimits.h limitx.h limity.h + if $(LIMITS_H_TEST) ; then \ + cat $(srcdir)/limitx.h $(srcdir)/glimits.h $(srcdir)/limity.h > tmp-xlimits.h; \ + else \ + cat $(srcdir)/glimits.h > tmp-xlimits.h; \ + fi + mv tmp-xlimits.h xlimits.h +# +# Build libgcc.a. +# This is done in two parts because some functions, in libgcc1.c, +# must be compiled with something other than GCC, +# while the rest, in libgcc2.c, must be compiled with xgcc. +# That means we can't do libgcc2.c until after xgcc, cc1, etc. + +# Use this as value of LIBGCC1 to cause conversion to GNU library format. +# LIBCONVERT should put its output in libgcc1.conv. +libgcc1.conv: libgcc1.a + $(LIBCONVERT) libgcc1.a libgcc1.conv + +# Use this as value of LIBGCC1 to inhibit use of libgcc1.c entirely. +# Make an empty file instead. +libgcc1.null: $(GCC_PASSES) + echo "void __foo () {}" > dummy.c + $(GCC_FOR_TARGET) $(GCC_CFLAGS) -c dummy.c + $(AR_FOR_TARGET) $(AR_FLAGS_FOR_TARGET) libgcc1.null dummy$(objext) + rm -f dummy$(objext) dummy.c + +# This is $(LIBGCC1) for a cross-compiler. +# We have no automatic way of building libgcc1.a, +# so it's up to the installer to find a way to do that. +# This rule deliberately does not depend on libgcc1.a +# so that it will fail if the installer hasn't provided it. +libgcc1.cross: + mv libgcc1.a libgcc1.cross || (echo You must find a way to make libgcc1.a; false) + +# Compile the library of arithmetic subroutines with the native compiler. +# Don't compile it with GCC! +# (That would cause most arithmetic functions to call themselves.) +# +# NOTE: If you modify these rules substantially, please be sure to +# check at least config/i386/t-sco5 and possibly other makefile +# fragments. +libgcc1.a: libgcc1.c $(CONFIG_H) $(LIB1FUNCS_EXTRA) config.status + -rm -f tmplibgcc1.a +# Actually build it in tmplibgcc1.a, then rename at end, +# so that libgcc1.a itself remains nonexistent if compilation is aborted. +# -e causes any failing command to make this rule fail. +# -e doesn't work in certain shells, so we test $$? as well. +# lynx has a broken ar, it always complains when the initial library is +# empty, thus this command works only if we don't do -e +# There is a trailing backslash (\) deleted from the following line. +# set -e; + for name in $(LIB1FUNCS); \ + do \ + echo $${name}; \ + rm -f $${name}$(objext); \ + $(OLDCC) -DIN_LIBGCC1 $(CCLIBFLAGS) $(INCLUDES) -c -DL$${name} $(srcdir)/libgcc1.c; \ + if [ $$? -eq 0 ] ; then true; else exit 1; fi; \ + mv libgcc1$(objext) $${name}$(objext); \ + $(OLDAR) $(OLDAR_FLAGS) tmplibgcc1.a $${name}$(objext); \ + rm -f $${name}$(objext); \ + done +# Some shells crash when a loop has no items. +# So make sure there is always at least one--`..'. +# Then ignore it. +# We don't use -e here because there are if statements +# that should not make the command give up when the if condition is false. +# Instead, we test for failure after each command where it matters. + for file in .. $(LIB1FUNCS_EXTRA); \ + do \ + if [ x$${file} != x.. ]; then \ + name=`echo $${file} | sed -e 's/[.][cS]$$//' -e 's/[.]asm$$//'`; \ + echo $${name}; \ + if [ $${name}.asm = $${file} ]; then \ + cp $${file} $${name}.s || exit 1; file=$${name}.s; \ + else true; fi; \ + $(OLDCC) -DIN_LIBGCC1 $(CCLIBFLAGS) $(INCLUDES) -c $${file}; \ + if [ $$? -eq 0 ] ; then true; else exit 1; fi; \ + $(OLDAR) $(OLDAR_FLAGS) tmplibgcc1.a $${name}$(objext); \ + if [ $$? -eq 0 ] ; then true; else exit 1; fi; \ + rm -f $${name}.s $${name}$(objext); \ + else true; \ + fi; \ + done + -if $(RANLIB_TEST_FOR_TARGET) ; then \ + $(RANLIB_FOR_TARGET) tmplibgcc1.a; \ + else true; fi + mv tmplibgcc1.a libgcc1.a + +# Build libgcc1.a from assembler source. LIB1ASMFUNCS is the list of +# functions. LIB1ASMSRC is the name of the source file in the config +# subdirectory. +libgcc1-asm.a: libgcc2.ready config.status $(srcdir)/config/$(LIB1ASMSRC) + -rm -f tmplibgcc1.a libgcc1.S + cp $(srcdir)/config/$(LIB1ASMSRC) libgcc1.S +# Actually build it in tmplibgcc1.a, then rename at end, +# so that libgcc1-asm.a itself remains nonexistent if compilation is aborted. +# -e causes any failing command to make this rule fail. +# -e doesn't work in certain shells, so we test $$? as well. +# lynx has a broken ar, it always complains when the initial library is +# empty, thus this command works only if we don't do -e +# There is a trailing backslash (\) deleted from the following line. +# set -e; + for name in $(LIB1ASMFUNCS); \ + do \ + echo $${name}; \ + $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) -c -DL$${name} libgcc1.S; \ + if [ $$? -eq 0 ] ; then true; else exit 1; fi; \ + mv libgcc1$(objext) $${name}$(objext); \ + $(AR_FOR_TARGET) $(AR_FLAGS_FOR_TARGET) tmplibgcc1.a $${name}$(objext); \ + rm -f $${name}$(objext); \ + done + -rm -f libgcc1.S + mv tmplibgcc1.a libgcc1-asm.a + +# Generate assembly versions of the functions required for libgcc1. +# You'll still need to massage the code by hand (possibly hacking +# underscores and local labels) but this will get you started. +libgcc1.S: libgcc1.c $(CONFIG_H) config.status + -rm -f libgcc1.S + touch libgcc1.S + for name in $(LIB1FUNCS); \ + do \ + echo $${name}; \ + $(OLDCC) -DIN_LIBGCC1 $(CCLIBFLAGS) $(INCLUDES) -S -DL$${name} $(srcdir)/libgcc1.c; \ + if [ $$? -eq 0 ] ; then true; else exit 1; fi; \ + echo '#ifdef ' L$${name} >> libgcc1.S; \ + cat libgcc1.s >> libgcc1.S; \ + echo '#endif /*' L$${name} '*/' >> libgcc1.S; \ + echo "" >> libgcc1.S; \ + done + +# Compiling libgcc2.a requires making sure that cc1, etc. have been compiled. +# But recompiling cc1 should not force recompilation of libgcc2.a. +# If you want to force recompilation, delete libgcc2.a. +libgcc2.ready: $(GCC_PASSES) $(LIBGCC2_DEPS) stmp-int-hdrs + -if [ -f libgcc2.ready ] ; then \ + true; \ + else \ + touch libgcc2.ready; \ + fi + +LIB2ADD = $(LIB2FUNCS_EXTRA) $(LANG_LIB2FUNCS) +libgcc2.a: libgcc2.c libgcc2.ready $(CONFIG_H) $(FPBIT) $(DPBIT) $(LIB2ADD) \ + machmode.h longlong.h config.status +# Actually build it in tmplibgcc2.a, then rename at end, +# so that libgcc2.a itself remains nonexistent if compilation is aborted. + -rm -f tmplibgcc2.a +# -e causes any failing command to make this rule fail. +# -e doesn't work in certain shells, so we test $$? as well. +# lynx has a broken ar, it always complains when the initial library is +# empty, thus this command works only if we don't do -e +# There is a trailing backslash (\) deleted from the following line. +# set -e; + for name in $(LIB2FUNCS); \ + do \ + echo $${name}; \ + $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) -c -DL$${name} \ + $(srcdir)/libgcc2.c -o $${name}$(objext); \ + if [ $$? -eq 0 ] ; then true; else exit 1; fi; \ + $(AR_FOR_TARGET) $(AR_FLAGS_FOR_TARGET) tmplibgcc2.a $${name}$(objext); \ + rm -f $${name}$(objext); \ + done + for name in $(LIB2FUNCS_EH); \ + do \ + echo $${name}; \ + $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) -fexceptions $(INCLUDES) -c \ + -DL$${name} $(srcdir)/libgcc2.c -o $${name}$(objext); \ + if [ $$? -eq 0 ] ; then true; else exit 1; fi; \ + $(AR_FOR_TARGET) $(AR_FLAGS_FOR_TARGET) tmplibgcc2.a $${name}$(objext); \ + rm -f $${name}$(objext); \ + done + if [ x$(FPBIT) != x ]; then \ + for name in $(FPBIT_FUNCS); \ + do \ + echo $${name}; \ + $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) -c -DL$${name} \ + -DFINE_GRAINED_LIBRARIES $(FPBIT) -o $${name}$(objext); \ + if [ $$? -eq 0 ] ; then true; else exit 1; fi; \ + $(AR_FOR_TARGET) $(AR_FLAGS_FOR_TARGET) tmplibgcc2.a $${name}$(objext); \ + rm -f $${name}$(objext); \ + done; \ + else true; fi; + if [ x$(DPBIT) != x ]; then \ + for name in $(DPBIT_FUNCS); \ + do \ + echo $${name}; \ + $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) -c -DL$${name} \ + -DFINE_GRAINED_LIBRARIES $(DPBIT) -o $${name}$(objext); \ + if [ $$? -eq 0 ] ; then true; else exit 1; fi; \ + $(AR_FOR_TARGET) $(AR_FLAGS_FOR_TARGET) tmplibgcc2.a $${name}$(objext); \ + rm -f $${name}$(objext); \ + done; \ + else true; fi; +# Some shells crash when a loop has no items. +# So make sure there is always at least one--`..'. +# Then ignore it. +# We don't use -e here because there are if statements +# that should not make the command give up when the if condition is false. +# Instead, we test for failure after each command where it matters. + for file in $(LIB2ADD); do \ + name=`echo $${file} | sed -e 's/[.][cSo]$$//' -e 's/[.]asm$$//' -e 's/[.]txt$$//'`; \ + oname=` echo $${name} | sed -e 's,.*/,,'`; \ + if [ $${name}.txt = $${file} ]; then \ + for f in .. `cat $${file}`; do if [ x$${f} != x.. ]; then \ + $(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \ + AR_FOR_TARGET="$(AR_FOR_TARGET)" \ + AR_FLAGS_FOR_TARGET="$(AR_FLAGS_FOR_TARGET)" CC="$(CC)" \ + CFLAGS="$(CFLAGS)" HOST_PREFIX="$(HOST_PREFIX)" \ + HOST_PREFIX_1="$(HOST_PREFIX_1)" \ + LANGUAGES="$(LANGUAGES)" \ + LIBGCC2_CFLAGS="$(LIBGCC2_CFLAGS)" $${f}; \ + if [ $$? -eq 0 ] ; then true; else exit 1; fi; \ + $(AR_FOR_TARGET) $(AR_FLAGS_FOR_TARGET) tmplibgcc2.a $${f}; \ + rm -f $${f}; \ + else true; \ + fi; done; \ + else \ + echo $${name}; \ + if [ $${name}.asm = $${file} ]; then \ + cp $${file} $${name}.s || exit 1; file=$${name}.s; \ + else true; fi; \ + $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) -c $${file}; \ + if [ $$? -eq 0 ] ; then true; else exit 1; fi; \ + $(AR_FOR_TARGET) $(AR_FLAGS_FOR_TARGET) tmplibgcc2.a $${oname}$(objext); \ + rm -f $${name}.s $${oname}$(objext); \ + fi; \ + done + mv tmplibgcc2.a libgcc2.a +# These lines were deleted from above the mv command +# because ranlibing libgcc.a itself should suffice. +# -if [ x${HPUX_GAS} = x ] ; then \ +# if $(RANLIB_TEST_FOR_TARGET) ; then \ +# $(RANLIB_FOR_TARGET) tmplibgcc2.a; +# else true; fi; \ +# else true; fi + +# Combine the various libraries into a single library, libgcc.a. +libgcc.a: $(LIBGCC1) $(LIBGCC2) + -rm -rf tmplibgcc.a libgcc.a tmpcopy + mkdir tmpcopy + -if [ x$(LIBGCC1) != x ]; \ + then (cd tmpcopy; $(AR_FOR_TARGET) x ../$(LIBGCC1)); \ + else true; \ + fi +# Some versions of ar (specifically the one in RISC/os 5.x), create an +# unwritable table of contents file, and then print an error message when +# the second ar command tries to overwrite this file. To avoid the error +# message from ar, we make sure all files are writable. + -(cd tmpcopy; chmod +w * > /dev/null 2>&1) + (cd tmpcopy; $(AR_FOR_TARGET) x ../$(LIBGCC2)) + (cd tmpcopy; $(AR_FOR_TARGET) $(AR_FLAGS_FOR_TARGET) ../tmplibgcc.a *$(objext)) + rm -rf tmpcopy + -if $(RANLIB_TEST_FOR_TARGET) ; then \ + $(RANLIB_FOR_TARGET) tmplibgcc.a; \ + else true; fi +# Actually build it in tmplibgcc.a, then rename at end, +# so that libgcc.a itself remains nonexistent if compilation is aborted. + mv tmplibgcc.a libgcc.a + +# Use the genmultilib shell script to generate the information the gcc +# driver program needs to select the library directory based on the +# switches. +multilib.h: s-mlib; @true +s-mlib: $(srcdir)/genmultilib Makefile + $(SHELL) $(srcdir)/genmultilib \ + "$(MULTILIB_OPTIONS)" \ + "$(MULTILIB_DIRNAMES)" \ + "$(MULTILIB_MATCHES)" \ + "$(MULTILIB_EXCEPTIONS)" \ + "$(MULTILIB_EXTRA_OPTS)" > tmp-mlib.h + $(srcdir)/move-if-change tmp-mlib.h multilib.h + touch s-mlib + +# Build multiple copies of libgcc.a, one for each target switch. +stmp-multilib: $(LIBGCC1) libgcc2.c libgcc2.ready $(CONFIG_H) \ + $(LIB2ADD) machmode.h longlong.h config.status + for i in `$(GCC_FOR_TARGET) --print-multi-lib`; do \ + dir=`echo $$i | sed -e 's/;.*$$//'`; \ + flags=`echo $$i | sed -e 's/^[^;]*;//' -e 's/@/ -/g'`; \ + $(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \ + AR_FOR_TARGET="$(AR_FOR_TARGET)" \ + AR_FLAGS_FOR_TARGET="$(AR_FLAGS_FOR_TARGET)" \ + CC="$(CC)" CFLAGS="$(CFLAGS)" \ + RANLIB_FOR_TARGET="$(RANLIB_FOR_TARGET)" \ + RANLIB_TEST_FOR_TARGET="$(RANLIB_TEST_FOR_TARGET)" \ + LANGUAGES="$(LANGUAGES)" \ + HOST_PREFIX="$(HOST_PREFIX)" HOST_PREFIX_1="$(HOST_PREFIX_1)" \ + LIBGCC2_CFLAGS="$(LIBGCC2_CFLAGS) $${flags}" \ + MULTILIB_CFLAGS="$${flags}" \ + LIBGCC1="$(LIBGCC1)" LIBGCC2="$(LIBGCC2)" \ + dir="$${dir}" stmp-multilib-sub; \ + if [ $$? -eq 0 ] ; then true; else exit 1; fi; \ + done + touch stmp-multilib + +# Subroutine of stmp-multilib so make -n works. +stmp-multilib-sub: + rm -f $(LIBGCC2) + if [ -d $(dir) ]; then \ + cd $(dir); \ + rm -f libgcc.a $(EXTRA_MULTILIB_PARTS); \ + else true; \ + fi + $(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \ + AR_FOR_TARGET="$(AR_FOR_TARGET)" \ + AR_FLAGS_FOR_TARGET="$(AR_FLAGS_FOR_TARGET)" \ + CC="$(CC)" CFLAGS="$(CFLAGS)" \ + HOST_PREFIX="$(HOST_PREFIX)" HOST_PREFIX_1="$(HOST_PREFIX_1)" \ + LANGUAGES="$(LANGUAGES)" \ + LIBGCC2_CFLAGS="$(LIBGCC2_CFLAGS)" $(LIBGCC2) + if [ x$(LIBGCC1) != xlibgcc1-asm.a ]; \ + then true; \ + else rm -f $(LIBGCC1); \ + fi + if [ x$(LIBGCC1) != xlibgcc1-asm.a ]; \ + then true; \ + else \ + $(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \ + AR_FOR_TARGET="$(AR_FOR_TARGET)" \ + AR_FLAGS_FOR_TARGET="$(AR_FLAGS_FOR_TARGET)" \ + CC="$(CC)" CFLAGS="$(CFLAGS)" \ + HOST_PREFIX="$(HOST_PREFIX)" HOST_PREFIX_1="$(HOST_PREFIX_1)" \ + LANGUAGES="$(LANGUAGES)" \ + LIBGCC2_CFLAGS="$(LIBGCC2_CFLAGS)" $(LIBGCC1); \ + fi + rm -rf tmplibgcc.a tmpcopy + mkdir tmpcopy + if [ x$(LIBGCC1) != x ]; \ + then (cd tmpcopy; $(AR_FOR_TARGET) x ../$(LIBGCC1)); \ + else true; \ + fi + (cd tmpcopy; $(AR_FOR_TARGET) x ../$(LIBGCC2)) + (cd tmpcopy; $(AR_FOR_TARGET) $(AR_FLAGS_FOR_TARGET) ../tmplibgcc.a *$(objext)) + rm -rf libgcc2.a tmpcopy + if $(RANLIB_TEST_FOR_TARGET) ; then \ + $(RANLIB_FOR_TARGET) tmplibgcc.a; \ + else true; fi + if [ -d $(dir) ]; then true; else mkdir $(dir); fi + mv tmplibgcc.a $(dir)/libgcc.a + for f in .. $(EXTRA_MULTILIB_PARTS); do if [ x$${f} != x.. ]; then \ + $(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \ + AR_FOR_TARGET="$(AR_FOR_TARGET)" \ + AR_FLAGS_FOR_TARGET="$(AR_FLAGS_FOR_TARGET)" \ + CC="$(CC)" CFLAGS="$(CFLAGS)" \ + HOST_PREFIX="$(HOST_PREFIX)" HOST_PREFIX_1="$(HOST_PREFIX_1)" \ + LANGUAGES="$(LANGUAGES)" \ + MULTILIB_CFLAGS="$(MULTILIB_CFLAGS)" T="t" t$${f}; \ + mv t$${f} $(dir)/$${f}; \ + else true; \ + fi; done + +# Compiling object files from source files. + +# Note that dependencies on obstack.h are not written +# because that file is not part of GCC. + +# C language specific files. + +# CYGNUS LOCAL: built in build directory +c-parse.o : c-parse.c $(CONFIG_H) $(TREE_H) c-lex.h c-parse.h \ + c-tree.h input.h flags.h system.h toplev.h + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c c-parse.c + +# CYGNUS LOCAL: c-gperf.h really depends on c-parse.gperf. +$(srcdir)/c-gperf.h: + gperf -L KR-C -F ', 0, 0' -p -j1 -i 1 -g -o -t -G -N is_reserved_word \ + -k1,3,$$ $(srcdir)/c-parse.gperf >tmp-gperf.h + $(srcdir)/move-if-change tmp-gperf.h $(srcdir)/c-gperf.h + +c-decl.o : c-decl.c $(CONFIG_H) system.h $(TREE_H) c-tree.h c-lex.h flags.h \ + output.h toplev.h +c-typeck.o : c-typeck.c $(CONFIG_H) system.h $(TREE_H) c-tree.h flags.h \ + output.h $(EXPR_H) $(RTL_H) toplev.h +c-lang.o : c-lang.c $(CONFIG_H) system.h $(TREE_H) c-tree.h c-lex.h toplev.h \ + output.h +# CYGNUS LOCAL: built in build directory +c-lex.o : c-lex.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) c-lex.h c-tree.h \ + c-parse.h input.h flags.h c-gperf.h c-pragma.h \ + toplev.h output.h mbchar.h +c-aux-info.o : c-aux-info.c $(CONFIG_H) system.h $(TREE_H) c-tree.h flags.h +c-convert.o : c-convert.c $(CONFIG_H) system.h $(TREE_H) flags.h toplev.h +c-pragma.o: c-pragma.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) except.h \ + function.h defaults.h c-pragma.h toplev.h +c-iterate.o: c-iterate.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) c-tree.h \ + flags.h toplev.h $(EXPR_H) +mbchar.o: mbchar.c $(CONFIG_H) system.h mbchar.h +graph.o: graph.c $(CONFIG_H) system.h toplev.h flags.h output.h $(RTL_H) \ + hard-reg-set.h $(BASIC_BLOCK_H) +sbitmap.o: sbitmap.c $(CONFIG_H) system.h $(RTL_H) flags.h $(BASIC_BLOCK_H) + +hash.o: hash.c hash.h system.h toplev.h + +pexecute.o: $(srcdir)/../libiberty/pexecute.c $(CONFIG_H) system.h + rm -f pexecute.c + $(LN_S) $(srcdir)/../libiberty/pexecute.c pexecute.c + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) pexecute.c + +vfprintf.o: $(srcdir)/../libiberty/vfprintf.c $(CONFIG_H) system.h + rm -f vfprintf.c + $(LN_S) $(srcdir)/../libiberty/vfprintf.c vfprintf.c + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) vfprintf.c + +splay-tree.o: $(srcdir)/../libiberty/splay-tree.c \ + $(srcdir)/../include/splay-tree.h $(srcdir)/../include/libiberty.h + rm -f splay-tree.c + $(LN_S) $(srcdir)/../libiberty/splay-tree.c splay-tree.c + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) splay-tree.c + +underscore.c: s-under ; @true + +s-under: $(GCC_PASSES) + echo "int xxy_us_dummy;" >tmp-dum.c + $(GCC_FOR_TARGET) -S tmp-dum.c + echo '/*WARNING: This file is automatically generated!*/' >tmp-under.c + if grep _xxy_us_dummy tmp-dum.s > /dev/null ; then \ + echo "int prepends_underscore = 1;" >>tmp-under.c; \ + else \ + echo "int prepends_underscore = 0;" >>tmp-under.c; \ + fi + $(srcdir)/move-if-change tmp-under.c underscore.c + -rm -f tmp-dum.c tmp-dum.s + touch s-under + +# A file used by all variants of C. + +c-common.o : c-common.c $(CONFIG_H) system.h $(TREE_H) c-tree.h c-lex.h \ + flags.h toplev.h output.h c-pragma.h $(RTL_H) + +# Language-independent files. + +# CYGNUS LOCAL -- meissner/relative pathnames +DRIVER_DEFINES = \ + -DSTANDARD_STARTFILE_PREFIX=\"$(unlibsubdir)/\" \ + -DSTANDARD_EXEC_PREFIX=\"$(libdir)/gcc-lib/\" \ + -DDEFAULT_TARGET_VERSION=\"$(version)\" \ + -DDEFAULT_TARGET_MACHINE=\"$(target_alias)\" \ + -DSTANDARD_BINDIR_PREFIX=\"$(bindir)/\" \ + -DTOOLDIR_BASE_PREFIX=\"$(unlibsubdir)/../\" +gcc.o: gcc.c $(CONFIG_H) system.h multilib.h Makefile prefix.h \ + $(lang_specs_files) + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(DRIVER_DEFINES) \ + -c `echo $(srcdir)/gcc.c | sed 's,^\./,,'` +# END CYGNUS LOCAL -- meissner/relative pathnames + +tree-check.h: s-check ; @true +s-check : gencheck $(srcdir)/move-if-change + ./gencheck > tmp-check.h + $(srcdir)/move-if-change tmp-check.h tree-check.h + touch s-check + +gencheck : gencheck.o tree.def $(lang_tree_files) $(HOST_LIBDEPS) + $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ + gencheck.o $(HOST_LIBS) + +gencheck.o : gencheck.c hconfig.h system.h + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/gencheck.c + +dumpvers: dumpvers.c + +version.o: version.c +obstack.o: $(srcdir)/../libiberty/obstack.c $(CONFIG_H) + rm -f obstack.c + $(LN_S) $(srcdir)/../libiberty/obstack.c obstack.c + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) obstack.c + +choose-temp.o: $(srcdir)/../libiberty/choose-temp.c $(CONFIG_H) system.h + rm -f choose-temp.c + $(LN_S) $(srcdir)/../libiberty/choose-temp.c choose-temp.c + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) choose-temp.c + +mkstemp.o: $(srcdir)/../libiberty/mkstemp.c $(CONFIG_H) system.h + rm -f mkstemp.c + $(LN_S) $(srcdir)/../libiberty/mkstemp.c mkstemp.c + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) mkstemp.c + +prefix.o: prefix.c $(CONFIG_H) system.h Makefile prefix.h + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + -DPREFIX=\"$(prefix)\" \ + -c `echo $(srcdir)/prefix.c | sed 's,^\./,,'` + +convert.o: convert.c $(CONFIG_H) $(TREE_H) flags.h convert.h toplev.h + +tree.o : tree.c $(CONFIG_H) system.h $(TREE_H) flags.h function.h toplev.h except.h +print-tree.o : print-tree.c $(CONFIG_H) system.h $(TREE_H) +stor-layout.o : stor-layout.c $(CONFIG_H) system.h $(TREE_H) flags.h \ + function.h $(EXPR_H) $(RTL_H) toplev.h except.h +fold-const.o : fold-const.c $(CONFIG_H) system.h $(TREE_H) flags.h toplev.h \ + $(RTL_H) +# CYGNUS LOCAL live range +toplev.o : toplev.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) \ + flags.h input.h insn-attr.h xcoffout.h defaults.h output.h range.h \ + insn-codes.h insn-config.h $(RECOG_H) Makefile toplev.h dwarfout.h \ + dwarf2out.h sdbout.h dbxout.h $(EXPR_H) \ + $(lang_options_files) + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + -DTARGET_NAME=\"$(target_alias)\" \ + -c `echo $(srcdir)/toplev.c | sed 's,^\./,,'` +# END CYGNUS LOCAL + +rtl.o : rtl.c $(CONFIG_H) system.h $(RTL_H) bitmap.h + +print-rtl.o : print-rtl.c $(CONFIG_H) system.h $(RTL_H) bitmap.h +rtlanal.o : rtlanal.c $(CONFIG_H) system.h $(RTL_H) + +varasm.o : varasm.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) flags.h \ + function.h defaults.h $(EXPR_H) hard-reg-set.h $(REGS_H) \ + xcoffout.h output.h c-pragma.h toplev.h except.h dbxout.h sdbout.h +function.o : function.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h \ + function.h insn-flags.h insn-codes.h $(EXPR_H) $(REGS_H) hard-reg-set.h \ + insn-config.h $(RECOG_H) output.h toplev.h except.h +stmt.o : stmt.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h function.h \ + insn-flags.h insn-config.h insn-codes.h hard-reg-set.h $(EXPR_H) except.h \ + loop.h $(RECOG_H) toplev.h output.h varray.h +except.o : except.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h \ + function.h insn-flags.h $(EXPR_H) $(REGS_H) hard-reg-set.h \ + insn-config.h $(RECOG_H) output.h except.h toplev.h +expr.o : expr.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h function.h \ + $(REGS_H) insn-flags.h insn-codes.h $(EXPR_H) insn-config.h $(RECOG_H) output.h \ + typeclass.h hard-reg-set.h toplev.h hard-reg-set.h except.h +calls.o : calls.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h $(EXPR_H) \ + insn-flags.h $(REGS_H) toplev.h output.h +expmed.o : expmed.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h \ + insn-flags.h insn-config.h insn-codes.h $(EXPR_H) $(RECOG_H) real.h +explow.o : explow.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h \ + hard-reg-set.h insn-config.h $(EXPR_H) $(RECOG_H) insn-flags.h insn-codes.h +optabs.o : optabs.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h \ + insn-flags.h insn-config.h insn-codes.h $(EXPR_H) $(RECOG_H) reload.h +# CYGNUS LOCAL live range +dbxout.o : dbxout.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) flags.h $(REGS_H) \ + insn-config.h reload.h gstab.h xcoffout.h defaults.h output.h dbxout.h \ + toplev.h range.h +# END CYGNUS LOCAL +sdbout.o : sdbout.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) flags.h except.h \ + function.h $(EXPR_H) output.h hard-reg-set.h $(REGS_H) defaults.h real.h \ + insn-config.h $(srcdir)/../include/obstack.h xcoffout.h c-pragma.h \ + sdbout.h toplev.h +dwarfout.o : dwarfout.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) dwarf.h \ + flags.h insn-config.h reload.h output.h defaults.h toplev.h dwarfout.h +dwarf2out.o : dwarf2out.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) dwarf2.h \ + flags.h insn-config.h reload.h output.h defaults.h \ + hard-reg-set.h $(REGS_H) $(EXPR_H) toplev.h dwarf2out.h dyn-string.h +xcoffout.o : xcoffout.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) xcoffout.h \ + flags.h toplev.h output.h dbxout.h +emit-rtl.o : emit-rtl.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h \ + except.h function.h $(REGS_H) insn-config.h $(RECOG_H) real.h \ + $(EXPR_H) $(srcdir)/../include/obstack.h hard-reg-set.h bitmap.h +real.o : real.c $(CONFIG_H) system.h $(TREE_H) toplev.h +getpwd.o : getpwd.c $(CONFIG_H) system.h + +integrate.o : integrate.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h \ + integrate.h insn-flags.h insn-config.h $(EXPR_H) real.h $(REGS_H) \ + function.h output.h $(RECOG_H) except.h toplev.h + +jump.o : jump.c $(CONFIG_H) system.h $(RTL_H) flags.h hard-reg-set.h $(REGS_H) \ + insn-config.h insn-flags.h $(RECOG_H) $(EXPR_H) real.h except.h \ + toplev.h +stupid.o : stupid.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) hard-reg-set.h \ + $(BASIC_BLOCK_H) insn-config.h reload.h flags.h toplev.h + +cse.o : cse.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) hard-reg-set.h flags.h \ + real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h output.h +gcse.o : gcse.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) hard-reg-set.h flags.h \ + real.h insn-config.h $(RECOG_H) $(EXPR_H) $(BASIC_BLOCK_H) output.h +resource.o : resource.c $(CONFIG_H) $(RTL_H) hard-reg-set.h system.h \ + $(BASIC_BLOCK_H) $(REGS_H) flags.h output.h resource.h +# CYGNUS LOCAL lcm +lcm.o : lcm.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) hard-reg-set.h flags.h \ + real.h insn-config.h $(RECOG_H) $(EXPR_H) $(BASIC_BLOCK_H) +loop.o : loop.c $(CONFIG_H) system.h $(RTL_H) flags.h loop.h insn-config.h \ + insn-flags.h $(REGS_H) hard-reg-set.h $(RECOG_H) $(EXPR_H) real.h \ + toplev.h varray.h +unroll.o : unroll.c $(CONFIG_H) system.h $(RTL_H) insn-config.h \ + integrate.h $(REGS_H) $(RECOG_H) flags.h $(EXPR_H) loop.h toplev.h varray.h +flow.o : flow.c $(CONFIG_H) system.h $(RTL_H) flags.h insn-config.h \ + $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h recog.h +combine.o : combine.c $(CONFIG_H) system.h $(RTL_H) flags.h \ + insn-config.h insn-flags.h insn-codes.h insn-attr.h $(REGS_H) $(EXPR_H) \ + $(BASIC_BLOCK_H) $(RECOG_H) real.h hard-reg-set.h toplev.h +regclass.o : regclass.c $(CONFIG_H) system.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 \ + output.h +local-alloc.o : local-alloc.c $(CONFIG_H) system.h $(RTL_H) flags.h \ + $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h insn-config.h $(RECOG_H) output.h \ + insn-attr.h toplev.h +bitmap.o : bitmap.c $(CONFIG_H) system.h $(RTL_H) flags.h $(BASIC_BLOCK_H) \ + $(REGS_H) +# CYGNUS LOCAL live range +range.o : range.c $(CONFIG_H) $(RTL_H) $(TREE_H) $(BASIC_BLOCK_H) flags.h \ + $(REGS_H) hard-reg-set.h insn-config.h recog.h output.h expr.h insn-codes.h \ + range.h function.h except.h system.h toplev.h +global.o : global.c $(CONFIG_H) system.h $(RTL_H) flags.h reload.h \ + $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h insn-config.h output.h toplev.h \ + range.h +#END CYGNUS LOCAL +varray.o : varray.c $(CONFIG_H) system.h varray.h $(RTL_H) $(TREE_H) bitmap.h + +reload.o : reload.c $(CONFIG_H) system.h $(RTL_H) flags.h output.h $(EXPR_H) \ + reload.h $(RECOG_H) hard-reg-set.h insn-config.h insn-codes.h $(REGS_H) \ + real.h toplev.h +reload1.o : reload1.c $(CONFIG_H) system.h $(RTL_H) real.h flags.h $(EXPR_H) \ + reload.h $(REGS_H) hard-reg-set.h insn-config.h insn-flags.h insn-codes.h \ + $(BASIC_BLOCK_H) $(RECOG_H) output.h toplev.h +caller-save.o : caller-save.c $(CONFIG_H) system.h $(RTL_H) flags.h \ + $(REGS_H) hard-reg-set.h insn-config.h $(BASIC_BLOCK_H) \ + $(RECOG_H) reload.h $(EXPR_H) toplev.h +reorg.o : reorg.c $(CONFIG_H) system.h $(RTL_H) conditions.h hard-reg-set.h \ + $(BASIC_BLOCK_H) $(REGS_H) insn-config.h insn-attr.h \ + insn-flags.h $(RECOG_H) flags.h output.h $(EXPR_H) +alias.o : alias.c $(CONFIG_H) system.h $(RTL_H) flags.h hard-reg-set.h \ + $(REGS_H) toplev.h output.h $(EXPR_H) +regmove.o : regmove.c $(CONFIG_H) system.h $(RTL_H) insn-config.h \ + $(RECOG_H) output.h reload.h $(REGS_H) hard-reg-set.h flags.h \ + $(EXPR_H) insn-flags.h $(BASIC_BLOCK_H) toplev.h +$(SCHED_PREFIX)sched.o : $(SCHED_PREFIX)sched.c $(CONFIG_H) system.h $(RTL_H) \ + $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h flags.h insn-config.h \ + insn-attr.h toplev.h recog.h +# CYGNUS LOCAL live range +final.o : final.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h $(REGS_H) \ + $(RECOG_H) conditions.h insn-config.h insn-attr.h except.h real.h output.h \ + hard-reg-set.h insn-flags.h insn-codes.h gstab.h xcoffout.h defaults.h \ + toplev.h reload.h dwarfout.h dwarf2out.h sdbout.h dbxout.h range.h +# END CYGNUS LOCAL +recog.o : recog.c $(CONFIG_H) system.h $(RTL_H) \ + $(REGS_H) $(RECOG_H) hard-reg-set.h flags.h insn-config.h insn-attr.h \ + insn-flags.h insn-codes.h real.h toplev.h +reg-stack.o : reg-stack.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) recog.h \ + $(REGS_H) hard-reg-set.h flags.h insn-config.h insn-flags.h toplev.h +dyn-string.o: dyn-string.c dyn-string.h $(CONFIG_H) system.h + +$(out_object_file): $(out_file) $(CONFIG_H) $(TREE_H) \ + $(RTL_H) $(REGS_H) hard-reg-set.h real.h insn-config.h conditions.h \ + insn-flags.h output.h insn-attr.h insn-codes.h system.h toplev.h + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(out_file) + +# 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 machmode.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 + +# Build file to support OSF/rose half-pic format. +halfpic.o: halfpic.c $(CONFIG_H) $(RTL_H) $(TREE_H) system.h + +# Normally this target is not used; but it is used if you +# define ALLOCA=alloca.o. In that case, you must get a suitable alloca.c +# from the GNU Emacs distribution. +alloca.o: $(srcdir)/../libiberty/alloca.c + rm -f alloca.c + $(LN_S) $(srcdir)/../libiberty/alloca.c alloca.c + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(ALLOCA_FLAGS) \ + -c `echo alloca.c | sed 's,^\./,,'` + $(ALLOCA_FINISH) +# +# Generate header and source files from the machine description, +# and compile them. + +.PRECIOUS: insn-config.h insn-flags.h insn-codes.h \ + insn-emit.c insn-recog.c insn-extract.c insn-output.c insn-peep.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 $(srcdir)/move-if-change + ./genconfig $(md_file) > tmp-config.h + $(srcdir)/move-if-change tmp-config.h insn-config.h + touch s-config + +insn-flags.h: s-flags ; @true +s-flags : $(md_file) genflags $(srcdir)/move-if-change + ./genflags $(md_file) > tmp-flags.h + $(srcdir)/move-if-change tmp-flags.h insn-flags.h + touch s-flags + +insn-codes.h: s-codes ; @true +s-codes : $(md_file) gencodes $(srcdir)/move-if-change + ./gencodes $(md_file) > tmp-codes.h + $(srcdir)/move-if-change tmp-codes.h insn-codes.h + touch s-codes + +insn-emit.o : insn-emit.c $(CONFIG_H) $(RTL_H) $(EXPR_H) real.h output.h \ + insn-config.h insn-flags.h insn-codes.h system.h reload.h recog.h + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c insn-emit.c + +insn-emit.c: s-emit ; @true +s-emit : $(md_file) genemit $(srcdir)/move-if-change + ./genemit $(md_file) > tmp-emit.c + $(srcdir)/move-if-change tmp-emit.c insn-emit.c + touch s-emit + +insn-recog.o : insn-recog.c $(CONFIG_H) $(RTL_H) insn-config.h $(RECOG_H) \ + real.h output.h flags.h system.h + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c insn-recog.c + +insn-recog.c: s-recog ; @true +s-recog : $(md_file) genrecog $(srcdir)/move-if-change + ./genrecog $(md_file) > tmp-recog.c + $(srcdir)/move-if-change tmp-recog.c insn-recog.c + touch s-recog + +insn-opinit.o : insn-opinit.c $(CONFIG_H) $(RTL_H) insn-codes.h insn-flags.h \ + insn-config.h flags.h $(RECOG_H) $(EXPR_H) reload.h system.h + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c insn-opinit.c + +insn-opinit.c: s-opinit ; @true +s-opinit : $(md_file) genopinit $(srcdir)/move-if-change + ./genopinit $(md_file) > tmp-opinit.c + $(srcdir)/move-if-change tmp-opinit.c insn-opinit.c + touch s-opinit + +insn-extract.o : insn-extract.c $(CONFIG_H) $(RTL_H) system.h toplev.h \ + insn-config.h recog.h + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c insn-extract.c + +insn-extract.c: s-extract ; @true +s-extract : $(md_file) genextract $(srcdir)/move-if-change + ./genextract $(md_file) > tmp-extract.c + $(srcdir)/move-if-change tmp-extract.c insn-extract.c + touch s-extract + +insn-peep.o : insn-peep.c $(CONFIG_H) $(RTL_H) $(REGS_H) output.h real.h \ + system.h insn-config.h recog.h + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c insn-peep.c + +insn-peep.c: s-peep ; @true +s-peep : $(md_file) genpeep $(srcdir)/move-if-change + ./genpeep $(md_file) > tmp-peep.c + $(srcdir)/move-if-change tmp-peep.c insn-peep.c + touch s-peep + +insn-attrtab.o : insn-attrtab.c $(CONFIG_H) $(RTL_H) $(REGS_H) real.h \ + output.h insn-attr.h insn-config.h system.h toplev.h + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c insn-attrtab.c + +insn-attr.h: s-attr ; @true +s-attr : $(md_file) genattr $(srcdir)/move-if-change + ./genattr $(md_file) > tmp-attr.h + $(srcdir)/move-if-change tmp-attr.h insn-attr.h + touch s-attr + +insn-attrtab.c: s-attrtab ; @true +s-attrtab : $(md_file) genattrtab $(srcdir)/move-if-change + if cmp -s $(PREMADE_ATTRTAB_MD) $(md_file); \ + then \ + echo Using $(PREMADE_ATTRTAB); \ + cp $(PREMADE_ATTRTAB) tmp-attrtab.c; \ + else \ + ./genattrtab $(md_file) > tmp-attrtab.c; \ + fi + $(srcdir)/move-if-change tmp-attrtab.c insn-attrtab.c + touch s-attrtab + +insn-output.o : insn-output.c $(CONFIG_H) $(RTL_H) $(REGS_H) real.h conditions.h \ + hard-reg-set.h insn-config.h insn-flags.h insn-attr.h output.h $(RECOG_H) \ + insn-codes.h system.h + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c insn-output.c + +insn-output.c: s-output ; @true +s-output : $(md_file) genoutput $(srcdir)/move-if-change + ./genoutput $(md_file) > tmp-output.c + $(srcdir)/move-if-change tmp-output.c insn-output.c + touch s-output + +genrtl.o : genrtl.c $(CONFIG_H) $(RTL_H) system.h +genrtl.c genrtl.h : s-genrtl + @true # force gnu make to recheck modification times. + +s-genrtl: gengenrtl $(srcdir)/move-if-change $(RTL_BASE_H) + ./gengenrtl tmp-genrtl.h tmp-genrtl.c + $(srcdir)/move-if-change tmp-genrtl.h genrtl.h + $(srcdir)/move-if-change tmp-genrtl.c genrtl.c + touch s-genrtl + +# +# Compile the programs that generate insn-* from the machine description. +# They are compiled with $(HOST_CC), and associated libraries, +# since they need to run on this machine +# even if GCC is being compiled to run on some other machine. + +# $(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. + +# Pass the md file through cpp if the target requests it. +$(MD_FILE): $(MD_DEPS) + rm -f $@ + $(MD_CPP) $(MD_CPPFLAGS) $(md_file) | sed 's/^# /; /g' > tmp-$@ + mv tmp-$@ $@ + +genconfig : genconfig.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBDEPS) + $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ + genconfig.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBS) + +genconfig.o : genconfig.c $(RTL_H) $(build_xm_file) system.h + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genconfig.c + +genflags : genflags.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBDEPS) + $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ + genflags.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBS) + +genflags.o : genflags.c $(RTL_H) $(build_xm_file) system.h + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genflags.c + +gencodes : gencodes.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBDEPS) + $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ + gencodes.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBS) + +gencodes.o : gencodes.c $(RTL_H) $(build_xm_file) system.h + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/gencodes.c + +genemit : genemit.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBDEPS) + $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ + genemit.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBS) + +genemit.o : genemit.c $(RTL_H) $(build_xm_file) system.h + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genemit.c + +genopinit : genopinit.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBDEPS) + $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ + genopinit.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBS) + +genopinit.o : genopinit.c $(RTL_H) $(build_xm_file) system.h + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genopinit.c + +genrecog : genrecog.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBDEPS) + $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ + genrecog.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBS) + +genrecog.o : genrecog.c $(RTL_H) $(build_xm_file) system.h + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genrecog.c + +genextract : genextract.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBDEPS) + $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ + genextract.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBS) + +genextract.o : genextract.c $(RTL_H) $(build_xm_file) system.h insn-config.h + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genextract.c + +genpeep : genpeep.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBDEPS) + $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ + genpeep.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBS) + +genpeep.o : genpeep.c $(RTL_H) $(build_xm_file) system.h + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genpeep.c + +genattr : genattr.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBDEPS) + $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ + genattr.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBS) + +genattr.o : genattr.c $(RTL_H) $(build_xm_file) system.h + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genattr.c + +genattrtab : genattrtab.o $(HOST_RTL) $(HOST_PRINT) $(HOST_RTLANAL) $(HOST_LIBDEPS) + $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ + genattrtab.o $(HOST_RTL) $(HOST_PRINT) $(HOST_RTLANAL) $(HOST_LIBS) + +genattrtab.o : genattrtab.c $(RTL_H) $(build_xm_file) system.h insn-config.h + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genattrtab.c + +genoutput : genoutput.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBDEPS) + $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ + genoutput.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBS) + +genoutput.o : genoutput.c $(RTL_H) $(build_xm_file) system.h + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genoutput.c + +gengenrtl : gengenrtl.o $(HOST_LIBDEPS) + $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ + gengenrtl.o $(HOST_LIBS) + +gengenrtl.o : gengenrtl.c $(RTL_BASE_H) system.h + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/gengenrtl.c + +# +# 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 HOST_PREFIX_1 is `foobar', just to ensure these rules don't conflict +# with the rules for rtl.o, alloca.o, etc. +$(HOST_PREFIX_1)rtl.o: $(srcdir)/rtl.c $(CONFIG_H) system.h $(RTL_H) bitmap.h + rm -f $(HOST_PREFIX)rtl.c + sed -e 's/config[.]h/hconfig.h/' $(srcdir)/rtl.c > $(HOST_PREFIX)rtl.c + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)rtl.c + +$(HOST_PREFIX_1)print-rtl.o: $(srcdir)/print-rtl.c $(CONFIG_H) $(RTL_H) + rm -f $(HOST_PREFIX)print-rtl.c + sed -e 's/config[.]h/hconfig.h/' $(srcdir)/print-rtl.c > $(HOST_PREFIX)print-rtl.c + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)print-rtl.c + +$(HOST_PREFIX_1)bitmap.o: $(srcdir)/bitmap.c $(CONFIG_H) system.h $(RTL_H) \ + flags.h $(BASIC_BLOCK_H) $(REGS_H) + rm -f $(HOST_PREFIX)bitmap.c + sed -e 's/config[.]h/hconfig.h/' $(srcdir)/bitmap.c > $(HOST_PREFIX)bitmap.c + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)bitmap.c + +$(HOST_PREFIX_1)rtlanal.o: $(srcdir)/rtlanal.c $(CONFIG_H) $(RTL_H) + rm -f $(HOST_PREFIX)rtlanal.c + sed -e 's/config[.]h/hconfig.h/' $(srcdir)/rtlanal.c > $(HOST_PREFIX)rtlanal.c + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)rtlanal.c + +$(HOST_PREFIX_1)alloca.o: $(srcdir)/../libiberty/alloca.c + rm -f $(HOST_PREFIX)alloca.c + $(LN_S) $(srcdir)/../libiberty/alloca.c $(HOST_PREFIX)alloca.c + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)alloca.c + +$(HOST_PREFIX_1)obstack.o: $(srcdir)/../libiberty/obstack.c + rm -f $(HOST_PREFIX)obstack.c + sed -e 's/config[.]h/hconfig.h/' $(srcdir)/../libiberty/obstack.c > $(HOST_PREFIX)obstack.c + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)obstack.c + +$(HOST_PREFIX_1)vfprintf.o: $(srcdir)/../libiberty/vfprintf.c + rm -f $(HOST_PREFIX)vfprintf.c + sed -e 's/config[.]h/hconfig.h/' $(srcdir)/../libiberty/vfprintf.c > $(HOST_PREFIX)vfprintf.c + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)vfprintf.c + +$(HOST_PREFIX_1)doprint.o: doprint.c + rm -f $(HOST_PREFIX)doprint.c + sed -e 's/config[.]h/hconfig.h/' $(srcdir)/doprint.c > $(HOST_PREFIX)doprint.c + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)doprint.c + +$(HOST_PREFIX_1)malloc.o: malloc.c + rm -f $(HOST_PREFIX)malloc.c + sed -e 's/config[.]h/hconfig.h/' $(srcdir)/malloc.c > $(HOST_PREFIX)malloc.c + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)malloc.c + +# This satisfies the dependency that we get if you cross-compile a compiler +# that does not need to compile alloca, malloc or whatever. +$(HOST_PREFIX_1): + touch $(HOST_PREFIX_1) + +# +# Remake cpp. + +# Making the preprocessor +cpp$(exeext): $(CCCP)$(exeext) + -rm -f cpp$(exeext) + $(LN) $(CCCP)$(exeext) cpp$(exeext) +cccp$(exeext): cccp.o cexp.o version.o prefix.o mbchar.o @extra_cpp_objs@ $(LIBDEPS) + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ cccp.o cexp.o prefix.o mbchar.o \ + version.o @extra_cpp_objs@ $(LIBS) +# CYGNUS LOCAL: built in build directory +cexp.o: cexp.c $(CONFIG_H) system.h + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c cexp.c +cexp.c: $(srcdir)/cexp.y + $(BISON) $(BISONFLAGS) $(srcdir)/cexp.y -o cexp.c +# We use $(libsubdir)/$(unlibsubdir) to match the +# -iprefix argument which gcc will pass if GCC_EXEC_PREFIX is used. +cccp.o: cccp.c $(CONFIG_H) pcp.h version.c config.status system.h \ + mbchar.h prefix.h Makefile + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + -DGCC_INCLUDE_DIR=\"$(libsubdir)/include\" \ + -DGPLUSPLUS_INCLUDE_DIR=\"$(gcc_gxx_include_dir)\" \ + -DLOCAL_INCLUDE_DIR=\"$(includedir)\" \ + -DCROSS_INCLUDE_DIR=\"$(gcc_tooldir)/sys-include\" \ + -DTOOL_INCLUDE_DIR=\"$(gcc_tooldir)/include\" \ + -c `echo $(srcdir)/cccp.c | sed 's,^\./,,'` + +LIBCPP_OBJS = cpplib.o cpphash.o cppalloc.o cpperror.o cppexp.o cppfiles.o \ + cppulp.o prefix.o version.o \ + mbchar.o + +# All the other archives built/used by this makefile are for targets. This +# one is strictly for the host. +# +libcpp.a: $(LIBCPP_OBJS) + $(AR) $(AR_FLAGS) libcpp.a $(LIBCPP_OBJS) + if $(RANLIB_TEST) ; then $(RANLIB) libcpp.a ; else true ; fi + +cppmain$(exeext): cppmain.o libcpp.a $(LIBDEPS) + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o cppmain$(exeext) cppmain.o \ + libcpp.a $(LIBS) + +cppmain.o: cppmain.c $(CONFIG_H) cpplib.h machmode.h system.h + +cpplib.o: cpplib.c $(CONFIG_H) cpplib.h machmode.h cpphash.h config.status \ + system.h prefix.h Makefile + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + -DGCC_INCLUDE_DIR=\"$(libsubdir)/include\" \ + -DGPLUSPLUS_INCLUDE_DIR=\"$(gcc_gxx_include_dir)\" \ + -DLOCAL_INCLUDE_DIR=\"$(includedir)\" \ + -DCROSS_INCLUDE_DIR=\"$(gcc_tooldir)/sys-include\" \ + -DTOOL_INCLUDE_DIR=\"$(gcc_tooldir)/include\" \ + -c `echo $(srcdir)/cpplib.c | sed 's,^\./,,'` + +cpperror.o: cpperror.c $(CONFIG_H) cpplib.h machmode.h system.h + +cppulp.o: cppulp.c $(CONFIG_H) system.h output.h + +cppexp.o: cppexp.c $(CONFIG_H) cpplib.h machmode.h system.h + +cppfiles.o: cppfiles.c $(CONFIG_H) cpplib.h machmode.h system.h + +cpphash.o: cpphash.c cpplib.h machmode.h cpphash.h $(CONFIG_H) system.h + +cppalloc.o: cppalloc.c $(CONFIG_H) cpplib.h machmode.h system.h + +# Note for the stamp targets, we run the program `true' instead of +# having an empty command (nothing following the semicolon). + +getopt.o: $(srcdir)/../libiberty/getopt.c $(srcdir)/../include/getopt.h + rm -f getopt.c + $(LN_S) $(srcdir)/../libiberty/getopt.c getopt.c + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) getopt.c + +getopt1.o: $(srcdir)/../libiberty/getopt1.c $(srcdir)/../include/getopt.h + rm -f getopt1.c + $(LN_S) $(srcdir)/../libiberty/getopt1.c getopt1.c + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) getopt1.c + +# This info describes the target machine, so compile with GCC just built. +SYSCALLS.c.X: $(srcdir)/sys-types.h $(srcdir)/sys-protos.h $(GCC_PASSES) \ + stmp-int-hdrs + -rm -f SYSCALLS.c tmp-SYSCALLS.s + cat $(srcdir)/sys-types.h $(srcdir)/sys-protos.h > SYSCALLS.c + $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + -aux-info $@ -S -o tmp-SYSCALLS.s SYSCALLS.c + -rm -f SYSCALLS.c tmp-SYSCALLS.s + +# Build the include directory. The stamp files are stmp-* rather than +# s-* so that mostlyclean does not force the include directory to +# be rebuilt. + +# Build the include directory including float.h (which no longer depends upon +# enquire). +stmp-int-hdrs: $(USER_H) xlimits.h +# Copy in the headers provided with gcc. + rm -rf include + mkdir include + for file in .. $(USER_H); do \ + if [ X$$file != X.. ]; then \ + realfile=`basename $$file`; \ + cp $$file include; \ + chmod a+r include/$$realfile; \ + fi; \ + done + rm -f include/limits.h + cp xlimits.h include/limits.h + chmod a+r include/limits.h + rm -f include/float.h + if [ x$(FLOAT_H) != xMakefile.in ]; then \ + cp $(srcdir)/config/$(FLOAT_H) include/float.h && \ + chmod a+r include/float.h; \ + fi + +# Now that float.h no longer depends upon enquire, this is actually a no-op. +stmp-headers: + touch $@ + +# Remake the info files. +# CYGNUS LOCAL: built in build directory + +doc: info INSTALL +info: cpp.info gcc.info lang.info + +cpp.info: $(srcdir)/cpp.texi + $(MAKEINFO) $(MAKEINFOFLAGS) -I$(srcdir) -o cpp.info $(srcdir)/cpp.texi + +gcc.info: $(srcdir)/gcc.texi extend.texi install.texi invoke.texi \ + md.texi rtl.texi tm.texi + $(MAKEINFO) $(MAKEINFOFLAGS) -I$(srcdir) -o gcc.info $(srcdir)/gcc.texi + +dvi: gcc.dvi cpp.dvi lang.dvi + +gcc.dvi: $(srcdir)/gcc.texi $(srcdir)/extend.texi $(srcdir)/invoke.texi $(srcdir)/md.texi $(srcdir)/rtl.texi $(srcdir)/tm.texi + TEXINPUTS=${texidir}:$(srcdir):$$TEXINPUTS tex gcc.texi + texindex gcc.?? + TEXINPUTS=${texidir}:$(srcdir):$$TEXINPUTS tex gcc.texi + +cpp.dvi: $(srcdir)/cpp.texi + TEXINPUTS=${texidir}:$(srcdir):$$TEXINPUTS tex cpp.texi + texindex cpp.?? + TEXINPUTS=${texidir}:$(srcdir):$$TEXINPUTS tex cpp.texi + +# CYGNUS LOCAL doc +usegcc.dvi: usegcc.texi $(srcdir)/extend.texi $(srcdir)/invoke.texi $(srcdir)/md.texi + TEXINPUTS=${texidir}:$(srcdir):$$TEXINPUTS tex usegcc.texi + texindex usegcc.?? + TEXINPUTS=${texidir}:$(srcdir):$$TEXINPUTS tex usegcc.texi + +usegcc.texi: $(srcdir)/gcc.texi + sed -e '/@setfilename gcc.info/d' \ + -e '/@c @setfilename usegcc.info/s/@c //' \ + -e '/@set INTERNALS/s/@/@c @/' \ + -e '/@c @clear INTERNALS/s/@c //' \ + $(srcdir)/gcc.texi > usegcc.texi + + +usegcc.info: usegcc.texi $(srcdir)/extend.texi $(srcdir)/invoke.texi + $(MAKEINFO) -I$(srcdir) -o usegcc.info usegcc.texi + +# CYGNUS LOCAL: don't rebuild gcc/INSTALL, ever. +#INSTALL: $(srcdir)/install1.texi $(srcdir)/install.texi +# cd $(srcdir); $(MAKEINFO) -D INSTALLONLY \ +# --no-split -o INSTALL install1.texi +# +# Deletion of files made during compilation. +# There are four levels of this: +# `mostlyclean', `clean', `distclean' and `maintainer-clean'. +# `mostlyclean' is useful while working on a particular type of machine. +# It deletes most, but not all, of the files made by compilation. +# It does not delete libgcc.a or its parts, so it won't have to be recompiled. +# `clean' deletes everything made by running `make all'. +# `distclean' also deletes the files made by config. +# `maintainer-clean' also deletes everything that could be regenerated +# automatically, except for `configure'. +# We remove as much from the language subdirectories as we can +# (less duplicated code). + + +mostlyclean: lang.mostlyclean + -rm -f $(STAGESTUFF) +# Delete the temporary source copies for cross compilation. + -rm -f $(HOST_PREFIX_1)rtl.c $(HOST_PREFIX_1)rtlanal.c + -rm -f $(HOST_PREFIX_1)alloca.c $(HOST_PREFIX_1)malloc.c + -rm -f $(HOST_PREFIX_1)obstack.c +# Delete the temp files made in the course of building libgcc.a. + -rm -f tmplibgcc* tmpcopy xlimits.h libgcc1-test + for name in $(LIB1FUNCS); do rm -f $${name}.c; done +# Delete other built files. + -rm -f t-float.h-cross xsys-protos.hT fp-bit.c dp-bit.c +# Delete the stamp and temporary files. + -rm -f s-* tmp-* stamp-* stmp-* + -rm -f */stamp-* */tmp-* +# Delete debugging dump files. + -rm -f *.greg *.lreg *.combine *.flow *.cse *.jump *.rtl *.tree *.loop + -rm -f *.dbr *.jump2 *.sched *.cse2 *.sched2 *.stack *.addressof + -rm -f *.regmove *.mach *.bp *.gcse + -rm -f */*.greg */*.lreg */*.combine */*.flow */*.cse */*.jump */*.rtl + -rm -f */*.tree */*.loop */*.dbr */*.jump2 */*.sched */*.cse2 + -rm -f */*.sched2 */*.stack */*.regmove */*.gcse +# Delete some files made during installation. + -rm -f specs float.h-* enquire SYSCALLS.c.X SYSCALLS.c + -rm -f collect mips-tfile mips-tdump alloca.s +# CYGNUS LOCAL: binary installation +# 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 +# Delete sorted indices we don't actually use. + -rm -f gcc.vrs gcc.kys gcc.tps gcc.pgs gcc.fns +# Delete core dumps. + -rm -f core */core +# CYGNUS LOCAL: built in build directory + -rm -f y.tab.c y.tab.h y.output +# Delete these files here instead of in realclean because they are now created +# in the build subdirectories. + -rm -f c-parse.output + -rm -f cexp.c cexp.output $(BUILD_SO1) $(BUILD_SO2) $(BUILD_SO3) +# END CYGNUS LOCAL +# CYGNUS LOCAL: live range + -rm -f *.range */*.range +# END CYGNUS LOCAL + -rm -f *.bp */*.bp + +# Delete all files made by compilation +# that don't exist in the distribution. +clean: mostlyclean lang.clean +# It may not be quite desirable to delete unprotoize.c here, +# but the spec for `make clean' requires it. +# Using unprotoize.c is not quite right in the first place, +# but what better way is there? + -rm -f libgcc.a libgcc1.a libgcc1-asm.a libgcc2.a libgcc2.ready + -rm -f libgcc1.null + -rm -f *.dvi + -rm -f */*.dvi + -if [ -f md.pre-cpp ]; then \ + rm -f md ; \ + fi +# Delete the include directory. + -rm -rf include +# Delete files used by the "multilib" facility (including libgcc subdirs). + -rm -f multilib.h tmpmultilib* + -if [ "x$(MULTILIB_DIRNAMES)" != x ] ; then \ + rm -rf $(MULTILIB_DIRNAMES); \ + else if [ "x$(MULTILIB_OPTIONS)" != x ] ; then \ + rm -rf `echo $(MULTILIB_OPTIONS) | sed -e 's/\// /g'`; \ + fi ; fi +# CYGNUS LOCAL: built in build directory + -rm -f c-parse.y +# END CYGNUS LOCAL + -rm -fr stage1 stage2 stage3 stage4 + +# Delete all files that users would normally create +# while building and installing GCC. +distclean: clean lang.distclean + -rm -f tm.h config.h auto-host.h auto-build.h tconfig.h hconfig.h + -rm -f md cstamp-h + -rm -f config.status config.run config.cache config.bak + -rm -f Make-lang Make-hooks Make-host Make-target + -rm -f Makefile specs.h options.h gencheck.h *.oaux + -rm -f gthr-default.h + -rm -f */stage1 */stage2 */stage3 */stage4 */include + -rm -f c-parse.output + -rm -f *.asm + -rm -f float.h + -rm -f site.exp site.bak testsuite/site.exp testsuite/site.bak + -rm -f testsuite/{gcc,g++}.{log,sum} + +# Delete anything likely to be found in the source directory +# that shouldn't be in the distribution. +extraclean: distclean lang.extraclean + -rm -rf =* ./"#"* *~* config/=* config/"#"* config/*~* + -rm -f patch* *.orig *.rej config/patch* config/*.orig config/*.rej + -rm -f config/*/=* config/*/"#"* config/*/*~* + -rm -f config/*/*.orig config/*/*.rej + -rm -f *.dvi *.ps *.oaux *.d *.[zZ] *.gz + -rm -f *.tar *.xtar *diff *.diff.* *.tar.* *.xtar.* *diffs + -rm -f *lose config/*lose config/*/*lose + -rm -f *.s *.s[0-9] *.i config/ChangeLog + -rm -f */=* */"#"* */*~* + -rm -f */patch* */*.orig */*.rej + -rm -f */*.dvi */*.oaux */*.d */*.[zZ] */*.gz + -rm -f */*.tar */*.xtar */*diff */*.diff.* */*.tar.* */*.xtar.* */*diffs + -rm -f */*lose */*.s */*.s[0-9] */*.i + +# 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. +maintainer-clean: + @echo 'This command is intended for maintainers to use; it' + @echo 'deletes files that may need special tools to rebuild.' + $(MAKE) distclean lang.maintainer-clean + -rm -f c-parse.y c-gperf.h + -rm -f c-parse.c c-parse.h c-parse.output + -rm -f cexp.c cexp.output TAGS + -rm -f cpp.info* cpp.??s cpp.*aux + -rm -f gcc.info* gcc.??s gcc.*aux +# CYGNUS LOCAL: Delete locally created files. + -rm -f *.as cp-hash.h +# END CYGNUS LOCAL + +# CYGNUS LOCAL: realclean +realclean: maintainer-clean +# END CYGNUS LOCAL +# +# Entry points `install' and `uninstall'. + +# The semicolon is to prevent the install.sh -> install default rule +# from doing anything. Having it run true helps avoid problems and +# noise from versions of make which don't like to have null commands. +install: $(INSTALL_TARGET) ; @true + +# Copy the compiler files into directories where they will be run. +# Install the driver last so that the window when things are +# broken is small. +# CYGNUS LOCAL: install-info done separately. +install-normal: install-common $(INSTALL_HEADERS) $(INSTALL_LIBGCC) \ + install-man lang.install-normal install-driver + +# Do nothing while making gcc with a cross-compiler. The person who +# makes gcc for the target machine has to know how to put a complete +# gcc together by hand. +install-build: force + @echo You have to install gcc on your target machine by hand. + +# Run this on the target machine +# to finish installation of cross compiler. +# This is not used anymore now that float.h does not depend on enquire. +install-cross-rest: install-float-h-cross + +# Install float.h for cross compiler. +# Run this on the target machine! +# This is not used anymore now that float.h does not depend on enquire. +install-float-h-cross: installdirs +# if [ -f enquire ] ; then true; else false; fi +# Note: don't use -. We should fail right away if enquire was not made. + ./enquire -f > $(tmpdir)/float.h + -rm -f $(libsubdir)/include/float.h + $(INSTALL_DATA) $(tmpdir)/float.h $(libsubdir)/include/float.h + -rm -f $(tmpdir)/float.h + chmod a-x $(libsubdir)/include/float.h + +# Create the installation directories. +installdirs: + -if [ -d $(prefix) ] ; then true ; else mkdir $(prefix) ; chmod a+rx $(prefix) ; fi + -if [ -d $(exec_prefix) ] ; then true ; else mkdir $(exec_prefix) ; chmod a+rx $(exec_prefix) ; fi + -if [ -d $(libdir) ] ; then true ; else mkdir $(libdir) ; chmod a+rx $(libdir) ; fi + -if [ -d $(libdir)/gcc-lib ] ; then true ; else mkdir $(libdir)/gcc-lib ; chmod a+rx $(libdir)/gcc-lib ; fi +# This dir isn't currently searched by cpp. +# -if [ -d $(libdir)/gcc-lib/include ] ; then true ; else mkdir $(libdir)/gcc-lib/include ; chmod a+rx $(libdir)/gcc-lib/include ; fi + -fdir= ; for dir in `echo $(libsubdir) | tr '/' ' '`; do \ + fdir=$${fdir}/$${dir}; \ + if [ -d $${fdir} ] ; then true ; else mkdir $${fdir}; chmod a+rx $${fdir}; fi ; \ + done + -if [ -d $(bindir) ] ; then true ; else mkdir $(bindir) ; chmod a+rx $(bindir) ; fi + -if [ -d $(includedir) ] ; then true ; else mkdir $(includedir) ; chmod a+rx $(includedir) ; fi + -if [ -d $(gcc_tooldir) ] ; then true ; else mkdir $(gcc_tooldir) ; chmod a+rx $(gcc_tooldir) ; fi + -if [ -d $(assertdir) ] ; then true ; else mkdir $(assertdir) ; chmod a+rx $(assertdir) ; fi + -if [ -d $(infodir) ] ; then true ; else mkdir $(infodir) ; chmod a+rx $(infodir) ; fi +# We don't use mkdir -p to create the parents of man1dir, +# because some systems don't support it. +# Instead, we use this technique to create the immediate parent of man1dir. + -parent=`echo $(man1dir)|sed -e 's@/[^/]*$$@@'`; \ + if [ -d $$parent ] ; then true ; else mkdir $$parent ; chmod a+rx $$parent ; fi + -if [ -d $(man1dir) ] ; then true ; else mkdir $(man1dir) ; chmod a+rx $(man1dir) ; fi + +# Install the compiler executables built during cross compilation. +install-common: native installdirs lang.install-common + for file in $(COMPILERS); do \ + if [ -f $$file ] ; then \ + rm -f $(libsubdir)/$$file; \ + $(INSTALL_PROGRAM) $$file $(libsubdir)/$$file; \ + else true; \ + fi; \ + done + for file in $(EXTRA_PASSES) $(EXTRA_PROGRAMS) ..; do \ + if [ x"$$file" != x.. ]; then \ + rm -f $(libsubdir)/$$file; \ + $(INSTALL_PROGRAM) $$file $(libsubdir)/$$file; \ + else true; fi; \ + done +# Don't mess with specs if it doesn't exist yet. + -if [ -f specs ] ; then \ + rm -f $(libsubdir)/specs; \ + $(INSTALL_DATA) specs $(libsubdir)/specs; \ + chmod a-x $(libsubdir)/specs; \ + fi + +# Install the driver program as $(target_alias)-gcc +# and also as either gcc (if native) or $(gcc_tooldir)/bin/gcc. +install-driver: xgcc$(exeext) + -if [ -f gcc-cross$(exeext) ] ; then \ + rm -f $(bindir)/$(GCC_CROSS_NAME)$(exeext); \ + $(INSTALL_PROGRAM) gcc-cross$(exeext) $(bindir)/$(GCC_CROSS_NAME)$(exeext); \ + if [ -d $(gcc_tooldir)/bin/. ] ; then \ + rm -f $(gcc_tooldir)/bin/gcc$(exeext); \ + $(INSTALL_PROGRAM) gcc-cross$(exeext) $(gcc_tooldir)/bin/gcc$(exeext); \ + else true; fi; \ + else \ + rm -f $(bindir)/$(GCC_INSTALL_NAME)$(exeext); \ + $(INSTALL_PROGRAM) xgcc$(exeext) $(bindir)/$(GCC_INSTALL_NAME)$(exeext); \ + rm -f $(bindir)/$(target_alias)-gcc-1$(exeext); \ + $(LN) $(bindir)/$(GCC_INSTALL_NAME)$(exeext) $(bindir)/$(target_alias)-gcc-1$(exeext); \ + mv $(bindir)/$(target_alias)-gcc-1$(exeext) $(bindir)/$(target_alias)-gcc$(exeext); \ + fi + +# Install the info files. +# $(INSTALL_DATA) might be a relative pathname, so we can't cd into srcdir +# to do the install. The sed rule was copied from stmp-int-hdrs. +# CYGNUS LOCAL: Handle an arbitrary set of .info files. +install-info: doc installdirs lang.install-info + -for i in *.info*; do \ + rm -f $(infodir)/$$i; \ + $(INSTALL_DATA) $$i $(infodir)/$$i; \ + done + -if $(SHELL) -c 'install-info --version' >/dev/null 2>&1; then \ + if [ -f $(infodir)/dir ] ; then \ + for f in *.info; do \ + install-info --dir-file=$(infodir)/dir $(infodir)/$$f; \ + done; \ + else true; fi; \ + else true; fi; + -chmod a-x $(infodir)/*.info* + +# CYGNUS LOCAL: clean-info +clean-info: + -rm -f *.info* + +# Install the man pages. +install-man: installdirs $(srcdir)/gcc.1 $(srcdir)/cccp.1 lang.install-man + -if [ -f gcc-cross$(exeext) ] ; then \ + rm -f $(man1dir)/$(GCC_CROSS_NAME)$(manext); \ + $(INSTALL_DATA) $(srcdir)/gcc.1 $(man1dir)/$(GCC_CROSS_NAME)$(manext); \ + chmod a-x $(man1dir)/$(GCC_CROSS_NAME)$(manext); \ + else \ + rm -f $(man1dir)/$(GCC_INSTALL_NAME)$(manext); \ + $(INSTALL_DATA) $(srcdir)/gcc.1 $(man1dir)/$(GCC_INSTALL_NAME)$(manext); \ + chmod a-x $(man1dir)/$(GCC_INSTALL_NAME)$(manext); \ + fi + -rm -f $(man1dir)/cccp$(manext) + -$(INSTALL_DATA) $(srcdir)/cccp.1 $(man1dir)/cccp$(manext) + -chmod a-x $(man1dir)/cccp$(manext) + # CYGNUS LOCAL: We install cpp.1. + -$(INSTALL_DATA) $(srcdir)/cpp.1 $(man1dir)/cpp$(manext) + -chmod a-x $(man1dir)/cpp$(manext) + +# Install the library. +install-libgcc: libgcc.a installdirs + -if [ -f libgcc.a ] ; then \ + rm -f $(libsubdir)/libgcc.a; \ + $(INSTALL_DATA) libgcc.a $(libsubdir)/libgcc.a; \ + if $(RANLIB_TEST_FOR_TARGET) ; then \ + (cd $(libsubdir); $(RANLIB_FOR_TARGET) libgcc.a); else true; fi; \ + chmod a-x $(libsubdir)/libgcc.a; \ + else true; fi + +# Install multiple versions of libgcc.a. +install-multilib: stmp-multilib installdirs + for i in `$(GCC_FOR_TARGET) --print-multi-lib`; do \ + dir=`echo $$i | sed -e 's/;.*$$//'`; \ + if [ -d $(libsubdir)/$${dir} ]; then true; else mkdir $(libsubdir)/$${dir}; fi; \ + for f in libgcc.a $(EXTRA_MULTILIB_PARTS); do \ + rm -f $(libsubdir)/$${dir}/$${f}; \ + $(INSTALL_DATA) $${dir}/$${f} $(libsubdir)/$${dir}/$${f}; \ + done; \ + if $(RANLIB_TEST_FOR_TARGET); then \ + (cd $(libsubdir)/$${dir}; $(RANLIB_FOR_TARGET) libgcc.a); \ + else true; fi; \ + chmod a-x $(libsubdir)/$${dir}/libgcc.a; \ + done + +# Install all the header files built in the include subdirectory. +install-headers: install-include-dir $(INSTALL_HEADERS_DIR) $(INSTALL_ASSERT_H) +# Fix symlinks to absolute paths in the installed include directory to +# point to the installed directory, not the build directory. +# Don't need to use LN_S here since we really do need ln -s and no substitutes. + -files=`cd $(libsubdir)/include; find . -type l -print 2>/dev/null`; \ + if [ $$? -eq 0 ]; then \ + dir=`cd include; pwd`; \ + for i in $$files; do \ + dest=`ls -ld $(libsubdir)/include/$$i | sed -n 's/.*-> //p'`; \ + if expr "$$dest" : "$$dir.*" > /dev/null; then \ + rm -f $(libsubdir)/include/$$i; \ + ln -s `echo $$i | sed "s|/[^/]*|/..|g" | sed 's|/..$$||'``echo "$$dest" | sed "s|$$dir||"` $(libsubdir)/include/$$i; \ + fi; \ + done; \ + fi + +# Create or recreate the gcc private include file directory. +install-include-dir: installdirs + -rm -rf $(libsubdir)/include + mkdir $(libsubdir)/include + -chmod a+rx $(libsubdir)/include + +# Install the include directory using tar. +install-headers-tar: stmp-headers $(STMP_FIXPROTO) install-include-dir + (cd include; \ + tar -cf - .; exit 0) | (cd $(libsubdir)/include; tar $(TAROUTOPTS) - ) +# /bin/sh on some systems returns the status of the first tar, +# and that can lose with GNU tar which always writes a full block. +# So use `exit 0' to ignore its exit status. + +# Install the include directory using cpio. +install-headers-cpio: stmp-headers $(STMP_FIXPROTO) install-include-dir + (cd include; find . -print) | (cd include; cpio -pdum $(libsubdir)/include) + +# Put assert.h where it won't override GNU libc's assert.h. +# It goes in a dir that is searched after GNU libc's headers; +# thus, the following conditionals are no longer needed. +# But it's not worth deleting them now. +## Don't replace the assert.h already there if it is not from GCC. +## This code would be simpler if it tested for -f ... && ! grep ... +## but supposedly the ! operator is missing in sh on some systems. +install-assert-h: assert.h installdirs + if [ -f $(assertdir)/assert.h ]; \ + then \ + if grep "__eprintf" $(assertdir)/assert.h >/dev/null; \ + then \ + rm -f $(assertdir)/assert.h; \ + $(INSTALL_DATA) $(srcdir)/assert.h $(assertdir)/assert.h; \ + chmod a-x $(assertdir)/assert.h; \ + else true; \ + fi; \ + else \ + rm -f $(assertdir)/assert.h; \ + $(INSTALL_DATA) $(srcdir)/assert.h $(assertdir)/assert.h; \ + chmod a-x $(assertdir)/assert.h; \ + fi + +# Cancel installation by deleting the installed files. +uninstall: lang.uninstall + -rm -rf $(libsubdir) + -rm -rf $(bindir)/$(GCC_INSTALL_NAME)$(exeext) + -rm -rf $(bindir)/$(GCC_CROSS_NAME)$(exeext) + -rm -rf $(man1dir)/$(GCC_INSTALL_NAME)$(manext) + -rm -rf $(man1dir)/$(GCC_CROSS_NAME)$(manext) + -rm -rf $(man1dir)/cccp$(manext) +# CYGNUS LOCAL: We install cpp.1. + -rm -rf $(man1dir)/cpp$(manext) + -rm -f $(infodir)/cpp.info* $(infodir)/gcc.info* +# +# These targets are for the dejagnu testsuites. The file site.exp +# contains global variables that all the testsuites will use. + +# Set to $(target_alias)/ for cross. +target_subdir = @target_subdir@ + +site.exp: ./config.status Makefile + @echo "Making a new config file..." + -@rm -f ./tmp? + @touch site.exp + -@mv site.exp site.bak + @echo "## these variables are automatically generated by make ##" > ./tmp0 + @echo "# Do not edit here. If you wish to override these values" >> ./tmp0 + @echo "# add them to the last section" >> ./tmp0 + @echo "set rootme \"`pwd`\"" >> ./tmp0 + @echo "set srcdir \"`cd ${srcdir}; pwd`\"" >> ./tmp0 + @echo "set host_triplet $(host_canonical)" >> ./tmp0 + @echo "set build_triplet $(build_canonical)" >> ./tmp0 + @echo "set target_triplet $(target)" >> ./tmp0 + @echo "set target_alias $(target_alias)" >> ./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 \"-I$(objdir)/../$(target_subdir)libio -I\$$srcdir/../libg++/src -I\$$srcdir/../libio -I\$$srcdir/../libstdc++ -I\$$srcdir/../libstdc++/stl -L$(objdir)/../$(target_subdir)libg++ -L$(objdir)/../$(target_subdir)libstdc++\"" >> ./tmp0 +# If newlib has been configured, we need to pass -B to gcc so it can find +# newlib's crt0.o if it exists. This will cause a "path prefix not used" +# message if it doesn't, but the testsuite is supposed to ignore the message - +# it's too difficult to tell when to and when not to pass -B (not all targets +# have crt0's). We could only add the -B if ../newlib/crt0.o exists, but that +# seems like too selective a test. +# ??? Another way to solve this might be to rely on linker scripts. Then +# theoretically the -B won't be needed. +# We also need to pass -L ../ld so that the linker can find ldscripts. + @if [ -d $(objdir)/../$(target_subdir)newlib ] ; then \ + echo "set newlib_cflags \"-I$(objdir)/../$(target_subdir)newlib/targ-include -I\$$srcdir/../newlib/libc/include\"" >> ./tmp0; \ + echo "set newlib_ldflags \"-B$(objdir)/../$(target_subdir)newlib/\"" >> ./tmp0; \ + echo "append CFLAGS \" \$$newlib_cflags\"" >> ./tmp0; \ + echo "append CXXFLAGS \" \$$newlib_cflags\"" >> ./tmp0; \ + echo "append LDFLAGS \" \$$newlib_ldflags\"" >> ./tmp0; \ + else true; \ + fi + @if [ -d $(objdir)/../ld ] ; then \ + echo "append LDFLAGS \" -L$(objdir)/../ld\"" >> ./tmp0; \ + else true; \ + fi + echo "set tmpdir $(objdir)/testsuite" >> ./tmp0 + @echo "set srcdir \"\$${srcdir}/testsuite\"" >> ./tmp0 + @echo "## All variables above are generated by configure. Do Not Edit ##" >> ./tmp0 + @cat ./tmp0 > site.exp + @cat site.bak | sed \ + -e '1,/^## All variables above are.*##/ d' >> site.exp + -@rm -f ./tmp? + +CHECK_TARGETS = check-gcc check-g++ check-g77 check-objc +# CYGNUS LOCAL don't build/check g77 or objc +CHECK_TARGETS = check-gcc check-g++ +# END CYGNUS LOCAL + +check: $(CHECK_TARGETS) + +testsuite/site.exp: site.exp + if [ -d testsuite ]; then \ + true; \ + else \ + mkdir testsuite; \ + fi + rm -rf testsuite/site.exp + cp site.exp testsuite/site.exp + +check-g++: testsuite/site.exp + -rootme=`pwd`; export rootme; \ + srcdir=`cd ${srcdir}; pwd` ; export srcdir ; \ + cd testsuite; \ + EXPECT=${EXPECT} ; export EXPECT ; \ + if [ -f $${rootme}/../expect/expect ] ; then \ + TCL_LIBRARY=$${srcdir}/../tcl/library ; \ + export TCL_LIBRARY ; fi ; \ + $(RUNTEST) --tool g++ $(RUNTESTFLAGS) + +check-gcc: testsuite/site.exp + -rootme=`pwd`; export rootme; \ + srcdir=`cd ${srcdir}; pwd` ; export srcdir ; \ + cd testsuite; \ + EXPECT=${EXPECT} ; export EXPECT ; \ + if [ -f $${rootme}/../expect/expect ] ; then \ + TCL_LIBRARY=$${srcdir}/../tcl/library ; \ + export TCL_LIBRARY ; fi ; \ + $(RUNTEST) --tool gcc $(RUNTESTFLAGS) + +check-g77: testsuite/site.exp + -rootme=`pwd`; export rootme; \ + srcdir=`cd ${srcdir}; pwd` ; export srcdir ; \ + cd testsuite; \ + EXPECT=${EXPECT} ; export EXPECT ; \ + if [ -f $${rootme}/../expect/expect ] ; then \ + TCL_LIBRARY=$${srcdir}/../tcl/library ; \ + export TCL_LIBRARY ; fi ; \ + $(RUNTEST) --tool g77 $(RUNTESTFLAGS) + +check-objc: testsuite/site.exp + -rootme=`pwd`; export rootme; \ + srcdir=`cd ${srcdir}; pwd` ; export srcdir ; \ + cd testsuite; \ + EXPECT=${EXPECT} ; export EXPECT ; \ + if [ -f $${rootme}/../expect/expect ] ; then \ + TCL_LIBRARY=$${srcdir}/../tcl/library ; \ + export TCL_LIBRARY ; fi ; \ + $(RUNTEST) --tool objc $(RUNTESTFLAGS) + +# CYGNUS LOCAL consistency testing/vmakarov +check-consistency: testsuite/site.exp + -rootme=`pwd`; export rootme; \ + srcdir=`cd ${srcdir}; pwd` ; export srcdir ; \ + cd testsuite; \ + EXPECT=${EXPECT} ; export EXPECT ; \ + if [ -f $${rootme}/../expect/expect ] ; then \ + TCL_LIBRARY=$${srcdir}/../tcl/library ; \ + export TCL_LIBRARY ; fi ; \ + $(RUNTEST) --tool consistency $(RUNTESTFLAGS) +# END CYGNUS LOCAL consistency testing/vmakarov + +# These exist for maintenance purposes. + +# Update the tags table. +TAGS: force + cd $(srcdir); \ + mkdir tmp-tags; \ + mv -f c-parse.[ch] cexp.c =*.[chy] tmp-tags; \ + etags *.y *.h *.c; \ + mv tmp-tags/* .; \ + rmdir tmp-tags + +# Create the distribution tar.gz file. +dist: tmp-gcc.xtar + gzip --best < tmp-gcc.xtar > tmp-gcc.xtar.gz + mv tmp-gcc.xtar.gz gcc-$(version).tar.gz + +tmp-gcc.xtar: distdir +# Make the distribution. + tar -chf tmp-gcc.xtar gcc-$(version) + +distdir-cvs: force + if [ -d $(srcdir)/CVS ]; then cd $(srcdir) && cvs -r update; fi + +# This target exists to do the initial work before the language specific +# stuff gets done. +# CYGNUS LOCAL: built in build directory +distdir-start: doc $(srcdir)/INSTALL c-parse.y $(srcdir)/c-gperf.h \ + c-parse.c cexp.c $(srcdir)/config.in $(srcdir)/version.c TAGS + @if grep -s "for version ${mainversion}" gcc.texi > /dev/null; \ + then true; \ + else echo "You must update the version number in \`gcc.texi'"; sleep 10;\ + fi +# Update the version number in README + awk '$$1 " " $$2 " " $$3 == "This directory contains" \ + { $$6 = version; print $$0 } \ + $$1 " " $$2 " " $$3 != "This directory contains"' \ + version=$(version) $(srcdir)/README > tmp.README + mv tmp.README README + -rm -rf gcc-$(version) tmp +# Put all the files in a temporary subdirectory +# which has the name that we want to have in the tar file. + mkdir tmp + mkdir tmp/config + mkdir tmp/ginclude + mkdir tmp/objc + for file in `(cd $(srcdir) && echo *[0-9a-zA-Z+])`; do \ + test -f $(srcdir)/$$file && $(LN_S) $(srcdir)/$$file tmp; \ + done + if test "$(srcdir)" != "." ; then \ + for file in c-parse.c cexp.c ; do \ + test -f ./$$file && $(LN_S) ../$$file tmp; \ + done; \ + fi + for file in `(cd $(srcdir)/config && echo *[0-9a-zA-Z+])`; do \ + if test -d $(srcdir)/config/$$file \ + && test "$$file" != RCS && test "$$file" != CVS; then \ + mkdir tmp/config/$$file; \ + for subfile in `(cd $(srcdir)/config/$$file && echo *[0-9a-zA-Z+])`; do \ + $(LN_S) $(srcdir)/config/$$file/$$subfile tmp/config/$$file; \ + done; \ + else \ + $(LN_S) $(srcdir)/config/$$file tmp/config; \ + fi; \ + done + for file in `(cd $(srcdir)/ginclude && echo *[0-9a-zA-Z+])`; do \ + $(LN_S) $(srcdir)/ginclude/$$file tmp/ginclude; \ + done + for file in `(cd $(srcdir)/objc && echo *[0-9a-zA-Z+])`; do \ + $(LN_S) $(srcdir)/objc/$$file tmp/objc; \ + done + $(LN_S) .gdbinit tmp + +# Finish making `distdir', after the languages have done their thing. +distdir-finish: + mv tmp gcc-$(version) +# Get rid of everything we don't want in the distribution. We'd want +# this to use Makefile.in, but it doesn't have the `lang.foo' targets +# expanded. + cd gcc-$(version); make extraclean VERSION_DEP= + +distdir: distdir-cvs distdir-start lang.distdir distdir-finish + +# make diff oldversion=M.N +# creates a diff file between an older distribution and this one. +# The -P option assumes this is GNU diff. +diff: + diff -rc2P -x c-parse.y -x c-parse.c -x c-parse.h -x c-gperf.h \ + -x cexp.c -x -x TAGS -x INSTALL \ + -x configure -x config.in \ + -x "gcc.??" -x "gcc.??s" -x gcc.aux -x "gcc.info*" \ + -x "cpp.??" -x "cpp.??s" -x cpp.aux -x "cpp.info*" \ + $(LANG_DIFF_EXCLUDES) \ + gcc-$(oldversion) gcc-$(version) > gcc-$(oldversion)-$(version).diff + +bootstrap bootstrap-lean: force +# 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. + $(MAKE) CC="$(CC)" libdir=$(libdir) LANGUAGES="$(BOOT_LANGUAGES)" + $(MAKE) stage1 +# This used to define ALLOCA as empty, but that would lead to bad results +# for a subsequent `make install' since that would not have ALLOCA empty. +# To prevent `make install' from compiling alloca.o and then relinking cc1 +# because alloca.o is newer, we permit these recursive makes to compile +# alloca.o. Then cc1 is newer, so it won't have to be relinked. + $(MAKE) CC="stage1/xgcc$(exeext) -Bstage1/ -B$(build_tooldir)/bin/" CFLAGS="$(WARN_CFLAGS) $(BOOT_CFLAGS)" LDFLAGS="$(BOOT_LDFLAGS)" libdir=$(libdir) STAGE_PREFIX=stage1/ LANGUAGES="$(LANGUAGES)" + $(MAKE) stage2 + -if test $@ = bootstrap-lean; then rm -rf stage1; else true; fi + $(MAKE) CC="stage2/xgcc$(exeext) -Bstage2/ -B$(build_tooldir)/bin/" CFLAGS="$(WARN_CFLAGS) $(BOOT_CFLAGS)" LDFLAGS="$(BOOT_LDFLAGS)" libdir=$(libdir) STAGE_PREFIX=stage2/ LANGUAGES="$(LANGUAGES)" + +bootstrap2 bootstrap2-lean: force + $(MAKE) CC="stage1/xgcc$(exeext) -Bstage1/ -B$(build_tooldir)/bin/" CFLAGS="$(WARN_CFLAGS) $(BOOT_CFLAGS)" LDFLAGS="$(BOOT_LDFLAGS)" libdir=$(libdir) STAGE_PREFIX=stage1/ LANGUAGES="$(LANGUAGES)" + $(MAKE) stage2 + -if test $@ = bootstrap2-lean; then rm -rf stage1; else true; fi + $(MAKE) CC="stage2/xgcc$(exeext) -Bstage2/ -B$(build_tooldir)/bin/" CFLAGS="$(WARN_CFLAGS) $(BOOT_CFLAGS)" LDFLAGS="$(BOOT_LDFLAGS)" libdir=$(libdir) STAGE_PREFIX=stage2/ LANGUAGES="$(LANGUAGES)" + +bootstrap3 bootstrap3-lean: force + $(MAKE) CC="stage2/xgcc$(exeext) -Bstage2/ -B$(build_tooldir)/bin/" CFLAGS="$(WARN_CFLAGS) $(BOOT_CFLAGS)" LDFLAGS="$(BOOT_LDFLAGS)" libdir=$(libdir) STAGE_PREFIX=stage2/ LANGUAGES="$(LANGUAGES)" + +bootstrap4 bootstrap4-lean: force + $(MAKE) CC="stage3/xgcc$(exeext) -Bstage3/ -B$(build_tooldir)/bin/" CFLAGS="$(WARN_CFLAGS) $(BOOT_CFLAGS)" LDFLAGS="$(BOOT_LDFLAGS)" libdir=$(libdir) STAGE_PREFIX=stage3/ LANGUAGES="$(LANGUAGES)" + +# Compare the object files in the current directory with those in the +# stage2 directory. + +# ./ avoids bug in some versions of tail. +compare compare3 compare4 compare-lean compare3-lean compare4-lean: force + -rm -f .bad_compare + case "$@" in compare | compare-lean ) stage=2 ;; * ) stage=`echo $@ | sed -e 's,^compare\([0-9][0-9]*\).*,\1,'` ;; esac; \ + for file in *$(objext); do \ + 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; \ + done + case "$@" in compare | compare-lean ) stage=2 ;; * ) stage=`echo $@ | sed -e 's,^compare\([0-9][0-9]*\).*,\1,'` ;; esac; \ + for dir in tmp-foo $(SUBDIRS); do \ + if [ "`echo $$dir/*$(objext)`" != "$$dir/*$(objext)" ] ; then \ + for file in $$dir/*$(objext); do \ + 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; \ + done; \ + else true; fi; \ + done + -rm -f tmp-foo* + case "$@" in compare | compare-lean ) stage=2 ;; * ) stage=`echo $@ | sed -e 's,^compare\([0-9][0-9]*\).*,\1,'` ;; esac; \ + if [ -f .bad_compare ]; then \ + echo "Bootstrap comparison failure!"; \ + cat .bad_compare; \ + exit 1; \ + else \ + case "$@" in \ + *-lean ) rm -rf stage$$stage ;; \ + *) ;; \ + esac; true; \ + fi + +# Compare the object files in the current directory with those in the +# stage2 directory. Use gnu cmp (diffutils v2.4 or later) to avoid +# running tail and the overhead of twice copying each object file. + +gnucompare gnucompare3 gnucompare4 gnucompare-lean gnucompare3-lean gnucompare4-lean: force + -rm -f .bad_compare + case "$@" in gnucompare | gnucompare-lean ) stage=2 ;; * ) stage=`echo $@ | sed -e 's,^gnucompare\([0-9][0-9]*\).*,\1,'` ;; esac; \ + for file in *$(objext); do \ + (cmp --ignore-initial=16 $$file stage$$stage/$$file > /dev/null 2>&1 || echo $$file differs >> .bad_compare) || true; \ + done + case "$@" in gnucompare | gnucompare-lean ) stage=2 ;; * ) stage=`echo $@ | sed -e 's,^gnucompare\([0-9][0-9]*\).*,\1,'` ;; esac; \ + for dir in tmp-foo $(SUBDIRS); do \ + if [ "`echo $$dir/*$(objext)`" != "$$dir/*$(objext)" ] ; then \ + for file in $$dir/*$(objext); do \ + (cmp --ignore-initial=16 $$file stage$$stage/$$file > /dev/null 2>&1 || echo $$file differs >> .bad_compare) || true; \ + done; \ + else true; fi; \ + done + case "$@" in gnucompare | gnucompare-lean ) stage=2 ;; * ) stage=`echo $@ | sed -e 's,^gnucompare\([0-9][0-9]*\).*,\1,'` ;; esac; \ + if [ -f .bad_compare ]; then \ + echo "Bootstrap comparison failure!"; \ + cat .bad_compare; \ + exit 1; \ + else \ + case "$@" in \ + *-lean ) rm -rf stage$$stage ;; \ + esac; true; \ + fi + +# Copy the object files from a particular stage into a subdirectory. +stage1-start: + -if [ -d stage1 ] ; then true ; else mkdir stage1 ; fi + -for dir in . $(SUBDIRS) ; \ + do \ + if [ -d stage1/$$dir ] ; then true ; else mkdir stage1/$$dir ; fi ; \ + done + -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 $(LN_S) ../as$(exeext) stage1 ; else true ; fi + -if [ -f ld$(exeext) ] ; then $(LN_S) ../ld$(exeext) stage1 ; else true ; fi + -rm -f stage1/libgcc.a + -cp libgcc.a stage1 + -if $(RANLIB_TEST_FOR_TARGET) ; then \ + $(RANLIB_FOR_TARGET) stage1/libgcc.a; \ + else true; fi + -for f in .. $(EXTRA_MULTILIB_PARTS); do if [ x$${f} != x.. ]; then \ + cp stage1/$${f} . ; \ + else true; \ + fi; done +stage1: force stage1-start lang.stage1 + +stage2-start: + -if [ -d stage2 ] ; then true ; else mkdir stage2 ; fi + -for dir in . $(SUBDIRS) ; \ + do \ + if [ -d stage2/$$dir ] ; then true ; else mkdir stage2/$$dir ; fi ; \ + done + -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 $(LN_S) ../as$(exeext) stage2 ; else true ; fi + -if [ -f ld$(exeext) ] ; then $(LN_S) ../ld$(exeext) stage2 ; else true ; fi + -rm -f stage2/libgcc.a + -cp libgcc.a stage2 + -if $(RANLIB_TEST_FOR_TARGET) ; then \ + $(RANLIB_FOR_TARGET) stage2/libgcc.a; \ + else true; fi + -for f in .. $(EXTRA_MULTILIB_PARTS); do if [ x$${f} != x.. ]; then \ + cp stage2/$${f} . ; \ + else true; \ + fi; done +stage2: force stage2-start lang.stage2 + +stage3-start: + -if [ -d stage3 ] ; then true ; else mkdir stage3 ; fi + -for dir in . $(SUBDIRS) ; \ + do \ + if [ -d stage3/$$dir ] ; then true ; else mkdir stage3/$$dir ; fi ; \ + done + -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 $(LN_S) ../as$(exeext) stage3 ; else true ; fi + -if [ -f ld$(exeext) ] ; then $(LN_S) ../ld$(exeext) stage3 ; else true ; fi + -rm -f stage3/libgcc.a + -cp libgcc.a stage3 + -if $(RANLIB_TEST_FOR_TARGET) ; then \ + $(RANLIB_FOR_TARGET) stage3/libgcc.a; \ + else true; fi + -for f in .. $(EXTRA_MULTILIB_PARTS); do if [ x$${f} != x.. ]; then \ + cp stage3/$${f} . ; \ + else true; \ + fi; done +stage3: force stage3-start lang.stage3 + +stage4-start: + -if [ -d stage4 ] ; then true ; else mkdir stage4 ; fi + -for dir in . $(SUBDIRS) ; \ + do \ + if [ -d stage4/$$dir ] ; then true ; else mkdir stage4/$$dir ; fi ; \ + done + -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 $(LN_S) ../as$(exeext) stage4 ; else true ; fi + -if [ -f ld$(exeext) ] ; then $(LN_S) ../ld$(exeext) stage4 ; else true ; fi + -rm -f stage4/libgcc.a + -cp libgcc.a stage4 + -if $(RANLIB_TEST_FOR_TARGET) ; then \ + $(RANLIB_FOR_TARGET) stage4/libgcc.a; \ + else true; fi + -for f in .. $(EXTRA_MULTILIB_PARTS); do if [ x$${f} != x.. ]; then \ + cp stage4/$${f} . ; \ + else true; \ + fi; done +stage4: force stage4-start lang.stage4 + +# Copy just the executable files from a particular stage into a subdirectory, +# and delete the object files. Use this if you're just verifying a version +# that is pretty sure to work, and you are short of disk space. +risky-stage1: stage1 + -make clean + +risky-stage2: stage2 + -make clean + +risky-stage3: stage3 + -make clean + +risky-stage4: stage4 + -make clean + +#In GNU Make, ignore whether `stage*' exists. +.PHONY: stage1 stage2 stage3 stage4 clean maintainer-clean TAGS bootstrap +.PHONY: risky-stage1 risky-stage2 risky-stage3 risky-stage4 + +force: + +# --- +# The enquire rules are still useful for building new float-anything.h. +# Special flags for compiling enquire. +# We disable optimization to make floating point more reliable. +ENQUIRE_CFLAGS = -DNO_MEM -DNO_LONG_DOUBLE_IO -O0 +ENQUIRE_LDFLAGS = $(LDFLAGS) + +# Enquire target (This is a variable so that a target can choose not to +# build it.) +ENQUIRE = enquire + +# Test to see whether exists in the system header files, +# and is not derived from GCC. +FLOAT_H_TEST = \ + [ -f $(SYSTEM_HEADER_DIR)/float.h ] && \ + if grep 'ifndef _FLOAT_H___' $(SYSTEM_HEADER_DIR)/float.h >/dev/null; \ + then false; \ + else :; fi +# We pretend to not having a usable , hence disable the FLOAT_H_TEST +# to ensure, we're emitting a full blown ourselves. +FLOAT_H_TEST = false + +# Used to compile enquire with standard cc, but have forgotten why. +# Let's try with GCC. +enquire: enquire.o $(GCC_PARTS) + $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(ENQUIRE_LDFLAGS) enquire.o -o $@ +enquire.o: $(srcdir)/enquire.c $(GCC_PASSES) stmp-int-hdrs + if $(FLOAT_H_TEST); then \ + rm -f include/float.h; \ + SYS_FLOAT_H_WRAP=1; \ + else :; \ + SYS_FLOAT_H_WRAP=0; \ + fi; \ + $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(ALL_CPPFLAGS) $(ENQUIRE_CFLAGS) \ + -DSYS_FLOAT_H_WRAP=$$SYS_FLOAT_H_WRAP \ + -I. -c $(srcdir)/enquire.c + +# Create float.h source for the native machine. +# Make it empty if we can use the system float.h without changes. +float.h-nat: enquire + -./enquire -f > tmp-float.h + grep '#define [^_]' tmp-float.h >/dev/null || true > tmp-float.h + mv tmp-float.h float.h-nat + +# Create a dummy float.h source for a cross-compiler. +# ??? This isn't used anymore. Should we create config/float-unkn.h +# and make that the default float_format in configure? +float.h-cross: + echo "#ifndef __GCC_FLOAT_NOT_NEEDED" > t-float.h-cross + echo "#error float.h values not known for cross-compiler" >> t-float.h-cross + echo "#endif" >> t-float.h-cross + mv t-float.h-cross float.h-cross + diff --git a/gcc_arm/NEWS b/gcc_arm/NEWS new file mode 100755 index 0000000..af07d2d --- /dev/null +++ b/gcc_arm/NEWS @@ -0,0 +1,1078 @@ +Noteworthy Cygnus only changes for GCC. +If you do not set the GCC_EXEC_PREFIX environment variable, the compiler will +try to figure out an appropriate prefix to use from the pathname it was invoked +by. This means as long as your shell fills in the entire pathname when +starting gcc, you can move the entire installation tree (binaries, libraries, +etc.) to another directory, without having to rebuild the compiler. + +Noteworthy changes in GCC after EGCS 1.1. +----------------------------------------- + +Target specific NEWS + + RS6000/PowerPC: -mcpu=401 was added as an alias for -mcpu=403. -mcpu=e603e + was added to do -mcpu=603e and -msoft-float. + +Noteworthy changes in GCC for EGCS 1.1. +--------------------------------------- + +The compiler now implements global common subexpression elimination (gcse) as +well as global constant/copy propagation. (link to gcse page). + +More major improvements have been made to the alias analysis code. A new +option to allow front-ends to provide alias information to the optimizers +has also been added (-fstrict-aliasing). -fstrict-aliasing is off by default +now, but will be enabled by default in the future. (link to alias page) + +Major changes continue in the exception handling support. This release +includes some changes to reduce static overhead for exception handling. It +also includes some major changes to the setjmp/longjmp based EH mechanism to +make it less pessimistic. And finally, major infrastructure improvements +to the dwarf2 EH mechanism have been made to make our EH support extensible. + +We have fixed the infamous security problems with temporary files. + +The "regmove" optimization pass has been nearly completely rewritten. It now +uses much more information about the target to determine profitability of +transformations. + +The compiler now recomputes register usage information immediately before +register allocation. Previously such information was only not kept up to +date after instruction combination which led to poor register allocation +choices by our priority based register allocator. + +The register reloading phase of the compiler has been improved to better +optimize spill code. This primarily helps targets which generate lots of +spills (like the x86 ports and many register poor embedded ports). + +A few changes in the heuristics used by the register allocator and scheduler +have been made which can significantly improve performance for certain +applications. + +The compiler's branch shortening algorithms have been significantly improved +to work better on targets which align jump targets. + +The compiler now supports the "ADDRESSOF" optimization which can significantly +reduce the overhead for certain inline calls (and inline calls in general). + +The compiler now supports a code size optimization switch (-Os). When enabled +the compiler will prefer optimizations which improve code size over those +which improve code speed. + +The compiler has been improved to completely eliminate library calls which +compute constant values. This is particularly useful on machines which +do not have integer mul/div or floating point support on-chip. + +GCC now supports a "--help" option to print detailed help information. + +cpplib has been greatly improved. It is probably useable for some sites now +(major missing feature is trigraphs). + +Memory footprint for the compiler has been significantly reduced for certain +pathalogical cases. + +Build time improvements for targets which support lots of sched parameters +(alpha and mips primarily). + +Compile time for certain programs using large constant initializers has been +improved (effects glibc significantly). + +Plus an incredible number of infrastructure changes, warning fixes, bugfixes +and local optimizations. + +Various improvements have been made to better support cross compilations. They +are still not easy, but they are improving. + +Target specific NEWS + + Sparc: Now includes V8 plus and V9 support, lots of tuning for Ultrasparcs + and uses the Haifa scheduler by default. + + Alpha: EV6 tuned, optimized expansion of memcpy/bzero. + + x86: Data in the static store is aligned per Intel recommendations. Jump + targets are aligned per Intel recommendations. Improved epilogue + sequences for Pentium chips. Backend improvements which should help + register allocation on all x86 variants. Support for PPro conditional + move instructions has been fixed and enabled. Random changes + throughout the port to make generated code more Pentium friendly. + Improved support for 64bit integer operations. + Unixware 7, a System V Release 5 target is now supported. + SCO OpenServer targets can support GAS. See gcc/INSTALL for details. + + RS6000/PowerPC: Includes AIX4.3 support as well as PowerPC64 support. + Haifa instruction scheduling is enabled by default now. + + MIPS: Multiply/Multiply-Add support has been largely rewritten to generate + more efficient code. Includes mips16 support. + + M68K: Various micro-optimizations and Coldfire fixes. + + M32r: Major improvements to this port. + + Arm: Includes Thumb and super interworking support. + +EGCS includes all gcc2 changes up to and including the June 9, 1998 snapshot. + + +Noteworthy changes in GCC version 2.8.1 +--------------------------------------- + +Numerous bugs have been fixed and some minor performance +improvements (compilation speed) have been made. + +Noteworthy changes in GCC version 2.8.0 +--------------------------------------- + +A major change in this release is the addition of a framework for +exception handling, currently used by C++. Many internal changes and +optimization improvements have been made. These increase the +maintainability and portability of GCC. GCC now uses autoconf to +compute many host parameters. + +The following lists changes that add new features or targets. + +See cp/NEWS for new features of C++ in this release. + +New tools and features: + + The Dwarf 2 debugging information format is supported on ELF systems, and + is the default for -ggdb where available. It can also be used for C++. + The Dwarf version 1 debugging format is also permitted for C++, but + does not work well. + + gcov.c is provided for test coverage analysis and branch profiling + analysis is also supported; see -fprofile-arcs, -ftest-coverage, + and -fbranch-probabilities. + + Support for the Checker memory checking tool. + + New switch, -fstack-check, to check for stack overflow on systems that + don't have such built into their ABI. + + New switches, -Wundef and -Wno-undef to warn if an undefined identifier + is evaluated in an #if directive. + + Options -Wall and -Wimplicit now cause GCC to warn about implicit int + in declarations (e.g. `register i;'), since the C Standard committee + has decided to disallow this in the next revision of the standard; + -Wimplicit-function-declarations and -Wimplicit-int are subsets of + this. + + Option -Wsign-compare causes GCC to warn about comparison of signed and + unsigned values. + + Add -dI option of cccp for cxref. + +New features in configuration, installation and specs file handling: + + New option --enable-c-cpplib to configure script. + + You can use --with-cpu on the configure command to specify the default + CPU that GCC should generate code for. + + The -specs=file switch allows you to override default specs used in + invoking programs like cc1, as, etc. + + Allow including one specs file from another and renaming a specs + variable. + + You can now relocate all GCC files with a single environment variable + or a registry entry under Windows 95 and Windows NT. + +Changes in Objective-C: + + The Objective-C Runtime Library has been made thread-safe. + + The Objective-C Runtime Library contains an interface for creating + mutexes, condition mutexes, and threads; it requires a back-end + implementation for the specific platform and/or thread package. + Currently supported are DEC/OSF1, IRIX, Mach, OS/2, POSIX, PCThreads, + Solaris, and Windows32. The --enable-threads parameter can be used + when configuring GCC to enable and select a thread back-end. + + Objective-C is now configured as separate front-end language to GCC, + making it more convenient to conditionally build it. + + The internal structures of the Objective-C Runtime Library have + changed sufficiently to warrant a new version number; now version 8. + Programs compiled with an older version must be recompiled. + + The Objective-C Runtime Library can be built as a DLL on Windows 95 + and Windows NT systems. + + The Objective-C Runtime Library implements +load. + +The following new targets are supported (see also list under each +individual CPU below): + + Embedded target m32r-elf. + Embedded Hitachi Super-H using ELF. + RTEMS real-time system on various CPU targets. + ARC processor. + NEC V850 processor. + Matsushita MN10200 processor. + Matsushita MN10300 processor. + Sparc and PowerPC running on VxWorks. + Support both glibc versions 1 and 2 on Linux-based GNU systems. + +New features for DEC Alpha systems: + + Allow detailed specification of IEEE fp support: + -mieee, -mieee-with-inexact, and -mieee-conformant + -mfp-trap-mode=xxx, -mfp-round-mode=xxx, -mtrap-precision=xxx + -mcpu=xxx for CPU selection + Support scheduling parameters for EV5. + Add support for BWX, CIX, and MAX instruction set extensions. + Support Linux-based GNU systems. + Support VMS. + +Additional supported processors and systems for MIPS targets: + + MIPS4 instruction set. + R4100, R4300 and R5000 processors. + N32 and N64 ABI. + IRIX 6.2. + SNI SINIX. + +New features for Intel x86 family: + + Add scheduling parameters for Pentium and Pentium Pro. + Support stabs on Solaris-x86. + Intel x86 processors running the SCO OpenServer 5 family. + Intel x86 processors running DG/UX. + Intel x86 using Cygwin32 or Mingw32 on Windows 95 and Windows NT. + +New features for Motorola 68k family: + + Support for 68060 processor. + More consistent switches to specify processor. + Motorola 68k family running AUX. + 68040 running pSOS, ELF object files, DBX debugging. + Coldfire variant of Motorola m68k family. + +New features for the HP PA RISC: + + -mspace and -mno-space + -mlong-load-store and -mno-long-load-store + -mbig-switch -mno-big-switch + + GCC on the PA requires either gas-2.7 or the HP assembler; for best + results using GAS is highly recommended. GAS is required for -g and + exception handling support. + +New features for SPARC-based systems: + + The ultrasparc cpu. + The sparclet cpu, supporting only a.out file format. + Sparc running SunOS 4 with the GNU assembler. + Sparc running the Linux-based GNU system. + Embedded Sparc processors running the ELF object file format. + -mcpu=xxx + -mtune=xxx + -malign-loops=xxx + -malign-jumps=xxx + -malign-functions=xxx + -mimpure-text and -mno-impure-text + + Options -mno-v8 and -mno-sparclite are no longer supported on SPARC + targets. Options -mcypress, -mv8, -msupersparc, -msparclite, -mf930, + and -mf934 are deprecated and will be deleted in GCC 2.9. Use + -mcpu=xxx instead. + +New features for rs6000 and PowerPC systems: + + Solaris 2.51 running on PowerPC's. + The Linux-based GNU system running on PowerPC's. + -mcpu=604e,602,603e,620,801,823,mpc505,821,860,power2 + -mtune=xxx + -mrelocatable-lib, -mno-relocatable-lib + -msim, -mmve, -memb + -mupdate, -mno-update + -mfused-madd, -mno-fused-madd + + -mregnames + -meabi + -mcall-linux, -mcall-solaris, -mcall-sysv-eabi, -mcall-sysv-noeabi + -msdata, -msdata=none, -msdata=default, -msdata=sysv, -msdata=eabi + -memb, -msim, -mmvme + -myellowknife, -mads + wchar_t is now of type long as per the ABI, not unsigned short. + -p/-pg support + -mcpu=403 now implies -mstrict-align. + Implement System V profiling. + + Aix 4.1 GCC targets now default to -mcpu=common so that programs + compiled can be moved between rs6000 and powerpc based systems. A + consequence of this is that -static won't work, and that some programs + may be slightly slower. + + You can select the default value to use for -mcpu=xxx on rs6000 and + powerpc targets by using the --with-cpu=xxx option when configuring the + compiler. In addition, a new options, -mtune=xxx was added that + selects the machine to schedule for but does not select the + architecture level. + + Directory names used for storing the multilib libraries on System V + and embedded PowerPC systems have been shortened to work with commands + like tar that have fixed limits on pathname size. + +New features for the Hitachi H8/300(H): + + -malign-300 + -ms (for the Hitachi H8/S processor) + -mint32 + +New features for the ARM: + + -march=xxx, -mtune=xxx, -mcpu=xxx + Support interworking with Thumb code. + ARM processor with a.out object format, COFF, or AOF assembler. + ARM on "semi-hosted" platform. + ARM running NetBSD. + ARM running the Linux-based GNU system. + +New feature for Solaris systems: + + GCC installation no longer makes a copy of system include files, + thus insulating GCC better from updates to the operating system. + + +Noteworthy changes in GCC version 2.7.2 +--------------------------------------- + +A few bugs have been fixed (most notably the generation of an +invalid assembler opcode on some RS/6000 systems). + +Noteworthy changes in GCC version 2.7.1 +--------------------------------------- + +This release fixes numerous bugs (mostly minor) in GCC 2.7.0, but +also contains a few new features, mostly related to specific targets. + +Major changes have been made in code to support Windows NT. + +The following new targets are supported: + + 2.9 BSD on PDP-11 + Linux on m68k + HP/UX version 10 on HP PA RISC (treated like version 9) + DEC Alpha running Windows NT + +When parsing C, GCC now recognizes C++ style `//' comments unless you +specify `-ansi' or `-traditional'. + +The PowerPC System V targets (powerpc-*-sysv, powerpc-*-eabi) now use the +calling sequence specified in the System V Application Binary Interface +Processor Supplement (PowerPC Processor ABI Supplement) rather than the calling +sequence used in GCC version 2.7.0. That calling sequence was based on the AIX +calling sequence without function descriptors. To compile code for that older +calling sequence, either configure the compiler for powerpc-*-eabiaix or use +the -mcall-aix switch when compiling and linking. + +Noteworthy changes in GCC version 2.7.0 +--------------------------------------- + +GCC now works better on systems that use ".obj" and ".exe" instead of +".o" and no extension. This involved changes to the driver program, +gcc.c, to convert ".o" names to ".obj" and to GCC's Makefile to use +".obj" and ".exe" in filenames that are not targets. In order to +build GCC on such systems, you may need versions of GNU make and/or +compatible shells. At this point, this support is preliminary. + +Object file extensions of ".obj" and executable file extensions of +".exe" are allowed when using appropriate version of GNU Make. + +Numerous enhancements were made to the __attribute__ facility including +more attributes and more places that support it. We now support the +"packed", "nocommon", "noreturn", "volatile", "const", "unused", +"transparent_union", "constructor", "destructor", "mode", "section", +"align", "format", "weak", and "alias" attributes. Each of these +names may also be specified with added underscores, e.g., "__packed__". +__attribute__ may now be applied to parameter definitions, function +definitions, and structure, enum, and union definitions. + +GCC now supports returning more structures in registers, as specified by +many calling sequences (ABIs), such as on the HP PA RISC. + +A new option '-fpack-struct' was added to automatically pack all structure +members together without holes. + +There is a new library (cpplib) and program (cppmain) that at some +point will replace cpp (aka cccp). To use cppmain as cpp now, pass +the option CCCP=cppmain to make. The library is already used by the +fix-header program, which should speed up the fixproto script. + +New options for supported targets: + + GNU on many targets. + NetBSD on MIPS, m68k, VAX, and x86. + LynxOS on x86, m68k, Sparc, and RS/6000. + VxWorks on many targets. + + Windows/NT on x86 architecture. Initial support for Windows/NT on Alpha + (not fully working). + + Many embedded targets, specifically UDI on a29k, aout, coff, elf, + and vsta "operating systems" on m68k, m88k, mips, sparc, and x86. + +Additional support for x86 (i386, i486, and Pentium): + + Work with old and new linkers for Linux-based GNU systems, + supporting both a.out and ELF. + FreeBSD on x86. + Stdcall convention. + -malign-double, -mregparm=, -malign-loops= and -malign-jumps= switches. + On ISC systems, support -Xp like -posix. + +Additions for RS/6000: + + Instruction scheduling information for PowerPC 403. + AIX 4.1 on PowerPC. + -mstring and -mno-string. + -msoft-float and floating-point emulation included. + Preliminary support for PowerPC System V.4 with or without the GNU as. + Preliminary support for EABI. + Preliminary support for 64-bit systems. + Both big and little endian systems. + +New features for MIPS-based systems: + + r4650. + mips4 and R8000. + Irix 6.0. + 64-bit ABI. + Allow dollar signs in labels on SGI/Irix 5.x. + +New support for HP PA RISC: + + Generation of PIC (requires binutils-2.5.2.u6 or later). + HP-UX version 9 on HP PA RISC (dynamically links even with -g). + Processor variants for HP PA RISC: 700, 7100, and 7100LC. + Automatic generation of long calls when needed. + -mfast-indirect-calls for kernels and static binaries. + + The called routine now copies arguments passed by invisible reference, + as required by the calling standard. + +Other new miscellaneous target-specific support: + + -mno-multm on a29k. + -mold-align for i960. + Configuration for "semi-hosted" ARM. + -momit-leaf-frame-pointer for M88k. + SH3 variant of Hitachi Super-H and support both big and little endian. + +Changes to Objective-C: + + Bare-bones implementation of NXConstantString has been added, + which is invoked by the @"string" directive. + + Class * has been changed to Class to conform to the NextSTEP and + OpenStep runtime. + + Enhancements to make dynamic loading easier. + + The module version number has been updated to Version 7, thus existing + code will need to be recompiled to use the current run-time library. + +GCC now supports the ISO Normative Addendum 1 to the C Standard. +As a result: + + The header defines macros for C programs written + in national variants of ISO 646. + + The following digraph tokens are supported: + <: :> <% %> %: %:%: + These behave like the following, respectively: + [ ] { } # ## + + Digraph tokens are supported unless you specify the `-traditional' + option; you do not need to specify `-ansi' or `-trigraphs'. Except + for contrived and unlikely examples involving preprocessor + stringizing, digraph interpretation doesn't change the meaning of + programs; this is unlike trigraph interpretation, which changes the + meanings of relatively common strings. + + The macro __STDC_VERSION__ has the value 199409L. + + As usual, for full conformance to the standard, you also need a + C library that conforms. + +The following lists changes that have been made to g++. If some +features mentioned below sound unfamiliar, you will probably want to +look at the recently-released public review copy of the C++ Working +Paper. For PostScript and PDF (Adobe Acrobat) versions, see the +archive at ftp://research.att.com/dist/stdc++/WP. For HTML and ASCII +versions, see ftp://ftp.cygnus.com/pub/g++. On the web, see +http://www.cygnus.com/~mrs/wp-draft. + +The scope of variables declared in the for-init-statement has been changed +to conform to http://www.cygnus.com/~mrs/wp-draft/stmt.html#stmt.for; as a +result, packages such as groff 1.09 will not compile unless you specify the +-fno-for-scope flag. PLEASE DO NOT REPORT THIS AS A BUG; this is a change +mandated by the C++ standardization committee. + +Binary incompatibilities: + + The builtin 'bool' type is now the size of a machine word on RISC targets, + for code efficiency; it remains one byte long on CISC targets. + + Code that does not use #pragma interface/implementation will most + likely shrink dramatically, as g++ now only emits the vtable for a + class in the translation unit where its first non-inline, non-abstract + virtual function is defined. + + Classes that do not define the copy constructor will sometimes be + passed and returned in registers. This may illuminate latent bugs in + your code. + +Support for automatic template instantiation has *NOT* been added, due +to a disagreement over design philosophies. + +Support for exception handling has been improved; more targets are now +supported, and throws will use the RTTI mechanism to match against the +catch parameter type. Optimization is NOT SUPPORTED with +-fhandle-exceptions; no need to report this as a bug. + +Support for Run-Time Type Identification has been added with -frtti. +This support is still in alpha; one major restriction is that any file +compiled with -frtti must include . + +Preliminary support for namespaces has been added. This support is far +from complete, and probably not useful. + +Synthesis of compiler-generated constructors, destructors and +assignment operators is now deferred until the functions are used. + +The parsing of expressions such as `a ? b : c = 1' has changed from +`(a ? b : c) = 1' to `a : b ? (c = 1)'. + +The code generated for testing conditions, especially those using || +and &&, is now more efficient. + +The operator keywords and, and_eq, bitand, bitor, compl, not, not_eq, +or, or_eq, xor and xor_eq are now supported. Use -ansi or +-foperator-names to enable them. + +The 'explicit' keyword is now supported. 'explicit' is used to mark +constructors and type conversion operators that should not be used +implicitly. + +g++ now accepts the typename keyword, though it currently has no +semantics; it can be a no-op in the current template implementation. +You may want to start using it in your code, however, since the +pending rewrite of the template implementation to compile STL properly +(perhaps for 2.8.0, perhaps not) will require you to use it as +indicated by the current draft. + +Handling of user-defined type conversion has been overhauled so that +type conversion operators are now found and used properly in +expressions and function calls. + +-fno-strict-prototype now only applies to function declarations with +"C" linkage. + +g++ now warns about 'if (x=0)' with -Wparentheses or -Wall. + +#pragma weak and #pragma pack are supported on System V R4 targets, as +are various other target-specific #pragmas supported by gcc. + +new and delete of const types is now allowed (with no additional +semantics). + +Explicit instantiation of template methods is now supported. Also, +'inline template class foo;' can be used to emit only the vtable +for a template class. + +With -fcheck-new, g++ will check the return value of all calls to +operator new, and not attempt to modify a returned null pointer. + +The template instantiation code now handles more conversions when +passing to a parameter that does not depend on template arguments. +This means that code like 'string s; cout << s;' now works. + +Invalid jumps in a switch statement past declarations that require +initializations are now caught. + +Functions declared 'extern inline' now have the same linkage semantics +as inline member functions. On supported targets, where previously +these functions (and vtables, and template instantiations) would have +been defined statically, they will now be defined as weak symbols so +that only one out-of-line definition is used. + +collect2 now demangles linker output, and c++filt has become part of +the gcc distribution. + +Noteworthy changes in GCC version 2.6.3: + +A few more bugs have been fixed. + +Noteworthy changes in GCC version 2.6.2: + +A few bugs have been fixed. + +Names of attributes can now be preceded and followed by double underscores. + +Noteworthy changes in GCC version 2.6.1: + +Numerous (mostly minor) bugs have been fixed. + +The following new configurations are supported: + + GNU on x86 (instead of treating it like MACH) + NetBSD on Sparc and Motorola 68k + AIX 4.1 on RS/6000 and PowerPC systems + Sequent DYNIX/ptx 1.x and 2.x. + Both COFF and ELF configurations on AViiON without using /bin/gcc + Windows/NT on x86 architecture; preliminary + AT&T DSP1610 digital signal processor chips + i960 systems on bare boards using COFF + PDP11; target only and not extensively tested + +The -pg option is now supported for Alpha under OSF/1 V3.0 or later. + +Files with an extension of ".c++" are treated as C++ code. + +The -Xlinker and -Wl arguments are now passed to the linker in the +position they were specified on the command line. This makes it +possible, for example, to pass flags to the linker about specific +object files. + +The use of positional arguments to the configure script is no longer +recommended. Use --target= to specify the target; see the GCC manual. + +The 386 now supports two new switches: -mreg-alloc= changes +the default register allocation order used by the compiler, and +-mno-wide-multiply disables the use of the mul/imul instructions that +produce 64 bit results in EAX:EDX from 32 bit operands to do long long +multiplies and 32-bit division by constants. + +Noteworthy changes in GCC version 2.6.0: + +Numerous bugs have been fixed, in the C and C++ front-ends, as +well as in the common compiler code. + +This release includes the C, Objective-C, and C++ compilers. However, +we have moved the files for the C++ compiler (G++) files to a +subdirectory, cp. Subsequent releases of GCC will split these files +to a separate TAR file. + +The G++ team has been tracking the development of the ANSI standard for C++. +Here are some new features added from the latest working paper: + + * built-in boolean type 'bool', with constants 'true' and 'false'. + * array new and delete (operator new [] and delete []). + * WP-conforming lifetime of temporaries. + * explicit instantiation of templates (template class A;), + along with an option (-fno-implicit-templates) to disable emission + of implicitly instantiated templates, obsoletes -fexternal-templates. + * static member constants (static const int foo = 4; within the + class declaration). + +Many error messages have been improved to tell the user more about the +problem. Conformance checking with -pedantic-errors has been +improved. G++ now compiles Fresco. + +There is now an experimental implementation of virtual functions using +thunks instead of Cfront-style vtables, enabled with -fvtable-thunks. +This option also enables a heuristic which causes the compiler to only +emit the vtable in the translation unit where its first non-inline +virtual function is defined; using this option and +-fno-implicit-templates, users should be able to avoid #pragma +interface/implementation altogether. + +Signatures have been added as a GNU C++ extension. Using the option +-fhandle-signatures, users are able to turn on recognition of +signatures. A short introduction on signatures is in the section +`Extension to the C++ Language' in the manual. + +The `g++' program is now a C program, rather than a shell script. + +Lots and lots and lots of bugs fixes, in nested types, access control, +pointers to member functions, the parser, templates, overload +resolution, etc, etc. + +There have been two major enhancements to the Objective-C compiler: + +1) Added portability. It now runs on Alpha, and some problems with + message forwarding have been addressed on other platforms. + +2) Selectors have been redefined to be pointers to structs like: + { void *sel_id, char *sel_types }, where the sel_id is the unique + identifier, the selector itself is no longer unique. + + Programmers should use the new function sel_eq to test selector + equivalence. + +The following major changes have been made to the base compiler and +machine-specific files. + +- The MIL-STD-1750A is a new port, but still preliminary. + +- The h8/300h is now supported; both the h8/300 and h8/300h ports come + with 32 bit IEEE 754 software floating point support. + +- The 64-bit Sparc (v9) and 64-bit MIPS chips are supported. + +- NetBSD is supported on m68k, Intel x86, and pc523 systems and FreeBSD + on x86. + +- COFF is supported on x86, m68k, and Sparc systems running LynxOS. + +- 68K systems from Bull and Concurrent are supported and System V + Release 4 is supported on the Atari. + +- GCC supports GAS on the Motorola 3300 (sysV68) and debugging + (assuming GAS) on the Plexus 68K system. (However, GAS does not yet + work on those systems). + +- System V Release 4 is supported on MIPS (Tandem). + +- For DG/UX, an ELF configuration is now supported, and both the ELF + and BCS configurations support ELF and COFF object file formats. + +- OSF/1 V2.0 is supported on Alpha. + +- Function profiling is also supported on Alpha. + +- GAS and GDB is supported for Irix 5 (MIPS). + +- "common mode" (code that will run on both POWER and PowerPC + architectures) is now supported for the RS/6000 family; the + compiler knows about more PPC chips. + +- Both NeXTStep 2.1 and 3 are supported on 68k-based architectures. + +- On the AMD 29k, the -msoft-float is now supported, as well as + -mno-sum-in-toc for RS/6000, -mapp-regs and -mflat for Sparc, and + -membedded-pic for MIPS. + +- GCC can now convert division by integer constants into the equivalent + multiplication and shift operations when that is faster than the + division. + +- Two new warning options, -Wbad-function-cast and + -Wmissing-declarations have been added. + +- Configurations may now add machine-specific __attribute__ options on + type; many machines support the `section' attribute. + +- The -ffast-math flag permits some optimization that violate strict + IEEE rules, such as converting X * 0.0 to 0.0. + +Noteworthy changes in GCC version 2.5.8: + +This release only fixes a few serious bugs. These include fixes for a +bug that prevented most programs from working on the RS/6000, a bug +that caused invalid assembler code for programs with a `switch' +statement on the NS32K, a G++ problem that caused undefined names in +some configurations, and several less serious problems, some of which +can affect most configuration. + +Noteworthy change in GCC version 2.5.7: + +This release only fixes a few bugs, one of which was causing bootstrap +compare errors on some systems. + +Noteworthy change in GCC version 2.5.6: + +A few backend bugs have been fixed, some of which only occur on one +machine. + +The C++ compiler in 2.5.6 includes: + + * fixes for some common crashes + * correct handling of nested types that are referenced as `foo::bar' + * spurious warnings about friends being declared static and never + defined should no longer appear + * enums that are local to a method in a class, or a class that's + local to a function, are now handled correctly. For example: + class foo { void bar () { enum { x, y } E; x; } }; + void bar () { class foo { enum { x, y } E; E baz; }; } + +Noteworthy change in GCC version 2.5.5: + +A large number of C++ bugs have been fixed. + +The fixproto script adds prototypes conditionally on __cplusplus. + +Noteworthy change in GCC version 2.5.4: + +A bug fix in passing of structure arguments for the HP-PA architecture +makes code compiled with GCC 2.5.4 incompatible with code compiled +with earlier versions (if it passes struct arguments of 33 to 64 bits, +interspersed with other types of arguments). + +Noteworthy change in gcc version 2.5.3: + +The method of "mangling" C++ function names has been changed. So you +must recompile all C++ programs completely when you start using GCC +2.5. Also, GCC 2.5 requires libg++ version 2.5. Earlier libg++ +versions won't work with GCC 2.5. (This is generally true--GCC +version M.N requires libg++ version M.N.) + +Noteworthy GCC changes in version 2.5: + +* There is now support for the IBM 370 architecture as a target. +Currently the only operating system supported is MVS; GCC does not run +on MVS, so you must produce .s files using GCC as a cross compiler, +then transfer them to MVS to assemble them. This port is not reliable +yet. + +* The Power PC is now supported. + +* The i860-based Paragon machine is now supported. + +* The Hitachi 3050 (an HP-PA machine) is now supported. + +* The variable __GNUC_MINOR__ holds the minor version number of GCC, as +an integer. For version 2.5.X, the value is 5. + +* In C, initializers for static and global variables are now processed +an element at a time, so that they don't need a lot of storage. + +* The C syntax for specifying which structure field comes next in an +initializer is now `.FIELDNAME='. The corresponding syntax for +array initializers is now `[INDEX]='. For example, + + char whitespace[256] + = { [' '] = 1, ['\t'] = 1, ['\n'] = 1 }; + +This was changed to accord with the syntax proposed by the Numerical +C Extensions Group (NCEG). + +* Complex numbers are now supported in C. Use the keyword __complex__ +to declare complex data types. See the manual for details. + +* GCC now supports `long double' meaningfully on the Sparc (128-bit +floating point) and on the 386 (96-bit floating point). The Sparc +support is enabled on Solaris 2.x because earlier system versions +(SunOS 4) have bugs in the emulation. + +* All targets now have assertions for cpu, machine and system. So you +can now use assertions to distinguish among all supported targets. + +* Nested functions in C may now be inline. Just declare them inline +in the usual way. + +* Packed structure members are now supported fully; it should be possible +to access them on any supported target, no matter how little alignment +they have. + +* To declare that a function does not return, you must now write +something like this (works only in 2.5): + + void fatal () __attribute__ ((noreturn)); + +or like this (works in older versions too): + + typedef void voidfn (); + + volatile voidfn fatal; + +It used to be possible to do so by writing this: + + volatile void fatal (); + +but it turns out that ANSI C requires that to mean something +else (which is useless). + +Likewise, to declare that a function is side-effect-free +so that calls may be deleted or combined, write +something like this (works only in 2.5): + + int computation () __attribute__ ((const)); + +or like this (works in older versions too): + + typedef int intfn (); + + const intfn computation; + +* The new option -iwithprefixbefore specifies a directory to add to +the search path for include files in the same position where -I would +put it, but uses the specified prefix just like -iwithprefix. + +* Basic block profiling has been enhanced to record the function the +basic block comes from, and if the module was compiled for debugging, +the line number and filename. A default version of the basic block +support module has been added to libgcc2 that appends the basic block +information to a text file 'bb.out'. Machine descriptions can now +override the basic block support module in the target macro file. + +New features in g++: + +* The new flag `-fansi-overloading' for C++. Use a newly implemented +scheme of argument matching for C++. It makes g++ more accurately +obey the rules set down in Chapter 13 of the Annotated C++ Reference +Manual (the ARM). This option will be turned on by default in a +future release. + +* The -finline-debug flag is now gone (it was never really used by the + compiler). + +* Recognizing the syntax for pointers to members, e.g., "foo::*bar", has been + dramatically improved. You should not get any syntax errors or incorrect + runtime results while using pointers to members correctly; if you do, it's + a definite bug. + +* Forward declaration of an enum is now flagged as an error. + +* Class-local typedefs are now working properly. + +* Nested class support has been significantly improved. The compiler + will now (in theory) support up to 240 nested classes before hitting + other system limits (like memory size). + +* There is a new C version of the `g++' driver, to replace the old + shell script. This should significantly improve the performance of + executing g++ on a system where a user's PATH environment variable + references many NFS-mounted filesystems. This driver also works + under MS-DOS and OS/2. + +* The ANSI committee working on the C++ standard has adopted a new + keyword `mutable'. This will allow you to make a specific member be + modifiable in an otherwise const class. + +Noteworthy GCC changes in version 2.4.4: + + A crash building g++ on various hosts (including m68k) has been + fixed. Also the g++ compiler no longer reports incorrect + ambiguities in some situations where they do not exist, and + const template member functions are now being found properly. + +Noteworthy GCC changes in version 2.4: + +* On each target, the default is now to return short structures +compatibly with the "usual" compiler on that target. + +For most targets, this means the default is to return all structures +in memory, like long structures, in whatever way is used on that +target. Use -freg-struct-return to enable returning short structures +(and unions) in registers. + +This change means that newly compiled binaries are incompatible with +binaries compiled with previous versions of GCC. + +On some targets, GCC is itself the usual compiler. On these targets, +the default way to return short structures is still in registers. +Use -fpcc-struct-return to tell GCC to return them in memory. + +* There is now a floating point emulator which can imitate the way all +supported target machines do floating point arithmetic. + +This makes it possible to have cross compilation to and from the VAX, +and between machines of different endianness. However, this works +only when the target machine description is updated to use the new +facilities, and not all have been updated. + +This also makes possible support for longer floating point types. +GCC 2.4 supports extended format on the 68K if you use `long double', +for targets that have a 68881. (When we have run time library +routines for extended floating point, then `long double' will use +extended format on all 68K targets.) + +We expect to support extended floating point on the i386 and Sparc in +future versions. + +* Building GCC now automatically fixes the system's header files. +This should require no attention. + +* GCC now installs an unsigned data type as size_t when it fixes the +header files (on all but a handful of old target machines). +Therefore, the bug that size_t failed to be unsigned is fixed. + +* Building and installation are now completely separate. +All new files are constructed during the build process; +installation just copies them. + +* New targets supported: Clipper, Hitachi SH, Hitachi 8300, and Sparc +Lite. + +* A totally new and much better Objective C run time system is included. + +* Objective C supports many new features. Alas, I can't describe them +since I don't use that language; however, they are the same ones +supported in recent versions of the NeXT operating system. + +* The builtin functions __builtin_apply_args, __builtin_apply and +__builtin_return let you record the arguments and returned +value of a function without knowing their number or type. + +* The builtin string variables __FUNCTION__ and __PRETTY_FUNCTION__ +give the name of the function in the source, and a pretty-printed +version of the name. The two are the same in C, but differ in C++. + +* Casts to union types do not yield lvalues. + +* ## before an empty rest argument discards the preceding sequence +of non-whitespace characters from the macro definition. +(This feature is subject to change.) + + +New features specific to C++: + +* The manual contains a new section ``Common Misunderstandings with +GNU C++'' that C++ users should read. + +* #pragma interface and #pragma implementation let you use the same +C++ source file for both interface and implementation. +However, this mechanism is still in transition. + +* Named returned values let you avoid an extra constructor call +when a function result has a class type. + +* The C++ operators ? yield min and max, respectively. + +* C++ gotos can exit a block safely even if the block has +aggregates that require destructors. + +* gcc defines the macro __GNUG__ when compiling C++ programs. + +* GNU C++ now correctly distinguishes between the prefix and postfix +forms of overloaded operator ++ and --. To avoid breaking old +code, if a class defines only the prefix form, the compiler +accepts either ++obj or obj++, unless -pedantic is used. + +* If you are using version 2.3 of libg++, you need to rebuild it with +`make CC=gcc' to avoid mismatches in the definition of `size_t'. + +Newly documented compiler options: + +-fnostartfiles + Omit the standard system startup files when linking. + +-fvolatile-global + Consider memory references to extern and global data items to + be volatile. + +-idirafter DIR + Add DIR to the second include path. + +-iprefix PREFIX + Specify PREFIX for later -iwithprefix options. + +-iwithprefix DIR + Add PREFIX/DIR to the second include path. + +-mv8 + Emit Sparc v8 code (with integer multiply and divide). +-msparclite + Emit Sparclite code (roughly v7.5). + +-print-libgcc-file-name + Search for the libgcc.a file, print its absolute file name, and exit. + +-Woverloaded-virtual + Warn when a derived class function declaration may be an error + in defining a C++ virtual function. + +-Wtemplate-debugging + When using templates in a C++ program, warn if debugging is + not yet fully available. + ++eN + Control how C++ virtual function definitions are used + (like cfront 1.x). + diff --git a/gcc_arm/PROBLEMS b/gcc_arm/PROBLEMS new file mode 100755 index 0000000..bc532e6 --- /dev/null +++ b/gcc_arm/PROBLEMS @@ -0,0 +1,117 @@ +3. When find_reloads is used to count number of spills needed +it does not take into account the fact that a reload may +turn out to be a dummy. + +I'm not sure this really happens any more. Doesn't it find +all the dummies on both passes? + +10. movl a3@,a0 + movl a3@(16),a1 + clrb a0@(a1:l) +is generated and may be worse than + movl a3@,a0 + addl a3@(16),a0 + clrb a0@ +If ordering of operands is improved, many more +such cases will be generated from typical array accesses. + +38. Hack expand_mult so that if there is no same-modes multiply +it will use a widening multiply and then truncate rather than +calling the library. + +39. Hack expanding of division to notice cases for +long -> short division. + +40. Represent divide insns as (DIV:SI ...) followed by +a separate lowpart extract. Represent remainder insns as DIV:SI +followed by a separate highpart extract. Then cse can work on +the DIV:SI part. Problem is, this may not be desirable on machines +where computing the quotient alone does not necessarily give +a remainder--such as the 68020 for long operands. + +52. Reloading can look at how reload_contents got set up. +If it was copied from a register, just reload from that register. +Otherwise, perhaps can change the previous insn to move the +data via the reload reg, thus avoiding one memory ref. + +63. Potential problem in cc_status.value2, if it ever activates itself +after a two-address subtraction (which currently cannot happen). +It is supposed to compare the current value of the destination +but eliminating it would use the results of the subtraction, equivalent +to comparing the previous value of the destination. + +65. Should loops that neither start nor end with a break +be rearranged to end with the last break? + +69. Define the floating point converting arithmetic instructions +for the 68881. + +74. Combine loop opt with cse opt in one pass. Do cse on each loop, +then loop opt on that loop, and go from innermost loops outward. +Make loop invariants available for cse at end of loop. + +85. pea can force a value to be reloaded into an areg +which can make it worse than separate adding and pushing. +This can only happen for adding something within addql range +and it only loses if the qty becomes dead at that point +so it can be added to with no copying. + +93. If a pseudo doesn't get a hard reg everywhere, +can it get one during a loop? + +96. Can do SImode bitfield insns without reloading, but must +alter the operands in special ways. + +99. final could check loop-entry branches to see if they +screw up deletion of a test instruction. If they do, +can put another test instruction before the branch and +make it conditional and redirect it. + +106. Aliasing may be impossible if data types of refs differ +and data type of containing objects also differ. +(But check this wrt unions.) + +108. Can speed up flow analysis by making a table saying which +register is set and which registers are used by each instruction that +only sets one register and only uses two. This way avoid the tree +walk for such instructions (most instructions). + +109. It is desirable to avoid converting INDEX to SImode if a +narrower mode suffices, as HImode does on the 68000. +How can this be done? + +110. Possible special combination pattern: +If the two operands to a comparison die there and both come from insns +that are identical except for replacing one operand with the other, +throw away those insns. Ok if insns being discarded are known 1 to 1. +An andl #1 after a seq is 1 to 1, but how should compiler know that? + +112. Can convert float to unsigned int by subtracting a constant, +converting to signed int, and changing the sign bit. + +117. Any number of slow zero-extensions in one loop, that have +their clr insns moved out of the loop, can share one register +if their original life spans are disjoint. +But it may be hard to be sure of this since +the life span data that regscan produces may be hard to interpret +validly or may be incorrect after cse. + +118. In cse, when a bfext insn refers to a register, if the field +corresponds to a halfword or a byte and the register is equivalent +to a memory location, it would be possible to detect this and +replace it with a simple memory reference. + +121. Insns that store two values cannot be moved out of loops. +The code in scan_loop doesn't even try to deal with them. + +122. When insn-output.c turns a bit-test into a sign-test, +it should see whether the cc is already set up with that sign. + +123. When a conditional expression is used as a function arg, it would +be faster (and in some cases shorter) to push each alternative rather +than compute in a register and push that. This would require +being able to specify "push this" as a target for expand_expr. + +124. On the 386, bad code results from foo (bar ()) when bar +returns a double, because the pseudo used fails to get preferenced +into an fp reg because of the distinction between regs 8 and 9. diff --git a/gcc_arm/PROJECTS b/gcc_arm/PROJECTS new file mode 100755 index 0000000..6ff7a05 --- /dev/null +++ b/gcc_arm/PROJECTS @@ -0,0 +1,435 @@ +Haifa scheduler (haifa-sched.c, loop.[ch], unroll.[ch], genattrtab.c): +(contact law@cygnus.com before starting any serious haifa work) + + * Fix all the formatting problems. Simple, mindless work. + + * Fix/add comments throughout the code. Many of the comments are from + the old scheduler and are out of date and misleading. Many new hunks + of code don't have sufficient comments and documentation. Those which + do have comments need to be rewritten to use complete sentences and + proper formatting. + + * Someone needs make one (or more) passes over the scheduler as a whole to + just clean it up. Try to move the machine dependent bits into the target + files where they belong, avoid re-creating functions where or near + equivalents already exist (ie is_conditional_branch and friends), etc., etc. + + * Document the new scheduling options. Remove those options which are + not really useful (like reverse scheduling for example). In general + the haifa scheduler adds _way_ too many options. I'm definitely of the + opinion that gcc already has too many -foptions, and haifa doesn't help + that situation. + + * Testing and benchmarking. We've converted a few ports to using the + Haifa scheduler (hppa, sparc, ppc, alpha). We need to continue testing + and benchmarking the new scheduler on additional targets. + + We need to have some kind of docs for how to best describe a machine to + the haifa scheduler to get good performance. Some existing ports have + been tuned to deal with the old scheduler -- they may need to be tuned + to generate good schedules with haifa. + + + +Improvements to global cse and partial redundancy elimination: + +The current implementation of global cse uses partial redundancy elimination +as described in Chow's thesis. + +Long term we want to use lazy code motion as the basis for partial redundancy +elimination. lcm will find as many (or more) redunancies *and* it will +place the remaining computations at computationally optimal placement points +within the function. This reduces the number of redundant operations performed +as well as reducing register lifetimes. My experiments have shown that the +cases were the current PRE code hurts performance are greatly helped by using +lazy code motion. + +lcm also provides the underlying framework for several additional optimizations +such as shrink wrapping, spill code motion, dead store elimination, and generic +load/store motion (all the other examples are subcases of load/store motion). + +It can probably also be used to improve the reg-stack pass of the compiler. + +Contact law@cygnus.com if you're interested in working on lazy code motion. + +------------- + +The old PROJECTS file. Stuff I know has been done has been deleted. +Stuff in progress has a contact name associated with it. +has been + +1. Better optimization. + +* Constants in unused inline functions + +It would be nice to delay output of string constants so that string +constants mentioned in unused inline functions are never generated. +Perhaps this would also take care of string constants in dead code. + +The difficulty is in finding a clean way for the RTL which refers +to the constant (currently, only by an assembler symbol name) +to point to the constant and cause it to be output. + +* Optimize a sequence of if statements whose conditions are exclusive. + +It is possible to optimize + + if (x == 1) ...; + if (x == 2) ...; + if (x == 3) ...; + +into + + if (x == 1) ...; + else if (x == 2) ...; + else if (x == 3) ...; + +provided that x is not altered by the contents of the if statements. + +It's not certain whether this is worth doing. Perhaps programmers +nearly always write the else's themselves, leaving few opportunities +to improve anything. + +* Un-cse. + +Perhaps we should have an un-cse step right after cse, which tries to +replace a reg with its value if the value can be substituted for the +reg everywhere, if that looks like an improvement. Which is if the +reg is used only a few times. Use rtx_cost to determine if the +change is really an improvement. + +* Clean up how cse works. + +The scheme is that each value has just one hash entry. The +first_same_value and next_same_value chains are no longer needed. + +For arithmetic, each hash table elt has the following slots: + +* Operation. This is an rtx code. +* Mode. +* Operands 0, 1 and 2. These point to other hash table elements. + +So, if we want to enter (PLUS:SI (REG:SI 30) (CONST_INT 104)), we +first enter (CONST_INT 104) and find the entry that (REG:SI 30) now +points to. Then we put these elts into operands 0 and 1 of a new elt. +We put PLUS and SI into the new elt. + +Registers and mem refs would never be entered into the table as such. +However, the values they contain would be entered. There would be a +table indexed by regno which points at the hash entry for the value in +that reg. + +The hash entry index now plays the role of a qty number. +We still need qty_first_reg, reg_next_eqv, etc. to record which regs +share a particular qty. + +When a reg is used whose contents are unknown, we need to create a +hash table entry whose contents say "unknown", as a place holder for +whatever the reg contains. If that reg is added to something, then +the hash entry for the sum will refer to the "unknown" entry. Use +UNKNOWN for the rtx code in this entry. This replaces make_new_qty. + +For a constant, a unique hash entry would be made based on the +value of the constant. + +What about MEM? Each time a memory address is referenced, we need a +qty (a hash table elt) to represent what is in it. (Just as for a +register.) If this isn't known, create one, just as for a reg whose +contents are unknown. + +We need a way to find all mem refs that still contain a certain value. +Do this with a chain of hash elts (for memory addresses) that point to +locations that hold the value. The hash elt for the value itself should +point to the start of the chain. It would be good for the hash elt +for an address to point to the hash elt for the contents of that address +(but this ptr can be null if the contents have never been entered). + +With this data structure, nothing need ever be invalidated except +the lists of which regs or mems hold a particular value. It is easy +to see if there is a reg or mem that is equiv to a particular value. +If the value is constant, it is always explicitly constant. + +* Support more general tail-recursion among different functions. + +This might be possible under certain circumstances, such as when +the argument lists of the functions have the same lengths. +Perhaps it could be done with a special declaration. + +You would need to verify in the calling function that it does not +use the addresses of any local variables and does not use setjmp. + +* Put short statics vars at low addresses and use short addressing mode? + +Useful on the 68000/68020 and perhaps on the 32000 series, +provided one has a linker that works with the feature. +This is said to make a 15% speedup on the 68000. + +* Keep global variables in registers. + +Here is a scheme for doing this. A global variable, or a local variable +whose address is taken, can be kept in a register for an entire function +if it does not use non-constant memory addresses and (for globals only) +does not call other functions. If the entire function does not meet +this criterion, a loop may. + +The VAR_DECL for such a variable would have to have two RTL expressions: +the true home in memory, and the pseudo-register used temporarily. +It is necessary to emit insns to copy the memory location into the +pseudo-register at the beginning of the function or loop, and perhaps +back out at the end. These insns should have REG_EQUIV notes so that, +if the pseudo-register does not get a hard register, it is spilled into +the memory location which exists in any case. + +The easiest way to set up these insns is to modify the routine +put_var_into_stack so that it does not apply to the entire function +(sparing any loops which contain nothing dangerous) and to call it at +the end of the function regardless of where in the function the +address of a local variable is taken. It would be called +unconditionally at the end of the function for all relevant global +variables. + +For debugger output, the thing to do is to invent a new binding level +around the appropriate loop and define the variable name as a register +variable with that scope. + +* Live-range splitting. + +Currently a variable is allocated a hard register either for the full +extent of its use or not at all. Sometimes it would be good to +allocate a variable a hard register for just part of a function; for +example, through a particular loop where the variable is mostly used, +or outside of a particular loop where the variable is not used. (The +latter is nice because it might let the variable be in a register most +of the time even though the loop needs all the registers.) + +Contact meissner@cygnus.com before starting any work on live range +splitting. + +* Detect dead stores into memory? + +A store into memory is dead if it is followed by another store into +the same location; and, in between, there is no reference to anything +that might be that location (including no reference to a variable +address). + +This can be modeled as a partial redundancy elimination/lazy code motion +problem. Contact law@cygnus.com before working on dead store elimination +optimizations. + +* Loop optimization. + +Strength reduction and iteration variable elimination could be +smarter. They should know how to decide which iteration variables are +not worth making explicit because they can be computed as part of an +address calculation. Based on this information, they should decide +when it is desirable to eliminate one iteration variable and create +another in its place. + +It should be possible to compute what the value of an iteration +variable will be at the end of the loop, and eliminate the variable +within the loop by computing that value at the loop end. + +When a loop has a simple increment that adds 1, +instead of jumping in after the increment, +decrement the loop count and jump to the increment. +This allows aob insns to be used. + +* Using constraints on values. + +Many operations could be simplified based on knowledge of the +minimum and maximum possible values of a register at any particular time. +These limits could come from the data types in the tree, via rtl generation, +or they can be deduced from operations that are performed. For example, +the result of an `and' operation one of whose operands is 7 must be in +the range 0 to 7. Compare instructions also tell something about the +possible values of the operand, in the code beyond the test. + +Value constraints can be used to determine the results of a further +comparison. They can also indicate that certain `and' operations are +redundant. Constraints might permit a decrement and branch +instruction that checks zeroness to be used when the user has +specified to exit if negative. + +* Change the type of a variable. + +Sometimes a variable is declared as `int', it is assigned only once +from a value of type `char', and then it is used only by comparison +against constants. On many machines, better code would result if +the variable had type `char'. If the compiler could detect this +case, it could change the declaration of the variable and change +all the places that use it. + +* Better handling for very sparse switches. + +There may be cases where it would be better to compile a switch +statement to use a fixed hash table rather than the current +combination of jump tables and binary search. + +* Order of subexpressions. + +It might be possible to make better code by paying attention +to the order in which to generate code for subexpressions of an expression. + +* More code motion. + +Consider hoisting common code up past conditional branches or tablejumps. + +Contact law@cygnus.com before working on code hoisting. + +* Trace scheduling. + +This technique is said to be able to figure out which way a jump +will usually go, and rearrange the code to make that path the +faster one. + +* Distributive law. + +The C expression *(X + 4 * (Y + C)) compiles better on certain +machines if rewritten as *(X + 4*C + 4*Y) because of known addressing +modes. It may be tricky to determine when, and for which machines, to +use each alternative. + +Some work has been done on this, in combine.c. + +* Can optimize by changing if (x) y; else z; into z; if (x) y; +if z and x do not interfere and z has no effects not undone by y. +This is desirable if z is faster than jumping. + +* For a two-insn loop on the 68020, such as + foo: movb a2@+,a3@+ + jne foo +it is better to insert dbeq d0,foo before the jne. +d0 can be a junk register. The challenge is to fit this into +a portable framework: when can you detect this situation and +still be able to allocate a junk register? + +2. Simpler porting. + +Right now, describing the target machine's instructions is done +cleanly, but describing its addressing mode is done with several +ad-hoc macro definitions. Porting would be much easier if there were +an RTL description for addressing modes like that for instructions. +Tools analogous to genflags and genrecog would generate macros from +this description. + +There would be one pattern in the address-description file for each +kind of addressing, and this pattern would have: + + * the RTL expression for the address + * C code to verify its validity (since that may depend on + the exact data). + * C code to print the address in assembler language. + * C code to convert the address into a valid one, if it is not valid. + (This would replace LEGITIMIZE_ADDRESS). + * Register constraints for all indeterminates that appear + in the RTL expression. + +3. Other languages. + +Front ends for Pascal, Fortran, Algol, Cobol, Modula-2 and Ada are +desirable. + +Pascal, Modula-2 and Ada require the implementation of functions +within functions. Some of the mechanisms for this already exist. + +4. More extensions. + +* Generated unique labels. Have some way of generating distinct labels +for use in extended asm statements. I don't know what a good syntax would +be. + +* A way of defining a structure containing a union, in which the choice of +union alternative is controlled by a previous structure component. + +Here is a possible syntax for this. + +struct foo { + enum { INT, DOUBLE } code; + auto union { case INT: int i; case DOUBLE: double d;} value : code; +}; + +* Allow constructor expressions as lvalues, like this: + + (struct foo) {a, b, c} = foo(); + +This would call foo, which returns a structure, and then store the +several components of the structure into the variables a, b, and c. + +5. Generalize the machine model. + +* Some new compiler features may be needed to do a good job on machines +where static data needs to be addressed using base registers. + +* Some machines have two stacks in different areas of memory, one used +for scalars and another for large objects. The compiler does not +now have a way to understand this. + +6. Useful warnings. + +* Warn about statements that are undefined because the order of +evaluation of increment operators makes a big difference. Here is an +example: + + *foo++ = hack (*foo); + +7. Better documentation of how GCC works and how to port it. + +Here is an outline proposed by Allan Adler. + +I. Overview of this document +II. The machines on which GCC is implemented + A. Prose description of those characteristics of target machines and + their operating systems which are pertinent to the implementation + of GCC. + i. target machine characteristics + ii. comparison of this system of machine characteristics with + other systems of machine specification currently in use + B. Tables of the characteristics of the target machines on which + GCC is implemented. + C. A priori restrictions on the values of characteristics of target + machines, with special reference to those parts of the source code + which entail those restrictions + i. restrictions on individual characteristics + ii. restrictions involving relations between various characteristics + D. The use of GCC as a cross-compiler + i. cross-compilation to existing machines + ii. cross-compilation to non-existent machines + E. Assumptions which are made regarding the target machine + i. assumptions regarding the architecture of the target machine + ii. assumptions regarding the operating system of the target machine + iii. assumptions regarding software resident on the target machine + iv. where in the source code these assumptions are in effect made +III. A systematic approach to writing the files tm.h and xm.h + A. Macros which require special care or skill + B. Examples, with special reference to the underlying reasoning +IV. A systematic approach to writing the machine description file md + A. Minimal viable sets of insn descriptions + B. Examples, with special reference to the underlying reasoning +V. Uses of the file aux-output.c +VI. Specification of what constitutes correct performance of an + implementation of GCC + A. The components of GCC + B. The itinerary of a C program through GCC + C. A system of benchmark programs + D. What your RTL and assembler should look like with these benchmarks + E. Fine tuning for speed and size of compiled code +VII. A systematic procedure for debugging an implementation of GCC + A. Use of GDB + i. the macros in the file .gdbinit for GCC + ii. obstacles to the use of GDB + a. functions implemented as macros can't be called in GDB + B. Debugging without GDB + i. How to turn off the normal operation of GCC and access specific + parts of GCC + C. Debugging tools + D. Debugging the parser + i. how machine macros and insn definitions affect the parser + E. Debugging the recognizer + i. how machine macros and insn definitions affect the recognizer + +ditto for other components + +VIII. Data types used by GCC, with special reference to restrictions not + specified in the formal definition of the data type +IX. References to the literature for the algorithms used in GCC + diff --git a/gcc_arm/README b/gcc_arm/README new file mode 100755 index 0000000..fe0ac0b --- /dev/null +++ b/gcc_arm/README @@ -0,0 +1,26 @@ +This directory contains the egcs version 1.1 release of the GNU C +compiler. It includes all of the support for compiling C++ and +Objective C, including a run-time library for Objective C. + +The GNU C compiler is free software. See the file COPYING for copying +permission. + +See the file gcc.texi (together with other files that it includes) for +installation and porting information. The file INSTALL contains a +copy of the installation information, as plain ASCII. + +Installing this package will create various files in subdirectories of +/usr/local/lib, which are passes used by the compiler and a library +named libgcc.a. It will also create /usr/local/bin/gcc, which is +the user-level command to do a compilation. + +See the Bugs chapter of the GCC Manual for how to report bugs +usefully. An online readable version of the manual is in the files +gcc.info*. + +The files pself.c and pself1.c are not part of GCC. +They are programs that print themselves on standard output. +They were written by Dario Dariol and Giovanni Cozzi, and are +included for your hacking pleasure. Likewise pself2.c +(Who is the author of that?) and pself3.c (by Vlad Taeerov and Rashit +Fakhreyev). diff --git a/gcc_arm/README-bugs b/gcc_arm/README-bugs new file mode 100755 index 0000000..06e15bb --- /dev/null +++ b/gcc_arm/README-bugs @@ -0,0 +1,144 @@ +The purpose of GCC pretesting is to verify that the new GCC +distribution, about to be released, works properly on your system *with +no change whatever*, when installed following the precise +recommendations that come with the distribution. + +Here are some guidelines on how to do pretesting so as to make it +helpful. All of them follow from common sense together with the +nature of the purpose and the situation. + +* It is absolutely vital that you mention even the smallest change or +departure from the standard sources and installation procedure. + +Otherwise, you are not testing the same program that I wrote. Testing +a different program is usually of no use whatever. It can even cause +trouble if you fail to tell me that you tested some other program +instead of what I know as GCC. I might think that GCC works, when in +fact it has not been properly tried, and might have a glaring fault. + +* Even changing the compilation options counts as a change in the +program. The GCC sources specify which compilation options to use. +Some of them are specified in makefiles, and some in machine-specific +configuration files. + +You have ways to override this--but if you do, then you are not +testing what ordinary users will do. Therefore, when pretesting, it +is vital to test with the default compilation options. + +(It is okay to test with nonstandard options as well as testing with +the standard ones.) + +* The machine and system configuration files of GCC are parts of +GCC. So when you test GCC, you need to do it with the +configuration files that come with GCC. + +If GCC does not come with configuration files for a certain machine, +and you test it with configuration files that don't come with GCC, +this is effectively changing GCC. Because the crucial fact about +the planned release is that, without changes, it doesn't work on that +machine. + +To make GCC work on that machine, I would need to install new +configuration files. That is not out of the question, since it is +safe--it certainly won't break any other machines that already work. +But you will have to rush me the legal papers to give the FSF +permission to use a large piece of text. + +* Look for recommendations for your system. + +You can find these recommendations in the Installation node of the +manual, and in the file INSTALL. (These two files have the same text.) + +These files say which configuration name to use for your machine, so +use the ones that are recommended. If you guess, you might guess +wrong and encounter spurious difficulties. What's more, if you don't +follow the recommendations then you aren't helping to test that its +recommendations are valid. + +These files may describe other things that you need to do to make GCC +work on your machine. If so, you should follow these recommendations +also, for the same reason. + +Also look at the Trouble chapter of the manual for items that +pertain to your machine. + +* Don't delay sending information. + +When you find a problem, please double check it if you can do so +quickly. But don't spend a long time double-checking. A good rule is +always to tell me about every problem on the same day you encounter +it, even if that means you can't find a solution before you report the +problem. + +I'd much rather hear about a problem today and a solution tomorrow +than get both of them tomorrow at the same time. + +* Make each bug report self-contained. + +If you refer back to another message, whether from you or from someone +else, then it will be necessary for anyone who wants to investigate +the bug to find the other message. This may be difficult, it is +probably time-consuming. + +To help me save time, simply copy the relevant parts of any previous +messages into your own bug report. + +In particular, if I ask you for more information because a bug report +was incomplete, it is best to send me the *entire* collection of +relevant information, all together. If you send just the additional +information, that makes me do extra work. There is even a risk that +I won't remember what question you are sending me the answer to. + +* Always be precise when talking about changes you have made. Show +things rather than describing them. Use exact filenames (relative to +the main directory of the distribution), not partial ones. For +example, say "I changed Makefile" rather than "I changed the +makefile". Instead of saying "I defined the MUMBLE macro", send a +diff that shows your change. + +* Always use `diff -c' to make diffs. If you don't include context, +it may be hard for me to figure out where you propose to make the +changes. I might have to ignore your patch because I can't tell what +it means. + +* When you write a fix, keep in mind that I can't install a change +that would break other systems. + +People often suggest fixing a problem by changing machine-independent +files such as toplev.c to do something special that a particular +system needs. Sometimes it is totally obvious that such changes would +break GCC for almost all users. I can't possibly make a change like +that. All I can do is send it back to you and ask you to find a fix +that is safe to install. + +Sometimes people send fixes that *might* be an improvement in +general--but it is hard to be sure of this. I can install such +changes some of the time, but not during pretest, when I am trying to +get a new version to work reliably as quickly as possible. + +The safest changes for me to install are changes to the configuration +files for a particular machine. At least I know those can't create +bugs on other machines. + +* Don't try changing GCC unless it fails to work if you don't change it. + +* Don't even suggest changes that would only make GCC cleaner. +Every change I install could introduce a bug, so I won't install +a change unless I see it is necessary. + +* If you would like to suggest changes for purposes other than fixing +serious bugs, don't wait till pretest time. Instead, send them just +after I make a release. That's the best time for me to install them. + +* In some cases, if you don't follow these guidelines, your +information might still be useful, but I might have to do more work to +make use of it. Unfortunately, I am so far behind in my work that I +just can't get the job done unless you help me to do it efficiently. + + + Thank you + rms + +Local Variables: +mode: text +End: diff --git a/gcc_arm/README-fixinc b/gcc_arm/README-fixinc new file mode 100755 index 0000000..4b303dd --- /dev/null +++ b/gcc_arm/README-fixinc @@ -0,0 +1,9 @@ +This README file is copied into the directory for GCC-only header files +when fixincludes is run by the makefile for GCC. + +Many of the files in this directory were made from the standard system +header files of this system by the shell script `fixincludes'. +They are system-specific, and will not work on any other kind of system. +They are also not part of GCC. The reason for making the files here +is to fix the places in the header files which use constructs +that are incompatible with ANSI C. diff --git a/gcc_arm/TESTS.FLUNK b/gcc_arm/TESTS.FLUNK new file mode 100755 index 0000000..04641e3 --- /dev/null +++ b/gcc_arm/TESTS.FLUNK @@ -0,0 +1,39 @@ +This is a collection of things that test suites have +said were "wrong" with GCC--but that I don't agree with. + +First, test suites sometimes test for compatibility with +traditional C. GCC with -traditional is not completely +compatible with traditional C, and in some ways I think it +should not be. + +* K&R C allowed \x to appear in a string literal (or character +literal?) even in cases where it is *not* followed by a sequence of +hex digits. I'm not convinced this is desirable. + +* K&R compilers allow comments to cross over an inclusion boundary (i.e. +started in an include file and ended in the including file). +I think this would be quite ugly and can't imagine it could +be needed. + +Sometimes tests disagree with GCC's interpretation of the ANSI standard. + +* One test claims that this function should return 1. + + enum {A, B} foo; + + func (enum {B, A} arg) + { + return B; + } + +I think it should return 0, because the definition of B that +applies is the one in func. + +* Some tests report failure when the compiler does not produce +an error message for a certain program. + +ANSI C requires a "diagnostic" message for certain kinds of invalid +programs, but a warning counts as a diagnostic. If GCC produces +a warning but not an error, that is correct ANSI support. +When test suites call this "failure", the tests are broken. + diff --git a/gcc_arm/acconfig.h b/gcc_arm/acconfig.h new file mode 100755 index 0000000..0487570 --- /dev/null +++ b/gcc_arm/acconfig.h @@ -0,0 +1,96 @@ +/* Define if you can safely include both and . */ +#undef STRING_WITH_STRINGS + +/* Define if printf supports "%p". */ +#undef HAVE_PRINTF_PTR + +/* Define if you want expensive run-time checks. */ +#undef ENABLE_CHECKING + +/* Define if your cpp understands the stringify operator. */ +#undef HAVE_CPP_STRINGIFY + +/* Define if your compiler understands volatile. */ +#undef HAVE_VOLATILE + +/* Define if your assembler supports specifying the maximum number + of bytes to skip when using the GAS .p2align command. */ +#undef HAVE_GAS_MAX_SKIP_P2ALIGN + +/* Define if your assembler supports .balign and .p2align. */ +#undef HAVE_GAS_BALIGN_AND_P2ALIGN + +/* Define if your assembler supports .subsection and .subsection -1 starts + emitting at the beginning of your section */ +#undef HAVE_GAS_SUBSECTION_ORDERING + +/* Define if you have a working header file. */ +#undef HAVE_INTTYPES_H + +/* Whether malloc must be declared even if is included. */ +#undef NEED_DECLARATION_MALLOC + +/* Whether realloc must be declared even if is included. */ +#undef NEED_DECLARATION_REALLOC + +/* Whether calloc must be declared even if is included. */ +#undef NEED_DECLARATION_CALLOC + +/* Whether free must be declared even if is included. */ +#undef NEED_DECLARATION_FREE + +/* Whether bcopy must be declared even if is included. */ +#undef NEED_DECLARATION_BCOPY + +/* Whether bcmp must be declared even if is included. */ +#undef NEED_DECLARATION_BCMP + +/* Whether bzero must be declared even if is included. */ +#undef NEED_DECLARATION_BZERO + +/* Whether index must be declared even if is included. */ +#undef NEED_DECLARATION_INDEX + +/* Whether rindex must be declared even if is included. */ +#undef NEED_DECLARATION_RINDEX + +/* Whether getenv must be declared even if is included. */ +#undef NEED_DECLARATION_GETENV + +/* Whether atol must be declared even if is included. */ +#undef NEED_DECLARATION_ATOL + +/* Whether sbrk must be declared even if is included. */ +#undef NEED_DECLARATION_SBRK + +/* Whether abort must be declared even if is included. */ +#undef NEED_DECLARATION_ABORT + +/* Whether strerror must be declared even if is included. */ +#undef NEED_DECLARATION_STRERROR + +/* Whether strsignal must be declared even if is included. */ +#undef NEED_DECLARATION_STRSIGNAL + +/* Whether getcwd must be declared even if is included. */ +#undef NEED_DECLARATION_GETCWD + +/* Whether getwd must be declared even if is included. */ +#undef NEED_DECLARATION_GETWD + +/* Whether getrlimit must be declared even if is included. */ +#undef NEED_DECLARATION_GETRLIMIT + +/* Whether setrlimit must be declared even if is included. */ +#undef NEED_DECLARATION_SETRLIMIT + +/* Define if you want expensive run-time checks. */ +#undef ENABLE_CHECKING + +/* Define to enable the use of a default assembler. */ +#undef DEFAULT_ASSEMBLER + +/* Define to enable the use of a default linker. */ +#undef DEFAULT_LINKER + +@TOP@ diff --git a/gcc_arm/aclocal.m4 b/gcc_arm/aclocal.m4 new file mode 100755 index 0000000..ce44ba1 --- /dev/null +++ b/gcc_arm/aclocal.m4 @@ -0,0 +1,237 @@ +dnl See whether we can include both string.h and strings.h. +AC_DEFUN(GCC_HEADER_STRING, +[AC_CACHE_CHECK([whether string.h and strings.h may both be included], + gcc_cv_header_string, +[AC_TRY_COMPILE([#include +#include ], , gcc_cv_header_string=yes, gcc_cv_header_string=no)]) +if test $gcc_cv_header_string = yes; then + AC_DEFINE(STRING_WITH_STRINGS) +fi +]) + +dnl See whether we need a declaration for a function. +dnl GCC_NEED_DECLARATION(FUNCTION [, EXTRA-HEADER-FILES]) +AC_DEFUN(GCC_NEED_DECLARATION, +[AC_MSG_CHECKING([whether $1 must be declared]) +AC_CACHE_VAL(gcc_cv_decl_needed_$1, +[AC_TRY_COMPILE([ +#include +#ifdef STRING_WITH_STRINGS +# include +# include +#else +# ifdef HAVE_STRING_H +# include +# else +# ifdef HAVE_STRINGS_H +# include +# endif +# endif +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifndef HAVE_RINDEX +#define rindex strrchr +#endif +#ifndef HAVE_INDEX +#define index strchr +#endif +$2], +[char *(*pfn) = (char *(*)) $1], +eval "gcc_cv_decl_needed_$1=no", eval "gcc_cv_decl_needed_$1=yes")]) +if eval "test \"`echo '$gcc_cv_decl_needed_'$1`\" = yes"; then + AC_MSG_RESULT(yes) + gcc_tr_decl=NEED_DECLARATION_`echo $1 | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + AC_DEFINE_UNQUOTED($gcc_tr_decl) +else + AC_MSG_RESULT(no) +fi +])dnl + +dnl Check multiple functions to see whether each needs a declaration. +dnl GCC_NEED_DECLARATIONS(FUNCTION... [, EXTRA-HEADER-FILES]) +AC_DEFUN(GCC_NEED_DECLARATIONS, +[for ac_func in $1 +do +GCC_NEED_DECLARATION($ac_func, $2) +done +]) + +dnl Check if we have vprintf and possibly _doprnt. +dnl Note autoconf checks for vprintf even though we care about vfprintf. +AC_DEFUN(GCC_FUNC_VFPRINTF_DOPRNT, +[AC_FUNC_VPRINTF +vfprintf= +doprint= +if test $ac_cv_func_vprintf != yes ; then + vfprintf=vfprintf.o + if test $ac_cv_func__doprnt != yes ; then + doprint=doprint.o + fi +fi +AC_SUBST(vfprintf) +AC_SUBST(doprint) +]) + +dnl See if the printf functions in libc support %p in format strings. +AC_DEFUN(GCC_FUNC_PRINTF_PTR, +[AC_CACHE_CHECK(whether the printf functions support %p, + gcc_cv_func_printf_ptr, +[AC_TRY_RUN([#include + +main() +{ + char buf[64]; + char *p = buf, *q = NULL; + sprintf(buf, "%p", p); + sscanf(buf, "%p", &q); + exit (p != q); +}], gcc_cv_func_printf_ptr=yes, gcc_cv_func_printf_ptr=no, + gcc_cv_func_printf_ptr=no) +rm -f core core.* *.core]) +if test $gcc_cv_func_printf_ptr = yes ; then + AC_DEFINE(HAVE_PRINTF_PTR) +fi +]) + +dnl See if symbolic links work and if not, try to substitute either hard links or simple copy. +AC_DEFUN(GCC_PROG_LN_S, +[AC_MSG_CHECKING(whether ln -s works) +AC_CACHE_VAL(gcc_cv_prog_LN_S, +[rm -f conftestdata_t +echo >conftestdata_f +if ln -s conftestdata_f conftestdata_t 2>/dev/null +then + gcc_cv_prog_LN_S="ln -s" +else + 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 +])dnl +LN_S="$gcc_cv_prog_LN_S" +if test "$gcc_cv_prog_LN_S" = "ln -s"; then + AC_MSG_RESULT(yes) +else + if test "$gcc_cv_prog_LN_S" = "ln"; then + AC_MSG_RESULT([no, using ln]) + else + AC_MSG_RESULT([no, and neither does ln, so using cp]) + fi +fi +AC_SUBST(LN_S)dnl +]) + +dnl See if hard links work and if not, try to substitute either symbolic links or simple copy. +AC_DEFUN(GCC_PROG_LN, +[AC_MSG_CHECKING(whether ln works) +AC_CACHE_VAL(gcc_cv_prog_LN, +[rm -f conftestdata_t +echo >conftestdata_f +if ln conftestdata_f conftestdata_t 2>/dev/null +then + gcc_cv_prog_LN="ln" +else + if ln -s conftestdata_f conftestdata_t 2>/dev/null + then + gcc_cv_prog_LN="ln -s" + else + gcc_cv_prog_LN=cp + fi +fi +rm -f conftestdata_f conftestdata_t +])dnl +LN="$gcc_cv_prog_LN" +if test "$gcc_cv_prog_LN" = "ln"; then + AC_MSG_RESULT(yes) +else + if test "$gcc_cv_prog_LN" = "ln -s"; then + AC_MSG_RESULT([no, using ln -s]) + else + AC_MSG_RESULT([no, and neither does ln -s, so using cp]) + fi +fi +AC_SUBST(LN)dnl +]) + +dnl See whether the stage1 host compiler accepts the volatile keyword. +AC_DEFUN(GCC_C_VOLATILE, +[AC_CACHE_CHECK([for volatile], gcc_cv_c_volatile, +[AC_TRY_COMPILE(, [volatile int foo;], + gcc_cv_c_volatile=yes, gcc_cv_c_volatile=no)]) +if test $gcc_cv_c_volatile = yes ; then + AC_DEFINE(HAVE_VOLATILE) +fi +]) + +AC_DEFUN(EGCS_PROG_INSTALL, +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +# 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: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +AC_MSG_CHECKING(for a BSD compatible install) +if test -z "$INSTALL"; then +AC_CACHE_VAL(ac_cv_path_install, +[ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + # OSF/1 installbsd also uses dspmsg, but is usable. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" +])dnl + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +dnl We do special magic for INSTALL instead of AC_SUBST, to get +dnl relative paths right. +AC_MSG_RESULT($INSTALL) +AC_SUBST(INSTALL)dnl + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' +AC_SUBST(INSTALL_PROGRAM)dnl + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' +AC_SUBST(INSTALL_DATA)dnl +]) diff --git a/gcc_arm/alias.c b/gcc_arm/alias.c new file mode 100755 index 0000000..fc6b90b --- /dev/null +++ b/gcc_arm/alias.c @@ -0,0 +1,1545 @@ +/* Alias analysis for GNU C + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + Contributed by John Carr (jfc@mit.edu). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "rtl.h" +#include "expr.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "flags.h" +#include "output.h" +#include "toplev.h" +#include "splay-tree.h" + +/* The alias sets assigned to MEMs assist the back-end in determining + which MEMs can alias which other MEMs. In general, two MEMs in + different alias sets to not alias each other. There is one + exception, however. Consider something like: + + struct S {int i; double d; }; + + a store to an `S' can alias something of either type `int' or type + `double'. (However, a store to an `int' cannot alias a `double' + and vice versa.) We indicate this via a tree structure that looks + like: + struct S + / \ + / \ + |/_ _\| + int double + + (The arrows are directed and point downwards.) If, when comparing + two alias sets, we can hold one set fixed, and trace the other set + downwards, and at some point find the first set, the two MEMs can + alias one another. In this situation we say the alias set for + `struct S' is the `superset' and that those for `int' and `double' + are `subsets'. + + Alias set zero is implicitly a superset of all other alias sets. + However, this is no actual entry for alias set zero. It is an + error to attempt to explicitly construct a subset of zero. */ + +typedef struct alias_set_entry { + /* The alias set number, as stored in MEM_ALIAS_SET. */ + int alias_set; + + /* The children of the alias set. These are not just the immediate + children, but, in fact, all children. So, if we have: + + struct T { struct S s; float f; } + + continuing our example above, the children here will be all of + `int', `double', `float', and `struct S'. */ + splay_tree children; +}* alias_set_entry; + +static rtx canon_rtx PROTO((rtx)); +static int rtx_equal_for_memref_p PROTO((rtx, rtx)); +static rtx find_symbolic_term PROTO((rtx)); +static int memrefs_conflict_p PROTO((int, rtx, int, rtx, + HOST_WIDE_INT)); +static void record_set PROTO((rtx, rtx)); +static rtx find_base_term PROTO((rtx)); +static int base_alias_check PROTO((rtx, rtx, enum machine_mode, + enum machine_mode)); +static rtx find_base_value PROTO((rtx)); +static int mems_in_disjoint_alias_sets_p PROTO((rtx, rtx)); +static int alias_set_compare PROTO((splay_tree_key, + splay_tree_key)); +static int insert_subset_children PROTO((splay_tree_node, + void*)); +static alias_set_entry get_alias_set_entry PROTO((int)); +static rtx fixed_scalar_and_varying_struct_p PROTO((rtx, rtx, int (*)(rtx))); +static int aliases_everything_p PROTO((rtx)); +static int write_dependence_p PROTO((rtx, rtx, int)); + +/* Set up all info needed to perform alias analysis on memory references. */ + +#define SIZE_FOR_MODE(X) (GET_MODE_SIZE (GET_MODE (X))) + +/* Returns nonzero if MEM1 and MEM2 do not alias because they are in + different alias sets. We ignore alias sets in functions making use + of variable arguments because the va_arg macros on some systems are + not legal ANSI C. */ +#define DIFFERENT_ALIAS_SETS_P(MEM1, MEM2) \ + mems_in_disjoint_alias_sets_p (MEM1, MEM2) + +/* Cap the number of passes we make over the insns propagating alias + information through set chains. + + 10 is a completely arbitrary choice. */ +#define MAX_ALIAS_LOOP_PASSES 10 + +/* reg_base_value[N] gives an address to which register N is related. + If all sets after the first add or subtract to the current value + or otherwise modify it so it does not point to a different top level + object, reg_base_value[N] is equal to the address part of the source + of the first set. + + A base address can be an ADDRESS, SYMBOL_REF, or LABEL_REF. ADDRESS + expressions represent certain special values: function arguments and + the stack, frame, and argument pointers. The contents of an address + expression are not used (but they are descriptive for debugging); + only the address and mode matter. Pointer equality, not rtx_equal_p, + determines whether two ADDRESS expressions refer to the same base + address. The mode determines whether it is a function argument or + other special value. */ + +rtx *reg_base_value; +rtx *new_reg_base_value; +unsigned int reg_base_value_size; /* size of reg_base_value array */ +#define REG_BASE_VALUE(X) \ + ((unsigned) REGNO (X) < reg_base_value_size ? reg_base_value[REGNO (X)] : 0) + +/* Vector of known invariant relationships between registers. Set in + loop unrolling. Indexed by register number, if nonzero the value + is an expression describing this register in terms of another. + + The length of this array is REG_BASE_VALUE_SIZE. + + Because this array contains only pseudo registers it has no effect + after reload. */ +static rtx *alias_invariant; + +/* Vector indexed by N giving the initial (unchanging) value known + for pseudo-register N. */ +rtx *reg_known_value; + +/* Indicates number of valid entries in reg_known_value. */ +static int reg_known_value_size; + +/* Vector recording for each reg_known_value whether it is due to a + REG_EQUIV note. Future passes (viz., reload) may replace the + pseudo with the equivalent expression and so we account for the + dependences that would be introduced if that happens. */ +/* ??? This is a problem only on the Convex. The REG_EQUIV notes created in + assign_parms mention the arg pointer, and there are explicit insns in the + RTL that modify the arg pointer. Thus we must ensure that such insns don't + get scheduled across each other because that would invalidate the REG_EQUIV + notes. One could argue that the REG_EQUIV notes are wrong, but solving + the problem in the scheduler will likely give better code, so we do it + here. */ +char *reg_known_equiv_p; + +/* True when scanning insns from the start of the rtl to the + NOTE_INSN_FUNCTION_BEG note. */ + +static int copying_arguments; + +/* The splay-tree used to store the various alias set entries. */ + +static splay_tree alias_sets; + +/* Returns -1, 0, 1 according to whether SET1 is less than, equal to, + or greater than SET2. */ + +static int +alias_set_compare (set1, set2) + splay_tree_key set1; + splay_tree_key set2; +{ + int s1 = (int) set1; + int s2 = (int) set2; + + if (s1 < s2) + return -1; + else if (s1 > s2) + return 1; + else + return 0; +} + +/* Returns a pointer to the alias set entry for ALIAS_SET, if there is + such an entry, or NULL otherwise. */ + +static alias_set_entry +get_alias_set_entry (alias_set) + int alias_set; +{ + splay_tree_node sn = + splay_tree_lookup (alias_sets, (splay_tree_key) alias_set); + + return sn ? ((alias_set_entry) sn->value) : ((alias_set_entry) 0); +} + +/* Returns nonzero value if the alias sets for MEM1 and MEM2 are such + that the two MEMs cannot alias each other. */ + +static int +mems_in_disjoint_alias_sets_p (mem1, mem2) + rtx mem1; + rtx mem2; +{ + alias_set_entry ase; + +#ifdef ENABLE_CHECKING +/* Perform a basic sanity check. Namely, that there are no alias sets + if we're not using strict aliasing. This helps to catch bugs + whereby someone uses PUT_CODE, but doesn't clear MEM_ALIAS_SET, or + where a MEM is allocated in some way other than by the use of + gen_rtx_MEM, and the MEM_ALIAS_SET is not cleared. If we begin to + use alias sets to indicate that spilled registers cannot alias each + other, we might need to remove this check. */ + if (!flag_strict_aliasing && + (MEM_ALIAS_SET (mem1) || MEM_ALIAS_SET (mem2))) + abort (); +#endif + + /* The code used in varargs macros are often not conforming ANSI C, + which can trick the compiler into making incorrect aliasing + assumptions in these functions. So, we don't use alias sets in + such a function. FIXME: This should be moved into the front-end; + it is a language-dependent notion, and there's no reason not to + still use these checks to handle globals. */ + if (current_function_stdarg || current_function_varargs) + return 0; + + if (!MEM_ALIAS_SET (mem1) || !MEM_ALIAS_SET (mem2)) + /* We have no alias set information for one of the MEMs, so we + have to assume it can alias anything. */ + return 0; + + if (MEM_ALIAS_SET (mem1) == MEM_ALIAS_SET (mem2)) + /* The two alias sets are the same, so they may alias. */ + return 0; + + /* Iterate through each of the children of the first alias set, + comparing it with the second alias set. */ + ase = get_alias_set_entry (MEM_ALIAS_SET (mem1)); + if (ase && splay_tree_lookup (ase->children, + (splay_tree_key) MEM_ALIAS_SET (mem2))) + return 0; + + /* Now do the same, but with the alias sets reversed. */ + ase = get_alias_set_entry (MEM_ALIAS_SET (mem2)); + if (ase && splay_tree_lookup (ase->children, + (splay_tree_key) MEM_ALIAS_SET (mem1))) + return 0; + + /* The two MEMs are in distinct alias sets, and neither one is the + child of the other. Therefore, they cannot alias. */ + return 1; +} + +/* Insert the NODE into the splay tree given by DATA. Used by + record_alias_subset via splay_tree_foreach. */ + +static int +insert_subset_children (node, data) + splay_tree_node node; + void *data; +{ + splay_tree_insert ((splay_tree) data, + node->key, + node->value); + + return 0; +} + +/* Indicate that things in SUBSET can alias things in SUPERSET, but + not vice versa. For example, in C, a store to an `int' can alias a + structure containing an `int', but not vice versa. Here, the + structure would be the SUPERSET and `int' the SUBSET. This + function should be called only once per SUPERSET/SUBSET pair. At + present any given alias set may only be a subset of one superset. + + It is illegal for SUPERSET to be zero; everything is implicitly a + subset of alias set zero. */ + +void +record_alias_subset (superset, subset) + int superset; + int subset; +{ + alias_set_entry superset_entry; + alias_set_entry subset_entry; + + if (superset == 0) + abort (); + + superset_entry = get_alias_set_entry (superset); + if (!superset_entry) + { + /* Create an entry for the SUPERSET, so that we have a place to + attach the SUBSET. */ + superset_entry = + (alias_set_entry) xmalloc (sizeof (struct alias_set_entry)); + superset_entry->alias_set = superset; + superset_entry->children + = splay_tree_new (alias_set_compare, 0, 0); + splay_tree_insert (alias_sets, + (splay_tree_key) superset, + (splay_tree_value) superset_entry); + + } + + subset_entry = get_alias_set_entry (subset); + if (subset_entry) + /* There is an entry for the subset. Enter all of its children + (if they are not already present) as children of the SUPERSET. */ + splay_tree_foreach (subset_entry->children, + insert_subset_children, + superset_entry->children); + + /* Enter the SUBSET itself as a child of the SUPERSET. */ + splay_tree_insert (superset_entry->children, + (splay_tree_key) subset, + /*value=*/0); +} + +/* Inside SRC, the source of a SET, find a base address. */ + +static rtx +find_base_value (src) + register rtx src; +{ + switch (GET_CODE (src)) + { + case SYMBOL_REF: + case LABEL_REF: + return src; + + case REG: + /* At the start of a function argument registers have known base + values which may be lost later. Returning an ADDRESS + expression here allows optimization based on argument values + even when the argument registers are used for other purposes. */ + if (REGNO (src) < FIRST_PSEUDO_REGISTER && copying_arguments) + return new_reg_base_value[REGNO (src)]; + + /* If a pseudo has a known base value, return it. Do not do this + for hard regs since it can result in a circular dependency + chain for registers which have values at function entry. + + The test above is not sufficient because the scheduler may move + a copy out of an arg reg past the NOTE_INSN_FUNCTION_BEGIN. */ + if (REGNO (src) >= FIRST_PSEUDO_REGISTER + && (unsigned) REGNO (src) < reg_base_value_size + && reg_base_value[REGNO (src)]) + return reg_base_value[REGNO (src)]; + + return src; + + case MEM: + /* Check for an argument passed in memory. Only record in the + copying-arguments block; it is too hard to track changes + otherwise. */ + if (copying_arguments + && (XEXP (src, 0) == arg_pointer_rtx + || (GET_CODE (XEXP (src, 0)) == PLUS + && XEXP (XEXP (src, 0), 0) == arg_pointer_rtx))) + return gen_rtx_ADDRESS (VOIDmode, src); + return 0; + + case CONST: + src = XEXP (src, 0); + if (GET_CODE (src) != PLUS && GET_CODE (src) != MINUS) + break; + /* fall through */ + + case PLUS: + case MINUS: + { + rtx temp, src_0 = XEXP (src, 0), src_1 = XEXP (src, 1); + + /* If either operand is a REG, then see if we already have + a known value for it. */ + if (GET_CODE (src_0) == REG) + { + temp = find_base_value (src_0); + if (temp) + src_0 = temp; + } + + if (GET_CODE (src_1) == REG) + { + temp = find_base_value (src_1); + if (temp) + src_1 = temp; + } + + /* Guess which operand is the base address. + + If either operand is a symbol, then it is the base. If + either operand is a CONST_INT, then the other is the base. */ + + if (GET_CODE (src_1) == CONST_INT + || GET_CODE (src_0) == SYMBOL_REF + || GET_CODE (src_0) == LABEL_REF + || GET_CODE (src_0) == CONST) + return find_base_value (src_0); + + if (GET_CODE (src_0) == CONST_INT + || GET_CODE (src_1) == SYMBOL_REF + || GET_CODE (src_1) == LABEL_REF + || GET_CODE (src_1) == CONST) + return find_base_value (src_1); + + /* This might not be necessary anymore. + + If either operand is a REG that is a known pointer, then it + is the base. */ + if (GET_CODE (src_0) == REG && REGNO_POINTER_FLAG (REGNO (src_0))) + return find_base_value (src_0); + + if (GET_CODE (src_1) == REG && REGNO_POINTER_FLAG (REGNO (src_1))) + return find_base_value (src_1); + + return 0; + } + + case LO_SUM: + /* The standard form is (lo_sum reg sym) so look only at the + second operand. */ + return find_base_value (XEXP (src, 1)); + + case AND: + /* If the second operand is constant set the base + address to the first operand. */ + if (GET_CODE (XEXP (src, 1)) == CONST_INT && INTVAL (XEXP (src, 1)) != 0) + return find_base_value (XEXP (src, 0)); + return 0; + + case ZERO_EXTEND: + case SIGN_EXTEND: /* used for NT/Alpha pointers */ + case HIGH: + return find_base_value (XEXP (src, 0)); + + default: + break; + } + + return 0; +} + +/* Called from init_alias_analysis indirectly through note_stores. */ + +/* while scanning insns to find base values, reg_seen[N] is nonzero if + register N has been set in this function. */ +static char *reg_seen; + +/* Addresses which are known not to alias anything else are identified + by a unique integer. */ +static int unique_id; + +static void +record_set (dest, set) + rtx dest, set; +{ + register int regno; + rtx src; + + if (GET_CODE (dest) != REG) + return; + + regno = REGNO (dest); + + if (set) + { + /* A CLOBBER wipes out any old value but does not prevent a previously + unset register from acquiring a base address (i.e. reg_seen is not + set). */ + if (GET_CODE (set) == CLOBBER) + { + new_reg_base_value[regno] = 0; + return; + } + src = SET_SRC (set); + } + else + { + if (reg_seen[regno]) + { + new_reg_base_value[regno] = 0; + return; + } + reg_seen[regno] = 1; + new_reg_base_value[regno] = gen_rtx_ADDRESS (Pmode, + GEN_INT (unique_id++)); + return; + } + + /* This is not the first set. If the new value is not related to the + old value, forget the base value. Note that the following code is + not detected: + extern int x, y; int *p = &x; p += (&y-&x); + ANSI C does not allow computing the difference of addresses + of distinct top level objects. */ + if (new_reg_base_value[regno]) + switch (GET_CODE (src)) + { + case LO_SUM: + case PLUS: + case MINUS: + if (XEXP (src, 0) != dest && XEXP (src, 1) != dest) + new_reg_base_value[regno] = 0; + break; + case AND: + if (XEXP (src, 0) != dest || GET_CODE (XEXP (src, 1)) != CONST_INT) + new_reg_base_value[regno] = 0; + break; + default: + new_reg_base_value[regno] = 0; + break; + } + /* If this is the first set of a register, record the value. */ + else if ((regno >= FIRST_PSEUDO_REGISTER || ! fixed_regs[regno]) + && ! reg_seen[regno] && new_reg_base_value[regno] == 0) + new_reg_base_value[regno] = find_base_value (src); + + reg_seen[regno] = 1; +} + +/* Called from loop optimization when a new pseudo-register is created. */ +void +record_base_value (regno, val, invariant) + int regno; + rtx val; + int invariant; +{ + if ((unsigned) regno >= reg_base_value_size) + return; + + /* If INVARIANT is true then this value also describes an invariant + relationship which can be used to deduce that two registers with + unknown values are different. */ + if (invariant && alias_invariant) + alias_invariant[regno] = val; + + if (GET_CODE (val) == REG) + { + if ((unsigned) REGNO (val) < reg_base_value_size) + { + reg_base_value[regno] = reg_base_value[REGNO (val)]; + } + return; + } + reg_base_value[regno] = find_base_value (val); +} + +static rtx +canon_rtx (x) + rtx x; +{ + /* Recursively look for equivalences. */ + if (GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER + && REGNO (x) < reg_known_value_size) + return reg_known_value[REGNO (x)] == x + ? x : canon_rtx (reg_known_value[REGNO (x)]); + else if (GET_CODE (x) == PLUS) + { + rtx x0 = canon_rtx (XEXP (x, 0)); + rtx x1 = canon_rtx (XEXP (x, 1)); + + if (x0 != XEXP (x, 0) || x1 != XEXP (x, 1)) + { + /* We can tolerate LO_SUMs being offset here; these + rtl are used for nothing other than comparisons. */ + if (GET_CODE (x0) == CONST_INT) + return plus_constant_for_output (x1, INTVAL (x0)); + else if (GET_CODE (x1) == CONST_INT) + return plus_constant_for_output (x0, INTVAL (x1)); + return gen_rtx_PLUS (GET_MODE (x), x0, x1); + } + } + /* This gives us much better alias analysis when called from + the loop optimizer. Note we want to leave the original + MEM alone, but need to return the canonicalized MEM with + all the flags with their original values. */ + else if (GET_CODE (x) == MEM) + { + rtx addr = canon_rtx (XEXP (x, 0)); + if (addr != XEXP (x, 0)) + { + rtx new = gen_rtx_MEM (GET_MODE (x), addr); + RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (x); + MEM_COPY_ATTRIBUTES (new, x); + MEM_ALIAS_SET (new) = MEM_ALIAS_SET (x); + x = new; + } + } + return x; +} + +/* Return 1 if X and Y are identical-looking rtx's. + + We use the data in reg_known_value above to see if two registers with + different numbers are, in fact, equivalent. */ + +static int +rtx_equal_for_memref_p (x, y) + rtx x, y; +{ + register int i; + register int j; + register enum rtx_code code; + register char *fmt; + + if (x == 0 && y == 0) + return 1; + if (x == 0 || y == 0) + return 0; + x = canon_rtx (x); + y = canon_rtx (y); + + if (x == y) + return 1; + + code = GET_CODE (x); + /* Rtx's of different codes cannot be equal. */ + if (code != GET_CODE (y)) + return 0; + + /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. + (REG:SI x) and (REG:HI x) are NOT equivalent. */ + + if (GET_MODE (x) != GET_MODE (y)) + return 0; + + /* REG, LABEL_REF, and SYMBOL_REF can be compared nonrecursively. */ + + if (code == REG) + return REGNO (x) == REGNO (y); + if (code == LABEL_REF) + return XEXP (x, 0) == XEXP (y, 0); + if (code == SYMBOL_REF) + return XSTR (x, 0) == XSTR (y, 0); + if (code == CONST_INT) + return INTVAL (x) == INTVAL (y); + if (code == ADDRESSOF) + return REGNO (XEXP (x, 0)) == REGNO (XEXP (y, 0)) && XINT (x, 1) == XINT (y, 1); + + /* For commutative operations, the RTX match if the operand match in any + order. Also handle the simple binary and unary cases without a loop. */ + if (code == EQ || code == NE || GET_RTX_CLASS (code) == 'c') + return ((rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 0)) + && rtx_equal_for_memref_p (XEXP (x, 1), XEXP (y, 1))) + || (rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 1)) + && rtx_equal_for_memref_p (XEXP (x, 1), XEXP (y, 0)))); + else if (GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == '2') + return (rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 0)) + && rtx_equal_for_memref_p (XEXP (x, 1), XEXP (y, 1))); + else if (GET_RTX_CLASS (code) == '1') + return rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 0)); + + /* Compare the elements. If any pair of corresponding elements + fail to match, return 0 for the whole things. + + Limit cases to types which actually appear in addresses. */ + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + switch (fmt[i]) + { + case 'i': + if (XINT (x, i) != XINT (y, i)) + return 0; + break; + + case 'E': + /* Two vectors must have the same length. */ + if (XVECLEN (x, i) != XVECLEN (y, i)) + return 0; + + /* And the corresponding elements must match. */ + for (j = 0; j < XVECLEN (x, i); j++) + if (rtx_equal_for_memref_p (XVECEXP (x, i, j), XVECEXP (y, i, j)) == 0) + return 0; + break; + + case 'e': + if (rtx_equal_for_memref_p (XEXP (x, i), XEXP (y, i)) == 0) + return 0; + break; + + /* This can happen for an asm which clobbers memory. */ + case '0': + break; + + /* It is believed that rtx's at this level will never + contain anything but integers and other rtx's, + except for within LABEL_REFs and SYMBOL_REFs. */ + default: + abort (); + } + } + return 1; +} + +/* Given an rtx X, find a SYMBOL_REF or LABEL_REF within + X and return it, or return 0 if none found. */ + +static rtx +find_symbolic_term (x) + rtx x; +{ + register int i; + register enum rtx_code code; + register char *fmt; + + code = GET_CODE (x); + if (code == SYMBOL_REF || code == LABEL_REF) + return x; + if (GET_RTX_CLASS (code) == 'o') + return 0; + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + rtx t; + + if (fmt[i] == 'e') + { + t = find_symbolic_term (XEXP (x, i)); + if (t != 0) + return t; + } + else if (fmt[i] == 'E') + break; + } + return 0; +} + +static rtx +find_base_term (x) + register rtx x; +{ + switch (GET_CODE (x)) + { + case REG: + return REG_BASE_VALUE (x); + + case ZERO_EXTEND: + case SIGN_EXTEND: /* Used for Alpha/NT pointers */ + case HIGH: + case PRE_INC: + case PRE_DEC: + case POST_INC: + case POST_DEC: + return find_base_term (XEXP (x, 0)); + + case CONST: + x = XEXP (x, 0); + if (GET_CODE (x) != PLUS && GET_CODE (x) != MINUS) + return 0; + /* fall through */ + case LO_SUM: + case PLUS: + case MINUS: + { + rtx tmp = find_base_term (XEXP (x, 0)); + if (tmp) + return tmp; + return find_base_term (XEXP (x, 1)); + } + + case AND: + if (GET_CODE (XEXP (x, 0)) == REG && GET_CODE (XEXP (x, 1)) == CONST_INT) + return REG_BASE_VALUE (XEXP (x, 0)); + return 0; + + case SYMBOL_REF: + case LABEL_REF: + return x; + + default: + return 0; + } +} + +/* Return 0 if the addresses X and Y are known to point to different + objects, 1 if they might be pointers to the same object. */ + +static int +base_alias_check (x, y, x_mode, y_mode) + rtx x, y; + enum machine_mode x_mode, y_mode; +{ + rtx x_base = find_base_term (x); + rtx y_base = find_base_term (y); + + /* If the address itself has no known base see if a known equivalent + value has one. If either address still has no known base, nothing + is known about aliasing. */ + if (x_base == 0) + { + rtx x_c; + if (! flag_expensive_optimizations || (x_c = canon_rtx (x)) == x) + return 1; + x_base = find_base_term (x_c); + if (x_base == 0) + return 1; + } + + if (y_base == 0) + { + rtx y_c; + if (! flag_expensive_optimizations || (y_c = canon_rtx (y)) == y) + return 1; + y_base = find_base_term (y_c); + if (y_base == 0) + return 1; + } + + /* If the base addresses are equal nothing is known about aliasing. */ + if (rtx_equal_p (x_base, y_base)) + return 1; + + /* The base addresses of the read and write are different expressions. + If they are both symbols and they are not accessed via AND, there is + no conflict. We can bring knowledge of object alignment into play + here. For example, on alpha, "char a, b;" can alias one another, + though "char a; long b;" cannot. */ + if (GET_CODE (x_base) != ADDRESS && GET_CODE (y_base) != ADDRESS) + { + if (GET_CODE (x) == AND && GET_CODE (y) == AND) + return 1; + if (GET_CODE (x) == AND + && (GET_CODE (XEXP (x, 1)) != CONST_INT + || GET_MODE_UNIT_SIZE (y_mode) < -INTVAL (XEXP (x, 1)))) + return 1; + if (GET_CODE (y) == AND + && (GET_CODE (XEXP (y, 1)) != CONST_INT + || GET_MODE_UNIT_SIZE (x_mode) < -INTVAL (XEXP (y, 1)))) + return 1; + /* Differing symbols never alias. */ + return 0; + } + + /* If one address is a stack reference there can be no alias: + stack references using different base registers do not alias, + a stack reference can not alias a parameter, and a stack reference + can not alias a global. */ + if ((GET_CODE (x_base) == ADDRESS && GET_MODE (x_base) == Pmode) + || (GET_CODE (y_base) == ADDRESS && GET_MODE (y_base) == Pmode)) + return 0; + + if (! flag_argument_noalias) + return 1; + + if (flag_argument_noalias > 1) + return 0; + + /* Weak noalias assertion (arguments are distinct, but may match globals). */ + return ! (GET_MODE (x_base) == VOIDmode && GET_MODE (y_base) == VOIDmode); +} + +/* Return the address of the (N_REFS + 1)th memory reference to ADDR + where SIZE is the size in bytes of the memory reference. If ADDR + is not modified by the memory reference then ADDR is returned. */ + +rtx +addr_side_effect_eval (addr, size, n_refs) + rtx addr; + int size; + int n_refs; +{ + int offset = 0; + + switch (GET_CODE (addr)) + { + case PRE_INC: + offset = (n_refs + 1) * size; + break; + case PRE_DEC: + offset = -(n_refs + 1) * size; + break; + case POST_INC: + offset = n_refs * size; + break; + case POST_DEC: + offset = -n_refs * size; + break; + + default: + return addr; + } + + if (offset) + addr = gen_rtx_PLUS (GET_MODE (addr), XEXP (addr, 0), GEN_INT (offset)); + else + addr = XEXP (addr, 0); + + return addr; +} + +/* Return nonzero if X and Y (memory addresses) could reference the + same location in memory. C is an offset accumulator. When + C is nonzero, we are testing aliases between X and Y + C. + XSIZE is the size in bytes of the X reference, + similarly YSIZE is the size in bytes for Y. + + If XSIZE or YSIZE is zero, we do not know the amount of memory being + referenced (the reference was BLKmode), so make the most pessimistic + assumptions. + + If XSIZE or YSIZE is negative, we may access memory outside the object + being referenced as a side effect. This can happen when using AND to + align memory references, as is done on the Alpha. + + Nice to notice that varying addresses cannot conflict with fp if no + local variables had their addresses taken, but that's too hard now. */ + + +static int +memrefs_conflict_p (xsize, x, ysize, y, c) + register rtx x, y; + int xsize, ysize; + HOST_WIDE_INT c; +{ + if (GET_CODE (x) == HIGH) + x = XEXP (x, 0); + else if (GET_CODE (x) == LO_SUM) + x = XEXP (x, 1); + else + x = canon_rtx (addr_side_effect_eval (x, xsize, 0)); + if (GET_CODE (y) == HIGH) + y = XEXP (y, 0); + else if (GET_CODE (y) == LO_SUM) + y = XEXP (y, 1); + else + y = canon_rtx (addr_side_effect_eval (y, ysize, 0)); + + if (rtx_equal_for_memref_p (x, y)) + { + if (xsize <= 0 || ysize <= 0) + return 1; + if (c >= 0 && xsize > c) + return 1; + if (c < 0 && ysize+c > 0) + return 1; + return 0; + } + + /* This code used to check for conflicts involving stack references and + globals but the base address alias code now handles these cases. */ + + if (GET_CODE (x) == PLUS) + { + /* The fact that X is canonicalized means that this + PLUS rtx is canonicalized. */ + rtx x0 = XEXP (x, 0); + rtx x1 = XEXP (x, 1); + + if (GET_CODE (y) == PLUS) + { + /* The fact that Y is canonicalized means that this + PLUS rtx is canonicalized. */ + rtx y0 = XEXP (y, 0); + rtx y1 = XEXP (y, 1); + + if (rtx_equal_for_memref_p (x1, y1)) + return memrefs_conflict_p (xsize, x0, ysize, y0, c); + if (rtx_equal_for_memref_p (x0, y0)) + return memrefs_conflict_p (xsize, x1, ysize, y1, c); + if (GET_CODE (x1) == CONST_INT) + { + if (GET_CODE (y1) == CONST_INT) + return memrefs_conflict_p (xsize, x0, ysize, y0, + c - INTVAL (x1) + INTVAL (y1)); + else + return memrefs_conflict_p (xsize, x0, ysize, y, + c - INTVAL (x1)); + } + else if (GET_CODE (y1) == CONST_INT) + return memrefs_conflict_p (xsize, x, ysize, y0, c + INTVAL (y1)); + + return 1; + } + else if (GET_CODE (x1) == CONST_INT) + return memrefs_conflict_p (xsize, x0, ysize, y, c - INTVAL (x1)); + } + else if (GET_CODE (y) == PLUS) + { + /* The fact that Y is canonicalized means that this + PLUS rtx is canonicalized. */ + rtx y0 = XEXP (y, 0); + rtx y1 = XEXP (y, 1); + + if (GET_CODE (y1) == CONST_INT) + return memrefs_conflict_p (xsize, x, ysize, y0, c + INTVAL (y1)); + else + return 1; + } + + if (GET_CODE (x) == GET_CODE (y)) + switch (GET_CODE (x)) + { + case MULT: + { + /* Handle cases where we expect the second operands to be the + same, and check only whether the first operand would conflict + or not. */ + rtx x0, y0; + rtx x1 = canon_rtx (XEXP (x, 1)); + rtx y1 = canon_rtx (XEXP (y, 1)); + if (! rtx_equal_for_memref_p (x1, y1)) + return 1; + x0 = canon_rtx (XEXP (x, 0)); + y0 = canon_rtx (XEXP (y, 0)); + if (rtx_equal_for_memref_p (x0, y0)) + return (xsize == 0 || ysize == 0 + || (c >= 0 && xsize > c) || (c < 0 && ysize+c > 0)); + + /* Can't properly adjust our sizes. */ + if (GET_CODE (x1) != CONST_INT) + return 1; + xsize /= INTVAL (x1); + ysize /= INTVAL (x1); + c /= INTVAL (x1); + return memrefs_conflict_p (xsize, x0, ysize, y0, c); + } + + case REG: + /* Are these registers known not to be equal? */ + if (alias_invariant) + { + unsigned int r_x = REGNO (x), r_y = REGNO (y); + rtx i_x, i_y; /* invariant relationships of X and Y */ + + i_x = r_x >= reg_base_value_size ? 0 : alias_invariant[r_x]; + i_y = r_y >= reg_base_value_size ? 0 : alias_invariant[r_y]; + + if (i_x == 0 && i_y == 0) + break; + + if (! memrefs_conflict_p (xsize, i_x ? i_x : x, + ysize, i_y ? i_y : y, c)) + return 0; + } + break; + + default: + break; + } + + /* Treat an access through an AND (e.g. a subword access on an Alpha) + as an access with indeterminate size. Assume that references + besides AND are aligned, so if the size of the other reference is + at least as large as the alignment, assume no other overlap. */ + if (GET_CODE (x) == AND && GET_CODE (XEXP (x, 1)) == CONST_INT) + { + if (GET_CODE (y) == AND || ysize < -INTVAL (XEXP (x, 1))) + xsize = -1; + return memrefs_conflict_p (xsize, XEXP (x, 0), ysize, y, c); + } + if (GET_CODE (y) == AND && GET_CODE (XEXP (y, 1)) == CONST_INT) + { + /* ??? If we are indexing far enough into the array/structure, we + may yet be able to determine that we can not overlap. But we + also need to that we are far enough from the end not to overlap + a following reference, so we do nothing with that for now. */ + if (GET_CODE (x) == AND || xsize < -INTVAL (XEXP (y, 1))) + ysize = -1; + return memrefs_conflict_p (xsize, x, ysize, XEXP (y, 0), c); + } + + if (CONSTANT_P (x)) + { + if (GET_CODE (x) == CONST_INT && GET_CODE (y) == CONST_INT) + { + c += (INTVAL (y) - INTVAL (x)); + return (xsize <= 0 || ysize <= 0 + || (c >= 0 && xsize > c) || (c < 0 && ysize+c > 0)); + } + + if (GET_CODE (x) == CONST) + { + if (GET_CODE (y) == CONST) + return memrefs_conflict_p (xsize, canon_rtx (XEXP (x, 0)), + ysize, canon_rtx (XEXP (y, 0)), c); + else + return memrefs_conflict_p (xsize, canon_rtx (XEXP (x, 0)), + ysize, y, c); + } + if (GET_CODE (y) == CONST) + return memrefs_conflict_p (xsize, x, ysize, + canon_rtx (XEXP (y, 0)), c); + + if (CONSTANT_P (y)) + return (xsize < 0 || ysize < 0 + || (rtx_equal_for_memref_p (x, y) + && (xsize == 0 || ysize == 0 + || (c >= 0 && xsize > c) || (c < 0 && ysize+c > 0)))); + + return 1; + } + return 1; +} + +/* Functions to compute memory dependencies. + + Since we process the insns in execution order, we can build tables + to keep track of what registers are fixed (and not aliased), what registers + are varying in known ways, and what registers are varying in unknown + ways. + + If both memory references are volatile, then there must always be a + dependence between the two references, since their order can not be + changed. A volatile and non-volatile reference can be interchanged + though. + + A MEM_IN_STRUCT reference at a non-QImode non-AND varying address can never + conflict with a non-MEM_IN_STRUCT reference at a fixed address. We must + allow QImode aliasing because the ANSI C standard allows character + pointers to alias anything. We are assuming that characters are + always QImode here. We also must allow AND addresses, because they may + generate accesses outside the object being referenced. This is used to + generate aligned addresses from unaligned addresses, for instance, the + alpha storeqi_unaligned pattern. */ + +/* Read dependence: X is read after read in MEM takes place. There can + only be a dependence here if both reads are volatile. */ + +int +read_dependence (mem, x) + rtx mem; + rtx x; +{ + return MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem); +} + +/* Returns MEM1 if and only if MEM1 is a scalar at a fixed address and + MEM2 is a reference to a structure at a varying address, or returns + MEM2 if vice versa. Otherwise, returns NULL_RTX. If a non-NULL + value is returned MEM1 and MEM2 can never alias. VARIES_P is used + to decide whether or not an address may vary; it should return + nozero whenever variation is possible. */ + +static rtx +fixed_scalar_and_varying_struct_p (mem1, mem2, varies_p) + rtx mem1; + rtx mem2; + int (*varies_p) PROTO((rtx)); +{ + rtx mem1_addr = XEXP (mem1, 0); + rtx mem2_addr = XEXP (mem2, 0); + + if (MEM_SCALAR_P (mem1) && MEM_IN_STRUCT_P (mem2) + && !varies_p (mem1_addr) && varies_p (mem2_addr)) + /* MEM1 is a scalar at a fixed address; MEM2 is a struct at a + varying address. */ + return mem1; + + if (MEM_IN_STRUCT_P (mem1) && MEM_SCALAR_P (mem2) + && varies_p (mem1_addr) && !varies_p (mem2_addr)) + /* MEM2 is a scalar at a fixed address; MEM1 is a struct at a + varying address. */ + return mem2; + + return NULL_RTX; +} + +/* Returns nonzero if something about the mode or address format MEM1 + indicates that it might well alias *anything*. */ + +static int +aliases_everything_p (mem) + rtx mem; +{ + if (GET_MODE (mem) == QImode) + /* ANSI C says that a `char*' can point to anything. */ + return 1; + + if (GET_CODE (XEXP (mem, 0)) == AND) + /* If the address is an AND, its very hard to know at what it is + actually pointing. */ + return 1; + + return 0; +} + +/* True dependence: X is read after store in MEM takes place. */ + +int +true_dependence (mem, mem_mode, x, varies) + rtx mem; + enum machine_mode mem_mode; + rtx x; + int (*varies) PROTO((rtx)); +{ + register rtx x_addr, mem_addr; + + if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem)) + return 1; + + if (DIFFERENT_ALIAS_SETS_P (x, mem)) + return 0; + + /* If X is an unchanging read, then it can't possibly conflict with any + non-unchanging store. It may conflict with an unchanging write though, + because there may be a single store to this address to initialize it. + Just fall through to the code below to resolve the case where we have + both an unchanging read and an unchanging write. This won't handle all + cases optimally, but the possible performance loss should be + negligible. */ + if (RTX_UNCHANGING_P (x) && ! RTX_UNCHANGING_P (mem)) + return 0; + + if (mem_mode == VOIDmode) + mem_mode = GET_MODE (mem); + + if (! base_alias_check (XEXP (x, 0), XEXP (mem, 0), GET_MODE (x), mem_mode)) + return 0; + + x_addr = canon_rtx (XEXP (x, 0)); + mem_addr = canon_rtx (XEXP (mem, 0)); + + if (! memrefs_conflict_p (GET_MODE_SIZE (mem_mode), mem_addr, + SIZE_FOR_MODE (x), x_addr, 0)) + return 0; + + if (aliases_everything_p (x)) + return 1; + + /* We cannot use aliases_everyting_p to test MEM, since we must look + at MEM_MODE, rather than GET_MODE (MEM). */ + if (mem_mode == QImode || GET_CODE (mem_addr) == AND) + return 1; + + /* In true_dependence we also allow BLKmode to alias anything. Why + don't we do this in anti_dependence and output_dependence? */ + if (mem_mode == BLKmode || GET_MODE (x) == BLKmode) + return 1; + + return !fixed_scalar_and_varying_struct_p (mem, x, varies); +} + +/* Returns non-zero if a write to X might alias a read from (or, if + WRITEP is non-zero, a write to) MEM. */ + +static int +write_dependence_p (mem, x, writep) + rtx mem; + rtx x; + int writep; +{ + rtx x_addr, mem_addr; + rtx fixed_scalar; + + if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem)) + return 1; + + /* If MEM is an unchanging read, then it can't possibly conflict with + the store to X, because there is at most one store to MEM, and it must + have occurred somewhere before MEM. */ + if (!writep && RTX_UNCHANGING_P (mem)) + return 0; + + if (! base_alias_check (XEXP (x, 0), XEXP (mem, 0), GET_MODE (x), + GET_MODE (mem))) + return 0; + + x = canon_rtx (x); + mem = canon_rtx (mem); + + if (DIFFERENT_ALIAS_SETS_P (x, mem)) + return 0; + + x_addr = XEXP (x, 0); + mem_addr = XEXP (mem, 0); + + if (!memrefs_conflict_p (SIZE_FOR_MODE (mem), mem_addr, + SIZE_FOR_MODE (x), x_addr, 0)) + return 0; + + fixed_scalar + = fixed_scalar_and_varying_struct_p (mem, x, rtx_addr_varies_p); + + return (!(fixed_scalar == mem && !aliases_everything_p (x)) + && !(fixed_scalar == x && !aliases_everything_p (mem))); +} + +/* Anti dependence: X is written after read in MEM takes place. */ + +int +anti_dependence (mem, x) + rtx mem; + rtx x; +{ + return write_dependence_p (mem, x, /*writep=*/0); +} + +/* Output dependence: X is written after store in MEM takes place. */ + +int +output_dependence (mem, x) + register rtx mem; + register rtx x; +{ + return write_dependence_p (mem, x, /*writep=*/1); +} + + +static HARD_REG_SET argument_registers; + +void +init_alias_once () +{ + register int i; + +#ifndef OUTGOING_REGNO +#define OUTGOING_REGNO(N) N +#endif + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + /* Check whether this register can hold an incoming pointer + argument. FUNCTION_ARG_REGNO_P tests outgoing register + numbers, so translate if necessary due to register windows. */ + if (FUNCTION_ARG_REGNO_P (OUTGOING_REGNO (i)) + && HARD_REGNO_MODE_OK (i, Pmode)) + SET_HARD_REG_BIT (argument_registers, i); + + alias_sets = splay_tree_new (alias_set_compare, 0, 0); +} + +void +init_alias_analysis () +{ + int maxreg = max_reg_num (); + int changed, pass; + register int i; + register unsigned int ui; + register rtx insn; + + reg_known_value_size = maxreg; + + reg_known_value + = (rtx *) oballoc ((maxreg - FIRST_PSEUDO_REGISTER) * sizeof (rtx)) + - FIRST_PSEUDO_REGISTER; + reg_known_equiv_p = + oballoc (maxreg - FIRST_PSEUDO_REGISTER) - FIRST_PSEUDO_REGISTER; + bzero ((char *) (reg_known_value + FIRST_PSEUDO_REGISTER), + (maxreg-FIRST_PSEUDO_REGISTER) * sizeof (rtx)); + bzero (reg_known_equiv_p + FIRST_PSEUDO_REGISTER, + (maxreg - FIRST_PSEUDO_REGISTER) * sizeof (char)); + + /* Overallocate reg_base_value to allow some growth during loop + optimization. Loop unrolling can create a large number of + registers. */ + reg_base_value_size = maxreg * 2; + reg_base_value = (rtx *)oballoc (reg_base_value_size * sizeof (rtx)); + new_reg_base_value = (rtx *)alloca (reg_base_value_size * sizeof (rtx)); + reg_seen = (char *)alloca (reg_base_value_size); + bzero ((char *) reg_base_value, reg_base_value_size * sizeof (rtx)); + if (! reload_completed && flag_unroll_loops) + { + alias_invariant = (rtx *)xrealloc (alias_invariant, + reg_base_value_size * sizeof (rtx)); + bzero ((char *)alias_invariant, reg_base_value_size * sizeof (rtx)); + } + + + /* The basic idea is that each pass through this loop will use the + "constant" information from the previous pass to propagate alias + information through another level of assignments. + + This could get expensive if the assignment chains are long. Maybe + we should throttle the number of iterations, possibly based on + the optimization level or flag_expensive_optimizations. + + We could propagate more information in the first pass by making use + of REG_N_SETS to determine immediately that the alias information + for a pseudo is "constant". + + A program with an uninitialized variable can cause an infinite loop + here. Instead of doing a full dataflow analysis to detect such problems + we just cap the number of iterations for the loop. + + The state of the arrays for the set chain in question does not matter + since the program has undefined behavior. */ + + pass = 0; + do + { + /* Assume nothing will change this iteration of the loop. */ + changed = 0; + + /* We want to assign the same IDs each iteration of this loop, so + start counting from zero each iteration of the loop. */ + unique_id = 0; + + /* We're at the start of the funtion each iteration through the + loop, so we're copying arguments. */ + copying_arguments = 1; + + /* Wipe the potential alias information clean for this pass. */ + bzero ((char *) new_reg_base_value, reg_base_value_size * sizeof (rtx)); + + /* Wipe the reg_seen array clean. */ + bzero ((char *) reg_seen, reg_base_value_size); + + /* Mark all hard registers which may contain an address. + The stack, frame and argument pointers may contain an address. + An argument register which can hold a Pmode value may contain + an address even if it is not in BASE_REGS. + + The address expression is VOIDmode for an argument and + Pmode for other registers. */ + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (TEST_HARD_REG_BIT (argument_registers, i)) + new_reg_base_value[i] = gen_rtx_ADDRESS (VOIDmode, + gen_rtx_REG (Pmode, i)); + + new_reg_base_value[STACK_POINTER_REGNUM] + = gen_rtx_ADDRESS (Pmode, stack_pointer_rtx); + new_reg_base_value[ARG_POINTER_REGNUM] + = gen_rtx_ADDRESS (Pmode, arg_pointer_rtx); + new_reg_base_value[FRAME_POINTER_REGNUM] + = gen_rtx_ADDRESS (Pmode, frame_pointer_rtx); +#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM + new_reg_base_value[HARD_FRAME_POINTER_REGNUM] + = gen_rtx_ADDRESS (Pmode, hard_frame_pointer_rtx); +#endif + if (struct_value_incoming_rtx + && GET_CODE (struct_value_incoming_rtx) == REG) + new_reg_base_value[REGNO (struct_value_incoming_rtx)] + = gen_rtx_ADDRESS (Pmode, struct_value_incoming_rtx); + + if (static_chain_rtx + && GET_CODE (static_chain_rtx) == REG) + new_reg_base_value[REGNO (static_chain_rtx)] + = gen_rtx_ADDRESS (Pmode, static_chain_rtx); + + /* Walk the insns adding values to the new_reg_base_value array. */ + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') + { + rtx note, set; + /* If this insn has a noalias note, process it, Otherwise, + scan for sets. A simple set will have no side effects + which could change the base value of any other register. */ + + if (GET_CODE (PATTERN (insn)) == SET + && (find_reg_note (insn, REG_NOALIAS, NULL_RTX))) + record_set (SET_DEST (PATTERN (insn)), NULL_RTX); + else + note_stores (PATTERN (insn), record_set); + + set = single_set (insn); + + if (set != 0 + && GET_CODE (SET_DEST (set)) == REG + && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER + && (((note = find_reg_note (insn, REG_EQUAL, 0)) != 0 + && REG_N_SETS (REGNO (SET_DEST (set))) == 1) + || (note = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != 0) + && GET_CODE (XEXP (note, 0)) != EXPR_LIST) + { + int regno = REGNO (SET_DEST (set)); + reg_known_value[regno] = XEXP (note, 0); + reg_known_equiv_p[regno] = REG_NOTE_KIND (note) == REG_EQUIV; + } + } + else if (GET_CODE (insn) == NOTE + && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG) + copying_arguments = 0; + } + + /* Now propagate values from new_reg_base_value to reg_base_value. */ + for (ui = 0; ui < reg_base_value_size; ui++) + { + if (new_reg_base_value[ui] + && new_reg_base_value[ui] != reg_base_value[ui] + && ! rtx_equal_p (new_reg_base_value[ui], reg_base_value[ui])) + { + reg_base_value[ui] = new_reg_base_value[ui]; + changed = 1; + } + } + } + while (changed && ++pass < MAX_ALIAS_LOOP_PASSES); + + /* Fill in the remaining entries. */ + for (i = FIRST_PSEUDO_REGISTER; i < maxreg; i++) + if (reg_known_value[i] == 0) + reg_known_value[i] = regno_reg_rtx[i]; + + /* Simplify the reg_base_value array so that no register refers to + another register, except to special registers indirectly through + ADDRESS expressions. + + In theory this loop can take as long as O(registers^2), but unless + there are very long dependency chains it will run in close to linear + time. + + This loop may not be needed any longer now that the main loop does + a better job at propagating alias information. */ + pass = 0; + do + { + changed = 0; + pass++; + for (ui = 0; ui < reg_base_value_size; ui++) + { + rtx base = reg_base_value[ui]; + if (base && GET_CODE (base) == REG) + { + unsigned int base_regno = REGNO (base); + if (base_regno == ui) /* register set from itself */ + reg_base_value[ui] = 0; + else + reg_base_value[ui] = reg_base_value[base_regno]; + changed = 1; + } + } + } + while (changed && pass < MAX_ALIAS_LOOP_PASSES); + + new_reg_base_value = 0; + reg_seen = 0; +} + +void +end_alias_analysis () +{ + reg_known_value = 0; + reg_base_value = 0; + reg_base_value_size = 0; + if (alias_invariant) + { + free ((char *)alias_invariant); + alias_invariant = 0; + } +} diff --git a/gcc_arm/assert.h b/gcc_arm/assert.h new file mode 100755 index 0000000..ecc02ee --- /dev/null +++ b/gcc_arm/assert.h @@ -0,0 +1,54 @@ +/* Allow this file to be included multiple times + with different settings of NDEBUG. */ +#undef assert +#undef __assert + +#ifdef NDEBUG +#define assert(ignore) ((void) 0) +#else + +#ifndef __GNUC__ + +#define assert(expression) \ + ((void) ((expression) ? 0 : __assert (expression, __FILE__, __LINE__))) + +#define __assert(expression, file, lineno) \ + (printf ("%s:%u: failed assertion\n", file, lineno), \ + abort (), 0) + +#else + +#if defined(__STDC__) || defined (__cplusplus) + +/* Defined in libgcc.a */ +#ifdef __cplusplus +extern "C" { +extern void __eprintf (const char *, const char *, unsigned, const char *) + __attribute__ ((noreturn)); +} +#else +extern void __eprintf (const char *, const char *, unsigned, const char *) + __attribute__ ((noreturn)); +#endif + +#define assert(expression) \ + ((void) ((expression) ? 0 : __assert (#expression, __FILE__, __LINE__))) + +#define __assert(expression, file, line) \ + (__eprintf ("%s:%u: failed assertion `%s'\n", \ + file, line, expression), 0) + +#else /* no __STDC__ and not C++; i.e. -traditional. */ + +extern void __eprintf () __attribute__ ((noreturn)); /* Defined in libgcc.a */ + +#define assert(expression) \ + ((void) ((expression) ? 0 : __assert (expression, __FILE__, __LINE__))) + +#define __assert(expression, file, lineno) \ + (__eprintf ("%s:%u: failed assertion `%s'\n", \ + file, lineno, "expression"), 0) + +#endif /* no __STDC__ and not C++; i.e. -traditional. */ +#endif /* no __GNU__; i.e., /bin/cc. */ +#endif diff --git a/gcc_arm/basic-block.h b/gcc_arm/basic-block.h new file mode 100755 index 0000000..11848d2 --- /dev/null +++ b/gcc_arm/basic-block.h @@ -0,0 +1,215 @@ +/* Define control and data flow tables, and regsets. + Copyright (C) 1987, 1997, 1998, 1999 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include "bitmap.h" +#include "sbitmap.h" + +typedef bitmap regset; /* Head of register set linked list. */ + +/* Clear a register set by freeing up the linked list. */ +#define CLEAR_REG_SET(HEAD) bitmap_clear (HEAD) + +/* Copy a register set to another register set. */ +#define COPY_REG_SET(TO, FROM) bitmap_copy (TO, FROM) + +/* `and' a register set with a second register set. */ +#define AND_REG_SET(TO, FROM) bitmap_operation (TO, TO, FROM, BITMAP_AND) + +/* `and' the complement of a register set with a register set. */ +#define AND_COMPL_REG_SET(TO, FROM) \ + bitmap_operation (TO, TO, FROM, BITMAP_AND_COMPL) + +/* Inclusive or a register set with a second register set. */ +#define IOR_REG_SET(TO, FROM) bitmap_operation (TO, TO, FROM, BITMAP_IOR) + +/* Or into TO the register set FROM1 `and'ed with the complement of FROM2. */ +#define IOR_AND_COMPL_REG_SET(TO, FROM1, FROM2) \ + bitmap_ior_and_compl (TO, FROM1, FROM2) + +/* Clear a single register in a register set. */ +#define CLEAR_REGNO_REG_SET(HEAD, REG) bitmap_clear_bit (HEAD, REG) + +/* Set a single register in a register set. */ +#define SET_REGNO_REG_SET(HEAD, REG) bitmap_set_bit (HEAD, REG) + +/* Return true if a register is set in a register set. */ +#define REGNO_REG_SET_P(TO, REG) bitmap_bit_p (TO, REG) + +/* Copy the hard registers in a register set to the hard register set. */ +#define REG_SET_TO_HARD_REG_SET(TO, FROM) \ +do { \ + int i_; \ + CLEAR_HARD_REG_SET (TO); \ + for (i_ = 0; i_ < FIRST_PSEUDO_REGISTER; i_++) \ + if (REGNO_REG_SET_P (FROM, i_)) \ + SET_HARD_REG_BIT (TO, i_); \ +} while (0) + +/* Loop over all registers in REGSET, starting with MIN, setting REGNUM to the + register number and executing CODE for all registers that are set. */ +#define EXECUTE_IF_SET_IN_REG_SET(REGSET, MIN, REGNUM, CODE) \ + EXECUTE_IF_SET_IN_BITMAP (REGSET, MIN, REGNUM, CODE) + +/* Loop over all registers in REGSET1 and REGSET2, starting with MIN, setting + REGNUM to the register number and executing CODE for all registers that are + set in the first regset and not set in the second. */ +#define EXECUTE_IF_AND_COMPL_IN_REG_SET(REGSET1, REGSET2, MIN, REGNUM, CODE) \ + EXECUTE_IF_AND_COMPL_IN_BITMAP (REGSET1, REGSET2, MIN, REGNUM, CODE) + +/* Loop over all registers in REGSET1 and REGSET2, starting with MIN, setting + REGNUM to the register number and executing CODE for all registers that are + set in both regsets. */ +#define EXECUTE_IF_AND_IN_REG_SET(REGSET1, REGSET2, MIN, REGNUM, CODE) \ + EXECUTE_IF_AND_IN_BITMAP (REGSET1, REGSET2, MIN, REGNUM, CODE) + +/* Allocate a register set with oballoc. */ +#define OBSTACK_ALLOC_REG_SET(OBSTACK) BITMAP_OBSTACK_ALLOC (OBSTACK) + +/* Allocate a register set with alloca. */ +#define ALLOCA_REG_SET() BITMAP_ALLOCA () + +/* Do any cleanup needed on a regset when it is no longer used. */ +#define FREE_REG_SET(REGSET) BITMAP_FREE(REGSET) + +/* Do any one-time initializations needed for regsets. */ +#define INIT_ONCE_REG_SET() BITMAP_INIT_ONCE () + +/* Grow any tables needed when the number of registers is calculated + or extended. For the linked list allocation, nothing needs to + be done, other than zero the statistics on the first allocation. */ +#define MAX_REGNO_REG_SET(NUM_REGS, NEW_P, RENUMBER_P) + +/* Number of basic blocks in the current function. */ + +extern int n_basic_blocks; + +/* Index by basic block number, get first insn in the block. */ + +extern rtx *x_basic_block_head; + +/* Index by basic block number, get last insn in the block. */ + +extern rtx *x_basic_block_end; + +/* Index by basic block number, determine whether the block can be reached + through a computed jump. */ + +extern char *basic_block_computed_jump_target; + +/* Index by basic block number, get address of regset + describing the registers live at the start of that block. */ + +extern regset *basic_block_live_at_start; + +/* What registers are live at the setjmp call. */ + +extern regset regs_live_at_setjmp; + +/* Indexed by n, gives number of basic block that (REG n) is used in. + If the value is REG_BLOCK_GLOBAL (-2), + it means (REG n) is used in more than one basic block. + REG_BLOCK_UNKNOWN (-1) means it hasn't been seen yet so we don't know. + This information remains valid for the rest of the compilation + of the current function; it is used to control register allocation. */ + +#define REG_BLOCK_UNKNOWN -1 +#define REG_BLOCK_GLOBAL -2 + +#define REG_BASIC_BLOCK(N) (VARRAY_REG (reg_n_info, N)->basic_block) + +/* List of integers. + These are used for storing things like predecessors, etc. + + This scheme isn't very space efficient, especially on 64 bit machines. + The interface is designed so that the implementation can be replaced with + something more efficient if desirable. */ + +typedef struct int_list { + struct int_list *next; + int val; +} int_list; + +typedef int_list *int_list_ptr; + +/* Integer list elements are allocated in blocks to reduce the frequency + of calls to malloc and to reduce the associated space overhead. */ + +typedef struct int_list_block { + struct int_list_block *next; + int nodes_left; +#define INT_LIST_NODES_IN_BLK 500 + struct int_list nodes[INT_LIST_NODES_IN_BLK]; +} int_list_block; + +/* Given a pointer to the list, return pointer to first element. */ +#define INT_LIST_FIRST(il) (il) + +/* Given a pointer to a list element, return pointer to next element. */ +#define INT_LIST_NEXT(p) ((p)->next) + +/* Return non-zero if P points to the end of the list. */ +#define INT_LIST_END(p) ((p) == NULL) + +/* Return element pointed to by P. */ +#define INT_LIST_VAL(p) ((p)->val) + +#define INT_LIST_SET_VAL(p, new_val) ((p)->val = (new_val)) + +extern void free_int_list PROTO ((int_list_block **)); + +/* Stuff for recording basic block info. */ + +#define BLOCK_HEAD(B) x_basic_block_head[(B)] +#define BLOCK_END(B) x_basic_block_end[(B)] + +/* Special block numbers [markers] for entry and exit. */ +#define ENTRY_BLOCK (-1) +#define EXIT_BLOCK (-2) + +/* from flow.c */ +extern void free_regset_vector PROTO ((regset *, int nelts)); +extern int *uid_block_number; +#define BLOCK_NUM(INSN) uid_block_number[INSN_UID (INSN)] + +extern void dump_bb_data PROTO ((FILE *, int_list_ptr *, int_list_ptr *, + int)); +extern void free_bb_mem PROTO ((void)); +extern void free_basic_block_vars PROTO ((int)); + +/* CYGNUS LOCAL edge_splitting/law */ +extern int compute_preds_succs PROTO ((int_list_ptr *, int_list_ptr *, + int *, int *, int)); +/* END CYGNUS LOCAL */ +extern void compute_dominators PROTO ((sbitmap *, sbitmap *, + int_list_ptr *, int_list_ptr *)); + +/* CYGNUS LOCAL lcm/law */ +/* In lcm.c */ +extern void pre_lcm PROTO ((int, int, int_list_ptr *, + int_list_ptr *, + sbitmap *, sbitmap *, + sbitmap *, sbitmap *)); +extern void pre_rev_lcm PROTO ((int, int, int_list_ptr *, + int_list_ptr *, + sbitmap *, sbitmap *, + sbitmap *, sbitmap *)); + +/* END CYGNUS LOCAL */ diff --git a/gcc_arm/bitmap.c b/gcc_arm/bitmap.c new file mode 100755 index 0000000..a5aa2e7 --- /dev/null +++ b/gcc_arm/bitmap.c @@ -0,0 +1,642 @@ +/* Functions to support general ended bitmaps. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "rtl.h" +#include "flags.h" +#include "obstack.h" +#include "regs.h" +#include "basic-block.h" + +/* Obstack to allocate bitmap elements from. */ +static struct obstack bitmap_obstack; +static int bitmap_obstack_init = FALSE; + + +#ifndef INLINE +#ifndef __GNUC__ +#define INLINE +#else +#define INLINE __inline__ +#endif +#endif + +/* Global data */ +bitmap_element bitmap_zero; /* An element of all zero bits. */ +bitmap_element *bitmap_free; /* Freelist of bitmap elements. */ + +static void bitmap_element_free PROTO((bitmap, bitmap_element *)); +static bitmap_element *bitmap_element_allocate PROTO((void)); +static int bitmap_element_zerop PROTO((bitmap_element *)); +static void bitmap_element_link PROTO((bitmap, bitmap_element *)); +static bitmap_element *bitmap_find_bit PROTO((bitmap, unsigned int)); + +/* Free a bitmap element */ + +static INLINE void +bitmap_element_free (head, elt) + bitmap head; + bitmap_element *elt; +{ + bitmap_element *next = elt->next; + bitmap_element *prev = elt->prev; + + if (prev) + prev->next = next; + + if (next) + next->prev = prev; + + if (head->first == elt) + head->first = next; + + /* Since the first thing we try is to insert before current, + make current the next entry in preference to the previous. */ + if (head->current == elt) + head->current = next != 0 ? next : prev; + + elt->next = bitmap_free; + bitmap_free = elt; +} + +/* Allocate a bitmap element. The bits are cleared, but nothing else is. */ + +static INLINE bitmap_element * +bitmap_element_allocate () +{ + bitmap_element *element; +#if BITMAP_ELEMENT_WORDS != 2 + int i; +#endif + + if (bitmap_free != 0) + { + element = bitmap_free; + bitmap_free = element->next; + } + else + { + /* We can't use gcc_obstack_init to initialize the obstack since + print-rtl.c now calls bitmap functions, and bitmap is linked + into the gen* functions. */ + if (!bitmap_obstack_init) + { + bitmap_obstack_init = TRUE; + + /* Let particular systems override the size of a chunk. */ +#ifndef OBSTACK_CHUNK_SIZE +#define OBSTACK_CHUNK_SIZE 0 +#endif + /* Let them override the alloc and free routines too. */ +#ifndef OBSTACK_CHUNK_ALLOC +#define OBSTACK_CHUNK_ALLOC xmalloc +#endif +#ifndef OBSTACK_CHUNK_FREE +#define OBSTACK_CHUNK_FREE free +#endif + +#if !defined(__GNUC__) || (__GNUC__ < 2) +#define __alignof__(type) 0 +#endif + + obstack_specify_allocation (&bitmap_obstack, OBSTACK_CHUNK_SIZE, + __alignof__ (bitmap_element), + (void *(*) ()) OBSTACK_CHUNK_ALLOC, + (void (*) ()) OBSTACK_CHUNK_FREE); + } + + element = (bitmap_element *) obstack_alloc (&bitmap_obstack, + sizeof (bitmap_element)); + } + +#if BITMAP_ELEMENT_WORDS == 2 + element->bits[0] = element->bits[1] = 0; +#else + for (i = 0; i < BITMAP_ELEMENT_WORDS; i++) + element->bits[i] = 0; +#endif + + return element; +} + +/* Return nonzero if all bits in an element are zero. */ + +static INLINE int +bitmap_element_zerop (element) + bitmap_element *element; +{ +#if BITMAP_ELEMENT_WORDS == 2 + return (element->bits[0] | element->bits[1]) == 0; +#else + int i; + + for (i = 0; i < BITMAP_ELEMENT_WORDS; i++) + if (element->bits[i] != 0) + return 0; + + return 1; +#endif +} + +/* Link the bitmap element into the current bitmap linked list. */ + +static INLINE void +bitmap_element_link (head, element) + bitmap head; + bitmap_element *element; +{ + unsigned int indx = element->indx; + bitmap_element *ptr; + + /* If this is the first and only element, set it in. */ + if (head->first == 0) + { + element->next = element->prev = 0; + head->first = element; + } + + /* If this index is less than that of the current element, it goes someplace + before the current element. */ + else if (indx < head->indx) + { + for (ptr = head->current; + ptr->prev != 0 && ptr->prev->indx > indx; + ptr = ptr->prev) + ; + + if (ptr->prev) + ptr->prev->next = element; + else + head->first = element; + + element->prev = ptr->prev; + element->next = ptr; + ptr->prev = element; + } + + /* Otherwise, it must go someplace after the current element. */ + else + { + for (ptr = head->current; + ptr->next != 0 && ptr->next->indx < indx; + ptr = ptr->next) + ; + + if (ptr->next) + ptr->next->prev = element; + + element->next = ptr->next; + element->prev = ptr; + ptr->next = element; + } + + /* Set up so this is the first element searched. */ + head->current = element; + head->indx = indx; +} + +/* Clear a bitmap by freeing the linked list. */ + +INLINE void +bitmap_clear (head) + bitmap head; +{ + bitmap_element *element, *next; + + for (element = head->first; element != 0; element = next) + { + next = element->next; + element->next = bitmap_free; + bitmap_free = element; + } + + head->first = head->current = 0; +} + +/* Copy a bitmap to another bitmap */ + +void +bitmap_copy (to, from) + bitmap to; + bitmap from; +{ + bitmap_element *from_ptr, *to_ptr = 0; +#if BITMAP_ELEMENT_WORDS != 2 + int i; +#endif + + bitmap_clear (to); + + /* Copy elements in forward direction one at a time */ + for (from_ptr = from->first; from_ptr; from_ptr = from_ptr->next) + { + bitmap_element *to_elt = bitmap_element_allocate (); + + to_elt->indx = from_ptr->indx; + +#if BITMAP_ELEMENT_WORDS == 2 + to_elt->bits[0] = from_ptr->bits[0]; + to_elt->bits[1] = from_ptr->bits[1]; +#else + for (i = 0; i < BITMAP_ELEMENT_WORDS; i++) + to_elt->bits[i] = from_ptr->bits[i]; +#endif + + /* Here we have a special case of bitmap_element_link, for the case + where we know the links are being entered in sequence. */ + if (to_ptr == 0) + { + to->first = to->current = to_elt; + to->indx = from_ptr->indx; + to_elt->next = to_elt->prev = 0; + } + else + { + to_elt->prev = to_ptr; + to_elt->next = 0; + to_ptr->next = to_elt; + } + + to_ptr = to_elt; + } +} + +/* Find a bitmap element that would hold a bitmap's bit. + Update the `current' field even if we can't find an element that + would hold the bitmap's bit to make eventual allocation + faster. */ + +static INLINE bitmap_element * +bitmap_find_bit (head, bit) + bitmap head; + unsigned int bit; +{ + bitmap_element *element; + unsigned HOST_WIDE_INT indx = bit / BITMAP_ELEMENT_ALL_BITS; + + if (head->current == 0) + return 0; + + if (head->indx > indx) + for (element = head->current; + element->prev != 0 && element->indx > indx; + element = element->prev) + ; + + else + for (element = head->current; + element->next != 0 && element->indx < indx; + element = element->next) + ; + + /* `element' is the nearest to the one we want. If it's not the one we + want, the one we want doesn't exist. */ + head->current = element; + head->indx = element->indx; + if (element != 0 && element->indx != indx) + element = 0; + + return element; +} + +/* Clear a single bit in a bitmap. */ + +void +bitmap_clear_bit (head, bit) + bitmap head; + int bit; +{ + bitmap_element *ptr = bitmap_find_bit (head, bit); + + if (ptr != 0) + { + unsigned bit_num = bit % (unsigned) HOST_BITS_PER_WIDE_INT; + unsigned word_num = ((bit / (unsigned) HOST_BITS_PER_WIDE_INT) + % BITMAP_ELEMENT_WORDS); + ptr->bits[word_num] &= ~ (((unsigned HOST_WIDE_INT) 1) << bit_num); + + /* If we cleared the entire word, free up the element */ + if (bitmap_element_zerop (ptr)) + bitmap_element_free (head, ptr); + } +} + + +/* Set a single bit in a bitmap. */ + +void +bitmap_set_bit (head, bit) + bitmap head; + int bit; +{ + bitmap_element *ptr = bitmap_find_bit (head, bit); + unsigned word_num + = ((bit / (unsigned) HOST_BITS_PER_WIDE_INT) % BITMAP_ELEMENT_WORDS); + unsigned bit_num = bit % (unsigned) HOST_BITS_PER_WIDE_INT; + unsigned HOST_WIDE_INT bit_val = ((unsigned HOST_WIDE_INT) 1) << bit_num; + + if (ptr == 0) + { + ptr = bitmap_element_allocate (); + ptr->indx = bit / BITMAP_ELEMENT_ALL_BITS; + ptr->bits[word_num] = bit_val; + bitmap_element_link (head, ptr); + } + else + ptr->bits[word_num] |= bit_val; +} + +/* Return whether a bit is set within a bitmap. */ + +int +bitmap_bit_p (head, bit) + bitmap head; + int bit; +{ + bitmap_element *ptr; + unsigned bit_num; + unsigned word_num; + + ptr = bitmap_find_bit (head, bit); + if (ptr == 0) + return 0; + + bit_num = bit % (unsigned) HOST_BITS_PER_WIDE_INT; + word_num + = ((bit / (unsigned) HOST_BITS_PER_WIDE_INT) % BITMAP_ELEMENT_WORDS); + + return + (ptr->bits[word_num] & (((unsigned HOST_WIDE_INT) 1) << bit_num)) != 0; +} + +/* Store in bitmap TO the result of combining bitmap FROM1 and + FROM2 using a specific bit manipulation. */ + +void +bitmap_operation (to, from1, from2, operation) + bitmap to; + bitmap from1; + bitmap from2; + enum bitmap_bits operation; +{ + bitmap_element *delete_list = 0; + bitmap_element *from1_ptr = from1->first; + bitmap_element *from2_ptr = from2->first; + unsigned int indx1 + = (from1_ptr) ? from1_ptr->indx : ~ (unsigned HOST_WIDE_INT) 0; + unsigned int indx2 + = (from2_ptr) ? from2_ptr->indx : ~ (unsigned HOST_WIDE_INT) 0; + bitmap_element *to_ptr = 0; + bitmap_element *from1_tmp; + bitmap_element *from2_tmp; + unsigned int indx; +#if BITMAP_ELEMENT_WORDS != 2 + int i; +#endif + + /* To simplify things, always create a new list. If the old list was one + of the inputs, free it later. Otherwise, free it now. */ + if (to == from1 || to == from2) + { + delete_list = to->first; + to->first = to->current = 0; + } + else + bitmap_clear (to); + + while (from1_ptr != 0 || from2_ptr != 0) + { + /* Figure out whether we need to substitute zero elements for + missing links. */ + if (indx1 == indx2) + { + indx = indx1; + from1_tmp = from1_ptr; + from2_tmp = from2_ptr; + from1_ptr = from1_ptr->next; + indx1 = (from1_ptr) ? from1_ptr->indx : ~ (unsigned HOST_WIDE_INT) 0; + from2_ptr = from2_ptr->next; + indx2 = (from2_ptr) ? from2_ptr->indx : ~ (unsigned HOST_WIDE_INT) 0; + } + else if (indx1 < indx2) + { + indx = indx1; + from1_tmp = from1_ptr; + from2_tmp = &bitmap_zero; + from1_ptr = from1_ptr->next; + indx1 = (from1_ptr) ? from1_ptr->indx : ~ (unsigned HOST_WIDE_INT) 0; + } + else + { + indx = indx2; + from1_tmp = &bitmap_zero; + from2_tmp = from2_ptr; + from2_ptr = from2_ptr->next; + indx2 = (from2_ptr) ? from2_ptr->indx : ~ (unsigned HOST_WIDE_INT) 0; + } + + if (to_ptr == 0) + to_ptr = bitmap_element_allocate (); + + /* Do the operation, and if any bits are set, link it into the + linked list. */ + switch (operation) + { + default: + abort (); + + case BITMAP_AND: +#if BITMAP_ELEMENT_WORDS == 2 + to_ptr->bits[0] = from1_tmp->bits[0] & from2_tmp->bits[0]; + to_ptr->bits[1] = from1_tmp->bits[1] & from2_tmp->bits[1]; +#else + for (i = BITMAP_ELEMENT_WORDS - 1; i >= 0; i--) + to_ptr->bits[i] = from1_tmp->bits[i] & from2_tmp->bits[i]; +#endif + break; + + case BITMAP_AND_COMPL: +#if BITMAP_ELEMENT_WORDS == 2 + to_ptr->bits[0] = from1_tmp->bits[0] & ~ from2_tmp->bits[0]; + to_ptr->bits[1] = from1_tmp->bits[1] & ~ from2_tmp->bits[1]; +#else + for (i = BITMAP_ELEMENT_WORDS - 1; i >= 0; i--) + to_ptr->bits[i] = from1_tmp->bits[i] & ~ from2_tmp->bits[i]; +#endif + break; + + case BITMAP_IOR: +#if BITMAP_ELEMENT_WORDS == 2 + to_ptr->bits[0] = from1_tmp->bits[0] | from2_tmp->bits[0]; + to_ptr->bits[1] = from1_tmp->bits[1] | from2_tmp->bits[1]; +#else + for (i = BITMAP_ELEMENT_WORDS - 1; i >= 0; i--) + to_ptr->bits[i] = from1_tmp->bits[i] | from2_tmp->bits[i]; +#endif + break; + } + + if (! bitmap_element_zerop (to_ptr)) + { + to_ptr->indx = indx; + bitmap_element_link (to, to_ptr); + to_ptr = 0; + } + } + + /* If we have an unallocated element due to the last element being 0, + release it back to the free pool. Don't bother calling + bitmap_element_free since it was never linked into a bitmap. */ + if (to_ptr != 0) + { + to_ptr->next = bitmap_free; + bitmap_free = to_ptr; + } + + /* If the output bitmap was one of the inputs, free up its + elements now that we're done. */ + for (; delete_list != 0; delete_list = to_ptr) + { + to_ptr = delete_list->next; + delete_list->next = bitmap_free; + bitmap_free = delete_list; + } +} + +/* Or into bitmap TO bitmap FROM1 and'ed with the complement of + bitmap FROM2. */ + +void +bitmap_ior_and_compl (to, from1, from2) + bitmap to; + bitmap from1; + bitmap from2; +{ + bitmap_head tmp; + + tmp.first = tmp.current = 0; + + bitmap_operation (&tmp, from1, from2, BITMAP_AND_COMPL); + bitmap_operation (to, to, &tmp, BITMAP_IOR); + bitmap_clear (&tmp); +} + +/* Initialize a bitmap header. */ + +bitmap +bitmap_initialize (head) + bitmap head; +{ + head->first = head->current = 0; + + return head; +} + +/* Debugging function to print out the contents of a bitmap. */ + +void +bitmap_debug_file (file, head) + FILE *file; + bitmap head; +{ + bitmap_element *ptr; + + fprintf (file, "\nfirst = "); + fprintf (file, HOST_PTR_PRINTF, head->first); + fprintf (file, " current = "); + fprintf (file, HOST_PTR_PRINTF, head->current); + fprintf (file, " indx = %u\n", head->indx); + + for (ptr = head->first; ptr; ptr = ptr->next) + { + int i, j, col = 26; + + fprintf (file, "\t"); + fprintf (file, HOST_PTR_PRINTF, ptr); + fprintf (file, " next = "); + fprintf (file, HOST_PTR_PRINTF, ptr->next); + fprintf (file, " prev = "); + fprintf (file, HOST_PTR_PRINTF, ptr->prev); + fprintf (file, " indx = %u\n\t\tbits = {", ptr->indx); + + for (i = 0; i < BITMAP_ELEMENT_WORDS; i++) + for (j = 0; j < HOST_BITS_PER_WIDE_INT; j++) + if ((ptr->bits[i] & (((unsigned HOST_WIDE_INT) 1) << j)) != 0) + { + if (col > 70) + { + fprintf (file, "\n\t\t\t"); + col = 24; + } + + fprintf (file, " %u", (ptr->indx * BITMAP_ELEMENT_ALL_BITS + + i * HOST_BITS_PER_WIDE_INT + j)); + col += 4; + } + + fprintf (file, " }\n"); + } +} + +/* Function to be called from the debugger to print the contents + of a bitmap. */ + +void +debug_bitmap (head) + bitmap head; +{ + bitmap_debug_file (stdout, head); +} + +/* Function to print out the contents of a bitmap. Unlike bitmap_debug_file, + it does not print anything but the bits. */ + +void +bitmap_print (file, head, prefix, suffix) + FILE *file; + bitmap head; + char *prefix; + char *suffix; +{ + char *comma = ""; + int i; + + fputs (prefix, file); + EXECUTE_IF_SET_IN_BITMAP (head, 0, i, + { + fprintf (file, "%s%d", comma, i); + comma = ", "; + }); + fputs (suffix, file); +} + +/* Release any memory allocated by bitmaps. */ + +void +bitmap_release_memory () +{ + bitmap_free = 0; + if (bitmap_obstack_init) + { + bitmap_obstack_init = FALSE; + obstack_free (&bitmap_obstack, NULL_PTR); + } +} diff --git a/gcc_arm/bitmap.h b/gcc_arm/bitmap.h new file mode 100755 index 0000000..6f3dfa6 --- /dev/null +++ b/gcc_arm/bitmap.h @@ -0,0 +1,317 @@ +/* Functions to support general ended bitmaps. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Number of words to use for each element in the linked list. */ + +#ifndef BITMAP_ELEMENT_WORDS +#define BITMAP_ELEMENT_WORDS 2 +#endif + +/* Number of bits in each actual element of a bitmap. We get slightly better + code for bit % BITMAP_ELEMENT_ALL_BITS and bit / BITMAP_ELEMENT_ALL_BITS if + bits is unsigned, assuming it is a power of 2. */ + +#define BITMAP_ELEMENT_ALL_BITS \ + ((unsigned) (BITMAP_ELEMENT_WORDS * HOST_BITS_PER_WIDE_INT)) + +/* Bitmap set element. We use a linked list to hold only the bits that + are set. This allows for use to grow the bitset dynamically without + having to realloc and copy a giant bit array. The `prev' field is + undefined for an element on the free list. */ + +typedef struct bitmap_element_def +{ + struct bitmap_element_def *next; /* Next element. */ + struct bitmap_element_def *prev; /* Previous element. */ + unsigned int indx; /* regno/BITMAP_ELEMENT_ALL_BITS. */ + unsigned HOST_WIDE_INT bits[BITMAP_ELEMENT_WORDS]; /* Bits that are set. */ +} bitmap_element; + +/* Head of bitmap linked list. */ +typedef struct bitmap_head_def { + bitmap_element *first; /* First element in linked list. */ + bitmap_element *current; /* Last element looked at. */ + int indx; /* Index of last element looked at. */ +} bitmap_head, *bitmap; + +/* Enumeration giving the various operations we support. */ +enum bitmap_bits { + BITMAP_AND, /* TO = FROM1 & FROM2 */ + BITMAP_AND_COMPL, /* TO = FROM1 & ~ FROM2 */ + BITMAP_IOR /* TO = FROM1 | FROM2 */ +}; + +/* Global data */ +extern bitmap_element *bitmap_free; /* Freelist of bitmap elements */ +extern bitmap_element bitmap_zero; /* Zero bitmap element */ + +/* Clear a bitmap by freeing up the linked list. */ +extern void bitmap_clear PROTO((bitmap)); + +/* Copy a bitmap to another bitmap. */ +extern void bitmap_copy PROTO((bitmap, bitmap)); + +/* Perform an operation on two bitmaps, yielding a third. */ +extern void bitmap_operation PROTO((bitmap, bitmap, bitmap, enum bitmap_bits)); + +/* `or' into one bitmap the `and' of a second bitmap witih the complement + of a third. */ +extern void bitmap_ior_and_compl PROTO((bitmap, bitmap, bitmap)); + +/* Clear a single register in a register set. */ +extern void bitmap_clear_bit PROTO((bitmap, int)); + +/* Set a single register in a register set. */ +extern void bitmap_set_bit PROTO((bitmap, int)); + +/* Return true if a register is set in a register set. */ +extern int bitmap_bit_p PROTO((bitmap, int)); + +/* Debug functions to print a bitmap linked list. */ +extern void bitmap_debug PROTO((bitmap)); +extern void bitmap_debug_file PROTO((FILE *, bitmap)); + +/* Print a bitmap */ +extern void bitmap_print PROTO((FILE *, bitmap, char *, char *)); + +/* Initialize a bitmap header. */ +extern bitmap bitmap_initialize PROTO((bitmap)); + +/* Release all memory held by bitmaps. */ +extern void bitmap_release_memory PROTO((void)); + +extern void debug_bitmap PROTO((bitmap)); + +/* Allocate a bitmap with oballoc. */ +#define BITMAP_OBSTACK_ALLOC(OBSTACK) \ + bitmap_initialize ((bitmap) obstack_alloc (OBSTACK, sizeof (bitmap_head))) + +/* Allocate a bitmap with alloca. */ +#define BITMAP_ALLOCA() \ + bitmap_initialize ((bitmap) alloca (sizeof (bitmap_head))) + +/* Do any cleanup needed on a bitmap when it is no longer used. */ +#define BITMAP_FREE(BITMAP) \ +do { \ + if (BITMAP) \ + { \ + bitmap_clear (BITMAP); \ + (BITMAP) = 0; \ + } \ +} while (0) + +/* Do any one-time initializations needed for bitmaps. */ +#define BITMAP_INIT_ONCE() + +/* Loop over all bits in BITMAP, starting with MIN, setting BITNUM to the + bit number and executing CODE for all bits that are set. */ + +#define EXECUTE_IF_SET_IN_BITMAP(BITMAP, MIN, BITNUM, CODE) \ +do { \ + bitmap_element *ptr_ = (BITMAP)->first; \ + unsigned int indx_ = (MIN) / BITMAP_ELEMENT_ALL_BITS; \ + unsigned bit_num_ = (MIN) % ((unsigned) HOST_BITS_PER_WIDE_INT); \ + unsigned word_num_ = (((MIN) / ((unsigned) HOST_BITS_PER_WIDE_INT)) \ + % BITMAP_ELEMENT_WORDS); \ + \ + \ + /* Find the block the minimum bit is in. */ \ + while (ptr_ != 0 && ptr_->indx < indx_) \ + ptr_ = ptr_->next; \ + \ + if (ptr_ != 0 && ptr_->indx != indx_) \ + { \ + bit_num_ = 0; \ + word_num_ = 0; \ + } \ + \ + for (; ptr_ != 0; ptr_ = ptr_->next) \ + { \ + for (; word_num_ < BITMAP_ELEMENT_WORDS; word_num_++) \ + { \ + unsigned HOST_WIDE_INT word_ = ptr_->bits[word_num_]; \ + \ + if (word_ != 0) \ + { \ + for (; bit_num_ < HOST_BITS_PER_WIDE_INT; bit_num_++) \ + { \ + unsigned HOST_WIDE_INT mask_ \ + = ((unsigned HOST_WIDE_INT) 1) << bit_num_; \ + \ + if ((word_ & mask_) != 0) \ + { \ + word_ &= ~ mask_; \ + (BITNUM) = (ptr_->indx * BITMAP_ELEMENT_ALL_BITS \ + + word_num_ * HOST_BITS_PER_WIDE_INT \ + + bit_num_); \ + CODE; \ + \ + if (word_ == 0) \ + break; \ + } \ + } \ + } \ + \ + bit_num_ = 0; \ + } \ + \ + word_num_ = 0; \ + } \ +} while (0) + +/* Loop over all bits in BITMAP1 and BITMAP2, starting with MIN, setting + BITNUM to the bit number and executing CODE for all bits that are set in + the first bitmap and not set in the second. */ + +#define EXECUTE_IF_AND_COMPL_IN_BITMAP(BITMAP1, BITMAP2, MIN, BITNUM, CODE) \ +do { \ + bitmap_element *ptr1_ = (BITMAP1)->first; \ + bitmap_element *ptr2_ = (BITMAP2)->first; \ + unsigned int indx_ = (MIN) / BITMAP_ELEMENT_ALL_BITS; \ + unsigned bit_num_ = (MIN) % ((unsigned) HOST_BITS_PER_WIDE_INT); \ + unsigned word_num_ = (((MIN) / ((unsigned) HOST_BITS_PER_WIDE_INT)) \ + % BITMAP_ELEMENT_WORDS); \ + \ + /* Find the block the minimum bit is in in the first bitmap. */ \ + while (ptr1_ != 0 && ptr1_->indx < indx_) \ + ptr1_ = ptr1_->next; \ + \ + if (ptr1_ != 0 && ptr1_->indx != indx_) \ + { \ + bit_num_ = 0; \ + word_num_ = 0; \ + } \ + \ + for (; ptr1_ != 0 ; ptr1_ = ptr1_->next) \ + { \ + /* Advance BITMAP2 to the equivalent link, using an all \ + zero element if an equivalent link doesn't exist. */ \ + bitmap_element *tmp2_; \ + \ + while (ptr2_ != 0 && ptr2_->indx < ptr1_->indx) \ + ptr2_ = ptr2_->next; \ + \ + tmp2_ = ((ptr2_ != 0 && ptr2_->indx == ptr1_->indx) \ + ? ptr2_ : &bitmap_zero); \ + \ + for (; word_num_ < BITMAP_ELEMENT_WORDS; word_num_++) \ + { \ + unsigned HOST_WIDE_INT word_ = (ptr1_->bits[word_num_] \ + & ~ tmp2_->bits[word_num_]); \ + if (word_ != 0) \ + { \ + for (; bit_num_ < HOST_BITS_PER_WIDE_INT; bit_num_++) \ + { \ + unsigned HOST_WIDE_INT mask_ \ + = ((unsigned HOST_WIDE_INT)1) << bit_num_; \ + \ + if ((word_ & mask_) != 0) \ + { \ + word_ &= ~ mask_; \ + (BITNUM) = (ptr1_->indx * BITMAP_ELEMENT_ALL_BITS \ + + word_num_ * HOST_BITS_PER_WIDE_INT \ + + bit_num_); \ + \ + CODE; \ + if (word_ == 0) \ + break; \ + } \ + } \ + } \ + \ + bit_num_ = 0; \ + } \ + \ + word_num_ = 0; \ + } \ +} while (0) + +/* Loop over all bits in BITMAP1 and BITMAP2, starting with MIN, setting + BITNUM to the bit number and executing CODE for all bits that are set in + the both bitmaps. */ + +#define EXECUTE_IF_AND_IN_BITMAP(BITMAP1, BITMAP2, MIN, BITNUM, CODE) \ +do { \ + bitmap_element *ptr1_ = (BITMAP1)->first; \ + bitmap_element *ptr2_ = (BITMAP2)->first; \ + unsigned int indx_ = (MIN) / BITMAP_ELEMENT_ALL_BITS; \ + unsigned bit_num_ = (MIN) % ((unsigned) HOST_BITS_PER_WIDE_INT); \ + unsigned word_num_ = (((MIN) / ((unsigned) HOST_BITS_PER_WIDE_INT)) \ + % BITMAP_ELEMENT_WORDS); \ + \ + /* Find the block the minimum bit is in in the first bitmap. */ \ + while (ptr1_ != 0 && ptr1_->indx < indx_) \ + ptr1_ = ptr1_->next; \ + \ + if (ptr1_ != 0 && ptr1_->indx != indx_) \ + { \ + bit_num_ = 0; \ + word_num_ = 0; \ + } \ + \ + for (; ptr1_ != 0 ; ptr1_ = ptr1_->next) \ + { \ + /* Advance BITMAP2 to the equivalent link */ \ + while (ptr2_ != 0 && ptr2_->indx < ptr1_->indx) \ + ptr2_ = ptr2_->next; \ + \ + if (ptr2_ == 0) \ + { \ + /* If there are no more elements in BITMAP2, exit loop now.*/ \ + ptr1_ = (bitmap_element *)0; \ + break; \ + } \ + else if (ptr2_->indx > ptr1_->indx) \ + { \ + bit_num_ = word_num_ = 0; \ + continue; \ + } \ + \ + for (; word_num_ < BITMAP_ELEMENT_WORDS; word_num_++) \ + { \ + unsigned HOST_WIDE_INT word_ = (ptr1_->bits[word_num_] \ + & ptr2_->bits[word_num_]); \ + if (word_ != 0) \ + { \ + for (; bit_num_ < HOST_BITS_PER_WIDE_INT; bit_num_++) \ + { \ + unsigned HOST_WIDE_INT mask_ \ + = ((unsigned HOST_WIDE_INT)1) << bit_num_; \ + \ + if ((word_ & mask_) != 0) \ + { \ + word_ &= ~ mask_; \ + (BITNUM) = (ptr1_->indx * BITMAP_ELEMENT_ALL_BITS \ + + word_num_ * HOST_BITS_PER_WIDE_INT \ + + bit_num_); \ + \ + CODE; \ + if (word_ == 0) \ + break; \ + } \ + } \ + } \ + \ + bit_num_ = 0; \ + } \ + \ + word_num_ = 0; \ + } \ +} while (0) diff --git a/gcc_arm/build-make b/gcc_arm/build-make new file mode 100755 index 0000000..f9049ae --- /dev/null +++ b/gcc_arm/build-make @@ -0,0 +1,35 @@ +# We have to use the cross-compiler we just built to compile it. +CC = gcc -b $(host) + +# Need those to compile binaries running on host machine. +# It is configured by +# +# configure --host=target_cpu-target_os \ +# --target=host=target_cpu-target_os --build=host_cpu-host_os +# +# That HOST stuff has to be taken care of very carefully. +HOST_PREFIX=l- +HOST_PREFIX_1=$(HOST_PREFIX) +HOST_CC=$(CC) -b $(build) +HOST_CFLAGS=$(INTERNAL_CFLAGS) $(T_CFLAGS) $(CFLAGS) $(XCFLAGS) +HOST_CLIB= +HOST_LDFLAGS=$(LDFLAGS) +HOST_CPPFLAGS=$(ALL_CPPFLAGS) +HOST_ALLOCA=$(ALLOCA) +HOST_MALLOC=$(MALLOC) +HOST_OBSTACK=$(OBSTACK) + +# To build the native compiler with the cross compiler, the headers +# for the target are already fixed. And /usr/include is for host, not +# target. +FIXINCLUDES=Makefile.in + +# Don't run fixproto either +STMP_FIXPROTO = + +# Cause installation using install-build. We do nothing here. +#INSTALL_TARGET = install-build + +# Don't try to compile the things we can't compile or we have made +# while making gcc with the cross-compiler. +#ALL = all.build diff --git a/gcc_arm/bytecode.def b/gcc_arm/bytecode.def new file mode 100755 index 0000000..5b24df7 --- /dev/null +++ b/gcc_arm/bytecode.def @@ -0,0 +1,322 @@ +# -*- C -*- +# bytecode.def - definitions of bytecodes for the stack machine. + +# The production of the bytecode interpreter and compiler is +# heavily automated by using this file creatively. + +# Various elementary data types are understood by the bytecode interpreter. +# Q[IU] - quarter word (byte) signed and unsigned integers (char). +# H[IU] - half word signed and unsigned integers (short int, maybe int). +# S[IU] - single word signed and unsigned integers (maybe int, long int). +# D[IU] - double word signed and unsigned integers (long long int). +# SF - single precision floating point (float). +# DF - double precision floating point (double). +# XF - extended precision floating point (long double). +# P - pointer type for address arithmetic and other purposes. + +# The bytecode specification consists of a series of define_operator +# forms, that are parsed by preprocessors to automatically build +# various switch statements. +# define_operator(name, +# , +# ) +# The is self explanatory. +# The consists of a (parenthesized list) of +# variation items, each of which is in itself a list. A variation +# item consists of a name suffix, the types of the input arguments +# expected on the stack (shallowest item first) and (optionally) the +# types of the output arguments (similarly ordered). Finally, the +# types of the literal arguments (if any) may appear. + +# Substitution in the C prototype code is as follows: +# Substitution happens only after a dollar sign. To get a literal +# dollar sign (why would you ever want one anyway?) use $$. +# $R1 means "result 1" $TR1 means "type name of result one" +# $S1 means "source 1" and similarly with $TS1. +# $L1 means "literal (inline) argument 1" and $TL1 means type thereof. +# + +# Notice that the number following $R doesn't affect the push order; +# it's used only for clarity and orthogonality, although it's checked +# to make sure it doesn't exceed the number of outputs. A $R reference +# results in a push, and represents the result lvalue. E.g. + +# $R1 = 2\, $R2 = 17 +# will expand to: +# INTERP_PUSH($TR1) = 2, INTERP_PUSH($TR2) = 17 +# + +# Opcode 0 should never happen. +define_operator(neverneverland, abort\(\), (())) + +# Stack manipulations. +define_operator(drop, 0, ((, (SI)))) +define_operator(duplicate, 0, ((, (SI), (SI, SI)))) +define_operator(over, 0, ((, (SI), (SI, SI)))) + +# Adjust stack pointer + +define_operator(setstack, 0, ((SI,,,(SI)))) +define_operator(adjstack, 0, ((SI,,,(SI)))) + +# Constants, loads, and stores. +define_operator(const, + $R1 = $L1, + ((QI,, (QI), (QI)), (HI,, (HI), (HI)), + (SI,, (SI), (SI)), (DI,, (DI), (DI)), + (SF,, (SF), (SF)), (DF,, (DF), (DF)), + (XF,, (XF), (XF)), (P,, (P), (P)))) +define_operator(load, + $R1 = *\($TR1 *\) $S1, + ((QI, (P), (QI)), (HI, (P), (HI)), + (SI, (P), (SI)), (DI, (P), (DI)), + (SF, (P), (SF)), (DF, (P), (DF)), + (XF, (P), (XF)), (P, (P), (P)))) +define_operator(store, + *\($TS2 *\) $S1 = $S2, + ((QI, (P, QI)), (HI, (P, HI)), + (SI, (P, SI)), (DI, (P, DI)), + (SF, (P, SF)), (DF, (P, DF)), + (XF, (P, XF)), (P, (P, P)), + (BLK, (SI, BLK, BLK)))) + +# Clear memory block + +define_operator(clear, $S1 + $S2, ((BLK, (SI, BLK)))) + + +# Advance pointer by SI constant + +define_operator(addconst, $R1 = $S1, ((PSI, (P), (P), (SI)))) + + +# newlocalSI is used for creating variable-sized storage during function +# initialization. + +# Create local space, return pointer to block + +define_operator(newlocal, $R1 = $S1, ((SI, (SI), (P)))) + + +# Push the address of a local variable. +define_operator(local, $R1 = locals + $L1, ((P,, (P), (SI)))) + +# Push the address of an argument variable. +define_operator(arg, $R1 = args + $L1, ((P,, (P), (SI)))) + +# Arithmetic conversions. +define_operator(convert, + $R1 = \($TR1\) $S1, + (# Signed integral promotions (sign extensions). + (QIHI, (QI), (HI)), (HISI, (HI), (SI)), (SIDI, (SI), (DI)), + (QISI, (QI), (SI)), + # Unsigned integral promotions (zero extensions). + (QUHU, (QU), (HU)), (HUSU, (HU), (SU)), (SUDU, (SU), (DU)), + (QUSU, (QU), (SU)), + # Floating promotions. + (SFDF, (SF), (DF)), (DFXF, (DF), (XF)), + # Integral truncation. + (HIQI, (HI), (QI)), (SIHI, (SI), (HI)), (DISI, (DI), (SI)), + (SIQI, (SI), (QI)), + # Unsigned truncation. + (SUQU, (SU), (QU)), + # Floating truncation. + (DFSF, (DF), (SF)), (XFDF, (XF), (DF)), + # Integral conversions to floating types. + (SISF, (SI), (SF)), (SIDF, (SI), (DF)), (SIXF, (SI), (XF)), + (SUSF, (SU), (SF)), (SUDF, (SU), (DF)), (SUXF, (SU), (XF)), + (DISF, (DI), (SF)), (DIDF, (DI), (DF)), (DIXF, (DI), (XF)), + (DUSF, (DU), (SF)), (DUDF, (DU), (DF)), (DUXF, (DU), (XF)), + # Floating conversions to integral types. + (SFSI, (SF), (SI)), (DFSI, (DF), (SI)), (XFSI, (XF), (SI)), + (SFSU, (SF), (SU)), (DFSU, (DF), (SU)), (XFSU, (XF), (SU)), + (SFDI, (SF), (DI)), (DFDI, (DF), (DI)), (XFDI, (XF), (DI)), + (SFDU, (SF), (DU)), (DFDU, (DF), (DU)), (XFDU, (XF), (DU)), + # Pointer/integer conversions. + (PSI, (P), (SI)), (SIP, (SI), (P)))) + +# Truth value conversion. These are necessary because conversions of, e.g., +# floating types to integers may not function correctly for large values. +define_operator(convert, + $R1 = !!$S1, + ((SIT, (SI), (T)), (DIT, (DI), (T)), + (SFT, (SF), (T)), (DFT, (DF), (T)), + (XFT, (XF), (T)), (PT, (P), (T)))) + +# Bit field load/store. + +# Load and zero-extend bitfield + +define_operator(zxload, $R1 = $S1, ((BI, (SU, SU, P), (SU)))) + +# Load and sign-extend bitfield + +define_operator(sxload, $R1 = $S1, ((BI, (SU, SU, P), (SI)))) + +# Store integer in bitfield + +define_operator(sstore, $R1 = $S1, ((BI, (SU, SU, P, SI)))) + + +# Binary operations. +define_operator(add, + $R1 = $S1 + $S2, + ((SI, (SI, SI), (SI)), (DI, (DI, DI), (DI)), + (SF, (SF, SF), (SF)), (DF, (DF, DF), (DF)), + (XF, (XF, XF), (XF)), + (PSI, (P, SI), (P)))) +define_operator(sub, + $R1 = $S1 - $S2, + ((SI, (SI, SI), (SI)), (DI, (DI, DI), (DI)), + (SF, (SF, SF), (SF)), (DF, (DF, DF), (DF)), + (XF, (XF, XF), (XF)), + (PP, (P, P), (SI)))) +define_operator(mul, + $R1 = $S1 * $S2, + ((SI, (SI, SI), (SI)), (DI, (DI, DI), (DI)), + (SU, (SU, SU), (SU)), (DU, (DU, DU), (DU)), + (SF, (SF, SF), (SF)), (DF, (DF, DF), (DF)), + (XF, (XF, XF), (XF)))) +define_operator(div, + $R1 = $S1 / $S2, + ((SI, (SI, SI), (SI)), (DI, (DI, DI), (DI)), + (SU, (SU, SU), (SU)), (DU, (DU, DU), (DU)), + (SF, (SF, SF), (SF)), (DF, (DF, DF), (DF)), + (XF, (XF, XF), (XF)))) +define_operator(mod, + $R1 = $S1 % $S2, + ((SI, (SI, SI), (SI)), (DI, (DI, DI), (DI)), + (SU, (SU, SU), (SU)), (DU, (DU, DU), (DU)))) +define_operator(and, + $R1 = $S1 & $S2, + ((SI, (SI, SI), (SI)), (DI, (DI, DI), (DI)))) +define_operator(ior, + $R1 = $S1 | $S2, + ((SI, (SI, SI), (SI)), (DI, (DI, DI), (DI)))) +define_operator(xor, + $R1 = $S1 ^ $S2, + ((SI, (SI, SI), (SI)), (DI, (DI, DI), (DI)))) +define_operator(lshift, + $R1 = $S1 << $S2, + ((SI, (SI, SI), (SI)), (SU, (SU, SI), (SU)), + (DI, (DI, SI), (DI)), (DU, (DU, SI), (DU)))) +define_operator(rshift, + $R1 = $S1 >> $S2, + ((SI, (SI, SI), (SI)), (SU, (SU, SI), (SU)), + (DI, (DI, SI), (DI)), (DU, (DU, SI), (DU)))) +define_operator(lt, + $R1 = $S1 < $S2, + ((SI, (SI, SI), (T)), (SU, (SU, SU), (T)), + (DI, (DI, DI), (T)), (DU, (DU, DU), (T)), + (SF, (SF, SF), (T)), (DF, (DF, DF), (T)), + (XF, (XF, XF), (T)), (P, (P, P), (T)))) +define_operator(le, + $R1 = $S1 <= $S2, + ((SI, (SI, SI), (T)), (SU, (SU, SU), (T)), + (DI, (DI, DI), (T)), (DU, (DU, DU), (T)), + (SF, (SF, SF), (T)), (DF, (DF, DF), (T)), + (XF, (XF, XF), (T)), (P, (P, P), (T)))) +define_operator(ge, + $R1 = $S1 >= $S2, + ((SI, (SI, SI), (T)), (SU, (SU, SU), (T)), + (DI, (DI, DI), (T)), (DU, (DU, DU), (T)), + (SF, (SF, SF), (T)), (DF, (DF, DF), (T)), + (XF, (XF, XF), (T)), (P, (P, P), (T)))) +define_operator(gt, + $R1 = $S1 > $S2, + ((SI, (SI, SI), (T)), (SU, (SU, SU), (T)), + (DI, (DI, DI), (T)), (DU, (DU, DU), (T)), + (SF, (SF, SF), (T)), (DF, (DF, DF), (T)), + (XF, (XF, XF), (T)), (P, (P, P), (T)))) +define_operator(eq, + $R1 = $S1 == $S2, + ((SI, (SI, SI), (T)), (DI, (DI, DI), (T)), + (SF, (SF, SF), (T)), (DF, (DF, DF), (T)), + (XF, (XF, XF), (T)), (P, (P, P), (T)))) +define_operator(ne, + $R1 = $S1 != $S2, + ((SI, (SI, SI), (T)), (DI, (DI, DI), (T)), + (SF, (SF, SF), (T)), (DF, (DF, DF), (T)), + (XF, (XF, XF), (T)), (P, (P, P), (T)))) + +# Unary operations. +define_operator(neg, + $R1 = -$S1, + ((SI, (SI), (SI)), (DI, (DI), (DI)), + (SF, (SF), (SF)), (DF, (DF), (DF)), + (XF, (XF), (XF)))) +define_operator(not, + $R1 = ~$S1, + ((SI, (SI), (SI)), (DI, (DI), (DI)))) +define_operator(not, + $R1 = !$S1, + ((T, (SI), (SI)))) + +# Increment operations. +define_operator(predec, + $R1 = *\($TR1 *\) $S1 -= $S2, + ((QI, (P, QI), (QI)), (HI, (P, HI), (HI)), + (SI, (P, SI), (SI)), (DI, (P, DI), (DI)), + (P, (P, SI), (P)), (SF, (P, SF), (SF)), + (DF, (P, DF), (DF)), (XF, (P, XF), (XF)), + (BI, (SU, SU, P, SI), (SI)))) + +define_operator(preinc, + $R1 = *\($TR1 *\) $S1 += $S2, + ((QI, (P, QI), (QI)), (HI, (P, HI), (HI)), + (SI, (P, SI), (SI)), (DI, (P, DI), (DI)), + (P, (P, SI), (P)), (SF, (P, SF), (SF)), + (DF, (P, DF), (DF)), (XF, (P, XF), (XF)), + (BI, (SU, SU, P, SI), (SI)))) + +define_operator(postdec, + $R1 = *\($TR1 *\) $S1\, *\($TR1 *\) $S1 -= $S2, + ((QI, (P, QI), (QI)), (HI, (P, HI), (HI)), + (SI, (P, SI), (SI)), (DI, (P, DI), (DI)), + (P, (P, SI), (P)), (SF, (P, SF), (SF)), + (DF, (P, DF), (DF)), (XF, (P, XF), (XF)), + (BI, (SU, SU, P, SI), (SI)))) + +define_operator(postinc, + $R1 = *\($TR1 *\) $S1\, *\($TR1 *\) $S1 += $S2, + ((QI, (P, QI), (QI)), (HI, (P, HI), (HI)), + (SI, (P, SI), (SI)), (DI, (P, DI), (DI)), + (P, (P, SI), (P)), (SF, (P, SF), (SF)), + (DF, (P, DF), (DF)), (XF, (P, XF), (XF)), + (BI, (SU, SU, P, SI), (SI)))) + +# Jumps. +define_operator(xjumpif, if \($S1\) pc = code->pc0 + $L1, ((, (T),, (SI)))) +define_operator(xjumpifnot, if \(! $S1\) pc = code->pc0 + $L1, ((, (T),, (SI)))) +define_operator(jump, pc = code->pc0 + $L1, ((,,,(SI)))) + +# This is for GCC2. It jumps to the address on the stack. +define_operator(jump, pc = \(void *\) $S1, ((P,,))) + +# Switches. In order to (eventually) support ranges we provide four different +# varieties of switches. Arguments are the switch index from the stack, the +# bytecode offset of the switch table, the size of the switch table, and +# the default label. +define_operator(caseSI, CASESI\($S1\, $L1\, $L2\, $L3\), ((, (SI),, (SI, SI, SI)))) +define_operator(caseSU, CASESU\($S1\, $L1\, $L2\, $L3\), ((, (SU),, (SI, SI, SI)))) +define_operator(caseDI, CASEDI\($S1\, $L1\, $L2\, $L3\), ((, (DI),, (SI, SI, SI)))) +define_operator(caseDU, CASEDU\($S1\, $L1\, $L2\, $L3\), ((, (DU),, (SI, SI, SI)))) + +# Procedure call. +# Stack arguments are (deepest first): +# procedure arguments in reverse order. +# pointer to the place to hold the return value. +# address of the call description vector. +# pointer to the procedure to be called. +define_operator(call, CALL\($S1\, $S2\, $S3\, sp\), ((, (P, P, P)))) + +# Procedure return. +# Pushes on interpreter stack: +# value of retptr (pointer to return value storage slot) +define_operator(return, $R1 = retptr, ((P,,(P)))) + +# Really return. +define_operator(ret, return, (())) + +# Print an obnoxious line number. +define_operator(linenote, fprintf\(stderr\, "%d\\n"\, $L1\), ((,,,(SI)))) diff --git a/gcc_arm/bytecode.h b/gcc_arm/bytecode.h new file mode 100755 index 0000000..a029f93 --- /dev/null +++ b/gcc_arm/bytecode.h @@ -0,0 +1,82 @@ +/* Bytecode definitions for GNU C-compiler. + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +extern int output_bytecode; +extern int stack_depth; +extern int max_stack_depth; + +/* Emit DI constant according to target machine word ordering */ + +#define bc_emit_bytecode_DI_const(CST) \ +{ int opcode; \ + opcode = (WORDS_BIG_ENDIAN \ + ? TREE_INT_CST_HIGH (CST) \ + : TREE_INT_CST_LOW (CST)); \ + bc_emit_bytecode_const ((char *) &opcode, sizeof opcode); \ + opcode = (WORDS_BIG_ENDIAN \ + ? TREE_INT_CST_LOW (CST) \ + : TREE_INT_CST_HIGH (CST)); \ + bc_emit_bytecode_const ((char *) &opcode, sizeof opcode); \ +} + +extern void bc_expand_expr (); +extern void bc_output_data_constructor (); +extern void bc_store_field (); +extern void bc_load_bit_field (); +extern void bc_store_bit_field (); +extern void bc_push_offset_and_size (); +extern void bc_init_mode_to_code_map (); + +/* These are just stubs, so the compiler will compile for targets + that aren't yet supported by the bytecode generator. */ + +#ifndef TARGET_SUPPORTS_BYTECODE + +#define MACHINE_SEG_ALIGN 1 +#define INT_ALIGN 1 +#define PTR_ALIGN 1 +#define NAMES_HAVE_UNDERSCORES +#define BC_NOP (0) +#define BC_GLOBALIZE_LABEL(FP, NAME) BC_NOP +#define BC_OUTPUT_COMMON(FP, NAME, SIZE, ROUNDED) BC_NOP +#define BC_OUTPUT_BSS(FP, NAME, SIZE, ROUNDED) BC_NOP +#define BC_OUTPUT_LOCAL(FP, NAME, SIZE, ROUNDED) BC_NOP +#define BC_OUTPUT_ALIGN(FP, ALIGN) BC_NOP +#define BC_OUTPUT_LABEL(FP, NAME) BC_NOP +#define BC_OUTPUT_SKIP(FP, SIZE) BC_NOP +#define BC_OUTPUT_LABELREF(FP, NAME) BC_NOP +#define BC_OUTPUT_FLOAT(FP, VAL) BC_NOP +#define BC_OUTPUT_DOUBLE(FP, VAL) BC_NOP +#define BC_OUTPUT_BYTE(FP, VAL) BC_NOP +#define BC_OUTPUT_FILE ASM_OUTPUT_FILE +#define BC_OUTPUT_ASCII ASM_OUTPUT_ASCII +#define BC_OUTPUT_IDENT ASM_OUTPUT_IDENT +#define BCXSTR(RTX) ((RTX)->bc_label) +#define BC_WRITE_FILE(FP) BC_NOP +#define BC_WRITE_SEGSYM(SEGSYM, FP) BC_NOP +#define BC_WRITE_RELOC_ENTRY(SEGRELOC, FP, OFFSET) BC_NOP +#define BC_START_BYTECODE_LINE(FP) BC_NOP +#define BC_WRITE_BYTECODE(SEP, VAL, FP) BC_NOP +#define BC_WRITE_RTL(R, FP) BC_NOP +#define BC_EMIT_TRAMPOLINE(TRAMPSEG, CALLINFO) BC_NOP +#define VALIDATE_STACK BC_NOP + +#endif /* !TARGET_SUPPORTS_BYTECODE */ diff --git a/gcc_arm/bytetypes.h b/gcc_arm/bytetypes.h new file mode 100755 index 0000000..f915669 --- /dev/null +++ b/gcc_arm/bytetypes.h @@ -0,0 +1,35 @@ +/* These should come from genemit */ + +/* Use __signed__ in case compiling with -traditional. */ + +typedef __signed__ char QItype; +typedef unsigned char QUtype; +typedef __signed__ short int HItype; +typedef unsigned short int HUtype; +typedef __signed__ long int SItype; +typedef unsigned long int SUtype; +typedef __signed__ long long int DItype; +typedef unsigned long long int DUtype; +typedef float SFtype; +typedef double DFtype; +typedef long double XFtype; +typedef char *Ptype; +typedef int Ttype; + + +typedef union stacktype +{ + QItype QIval; + QUtype QUval; + HItype HIval; + HUtype HUval; + SItype SIval; + SUtype SUval; + DItype DIval; + DUtype DUval; + SFtype SFval; + DFtype DFval; + XFtype XFval; + Ptype Pval; + Ttype Tval; +} stacktype; diff --git a/gcc_arm/c-aux-info.c b/gcc_arm/c-aux-info.c new file mode 100755 index 0000000..d86d445 --- /dev/null +++ b/gcc_arm/c-aux-info.c @@ -0,0 +1,661 @@ +/* Generate information regarding function declarations and definitions based + on information stored in GCC's tree structure. This code implements the + -aux-info option. + Copyright (C) 1989, 91, 94, 95, 97, 1998 Free Software Foundation, Inc. + Contributed by Ron Guilmette (rfg@segfault.us.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "flags.h" +#include "tree.h" +#include "c-tree.h" + +enum formals_style_enum { + ansi, + k_and_r_names, + k_and_r_decls +}; +typedef enum formals_style_enum formals_style; + + +static char *data_type; + +static char *affix_data_type PROTO((char *)); +static char *gen_formal_list_for_type PROTO((tree, formals_style)); +static int deserves_ellipsis PROTO((tree)); +static char *gen_formal_list_for_func_def PROTO((tree, formals_style)); +static char *gen_type PROTO((char *, tree, formals_style)); +static char *gen_decl PROTO((tree, int, formals_style)); + +/* Concatenate a sequence of strings, returning the result. + + This function is based on the one in libiberty. */ + +/* This definition will conflict with the one from prefix.c in + libcpp.a when linking cc1 and cc1obj. So only provide it if we are + not using libcpp.a */ +#ifndef USE_CPPLIB +char * +concat VPROTO((const char *first, ...)) +{ + register int length; + register char *newstr; + register char *end; + register const char *arg; + va_list args; +#ifndef ANSI_PROTOTYPES + const char *first; +#endif + + /* First compute the size of the result and get sufficient memory. */ + + VA_START (args, first); +#ifndef ANSI_PROTOTYPES + first = va_arg (args, const char *); +#endif + + arg = first; + length = 0; + + while (arg != 0) + { + length += strlen (arg); + arg = va_arg (args, const char *); + } + + newstr = (char *) malloc (length + 1); + va_end (args); + + /* Now copy the individual pieces to the result string. */ + + VA_START (args, first); +#ifndef ANSI_PROTOTYPES + first = va_arg (args, char *); +#endif + + end = newstr; + arg = first; + while (arg != 0) + { + while (*arg) + *end++ = *arg++; + arg = va_arg (args, const char *); + } + *end = '\000'; + va_end (args); + + return (newstr); +} +#endif /* ! USE_CPPLIB */ + +/* Given a string representing an entire type or an entire declaration + which only lacks the actual "data-type" specifier (at its left end), + affix the data-type specifier to the left end of the given type + specification or object declaration. + + Because of C language weirdness, the data-type specifier (which normally + goes in at the very left end) may have to be slipped in just to the + right of any leading "const" or "volatile" qualifiers (there may be more + than one). Actually this may not be strictly necessary because it seems + that GCC (at least) accepts ` const foo;' and treats it the + same as `const foo;' but people are accustomed to seeing + `const char *foo;' and *not* `char const *foo;' so we try to create types + that look as expected. */ + +static char * +affix_data_type (type_or_decl) + char *type_or_decl; +{ + char *p = type_or_decl; + char *qualifiers_then_data_type; + char saved; + + /* Skip as many leading const's or volatile's as there are. */ + + for (;;) + { + if (!strncmp (p, "volatile ", 9)) + { + p += 9; + continue; + } + if (!strncmp (p, "const ", 6)) + { + p += 6; + continue; + } + break; + } + + /* p now points to the place where we can insert the data type. We have to + add a blank after the data-type of course. */ + + if (p == type_or_decl) + return concat (data_type, " ", type_or_decl, NULL_PTR); + + saved = *p; + *p = '\0'; + qualifiers_then_data_type = concat (type_or_decl, data_type, NULL_PTR); + *p = saved; + return concat (qualifiers_then_data_type, " ", p, NULL_PTR); +} + +/* Given a tree node which represents some "function type", generate the + source code version of a formal parameter list (of some given style) for + this function type. Return the whole formal parameter list (including + a pair of surrounding parens) as a string. Note that if the style + we are currently aiming for is non-ansi, then we just return a pair + of empty parens here. */ + +static char * +gen_formal_list_for_type (fntype, style) + tree fntype; + formals_style style; +{ + char *formal_list = ""; + tree formal_type; + + if (style != ansi) + return "()"; + + formal_type = TYPE_ARG_TYPES (fntype); + while (formal_type && TREE_VALUE (formal_type) != void_type_node) + { + char *this_type; + + if (*formal_list) + formal_list = concat (formal_list, ", ", NULL_PTR); + + this_type = gen_type ("", TREE_VALUE (formal_type), ansi); + formal_list + = ((strlen (this_type)) + ? concat (formal_list, affix_data_type (this_type), NULL_PTR) + : concat (formal_list, data_type, NULL_PTR)); + + formal_type = TREE_CHAIN (formal_type); + } + + /* If we got to here, then we are trying to generate an ANSI style formal + parameters list. + + New style prototyped ANSI formal parameter lists should in theory always + contain some stuff between the opening and closing parens, even if it is + only "void". + + The brutal truth though is that there is lots of old K&R code out there + which contains declarations of "pointer-to-function" parameters and + these almost never have fully specified formal parameter lists associated + with them. That is, the pointer-to-function parameters are declared + with just empty parameter lists. + + In cases such as these, protoize should really insert *something* into + the vacant parameter lists, but what? It has no basis on which to insert + anything in particular. + + Here, we make life easy for protoize by trying to distinguish between + K&R empty parameter lists and new-style prototyped parameter lists + that actually contain "void". In the latter case we (obviously) want + to output the "void" verbatim, and that what we do. In the former case, + we do our best to give protoize something nice to insert. + + This "something nice" should be something that is still valid (when + re-compiled) but something that can clearly indicate to the user that + more typing information (for the parameter list) should be added (by + hand) at some convenient moment. + + The string chosen here is a comment with question marks in it. */ + + if (!*formal_list) + { + if (TYPE_ARG_TYPES (fntype)) + /* assert (TREE_VALUE (TYPE_ARG_TYPES (fntype)) == void_type_node); */ + formal_list = "void"; + else + formal_list = "/* ??? */"; + } + else + { + /* If there were at least some parameters, and if the formals-types-list + petered out to a NULL (i.e. without being terminated by a + void_type_node) then we need to tack on an ellipsis. */ + if (!formal_type) + formal_list = concat (formal_list, ", ...", NULL_PTR); + } + + return concat (" (", formal_list, ")", NULL_PTR); +} + +/* For the generation of an ANSI prototype for a function definition, we have + to look at the formal parameter list of the function's own "type" to + determine if the function's formal parameter list should end with an + ellipsis. Given a tree node, the following function will return non-zero + if the "function type" parameter list should end with an ellipsis. */ + +static int +deserves_ellipsis (fntype) + tree fntype; +{ + tree formal_type; + + formal_type = TYPE_ARG_TYPES (fntype); + while (formal_type && TREE_VALUE (formal_type) != void_type_node) + formal_type = TREE_CHAIN (formal_type); + + /* If there were at least some parameters, and if the formals-types-list + petered out to a NULL (i.e. without being terminated by a void_type_node) + then we need to tack on an ellipsis. */ + + return (!formal_type && TYPE_ARG_TYPES (fntype)); +} + +/* Generate a parameter list for a function definition (in some given style). + + Note that this routine has to be separate (and different) from the code that + generates the prototype parameter lists for function declarations, because + in the case of a function declaration, all we have to go on is a tree node + representing the function's own "function type". This can tell us the types + of all of the formal parameters for the function, but it cannot tell us the + actual *names* of each of the formal parameters. We need to output those + parameter names for each function definition. + + This routine gets a pointer to a tree node which represents the actual + declaration of the given function, and this DECL node has a list of formal + parameter (variable) declarations attached to it. These formal parameter + (variable) declaration nodes give us the actual names of the formal + parameters for the given function definition. + + This routine returns a string which is the source form for the entire + function formal parameter list. */ + +static char * +gen_formal_list_for_func_def (fndecl, style) + tree fndecl; + formals_style style; +{ + char *formal_list = ""; + tree formal_decl; + + formal_decl = DECL_ARGUMENTS (fndecl); + while (formal_decl) + { + char *this_formal; + + if (*formal_list && ((style == ansi) || (style == k_and_r_names))) + formal_list = concat (formal_list, ", ", NULL_PTR); + this_formal = gen_decl (formal_decl, 0, style); + if (style == k_and_r_decls) + formal_list = concat (formal_list, this_formal, "; ", NULL_PTR); + else + formal_list = concat (formal_list, this_formal, NULL_PTR); + formal_decl = TREE_CHAIN (formal_decl); + } + if (style == ansi) + { + if (!DECL_ARGUMENTS (fndecl)) + formal_list = concat (formal_list, "void", NULL_PTR); + if (deserves_ellipsis (TREE_TYPE (fndecl))) + formal_list = concat (formal_list, ", ...", NULL_PTR); + } + if ((style == ansi) || (style == k_and_r_names)) + formal_list = concat (" (", formal_list, ")", NULL_PTR); + return formal_list; +} + +/* Generate a string which is the source code form for a given type (t). This + routine is ugly and complex because the C syntax for declarations is ugly + and complex. This routine is straightforward so long as *no* pointer types, + array types, or function types are involved. + + In the simple cases, this routine will return the (string) value which was + passed in as the "ret_val" argument. Usually, this starts out either as an + empty string, or as the name of the declared item (i.e. the formal function + parameter variable). + + This routine will also return with the global variable "data_type" set to + some string value which is the "basic" data-type of the given complete type. + This "data_type" string can be concatenated onto the front of the returned + string after this routine returns to its caller. + + In complicated cases involving pointer types, array types, or function + types, the C declaration syntax requires an "inside out" approach, i.e. if + you have a type which is a "pointer-to-function" type, you need to handle + the "pointer" part first, but it also has to be "innermost" (relative to + the declaration stuff for the "function" type). Thus, is this case, you + must prepend a "(*" and append a ")" to the name of the item (i.e. formal + variable). Then you must append and prepend the other info for the + "function type" part of the overall type. + + To handle the "innermost precedence" rules of complicated C declarators, we + do the following (in this routine). The input parameter called "ret_val" + is treated as a "seed". Each time gen_type is called (perhaps recursively) + some additional strings may be appended or prepended (or both) to the "seed" + string. If yet another (lower) level of the GCC tree exists for the given + type (as in the case of a pointer type, an array type, or a function type) + then the (wrapped) seed is passed to a (recursive) invocation of gen_type() + this recursive invocation may again "wrap" the (new) seed with yet more + declarator stuff, by appending, prepending (or both). By the time the + recursion bottoms out, the "seed value" at that point will have a value + which is (almost) the complete source version of the declarator (except + for the data_type info). Thus, this deepest "seed" value is simply passed + back up through all of the recursive calls until it is given (as the return + value) to the initial caller of the gen_type() routine. All that remains + to do at this point is for the initial caller to prepend the "data_type" + string onto the returned "seed". */ + +static char * +gen_type (ret_val, t, style) + char *ret_val; + tree t; + formals_style style; +{ + tree chain_p; + + /* If there is a typedef name for this type, use it. */ + if (TYPE_NAME (t) && TREE_CODE (TYPE_NAME (t)) == TYPE_DECL) + data_type = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t))); + else + { + switch (TREE_CODE (t)) + { + case POINTER_TYPE: + if (TYPE_READONLY (t)) + ret_val = concat ("const ", ret_val, NULL_PTR); + if (TYPE_VOLATILE (t)) + ret_val = concat ("volatile ", ret_val, NULL_PTR); + + ret_val = concat ("*", ret_val, NULL_PTR); + + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE || TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE) + ret_val = concat ("(", ret_val, ")", NULL_PTR); + + ret_val = gen_type (ret_val, TREE_TYPE (t), style); + + return ret_val; + + case ARRAY_TYPE: + if (TYPE_SIZE (t) == 0 || TREE_CODE (TYPE_SIZE (t)) != INTEGER_CST) + ret_val = gen_type (concat (ret_val, "[]", NULL_PTR), + TREE_TYPE (t), style); + else if (int_size_in_bytes (t) == 0) + ret_val = gen_type (concat (ret_val, "[0]", NULL_PTR), + TREE_TYPE (t), style); + else + { + int size = (int_size_in_bytes (t) / int_size_in_bytes (TREE_TYPE (t))); + char buff[10]; + sprintf (buff, "[%d]", size); + ret_val = gen_type (concat (ret_val, buff, NULL_PTR), + TREE_TYPE (t), style); + } + break; + + case FUNCTION_TYPE: + ret_val = gen_type (concat (ret_val, + gen_formal_list_for_type (t, style), + NULL_PTR), + TREE_TYPE (t), style); + break; + + case IDENTIFIER_NODE: + data_type = IDENTIFIER_POINTER (t); + break; + + /* The following three cases are complicated by the fact that a + user may do something really stupid, like creating a brand new + "anonymous" type specification in a formal argument list (or as + part of a function return type specification). For example: + + int f (enum { red, green, blue } color); + + In such cases, we have no name that we can put into the prototype + to represent the (anonymous) type. Thus, we have to generate the + whole darn type specification. Yuck! */ + + case RECORD_TYPE: + if (TYPE_NAME (t)) + data_type = IDENTIFIER_POINTER (TYPE_NAME (t)); + else + { + data_type = ""; + chain_p = TYPE_FIELDS (t); + while (chain_p) + { + data_type = concat (data_type, gen_decl (chain_p, 0, ansi), + NULL_PTR); + chain_p = TREE_CHAIN (chain_p); + data_type = concat (data_type, "; ", NULL_PTR); + } + data_type = concat ("{ ", data_type, "}", NULL_PTR); + } + data_type = concat ("struct ", data_type, NULL_PTR); + break; + + case UNION_TYPE: + if (TYPE_NAME (t)) + data_type = IDENTIFIER_POINTER (TYPE_NAME (t)); + else + { + data_type = ""; + chain_p = TYPE_FIELDS (t); + while (chain_p) + { + data_type = concat (data_type, gen_decl (chain_p, 0, ansi), + NULL_PTR); + chain_p = TREE_CHAIN (chain_p); + data_type = concat (data_type, "; ", NULL_PTR); + } + data_type = concat ("{ ", data_type, "}", NULL_PTR); + } + data_type = concat ("union ", data_type, NULL_PTR); + break; + + case ENUMERAL_TYPE: + if (TYPE_NAME (t)) + data_type = IDENTIFIER_POINTER (TYPE_NAME (t)); + else + { + data_type = ""; + chain_p = TYPE_VALUES (t); + while (chain_p) + { + data_type = concat (data_type, + IDENTIFIER_POINTER (TREE_PURPOSE (chain_p)), NULL_PTR); + chain_p = TREE_CHAIN (chain_p); + if (chain_p) + data_type = concat (data_type, ", ", NULL_PTR); + } + data_type = concat ("{ ", data_type, " }", NULL_PTR); + } + data_type = concat ("enum ", data_type, NULL_PTR); + break; + + case TYPE_DECL: + data_type = IDENTIFIER_POINTER (DECL_NAME (t)); + break; + + case INTEGER_TYPE: + data_type = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t))); + /* Normally, `unsigned' is part of the deal. Not so if it comes + with a type qualifier. */ + if (TREE_UNSIGNED (t) && TYPE_QUALS (t)) + data_type = concat ("unsigned ", data_type, NULL_PTR); + break; + + case REAL_TYPE: + data_type = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t))); + break; + + case VOID_TYPE: + data_type = "void"; + break; + + case ERROR_MARK: + data_type = "[ERROR]"; + break; + + default: + abort (); + } + } + if (TYPE_READONLY (t)) + ret_val = concat ("const ", ret_val, NULL_PTR); + if (TYPE_VOLATILE (t)) + ret_val = concat ("volatile ", ret_val, NULL_PTR); + if (TYPE_RESTRICT (t)) + ret_val = concat ("restrict ", ret_val, NULL_PTR); + return ret_val; +} + +/* Generate a string (source) representation of an entire entity declaration + (using some particular style for function types). + + The given entity may be either a variable or a function. + + If the "is_func_definition" parameter is non-zero, assume that the thing + we are generating a declaration for is a FUNCTION_DECL node which is + associated with a function definition. In this case, we can assume that + an attached list of DECL nodes for function formal arguments is present. */ + +static char * +gen_decl (decl, is_func_definition, style) + tree decl; + int is_func_definition; + formals_style style; +{ + char *ret_val; + + if (DECL_NAME (decl)) + ret_val = IDENTIFIER_POINTER (DECL_NAME (decl)); + else + ret_val = ""; + + /* If we are just generating a list of names of formal parameters, we can + simply return the formal parameter name (with no typing information + attached to it) now. */ + + if (style == k_and_r_names) + return ret_val; + + /* Note that for the declaration of some entity (either a function or a + data object, like for instance a parameter) if the entity itself was + declared as either const or volatile, then const and volatile properties + are associated with just the declaration of the entity, and *not* with + the `type' of the entity. Thus, for such declared entities, we have to + generate the qualifiers here. */ + + if (TREE_THIS_VOLATILE (decl)) + ret_val = concat ("volatile ", ret_val, NULL_PTR); + if (TREE_READONLY (decl)) + ret_val = concat ("const ", ret_val, NULL_PTR); + + data_type = ""; + + /* For FUNCTION_DECL nodes, there are two possible cases here. First, if + this FUNCTION_DECL node was generated from a function "definition", then + we will have a list of DECL_NODE's, one for each of the function's formal + parameters. In this case, we can print out not only the types of each + formal, but also each formal's name. In the second case, this + FUNCTION_DECL node came from an actual function declaration (and *not* + a definition). In this case, we do nothing here because the formal + argument type-list will be output later, when the "type" of the function + is added to the string we are building. Note that the ANSI-style formal + parameter list is considered to be a (suffix) part of the "type" of the + function. */ + + if (TREE_CODE (decl) == FUNCTION_DECL && is_func_definition) + { + ret_val = concat (ret_val, gen_formal_list_for_func_def (decl, ansi), + NULL_PTR); + + /* Since we have already added in the formals list stuff, here we don't + add the whole "type" of the function we are considering (which + would include its parameter-list info), rather, we only add in + the "type" of the "type" of the function, which is really just + the return-type of the function (and does not include the parameter + list info). */ + + ret_val = gen_type (ret_val, TREE_TYPE (TREE_TYPE (decl)), style); + } + else + ret_val = gen_type (ret_val, TREE_TYPE (decl), style); + + ret_val = affix_data_type (ret_val); + + if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl)) + ret_val = concat ("register ", ret_val, NULL_PTR); + if (TREE_PUBLIC (decl)) + ret_val = concat ("extern ", ret_val, NULL_PTR); + if (TREE_CODE (decl) == FUNCTION_DECL && !TREE_PUBLIC (decl)) + ret_val = concat ("static ", ret_val, NULL_PTR); + + return ret_val; +} + +extern FILE *aux_info_file; + +/* Generate and write a new line of info to the aux-info (.X) file. This + routine is called once for each function declaration, and once for each + function definition (even the implicit ones). */ + +void +gen_aux_info_record (fndecl, is_definition, is_implicit, is_prototyped) + tree fndecl; + int is_definition; + int is_implicit; + int is_prototyped; +{ + if (flag_gen_aux_info) + { + static int compiled_from_record = 0; + + /* Each output .X file must have a header line. Write one now if we + have not yet done so. */ + + if (! compiled_from_record++) + { + /* The first line tells which directory file names are relative to. + Currently, -aux-info works only for files in the working + directory, so just use a `.' as a placeholder for now. */ + fprintf (aux_info_file, "/* compiled from: . */\n"); + } + + /* Write the actual line of auxiliary info. */ + + fprintf (aux_info_file, "/* %s:%d:%c%c */ %s;", + DECL_SOURCE_FILE (fndecl), + DECL_SOURCE_LINE (fndecl), + (is_implicit) ? 'I' : (is_prototyped) ? 'N' : 'O', + (is_definition) ? 'F' : 'C', + gen_decl (fndecl, is_definition, ansi)); + + /* If this is an explicit function declaration, we need to also write + out an old-style (i.e. K&R) function header, just in case the user + wants to run unprotoize. */ + + if (is_definition) + { + fprintf (aux_info_file, " /*%s %s*/", + gen_formal_list_for_func_def (fndecl, k_and_r_names), + gen_formal_list_for_func_def (fndecl, k_and_r_decls)); + } + + fprintf (aux_info_file, "\n"); + } +} diff --git a/gcc_arm/c-common.c b/gcc_arm/c-common.c new file mode 100755 index 0000000..936b609 --- /dev/null +++ b/gcc_arm/c-common.c @@ -0,0 +1,3240 @@ +/* Subroutines shared by all languages that are variants of C. + Copyright (C) 1992, 93-98, 1999 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "tree.h" +#include "c-lex.h" +#include "c-tree.h" +#include "flags.h" +#include "obstack.h" +#include "toplev.h" +#include "output.h" +#include "c-pragma.h" +#include "rtl.h" + +#if USE_CPPLIB +#include "cpplib.h" +cpp_reader parse_in; +cpp_options parse_options; +static enum cpp_token cpp_token; +#endif + +#ifndef WCHAR_TYPE_SIZE +#ifdef INT_TYPE_SIZE +#define WCHAR_TYPE_SIZE INT_TYPE_SIZE +#else +#define WCHAR_TYPE_SIZE BITS_PER_WORD +#endif +#endif + +extern struct obstack permanent_obstack; + +/* Nonzero means the expression being parsed will never be evaluated. + This is a count, since unevaluated expressions can nest. */ +int skip_evaluation; + +enum attrs {A_PACKED, A_NOCOMMON, A_COMMON, A_NORETURN, A_CONST, A_T_UNION, + A_NO_CHECK_MEMORY_USAGE, A_NO_INSTRUMENT_FUNCTION, + A_CONSTRUCTOR, A_DESTRUCTOR, A_MODE, A_SECTION, A_ALIGNED, + A_UNUSED, A_FORMAT, A_FORMAT_ARG, A_WEAK, A_ALIAS, + A_INIT_PRIORITY}; + +enum format_type { printf_format_type, scanf_format_type, + strftime_format_type }; + +static void declare_hidden_char_array PROTO((char *, char *)); +static void add_attribute PROTO((enum attrs, char *, + int, int, int)); +static void init_attributes PROTO((void)); +static void record_function_format PROTO((tree, tree, enum format_type, + int, int)); +static void record_international_format PROTO((tree, tree, int)); +static tree c_find_base_decl PROTO((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; + int line; + char *file; + int needs_warning; +} 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; + +/* Generate RTL for the start of an if-then, and record the start of it + for ambiguous else detection. */ + +/* A list of objects which have constructors or destructors which + reside in the global scope, and have an init_priority attribute + associated with them. The decl is stored in the TREE_VALUE slot + and the priority number is stored in the TREE_PURPOSE slot. */ +tree static_aggregates_initp; + +void +c_expand_start_cond (cond, exitflag, compstmt_count) + tree cond; + int exitflag; + int compstmt_count; +{ + /* Make sure there is enough space on the stack. */ + if (if_stack_space == 0) + { + if_stack_space = 10; + if_stack = (if_elt *)xmalloc (10 * sizeof (if_elt)); + } + else if (if_stack_space == if_stack_pointer) + { + if_stack_space += 10; + if_stack = (if_elt *)xrealloc (if_stack, if_stack_space * sizeof (if_elt)); + } + + /* Record this if statement. */ + if_stack[if_stack_pointer].compstmt_count = compstmt_count; + if_stack[if_stack_pointer].file = input_filename; + if_stack[if_stack_pointer].line = lineno; + if_stack[if_stack_pointer].needs_warning = 0; + if_stack_pointer++; + + expand_start_cond (cond, exitflag); +} + +/* Generate RTL for the end of an if-then. Optionally warn if a nested + if statement had an ambiguous else clause. */ + +void +c_expand_end_cond () +{ + if_stack_pointer--; + if (if_stack[if_stack_pointer].needs_warning) + warning_with_file_and_line (if_stack[if_stack_pointer].file, + if_stack[if_stack_pointer].line, + "suggest explicit braces to avoid ambiguous `else'"); + expand_end_cond (); +} + +/* Generate RTL between the then-clause and the else-clause + of an if-then-else. */ + +void +c_expand_start_else () +{ + /* 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--; + + expand_start_else (); +} + +/* Make bindings for __FUNCTION__, __PRETTY_FUNCTION__, and __func__. */ + +void +declare_function_name () +{ + char *name, *printable_name; + + if (current_function_decl == NULL) + { + name = ""; + printable_name = "top level"; + } + else + { + /* Allow functions to be nameless (such as artificial ones). */ + if (DECL_NAME (current_function_decl)) + name = IDENTIFIER_POINTER (DECL_NAME (current_function_decl)); + else + name = ""; + printable_name = (*decl_printable_name) (current_function_decl, 2); + } + + declare_hidden_char_array ("__FUNCTION__", name); + declare_hidden_char_array ("__PRETTY_FUNCTION__", printable_name); + /* The ISO C people "of course" couldn't use __FUNCTION__ in the + ISO C 9x standard; instead a new variable is invented. */ + declare_hidden_char_array ("__func__", name); +} + +static void +declare_hidden_char_array (name, value) + char *name, *value; +{ + tree decl, type, init; + int vlen; + + /* If the default size of char arrays isn't big enough for the name, + or if we want to give warnings for large objects, make a bigger one. */ + vlen = strlen (value) + 1; + type = char_array_type_node; + if (TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) < vlen + || warn_larger_than) + type = build_array_type (char_type_node, + build_index_type (build_int_2 (vlen, 0))); + push_obstacks_nochange (); + decl = build_decl (VAR_DECL, get_identifier (name), type); + TREE_STATIC (decl) = 1; + TREE_READONLY (decl) = 1; + TREE_ASM_WRITTEN (decl) = 1; + DECL_SOURCE_LINE (decl) = 0; + DECL_ARTIFICIAL (decl) = 1; + DECL_IN_SYSTEM_HEADER (decl) = 1; + DECL_IGNORED_P (decl) = 1; + init = build_string (vlen, value); + TREE_TYPE (init) = type; + DECL_INITIAL (decl) = init; + finish_decl (pushdecl (decl), init, NULL_TREE); +} + +/* Given a chain of STRING_CST nodes, + concatenate them into one STRING_CST + and give it a suitable array-of-chars data type. */ + +tree +combine_strings (strings) + tree strings; +{ + register tree value, t; + register int length = 1; + int wide_length = 0; + int wide_flag = 0; + int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT; + int nchars; + + if (TREE_CHAIN (strings)) + { + /* More than one in the chain, so concatenate. */ + register char *p, *q; + + /* Don't include the \0 at the end of each substring, + except for the last one. + Count wide strings and ordinary strings separately. */ + for (t = strings; t; t = TREE_CHAIN (t)) + { + if (TREE_TYPE (t) == wchar_array_type_node) + { + wide_length += (TREE_STRING_LENGTH (t) - wchar_bytes); + wide_flag = 1; + } + else + length += (TREE_STRING_LENGTH (t) - 1); + } + + /* If anything is wide, the non-wides will be converted, + which makes them take more space. */ + if (wide_flag) + length = length * wchar_bytes + wide_length; + + p = savealloc (length); + + /* Copy the individual strings into the new combined string. + If the combined string is wide, convert the chars to ints + for any individual strings that are not wide. */ + + q = p; + for (t = strings; t; t = TREE_CHAIN (t)) + { + int len = (TREE_STRING_LENGTH (t) + - ((TREE_TYPE (t) == wchar_array_type_node) + ? wchar_bytes : 1)); + if ((TREE_TYPE (t) == wchar_array_type_node) == wide_flag) + { + memcpy (q, TREE_STRING_POINTER (t), len); + q += len; + } + else + { + int i; + for (i = 0; i < len; i++) + { + if (WCHAR_TYPE_SIZE == HOST_BITS_PER_SHORT) + ((short *) q)[i] = TREE_STRING_POINTER (t)[i]; + else + ((int *) q)[i] = TREE_STRING_POINTER (t)[i]; + } + q += len * wchar_bytes; + } + } + if (wide_flag) + { + int i; + for (i = 0; i < wchar_bytes; i++) + *q++ = 0; + } + else + *q = 0; + + value = make_node (STRING_CST); + TREE_STRING_POINTER (value) = p; + TREE_STRING_LENGTH (value) = length; + } + else + { + value = strings; + length = TREE_STRING_LENGTH (value); + if (TREE_TYPE (value) == wchar_array_type_node) + wide_flag = 1; + } + + /* Compute the number of elements, for the array type. */ + nchars = wide_flag ? length / wchar_bytes : length; + + /* 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_traditional && ! 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_READONLY (value) = TREE_CONSTANT (value) = ! flag_writable_strings; + TREE_STATIC (value) = 1; + return value; +} + +/* To speed up processing of attributes, we maintain an array of + IDENTIFIER_NODES and the corresponding attribute types. */ + +/* Array to hold attribute information. */ + +static struct {enum attrs id; tree name; int min, max, decl_req;} attrtab[50]; + +static int attrtab_idx = 0; + +/* Add an entry to the attribute table above. */ + +static void +add_attribute (id, string, min_len, max_len, decl_req) + enum attrs id; + char *string; + int min_len, max_len; + int decl_req; +{ + char buf[100]; + + attrtab[attrtab_idx].id = id; + attrtab[attrtab_idx].name = get_identifier (string); + attrtab[attrtab_idx].min = min_len; + attrtab[attrtab_idx].max = max_len; + attrtab[attrtab_idx++].decl_req = decl_req; + + sprintf (buf, "__%s__", string); + + attrtab[attrtab_idx].id = id; + attrtab[attrtab_idx].name = get_identifier (buf); + attrtab[attrtab_idx].min = min_len; + attrtab[attrtab_idx].max = max_len; + attrtab[attrtab_idx++].decl_req = decl_req; +} + +/* Initialize attribute table. */ + +static void +init_attributes () +{ + add_attribute (A_PACKED, "packed", 0, 0, 0); + add_attribute (A_NOCOMMON, "nocommon", 0, 0, 1); + add_attribute (A_COMMON, "common", 0, 0, 1); + add_attribute (A_NORETURN, "noreturn", 0, 0, 1); + add_attribute (A_NORETURN, "volatile", 0, 0, 1); + add_attribute (A_UNUSED, "unused", 0, 0, 0); + add_attribute (A_CONST, "const", 0, 0, 1); + add_attribute (A_T_UNION, "transparent_union", 0, 0, 0); + add_attribute (A_CONSTRUCTOR, "constructor", 0, 0, 1); + add_attribute (A_DESTRUCTOR, "destructor", 0, 0, 1); + add_attribute (A_MODE, "mode", 1, 1, 1); + add_attribute (A_SECTION, "section", 1, 1, 1); + add_attribute (A_ALIGNED, "aligned", 0, 1, 0); + add_attribute (A_FORMAT, "format", 3, 3, 1); + add_attribute (A_FORMAT_ARG, "format_arg", 1, 1, 1); + add_attribute (A_WEAK, "weak", 0, 0, 1); + add_attribute (A_ALIAS, "alias", 1, 1, 1); + add_attribute (A_INIT_PRIORITY, "init_priority", 0, 1, 0); + add_attribute (A_NO_INSTRUMENT_FUNCTION, "no_instrument_function", 0, 0, 1); + add_attribute (A_NO_CHECK_MEMORY_USAGE, "no_check_memory_usage", 0, 0, 1); +} + +/* Process the attributes listed in ATTRIBUTES and PREFIX_ATTRIBUTES + and install them in NODE, which is either a DECL (including a TYPE_DECL) + or a TYPE. PREFIX_ATTRIBUTES can appear after the declaration specifiers + and declaration modifiers but before the declaration proper. */ + +void +decl_attributes (node, attributes, prefix_attributes) + tree node, attributes, prefix_attributes; +{ + tree decl = 0, type = 0; + int is_type = 0; + tree a; + + if (attrtab_idx == 0) + init_attributes (); + + if (TREE_CODE_CLASS (TREE_CODE (node)) == 'd') + { + decl = node; + type = TREE_TYPE (decl); + is_type = TREE_CODE (node) == TYPE_DECL; + } + else if (TREE_CODE_CLASS (TREE_CODE (node)) == 't') + type = node, is_type = 1; + +#ifdef PRAGMA_INSERT_ATTRIBUTES + /* If the code in c-pragma.c wants to insert some attributes then + allow it to do so. Do this before allowing machine back ends to + insert attributes, so that they have the opportunity to override + anything done here. */ + PRAGMA_INSERT_ATTRIBUTES (node, & attributes, & prefix_attributes); +#endif + +#ifdef INSERT_ATTRIBUTES + INSERT_ATTRIBUTES (node, & attributes, & prefix_attributes); +#endif + + attributes = chainon (prefix_attributes, attributes); + + for (a = attributes; a; a = TREE_CHAIN (a)) + { + tree name = TREE_PURPOSE (a); + tree args = TREE_VALUE (a); + int i; + enum attrs id; + + for (i = 0; i < attrtab_idx; i++) + if (attrtab[i].name == name) + break; + + if (i == attrtab_idx) + { + if (! valid_machine_attribute (name, args, decl, type)) + warning ("`%s' attribute directive ignored", + IDENTIFIER_POINTER (name)); + else if (decl != 0) + type = TREE_TYPE (decl); + continue; + } + else if (attrtab[i].decl_req && decl == 0) + { + warning ("`%s' attribute does not apply to types", + IDENTIFIER_POINTER (name)); + continue; + } + else if (list_length (args) < attrtab[i].min + || list_length (args) > attrtab[i].max) + { + error ("wrong number of arguments specified for `%s' attribute", + IDENTIFIER_POINTER (name)); + continue; + } + + id = attrtab[i].id; + switch (id) + { + case A_PACKED: + if (is_type) + TYPE_PACKED (type) = 1; + else if (TREE_CODE (decl) == FIELD_DECL) + DECL_PACKED (decl) = 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. */ + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_NOCOMMON: + if (TREE_CODE (decl) == VAR_DECL) + DECL_COMMON (decl) = 0; + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_COMMON: + if (TREE_CODE (decl) == VAR_DECL) + DECL_COMMON (decl) = 1; + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_NORETURN: + if (TREE_CODE (decl) == FUNCTION_DECL) + TREE_THIS_VOLATILE (decl) = 1; + else if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) + TREE_TYPE (decl) = type + = build_pointer_type + (build_type_variant (TREE_TYPE (type), + TREE_READONLY (TREE_TYPE (type)), 1)); + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_UNUSED: + if (is_type) + TREE_USED (type) = 1; + else if (TREE_CODE (decl) == PARM_DECL + || TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == LABEL_DECL) + TREE_USED (decl) = 1; + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_CONST: + if (TREE_CODE (decl) == FUNCTION_DECL) + TREE_READONLY (decl) = 1; + else if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) + TREE_TYPE (decl) = type + = build_pointer_type + (build_type_variant (TREE_TYPE (type), 1, + TREE_THIS_VOLATILE (TREE_TYPE (type)))); + else + warning ( "`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_T_UNION: + if (is_type + && TREE_CODE (type) == UNION_TYPE + && (decl == 0 + || (TYPE_FIELDS (type) != 0 + && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (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)); + break; + + case A_CONSTRUCTOR: + if (TREE_CODE (decl) == FUNCTION_DECL + && TREE_CODE (type) == FUNCTION_TYPE + && decl_function_context (decl) == 0) + { + DECL_STATIC_CONSTRUCTOR (decl) = 1; + TREE_USED (decl) = 1; + } + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_DESTRUCTOR: + if (TREE_CODE (decl) == FUNCTION_DECL + && TREE_CODE (type) == FUNCTION_TYPE + && decl_function_context (decl) == 0) + { + DECL_STATIC_DESTRUCTOR (decl) = 1; + TREE_USED (decl) = 1; + } + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_MODE: + if (TREE_CODE (TREE_VALUE (args)) != IDENTIFIER_NODE) + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + else + { + int j; + char *p = IDENTIFIER_POINTER (TREE_VALUE (args)); + int len = strlen (p); + enum machine_mode mode = VOIDmode; + tree typefm; + + if (len > 4 && p[0] == '_' && p[1] == '_' + && p[len - 1] == '_' && p[len - 2] == '_') + { + char *newp = (char *) alloca (len - 1); + + strcpy (newp, &p[2]); + newp[len - 4] = '\0'; + p = newp; + } + + /* Give this decl a type with the specified mode. + First check for the special modes. */ + if (! strcmp (p, "byte")) + mode = byte_mode; + else if (!strcmp (p, "word")) + mode = word_mode; + else if (! strcmp (p, "pointer")) + mode = ptr_mode; + else + for (j = 0; j < NUM_MACHINE_MODES; j++) + if (!strcmp (p, GET_MODE_NAME (j))) + mode = (enum machine_mode) j; + + if (mode == VOIDmode) + error ("unknown machine mode `%s'", p); + else if (0 == (typefm = type_for_mode (mode, + TREE_UNSIGNED (type)))) + error ("no data type for mode `%s'", p); + else + { + TREE_TYPE (decl) = type = typefm; + DECL_SIZE (decl) = 0; + layout_decl (decl, 0); + } + } + break; + + case A_SECTION: +#ifdef ASM_OUTPUT_SECTION_NAME + 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)) + error_with_decl (decl, + "section attribute cannot be specified for local variables"); + /* The decl may have already been given a section attribute from + a previous declaration. Ensure they match. */ + else if (DECL_SECTION_NAME (decl) != NULL_TREE + && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)), + TREE_STRING_POINTER (TREE_VALUE (args))) != 0) + error_with_decl (node, + "section of `%s' conflicts with previous declaration"); + else + DECL_SECTION_NAME (decl) = TREE_VALUE (args); + } + else + error_with_decl (node, + "section attribute not allowed for `%s'"); +#else + error_with_decl (node, + "section attributes are not supported for this target"); +#endif + break; + + case A_ALIGNED: + { + tree align_expr + = (args ? TREE_VALUE (args) + : size_int (BIGGEST_ALIGNMENT / BITS_PER_UNIT)); + int align; + + /* 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"); + continue; + } + + align = TREE_INT_CST_LOW (align_expr) * BITS_PER_UNIT; + + if (exact_log2 (align) == -1) + error ("requested alignment is not a power of 2"); + else if (is_type) + TYPE_ALIGN (type) = align; + else if (TREE_CODE (decl) != VAR_DECL + && TREE_CODE (decl) != FIELD_DECL) + error_with_decl (decl, + "alignment may not be specified for `%s'"); + else + DECL_ALIGN (decl) = align; + } + break; + + case A_FORMAT: + { + tree format_type_id = TREE_VALUE (args); + tree format_num_expr = TREE_VALUE (TREE_CHAIN (args)); + tree first_arg_num_expr + = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))); + int format_num; + int first_arg_num; + enum format_type format_type; + tree argument; + int arg_num; + + if (TREE_CODE (decl) != FUNCTION_DECL) + { + error_with_decl (decl, + "argument format specified for non-function `%s'"); + continue; + } + + if (TREE_CODE (format_type_id) != IDENTIFIER_NODE) + { + error ("unrecognized format specifier"); + continue; + } + else + { + char *p = IDENTIFIER_POINTER (format_type_id); + + if (!strcmp (p, "printf") || !strcmp (p, "__printf__")) + format_type = printf_format_type; + else if (!strcmp (p, "scanf") || !strcmp (p, "__scanf__")) + format_type = scanf_format_type; + else if (!strcmp (p, "strftime") + || !strcmp (p, "__strftime__")) + format_type = strftime_format_type; + else + { + error ("`%s' is an unrecognized format function type", p); + continue; + } + } + + /* Strip any conversions from the string index and first arg number + and verify they are constants. */ + 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); + + while (TREE_CODE (first_arg_num_expr) == NOP_EXPR + || TREE_CODE (first_arg_num_expr) == CONVERT_EXPR + || TREE_CODE (first_arg_num_expr) == NON_LVALUE_EXPR) + first_arg_num_expr = TREE_OPERAND (first_arg_num_expr, 0); + + if (TREE_CODE (format_num_expr) != INTEGER_CST + || TREE_CODE (first_arg_num_expr) != INTEGER_CST) + { + error ("format string has non-constant operand number"); + continue; + } + + format_num = TREE_INT_CST_LOW (format_num_expr); + first_arg_num = TREE_INT_CST_LOW (first_arg_num_expr); + if (first_arg_num != 0 && first_arg_num <= format_num) + { + error ("format string arg follows the args to be formatted"); + continue; + } + + /* If a parameter list is specified, verify that the format_num + argument is actually a string, in case the format attribute + is in error. */ + argument = TYPE_ARG_TYPES (type); + if (argument) + { + for (arg_num = 1; ; ++arg_num) + { + if (argument == 0 || arg_num == format_num) + break; + argument = TREE_CHAIN (argument); + } + if (! argument + || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE + || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument))) + != char_type_node)) + { + error ("format string arg not a string type"); + continue; + } + if (first_arg_num != 0) + { + /* Verify that first_arg_num points to the last arg, + the ... */ + while (argument) + arg_num++, argument = TREE_CHAIN (argument); + if (arg_num != first_arg_num) + { + error ("args to be formatted is not ..."); + continue; + } + } + } + + record_function_format (DECL_NAME (decl), + DECL_ASSEMBLER_NAME (decl), + format_type, format_num, first_arg_num); + break; + } + + case A_FORMAT_ARG: + { + tree format_num_expr = TREE_VALUE (args); + int format_num, arg_num; + tree argument; + + if (TREE_CODE (decl) != FUNCTION_DECL) + { + error_with_decl (decl, + "argument format specified for non-function `%s'"); + continue; + } + + /* Strip any conversions from the first arg number and verify it + is a constant. */ + 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); + + if (TREE_CODE (format_num_expr) != INTEGER_CST) + { + error ("format string has non-constant operand number"); + continue; + } + + format_num = TREE_INT_CST_LOW (format_num_expr); + + /* If a parameter list is specified, verify that the format_num + argument is actually a string, in case the format attribute + is in error. */ + argument = TYPE_ARG_TYPES (type); + if (argument) + { + for (arg_num = 1; ; ++arg_num) + { + if (argument == 0 || arg_num == format_num) + break; + argument = TREE_CHAIN (argument); + } + if (! argument + || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE + || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument))) + != char_type_node)) + { + error ("format string arg not a string type"); + continue; + } + } + + if (TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) != POINTER_TYPE + || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (TREE_TYPE (decl)))) + != char_type_node)) + { + error ("function does not return string type"); + continue; + } + + record_international_format (DECL_NAME (decl), + DECL_ASSEMBLER_NAME (decl), + format_num); + break; + } + + case A_WEAK: + declare_weak (decl); + break; + + case A_ALIAS: + if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl)) + || (TREE_CODE (decl) != FUNCTION_DECL && ! DECL_EXTERNAL (decl))) + error_with_decl (decl, + "`%s' defined both normally and as an alias"); + else if (decl_function_context (decl) == 0) + { + tree id; + + id = TREE_VALUE (args); + if (TREE_CODE (id) != STRING_CST) + { + error ("alias arg not a string"); + break; + } + id = get_identifier (TREE_STRING_POINTER (id)); + + if (TREE_CODE (decl) == FUNCTION_DECL) + DECL_INITIAL (decl) = error_mark_node; + else + DECL_EXTERNAL (decl) = 0; + assemble_alias (decl, id); + } + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_NO_CHECK_MEMORY_USAGE: + if (TREE_CODE (decl) != FUNCTION_DECL) + { + error_with_decl (decl, + "`%s' attribute applies only to functions", + IDENTIFIER_POINTER (name)); + } + else if (DECL_INITIAL (decl)) + { + error_with_decl (decl, + "can't set `%s' attribute after definition", + IDENTIFIER_POINTER (name)); + } + else + DECL_NO_CHECK_MEMORY_USAGE (decl) = 1; + break; + + case A_INIT_PRIORITY: + { + tree initp_expr = (args ? TREE_VALUE (args): NULL_TREE); + int pri; + + if (initp_expr) + STRIP_NOPS (initp_expr); + + if (!initp_expr || TREE_CODE (initp_expr) != INTEGER_CST) + { + error ("requested init_priority is not an integer constant"); + continue; + } + + pri = TREE_INT_CST_LOW (initp_expr); + + while (TREE_CODE (type) == ARRAY_TYPE) + type = TREE_TYPE (type); + + if (is_type || TREE_CODE (decl) != VAR_DECL + || ! TREE_STATIC (decl) + || DECL_EXTERNAL (decl) + || (TREE_CODE (type) != RECORD_TYPE + && TREE_CODE (type) != UNION_TYPE) + /* Static objects in functions are initialized the + first time control passes through that + function. This is not precise enough to pin down an + init_priority value, so don't allow it. */ + || current_function_decl) + { + error ("can only use init_priority attribute on file-scope definitions of objects of class type"); + continue; + } + + if (pri > MAX_INIT_PRIORITY || pri <= 0) + { + error ("requested init_priority is out of range"); + continue; + } + + /* Check for init_priorities that are reserved for + language and runtime support implementations.*/ + if (pri <= MAX_RESERVED_INIT_PRIORITY) + { + warning + ("requested init_priority is reserved for internal use"); + } + + static_aggregates_initp + = perm_tree_cons (initp_expr, decl, static_aggregates_initp); + break; + } + + case A_NO_INSTRUMENT_FUNCTION: + if (TREE_CODE (decl) != FUNCTION_DECL) + { + error_with_decl (decl, + "`%s' attribute applies only to functions", + IDENTIFIER_POINTER (name)); + } + else if (DECL_INITIAL (decl)) + { + error_with_decl (decl, + "can't set `%s' attribute after definition", + IDENTIFIER_POINTER (name)); + } + else + DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1; + break; + } + } +} + +/* Split SPECS_ATTRS, a list of declspecs and prefix attributes, into two + lists. SPECS_ATTRS may also be just a typespec (eg: RECORD_TYPE). + + The head of the declspec list is stored in DECLSPECS. + The head of the attribute list is stored in PREFIX_ATTRIBUTES. + + Note that attributes in SPECS_ATTRS are stored in the TREE_PURPOSE of + the list elements. We drop the containing TREE_LIST nodes and link the + resulting attributes together the way decl_attributes expects them. */ + +void +split_specs_attrs (specs_attrs, declspecs, prefix_attributes) + tree specs_attrs; + tree *declspecs, *prefix_attributes; +{ + tree t, s, a, next, specs, attrs; + + /* This can happen in c++ (eg: decl: typespec initdecls ';'). */ + if (specs_attrs != NULL_TREE + && TREE_CODE (specs_attrs) != TREE_LIST) + { + *declspecs = specs_attrs; + *prefix_attributes = NULL_TREE; + return; + } + + /* Remember to keep the lists in the same order, element-wise. */ + + specs = s = NULL_TREE; + attrs = a = NULL_TREE; + for (t = specs_attrs; t; t = next) + { + next = TREE_CHAIN (t); + /* Declspecs have a non-NULL TREE_VALUE. */ + if (TREE_VALUE (t) != NULL_TREE) + { + if (specs == NULL_TREE) + specs = s = t; + else + { + TREE_CHAIN (s) = t; + s = t; + } + } + else + { + if (attrs == NULL_TREE) + attrs = a = TREE_PURPOSE (t); + else + { + TREE_CHAIN (a) = TREE_PURPOSE (t); + a = TREE_PURPOSE (t); + } + /* More attrs can be linked here, move A to the end. */ + while (TREE_CHAIN (a) != NULL_TREE) + a = TREE_CHAIN (a); + } + } + + /* Terminate the lists. */ + if (s != NULL_TREE) + TREE_CHAIN (s) = NULL_TREE; + if (a != NULL_TREE) + TREE_CHAIN (a) = NULL_TREE; + + /* All done. */ + *declspecs = specs; + *prefix_attributes = attrs; +} + +/* Strip attributes from SPECS_ATTRS, a list of declspecs and attributes. + This function is used by the parser when a rule will accept attributes + in a particular position, but we don't want to support that just yet. + + A warning is issued for every ignored attribute. */ + +tree +strip_attrs (specs_attrs) + tree specs_attrs; +{ + tree specs, attrs; + + split_specs_attrs (specs_attrs, &specs, &attrs); + + while (attrs) + { + warning ("`%s' attribute ignored", + IDENTIFIER_POINTER (TREE_PURPOSE (attrs))); + attrs = TREE_CHAIN (attrs); + } + + return specs; +} + +/* Check a printf/fprintf/sprintf/scanf/fscanf/sscanf format against + a parameter list. */ + +#define T_I &integer_type_node +#define T_L &long_integer_type_node +#define T_LL &long_long_integer_type_node +#define T_S &short_integer_type_node +#define T_UI &unsigned_type_node +#define T_UL &long_unsigned_type_node +#define T_ULL &long_long_unsigned_type_node +#define T_US &short_unsigned_type_node +#define T_F &float_type_node +#define T_D &double_type_node +#define T_LD &long_double_type_node +#define T_C &char_type_node +#define T_UC &unsigned_char_type_node +#define T_V &void_type_node +#define T_W &wchar_type_node +#define T_ST &sizetype + +typedef struct { + char *format_chars; + int pointer_count; + /* Type of argument if no length modifier is used. */ + tree *nolen; + /* Type of argument if length modifier for shortening to byte is used. + If NULL, then this modifier is not allowed. */ + tree *hhlen; + /* Type of argument if length modifier for shortening is used. + If NULL, then this modifier is not allowed. */ + tree *hlen; + /* Type of argument if length modifier `l' is used. + If NULL, then this modifier is not allowed. */ + tree *llen; + /* Type of argument if length modifier `q' or `ll' is used. + If NULL, then this modifier is not allowed. */ + tree *qlen; + /* Type of argument if length modifier `L' is used. + If NULL, then this modifier is not allowed. */ + tree *bigllen; + /* Type of argument if length modifier `Z' is used. + If NULL, then this modifier is not allowed. */ + tree *zlen; + /* List of other modifier characters allowed with these options. */ + char *flag_chars; +} format_char_info; + +static format_char_info print_char_table[] = { + { "di", 0, T_I, T_I, T_I, T_L, T_LL, T_LL, T_ST, "-wp0 +" }, + { "oxX", 0, T_UI, T_UI, T_UI, T_UL, T_ULL, T_ULL, T_ST, "-wp0#" }, + { "u", 0, T_UI, T_UI, T_UI, T_UL, T_ULL, T_ULL, T_ST, "-wp0" }, +/* A GNU extension. */ + { "m", 0, T_V, NULL, NULL, NULL, NULL, NULL, NULL, "-wp" }, + { "feEgGaA", 0, T_D, NULL, NULL, NULL, NULL, T_LD, NULL, "-wp0 +#" }, + { "c", 0, T_I, NULL, NULL, T_W, NULL, NULL, NULL, "-w" }, + { "C", 0, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "-w" }, + { "s", 1, T_C, NULL, NULL, T_W, NULL, NULL, NULL, "-wp" }, + { "S", 1, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "-wp" }, + { "p", 1, T_V, NULL, NULL, NULL, NULL, NULL, NULL, "-w" }, + { "n", 1, T_I, NULL, T_S, T_L, T_LL, NULL, NULL, "" }, + { NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } +}; + +static format_char_info scan_char_table[] = { + { "di", 1, T_I, T_C, T_S, T_L, T_LL, T_LL, NULL, "*" }, + { "ouxX", 1, T_UI, T_UC, T_US, T_UL, T_ULL, T_ULL, NULL, "*" }, + { "efgEGaA", 1, T_F, NULL, NULL, T_D, NULL, T_LD, NULL, "*" }, + { "c", 1, T_C, NULL, NULL, T_W, NULL, NULL, NULL, "*" }, + { "s", 1, T_C, NULL, NULL, T_W, NULL, NULL, NULL, "*a" }, + { "[", 1, T_C, NULL, NULL, NULL, NULL, NULL, NULL, "*a" }, + { "C", 1, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "*" }, + { "S", 1, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "*a" }, + { "p", 2, T_V, NULL, NULL, NULL, NULL, NULL, NULL, "*" }, + { "n", 1, T_I, T_C, T_S, T_L, T_LL, NULL, NULL, "" }, + { NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } +}; + +/* Handle format characters recognized by glibc's strftime.c. + '2' - MUST do years as only two digits + '3' - MAY do years as only two digits (depending on locale) + 'E' - E modifier is acceptable + 'O' - O modifier is acceptable to Standard C + 'o' - O modifier is acceptable as a GNU extension + 'G' - other GNU extensions */ + +static format_char_info time_char_table[] = { + { "y", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "2EO-_0w" }, + { "D", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "2" }, + { "g", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "2O-_0w" }, + { "cx", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "3E" }, + { "%RTXnrt", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "" }, + { "P", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "G" }, + { "HIMSUWdemw", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0Ow" }, + { "Vju", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0Oow" }, + { "Gklsz", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0OGw" }, + { "ABZa", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "^#" }, + { "p", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "#" }, + { "bh", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "^" }, + { "CY", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0EOw" }, + { NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } +}; + +typedef struct function_format_info +{ + struct function_format_info *next; /* next structure on the list */ + tree name; /* identifier such as "printf" */ + tree assembler_name; /* optional mangled identifier (for C++) */ + enum format_type format_type; /* type of format (printf, scanf, etc.) */ + int format_num; /* number of format argument */ + int first_arg_num; /* number of first arg (zero for varargs) */ +} function_format_info; + +static function_format_info *function_format_list = NULL; + +typedef struct international_format_info +{ + struct international_format_info *next; /* next structure on the list */ + tree name; /* identifier such as "gettext" */ + tree assembler_name; /* optional mangled identifier (for C++) */ + int format_num; /* number of format argument */ +} international_format_info; + +static international_format_info *international_format_list = NULL; + +static void check_format_info PROTO((function_format_info *, tree)); + +/* Initialize the table of functions to perform format checking on. + The ANSI functions are always checked (whether is + included or not), since it is common to call printf without + including . There shouldn't be a problem with this, + since ANSI reserves these function names whether you include the + header file or not. In any case, the checking is harmless. + + Also initialize the name of function that modify the format string for + internationalization purposes. */ + +void +init_function_format_info () +{ + record_function_format (get_identifier ("printf"), NULL_TREE, + printf_format_type, 1, 2); + record_function_format (get_identifier ("fprintf"), NULL_TREE, + printf_format_type, 2, 3); + record_function_format (get_identifier ("sprintf"), NULL_TREE, + printf_format_type, 2, 3); + record_function_format (get_identifier ("scanf"), NULL_TREE, + scanf_format_type, 1, 2); + record_function_format (get_identifier ("fscanf"), NULL_TREE, + scanf_format_type, 2, 3); + record_function_format (get_identifier ("sscanf"), NULL_TREE, + scanf_format_type, 2, 3); + record_function_format (get_identifier ("vprintf"), NULL_TREE, + printf_format_type, 1, 0); + record_function_format (get_identifier ("vfprintf"), NULL_TREE, + printf_format_type, 2, 0); + record_function_format (get_identifier ("vsprintf"), NULL_TREE, + printf_format_type, 2, 0); + record_function_format (get_identifier ("strftime"), NULL_TREE, + strftime_format_type, 3, 0); +} + +/* Record information for argument format checking. FUNCTION_IDENT is + the identifier node for the name of the function to check (its decl + need not exist yet). + FORMAT_TYPE specifies the type of format checking. FORMAT_NUM is the number + of the argument which is the format control string (starting from 1). + FIRST_ARG_NUM is the number of the first actual argument to check + against the format string, or zero if no checking is not be done + (e.g. for varargs such as vfprintf). */ + +static void +record_function_format (name, assembler_name, format_type, + format_num, first_arg_num) + tree name; + tree assembler_name; + enum format_type format_type; + int format_num; + int first_arg_num; +{ + function_format_info *info; + + /* Re-use existing structure if it's there. */ + + for (info = function_format_list; info; info = info->next) + { + if (info->name == name && info->assembler_name == assembler_name) + break; + } + if (! info) + { + info = (function_format_info *) xmalloc (sizeof (function_format_info)); + info->next = function_format_list; + function_format_list = info; + + info->name = name; + info->assembler_name = assembler_name; + } + + info->format_type = format_type; + info->format_num = format_num; + info->first_arg_num = first_arg_num; +} + +/* Record information for the names of function that modify the format + argument to format functions. FUNCTION_IDENT is the identifier node for + the name of the function (its decl need not exist yet) and FORMAT_NUM is + the number of the argument which is the format control string (starting + from 1). */ + +static void +record_international_format (name, assembler_name, format_num) + tree name; + tree assembler_name; + int format_num; +{ + international_format_info *info; + + /* Re-use existing structure if it's there. */ + + for (info = international_format_list; info; info = info->next) + { + if (info->name == name && info->assembler_name == assembler_name) + break; + } + + if (! info) + { + info + = (international_format_info *) + xmalloc (sizeof (international_format_info)); + info->next = international_format_list; + international_format_list = info; + + info->name = name; + info->assembler_name = assembler_name; + } + + info->format_num = format_num; +} + +static char tfaff[] = "too few arguments for format"; + +/* Check the argument list of a call to printf, scanf, etc. + NAME is the function identifier. + ASSEMBLER_NAME is the function's assembler identifier. + (Either NAME or ASSEMBLER_NAME, but not both, may be NULL_TREE.) + PARAMS is the list of argument values. */ + +void +check_function_format (name, assembler_name, params) + tree name; + tree assembler_name; + tree params; +{ + function_format_info *info; + + /* See if this function is a format function. */ + for (info = function_format_list; info; info = info->next) + { + if (info->assembler_name + ? (info->assembler_name == assembler_name) + : (info->name == name)) + { + /* Yup; check it. */ + check_format_info (info, params); + break; + } + } +} + +/* Check the argument list of a call to printf, scanf, etc. + INFO points to the function_format_info structure. + PARAMS is the list of argument values. */ + +static void +check_format_info (info, params) + function_format_info *info; + tree params; +{ + int i; + int arg_num; + int suppressed, wide, precise; + int length_char = 0; + int format_char; + int format_length; + tree format_tree; + tree cur_param; + tree cur_type; + tree wanted_type; + tree first_fillin_param; + char *format_chars; + format_char_info *fci = NULL; + char flag_chars[8]; + int has_operand_number = 0; + + /* Skip to format argument. If the argument isn't available, there's + no work for us to do; prototype checking will catch the problem. */ + for (arg_num = 1; ; ++arg_num) + { + if (params == 0) + return; + if (arg_num == info->format_num) + break; + params = TREE_CHAIN (params); + } + format_tree = TREE_VALUE (params); + params = TREE_CHAIN (params); + if (format_tree == 0) + return; + + /* We can only check the format if it's a string constant. */ + while (TREE_CODE (format_tree) == NOP_EXPR) + format_tree = TREE_OPERAND (format_tree, 0); /* strip coercion */ + + if (TREE_CODE (format_tree) == CALL_EXPR + && TREE_CODE (TREE_OPERAND (format_tree, 0)) == ADDR_EXPR + && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (format_tree, 0), 0)) + == FUNCTION_DECL)) + { + tree function = TREE_OPERAND (TREE_OPERAND (format_tree, 0), 0); + + /* See if this is a call to a known internationalization function + that modifies the format arg. */ + international_format_info *info; + + for (info = international_format_list; info; info = info->next) + if (info->assembler_name + ? (info->assembler_name == DECL_ASSEMBLER_NAME (function)) + : (info->name == DECL_NAME (function))) + { + tree inner_args; + int i; + + for (inner_args = TREE_OPERAND (format_tree, 1), i = 1; + inner_args != 0; + inner_args = TREE_CHAIN (inner_args), i++) + if (i == info->format_num) + { + format_tree = TREE_VALUE (inner_args); + + while (TREE_CODE (format_tree) == NOP_EXPR) + format_tree = TREE_OPERAND (format_tree, 0); + } + } + } + + if (integer_zerop (format_tree)) + { + warning ("null format string"); + return; + } + if (TREE_CODE (format_tree) != ADDR_EXPR) + return; + format_tree = TREE_OPERAND (format_tree, 0); + if (TREE_CODE (format_tree) != STRING_CST) + return; + format_chars = TREE_STRING_POINTER (format_tree); + format_length = TREE_STRING_LENGTH (format_tree); + if (format_length <= 1) + warning ("zero-length format string"); + if (format_chars[--format_length] != 0) + { + warning ("unterminated format string"); + return; + } + /* Skip to first argument to check. */ + while (arg_num + 1 < info->first_arg_num) + { + if (params == 0) + return; + params = TREE_CHAIN (params); + ++arg_num; + } + + first_fillin_param = params; + while (1) + { + int aflag; + if (*format_chars == 0) + { + if (format_chars - TREE_STRING_POINTER (format_tree) != format_length) + warning ("embedded `\\0' in format"); + if (info->first_arg_num != 0 && params != 0 && ! has_operand_number) + warning ("too many arguments for format"); + return; + } + if (*format_chars++ != '%') + continue; + if (*format_chars == 0) + { + warning ("spurious trailing `%%' in format"); + continue; + } + if (*format_chars == '%') + { + ++format_chars; + continue; + } + flag_chars[0] = 0; + suppressed = wide = precise = FALSE; + if (info->format_type == scanf_format_type) + { + suppressed = *format_chars == '*'; + if (suppressed) + ++format_chars; + while (ISDIGIT (*format_chars)) + ++format_chars; + } + else if (info->format_type == strftime_format_type) + { + while (*format_chars != 0 && index ("_-0^#", *format_chars) != 0) + { + if (pedantic) + warning ("ANSI C does not support the strftime `%c' flag", + *format_chars); + if (index (flag_chars, *format_chars) != 0) + { + warning ("repeated `%c' flag in format", + *format_chars); + ++format_chars; + } + else + { + i = strlen (flag_chars); + flag_chars[i++] = *format_chars++; + flag_chars[i] = 0; + } + } + while (ISDIGIT ((unsigned char) *format_chars)) + { + wide = TRUE; + ++format_chars; + } + if (wide && pedantic) + warning ("ANSI C does not support strftime format width"); + if (*format_chars == 'E' || *format_chars == 'O') + { + i = strlen (flag_chars); + flag_chars[i++] = *format_chars++; + flag_chars[i] = 0; + if (*format_chars == 'E' || *format_chars == 'O') + { + warning ("multiple E/O modifiers in format"); + while (*format_chars == 'E' || *format_chars == 'O') + ++format_chars; + } + } + } + else if (info->format_type == printf_format_type) + { + /* See if we have a number followed by a dollar sign. If we do, + it is an operand number, so set PARAMS to that operand. */ + if (*format_chars >= '0' && *format_chars <= '9') + { + char *p = format_chars; + + while (*p >= '0' && *p++ <= '9') + ; + + if (*p == '$') + { + int opnum = atoi (format_chars); + + params = first_fillin_param; + format_chars = p + 1; + has_operand_number = 1; + + for (i = 1; i < opnum && params != 0; i++) + params = TREE_CHAIN (params); + + if (opnum == 0 || params == 0) + { + warning ("operand number out of range in format"); + return; + } + } + } + + while (*format_chars != 0 && index (" +#0-", *format_chars) != 0) + { + if (index (flag_chars, *format_chars) != 0) + warning ("repeated `%c' flag in format", *format_chars++); + else + { + i = strlen (flag_chars); + flag_chars[i++] = *format_chars++; + flag_chars[i] = 0; + } + } + /* "If the space and + flags both appear, + the space flag will be ignored." */ + if (index (flag_chars, ' ') != 0 + && index (flag_chars, '+') != 0) + warning ("use of both ` ' and `+' flags in format"); + /* "If the 0 and - flags both appear, + the 0 flag will be ignored." */ + if (index (flag_chars, '0') != 0 + && index (flag_chars, '-') != 0) + warning ("use of both `0' and `-' flags in format"); + if (*format_chars == '*') + { + wide = TRUE; + /* "...a field width...may be indicated by an asterisk. + In this case, an int argument supplies the field width..." */ + ++format_chars; + if (params == 0) + { + warning (tfaff); + return; + } + if (info->first_arg_num != 0) + { + cur_param = TREE_VALUE (params); + params = TREE_CHAIN (params); + ++arg_num; + /* size_t is generally not valid here. + It will work on most machines, because size_t and int + have the same mode. But might as well warn anyway, + since it will fail on other machines. */ + if ((TYPE_MAIN_VARIANT (TREE_TYPE (cur_param)) + != integer_type_node) + && + (TYPE_MAIN_VARIANT (TREE_TYPE (cur_param)) + != unsigned_type_node)) + warning ("field width is not type int (arg %d)", arg_num); + } + } + else + { + while (ISDIGIT (*format_chars)) + { + wide = TRUE; + ++format_chars; + } + } + if (*format_chars == '.') + { + precise = TRUE; + ++format_chars; + if (*format_chars != '*' && !ISDIGIT (*format_chars)) + warning ("`.' not followed by `*' or digit in format"); + /* "...a...precision...may be indicated by an asterisk. + In this case, an int argument supplies the...precision." */ + if (*format_chars == '*') + { + if (info->first_arg_num != 0) + { + ++format_chars; + if (params == 0) + { + warning (tfaff); + return; + } + cur_param = TREE_VALUE (params); + params = TREE_CHAIN (params); + ++arg_num; + if (TYPE_MAIN_VARIANT (TREE_TYPE (cur_param)) + != integer_type_node) + warning ("field width is not type int (arg %d)", + arg_num); + } + } + else + { + while (ISDIGIT (*format_chars)) + ++format_chars; + } + } + } + + aflag = 0; + + if (info->format_type != strftime_format_type) + { + if (*format_chars == 'h' || *format_chars == 'l') + length_char = *format_chars++; + else if (*format_chars == 'q' || *format_chars == 'L') + { + length_char = *format_chars++; + if (pedantic) + warning ("ANSI C does not support the `%c' length modifier", + length_char); + } + else if (*format_chars == 'Z') + { + length_char = *format_chars++; + if (pedantic) + warning ("ANSI C does not support the `Z' length modifier"); + } + else + length_char = 0; + if (length_char == 'l' && *format_chars == 'l') + { + length_char = 'q', format_chars++; + /* FIXME: Is allowed in ISO C 9x. */ + if (pedantic) + warning ("ANSI C does not support the `ll' length modifier"); + } + else if (length_char == 'h' && *format_chars == 'h') + { + length_char = 'H', format_chars++; + /* FIXME: Is allowed in ISO C 9x. */ + if (pedantic) + warning ("ANSI C does not support the `hh' length modifier"); + } + if (*format_chars == 'a' && info->format_type == scanf_format_type) + { + if (format_chars[1] == 's' || format_chars[1] == 'S' + || format_chars[1] == '[') + { + /* `a' is used as a flag. */ + aflag = 1; + format_chars++; + } + } + if (suppressed && length_char != 0) + warning ("use of `*' and `%c' together in format", length_char); + } + format_char = *format_chars; + if (format_char == 0 + || (info->format_type != strftime_format_type && format_char == '%')) + { + warning ("conversion lacks type at end of format"); + continue; + } + /* The m, C, and S formats are GNU extensions. */ + if (pedantic && info->format_type != strftime_format_type + && (format_char == 'm' || format_char == 'C' || format_char == 'S')) + warning ("ANSI C does not support the `%c' format", format_char); + /* ??? The a and A formats are C9X extensions, and should be allowed + when a C9X option is added. */ + if (pedantic && info->format_type != strftime_format_type + && (format_char == 'a' || format_char == 'A')) + warning ("ANSI C does not support the `%c' format", format_char); + format_chars++; + switch (info->format_type) + { + case printf_format_type: + fci = print_char_table; + break; + case scanf_format_type: + fci = scan_char_table; + break; + case strftime_format_type: + fci = time_char_table; + break; + default: + abort (); + } + while (fci->format_chars != 0 + && index (fci->format_chars, format_char) == 0) + ++fci; + if (fci->format_chars == 0) + { + if (format_char >= 040 && format_char < 0177) + warning ("unknown conversion type character `%c' in format", + format_char); + else + warning ("unknown conversion type character 0x%x in format", + format_char); + continue; + } + if (pedantic) + { + if (index (fci->flag_chars, 'G') != 0) + warning ("ANSI C does not support `%%%c'", format_char); + if (index (fci->flag_chars, 'o') != 0 + && index (flag_chars, 'O') != 0) + warning ("ANSI C does not support `%%O%c'", format_char); + } + if (wide && index (fci->flag_chars, 'w') == 0) + warning ("width used with `%c' format", format_char); + if (index (fci->flag_chars, '2') != 0) + warning ("`%%%c' yields only last 2 digits of year", format_char); + else if (index (fci->flag_chars, '3') != 0) + warning ("`%%%c' yields only last 2 digits of year in some locales", + format_char); + if (precise && index (fci->flag_chars, 'p') == 0) + warning ("precision used with `%c' format", format_char); + if (aflag && index (fci->flag_chars, 'a') == 0) + { + warning ("`a' flag used with `%c' format", format_char); + /* To simplify the following code. */ + aflag = 0; + } + /* The a flag is a GNU extension. */ + else if (pedantic && aflag) + warning ("ANSI C does not support the `a' flag"); + if (info->format_type == scanf_format_type && format_char == '[') + { + /* Skip over scan set, in case it happens to have '%' in it. */ + if (*format_chars == '^') + ++format_chars; + /* Find closing bracket; if one is hit immediately, then + it's part of the scan set rather than a terminator. */ + if (*format_chars == ']') + ++format_chars; + while (*format_chars && *format_chars != ']') + ++format_chars; + if (*format_chars != ']') + /* The end of the format string was reached. */ + warning ("no closing `]' for `%%[' format"); + } + if (suppressed) + { + if (index (fci->flag_chars, '*') == 0) + warning ("suppression of `%c' conversion in format", format_char); + continue; + } + for (i = 0; flag_chars[i] != 0; ++i) + { + if (index (fci->flag_chars, flag_chars[i]) == 0) + warning ("flag `%c' used with type `%c'", + flag_chars[i], format_char); + } + if (info->format_type == strftime_format_type) + continue; + if (precise && index (flag_chars, '0') != 0 + && (format_char == 'd' || format_char == 'i' + || format_char == 'o' || format_char == 'u' + || format_char == 'x' || format_char == 'X')) + warning ("`0' flag ignored with precision specifier and `%c' format", + format_char); + switch (length_char) + { + default: wanted_type = fci->nolen ? *(fci->nolen) : 0; break; + case 'H': wanted_type = fci->hhlen ? *(fci->hhlen) : 0; break; + case 'h': wanted_type = fci->hlen ? *(fci->hlen) : 0; break; + case 'l': wanted_type = fci->llen ? *(fci->llen) : 0; break; + case 'q': wanted_type = fci->qlen ? *(fci->qlen) : 0; break; + case 'L': wanted_type = fci->bigllen ? *(fci->bigllen) : 0; break; + case 'Z': wanted_type = fci->zlen ? *fci->zlen : 0; break; + } + if (wanted_type == 0) + warning ("use of `%c' length character with `%c' type character", + length_char, format_char); + + /* Finally. . .check type of argument against desired type! */ + if (info->first_arg_num == 0) + continue; + if (fci->pointer_count == 0 && wanted_type == void_type_node) + /* This specifier takes no argument. */ + continue; + if (params == 0) + { + warning (tfaff); + return; + } + cur_param = TREE_VALUE (params); + params = TREE_CHAIN (params); + ++arg_num; + cur_type = TREE_TYPE (cur_param); + + STRIP_NOPS (cur_param); + + /* Check the types of any additional pointer arguments + that precede the "real" argument. */ + for (i = 0; i < fci->pointer_count + aflag; ++i) + { + if (TREE_CODE (cur_type) == POINTER_TYPE) + { + cur_type = TREE_TYPE (cur_type); + + if (cur_param != 0 && TREE_CODE (cur_param) == ADDR_EXPR) + cur_param = TREE_OPERAND (cur_param, 0); + else + cur_param = 0; + + continue; + } + if (TREE_CODE (cur_type) != ERROR_MARK) + warning ("format argument is not a %s (arg %d)", + ((fci->pointer_count + aflag == 1) + ? "pointer" : "pointer to a pointer"), + arg_num); + break; + } + + /* See if this is an attempt to write into a const type with + scanf or with printf "%n". */ + if ((info->format_type == scanf_format_type + || (info->format_type == printf_format_type + && format_char == 'n')) + && i == fci->pointer_count + aflag + && wanted_type != 0 + && TREE_CODE (cur_type) != ERROR_MARK + && (TYPE_READONLY (cur_type) + || (cur_param != 0 + && (TREE_CODE_CLASS (TREE_CODE (cur_param)) == 'c' + || (TREE_CODE_CLASS (TREE_CODE (cur_param)) == 'd' + && TREE_READONLY (cur_param)))))) + warning ("writing into constant object (arg %d)", arg_num); + + /* Check the type of the "real" argument, if there's a type we want. */ + if (i == fci->pointer_count + aflag && wanted_type != 0 + && TREE_CODE (cur_type) != ERROR_MARK + && wanted_type != TYPE_MAIN_VARIANT (cur_type) + /* If we want `void *', allow any pointer type. + (Anything else would already have got a warning.) */ + && ! (wanted_type == void_type_node + && fci->pointer_count > 0) + /* Don't warn about differences merely in signedness. */ + && !(TREE_CODE (wanted_type) == INTEGER_TYPE + && TREE_CODE (TYPE_MAIN_VARIANT (cur_type)) == INTEGER_TYPE + && (TREE_UNSIGNED (wanted_type) + ? wanted_type == (cur_type = unsigned_type (cur_type)) + : wanted_type == (cur_type = signed_type (cur_type)))) + /* Likewise, "signed char", "unsigned char" and "char" are + equivalent but the above test won't consider them equivalent. */ + && ! (wanted_type == char_type_node + && (TYPE_MAIN_VARIANT (cur_type) == signed_char_type_node + || TYPE_MAIN_VARIANT (cur_type) == unsigned_char_type_node))) + { + register char *this; + register char *that; + + this = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (wanted_type))); + that = 0; + if (TREE_CODE (cur_type) != ERROR_MARK + && TYPE_NAME (cur_type) != 0 + && TREE_CODE (cur_type) != INTEGER_TYPE + && !(TREE_CODE (cur_type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (cur_type)) == INTEGER_TYPE)) + { + if (TREE_CODE (TYPE_NAME (cur_type)) == TYPE_DECL + && DECL_NAME (TYPE_NAME (cur_type)) != 0) + that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (cur_type))); + else + that = IDENTIFIER_POINTER (TYPE_NAME (cur_type)); + } + + /* 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 (cur_type) == POINTER_TYPE) + that = "pointer"; + else + that = "different type"; + } + + /* Make the warning better in case of mismatch of int vs long. */ + if (TREE_CODE (cur_type) == INTEGER_TYPE + && TREE_CODE (wanted_type) == INTEGER_TYPE + && TYPE_PRECISION (cur_type) == TYPE_PRECISION (wanted_type) + && TYPE_NAME (cur_type) != 0 + && TREE_CODE (TYPE_NAME (cur_type)) == TYPE_DECL) + that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (cur_type))); + + if (strcmp (this, that) != 0) + warning ("%s format, %s arg (arg %d)", this, that, arg_num); + } + } +} + +/* Print a warning if a constant expression had overflow in folding. + Invoke this function on every expression that the language + requires to be a constant expression. + Note the ANSI C standard says it is erroneous for a + constant expression to overflow. */ + +void +constant_expression_warning (value) + tree value; +{ + if ((TREE_CODE (value) == INTEGER_CST || TREE_CODE (value) == REAL_CST + || TREE_CODE (value) == COMPLEX_CST) + && TREE_CONSTANT_OVERFLOW (value) && pedantic) + pedwarn ("overflow in constant expression"); +} + +/* Print a warning if an expression had overflow in folding. + Invoke this function on every expression that + (1) appears in the source code, and + (2) might be a constant expression that overflowed, and + (3) is not already checked by convert_and_check; + however, do not invoke this function on operands of explicit casts. */ + +void +overflow_warning (value) + tree value; +{ + if ((TREE_CODE (value) == INTEGER_CST + || (TREE_CODE (value) == COMPLEX_CST + && TREE_CODE (TREE_REALPART (value)) == INTEGER_CST)) + && TREE_OVERFLOW (value)) + { + TREE_OVERFLOW (value) = 0; + if (skip_evaluation == 0) + warning ("integer overflow in expression"); + } + else if ((TREE_CODE (value) == REAL_CST + || (TREE_CODE (value) == COMPLEX_CST + && TREE_CODE (TREE_REALPART (value)) == REAL_CST)) + && TREE_OVERFLOW (value)) + { + TREE_OVERFLOW (value) = 0; + if (skip_evaluation == 0) + warning ("floating point overflow in expression"); + } +} + +/* Print a warning if a large constant is truncated to unsigned, + or if -Wconversion is used and a constant < 0 is converted to unsigned. + Invoke this function on every expression that might be implicitly + converted to an unsigned type. */ + +void +unsigned_conversion_warning (result, operand) + tree result, operand; +{ + if (TREE_CODE (operand) == INTEGER_CST + && TREE_CODE (TREE_TYPE (result)) == INTEGER_TYPE + && TREE_UNSIGNED (TREE_TYPE (result)) + && skip_evaluation == 0 + && !int_fits_type_p (operand, TREE_TYPE (result))) + { + if (!int_fits_type_p (operand, signed_type (TREE_TYPE (result)))) + /* This detects cases like converting -129 or 256 to unsigned char. */ + warning ("large integer implicitly truncated to unsigned type"); + else if (warn_conversion) + warning ("negative integer implicitly converted to unsigned type"); + } +} + +/* Convert EXPR to TYPE, warning about conversion problems with constants. + Invoke this function on every expression that is converted implicitly, + i.e. because of language rules and not because of an explicit cast. */ + +tree +convert_and_check (type, expr) + tree type, expr; +{ + tree t = convert (type, expr); + if (TREE_CODE (t) == INTEGER_CST) + { + if (TREE_OVERFLOW (t)) + { + TREE_OVERFLOW (t) = 0; + + /* Do not diagnose overflow in a constant expression merely + because a conversion overflowed. */ + TREE_CONSTANT_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (expr); + + /* No warning for converting 0x80000000 to int. */ + 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 + || TREE_UNSIGNED (type) + || ! int_fits_type_p (expr, unsigned_type (type))) + && skip_evaluation == 0) + warning ("overflow in implicit constant conversion"); + } + else + unsigned_conversion_warning (t, expr); + } + return t; +} + +void +c_expand_expr_stmt (expr) + tree expr; +{ + /* Do default conversion if safe and possibly important, + in case within ({...}). */ + if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE && lvalue_p (expr)) + || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE) + expr = default_conversion (expr); + + if (TREE_TYPE (expr) != error_mark_node + && TYPE_SIZE (TREE_TYPE (expr)) == 0 + && TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE) + error ("expression statement has incomplete type"); + + expand_expr_stmt (expr); +} + +/* Validate the expression after `case' and apply default promotions. */ + +tree +check_case_value (value) + tree value; +{ + if (value == NULL_TREE) + return value; + + /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ + STRIP_TYPE_NOPS (value); + + 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; +} + +/* Return an integer type with BITS bits of precision, + that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */ + +tree +type_for_size (bits, unsignedp) + unsigned bits; + int unsignedp; +{ + if (bits == TYPE_PRECISION (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + + if (bits == TYPE_PRECISION (signed_char_type_node)) + return unsignedp ? unsigned_char_type_node : signed_char_type_node; + + if (bits == TYPE_PRECISION (short_integer_type_node)) + return unsignedp ? short_unsigned_type_node : short_integer_type_node; + + if (bits == TYPE_PRECISION (long_integer_type_node)) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + + if (bits == TYPE_PRECISION (long_long_integer_type_node)) + return (unsignedp ? long_long_unsigned_type_node + : long_long_integer_type_node); + + if (bits <= TYPE_PRECISION (intQI_type_node)) + return unsignedp ? unsigned_intQI_type_node : intQI_type_node; + + if (bits <= TYPE_PRECISION (intHI_type_node)) + return unsignedp ? unsigned_intHI_type_node : intHI_type_node; + + if (bits <= TYPE_PRECISION (intSI_type_node)) + return unsignedp ? unsigned_intSI_type_node : intSI_type_node; + + if (bits <= TYPE_PRECISION (intDI_type_node)) + return unsignedp ? unsigned_intDI_type_node : intDI_type_node; + + return 0; +} + +/* Return a data type that has machine mode MODE. + If the mode is an integer, + then UNSIGNEDP selects between signed and unsigned types. */ + +tree +type_for_mode (mode, unsignedp) + enum machine_mode mode; + int unsignedp; +{ + if (mode == TYPE_MODE (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + + if (mode == TYPE_MODE (signed_char_type_node)) + return unsignedp ? unsigned_char_type_node : signed_char_type_node; + + if (mode == TYPE_MODE (short_integer_type_node)) + return unsignedp ? short_unsigned_type_node : short_integer_type_node; + + if (mode == TYPE_MODE (long_integer_type_node)) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + + if (mode == TYPE_MODE (long_long_integer_type_node)) + return unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node; + + if (mode == TYPE_MODE (intQI_type_node)) + return unsignedp ? unsigned_intQI_type_node : intQI_type_node; + + if (mode == TYPE_MODE (intHI_type_node)) + return unsignedp ? unsigned_intHI_type_node : intHI_type_node; + + if (mode == TYPE_MODE (intSI_type_node)) + return unsignedp ? unsigned_intSI_type_node : intSI_type_node; + + if (mode == TYPE_MODE (intDI_type_node)) + return unsignedp ? unsigned_intDI_type_node : intDI_type_node; + +#if HOST_BITS_PER_WIDE_INT >= 64 + if (mode == TYPE_MODE (intTI_type_node)) + return unsignedp ? unsigned_intTI_type_node : intTI_type_node; +#endif + + if (mode == TYPE_MODE (float_type_node)) + return float_type_node; + + if (mode == TYPE_MODE (double_type_node)) + return double_type_node; + + if (mode == TYPE_MODE (long_double_type_node)) + return long_double_type_node; + + if (mode == TYPE_MODE (build_pointer_type (char_type_node))) + return build_pointer_type (char_type_node); + + if (mode == TYPE_MODE (build_pointer_type (integer_type_node))) + return build_pointer_type (integer_type_node); + + return 0; +} + +/* Return the minimum number of bits needed to represent VALUE in a + signed or unsigned type, UNSIGNEDP says which. */ + +int +min_precision (value, unsignedp) + tree value; + int unsignedp; +{ + int log; + + /* If the value is negative, compute its negative minus 1. The latter + adjustment is because the absolute value of the largest negative value + is one larger than the largest positive value. This is equivalent to + 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)); + + /* Return the number of bits needed, taking into account the fact + that we need one more bit for a signed than unsigned type. */ + + if (integer_zerop (value)) + log = 0; + else if (TREE_INT_CST_HIGH (value) != 0) + log = HOST_BITS_PER_WIDE_INT + floor_log2 (TREE_INT_CST_HIGH (value)); + else + log = floor_log2 (TREE_INT_CST_LOW (value)); + + return log + 1 + ! unsignedp; +} + +/* Print an error message for invalid operands to arith operation CODE. + NOP_EXPR is used as a special case (see truthvalue_conversion). */ + +void +binary_op_error (code) + enum tree_code code; +{ + register char *opname; + + switch (code) + { + case NOP_EXPR: + error ("invalid truth-value expression"); + return; + + case PLUS_EXPR: + opname = "+"; break; + case MINUS_EXPR: + opname = "-"; break; + case MULT_EXPR: + opname = "*"; break; + case MAX_EXPR: + opname = "max"; break; + case MIN_EXPR: + opname = "min"; break; + case EQ_EXPR: + opname = "=="; break; + case NE_EXPR: + opname = "!="; break; + case LE_EXPR: + opname = "<="; break; + case GE_EXPR: + opname = ">="; break; + case LT_EXPR: + opname = "<"; break; + case GT_EXPR: + opname = ">"; break; + case LSHIFT_EXPR: + opname = "<<"; break; + case RSHIFT_EXPR: + opname = ">>"; break; + case TRUNC_MOD_EXPR: + case FLOOR_MOD_EXPR: + opname = "%"; break; + case TRUNC_DIV_EXPR: + case FLOOR_DIV_EXPR: + opname = "/"; break; + case BIT_AND_EXPR: + opname = "&"; break; + case BIT_IOR_EXPR: + opname = "|"; break; + case TRUTH_ANDIF_EXPR: + opname = "&&"; break; + case TRUTH_ORIF_EXPR: + opname = "||"; break; + case BIT_XOR_EXPR: + opname = "^"; break; + case LROTATE_EXPR: + case RROTATE_EXPR: + opname = "rotate"; break; + default: + opname = "unknown"; break; + } + error ("invalid operands to binary %s", opname); +} + +/* Subroutine of build_binary_op, used for comparison operations. + See if the operands have both been converted from subword integer types + and, if so, perhaps change them both back to their original type. + This function is also responsible for converting the two operands + to the proper common type for comparison. + + The arguments of this function are all pointers to local variables + of build_binary_op: OP0_PTR is &OP0, OP1_PTR is &OP1, + RESTYPE_PTR is &RESULT_TYPE and RESCODE_PTR is &RESULTCODE. + + If this function returns nonzero, it means that the comparison has + a constant value. What this function returns is an expression for + that value. */ + +tree +shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr) + tree *op0_ptr, *op1_ptr; + tree *restype_ptr; + enum tree_code *rescode_ptr; +{ + register tree type; + tree op0 = *op0_ptr; + tree op1 = *op1_ptr; + int unsignedp0, unsignedp1; + int real1, real2; + tree primop0, primop1; + enum tree_code code = *rescode_ptr; + + /* Throw away any conversions to wider types + already present in the operands. */ + + primop0 = get_narrower (op0, &unsignedp0); + primop1 = get_narrower (op1, &unsignedp1); + + /* Handle the case that OP0 does not *contain* a conversion + but it *requires* conversion to FINAL_TYPE. */ + + if (op0 == primop0 && TREE_TYPE (op0) != *restype_ptr) + unsignedp0 = TREE_UNSIGNED (TREE_TYPE (op0)); + if (op1 == primop1 && TREE_TYPE (op1) != *restype_ptr) + 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; + real2 = TREE_CODE (TREE_TYPE (primop1)) == REAL_TYPE; + + /* If first arg is constant, swap the args (changing operation + so value is preserved), for canonicalization. Don't do this if + the second arg is 0. */ + + if (TREE_CONSTANT (primop0) + && ! integer_zerop (primop1) && ! real_zerop (primop1)) + { + register tree tem = primop0; + register int temi = unsignedp0; + primop0 = primop1; + primop1 = tem; + tem = op0; + op0 = op1; + op1 = tem; + *op0_ptr = op0; + *op1_ptr = op1; + unsignedp0 = unsignedp1; + unsignedp1 = temi; + temi = real1; + real1 = real2; + real2 = temi; + + switch (code) + { + case LT_EXPR: + code = GT_EXPR; + break; + case GT_EXPR: + code = LT_EXPR; + break; + case LE_EXPR: + code = GE_EXPR; + break; + case GE_EXPR: + code = LE_EXPR; + break; + default: + break; + } + *rescode_ptr = code; + } + + /* If comparing an integer against a constant more bits wide, + maybe we can deduce a value of 1 or 0 independent of the data. + Or else truncate the constant now + rather than extend the variable at run time. + + This is only interesting if the constant is the wider arg. + Also, it is not safe if the constant is unsigned and the + variable arg is signed, since in this case the variable + would be sign-extended and then regarded as unsigned. + Our technique fails in this case because the lowest/highest + possible unsigned results don't follow naturally from the + lowest/highest possible values of the variable operand. + For just EQ_EXPR and NE_EXPR there is another technique that + could be used: see if the constant can be faithfully represented + in the other operand's type, by truncating it and reextending it + and see if that preserves the constant's value. */ + + if (!real1 && !real2 + && TREE_CODE (primop1) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr)) + { + int min_gt, max_gt, min_lt, max_lt; + tree maxval, minval; + /* 1 if comparison is nominally unsigned. */ + int unsignedp = TREE_UNSIGNED (*restype_ptr); + tree val; + + type = signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0)); + + maxval = TYPE_MAX_VALUE (type); + minval = TYPE_MIN_VALUE (type); + + if (unsignedp && !unsignedp0) + *restype_ptr = signed_type (*restype_ptr); + + if (TREE_TYPE (primop1) != *restype_ptr) + primop1 = convert (*restype_ptr, primop1); + if (type != *restype_ptr) + { + minval = convert (*restype_ptr, minval); + maxval = convert (*restype_ptr, maxval); + } + + if (unsignedp && unsignedp0) + { + min_gt = INT_CST_LT_UNSIGNED (primop1, minval); + max_gt = INT_CST_LT_UNSIGNED (primop1, maxval); + min_lt = INT_CST_LT_UNSIGNED (minval, primop1); + max_lt = INT_CST_LT_UNSIGNED (maxval, primop1); + } + else + { + min_gt = INT_CST_LT (primop1, minval); + max_gt = INT_CST_LT (primop1, maxval); + min_lt = INT_CST_LT (minval, primop1); + max_lt = INT_CST_LT (maxval, primop1); + } + + val = 0; + /* This used to be a switch, but Genix compiler can't handle that. */ + if (code == NE_EXPR) + { + if (max_lt || min_gt) + val = boolean_true_node; + } + else if (code == EQ_EXPR) + { + if (max_lt || min_gt) + val = boolean_false_node; + } + else if (code == LT_EXPR) + { + if (max_lt) + val = boolean_true_node; + if (!min_lt) + val = boolean_false_node; + } + else if (code == GT_EXPR) + { + if (min_gt) + val = boolean_true_node; + if (!max_gt) + val = boolean_false_node; + } + else if (code == LE_EXPR) + { + if (!max_gt) + val = boolean_true_node; + if (min_gt) + val = boolean_false_node; + } + else if (code == GE_EXPR) + { + if (!min_lt) + val = boolean_true_node; + if (max_lt) + val = boolean_false_node; + } + + /* If primop0 was sign-extended and unsigned comparison specd, + we did a signed comparison above using the signed type bounds. + But the comparison we output must be unsigned. + + Also, for inequalities, VAL is no good; but if the signed + comparison had *any* fixed result, it follows that the + unsigned comparison just tests the sign in reverse + (positive values are LE, negative ones GE). + So we can generate an unsigned comparison + against an extreme value of the signed type. */ + + if (unsignedp && !unsignedp0) + { + if (val != 0) + switch (code) + { + case LT_EXPR: + case GE_EXPR: + primop1 = TYPE_MIN_VALUE (type); + val = 0; + break; + + case LE_EXPR: + case GT_EXPR: + primop1 = TYPE_MAX_VALUE (type); + val = 0; + break; + + default: + break; + } + type = unsigned_type (type); + } + + if (!max_gt && !unsignedp0 && TREE_CODE (primop0) != INTEGER_CST) + { + /* This is the case of (char)x >?< 0x80, which people used to use + expecting old C compilers to change the 0x80 into -0x80. */ + if (val == boolean_false_node) + warning ("comparison is always false due to limited range of data type"); + if (val == boolean_true_node) + warning ("comparison is always true due to limited range of data type"); + } + + if (!min_lt && unsignedp0 && TREE_CODE (primop0) != INTEGER_CST) + { + /* This is the case of (unsigned char)x >?< -1 or < 0. */ + if (val == boolean_false_node) + warning ("comparison is always false due to limited range of data type"); + if (val == boolean_true_node) + 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 build (COMPOUND_EXPR, TREE_TYPE (val), primop0, val); + return val; + } + + /* Value is not predetermined, but do the comparison + in the type of the operand that is not constant. + TYPE is already properly set. */ + } + else if (real1 && real2 + && (TYPE_PRECISION (TREE_TYPE (primop0)) + == TYPE_PRECISION (TREE_TYPE (primop1)))) + type = TREE_TYPE (primop0); + + /* If args' natural types are both narrower than nominal type + and both extend in the same manner, compare them + in the type of the wider arg. + Otherwise must actually extend both to the nominal + common type lest different ways of extending + alter the result. + (eg, (short)-1 == (unsigned short)-1 should be 0.) */ + + else if (unsignedp0 == unsignedp1 && real1 == real2 + && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr) + && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr)) + { + type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1)); + type = signed_or_unsigned_type (unsignedp0 + || TREE_UNSIGNED (*restype_ptr), + type); + /* Make sure shorter operand is extended the right way + to match the longer operand. */ + primop0 = convert (signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0)), + primop0); + primop1 = convert (signed_or_unsigned_type (unsignedp1, TREE_TYPE (primop1)), + primop1); + } + else + { + /* Here we must do the comparison on the nominal type + using the args exactly as we received them. */ + type = *restype_ptr; + primop0 = op0; + primop1 = op1; + + if (!real1 && !real2 && integer_zerop (primop1) + && TREE_UNSIGNED (*restype_ptr)) + { + tree value = 0; + switch (code) + { + case GE_EXPR: + /* All unsigned values are >= 0, so we warn if extra warnings + are requested. However, if OP0 is a constant that is + >= 0, the signedness of the comparison isn't an issue, + so suppress the warning. */ + if (extra_warnings + && ! (TREE_CODE (primop0) == INTEGER_CST + && ! TREE_OVERFLOW (convert (signed_type (type), + primop0)))) + warning ("comparison of unsigned expression >= 0 is always true"); + value = boolean_true_node; + break; + + case LT_EXPR: + if (extra_warnings + && ! (TREE_CODE (primop0) == INTEGER_CST + && ! TREE_OVERFLOW (convert (signed_type (type), + primop0)))) + warning ("comparison of unsigned expression < 0 is always false"); + value = boolean_false_node; + break; + + default: + break; + } + + if (value != 0) + { + /* Don't forget to evaluate PRIMOP0 if it has side effects. */ + if (TREE_SIDE_EFFECTS (primop0)) + return build (COMPOUND_EXPR, TREE_TYPE (value), + primop0, value); + return value; + } + } + } + + *op0_ptr = convert (type, primop0); + *op1_ptr = convert (type, primop1); + + *restype_ptr = boolean_type_node; + + return 0; +} + +/* Prepare expr to be an argument of a TRUTH_NOT_EXPR, + 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 + boolean expression describing whether expr is nonzero. We could + simply always do build_binary_op (NE_EXPR, expr, boolean_false_node, 1), + but we optimize comparisons, &&, ||, and !. + + The resulting type should always be `boolean_type_node'. */ + +tree +truthvalue_conversion (expr) + tree expr; +{ + if (TREE_CODE (expr) == ERROR_MARK) + return expr; + +#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 RECORD_TYPE: + error ("struct type value used where scalar is required"); + return boolean_false_node; + + case UNION_TYPE: + error ("union type value used where scalar is required"); + return boolean_false_node; + + case ARRAY_TYPE: + error ("array type value used where scalar is required"); + return boolean_false_node; + + default: + break; + } +#endif /* 0 */ + + switch (TREE_CODE (expr)) + { + /* It is simpler and generates better code to have only TRUTH_*_EXPR + or comparison expressions as truth values at this level. */ +#if 0 + case COMPONENT_REF: + /* A one-bit unsigned bit-field is already acceptable. */ + if (1 == TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (expr, 1))) + && TREE_UNSIGNED (TREE_OPERAND (expr, 1))) + return expr; + break; +#endif + + case EQ_EXPR: + /* It is simpler and generates better code to have only TRUTH_*_EXPR + or comparison expressions as truth values at this level. */ +#if 0 + if (integer_zerop (TREE_OPERAND (expr, 1))) + return build_unary_op (TRUTH_NOT_EXPR, TREE_OPERAND (expr, 0), 0); +#endif + 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: + case TRUTH_NOT_EXPR: + TREE_TYPE (expr) = boolean_type_node; + return expr; + + case ERROR_MARK: + return expr; + + case INTEGER_CST: + return integer_zerop (expr) ? boolean_false_node : boolean_true_node; + + case REAL_CST: + return real_zerop (expr) ? boolean_false_node : boolean_true_node; + + case ADDR_EXPR: + /* If we are taking the address of a external decl, it might be zero + if it is weak, so we cannot optimize. */ + if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (expr, 0))) == 'd' + && DECL_EXTERNAL (TREE_OPERAND (expr, 0))) + break; + + if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0))) + return build (COMPOUND_EXPR, boolean_type_node, + TREE_OPERAND (expr, 0), boolean_true_node); + else + return boolean_true_node; + + case COMPLEX_EXPR: + return build_binary_op ((TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)) + ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR), + truthvalue_conversion (TREE_OPERAND (expr, 0)), + truthvalue_conversion (TREE_OPERAND (expr, 1)), + 0); + + case NEGATE_EXPR: + case ABS_EXPR: + case FLOAT_EXPR: + case FFS_EXPR: + /* These don't change whether an object is non-zero or zero. */ + return truthvalue_conversion (TREE_OPERAND (expr, 0)); + + case LROTATE_EXPR: + case RROTATE_EXPR: + /* These don't change whether an object is zero or non-zero, but + we can't ignore them if their second arg has side-effects. */ + if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))) + return build (COMPOUND_EXPR, boolean_type_node, TREE_OPERAND (expr, 1), + truthvalue_conversion (TREE_OPERAND (expr, 0))); + else + return truthvalue_conversion (TREE_OPERAND (expr, 0)); + + case COND_EXPR: + /* Distribute the conversion into the arms of a COND_EXPR. */ + return fold (build (COND_EXPR, boolean_type_node, TREE_OPERAND (expr, 0), + truthvalue_conversion (TREE_OPERAND (expr, 1)), + truthvalue_conversion (TREE_OPERAND (expr, 2)))); + + case CONVERT_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 truthvalue_conversion (TREE_OPERAND (expr, 0)); + break; + + case MINUS_EXPR: + /* With IEEE arithmetic, x - x may not equal 0, so we can't optimize + this case. */ + if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT + && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE) + 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) != boolean_type_node) + /* Using convert here would cause infinite recursion. */ + return build1 (NOP_EXPR, boolean_type_node, expr); + break; + + case MODIFY_EXPR: + if (warn_parentheses && C_EXP_ORIGINAL_CODE (expr) == MODIFY_EXPR) + warning ("suggest parentheses around assignment used as truth value"); + break; + + default: + break; + } + + if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE) + { + tree tem = save_expr (expr); + return (build_binary_op + ((TREE_SIDE_EFFECTS (expr) + ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR), + truthvalue_conversion (build_unary_op (REALPART_EXPR, tem, 0)), + truthvalue_conversion (build_unary_op (IMAGPART_EXPR, tem, 0)), + 0)); + } + + return build_binary_op (NE_EXPR, expr, integer_zero_node, 1); +} + +#if USE_CPPLIB +/* Read the rest of a #-directive from input stream FINPUT. + In normal use, the directive name and the white space after it + have already been read, so they won't be included in the result. + We allow for the fact that the directive line may contain + a newline embedded within a character or string literal which forms + a part of the directive. + + The value is a string in a reusable buffer. It remains valid + only until the next time this function is called. */ +unsigned char *yy_cur, *yy_lim; + +#define GETC() (yy_cur < yy_lim ? *yy_cur++ : yy_get_token ()) +#define UNGETC(c) ((c), yy_cur--) + +int +yy_get_token () +{ + for (;;) + { + parse_in.limit = parse_in.token_buffer; + cpp_token = cpp_get_token (&parse_in); + if (cpp_token == CPP_EOF) + return -1; + yy_lim = CPP_PWRITTEN (&parse_in); + yy_cur = parse_in.token_buffer; + if (yy_cur < yy_lim) + return *yy_cur++; + } +} + +char * +get_directive_line () +{ + static char *directive_buffer = NULL; + static unsigned buffer_length = 0; + register char *p; + register char *buffer_limit; + register int looking_for = 0; + register int char_escaped = 0; + + if (buffer_length == 0) + { + directive_buffer = (char *)xmalloc (128); + buffer_length = 128; + } + + buffer_limit = &directive_buffer[buffer_length]; + + for (p = directive_buffer; ; ) + { + int c; + + /* Make buffer bigger if it is full. */ + if (p >= buffer_limit) + { + register unsigned bytes_used = (p - directive_buffer); + + buffer_length *= 2; + directive_buffer + = (char *)xrealloc (directive_buffer, buffer_length); + p = &directive_buffer[bytes_used]; + buffer_limit = &directive_buffer[buffer_length]; + } + + c = GETC (); + + /* Discard initial whitespace. */ + if ((c == ' ' || c == '\t') && p == directive_buffer) + continue; + + /* Detect the end of the directive. */ + if (c == '\n' && looking_for == 0) + { + UNGETC (c); + c = '\0'; + } + + *p++ = c; + + if (c == 0) + return directive_buffer; + + /* Handle string and character constant syntax. */ + if (looking_for) + { + if (looking_for == c && !char_escaped) + looking_for = 0; /* Found terminator... stop looking. */ + } + else + if (c == '\'' || c == '"') + looking_for = c; /* Don't stop buffering until we see another + another one of these (or an EOF). */ + + /* Handle backslash. */ + char_escaped = (c == '\\' && ! char_escaped); + } +} +#else +/* Read the rest of a #-directive from input stream FINPUT. + In normal use, the directive name and the white space after it + have already been read, so they won't be included in the result. + We allow for the fact that the directive line may contain + a newline embedded within a character or string literal which forms + a part of the directive. + + The value is a string in a reusable buffer. It remains valid + only until the next time this function is called. + + The terminating character ('\n' or EOF) is left in FINPUT for the + caller to re-read. */ + +char * +get_directive_line (finput) + register FILE *finput; +{ + static char *directive_buffer = NULL; + static unsigned buffer_length = 0; + register char *p; + register char *buffer_limit; + register int looking_for = 0; + register int char_escaped = 0; + + if (buffer_length == 0) + { + directive_buffer = (char *)xmalloc (128); + buffer_length = 128; + } + + buffer_limit = &directive_buffer[buffer_length]; + + for (p = directive_buffer; ; ) + { + int c; + + /* Make buffer bigger if it is full. */ + if (p >= buffer_limit) + { + register unsigned bytes_used = (p - directive_buffer); + + buffer_length *= 2; + directive_buffer + = (char *)xrealloc (directive_buffer, buffer_length); + p = &directive_buffer[bytes_used]; + buffer_limit = &directive_buffer[buffer_length]; + } + + c = getc (finput); + + /* Discard initial whitespace. */ + if ((c == ' ' || c == '\t') && p == directive_buffer) + continue; + + /* Detect the end of the directive. */ + if (looking_for == 0 + && (c == '\n' || c == EOF)) + { + ungetc (c, finput); + c = '\0'; + } + + *p++ = c; + + if (c == 0) + return directive_buffer; + + /* Handle string and character constant syntax. */ + if (looking_for) + { + if (looking_for == c && !char_escaped) + looking_for = 0; /* Found terminator... stop looking. */ + } + else + if (c == '\'' || c == '"') + looking_for = c; /* Don't stop buffering until we see another + one of these (or an EOF). */ + + /* Handle backslash. */ + char_escaped = (c == '\\' && ! char_escaped); + } +} +#endif /* !USE_CPPLIB */ + +/* Make a variant type in the proper way for C/C++, propagating qualifiers + down to the element type of an array. */ + +tree +c_build_qualified_type (type, type_quals) + tree type; + int type_quals; +{ + /* A restrict-qualified pointer type must be a pointer to object or + incomplete type. Note that the use of POINTER_TYPE_P also allows + REFERENCE_TYPEs, which is appropriate for C++. Unfortunately, + the C++ front-end also use POINTER_TYPE for pointer-to-member + values, so even though it should be illegal to use `restrict' + with such an entity we don't flag that here. Thus, special case + code for that case is required in the C++ front-end. */ + if ((type_quals & TYPE_QUAL_RESTRICT) + && (!POINTER_TYPE_P (type) + || !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type)))) + { + error ("invalid use of `restrict'"); + type_quals &= ~TYPE_QUAL_RESTRICT; + } + + if (TREE_CODE (type) == ARRAY_TYPE) + return build_array_type (c_build_qualified_type (TREE_TYPE (type), + type_quals), + TYPE_DOMAIN (type)); + return build_qualified_type (type, type_quals); +} + +/* Apply the TYPE_QUALS to the new DECL. */ + +void +c_apply_type_quals_to_decl (type_quals, decl) + int type_quals; + tree decl; +{ + if (type_quals & TYPE_QUAL_CONST) + TREE_READONLY (decl) = 1; + if (type_quals & TYPE_QUAL_VOLATILE) + { + TREE_SIDE_EFFECTS (decl) = 1; + TREE_THIS_VOLATILE (decl) = 1; + } + if (type_quals & TYPE_QUAL_RESTRICT) + { + if (!TREE_TYPE (decl) + || !POINTER_TYPE_P (TREE_TYPE (decl)) + || !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (TREE_TYPE (decl)))) + error ("invalid use of `restrict'"); + else if (flag_strict_aliasing) + { + /* No two restricted pointers can point at the same thing. + However, a restricted pointer can point at the same thing + as an unrestricted pointer, if that unrestricted pointer + is based on the restricted pointer. So, we make the + alias set for the restricted pointer a subset of the + alias set for the type pointed to by the type of the + decl. */ + + int pointed_to_alias_set + = get_alias_set (TREE_TYPE (TREE_TYPE (decl))); + + if (!pointed_to_alias_set) + /* It's not legal to make a subset of alias set zero. */ + ; + else + { + DECL_POINTER_ALIAS_SET (decl) = new_alias_set (); + record_alias_subset (pointed_to_alias_set, + DECL_POINTER_ALIAS_SET (decl)); + } + } + } +} + +/* T is an expression with pointer type. Find the DECL on which this + expression is based. (For example, in `a[i]' this would be `a'.) + If there is no such DECL, or a unique decl cannot be determined, + NULL_TREE is retured. */ + +static tree +c_find_base_decl (t) + tree t; +{ + int i; + tree decl; + + if (t == NULL_TREE || t == error_mark_node) + return NULL_TREE; + + if (!POINTER_TYPE_P (TREE_TYPE (t))) + return NULL_TREE; + + decl = NULL_TREE; + + if (TREE_CODE (t) == FIELD_DECL + || TREE_CODE (t) == PARM_DECL + || TREE_CODE (t) == VAR_DECL) + /* Aha, we found a pointer-typed declaration. */ + return t; + + /* It would be nice to deal with COMPONENT_REFs here. If we could + tell that `a' and `b' were the same, then `a->f' and `b->f' are + also the same. */ + + /* Handle general expressions. */ + switch (TREE_CODE_CLASS (TREE_CODE (t))) + { + case '1': + case '2': + case '3': + for (i = tree_code_length [(int) TREE_CODE (t)]; --i >= 0;) + { + tree d = c_find_base_decl (TREE_OPERAND (t, i)); + if (d) + { + if (!decl) + decl = d; + else if (d && d != decl) + /* Two different declarations. That's confusing; let's + just assume we don't know what's going on. */ + decl = NULL_TREE; + } + } + break; + + default: + break; + } + + return decl; +} + +/* Return the typed-based alias set for T, which may be an expression + or a type. */ + +int +c_get_alias_set (t) + tree t; +{ + tree type; + tree u; + + if (t == error_mark_node) + return 0; + + type = (TREE_CODE_CLASS (TREE_CODE (t)) == 't') + ? t : TREE_TYPE (t); + + if (type == error_mark_node) + return 0; + + /* Deal with special cases first; for certain kinds of references + we're interested in more than just the type. */ + + if (TREE_CODE (t) == BIT_FIELD_REF) + /* Perhaps reads and writes to this piece of data alias fields + neighboring the bitfield. Perhaps that's impossible. For now, + let's just assume that bitfields can alias everything, which is + the conservative assumption. */ + return 0; + + /* Permit type-punning when accessing a union, provided the access + is directly through the union. For example, this code does not + permit taking the address of a union member and then storing + through it. Even the type-punning allowed here is a GCC + extension, albeit a common and useful one; the C standard says + that such accesses have implementation-defined behavior. */ + for (u = t; + TREE_CODE (u) == COMPONENT_REF || TREE_CODE (u) == ARRAY_REF; + u = TREE_OPERAND (u, 0)) + if (TREE_CODE (u) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (TREE_OPERAND (u, 0))) == UNION_TYPE) + return 0; + + if (TREE_CODE (t) == INDIRECT_REF) + { + /* Check for accesses through restrict-qualified pointers. */ + tree decl = c_find_base_decl (TREE_OPERAND (t, 0)); + + if (decl && DECL_POINTER_ALIAS_SET_KNOWN_P (decl)) + /* We use the alias set indicated in the declaration. */ + return DECL_POINTER_ALIAS_SET (decl); + } + + /* From here on, only the type matters. */ + + if (TREE_CODE (t) == COMPONENT_REF + && DECL_BIT_FIELD_TYPE (TREE_OPERAND (t, 1))) + /* Since build_modify_expr calls get_unwidened for stores to + component references, the type of a bit field can be changed + from (say) `unsigned int : 16' to `unsigned short' or from + `enum E : 16' to `short'. We want the real type of the + bit-field in this case, not some the integral equivalent. */ + type = DECL_BIT_FIELD_TYPE (TREE_OPERAND (t, 1)); + + if (TYPE_ALIAS_SET_KNOWN_P (type)) + /* If we've already calculated the value, just return it. */ + return TYPE_ALIAS_SET (type); + else if (TYPE_MAIN_VARIANT (type) != type) + /* The C standard specifically allows aliasing between + cv-qualified variants of types. */ + TYPE_ALIAS_SET (type) = c_get_alias_set (TYPE_MAIN_VARIANT (type)); + else if (TREE_CODE (type) == INTEGER_TYPE) + { + tree signed_variant; + + /* The C standard specifically allows aliasing between signed and + unsigned variants of the same type. We treat the signed + variant as canonical. */ + signed_variant = signed_type (type); + + if (signed_variant != type) + TYPE_ALIAS_SET (type) = c_get_alias_set (signed_variant); + else if (signed_variant == signed_char_type_node) + /* The C standard guarantess that any object may be accessed + via an lvalue that has character type. We don't have to + check for unsigned_char_type_node or char_type_node because + we are specifically looking at the signed variant. */ + TYPE_ALIAS_SET (type) = 0; + } + else if (TREE_CODE (type) == ARRAY_TYPE) + /* Anything that can alias one of the array elements can alias + the entire array as well. */ + TYPE_ALIAS_SET (type) = c_get_alias_set (TREE_TYPE (type)); + else if (TREE_CODE (type) == FUNCTION_TYPE) + /* There are no objects of FUNCTION_TYPE, so there's no point in + using up an alias set for them. (There are, of course, + pointers and references to functions, but that's + different.) */ + TYPE_ALIAS_SET (type) = 0; + else if (TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE) + /* If TYPE is a struct or union type then we're reading or + writing an entire struct. Thus, we don't know anything about + aliasing. (In theory, such an access can only alias objects + whose type is the same as one of the fields, recursively, but + we don't yet make any use of that information.) */ + TYPE_ALIAS_SET (type) = 0; + + if (!TYPE_ALIAS_SET_KNOWN_P (type)) + /* TYPE is something we haven't seen before. Put it in a new + alias set. */ + TYPE_ALIAS_SET (type) = new_alias_set (); + + return TYPE_ALIAS_SET (type); +} diff --git a/gcc_arm/c-convert.c b/gcc_arm/c-convert.c new file mode 100755 index 0000000..9cb9416 --- /dev/null +++ b/gcc_arm/c-convert.c @@ -0,0 +1,97 @@ +/* Language-level data type conversion for GNU C. + Copyright (C) 1987, 1988, 1991, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* This file contains the functions for converting C expressions + to different data types. The only entry point is `convert'. + Every language front end must have a `convert' function + but what kind of conversions it does will depend on the language. */ + +#include "config.h" +#include "tree.h" +#include "flags.h" +#include "convert.h" +#include "toplev.h" + +/* Change of width--truncation and extension of integers or reals-- + is represented with NOP_EXPR. Proper functioning of many things + assumes that no other conversions can be NOP_EXPRs. + + Conversion between integer and pointer is represented with CONVERT_EXPR. + Converting integer to real uses FLOAT_EXPR + and real to integer uses FIX_TRUNC_EXPR. + + Here is a list of all the functions that assume that widening and + narrowing is always done with a NOP_EXPR: + In convert.c, convert_to_integer. + In c-typeck.c, build_binary_op (boolean ops), and truthvalue_conversion. + In expr.c: expand_expr, for operands of a MULT_EXPR. + In fold-const.c: fold. + In tree.c: get_narrower and get_unwidened. */ + +/* Subroutines of `convert'. */ + + + +/* Create an expression whose value is that of EXPR, + converted to type TYPE. The TREE_TYPE of the value + is always TYPE. This function implements all reasonable + conversions; callers should filter out those that are + not permitted by the language being compiled. */ + +tree +convert (type, expr) + tree type, expr; +{ + register tree e = expr; + register enum tree_code code = TREE_CODE (type); + + if (type == TREE_TYPE (expr) + || TREE_CODE (expr) == ERROR_MARK) + return expr; + if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr))) + return fold (build1 (NOP_EXPR, type, expr)); + if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK) + return error_mark_node; + if (TREE_CODE (TREE_TYPE (expr)) == VOID_TYPE) + { + error ("void value not ignored as it ought to be"); + return error_mark_node; + } + if (code == VOID_TYPE) + return build1 (CONVERT_EXPR, type, e); +#if 0 + /* This is incorrect. A truncation can't be stripped this way. + Extensions will be stripped by the use of get_unwidened. */ + if (TREE_CODE (expr) == NOP_EXPR) + return convert (type, TREE_OPERAND (expr, 0)); +#endif + if (code == INTEGER_TYPE || code == ENUMERAL_TYPE) + return fold (convert_to_integer (type, e)); + if (code == POINTER_TYPE) + return fold (convert_to_pointer (type, e)); + if (code == REAL_TYPE) + return fold (convert_to_real (type, e)); + if (code == COMPLEX_TYPE) + return fold (convert_to_complex (type, e)); + + error ("conversion to non-scalar type requested"); + return error_mark_node; +} diff --git a/gcc_arm/c-decl.c b/gcc_arm/c-decl.c new file mode 100755 index 0000000..2469655 --- /dev/null +++ b/gcc_arm/c-decl.c @@ -0,0 +1,7458 @@ +/* Process declarations and variables for C compiler. + Copyright (C) 1988, 92-97, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* Process declarations and symbol lookup for C front end. + Also constructs types; the standard scalar types at initialization, + and structure, union, array and enum types when they are declared. */ + +/* ??? not all decl nodes are given the most useful possible + line numbers. For example, the CONST_DECLs for enum values. */ + +#include "config.h" +#include "system.h" +#include "tree.h" +#include "flags.h" +#include "output.h" +#include "c-tree.h" +#include "c-lex.h" +#include "toplev.h" + +#if USE_CPPLIB +#include "cpplib.h" +extern cpp_reader parse_in; +#endif + +/* In grokdeclarator, distinguish syntactic contexts of declarators. */ +enum decl_context +{ NORMAL, /* Ordinary declaration */ + FUNCDEF, /* Function definition */ + PARM, /* Declaration of parm before function body */ + FIELD, /* Declaration inside struct or union */ + BITFIELD, /* Likewise but with specified width */ + TYPENAME}; /* Typename (inside cast or sizeof) */ + +#ifndef CHAR_TYPE_SIZE +#define CHAR_TYPE_SIZE BITS_PER_UNIT +#endif + +#ifndef SHORT_TYPE_SIZE +#define SHORT_TYPE_SIZE (BITS_PER_UNIT * MIN ((UNITS_PER_WORD + 1) / 2, 2)) +#endif + +#ifndef INT_TYPE_SIZE +#define INT_TYPE_SIZE BITS_PER_WORD +#endif + +#ifndef LONG_TYPE_SIZE +#define LONG_TYPE_SIZE BITS_PER_WORD +#endif + +#ifndef LONG_LONG_TYPE_SIZE +#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2) +#endif + +#ifndef WCHAR_UNSIGNED +#define WCHAR_UNSIGNED 0 +#endif + +#ifndef FLOAT_TYPE_SIZE +#define FLOAT_TYPE_SIZE BITS_PER_WORD +#endif + +#ifndef DOUBLE_TYPE_SIZE +#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2) +#endif + +#ifndef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2) +#endif + +/* We let tm.h override the types used here, to handle trivial differences + such as the choice of unsigned int or long unsigned int for size_t. + When machines start needing nontrivial differences in the size type, + it would be best to do something here to figure out automatically + from other information what type to use. */ + +#ifndef SIZE_TYPE +#define SIZE_TYPE "long unsigned int" +#endif + +#ifndef PTRDIFF_TYPE +#define PTRDIFF_TYPE "long int" +#endif + +#ifndef WCHAR_TYPE +#define WCHAR_TYPE "int" +#endif + +/* a node which has tree code ERROR_MARK, and whose type is itself. + All erroneous expressions are replaced with this node. All functions + that accept nodes as arguments should avoid generating error messages + if this node is one of the arguments, since it is undesirable to get + multiple error messages from one error in the input. */ + +tree error_mark_node; + +/* INTEGER_TYPE and REAL_TYPE nodes for the standard data types */ + +tree short_integer_type_node; +tree integer_type_node; +tree long_integer_type_node; +tree long_long_integer_type_node; + +tree short_unsigned_type_node; +tree unsigned_type_node; +tree long_unsigned_type_node; +tree long_long_unsigned_type_node; + +tree boolean_type_node; +tree boolean_false_node; +tree boolean_true_node; + +tree ptrdiff_type_node; + +tree unsigned_char_type_node; +tree signed_char_type_node; +tree char_type_node; +tree wchar_type_node; +tree signed_wchar_type_node; +tree unsigned_wchar_type_node; + +tree float_type_node; +tree double_type_node; +tree long_double_type_node; + +tree complex_integer_type_node; +tree complex_float_type_node; +tree complex_double_type_node; +tree complex_long_double_type_node; + +tree intQI_type_node; +tree intHI_type_node; +tree intSI_type_node; +tree intDI_type_node; +#if HOST_BITS_PER_WIDE_INT >= 64 +tree intTI_type_node; +#endif + +tree unsigned_intQI_type_node; +tree unsigned_intHI_type_node; +tree unsigned_intSI_type_node; +tree unsigned_intDI_type_node; +#if HOST_BITS_PER_WIDE_INT >= 64 +tree unsigned_intTI_type_node; +#endif + +/* a VOID_TYPE node. */ + +tree void_type_node; + +/* Nodes for types `void *' and `const void *'. */ + +tree ptr_type_node, const_ptr_type_node; + +/* Nodes for types `char *' and `const char *'. */ + +tree string_type_node, const_string_type_node; + +/* Type `char[SOMENUMBER]'. + Used when an array of char is needed and the size is irrelevant. */ + +tree char_array_type_node; + +/* Type `int[SOMENUMBER]' or something like it. + Used when an array of int needed and the size is irrelevant. */ + +tree int_array_type_node; + +/* Type `wchar_t[SOMENUMBER]' or something like it. + Used when a wide string literal is created. */ + +tree wchar_array_type_node; + +/* type `int ()' -- used for implicit declaration of functions. */ + +tree default_function_type; + +/* function types `double (double)' and `double (double, double)', etc. */ + +tree double_ftype_double, double_ftype_double_double; +tree int_ftype_int, long_ftype_long; +tree float_ftype_float; +tree ldouble_ftype_ldouble; + +/* Function type `void (void *, void *, int)' and similar ones */ + +tree void_ftype_ptr_ptr_int, int_ftype_ptr_ptr_int, void_ftype_ptr_int_int; + +/* Function type `char *(char *, char *)' and similar ones */ +tree string_ftype_ptr_ptr, int_ftype_string_string; + +/* Function type `int (const void *, const void *, size_t)' */ +tree int_ftype_cptr_cptr_sizet; + +/* Two expressions that are constants with value zero. + The first is of type `int', the second of type `void *'. */ + +tree integer_zero_node; +tree null_pointer_node; + +/* A node for the integer constant 1. */ + +tree integer_one_node; + +/* 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; +/* File and line to appear in the eventual error message. */ +char *pending_invalid_xref_file; +int pending_invalid_xref_line; + +/* 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 + occur in an enum value expression and we don't use these variables in + that case. */ + +static tree enum_next_value; + +/* Nonzero means that there was overflow computing enum_next_value. */ + +static int enum_overflow; + +/* Parsing a function declarator leaves a list of parameter names + or a chain or parameter decls here. */ + +static tree last_function_parms; + +/* Parsing a function declarator leaves here a chain of structure + and enum types declared in the parmlist. */ + +static tree last_function_parm_tags; + +/* After parsing the declarator that starts a function definition, + `start_function' puts here the list of parameter names or chain of decls. + `store_parm_decls' finds it here. */ + +static tree current_function_parms; + +/* Similar, for last_function_parm_tags. */ +static tree current_function_parm_tags; + +/* Similar, for the file and line that the prototype came from if this is + an old-style definition. */ +static char *current_function_prototype_file; +static int current_function_prototype_line; + +/* A list (chain of TREE_LIST nodes) 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. */ + +static tree named_labels; + +/* A list of LABEL_DECLs from outer contexts that are currently shadowed. */ + +static tree shadowed_labels; + +/* Nonzero when store_parm_decls is called indicates a varargs function. + Value not meaningful after store_parm_decls. */ + +static int c_function_varargs; + +/* The FUNCTION_DECL for the function currently being compiled, + or 0 if between functions. */ +tree current_function_decl; + +/* Set to 0 at beginning of a function definition, set to 1 if + a return statement that specifies a return value is seen. */ + +int current_function_returns_value; + +/* Set to 0 at beginning of a function definition, set to 1 if + a return statement with no argument is seen. */ + +int current_function_returns_null; + +/* Set to nonzero by `grokdeclarator' for a function + whose return type is defaulted, if warnings for this are desired. */ + +static int warn_about_return_type; + +/* Nonzero when starting a function declared `extern inline'. */ + +static int current_extern_inline; + +/* For each binding contour we allocate a binding_level structure + * which records the names defined in that contour. + * Contours include: + * 0) the global one + * 1) one for each function definition, + * where internal declarations of the parameters appear. + * 2) one for each compound statement, + * to record its declarations. + * + * The current meaning of a name can be found by searching the levels from + * the current one out to the global one. + */ + +/* Note that the information in the `names' component of the global contour + is duplicated in the IDENTIFIER_GLOBAL_VALUEs of all identifiers. */ + +struct binding_level + { + /* A chain of _DECL nodes for all variables, constants, functions, + and typedef types. These are in the reverse of the order supplied. + */ + tree names; + + /* A list of structure, union and enum definitions, + * for looking up tag names. + * It is a chain of TREE_LIST nodes, each of whose TREE_PURPOSE is a name, + * or NULL_TREE; and whose TREE_VALUE is a RECORD_TYPE, UNION_TYPE, + * or ENUMERAL_TYPE node. + */ + tree tags; + + /* For each level, a list of shadowed outer-level local definitions + to be restored when this level 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 level (except not the global one), + a chain of BLOCK nodes for all the levels + that were entered and exited one level down. */ + tree blocks; + + /* The BLOCK node for this level, if one has been preallocated. + If 0, the BLOCK is allocated (if needed) when the level is popped. */ + tree this_block; + + /* The binding level which this one is contained in (inherits from). */ + struct binding_level *level_chain; + + /* Nonzero for the level that holds the parameters of a function. */ + char parm_flag; + + /* Nonzero if this level "doesn't exist" for tags. */ + char tag_transparent; + + /* Nonzero if sublevels of this level "don't exist" for tags. + This is set in the parm level of a function definition + while reading the function body, so that the outermost block + of the function body will be tag-transparent. */ + char subblocks_tag_transparent; + + /* Nonzero means make a BLOCK for this level regardless of all else. */ + char keep; + + /* Nonzero means make a BLOCK if this level has any subblocks. */ + char keep_if_subblocks; + + /* Number of decls in `names' that have incomplete + structure or union types. */ + int n_incomplete; + + /* A list of decls giving the (reversed) specified order of parms, + not including any forward-decls in the parmlist. + This is so we can put the parms in proper order for assign_parms. */ + tree parm_order; + }; + +#define NULL_BINDING_LEVEL (struct binding_level *) NULL + +/* The binding level currently in effect. */ + +static struct binding_level *current_binding_level; + +/* A chain of binding_level structures awaiting reuse. */ + +static struct binding_level *free_binding_level; + +/* The outermost binding level, for names of file scope. + This is created when the compiler is started and exists + through the entire run. */ + +static struct binding_level *global_binding_level; + +/* Binding level structures are initialized by copying this one. */ + +static struct binding_level clear_binding_level + = {NULL, NULL, NULL, NULL, NULL, NULL_BINDING_LEVEL, 0, 0, 0, 0, 0, 0, + NULL}; + +/* Nonzero means unconditionally make a BLOCK for the next level pushed. */ + +static int keep_next_level_flag; + +/* Nonzero means make a BLOCK for the next level pushed + if it has subblocks. */ + +static int keep_next_if_subblocks; + +/* The chain of outer levels of label scopes. + This uses the same data structure used for binding levels, + but it works differently: each link in the chain records + saved values of named_labels and shadowed_labels for + a label binding level outside the current one. */ + +static struct binding_level *label_level_chain; + +/* Functions called automatically at the beginning and end of execution. */ + +tree static_ctors, static_dtors; + +/* Forward declarations. */ + +static struct binding_level * make_binding_level PROTO((void)); +static void clear_limbo_values PROTO((tree)); +static int duplicate_decls PROTO((tree, tree, int)); +static char *redeclaration_error_message PROTO((tree, tree)); +static void storedecls PROTO((tree)); +static void storetags PROTO((tree)); +static tree lookup_tag PROTO((enum tree_code, tree, + struct binding_level *, int)); +static tree lookup_tag_reverse PROTO((tree)); +static tree grokdeclarator PROTO((tree, tree, enum decl_context, + int)); +static tree grokparms PROTO((tree, int)); +static int field_decl_cmp PROTO((const GENERIC_PTR, const GENERIC_PTR)); +static void layout_array_type PROTO((tree)); + +/* C-specific option variables. */ + +/* Nonzero means allow type mismatches in conditional expressions; + just make their values `void'. */ + +int flag_cond_mismatch; + +/* Nonzero means give `double' the same size as `float'. */ + +int flag_short_double; + +/* Nonzero means don't recognize the keyword `asm'. */ + +int flag_no_asm; + +/* Nonzero means don't recognize any builtin functions. */ + +int flag_no_builtin; + +/* Nonzero means don't recognize the non-ANSI builtin functions. + -ansi sets this. */ + +int flag_no_nonansi_builtin; + +/* Nonzero means do some things the same way PCC does. */ + +int flag_traditional; + +/* Nonzero means use the ISO C9x dialect of C. */ + +int flag_isoc9x = 0; + +/* Nonzero means that we have builtin functions, and main is an int */ + +int flag_hosted = 1; + +/* Nonzero means to allow single precision math even if we're generally + being traditional. */ +int flag_allow_single_precision = 0; + +/* Nonzero means to treat bitfields as signed unless they say `unsigned'. */ + +int flag_signed_bitfields = 1; +int explicit_flag_signed_bitfields = 0; + +/* Nonzero means handle `#ident' directives. 0 means ignore them. */ + +int flag_no_ident = 0; + +/* Nonzero means warn about use of implicit int. */ + +int warn_implicit_int; + +/* Nonzero means warn about usage of long long when `-pedantic'. */ + +int warn_long_long = 1; + +/* Nonzero means message about use of implicit function declarations; + 1 means warning; 2 means error. */ + +int mesg_implicit_function_declaration; + +/* Nonzero means give string constants the type `const char *' + to get extra warnings from them. These warnings will be too numerous + to be useful, except in thoroughly ANSIfied programs. */ + +int flag_const_strings; + +/* Nonzero means warn about pointer casts that can drop a type qualifier + from the pointer target type. */ + +int warn_cast_qual; + +/* 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 functions which might be candidates for attribute noreturn. */ + +int warn_missing_noreturn; + +/* Warn about traditional constructs whose meanings changed in ANSI C. */ + +int warn_traditional; + +/* Nonzero means warn about sizeof(function) or addition/subtraction + of function pointers. */ + +int warn_pointer_arith; + +/* 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 prototype decl. */ + +int warn_missing_prototypes; + +/* Nonzero means warn for any global function def + without separate previous decl. */ + +int warn_missing_declarations; + +/* Nonzero means warn about multiple (redundant) decls for the same single + variable or function. */ + +int warn_redundant_decls = 0; + +/* 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. */ + +int warn_nested_externs = 0; + +/* Warn about *printf or *scanf format/argument anomalies. */ + +int warn_format; + +/* Warn about a subscript that has type char. */ + +int warn_char_subscripts = 0; + +/* Warn if a type conversion is done that might have confusing results. */ + +int warn_conversion; + +/* Warn if adding () is suggested. */ + +int warn_parentheses; + +/* Warn if initializer is not completely bracketed. */ + +int warn_missing_braces; + +/* Warn if main is suspicious. */ + +int warn_main; + +/* Warn about #pragma directives that are not recognised. */ + +int warn_unknown_pragmas = 0; /* Tri state variable. */ + +/* Warn about comparison of signed and unsigned values. + If -1, neither -Wsign-compare nor -Wno-sign-compare has been specified. */ + +int warn_sign_compare = -1; + +/* Nonzero means warn about use of multicharacter literals. */ + +int warn_multichar = 1; + +/* Nonzero means `$' can be in an identifier. */ + +#ifndef DOLLARS_IN_IDENTIFIERS +#define DOLLARS_IN_IDENTIFIERS 1 +#endif +int dollars_in_ident = DOLLARS_IN_IDENTIFIERS; + +/* Decode the string P as a language-specific option for C. + Return the number of strings consumed. */ + +int +c_decode_option (argc, argv) + int argc ATTRIBUTE_UNUSED; + char **argv; +{ + int strings_processed; + char *p = argv[0]; +#if USE_CPPLIB + strings_processed = cpp_handle_option (&parse_in, argc, argv); +#else + strings_processed = 0; +#endif /* ! USE_CPPLIB */ + + if (!strcmp (p, "-ftraditional") || !strcmp (p, "-traditional")) + { + flag_traditional = 1; + flag_writable_strings = 1; + } + else if (!strcmp (p, "-fallow-single-precision")) + flag_allow_single_precision = 1; + else if (!strcmp (p, "-fhosted") || !strcmp (p, "-fno-freestanding")) + { + flag_hosted = 1; + flag_no_builtin = 0; + } + else if (!strcmp (p, "-ffreestanding") || !strcmp (p, "-fno-hosted")) + { + flag_hosted = 0; + flag_no_builtin = 1; + /* warn_main will be 2 if set by -Wall, 1 if set by -Wmain */ + if (warn_main == 2) + warn_main = 0; + } + else if (!strcmp (p, "-fnotraditional") || !strcmp (p, "-fno-traditional")) + { + flag_traditional = 0; + flag_writable_strings = 0; + } + else if (!strncmp (p, "-std=", 5)) + { + /* Select the appropriate language standard. We currently + recognize: + -std=iso9899:1990 same as -ansi + -std=iso9899:199409 ISO C as modified in amend. 1 + -std=iso9899:199x ISO C 9x + -std=c89 same as -std=iso9899:1990 + -std=c9x same as -std=iso9899:199x + -std=gnu89 default, iso9899:1990 + gnu extensions + -std=gnu9x iso9899:199x + gnu extensions + */ + const char *argstart = &p[5]; + + if (!strcmp (argstart, "iso9899:1990") + || !strcmp (argstart, "c89")) + { + iso_1990: + flag_traditional = 0; + flag_writable_strings = 0; + flag_no_asm = 1; + flag_no_nonansi_builtin = 1; + flag_isoc9x = 0; + } + else if (!strcmp (argstart, "iso9899:199409")) + { + /* ??? The changes since ISO C 1990 are not supported. */ + goto iso_1990; + } + else if (!strcmp (argstart, "iso9899:199x") + || !strcmp (argstart, "c9x")) + { + flag_traditional = 0; + flag_writable_strings = 0; + flag_no_asm = 1; + flag_no_nonansi_builtin = 1; + flag_isoc9x = 1; + } + else if (!strcmp (argstart, "gnu89")) + { + flag_traditional = 0; + flag_writable_strings = 0; + flag_no_asm = 0; + flag_no_nonansi_builtin = 0; + flag_isoc9x = 0; + } + else if (!strcmp (argstart, "gnu9x")) + { + flag_traditional = 0; + flag_writable_strings = 0; + flag_no_asm = 0; + flag_no_nonansi_builtin = 0; + flag_isoc9x = 1; + } + else + error ("unknown C standard `%s'", argstart); + } + else if (!strcmp (p, "-fdollars-in-identifiers")) + dollars_in_ident = 1; + else if (!strcmp (p, "-fno-dollars-in-identifiers")) + dollars_in_ident = 0; + else if (!strcmp (p, "-fsigned-char")) + flag_signed_char = 1; + else if (!strcmp (p, "-funsigned-char")) + flag_signed_char = 0; + else if (!strcmp (p, "-fno-signed-char")) + flag_signed_char = 0; + else if (!strcmp (p, "-fno-unsigned-char")) + flag_signed_char = 1; + else if (!strcmp (p, "-fsigned-bitfields") + || !strcmp (p, "-fno-unsigned-bitfields")) + { + flag_signed_bitfields = 1; + explicit_flag_signed_bitfields = 1; + } + else if (!strcmp (p, "-funsigned-bitfields") + || !strcmp (p, "-fno-signed-bitfields")) + { + flag_signed_bitfields = 0; + explicit_flag_signed_bitfields = 1; + } + else if (!strcmp (p, "-fshort-enums")) + flag_short_enums = 1; + else if (!strcmp (p, "-fno-short-enums")) + flag_short_enums = 0; + else if (!strcmp (p, "-fcond-mismatch")) + flag_cond_mismatch = 1; + else if (!strcmp (p, "-fno-cond-mismatch")) + flag_cond_mismatch = 0; + else if (!strcmp (p, "-fshort-double")) + flag_short_double = 1; + else if (!strcmp (p, "-fno-short-double")) + flag_short_double = 0; + else if (!strcmp (p, "-fasm")) + flag_no_asm = 0; + else if (!strcmp (p, "-fno-asm")) + flag_no_asm = 1; + else if (!strcmp (p, "-fbuiltin")) + flag_no_builtin = 0; + else if (!strcmp (p, "-fno-builtin")) + flag_no_builtin = 1; + else if (!strcmp (p, "-fno-ident")) + flag_no_ident = 1; + else if (!strcmp (p, "-fident")) + flag_no_ident = 0; + else if (!strcmp (p, "-ansi")) + goto iso_1990; + else if (!strcmp (p, "-Werror-implicit-function-declaration")) + mesg_implicit_function_declaration = 2; + else if (!strcmp (p, "-Wimplicit-function-declaration")) + mesg_implicit_function_declaration = 1; + else if (!strcmp (p, "-Wno-implicit-function-declaration")) + mesg_implicit_function_declaration = 0; + else if (!strcmp (p, "-Wimplicit-int")) + warn_implicit_int = 1; + else if (!strcmp (p, "-Wno-implicit-int")) + warn_implicit_int = 0; + else if (!strcmp (p, "-Wimplicit")) + { + warn_implicit_int = 1; + if (mesg_implicit_function_declaration != 2) + mesg_implicit_function_declaration = 1; + } + else if (!strcmp (p, "-Wno-implicit")) + warn_implicit_int = 0, mesg_implicit_function_declaration = 0; + else if (!strcmp (p, "-Wlong-long")) + warn_long_long = 1; + else if (!strcmp (p, "-Wno-long-long")) + warn_long_long = 0; + else if (!strcmp (p, "-Wwrite-strings")) + flag_const_strings = 1; + else if (!strcmp (p, "-Wno-write-strings")) + flag_const_strings = 0; + else if (!strcmp (p, "-Wcast-qual")) + warn_cast_qual = 1; + else if (!strcmp (p, "-Wno-cast-qual")) + warn_cast_qual = 0; + else if (!strcmp (p, "-Wbad-function-cast")) + warn_bad_function_cast = 1; + else if (!strcmp (p, "-Wno-bad-function-cast")) + warn_bad_function_cast = 0; + else if (!strcmp (p, "-Wmissing-noreturn")) + warn_missing_noreturn = 1; + else if (!strcmp (p, "-Wno-missing-noreturn")) + warn_missing_noreturn = 0; + else if (!strcmp (p, "-Wpointer-arith")) + warn_pointer_arith = 1; + else if (!strcmp (p, "-Wno-pointer-arith")) + warn_pointer_arith = 0; + else if (!strcmp (p, "-Wstrict-prototypes")) + warn_strict_prototypes = 1; + else if (!strcmp (p, "-Wno-strict-prototypes")) + warn_strict_prototypes = 0; + else if (!strcmp (p, "-Wmissing-prototypes")) + warn_missing_prototypes = 1; + else if (!strcmp (p, "-Wno-missing-prototypes")) + warn_missing_prototypes = 0; + else if (!strcmp (p, "-Wmissing-declarations")) + warn_missing_declarations = 1; + else if (!strcmp (p, "-Wno-missing-declarations")) + warn_missing_declarations = 0; + else if (!strcmp (p, "-Wredundant-decls")) + warn_redundant_decls = 1; + else if (!strcmp (p, "-Wno-redundant-decls")) + warn_redundant_decls = 0; + else if (!strcmp (p, "-Wnested-externs")) + warn_nested_externs = 1; + else if (!strcmp (p, "-Wno-nested-externs")) + warn_nested_externs = 0; + else if (!strcmp (p, "-Wtraditional")) + warn_traditional = 1; + else if (!strcmp (p, "-Wno-traditional")) + warn_traditional = 0; + else if (!strcmp (p, "-Wformat")) + warn_format = 1; + else if (!strcmp (p, "-Wno-format")) + warn_format = 0; + else if (!strcmp (p, "-Wchar-subscripts")) + warn_char_subscripts = 1; + else if (!strcmp (p, "-Wno-char-subscripts")) + warn_char_subscripts = 0; + else if (!strcmp (p, "-Wconversion")) + warn_conversion = 1; + else if (!strcmp (p, "-Wno-conversion")) + warn_conversion = 0; + else if (!strcmp (p, "-Wparentheses")) + warn_parentheses = 1; + else if (!strcmp (p, "-Wno-parentheses")) + warn_parentheses = 0; + else if (!strcmp (p, "-Wreturn-type")) + warn_return_type = 1; + else if (!strcmp (p, "-Wno-return-type")) + warn_return_type = 0; + else if (!strcmp (p, "-Wcomment")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wno-comment")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wcomments")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wno-comments")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wtrigraphs")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wno-trigraphs")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wundef")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wno-undef")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wimport")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wno-import")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wmissing-braces")) + warn_missing_braces = 1; + else if (!strcmp (p, "-Wno-missing-braces")) + warn_missing_braces = 0; + else if (!strcmp (p, "-Wmain")) + warn_main = 1; + else if (!strcmp (p, "-Wno-main")) + warn_main = 0; + else if (!strcmp (p, "-Wsign-compare")) + warn_sign_compare = 1; + else if (!strcmp (p, "-Wno-sign-compare")) + warn_sign_compare = 0; + else if (!strcmp (p, "-Wmultichar")) + warn_multichar = 1; + else if (!strcmp (p, "-Wno-multichar")) + warn_multichar = 0; + else if (!strcmp (p, "-Wunknown-pragmas")) + /* Set to greater than 1, so that even unknown pragmas in system + headers will be warned about. */ + warn_unknown_pragmas = 2; + else if (!strcmp (p, "-Wno-unknown-pragmas")) + warn_unknown_pragmas = 0; + else if (!strcmp (p, "-Wall")) + { + /* We save the value of warn_uninitialized, since if they put + -Wuninitialized on the command line, we need to generate a + warning about not using it without also specifying -O. */ + if (warn_uninitialized != 1) + warn_uninitialized = 2; + warn_implicit_int = 1; + mesg_implicit_function_declaration = 1; + warn_return_type = 1; + warn_unused = 1; + warn_switch = 1; + warn_format = 1; + warn_char_subscripts = 1; + warn_parentheses = 1; + warn_missing_braces = 1; + /* We set this to 2 here, but 1 in -Wmain, so -ffreestanding can turn + it off only if it's not explicit. */ + warn_main = 2; + /* Only warn about unknown pragmas that are not in system headers. */ + warn_unknown_pragmas = 1; + } + else + return strings_processed; + + return 1; +} + +/* Hooks for print_node. */ + +void +print_lang_decl (file, node, indent) + FILE *file ATTRIBUTE_UNUSED; + tree node ATTRIBUTE_UNUSED; + int indent ATTRIBUTE_UNUSED; +{ +} + +void +print_lang_type (file, node, indent) + FILE *file ATTRIBUTE_UNUSED; + tree node ATTRIBUTE_UNUSED; + int indent ATTRIBUTE_UNUSED; +{ +} + +void +print_lang_identifier (file, node, indent) + FILE *file; + tree node; + int indent; +{ + print_node (file, "global", IDENTIFIER_GLOBAL_VALUE (node), indent + 4); + print_node (file, "local", IDENTIFIER_LOCAL_VALUE (node), indent + 4); + print_node (file, "label", IDENTIFIER_LABEL_VALUE (node), indent + 4); + print_node (file, "implicit", IDENTIFIER_IMPLICIT_DECL (node), indent + 4); + print_node (file, "error locus", IDENTIFIER_ERROR_LOCUS (node), indent + 4); + print_node (file, "limbo value", IDENTIFIER_LIMBO_VALUE (node), indent + 4); +} + +/* Hook called at end of compilation to assume 1 elt + for a top-level array decl that wasn't complete before. */ + +void +finish_incomplete_decl (decl) + tree decl; +{ + if (TREE_CODE (decl) == VAR_DECL) + { + tree type = TREE_TYPE (decl); + if (type != error_mark_node + && TREE_CODE (type) == ARRAY_TYPE + && TYPE_DOMAIN (type) == 0) + { + if (! DECL_EXTERNAL (decl)) + warning_with_decl (decl, "array `%s' assumed to have one element"); + + complete_array_type (type, NULL_TREE, 1); + + layout_decl (decl, 0); + } + } +} + +/* Create a new `struct binding_level'. */ + +static +struct binding_level * +make_binding_level () +{ + /* NOSTRICT */ + return (struct binding_level *) xmalloc (sizeof (struct binding_level)); +} + +/* Nonzero if we are currently in the global binding level. */ + +int +global_bindings_p () +{ + return current_binding_level == global_binding_level; +} + +void +keep_next_level () +{ + keep_next_level_flag = 1; +} + +/* Nonzero if the current level needs to have a BLOCK made. */ + +int +kept_level_p () +{ + return ((current_binding_level->keep_if_subblocks + && current_binding_level->blocks != 0) + || current_binding_level->keep + || current_binding_level->names != 0 + || (current_binding_level->tags != 0 + && !current_binding_level->tag_transparent)); +} + +/* Identify this binding level as a level of parameters. + DEFINITION_FLAG is 1 for a definition, 0 for a declaration. + But it turns out there is no way to pass the right value for + DEFINITION_FLAG, so we ignore it. */ + +void +declare_parm_level (definition_flag) + int definition_flag ATTRIBUTE_UNUSED; +{ + current_binding_level->parm_flag = 1; +} + +/* Nonzero if currently making parm declarations. */ + +int +in_parm_level_p () +{ + return current_binding_level->parm_flag; +} + +/* Enter a new binding level. + If TAG_TRANSPARENT is nonzero, do so only for the name space of variables, + not for that of tags. */ + +void +pushlevel (tag_transparent) + int tag_transparent; +{ + register struct binding_level *newlevel = NULL_BINDING_LEVEL; + + /* If this is the top level of a function, + just make sure that NAMED_LABELS is 0. */ + + if (current_binding_level == global_binding_level) + { + named_labels = 0; + } + + /* Reuse or create a struct for this binding level. */ + + if (free_binding_level) + { + newlevel = free_binding_level; + free_binding_level = free_binding_level->level_chain; + } + else + { + newlevel = make_binding_level (); + } + + /* Add this level to the front of the chain (stack) of levels that + are active. */ + + *newlevel = clear_binding_level; + newlevel->tag_transparent + = (tag_transparent + || (current_binding_level + ? current_binding_level->subblocks_tag_transparent + : 0)); + newlevel->level_chain = current_binding_level; + current_binding_level = newlevel; + newlevel->keep = keep_next_level_flag; + keep_next_level_flag = 0; + newlevel->keep_if_subblocks = keep_next_if_subblocks; + keep_next_if_subblocks = 0; +} + +/* Clear the limbo values of all identifiers defined in BLOCK or a subblock. */ + +static void +clear_limbo_values (block) + tree block; +{ + tree tem; + + for (tem = BLOCK_VARS (block); tem; tem = TREE_CHAIN (tem)) + if (DECL_NAME (tem) != 0) + IDENTIFIER_LIMBO_VALUE (DECL_NAME (tem)) = 0; + + for (tem = BLOCK_SUBBLOCKS (block); tem; tem = TREE_CHAIN (tem)) + clear_limbo_values (tem); +} + +/* Exit a binding level. + Pop the level off, and restore the state of the identifier-decl mappings + that were in effect when this level was entered. + + If KEEP is nonzero, this level had explicit declarations, so + and create a "block" (a BLOCK node) for the level + to record its declarations and subblocks for symbol table output. + + If FUNCTIONBODY is nonzero, this level is the body of a function, + so create a block as if KEEP were set and also clear out all + label names. + + If REVERSE is nonzero, reverse the order of decls before putting + them into the BLOCK. */ + +tree +poplevel (keep, reverse, functionbody) + int keep; + int reverse; + int functionbody; +{ + register tree link; + /* The chain of decls was accumulated in reverse order. + Put it into forward order, just for cleanliness. */ + tree decls; + tree tags = current_binding_level->tags; + tree subblocks = current_binding_level->blocks; + tree block = 0; + tree decl; + int block_previously_created; + + keep |= current_binding_level->keep; + + /* This warning is turned off because it causes warnings for + declarations like `extern struct foo *x'. */ +#if 0 + /* Warn about incomplete structure types in this level. */ + for (link = tags; link; link = TREE_CHAIN (link)) + if (TYPE_SIZE (TREE_VALUE (link)) == 0) + { + tree type = TREE_VALUE (link); + char *errmsg; + switch (TREE_CODE (type)) + { + case RECORD_TYPE: + errmsg = "`struct %s' incomplete in scope ending here"; + break; + case UNION_TYPE: + errmsg = "`union %s' incomplete in scope ending here"; + break; + case ENUMERAL_TYPE: + errmsg = "`enum %s' incomplete in scope ending here"; + break; + } + if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) + error (errmsg, IDENTIFIER_POINTER (TYPE_NAME (type))); + else + /* If this type has a typedef-name, the TYPE_NAME is a TYPE_DECL. */ + error (errmsg, IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)))); + } +#endif /* 0 */ + + /* Get the decls in the order they were written. + Usually current_binding_level->names is in reverse order. + But parameter decls were previously put in forward order. */ + + if (reverse) + current_binding_level->names + = decls = nreverse (current_binding_level->names); + 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) != 0 + && TREE_ADDRESSABLE (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. + + DECL_ABSTRACT_ORIGIN can be set to itself if warn_return_type is + true, since then the decl goes through save_for_inline_copying. */ + if (DECL_ABSTRACT_ORIGIN (decl) != 0 + && DECL_ABSTRACT_ORIGIN (decl) != decl) + TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1; + else if (DECL_SAVED_INSNS (decl) != 0) + { + push_function_context (); + output_inline_function (decl); + pop_function_context (); + } + } + + /* 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. */ + + block = 0; + block_previously_created = (current_binding_level->this_block != 0); + if (block_previously_created) + block = current_binding_level->this_block; + else if (keep || functionbody + || (current_binding_level->keep_if_subblocks && subblocks != 0)) + block = make_node (BLOCK); + if (block != 0) + { + BLOCK_VARS (block) = decls; + BLOCK_TYPE_TAGS (block) = tags; + BLOCK_SUBBLOCKS (block) = subblocks; + remember_end_note (block); + } + + /* In each subblock, record that this is its superior. */ + + for (link = subblocks; link; link = TREE_CHAIN (link)) + BLOCK_SUPERCONTEXT (link) = block; + + /* Clear out the meanings of the local variables of this level. */ + + for (link = decls; link; link = TREE_CHAIN (link)) + { + if (DECL_NAME (link) != 0) + { + /* If the ident. was used or addressed via a local extern decl, + don't forget that fact. */ + if (DECL_EXTERNAL (link)) + { + if (TREE_USED (link)) + TREE_USED (DECL_NAME (link)) = 1; + if (TREE_ADDRESSABLE (link)) + TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (link)) = 1; + } + IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = 0; + } + } + + /* Restore all name-meanings of the outer levels + that were shadowed by this level. */ + + for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link)) + IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link); + + /* If the level being exited is the top level of a function, + check over all the labels, and clear out the current + (function local) meanings of their names. */ + + if (functionbody) + { + clear_limbo_values (block); + + /* If this is the top level block of a function, + the vars are the function's parameters. + Don't leave them in the BLOCK because they are + found in the FUNCTION_DECL instead. */ + + BLOCK_VARS (block) = 0; + + /* Clear out the definitions of all label names, + since their scopes end here, + and add them to BLOCK_VARS. */ + + for (link = named_labels; link; link = TREE_CHAIN (link)) + { + register tree label = TREE_VALUE (link); + + if (DECL_INITIAL (label) == 0) + { + error_with_decl (label, "label `%s' used but not defined"); + /* Avoid crashing later. */ + define_label (input_filename, lineno, + DECL_NAME (label)); + } + else if (warn_unused && !TREE_USED (label)) + warning_with_decl (label, "label `%s' defined but not used"); + IDENTIFIER_LABEL_VALUE (DECL_NAME (label)) = 0; + + /* Put the labels into the "variables" of the + top-level block, so debugger can see them. */ + TREE_CHAIN (label) = BLOCK_VARS (block); + BLOCK_VARS (block) = label; + } + } + + /* Pop the current level, and free the structure for reuse. */ + + { + register struct binding_level *level = current_binding_level; + current_binding_level = current_binding_level->level_chain; + + level->level_chain = free_binding_level; + free_binding_level = level; + } + + /* Dispose of the block that we just made inside some higher level. */ + if (functionbody) + DECL_INITIAL (current_function_decl) = block; + else if (block) + { + if (!block_previously_created) + current_binding_level->blocks + = chainon (current_binding_level->blocks, block); + } + /* If we did not make a block for the level just exited, + any blocks made for inner levels + (since they cannot be recorded as subblocks in that level) + must be carried forward so they will later become subblocks + of something else. */ + else if (subblocks) + current_binding_level->blocks + = chainon (current_binding_level->blocks, subblocks); + + /* Set the TYPE_CONTEXTs for all of the tagged types belonging to this + binding contour 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. + */ + + if (functionbody) + for (link = tags; link; link = TREE_CHAIN (link)) + TYPE_CONTEXT (TREE_VALUE (link)) = current_function_decl; + else if (block) + for (link = tags; link; link = TREE_CHAIN (link)) + TYPE_CONTEXT (TREE_VALUE (link)) = block; + + if (block) + TREE_USED (block) = 1; + return 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 (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; + /* 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. */ + +void +insert_block (block) + tree block; +{ + TREE_USED (block) = 1; + current_binding_level->blocks + = chainon (current_binding_level->blocks, block); +} + +/* Set the BLOCK node for the innermost scope + (the one we are currently in). */ + +void +set_block (block) + register tree block; +{ + current_binding_level->this_block = block; +} + +void +push_label_level () +{ + register struct binding_level *newlevel; + + /* Reuse or create a struct for this binding level. */ + + if (free_binding_level) + { + newlevel = free_binding_level; + free_binding_level = free_binding_level->level_chain; + } + else + { + newlevel = make_binding_level (); + } + + /* Add this level to the front of the chain (stack) of label levels. */ + + newlevel->level_chain = label_level_chain; + label_level_chain = newlevel; + + newlevel->names = named_labels; + newlevel->shadowed = shadowed_labels; + named_labels = 0; + shadowed_labels = 0; +} + +void +pop_label_level () +{ + register struct binding_level *level = label_level_chain; + tree link, prev; + + /* Clear out the definitions of the declared labels in this level. + Leave in the list any ordinary, non-declared labels. */ + for (link = named_labels, prev = 0; link;) + { + if (C_DECLARED_LABEL_FLAG (TREE_VALUE (link))) + { + if (DECL_SOURCE_LINE (TREE_VALUE (link)) == 0) + { + error_with_decl (TREE_VALUE (link), + "label `%s' used but not defined"); + /* Avoid crashing later. */ + define_label (input_filename, lineno, + DECL_NAME (TREE_VALUE (link))); + } + else if (warn_unused && !TREE_USED (TREE_VALUE (link))) + warning_with_decl (TREE_VALUE (link), + "label `%s' defined but not used"); + IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link))) = 0; + + /* Delete this element from the list. */ + link = TREE_CHAIN (link); + if (prev) + TREE_CHAIN (prev) = link; + else + named_labels = link; + } + else + { + prev = link; + link = TREE_CHAIN (link); + } + } + + /* Bring back all the labels that were shadowed. */ + for (link = shadowed_labels; link; link = TREE_CHAIN (link)) + if (DECL_NAME (TREE_VALUE (link)) != 0) + IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link))) + = TREE_VALUE (link); + + named_labels = chainon (named_labels, level->names); + shadowed_labels = level->shadowed; + + /* Pop the current level, and free the structure for reuse. */ + label_level_chain = label_level_chain->level_chain; + level->level_chain = free_binding_level; + free_binding_level = level; +} + +/* Push a definition or a declaration of struct, union or enum tag "name". + "type" should be the type node. + We assume that the tag "name" is not already defined. + + Note that the definition may really be just a forward reference. + In that case, the TYPE_SIZE will be zero. */ + +void +pushtag (name, type) + tree name, type; +{ + register struct binding_level *b; + + /* Find the proper binding level for this type tag. */ + + for (b = current_binding_level; b->tag_transparent; b = b->level_chain) + continue; + + if (name) + { + /* Record the identifier as the type's name if it has none. */ + + if (TYPE_NAME (type) == 0) + TYPE_NAME (type) = name; + } + + if (b == global_binding_level) + b->tags = perm_tree_cons (name, type, b->tags); + else + b->tags = saveable_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 binding level. This fake + NULL-named TYPE_DECL node helps dwarfout.c to know when it needs + to output a representation of a tagged type, and it also gives + us a convenient place to record the "scope start" address for the + tagged 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 poplevel. */ + TYPE_CONTEXT (type) = DECL_CONTEXT (TYPE_STUB_DECL (type)); +} + +/* Handle when a new declaration NEWDECL + has the same name as an old one OLDDECL + in the same binding contour. + Prints an error message if appropriate. + + If safely possible, alter OLDDECL to look like NEWDECL, and return 1. + Otherwise, return 0. + + When DIFFERENT_BINDING_LEVEL is true, NEWDECL is an external declaration, + and OLDDECL is in an outer binding level and should thus not be changed. */ + +static int +duplicate_decls (newdecl, olddecl, different_binding_level) + register tree newdecl, olddecl; + int different_binding_level; +{ + int types_match = comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl)); + int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL + && DECL_INITIAL (newdecl) != 0); + tree oldtype = TREE_TYPE (olddecl); + tree newtype = TREE_TYPE (newdecl); + char *errmsg = 0; + + if (TREE_CODE_CLASS (TREE_CODE (olddecl)) == 'd') + DECL_MACHINE_ATTRIBUTES (newdecl) + = merge_machine_decl_attributes (olddecl, newdecl); + + if (TREE_CODE (newtype) == ERROR_MARK + || TREE_CODE (oldtype) == ERROR_MARK) + types_match = 0; + + /* New decl is completely inconsistent with the old one => + tell caller to replace the old one. + This is always an error except in the case of shadowing a builtin. */ + if (TREE_CODE (olddecl) != TREE_CODE (newdecl)) + { + if (TREE_CODE (olddecl) == FUNCTION_DECL + && (DECL_BUILT_IN (olddecl) + || DECL_BUILT_IN_NONANSI (olddecl))) + { + /* 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)) + { + if (!warn_shadow) + ; + else if (DECL_BUILT_IN (olddecl)) + warning_with_decl (newdecl, "shadowing built-in function `%s'"); + else + warning_with_decl (newdecl, "shadowing library function `%s'"); + } + /* Likewise, if the built-in is not ansi, then programs can + override it even globally without an error. */ + else if (! DECL_BUILT_IN (olddecl)) + warning_with_decl (newdecl, + "library function `%s' declared as non-function"); + + else if (DECL_BUILT_IN_NONANSI (olddecl)) + warning_with_decl (newdecl, + "built-in function `%s' declared as non-function"); + else + warning_with_decl (newdecl, + "built-in function `%s' declared as non-function"); + } + else + { + error_with_decl (newdecl, "`%s' redeclared as different kind of symbol"); + error_with_decl (olddecl, "previous declaration of `%s'"); + } + + return 0; + } + + /* For real parm decl following a forward decl, + return 1 so old decl will be reused. */ + if (types_match && TREE_CODE (newdecl) == PARM_DECL + && TREE_ASM_WRITTEN (olddecl) && ! TREE_ASM_WRITTEN (newdecl)) + return 1; + + /* The new declaration is the same kind of object as the old one. + The declarations may partially match. Print warnings if they don't + match enough. Ultimately, copy most of the information from the new + decl to the old one, and keep using the old one. */ + + if (flag_traditional && TREE_CODE (newdecl) == FUNCTION_DECL + && IDENTIFIER_IMPLICIT_DECL (DECL_NAME (newdecl)) == olddecl + && DECL_INITIAL (olddecl) == 0) + /* If -traditional, avoid error for redeclaring fcn + after implicit decl. */ + ; + else if (TREE_CODE (olddecl) == FUNCTION_DECL + && DECL_BUILT_IN (olddecl)) + { + /* A function declaration for a built-in function. */ + if (!TREE_PUBLIC (newdecl)) + { + /* If you declare a built-in function name as static, the + built-in definition is overridden, + but optionally warn this was a bad choice of name. */ + if (warn_shadow) + warning_with_decl (newdecl, "shadowing built-in function `%s'"); + /* Discard the old built-in function. */ + return 0; + } + else if (!types_match) + { + /* Accept the return type of the new declaration if same modes. */ + tree oldreturntype = TREE_TYPE (oldtype); + tree newreturntype = TREE_TYPE (newtype); + + /* Make sure we put the new type in the same obstack as the old ones. + If the old types are not both in the same obstack, use the + permanent one. */ + if (TYPE_OBSTACK (oldtype) == TYPE_OBSTACK (newtype)) + push_obstacks (TYPE_OBSTACK (oldtype), TYPE_OBSTACK (oldtype)); + else + { + push_obstacks_nochange (); + end_temporary_allocation (); + } + + if (TYPE_MODE (oldreturntype) == TYPE_MODE (newreturntype)) + { + /* Function types may be shared, so we can't just modify + the return type of olddecl's function type. */ + tree trytype + = build_function_type (newreturntype, + TYPE_ARG_TYPES (oldtype)); + + types_match = comptypes (newtype, trytype); + if (types_match) + oldtype = trytype; + } + /* Accept harmless mismatch in first argument type also. + This is for ffs. */ + if (TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != 0 + && TYPE_ARG_TYPES (oldtype) != 0 + && TREE_VALUE (TYPE_ARG_TYPES (newtype)) != 0 + && TREE_VALUE (TYPE_ARG_TYPES (oldtype)) != 0 + && (TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (newtype))) + == TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (oldtype))))) + { + /* Function types may be shared, so we can't just modify + the return type of olddecl's function type. */ + tree trytype + = build_function_type (TREE_TYPE (oldtype), + tree_cons (NULL_TREE, + TREE_VALUE (TYPE_ARG_TYPES (newtype)), + TREE_CHAIN (TYPE_ARG_TYPES (oldtype)))); + + types_match = comptypes (newtype, trytype); + if (types_match) + oldtype = trytype; + } + if (! different_binding_level) + TREE_TYPE (olddecl) = oldtype; + + pop_obstacks (); + } + if (!types_match) + { + /* If types don't match for a built-in, throw away the built-in. */ + warning_with_decl (newdecl, "conflicting types for built-in function `%s'"); + return 0; + } + } + else if (TREE_CODE (olddecl) == FUNCTION_DECL + && DECL_SOURCE_LINE (olddecl) == 0) + { + /* A function declaration for a predeclared function + that isn't actually built in. */ + if (!TREE_PUBLIC (newdecl)) + { + /* If you declare it as static, the + default definition is overridden. */ + return 0; + } + else if (!types_match) + { + /* If the types don't match, preserve volatility indication. + Later on, we will discard everything else about the + default declaration. */ + TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl); + } + } + /* Permit char *foo () to match void *foo (...) if not pedantic, + if one of them came from a system header file. */ + else if (!types_match + && TREE_CODE (olddecl) == FUNCTION_DECL + && TREE_CODE (newdecl) == FUNCTION_DECL + && TREE_CODE (TREE_TYPE (oldtype)) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (newtype)) == POINTER_TYPE + && (DECL_IN_SYSTEM_HEADER (olddecl) + || DECL_IN_SYSTEM_HEADER (newdecl)) + && ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (newtype))) == void_type_node + && TYPE_ARG_TYPES (oldtype) == 0 + && self_promoting_args_p (TYPE_ARG_TYPES (newtype)) + && TREE_TYPE (TREE_TYPE (oldtype)) == char_type_node) + || + (TREE_TYPE (TREE_TYPE (newtype)) == char_type_node + && TYPE_ARG_TYPES (newtype) == 0 + && self_promoting_args_p (TYPE_ARG_TYPES (oldtype)) + && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (oldtype))) == void_type_node))) + { + if (pedantic) + pedwarn_with_decl (newdecl, "conflicting types for `%s'"); + /* Make sure we keep void * as ret type, not char *. */ + if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (oldtype))) == void_type_node) + TREE_TYPE (newdecl) = newtype = oldtype; + + /* Set DECL_IN_SYSTEM_HEADER, so that if we see another declaration + we will come back here again. */ + DECL_IN_SYSTEM_HEADER (newdecl) = 1; + } + else if (!types_match + /* Permit char *foo (int, ...); followed by char *foo (); + if not pedantic. */ + && ! (TREE_CODE (olddecl) == FUNCTION_DECL + && ! pedantic + /* Return types must still match. */ + && comptypes (TREE_TYPE (oldtype), + TREE_TYPE (newtype)) + && TYPE_ARG_TYPES (newtype) == 0)) + { + error_with_decl (newdecl, "conflicting types for `%s'"); + /* Check for function type mismatch + involving an empty arglist vs a nonempty one. */ + if (TREE_CODE (olddecl) == FUNCTION_DECL + && comptypes (TREE_TYPE (oldtype), + TREE_TYPE (newtype)) + && ((TYPE_ARG_TYPES (oldtype) == 0 + && DECL_INITIAL (olddecl) == 0) + || + (TYPE_ARG_TYPES (newtype) == 0 + && DECL_INITIAL (newdecl) == 0))) + { + /* Classify the problem further. */ + register tree t = TYPE_ARG_TYPES (oldtype); + if (t == 0) + t = TYPE_ARG_TYPES (newtype); + for (; t; t = TREE_CHAIN (t)) + { + register tree type = TREE_VALUE (t); + + if (TREE_CHAIN (t) == 0 + && TYPE_MAIN_VARIANT (type) != void_type_node) + { + error ("A parameter list with an ellipsis can't match"); + error ("an empty parameter name list declaration."); + break; + } + + if (TYPE_MAIN_VARIANT (type) == float_type_node + || C_PROMOTING_INTEGER_TYPE_P (type)) + { + error ("An argument type that has a default promotion"); + error ("can't match an empty parameter name list declaration."); + break; + } + } + } + error_with_decl (olddecl, "previous declaration of `%s'"); + } + else + { + errmsg = redeclaration_error_message (newdecl, olddecl); + if (errmsg) + { + error_with_decl (newdecl, errmsg); + error_with_decl (olddecl, + ((DECL_INITIAL (olddecl) + && current_binding_level == global_binding_level) + ? "`%s' previously defined here" + : "`%s' previously declared here")); + } + else if (TREE_CODE (newdecl) == TYPE_DECL + && (DECL_IN_SYSTEM_HEADER (olddecl) + || DECL_IN_SYSTEM_HEADER (newdecl))) + { + warning_with_decl (newdecl, "redefinition of `%s'"); + warning_with_decl + (olddecl, + ((DECL_INITIAL (olddecl) + && current_binding_level == global_binding_level) + ? "`%s' previously defined here" + : "`%s' previously declared here")); + } + else if (TREE_CODE (olddecl) == FUNCTION_DECL + && DECL_INITIAL (olddecl) != 0 + && TYPE_ARG_TYPES (oldtype) == 0 + && TYPE_ARG_TYPES (newtype) != 0 + && TYPE_ACTUAL_ARG_TYPES (oldtype) != 0) + { + register tree type, parm; + register int nargs; + /* Prototype decl follows defn w/o prototype. */ + + for (parm = TYPE_ACTUAL_ARG_TYPES (oldtype), + type = TYPE_ARG_TYPES (newtype), + nargs = 1; + (TYPE_MAIN_VARIANT (TREE_VALUE (parm)) != void_type_node + || TYPE_MAIN_VARIANT (TREE_VALUE (type)) != void_type_node); + parm = TREE_CHAIN (parm), type = TREE_CHAIN (type), nargs++) + { + if (TYPE_MAIN_VARIANT (TREE_VALUE (parm)) == void_type_node + || TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node) + { + errmsg = "prototype for `%s' follows and number of arguments"; + break; + } + /* Type for passing arg must be consistent + with that declared for the arg. */ + if (! comptypes (TREE_VALUE (parm), TREE_VALUE (type)) + /* If -traditional, allow `unsigned int' instead of `int' + in the prototype. */ + && (! (flag_traditional + && TYPE_MAIN_VARIANT (TREE_VALUE (parm)) == integer_type_node + && TYPE_MAIN_VARIANT (TREE_VALUE (type)) == unsigned_type_node))) + { + errmsg = "prototype for `%s' follows and argument %d"; + break; + } + } + if (errmsg) + { + error_with_decl (newdecl, errmsg, nargs); + error_with_decl (olddecl, + "doesn't match non-prototype definition here"); + } + else + { + warning_with_decl (newdecl, "prototype for `%s' follows"); + warning_with_decl (olddecl, "non-prototype definition here"); + } + } + /* Warn about mismatches in various flags. */ + else + { + /* Warn if function is now inline + but was previously declared not inline and has been called. */ + if (TREE_CODE (olddecl) == FUNCTION_DECL + && ! DECL_INLINE (olddecl) && DECL_INLINE (newdecl) + && TREE_USED (olddecl)) + warning_with_decl (newdecl, + "`%s' declared inline after being called"); + if (TREE_CODE (olddecl) == FUNCTION_DECL + && ! DECL_INLINE (olddecl) && DECL_INLINE (newdecl) + && DECL_INITIAL (olddecl) != 0) + warning_with_decl (newdecl, + "`%s' declared inline after its definition"); + + /* If pedantic, warn when static declaration follows a non-static + declaration. Otherwise, do so only for functions. */ + if ((pedantic || TREE_CODE (olddecl) == FUNCTION_DECL) + && TREE_PUBLIC (olddecl) + && !TREE_PUBLIC (newdecl)) + warning_with_decl (newdecl, "static declaration for `%s' follows non-static"); + + /* Warn when const declaration follows a non-const + declaration, but not for functions. */ + if (TREE_CODE (olddecl) != FUNCTION_DECL + && !TREE_READONLY (olddecl) + && TREE_READONLY (newdecl)) + warning_with_decl (newdecl, "const declaration for `%s' follows non-const"); + /* These bits are logically part of the type, for variables. + But not for functions + (where qualifiers are not valid ANSI anyway). */ + else if (pedantic && TREE_CODE (olddecl) != FUNCTION_DECL + && (TREE_READONLY (newdecl) != TREE_READONLY (olddecl) + || TREE_THIS_VOLATILE (newdecl) != TREE_THIS_VOLATILE (olddecl))) + pedwarn_with_decl (newdecl, "type qualifiers for `%s' conflict with previous decl"); + } + } + + /* Optionally warn about more than one declaration for the same name. */ + if (errmsg == 0 && warn_redundant_decls && DECL_SOURCE_LINE (olddecl) != 0 + /* Don't warn about a function declaration + followed by a definition. */ + && !(TREE_CODE (newdecl) == FUNCTION_DECL && DECL_INITIAL (newdecl) != 0 + && DECL_INITIAL (olddecl) == 0) + /* Don't warn about extern decl followed by (tentative) definition. */ + && !(DECL_EXTERNAL (olddecl) && ! DECL_EXTERNAL (newdecl))) + { + warning_with_decl (newdecl, "redundant redeclaration of `%s' in same scope"); + warning_with_decl (olddecl, "previous declaration of `%s'"); + } + + /* Copy all the DECL_... slots specified in the new decl + except for any that we copy here from the old type. + + Past this point, we don't change OLDTYPE and NEWTYPE + even if we change the types of NEWDECL and OLDDECL. */ + + if (types_match) + { + /* When copying info to olddecl, we store into write_olddecl + instead. This allows us to avoid modifying olddecl when + different_binding_level is true. */ + tree write_olddecl = different_binding_level ? newdecl : olddecl; + + /* Make sure we put the new type in the same obstack as the old ones. + If the old types are not both in the same obstack, use the permanent + one. */ + if (TYPE_OBSTACK (oldtype) == TYPE_OBSTACK (newtype)) + push_obstacks (TYPE_OBSTACK (oldtype), TYPE_OBSTACK (oldtype)); + else + { + push_obstacks_nochange (); + end_temporary_allocation (); + } + + /* Merge the data types specified in the two decls. */ + if (TREE_CODE (newdecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl)) + { + if (different_binding_level) + TREE_TYPE (newdecl) + = build_type_attribute_variant + (newtype, + merge_attributes (TYPE_ATTRIBUTES (newtype), + TYPE_ATTRIBUTES (oldtype))); + else + TREE_TYPE (newdecl) + = TREE_TYPE (olddecl) + = common_type (newtype, oldtype); + } + + /* Lay the type out, unless already done. */ + if (oldtype != TREE_TYPE (newdecl)) + { + if (TREE_TYPE (newdecl) != error_mark_node) + layout_type (TREE_TYPE (newdecl)); + if (TREE_CODE (newdecl) != FUNCTION_DECL + && TREE_CODE (newdecl) != TYPE_DECL + && TREE_CODE (newdecl) != CONST_DECL) + layout_decl (newdecl, 0); + } + else + { + /* Since the type is OLDDECL's, make OLDDECL's size go with. */ + DECL_SIZE (newdecl) = DECL_SIZE (olddecl); + if (TREE_CODE (olddecl) != FUNCTION_DECL) + if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl)) + DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl); + } + + /* Keep the old rtl since we can safely use it. */ + DECL_RTL (newdecl) = DECL_RTL (olddecl); + + /* Merge the type qualifiers. */ + if (DECL_BUILT_IN_NONANSI (olddecl) && TREE_THIS_VOLATILE (olddecl) + && !TREE_THIS_VOLATILE (newdecl)) + TREE_THIS_VOLATILE (write_olddecl) = 0; + if (TREE_READONLY (newdecl)) + TREE_READONLY (write_olddecl) = 1; + if (TREE_THIS_VOLATILE (newdecl)) + { + TREE_THIS_VOLATILE (write_olddecl) = 1; + if (TREE_CODE (newdecl) == VAR_DECL) + make_var_volatile (newdecl); + } + + /* Keep source location of definition rather than declaration. */ + /* When called with different_binding_level set, keep the old + information so that meaningful diagnostics can be given. */ + if (DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0 + && ! different_binding_level) + { + DECL_SOURCE_LINE (newdecl) = DECL_SOURCE_LINE (olddecl); + DECL_SOURCE_FILE (newdecl) = DECL_SOURCE_FILE (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 (write_olddecl) = 1; + + /* Merge the initialization information. */ + /* When called with different_binding_level set, don't copy over + DECL_INITIAL, so that we don't accidentally change function + declarations into function definitions. */ + if (DECL_INITIAL (newdecl) == 0 && ! different_binding_level) + DECL_INITIAL (newdecl) = DECL_INITIAL (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); + + if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl); + DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl); + + DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl) + |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl); + DECL_NO_CHECK_MEMORY_USAGE (newdecl) + |= DECL_NO_CHECK_MEMORY_USAGE (olddecl); + } + + pop_obstacks (); + } + /* If cannot merge, then use the new type and qualifiers, + and don't preserve the old rtl. */ + else if (! different_binding_level) + { + TREE_TYPE (olddecl) = TREE_TYPE (newdecl); + TREE_READONLY (olddecl) = TREE_READONLY (newdecl); + TREE_THIS_VOLATILE (olddecl) = TREE_THIS_VOLATILE (newdecl); + TREE_SIDE_EFFECTS (olddecl) = TREE_SIDE_EFFECTS (newdecl); + } + + /* Merge the storage class information. */ + DECL_WEAK (newdecl) |= DECL_WEAK (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. */ + /* No need to worry about different_binding_level here because + then TREE_PUBLIC (newdecl) was true. */ + 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); + DECL_EXTERNAL (newdecl) = DECL_EXTERNAL (olddecl); + /* An extern decl does not override previous storage class. */ + TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl); + if (! DECL_EXTERNAL (newdecl)) + DECL_CONTEXT (newdecl) = DECL_CONTEXT (olddecl); + } + else + { + TREE_STATIC (olddecl) = TREE_STATIC (newdecl); + TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl); + } + + /* If either decl says `inline', this fn is inline, + unless its definition was passed already. */ + if (DECL_INLINE (newdecl) && DECL_INITIAL (olddecl) == 0) + DECL_INLINE (olddecl) = 1; + DECL_INLINE (newdecl) = DECL_INLINE (olddecl); + + if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + if (DECL_BUILT_IN (olddecl)) + { + /* Get rid of any built-in function if new arg types don't match it + or if we have a function definition. */ + if (! types_match || new_is_definition) + { + if (! different_binding_level) + { + TREE_TYPE (olddecl) = TREE_TYPE (newdecl); + DECL_BUILT_IN (olddecl) = 0; + } + } + else + { + /* If redeclaring a builtin function, and not a definition, + it stays built in. */ + DECL_BUILT_IN (newdecl) = 1; + DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl); + } + } + /* Also preserve various other info from the definition. */ + else if (! new_is_definition) + DECL_FRAME_SIZE (newdecl) = DECL_FRAME_SIZE (olddecl); + if (! new_is_definition) + { + DECL_RESULT (newdecl) = DECL_RESULT (olddecl); + /* When called with different_binding_level set, don't copy over + DECL_INITIAL, so that we don't accidentally change function + declarations into function definitions. */ + if (! different_binding_level) + DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); + DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl); + DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl); + if (DECL_INLINE (newdecl)) + DECL_ABSTRACT_ORIGIN (newdecl) = DECL_ORIGIN (olddecl); + } + } + if (different_binding_level) + { + /* Don't output a duplicate symbol or debugging information for this + declaration. + + Do not set TREE_ASM_WRITTEN for a FUNCTION_DECL since we may actually + just have two declarations without a definition. VAR_DECLs may need + the same treatment, I'm not sure. */ + if (TREE_CODE (newdecl) == FUNCTION_DECL) + DECL_IGNORED_P (newdecl) = 1; + else + TREE_ASM_WRITTEN (newdecl) = DECL_IGNORED_P (newdecl) = 1; + return 0; + } + + /* Copy most of the decl-specific fields of NEWDECL into OLDDECL. + But preserve OLDDECL's DECL_UID. */ + { + register unsigned olddecl_uid = DECL_UID (olddecl); + + bcopy ((char *) newdecl + sizeof (struct tree_common), + (char *) olddecl + sizeof (struct tree_common), + sizeof (struct tree_decl) - sizeof (struct tree_common)); + DECL_UID (olddecl) = olddecl_uid; + } + + /* NEWDECL contains the merged attribute lists. + Update OLDDECL to be the same. */ + DECL_MACHINE_ATTRIBUTES (olddecl) = DECL_MACHINE_ATTRIBUTES (newdecl); + + return 1; +} + +/* Record a decl-node X as belonging to the current lexical scope. + Check for errors (such as an incompatible declaration for the same + name already seen in the same scope). + + Returns either X or an old decl for the same name. + If an old decl is returned, it may have been smashed + to agree with what X says. */ + +tree +pushdecl (x) + tree x; +{ + register tree t; + register tree name = DECL_NAME (x); + register struct binding_level *b = current_binding_level; + + DECL_CONTEXT (x) = current_function_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 (TREE_CODE (x) == FUNCTION_DECL && DECL_INITIAL (x) == 0 + && DECL_EXTERNAL (x)) + DECL_CONTEXT (x) = 0; + + if (warn_nested_externs && DECL_EXTERNAL (x) && b != global_binding_level + && x != IDENTIFIER_IMPLICIT_DECL (name) + /* Don't print error messages for __FUNCTION__ and __PRETTY_FUNCTION__ */ + && !DECL_IN_SYSTEM_HEADER (x)) + warning ("nested extern declaration of `%s'", IDENTIFIER_POINTER (name)); + + if (name) + { + char *file; + int line; + int different_binding_level = 0; + + t = lookup_name_current_level (name); + /* Don't type check externs here when -traditional. This is so that + code with conflicting declarations inside blocks will get warnings + not errors. X11 for instance depends on this. */ + if (! t && DECL_EXTERNAL (x) && TREE_PUBLIC (x) && ! flag_traditional) + { + t = IDENTIFIER_GLOBAL_VALUE (name); + /* Type decls at global scope don't conflict with externs declared + inside lexical blocks. */ + if (t && TREE_CODE (t) == TYPE_DECL) + t = 0; + different_binding_level = 1; + } + if (t != 0 && t == error_mark_node) + /* error_mark_node is 0 for a while during initialization! */ + { + t = 0; + error_with_decl (x, "`%s' used prior to declaration"); + } + + if (t != 0) + { + file = DECL_SOURCE_FILE (t); + line = DECL_SOURCE_LINE (t); + } + + /* If this decl is `static' and an implicit decl was seen previously, + warn. But don't complain if -traditional, + since traditional compilers don't complain. */ + if (! flag_traditional && TREE_PUBLIC (name) + /* Don't test for DECL_EXTERNAL, because grokdeclarator + sets this for all functions. */ + && ! TREE_PUBLIC (x) + && (TREE_CODE (x) == FUNCTION_DECL || b == global_binding_level) + /* We used to warn also for explicit extern followed by static, + but sometimes you need to do it that way. */ + && IDENTIFIER_IMPLICIT_DECL (name) != 0) + { + pedwarn ("`%s' was declared implicitly `extern' and later `static'", + IDENTIFIER_POINTER (name)); + pedwarn_with_file_and_line + (DECL_SOURCE_FILE (IDENTIFIER_IMPLICIT_DECL (name)), + DECL_SOURCE_LINE (IDENTIFIER_IMPLICIT_DECL (name)), + "previous declaration of `%s'", + IDENTIFIER_POINTER (name)); + TREE_THIS_VOLATILE (name) = 1; + } + + if (t != 0 && duplicate_decls (x, t, different_binding_level)) + { + if (TREE_CODE (t) == PARM_DECL) + { + /* Don't allow more than one "real" duplicate + of a forward parm decl. */ + TREE_ASM_WRITTEN (t) = TREE_ASM_WRITTEN (x); + return t; + } + return t; + } + + /* If we are processing a typedef statement, generate a whole new + ..._TYPE node (which will be just an variant of the existing + ..._TYPE node with identical properties) and then install the + TYPE_DECL node generated to represent the typedef name as the + TYPE_NAME of this brand new (duplicate) ..._TYPE node. + + The whole point here is to end up with a situation where each + and every ..._TYPE node the compiler creates will be uniquely + associated with AT MOST one node representing a typedef name. + This way, even though the compiler substitutes corresponding + ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very + early on, later parts of the compiler can always do the reverse + translation and get back the corresponding typedef name. For + example, given: + + typedef struct S MY_TYPE; + MY_TYPE object; + + Later parts of the compiler might only know that `object' was of + type `struct S' if it were not for code just below. With this + code however, later parts of the compiler see something like: + + struct S' == struct S + typedef struct S' MY_TYPE; + struct S' object; + + And they can then deduce (from the node for type struct S') that + the original object declaration was: + + MY_TYPE object; + + Being able to do this is important for proper support of protoize, + and also for generating precise symbolic debugging information + which takes full account of the programmer's (typedef) vocabulary. + + Obviously, we don't want to generate a duplicate ..._TYPE node if + the TYPE_DECL node that we are now processing really represents a + standard built-in type. + + Since all standard types are effectively declared at line zero + in the source file, we can easily check to see if we are working + on a standard type by checking the current value of lineno. */ + + if (TREE_CODE (x) == TYPE_DECL) + { + if (DECL_SOURCE_LINE (x) == 0) + { + if (TYPE_NAME (TREE_TYPE (x)) == 0) + TYPE_NAME (TREE_TYPE (x)) = x; + } + else if (TREE_TYPE (x) != error_mark_node + && DECL_ORIGINAL_TYPE (x) == NULL_TREE) + { + tree tt = TREE_TYPE (x); + DECL_ORIGINAL_TYPE (x) = tt; + tt = build_type_copy (tt); + TYPE_NAME (tt) = x; + TREE_TYPE (x) = tt; + } + } + + /* Multiple external decls of the same identifier ought to match. + Check against both global declarations (when traditional) and out of + scope (limbo) block level declarations. + + We get warnings about inline functions where they are defined. + Avoid duplicate warnings where they are used. */ + if (TREE_PUBLIC (x) && ! DECL_INLINE (x)) + { + tree decl; + + if (flag_traditional && IDENTIFIER_GLOBAL_VALUE (name) != 0 + && (DECL_EXTERNAL (IDENTIFIER_GLOBAL_VALUE (name)) + || TREE_PUBLIC (IDENTIFIER_GLOBAL_VALUE (name)))) + decl = IDENTIFIER_GLOBAL_VALUE (name); + else if (IDENTIFIER_LIMBO_VALUE (name) != 0) + /* Decls in limbo are always extern, so no need to check that. */ + decl = IDENTIFIER_LIMBO_VALUE (name); + else + decl = 0; + + if (decl && ! comptypes (TREE_TYPE (x), TREE_TYPE (decl)) + /* If old decl is built-in, we already warned if we should. */ + && !DECL_BUILT_IN (decl)) + { + pedwarn_with_decl (x, + "type mismatch with previous external decl"); + pedwarn_with_decl (decl, "previous external decl of `%s'"); + } + } + + /* If a function has had an implicit declaration, and then is defined, + make sure they are compatible. */ + + if (IDENTIFIER_IMPLICIT_DECL (name) != 0 + && IDENTIFIER_GLOBAL_VALUE (name) == 0 + && TREE_CODE (x) == FUNCTION_DECL + && ! comptypes (TREE_TYPE (x), + TREE_TYPE (IDENTIFIER_IMPLICIT_DECL (name)))) + { + warning_with_decl (x, "type mismatch with previous implicit declaration"); + warning_with_decl (IDENTIFIER_IMPLICIT_DECL (name), + "previous implicit declaration of `%s'"); + } + + /* In PCC-compatibility mode, extern decls of vars with no current decl + take effect at top level no matter where they are. */ + if (flag_traditional && DECL_EXTERNAL (x) + && lookup_name (name) == 0) + { + tree type = TREE_TYPE (x); + + /* But don't do this if the type contains temporary nodes. */ + while (type) + { + if (type == error_mark_node) + break; + if (! TREE_PERMANENT (type)) + { + warning_with_decl (x, "type of external `%s' is not global"); + /* By exiting the loop early, we leave TYPE nonzero, + and thus prevent globalization of the decl. */ + break; + } + else if (TREE_CODE (type) == FUNCTION_TYPE + && TYPE_ARG_TYPES (type) != 0) + /* The types might not be truly local, + but the list of arg types certainly is temporary. + Since prototypes are nontraditional, + ok not to do the traditional thing. */ + break; + type = TREE_TYPE (type); + } + + if (type == 0) + b = global_binding_level; + } + + /* This name is new in its binding level. + Install the new declaration and return it. */ + if (b == global_binding_level) + { + /* Install a global value. */ + + /* If the first global decl has external linkage, + warn if we later see static one. */ + if (IDENTIFIER_GLOBAL_VALUE (name) == 0 && TREE_PUBLIC (x)) + TREE_PUBLIC (name) = 1; + + IDENTIFIER_GLOBAL_VALUE (name) = x; + + /* We no longer care about any previous block level declarations. */ + IDENTIFIER_LIMBO_VALUE (name) = 0; + + /* Don't forget if the function was used via an implicit decl. */ + if (IDENTIFIER_IMPLICIT_DECL (name) + && TREE_USED (IDENTIFIER_IMPLICIT_DECL (name))) + TREE_USED (x) = 1, TREE_USED (name) = 1; + + /* Don't forget if its address was taken in that way. */ + if (IDENTIFIER_IMPLICIT_DECL (name) + && TREE_ADDRESSABLE (IDENTIFIER_IMPLICIT_DECL (name))) + TREE_ADDRESSABLE (x) = 1; + + /* Warn about mismatches against previous implicit decl. */ + if (IDENTIFIER_IMPLICIT_DECL (name) != 0 + /* If this real decl matches the implicit, don't complain. */ + && ! (TREE_CODE (x) == FUNCTION_DECL + && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (x))) + == integer_type_node))) + pedwarn ("`%s' was previously implicitly declared to return `int'", + IDENTIFIER_POINTER (name)); + + /* If this decl is `static' and an `extern' was seen previously, + that is erroneous. */ + if (TREE_PUBLIC (name) + && ! TREE_PUBLIC (x) && ! DECL_EXTERNAL (x)) + { + /* Okay to redeclare an ANSI built-in as static. */ + if (t != 0 && DECL_BUILT_IN (t)) + ; + /* Okay to declare a non-ANSI built-in as anything. */ + else if (t != 0 && DECL_BUILT_IN_NONANSI (t)) + ; + /* Okay to have global type decl after an earlier extern + declaration inside a lexical block. */ + else if (TREE_CODE (x) == TYPE_DECL) + ; + else if (IDENTIFIER_IMPLICIT_DECL (name)) + { + if (! TREE_THIS_VOLATILE (name)) + pedwarn ("`%s' was declared implicitly `extern' and later `static'", + IDENTIFIER_POINTER (name)); + } + else + pedwarn ("`%s' was declared `extern' and later `static'", + IDENTIFIER_POINTER (name)); + } + } + else + { + /* Here to install a non-global value. */ + tree oldlocal = IDENTIFIER_LOCAL_VALUE (name); + tree oldglobal = IDENTIFIER_GLOBAL_VALUE (name); + IDENTIFIER_LOCAL_VALUE (name) = x; + + /* If this is an extern function declaration, see if we + have a global definition or declaration for the function. */ + if (oldlocal == 0 + && DECL_EXTERNAL (x) && !DECL_INLINE (x) + && oldglobal != 0 + && TREE_CODE (x) == FUNCTION_DECL + && TREE_CODE (oldglobal) == FUNCTION_DECL) + { + /* We have one. Their types must agree. */ + if (! comptypes (TREE_TYPE (x), + TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (name)))) + pedwarn_with_decl (x, "extern declaration of `%s' doesn't match global one"); + else + { + /* Inner extern decl is inline if global one is. + Copy enough to really inline it. */ + if (DECL_INLINE (oldglobal)) + { + DECL_INLINE (x) = DECL_INLINE (oldglobal); + DECL_INITIAL (x) = (current_function_decl == oldglobal + ? 0 : DECL_INITIAL (oldglobal)); + DECL_SAVED_INSNS (x) = DECL_SAVED_INSNS (oldglobal); + DECL_FRAME_SIZE (x) = DECL_FRAME_SIZE (oldglobal); + DECL_ARGUMENTS (x) = DECL_ARGUMENTS (oldglobal); + DECL_RESULT (x) = DECL_RESULT (oldglobal); + TREE_ASM_WRITTEN (x) = TREE_ASM_WRITTEN (oldglobal); + DECL_ABSTRACT_ORIGIN (x) = DECL_ORIGIN (oldglobal); + } + /* Inner extern decl is built-in if global one is. */ + if (DECL_BUILT_IN (oldglobal)) + { + DECL_BUILT_IN (x) = DECL_BUILT_IN (oldglobal); + DECL_FUNCTION_CODE (x) = DECL_FUNCTION_CODE (oldglobal); + } + /* Keep the arg types from a file-scope fcn defn. */ + if (TYPE_ARG_TYPES (TREE_TYPE (oldglobal)) != 0 + && DECL_INITIAL (oldglobal) + && TYPE_ARG_TYPES (TREE_TYPE (x)) == 0) + TREE_TYPE (x) = TREE_TYPE (oldglobal); + } + } + +#if 0 /* This case is probably sometimes the right thing to do. */ + /* If we have a local external declaration, + then any file-scope declaration should not + have been static. */ + if (oldlocal == 0 && oldglobal != 0 + && !TREE_PUBLIC (oldglobal) + && DECL_EXTERNAL (x) && TREE_PUBLIC (x)) + warning ("`%s' locally external but globally static", + IDENTIFIER_POINTER (name)); +#endif + + /* If we have a local external declaration, + and no file-scope declaration has yet been seen, + then if we later have a file-scope decl it must not be static. */ + if (oldlocal == 0 + && DECL_EXTERNAL (x) + && TREE_PUBLIC (x)) + { + if (oldglobal == 0) + TREE_PUBLIC (name) = 1; + + /* Save this decl, so that we can do type checking against + other decls after it falls out of scope. + + Only save it once. This prevents temporary decls created in + expand_inline_function from being used here, since this + will have been set when the inline function was parsed. + It also helps give slightly better warnings. */ + if (IDENTIFIER_LIMBO_VALUE (name) == 0) + IDENTIFIER_LIMBO_VALUE (name) = x; + } + + /* Warn if shadowing an argument at the top level of the body. */ + if (oldlocal != 0 && !DECL_EXTERNAL (x) + /* This warning doesn't apply to the parms of a nested fcn. */ + && ! current_binding_level->parm_flag + /* Check that this is one level down from the parms. */ + && current_binding_level->level_chain->parm_flag + /* Check that the decl being shadowed + comes from the parm level, one level up. */ + && chain_member (oldlocal, current_binding_level->level_chain->names)) + { + if (TREE_CODE (oldlocal) == PARM_DECL) + pedwarn ("declaration of `%s' shadows a parameter", + IDENTIFIER_POINTER (name)); + else + pedwarn ("declaration of `%s' shadows a symbol from the parameter list", + IDENTIFIER_POINTER (name)); + } + + /* Maybe warn if shadowing something else. */ + else if (warn_shadow && !DECL_EXTERNAL (x) + /* No shadow warnings for internally generated vars. */ + && DECL_SOURCE_LINE (x) != 0 + /* No shadow warnings for vars made for inlining. */ + && ! DECL_FROM_INLINE (x)) + { + char *warnstring = 0; + + if (TREE_CODE (x) == PARM_DECL + && current_binding_level->level_chain->parm_flag) + /* 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. */ + ; + else if (oldlocal != 0 && TREE_CODE (oldlocal) == PARM_DECL) + warnstring = "declaration of `%s' shadows a parameter"; + else if (oldlocal != 0) + warnstring = "declaration of `%s' shadows previous local"; + else if (IDENTIFIER_GLOBAL_VALUE (name) != 0 + && IDENTIFIER_GLOBAL_VALUE (name) != error_mark_node) + warnstring = "declaration of `%s' shadows global declaration"; + + if (warnstring) + warning (warnstring, IDENTIFIER_POINTER (name)); + } + + /* If storing a local value, there may already be one (inherited). + If so, record it for restoration when this binding level ends. */ + if (oldlocal != 0) + b->shadowed = tree_cons (name, oldlocal, b->shadowed); + } + + /* Keep count of variables in this level with incomplete type. */ + if (TYPE_SIZE (TREE_TYPE (x)) == 0) + ++b->n_incomplete; + } + + /* Put decls on list in reverse order. + We will reverse them later if necessary. */ + TREE_CHAIN (x) = b->names; + b->names = x; + + return x; +} + +/* Like pushdecl, only it places X in GLOBAL_BINDING_LEVEL, if appropriate. */ + +tree +pushdecl_top_level (x) + tree x; +{ + register tree t; + register struct binding_level *b = current_binding_level; + + current_binding_level = global_binding_level; + t = pushdecl (x); + current_binding_level = b; + return t; +} + +/* Generate an implicit declaration for identifier FUNCTIONID + as a function of type int (). Print a warning if appropriate. */ + +tree +implicitly_declare (functionid) + tree functionid; +{ + register tree decl; + int traditional_warning = 0; + /* Only one "implicit declaration" warning per identifier. */ + int implicit_warning; + + /* Save the decl permanently so we can warn if definition follows. */ + push_obstacks_nochange (); + end_temporary_allocation (); + + /* We used to reuse an old implicit decl here, + but this loses with inline functions because it can clobber + the saved decl chains. */ +/* if (IDENTIFIER_IMPLICIT_DECL (functionid) != 0) + decl = IDENTIFIER_IMPLICIT_DECL (functionid); + else */ + decl = build_decl (FUNCTION_DECL, functionid, default_function_type); + + /* Warn of implicit decl following explicit local extern decl. + This is probably a program designed for traditional C. */ + if (TREE_PUBLIC (functionid) && IDENTIFIER_GLOBAL_VALUE (functionid) == 0) + traditional_warning = 1; + + /* Warn once of an implicit declaration. */ + implicit_warning = (IDENTIFIER_IMPLICIT_DECL (functionid) == 0); + + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + + /* Record that we have an implicit decl and this is it. */ + IDENTIFIER_IMPLICIT_DECL (functionid) = decl; + + /* ANSI standard says implicit declarations are in the innermost block. + So we record the decl in the standard fashion. + If flag_traditional is set, pushdecl does it top-level. */ + pushdecl (decl); + + /* This is a no-op in c-lang.c or something real in objc-actions.c. */ + maybe_objc_check_decl (decl); + + rest_of_decl_compilation (decl, NULL_PTR, 0, 0); + + if (mesg_implicit_function_declaration && implicit_warning) + { + if (mesg_implicit_function_declaration == 2) + error ("implicit declaration of function `%s'", + IDENTIFIER_POINTER (functionid)); + else + warning ("implicit declaration of function `%s'", + IDENTIFIER_POINTER (functionid)); + } + else if (warn_traditional && traditional_warning) + warning ("function `%s' was previously declared within a block", + IDENTIFIER_POINTER (functionid)); + + /* Write a record describing this implicit function declaration to the + prototypes file (if requested). */ + + gen_aux_info_record (decl, 0, 1, 0); + + pop_obstacks (); + + 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. + Otherwise return an error message format string with a %s + where the identifier should go. */ + +static char * +redeclaration_error_message (newdecl, olddecl) + tree newdecl, olddecl; +{ + if (TREE_CODE (newdecl) == TYPE_DECL) + { + if (flag_traditional && TREE_TYPE (newdecl) == TREE_TYPE (olddecl)) + return 0; + /* pushdecl creates distinct types for TYPE_DECLs by calling + build_type_copy, so the above comparison generally fails. We do + another test against the TYPE_MAIN_VARIANT of the olddecl, which + is equivalent to what this code used to do before the build_type_copy + call. The variant type distinction should not matter for traditional + code, because it doesn't have type qualifiers. */ + if (flag_traditional + && TYPE_MAIN_VARIANT (TREE_TYPE (olddecl)) == TREE_TYPE (newdecl)) + return 0; + if (DECL_IN_SYSTEM_HEADER (olddecl) || DECL_IN_SYSTEM_HEADER (newdecl)) + return 0; + return "redefinition of `%s'"; + } + else if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + /* Declarations of functions can insist on internal linkage + but they can't be inconsistent with internal linkage, + so there can be no error on that account. + However defining the same name twice is no good. */ + if (DECL_INITIAL (olddecl) != 0 && DECL_INITIAL (newdecl) != 0 + /* However, defining once as extern inline and a second + time in another way is ok. */ + && !(DECL_INLINE (olddecl) && DECL_EXTERNAL (olddecl) + && !(DECL_INLINE (newdecl) && DECL_EXTERNAL (newdecl)))) + return "redefinition of `%s'"; + return 0; + } + else if (current_binding_level == global_binding_level) + { + /* Objects declared at top level: */ + /* If at least one is a reference, it's ok. */ + if (DECL_EXTERNAL (newdecl) || DECL_EXTERNAL (olddecl)) + return 0; + /* Reject two definitions. */ + if (DECL_INITIAL (olddecl) != 0 && DECL_INITIAL (newdecl) != 0) + return "redefinition of `%s'"; + /* Now we have two tentative defs, or one tentative and one real def. */ + /* Insist that the linkage match. */ + if (TREE_PUBLIC (olddecl) != TREE_PUBLIC (newdecl)) + return "conflicting declarations of `%s'"; + return 0; + } + else if (current_binding_level->parm_flag + && TREE_ASM_WRITTEN (olddecl) && !TREE_ASM_WRITTEN (newdecl)) + return 0; + else + { + /* Newdecl has block scope. If olddecl has block scope also, then + reject two definitions, and reject a definition together with an + external reference. Otherwise, it is OK, because newdecl must + be an extern reference to olddecl. */ + if (!(DECL_EXTERNAL (newdecl) && DECL_EXTERNAL (olddecl)) + && DECL_CONTEXT (newdecl) == DECL_CONTEXT (olddecl)) + return "redeclaration of `%s'"; + return 0; + } +} + +/* Get the LABEL_DECL corresponding to identifier ID as a label. + Create one if none exists so far for the current function. + This function is called for both label definitions and label references. */ + +tree +lookup_label (id) + tree id; +{ + register tree decl = IDENTIFIER_LABEL_VALUE (id); + + if (current_function_decl == 0) + { + error ("label %s referenced outside of any function", + IDENTIFIER_POINTER (id)); + return 0; + } + + /* Use a label already defined or ref'd with this name. */ + if (decl != 0) + { + /* But not if it is inherited and wasn't declared to be inheritable. */ + if (DECL_CONTEXT (decl) != current_function_decl + && ! C_DECLARED_LABEL_FLAG (decl)) + return shadow_label (id); + return decl; + } + + decl = build_decl (LABEL_DECL, id, void_type_node); + + /* Make sure every label has an rtx. */ + label_rtx (decl); + + /* A label not explicitly declared must be local to where it's ref'd. */ + DECL_CONTEXT (decl) = current_function_decl; + + DECL_MODE (decl) = VOIDmode; + + /* Say where one reference is to the label, + for the sake of the error if it is not defined. */ + DECL_SOURCE_LINE (decl) = lineno; + DECL_SOURCE_FILE (decl) = input_filename; + + IDENTIFIER_LABEL_VALUE (id) = decl; + + named_labels = tree_cons (NULL_TREE, decl, named_labels); + + return decl; +} + +/* Make a label named NAME in the current function, + shadowing silently any that may be inherited from containing functions + or containing scopes. + + Note that valid use, if the label being shadowed + comes from another scope in the same function, + requires calling declare_nonlocal_label right away. */ + +tree +shadow_label (name) + tree name; +{ + register tree decl = IDENTIFIER_LABEL_VALUE (name); + + if (decl != 0) + { + register tree dup; + + /* Check to make sure that the label hasn't already been declared + at this label scope */ + for (dup = named_labels; dup; dup = TREE_CHAIN (dup)) + if (TREE_VALUE (dup) == decl) + { + error ("duplicate label declaration `%s'", + IDENTIFIER_POINTER (name)); + error_with_decl (TREE_VALUE (dup), + "this is a previous declaration"); + /* Just use the previous declaration. */ + return lookup_label (name); + } + + shadowed_labels = tree_cons (NULL_TREE, decl, shadowed_labels); + IDENTIFIER_LABEL_VALUE (name) = decl = 0; + } + + return lookup_label (name); +} + +/* Define a label, specifying the location in the source file. + Return the LABEL_DECL node for the label, if the definition is valid. + Otherwise return 0. */ + +tree +define_label (filename, line, name) + char *filename; + int line; + tree name; +{ + tree decl = lookup_label (name); + + /* If label with this name is known from an outer context, shadow it. */ + if (decl != 0 && DECL_CONTEXT (decl) != current_function_decl) + { + shadowed_labels = tree_cons (NULL_TREE, decl, shadowed_labels); + IDENTIFIER_LABEL_VALUE (name) = 0; + decl = lookup_label (name); + } + + if (DECL_INITIAL (decl) != 0) + { + error ("duplicate label `%s'", IDENTIFIER_POINTER (name)); + return 0; + } + else + { + /* Mark label as having been defined. */ + DECL_INITIAL (decl) = error_mark_node; + /* Say where in the source. */ + DECL_SOURCE_FILE (decl) = filename; + DECL_SOURCE_LINE (decl) = line; + return decl; + } +} + +/* Return the list of declarations of the current level. + Note that this list is in reverse order unless/until + you nreverse it; and when you do nreverse it, you must + store the result back using `storedecls' or you will lose. */ + +tree +getdecls () +{ + return current_binding_level->names; +} + +/* Return the list of type-tags (for structs, etc) of the current level. */ + +tree +gettags () +{ + return current_binding_level->tags; +} + +/* Store the list of declarations of the current level. + This is done for the parameter declarations of a function being defined, + after they are modified in the light of any missing parameters. */ + +static void +storedecls (decls) + tree decls; +{ + current_binding_level->names = decls; +} + +/* Similarly, store the list of tags of the current level. */ + +static void +storetags (tags) + tree tags; +{ + current_binding_level->tags = tags; +} + +/* Given NAME, an IDENTIFIER_NODE, + return the structure (or union or enum) definition for that name. + Searches binding levels from BINDING_LEVEL up to the global level. + If THISLEVEL_ONLY is nonzero, searches only the specified context + (but skips any tag-transparent contexts to find one that is + meaningful for tags). + CODE says which kind of type the caller wants; + it is RECORD_TYPE or UNION_TYPE or ENUMERAL_TYPE. + If the wrong kind of type is found, an error is reported. */ + +static tree +lookup_tag (code, name, binding_level, thislevel_only) + enum tree_code code; + struct binding_level *binding_level; + tree name; + int thislevel_only; +{ + register struct binding_level *level; + + for (level = binding_level; level; level = level->level_chain) + { + register tree tail; + for (tail = level->tags; tail; tail = TREE_CHAIN (tail)) + { + if (TREE_PURPOSE (tail) == name) + { + if (TREE_CODE (TREE_VALUE (tail)) != code) + { + /* Definition isn't the kind we were looking for. */ + pending_invalid_xref = name; + pending_invalid_xref_file = input_filename; + pending_invalid_xref_line = lineno; + } + return TREE_VALUE (tail); + } + } + if (thislevel_only && ! level->tag_transparent) + return NULL_TREE; + } + return NULL_TREE; +} + +/* Print an error message now + for a recent invalid struct, union or enum cross reference. + We don't print them immediately because they are not invalid + when used in the `struct foo;' construct for shadowing. */ + +void +pending_xref_error () +{ + if (pending_invalid_xref != 0) + error_with_file_and_line (pending_invalid_xref_file, + pending_invalid_xref_line, + "`%s' defined as wrong kind of tag", + IDENTIFIER_POINTER (pending_invalid_xref)); + pending_invalid_xref = 0; +} + +/* Given a type, find the tag that was defined for it and return the tag name. + Otherwise return 0. */ + +static tree +lookup_tag_reverse (type) + tree type; +{ + register struct binding_level *level; + + for (level = current_binding_level; level; level = level->level_chain) + { + register tree tail; + for (tail = level->tags; tail; tail = TREE_CHAIN (tail)) + { + if (TREE_VALUE (tail) == type) + return TREE_PURPOSE (tail); + } + } + return NULL_TREE; +} + +/* Look up NAME in the current binding level and its superiors + in the namespace of variables, functions and typedefs. + Return a ..._DECL node of some kind representing its definition, + or return 0 if it is undefined. */ + +tree +lookup_name (name) + tree name; +{ + register tree val; + if (current_binding_level != global_binding_level + && IDENTIFIER_LOCAL_VALUE (name)) + val = IDENTIFIER_LOCAL_VALUE (name); + else + val = IDENTIFIER_GLOBAL_VALUE (name); + return val; +} + +/* Similar to `lookup_name' but look only at current binding level. */ + +tree +lookup_name_current_level (name) + tree name; +{ + register tree t; + + if (current_binding_level == global_binding_level) + return IDENTIFIER_GLOBAL_VALUE (name); + + if (IDENTIFIER_LOCAL_VALUE (name) == 0) + return 0; + + for (t = current_binding_level->names; t; t = TREE_CHAIN (t)) + if (DECL_NAME (t) == name) + break; + + return t; +} + +/* Create the predefined scalar types of C, + and some nodes representing standard constants (0, 1, (void *) 0). + Initialize the global binding level. + Make definitions for built-in primitive functions. */ + +void +init_decl_processing () +{ + register tree endlink; + /* Either char* or void*. */ + tree traditional_ptr_type_node; + /* Data types of memcpy and strlen. */ + tree memcpy_ftype, memset_ftype, strlen_ftype; + tree void_ftype_any, ptr_ftype_void, ptr_ftype_ptr; + int wchar_type_size; + tree temp; + tree array_domain_type; + + current_function_decl = NULL; + named_labels = NULL; + current_binding_level = NULL_BINDING_LEVEL; + free_binding_level = NULL_BINDING_LEVEL; + pushlevel (0); /* make the binding_level structure for global names */ + global_binding_level = current_binding_level; + + /* Define `int' and `char' first so that dbx will output them first. */ + + integer_type_node = make_signed_type (INT_TYPE_SIZE); + pushdecl (build_decl (TYPE_DECL, ridpointers[(int) RID_INT], + integer_type_node)); + + /* Define `char', which is like either `signed char' or `unsigned char' + but not the same as either. */ + + char_type_node + = (flag_signed_char + ? make_signed_type (CHAR_TYPE_SIZE) + : make_unsigned_type (CHAR_TYPE_SIZE)); + pushdecl (build_decl (TYPE_DECL, get_identifier ("char"), + char_type_node)); + + long_integer_type_node = make_signed_type (LONG_TYPE_SIZE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("long int"), + long_integer_type_node)); + + unsigned_type_node = make_unsigned_type (INT_TYPE_SIZE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned int"), + unsigned_type_node)); + + long_unsigned_type_node = make_unsigned_type (LONG_TYPE_SIZE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("long unsigned int"), + long_unsigned_type_node)); + + long_long_integer_type_node = make_signed_type (LONG_LONG_TYPE_SIZE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("long long int"), + long_long_integer_type_node)); + + long_long_unsigned_type_node = make_unsigned_type (LONG_LONG_TYPE_SIZE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("long long unsigned int"), + long_long_unsigned_type_node)); + + short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("short int"), + short_integer_type_node)); + + short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("short unsigned int"), + short_unsigned_type_node)); + + /* `unsigned long' is the standard type for sizeof. + Traditionally, use a signed type. + Note that stddef.h uses `unsigned long', + and this must agree, even if long and int are the same size. */ + set_sizetype + (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE)))); + if (flag_traditional && TREE_UNSIGNED (sizetype)) + set_sizetype (signed_type (sizetype)); + + ptrdiff_type_node + = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (PTRDIFF_TYPE))); + + error_mark_node = make_node (ERROR_MARK); + TREE_TYPE (error_mark_node) = error_mark_node; + + /* Define both `signed char' and `unsigned char'. */ + signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("signed char"), + signed_char_type_node)); + + unsigned_char_type_node = make_unsigned_type (CHAR_TYPE_SIZE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned char"), + unsigned_char_type_node)); + + intQI_type_node = make_signed_type (GET_MODE_BITSIZE (QImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, intQI_type_node)); + + intHI_type_node = make_signed_type (GET_MODE_BITSIZE (HImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, intHI_type_node)); + + intSI_type_node = make_signed_type (GET_MODE_BITSIZE (SImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, intSI_type_node)); + + intDI_type_node = make_signed_type (GET_MODE_BITSIZE (DImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, intDI_type_node)); + +#if HOST_BITS_PER_WIDE_INT >= 64 + intTI_type_node = make_signed_type (GET_MODE_BITSIZE (TImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, intTI_type_node)); +#endif + + unsigned_intQI_type_node = make_unsigned_type (GET_MODE_BITSIZE (QImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intQI_type_node)); + + unsigned_intHI_type_node = make_unsigned_type (GET_MODE_BITSIZE (HImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intHI_type_node)); + + unsigned_intSI_type_node = make_unsigned_type (GET_MODE_BITSIZE (SImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intSI_type_node)); + + unsigned_intDI_type_node = make_unsigned_type (GET_MODE_BITSIZE (DImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intDI_type_node)); + +#if HOST_BITS_PER_WIDE_INT >= 64 + unsigned_intTI_type_node = make_unsigned_type (GET_MODE_BITSIZE (TImode)); + pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intTI_type_node)); +#endif + + float_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE; + pushdecl (build_decl (TYPE_DECL, ridpointers[(int) RID_FLOAT], + float_type_node)); + layout_type (float_type_node); + + double_type_node = make_node (REAL_TYPE); + if (flag_short_double) + TYPE_PRECISION (double_type_node) = FLOAT_TYPE_SIZE; + else + TYPE_PRECISION (double_type_node) = DOUBLE_TYPE_SIZE; + pushdecl (build_decl (TYPE_DECL, ridpointers[(int) RID_DOUBLE], + double_type_node)); + layout_type (double_type_node); + + long_double_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE; + pushdecl (build_decl (TYPE_DECL, get_identifier ("long double"), + long_double_type_node)); + layout_type (long_double_type_node); + + complex_integer_type_node = make_node (COMPLEX_TYPE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("complex int"), + complex_integer_type_node)); + TREE_TYPE (complex_integer_type_node) = integer_type_node; + layout_type (complex_integer_type_node); + + complex_float_type_node = make_node (COMPLEX_TYPE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("complex float"), + complex_float_type_node)); + TREE_TYPE (complex_float_type_node) = float_type_node; + layout_type (complex_float_type_node); + + complex_double_type_node = make_node (COMPLEX_TYPE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("complex double"), + complex_double_type_node)); + TREE_TYPE (complex_double_type_node) = double_type_node; + layout_type (complex_double_type_node); + + complex_long_double_type_node = make_node (COMPLEX_TYPE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("complex long double"), + complex_long_double_type_node)); + TREE_TYPE (complex_long_double_type_node) = long_double_type_node; + layout_type (complex_long_double_type_node); + + wchar_type_node + = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (WCHAR_TYPE))); + wchar_type_size = TYPE_PRECISION (wchar_type_node); + signed_wchar_type_node = signed_type (wchar_type_node); + unsigned_wchar_type_node = unsigned_type (wchar_type_node); + + integer_zero_node = build_int_2 (0, 0); + TREE_TYPE (integer_zero_node) = integer_type_node; + integer_one_node = build_int_2 (1, 0); + TREE_TYPE (integer_one_node) = integer_type_node; + + boolean_type_node = integer_type_node; + boolean_true_node = integer_one_node; + boolean_false_node = integer_zero_node; + + size_zero_node = build_int_2 (0, 0); + TREE_TYPE (size_zero_node) = sizetype; + size_one_node = build_int_2 (1, 0); + TREE_TYPE (size_one_node) = sizetype; + + void_type_node = make_node (VOID_TYPE); + pushdecl (build_decl (TYPE_DECL, + ridpointers[(int) RID_VOID], void_type_node)); + layout_type (void_type_node); /* Uses integer_zero_node */ + /* We are not going to have real types in C with less than byte alignment, + so we might as well not have any types that claim to have it. */ + TYPE_ALIGN (void_type_node) = BITS_PER_UNIT; + + null_pointer_node = build_int_2 (0, 0); + TREE_TYPE (null_pointer_node) = build_pointer_type (void_type_node); + layout_type (TREE_TYPE (null_pointer_node)); + + string_type_node = build_pointer_type (char_type_node); + const_string_type_node + = build_pointer_type (build_type_variant (char_type_node, 1, 0)); + + /* Make a type to be the domain of a few array types + whose domains don't really matter. + 200 is small enough that it always fits in size_t + and large enough that it can hold most function names for the + initializations of __FUNCTION__ and __PRETTY_FUNCTION__. */ + array_domain_type = build_index_type (build_int_2 (200, 0)); + + /* make a type for arrays of characters. + With luck nothing will ever really depend on the length of this + array type. */ + char_array_type_node + = build_array_type (char_type_node, array_domain_type); + /* Likewise for arrays of ints. */ + int_array_type_node + = build_array_type (integer_type_node, array_domain_type); + /* This is for wide string constants. */ + wchar_array_type_node + = build_array_type (wchar_type_node, array_domain_type); + + default_function_type + = build_function_type (integer_type_node, NULL_TREE); + + ptr_type_node = build_pointer_type (void_type_node); + const_ptr_type_node + = build_pointer_type (build_type_variant (void_type_node, 1, 0)); + + endlink = tree_cons (NULL_TREE, void_type_node, NULL_TREE); + + void_ftype_any + = build_function_type (void_type_node, NULL_TREE); + + float_ftype_float + = build_function_type (float_type_node, + tree_cons (NULL_TREE, float_type_node, endlink)); + + double_ftype_double + = build_function_type (double_type_node, + tree_cons (NULL_TREE, double_type_node, endlink)); + + ldouble_ftype_ldouble + = build_function_type (long_double_type_node, + tree_cons (NULL_TREE, long_double_type_node, + endlink)); + + double_ftype_double_double + = build_function_type (double_type_node, + tree_cons (NULL_TREE, double_type_node, + tree_cons (NULL_TREE, + double_type_node, endlink))); + + int_ftype_int + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, integer_type_node, endlink)); + + long_ftype_long + = build_function_type (long_integer_type_node, + tree_cons (NULL_TREE, + long_integer_type_node, endlink)); + + void_ftype_ptr_ptr_int + = build_function_type (void_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, + integer_type_node, + endlink)))); + + int_ftype_cptr_cptr_sizet + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, const_ptr_type_node, + tree_cons (NULL_TREE, const_ptr_type_node, + tree_cons (NULL_TREE, + sizetype, + endlink)))); + + void_ftype_ptr_int_int + = build_function_type (void_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, + integer_type_node, + endlink)))); + + string_ftype_ptr_ptr /* strcpy prototype */ + = build_function_type (string_type_node, + tree_cons (NULL_TREE, string_type_node, + tree_cons (NULL_TREE, + const_string_type_node, + endlink))); + + int_ftype_string_string /* strcmp prototype */ + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, const_string_type_node, + tree_cons (NULL_TREE, + const_string_type_node, + endlink))); + + strlen_ftype /* strlen prototype */ + = build_function_type (flag_traditional ? integer_type_node : sizetype, + tree_cons (NULL_TREE, const_string_type_node, + endlink)); + + traditional_ptr_type_node + = (flag_traditional ? string_type_node : ptr_type_node); + + memcpy_ftype /* memcpy prototype */ + = build_function_type (traditional_ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, const_ptr_type_node, + tree_cons (NULL_TREE, + sizetype, + endlink)))); + + memset_ftype /* memset prototype */ + = build_function_type (traditional_ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, + sizetype, + endlink)))); + + 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)); + + builtin_function ("__builtin_constant_p", default_function_type, + BUILT_IN_CONSTANT_P, NULL_PTR); + + builtin_function ("__builtin_return_address", + build_function_type (ptr_type_node, + tree_cons (NULL_TREE, + unsigned_type_node, + endlink)), + BUILT_IN_RETURN_ADDRESS, NULL_PTR); + + builtin_function ("__builtin_frame_address", + build_function_type (ptr_type_node, + tree_cons (NULL_TREE, + unsigned_type_node, + endlink)), + BUILT_IN_FRAME_ADDRESS, NULL_PTR); + + builtin_function ("__builtin_aggregate_incoming_address", + build_function_type (ptr_type_node, NULL_TREE), + BUILT_IN_AGGREGATE_INCOMING_ADDRESS, NULL_PTR); + + /* Hooks for the DWARF 2 __throw routine. */ + builtin_function ("__builtin_unwind_init", + build_function_type (void_type_node, endlink), + BUILT_IN_UNWIND_INIT, NULL_PTR); + builtin_function ("__builtin_dwarf_cfa", ptr_ftype_void, + BUILT_IN_DWARF_CFA, NULL_PTR); + builtin_function ("__builtin_dwarf_fp_regnum", + build_function_type (unsigned_type_node, endlink), + BUILT_IN_DWARF_FP_REGNUM, NULL_PTR); + builtin_function ("__builtin_dwarf_reg_size", int_ftype_int, + BUILT_IN_DWARF_REG_SIZE, NULL_PTR); + builtin_function ("__builtin_frob_return_addr", ptr_ftype_ptr, + BUILT_IN_FROB_RETURN_ADDR, NULL_PTR); + builtin_function ("__builtin_extract_return_addr", ptr_ftype_ptr, + BUILT_IN_EXTRACT_RETURN_ADDR, NULL_PTR); + builtin_function + ("__builtin_eh_return", + build_function_type (void_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, + type_for_mode (ptr_mode, 0), + tree_cons (NULL_TREE, + ptr_type_node, + endlink)))), + BUILT_IN_EH_RETURN, NULL_PTR); + + builtin_function ("__builtin_alloca", + build_function_type (ptr_type_node, + tree_cons (NULL_TREE, + sizetype, + endlink)), + BUILT_IN_ALLOCA, "alloca"); + builtin_function ("__builtin_ffs", int_ftype_int, BUILT_IN_FFS, NULL_PTR); + /* Define alloca, ffs as builtins. + Declare _exit just to mark it as volatile. */ + if (! flag_no_builtin && !flag_no_nonansi_builtin) + { + temp = builtin_function ("alloca", + build_function_type (ptr_type_node, + tree_cons (NULL_TREE, + sizetype, + endlink)), + BUILT_IN_ALLOCA, NULL_PTR); + /* Suppress error if redefined as a non-function. */ + DECL_BUILT_IN_NONANSI (temp) = 1; + temp = builtin_function ("ffs", int_ftype_int, BUILT_IN_FFS, NULL_PTR); + /* Suppress error if redefined as a non-function. */ + DECL_BUILT_IN_NONANSI (temp) = 1; + temp = builtin_function ("_exit", void_ftype_any, NOT_BUILT_IN, + NULL_PTR); + TREE_THIS_VOLATILE (temp) = 1; + TREE_SIDE_EFFECTS (temp) = 1; + /* Suppress error if redefined as a non-function. */ + DECL_BUILT_IN_NONANSI (temp) = 1; + } + + builtin_function ("__builtin_abs", int_ftype_int, BUILT_IN_ABS, NULL_PTR); + builtin_function ("__builtin_fabsf", float_ftype_float, BUILT_IN_FABS, + NULL_PTR); + builtin_function ("__builtin_fabs", double_ftype_double, BUILT_IN_FABS, + NULL_PTR); + builtin_function ("__builtin_fabsl", ldouble_ftype_ldouble, BUILT_IN_FABS, + NULL_PTR); + builtin_function ("__builtin_labs", long_ftype_long, BUILT_IN_LABS, + NULL_PTR); + builtin_function ("__builtin_saveregs", + build_function_type (ptr_type_node, NULL_TREE), + BUILT_IN_SAVEREGS, NULL_PTR); +/* EXPAND_BUILTIN_VARARGS is obsolete. */ +#if 0 + builtin_function ("__builtin_varargs", + build_function_type (ptr_type_node, + tree_cons (NULL_TREE, + integer_type_node, + endlink)), + BUILT_IN_VARARGS, NULL_PTR); +#endif + builtin_function ("__builtin_classify_type", default_function_type, + BUILT_IN_CLASSIFY_TYPE, NULL_PTR); + builtin_function ("__builtin_next_arg", + build_function_type (ptr_type_node, NULL_TREE), + BUILT_IN_NEXT_ARG, NULL_PTR); + builtin_function ("__builtin_args_info", + build_function_type (integer_type_node, + tree_cons (NULL_TREE, + integer_type_node, + endlink)), + BUILT_IN_ARGS_INFO, NULL_PTR); + + /* Untyped call and return. */ + builtin_function ("__builtin_apply_args", + build_function_type (ptr_type_node, NULL_TREE), + BUILT_IN_APPLY_ARGS, NULL_PTR); + + temp = tree_cons (NULL_TREE, + build_pointer_type (build_function_type (void_type_node, + NULL_TREE)), + tree_cons (NULL_TREE, + ptr_type_node, + tree_cons (NULL_TREE, + sizetype, + endlink))); + builtin_function ("__builtin_apply", + build_function_type (ptr_type_node, temp), + BUILT_IN_APPLY, NULL_PTR); + builtin_function ("__builtin_return", + build_function_type (void_type_node, + tree_cons (NULL_TREE, + ptr_type_node, + endlink)), + BUILT_IN_RETURN, NULL_PTR); + + /* CYGNUS LOCAL -- branch prediction */ + builtin_function ("__builtin_expect", + build_function_type (integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, + integer_type_node, + endlink))), + BUILT_IN_EXPECT, NULL_PTR); + + /* END CYGNUS LOCAL -- branch prediction */ + + /* Currently under experimentation. */ + builtin_function ("__builtin_memcpy", memcpy_ftype, + BUILT_IN_MEMCPY, "memcpy"); + builtin_function ("__builtin_memcmp", int_ftype_cptr_cptr_sizet, + BUILT_IN_MEMCMP, "memcmp"); + builtin_function ("__builtin_memset", memset_ftype, + BUILT_IN_MEMSET, "memset"); + builtin_function ("__builtin_strcmp", int_ftype_string_string, + BUILT_IN_STRCMP, "strcmp"); + builtin_function ("__builtin_strcpy", string_ftype_ptr_ptr, + BUILT_IN_STRCPY, "strcpy"); + builtin_function ("__builtin_strlen", strlen_ftype, + BUILT_IN_STRLEN, "strlen"); + builtin_function ("__builtin_sqrtf", float_ftype_float, + BUILT_IN_FSQRT, "sqrtf"); + builtin_function ("__builtin_fsqrt", double_ftype_double, + BUILT_IN_FSQRT, "sqrt"); + builtin_function ("__builtin_sqrtl", ldouble_ftype_ldouble, + BUILT_IN_FSQRT, "sqrtl"); + builtin_function ("__builtin_sinf", float_ftype_float, + BUILT_IN_SIN, "sinf"); + builtin_function ("__builtin_sin", double_ftype_double, + BUILT_IN_SIN, "sin"); + builtin_function ("__builtin_sinl", ldouble_ftype_ldouble, + BUILT_IN_SIN, "sinl"); + builtin_function ("__builtin_cosf", float_ftype_float, + BUILT_IN_COS, "cosf"); + builtin_function ("__builtin_cos", double_ftype_double, + BUILT_IN_COS, "cos"); + builtin_function ("__builtin_cosl", ldouble_ftype_ldouble, + BUILT_IN_COS, "cosl"); + builtin_function ("__builtin_setjmp", + build_function_type (integer_type_node, + tree_cons (NULL_TREE, + ptr_type_node, endlink)), + BUILT_IN_SETJMP, NULL_PTR); + builtin_function ("__builtin_longjmp", + build_function_type + (void_type_node, + tree_cons (NULL, ptr_type_node, + tree_cons (NULL_TREE, + integer_type_node, + endlink))), + BUILT_IN_LONGJMP, NULL_PTR); + builtin_function ("__builtin_trap", + build_function_type (void_type_node, endlink), + BUILT_IN_TRAP, NULL_PTR); + + /* In an ANSI C program, it is okay to supply built-in meanings + for these functions, since applications cannot validly use them + with any other meaning. + However, honor the -fno-builtin option. */ + if (!flag_no_builtin) + { + builtin_function ("abs", int_ftype_int, BUILT_IN_ABS, NULL_PTR); + builtin_function ("fabsf", float_ftype_float, BUILT_IN_FABS, NULL_PTR); + builtin_function ("fabs", double_ftype_double, BUILT_IN_FABS, NULL_PTR); + builtin_function ("fabsl", ldouble_ftype_ldouble, BUILT_IN_FABS, + NULL_PTR); + builtin_function ("labs", long_ftype_long, BUILT_IN_LABS, NULL_PTR); + builtin_function ("memcpy", memcpy_ftype, BUILT_IN_MEMCPY, NULL_PTR); + builtin_function ("memcmp", int_ftype_cptr_cptr_sizet, BUILT_IN_MEMCMP, + NULL_PTR); + builtin_function ("memset", memset_ftype, BUILT_IN_MEMSET, NULL_PTR); + builtin_function ("strcmp", int_ftype_string_string, BUILT_IN_STRCMP, + NULL_PTR); + builtin_function ("strcpy", string_ftype_ptr_ptr, BUILT_IN_STRCPY, + NULL_PTR); + builtin_function ("strlen", strlen_ftype, BUILT_IN_STRLEN, NULL_PTR); + builtin_function ("sqrtf", float_ftype_float, BUILT_IN_FSQRT, NULL_PTR); + builtin_function ("sqrt", double_ftype_double, BUILT_IN_FSQRT, NULL_PTR); + builtin_function ("sqrtl", ldouble_ftype_ldouble, BUILT_IN_FSQRT, + NULL_PTR); + builtin_function ("sinf", float_ftype_float, BUILT_IN_SIN, NULL_PTR); + builtin_function ("sin", double_ftype_double, BUILT_IN_SIN, NULL_PTR); + builtin_function ("sinl", ldouble_ftype_ldouble, BUILT_IN_SIN, NULL_PTR); + builtin_function ("cosf", float_ftype_float, BUILT_IN_COS, NULL_PTR); + builtin_function ("cos", double_ftype_double, BUILT_IN_COS, NULL_PTR); + builtin_function ("cosl", ldouble_ftype_ldouble, BUILT_IN_COS, NULL_PTR); + + /* Declare these functions volatile + to avoid spurious "control drops through" warnings. */ + /* Don't specify the argument types, to avoid errors + from certain code which isn't valid in ANSI but which exists. */ + temp = builtin_function ("abort", void_ftype_any, NOT_BUILT_IN, + NULL_PTR); + TREE_THIS_VOLATILE (temp) = 1; + TREE_SIDE_EFFECTS (temp) = 1; + temp = builtin_function ("exit", void_ftype_any, NOT_BUILT_IN, NULL_PTR); + TREE_THIS_VOLATILE (temp) = 1; + TREE_SIDE_EFFECTS (temp) = 1; + } + +#if 0 + /* Support for these has not been written in either expand_builtin + or build_function_call. */ + builtin_function ("__builtin_div", default_ftype, BUILT_IN_DIV, NULL_PTR); + builtin_function ("__builtin_ldiv", default_ftype, BUILT_IN_LDIV, NULL_PTR); + builtin_function ("__builtin_ffloor", double_ftype_double, BUILT_IN_FFLOOR, + NULL_PTR); + builtin_function ("__builtin_fceil", double_ftype_double, BUILT_IN_FCEIL, + NULL_PTR); + builtin_function ("__builtin_fmod", double_ftype_double_double, + BUILT_IN_FMOD, NULL_PTR); + builtin_function ("__builtin_frem", double_ftype_double_double, + BUILT_IN_FREM, NULL_PTR); + builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP, + NULL_PTR); + builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN, + NULL_PTR); +#endif + + pedantic_lvalues = pedantic; + + /* Create the global bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */ + declare_function_name (); + + start_identifier_warnings (); + + /* Prepare to check format strings against argument lists. */ + init_function_format_info (); + + init_iterators (); + + incomplete_decl_finalize_hook = finish_incomplete_decl; + + lang_get_alias_set = c_get_alias_set; +} + +/* Return a definition for a builtin function named NAME and whose data type + is TYPE. TYPE should be a function type with argument types. + FUNCTION_CODE tells later passes how to compile calls to this function. + See tree.h for its possible values. + + If LIBRARY_NAME is nonzero, use that for DECL_ASSEMBLER_NAME, + the name to be called if we can't opencode the function. */ + +tree +builtin_function (name, type, function_code, library_name) + char *name; + tree type; + enum built_in_function function_code; + char *library_name; +{ + tree decl = build_decl (FUNCTION_DECL, get_identifier (name), type); + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + /* If -traditional, permit redefining a builtin function any way you like. + (Though really, if the program redefines these functions, + it probably won't work right unless compiled with -fno-builtin.) */ + if (flag_traditional && name[0] != '_') + DECL_BUILT_IN_NONANSI (decl) = 1; + if (library_name) + DECL_ASSEMBLER_NAME (decl) = get_identifier (library_name); + make_decl_rtl (decl, NULL_PTR, 1); + pushdecl (decl); + if (function_code != NOT_BUILT_IN) + { + DECL_BUILT_IN (decl) = 1; + DECL_FUNCTION_CODE (decl) = function_code; + } + /* 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_ANTICIPATED (decl) = 1; + + return decl; +} + +/* Called when a declaration is seen that contains no names to declare. + If its type is a reference to a structure, union or enum inherited + from a containing scope, shadow that tag name for the current scope + with a forward reference. + If its type defines a new named structure or union + or defines an enum, it is valid but we need not do anything here. + Otherwise, it is an error. */ + +void +shadow_tag (declspecs) + tree declspecs; +{ + shadow_tag_warned (declspecs, 0); +} + +void +shadow_tag_warned (declspecs, warned) + tree declspecs; + int warned; + /* 1 => we have done a pedwarn. 2 => we have done a warning, but + no pedwarn. */ +{ + int found_tag = 0; + register tree link; + tree specs, attrs; + + 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)) + { + register tree value = TREE_VALUE (link); + register enum tree_code code = TREE_CODE (value); + + if (code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE) + /* Used to test also that TYPE_SIZE (value) != 0. + That caused warning for `struct foo;' at top level in the file. */ + { + register tree name = lookup_tag_reverse (value); + register tree t; + + found_tag++; + + if (name == 0) + { + if (warned != 1 && code != ENUMERAL_TYPE) + /* Empty unnamed enum OK */ + { + pedwarn ("unnamed struct/union that defines no instances"); + warned = 1; + } + } + else + { + t = lookup_tag (code, name, current_binding_level, 1); + + if (t == 0) + { + t = make_node (code); + pushtag (name, t); + } + } + } + else + { + if (!warned && ! in_system_header) + { + warning ("useless keyword or type name in empty declaration"); + warned = 2; + } + } + } + + if (found_tag > 1) + error ("two types specified in one empty declaration"); + + if (warned != 1) + { + if (found_tag == 0) + pedwarn ("empty declaration"); + } +} + +/* Decode a "typename", such as "int **", returning a ..._TYPE node. */ + +tree +groktypename (typename) + tree typename; +{ + if (TREE_CODE (typename) != TREE_LIST) + return typename; + return grokdeclarator (TREE_VALUE (typename), + TREE_PURPOSE (typename), + TYPENAME, 0); +} + +/* Return a PARM_DECL node for a given pair of specs and declarator. */ + +tree +groktypename_in_parm_context (typename) + tree typename; +{ + if (TREE_CODE (typename) != TREE_LIST) + return typename; + return grokdeclarator (TREE_VALUE (typename), + TREE_PURPOSE (typename), + PARM, 0); +} + +/* Decode a declarator in an ordinary declaration or data definition. + This is called as soon as the type information and variable name + have been parsed, before parsing the initializer if any. + Here we create the ..._DECL node, fill in its type, + and put it on the list of decls for the current context. + The ..._DECL node is returned as the value. + + Exception: for arrays where the length is not specified, + the type is left null, to be filled in by `finish_decl'. + + Function definitions do not come here; they go to start_function + instead. However, external and forward declarations of functions + do go through here. Structure field declarations are done by + grokfield and not through here. */ + +/* Set this to zero to debug not using the temporary obstack + to parse initializers. */ +int debug_temp_inits = 1; + +tree +start_decl (declarator, declspecs, initialized, attributes, prefix_attributes) + tree declarator, declspecs; + int initialized; + tree attributes, prefix_attributes; +{ + register tree decl = grokdeclarator (declarator, declspecs, + NORMAL, initialized); + register tree tem; + int init_written = initialized; + + /* The corresponding pop_obstacks is in finish_decl. */ + push_obstacks_nochange (); + + if (warn_main && TREE_CODE (decl) != FUNCTION_DECL + && !strcmp (IDENTIFIER_POINTER (DECL_NAME (decl)), "main")) + warning_with_decl (decl, "`%s' is usually a function"); + + 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. */ + switch (TREE_CODE (decl)) + { + case TYPE_DECL: + /* typedef foo = bar means give foo the same type as bar. + We haven't parsed bar yet, so `finish_decl' will fix that up. + Any other case of an initialization in a TYPE_DECL is an error. */ + if (pedantic || list_length (declspecs) > 1) + { + error ("typedef `%s' is initialized", + IDENTIFIER_POINTER (DECL_NAME (decl))); + initialized = 0; + } + break; + + case FUNCTION_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 `%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. */ + if (TYPE_SIZE (TREE_TYPE (decl)) != 0) + { + /* A complete type is ok if size is fixed. */ + + if (TREE_CODE (TYPE_SIZE (TREE_TYPE (decl))) != INTEGER_CST + || C_DECL_VARIABLE_SIZE (decl)) + { + error ("variable-sized object may not be initialized"); + initialized = 0; + } + } + else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE) + { + error ("variable `%s' has initializer but incomplete type", + IDENTIFIER_POINTER (DECL_NAME (decl))); + initialized = 0; + } + else if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (decl))) == 0) + { + error ("elements of array `%s' have incomplete type", + IDENTIFIER_POINTER (DECL_NAME (decl))); + initialized = 0; + } + } + + if (initialized) + { +#if 0 /* Seems redundant with grokdeclarator. */ + if (current_binding_level != global_binding_level + && DECL_EXTERNAL (decl) + && TREE_CODE (decl) != FUNCTION_DECL) + warning ("declaration of `%s' has `extern' and is initialized", + IDENTIFIER_POINTER (DECL_NAME (decl))); +#endif + DECL_EXTERNAL (decl) = 0; + if (current_binding_level == global_binding_level) + TREE_STATIC (decl) = 1; + + /* 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. */ + DECL_INITIAL (decl) = error_mark_node; + } + + /* If this is a function declaration, write a record describing it to the + prototypes file (if requested). */ + + if (TREE_CODE (decl) == FUNCTION_DECL) + gen_aux_info_record (decl, 0, 0, TYPE_ARG_TYPES (TREE_TYPE (decl)) != 0); + + /* ANSI specifies that a tentative definition which is not merged with + a non-tentative definition behaves exactly like a definition with an + initializer equal to zero. (Section 3.7.2) + -fno-common gives strict ANSI behavior. Usually you don't want it. + This matters only for variables with external linkage. */ + if (! flag_no_common || ! TREE_PUBLIC (decl)) + DECL_COMMON (decl) = 1; + +#ifdef SET_DEFAULT_DECL_ATTRIBUTES + SET_DEFAULT_DECL_ATTRIBUTES (decl, attributes); +#endif + + /* Set attributes here so if duplicate decl, will have proper attributes. */ + decl_attributes (decl, attributes, prefix_attributes); + + /* Add this decl to the current binding level. + TEM may equal DECL or it may be a previous decl of the same name. */ + tem = pushdecl (decl); + + /* For a local variable, define the RTL now. */ + if (current_binding_level != global_binding_level + /* 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 (tem) == 0) + { + if (TYPE_SIZE (TREE_TYPE (tem)) != 0) + expand_decl (tem); + else if (TREE_CODE (TREE_TYPE (tem)) == ARRAY_TYPE + && DECL_INITIAL (tem) != 0) + expand_decl (tem); + } + + if (init_written) + { + /* When parsing and digesting the initializer, + use temporary storage. Do this even if we will ignore the value. */ + if (current_binding_level == global_binding_level && debug_temp_inits) + temporary_allocation (); + } + + return tem; +} + +/* Finish processing of a declaration; + install its 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. */ + +void +finish_decl (decl, init, asmspec_tree) + tree decl, init; + tree asmspec_tree; +{ + register tree type = TREE_TYPE (decl); + int was_incomplete = (DECL_SIZE (decl) == 0); + int temporary = allocation_temporary_p (); + char *asmspec = 0; + + /* If a name was specified, get the string. */ + if (asmspec_tree) + asmspec = TREE_STRING_POINTER (asmspec_tree); + + /* If `start_decl' didn't like having an initialization, ignore it now. */ + + if (init != 0 && DECL_INITIAL (decl) == 0) + init = 0; + /* Don't crash if parm is initialized. */ + if (TREE_CODE (decl) == PARM_DECL) + init = 0; + + if (ITERATOR_P (decl)) + { + if (init == 0) + error_with_decl (decl, "iterator has no initial value"); + else + init = save_expr (init); + } + + if (init) + { + if (TREE_CODE (decl) != TYPE_DECL) + store_init_value (decl, init); + else + { + /* typedef foo = bar; store the type of bar as the type of foo. */ + TREE_TYPE (decl) = TREE_TYPE (init); + DECL_INITIAL (decl) = init = 0; + } + } + + /* Pop back to the obstack that is current for this binding level. + This is because MAXINDEX, rtl, etc. to be made below + must go in the permanent obstack. But don't discard the + temporary data yet. */ + pop_obstacks (); +#if 0 /* pop_obstacks was near the end; this is what was here. */ + if (current_binding_level == global_binding_level && temporary) + end_temporary_allocation (); +#endif + + /* 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) + { + 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 (type, DECL_INITIAL (decl), do_default); + + /* Get the completed type made by complete_array_type. */ + type = TREE_TYPE (decl); + + if (failure == 1) + error_with_decl (decl, "initializer fails to determine size of `%s'"); + + if (failure == 2) + { + if (do_default) + error_with_decl (decl, "array size missing in `%s'"); + /* 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)) + DECL_EXTERNAL (decl) = 1; + } + + /* 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. */ + if (pedantic && TYPE_DOMAIN (type) != 0 + && tree_int_cst_sgn (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) < 0) + error_with_decl (decl, "zero or negative size array `%s'"); + + layout_decl (decl, 0); + } + + if (TREE_CODE (decl) == VAR_DECL) + { + if (DECL_SIZE (decl) == 0 + && TYPE_SIZE (TREE_TYPE (decl)) != 0) + layout_decl (decl, 0); + + if (DECL_SIZE (decl) == 0 + && (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. */ + /* A duplicate_decls call could have changed an extern + declaration into a file scope one. This can be detected + by TREE_ASM_WRITTEN being set. */ + (DECL_INITIAL (decl) != 0 + || (DECL_CONTEXT (decl) != 0 && ! TREE_ASM_WRITTEN (decl))) + : + /* An automatic variable with an incomplete type + is an error. */ + !DECL_EXTERNAL (decl))) + { + error_with_decl (decl, "storage size of `%s' isn't known"); + TREE_TYPE (decl) = error_mark_node; + } + + if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl)) + && DECL_SIZE (decl) != 0) + { + if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST) + constant_expression_warning (DECL_SIZE (decl)); + else + error_with_decl (decl, "storage size of `%s' isn't constant"); + } + + if (TREE_USED (type)) + TREE_USED (decl) = 1; + } + + /* If this is a function and an assembler name is specified, it isn't + builtin any more. Also reset DECL_RTL so we can give it its new + name. */ + if (TREE_CODE (decl) == FUNCTION_DECL && asmspec) + { + DECL_BUILT_IN (decl) = 0; + DECL_RTL (decl) = 0; + } + + /* 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 ((flag_traditional || TREE_PERMANENT (decl)) + && allocation_temporary_p ()) + { + push_obstacks_nochange (); + end_temporary_allocation (); + /* This is a no-op in c-lang.c or something real in objc-actions.c. */ + maybe_objc_check_decl (decl); + rest_of_decl_compilation (decl, asmspec, + (DECL_CONTEXT (decl) == 0 + || TREE_ASM_WRITTEN (decl)), + 0); + pop_obstacks (); + } + else + { + /* This is a no-op in c-lang.c or something real in objc-actions.c. */ + maybe_objc_check_decl (decl); + rest_of_decl_compilation (decl, asmspec, DECL_CONTEXT (decl) == 0, + 0); + } + if (DECL_CONTEXT (decl) != 0) + { + /* 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)) + { + /* If we used it already as memory, it must stay in memory. */ + TREE_ADDRESSABLE (decl) = TREE_USED (decl); + /* If it's still incomplete now, no init will save it. */ + if (DECL_SIZE (decl) == 0) + DECL_INITIAL (decl) = 0; + expand_decl (decl); + } + /* Compute and store the initial value. */ + if (TREE_CODE (decl) != FUNCTION_DECL) + expand_decl_init (decl); + } + } + + if (TREE_CODE (decl) == TYPE_DECL) + { + /* This is a no-op in c-lang.c or something real in objc-actions.c. */ + maybe_objc_check_decl (decl); + rest_of_decl_compilation (decl, NULL_PTR, DECL_CONTEXT (decl) == 0, + 0); + } + + /* ??? After 2.3, test (init != 0) instead of TREE_CODE. */ + /* This test used to include TREE_PERMANENT, however, we have the same + problem with initializers at the function level. Such initializers get + saved until the end of the function on the momentary_obstack. */ + if (!(TREE_CODE (decl) == FUNCTION_DECL && DECL_INLINE (decl)) + && temporary + /* DECL_INITIAL is not defined in PARM_DECLs, since it shares + space with DECL_ARG_TYPE. */ + && TREE_CODE (decl) != PARM_DECL) + { + /* We need to remember that this array HAD an initialization, + but discard the actual temporary nodes, + since we can't have a permanent node keep pointing to them. */ + /* We make an exception for inline functions, since it's + normal for a local extern redeclaration of an inline function + to have a copy of the top-level decl's DECL_INLINE. */ + if (DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node) + { + /* If this is a const variable, then preserve the + initializer instead of discarding it so that we can optimize + references to it. */ + /* This test used to include TREE_STATIC, but this won't be set + for function level initializers. */ + if (TREE_READONLY (decl) || ITERATOR_P (decl)) + { + preserve_initializer (); + /* Hack? Set the permanent bit for something that is permanent, + but not on the permanent obstack, so as to convince + output_constant_def to make its rtl on the permanent + obstack. */ + TREE_PERMANENT (DECL_INITIAL (decl)) = 1; + + /* The initializer and DECL must have the same (or equivalent + types), but if the initializer is a STRING_CST, its type + might not be on the right obstack, so copy the type + of DECL. */ + TREE_TYPE (DECL_INITIAL (decl)) = type; + } + else + DECL_INITIAL (decl) = error_mark_node; + } + } + + /* If requested, warn about definitions of large data objects. */ + + if (warn_larger_than + && (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL) + && !DECL_EXTERNAL (decl)) + { + register tree decl_size = DECL_SIZE (decl); + + if (decl_size && TREE_CODE (decl_size) == INTEGER_CST) + { + unsigned units = TREE_INT_CST_LOW(decl_size) / BITS_PER_UNIT; + + if (units > larger_than_size) + warning_with_decl (decl, "size of `%s' is %u bytes", units); + } + } + +#if 0 + /* Resume permanent allocation, if not within a function. */ + /* The corresponding push_obstacks_nochange is in start_decl, + and in push_parm_decl and in grokfield. */ + pop_obstacks (); +#endif + + /* If we have gone back from temporary to permanent allocation, + actually free the temporary space that we no longer need. */ + if (temporary && !allocation_temporary_p ()) + permanent_allocation (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_binding_level == global_binding_level) + get_pending_sizes (); +} + +/* If DECL has a cleanup, build and return that cleanup here. + This is a callback called by expand_expr. */ + +tree +maybe_build_cleanup (decl) + tree decl ATTRIBUTE_UNUSED; +{ + /* There are no cleanups in C. */ + return NULL_TREE; +} + +/* Given a parsed parameter declaration, + decode it into a PARM_DECL and push that on the current binding level. + Also, for the sake of forward parm decls, + record the given order of parms in `parm_order'. */ + +void +push_parm_decl (parm) + tree parm; +{ + tree decl; + int old_immediate_size_expand = immediate_size_expand; + /* Don't try computing parm sizes now -- wait till fn is called. */ + immediate_size_expand = 0; + + /* The corresponding pop_obstacks is in finish_decl. */ + push_obstacks_nochange (); + + decl = grokdeclarator (TREE_VALUE (TREE_PURPOSE (parm)), + TREE_PURPOSE (TREE_PURPOSE (parm)), PARM, 0); + decl_attributes (decl, TREE_VALUE (TREE_VALUE (parm)), + TREE_PURPOSE (TREE_VALUE (parm))); + +#if 0 + if (DECL_NAME (decl)) + { + tree olddecl; + olddecl = lookup_name (DECL_NAME (decl)); + if (pedantic && olddecl != 0 && TREE_CODE (olddecl) == TYPE_DECL) + pedwarn_with_decl (decl, "ANSI C forbids parameter `%s' shadowing typedef"); + } +#endif + + decl = pushdecl (decl); + + immediate_size_expand = old_immediate_size_expand; + + current_binding_level->parm_order + = tree_cons (NULL_TREE, decl, current_binding_level->parm_order); + + /* Add this decl to the current binding level. */ + finish_decl (decl, NULL_TREE, NULL_TREE); +} + +/* Clear the given order of parms in `parm_order'. + Used at start of parm list, + and also at semicolon terminating forward decls. */ + +void +clear_parm_order () +{ + current_binding_level->parm_order = NULL_TREE; +} + +/* 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 (type, initial_value, do_default) + tree type; + tree initial_value; + int do_default; +{ + register 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 = size_binop (MINUS_EXPR, integer_zero_node, size_one_node); + for (; elts; elts = TREE_CHAIN (elts)) + { + if (TREE_PURPOSE (elts)) + maxindex = TREE_PURPOSE (elts); + else + maxindex = size_binop (PLUS_EXPR, maxindex, size_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; +} + +/* Given declspecs and a declarator, + determine the name and type of the object declared + and construct a ..._DECL node for it. + (In one case we can return a ..._TYPE node instead. + For invalid input we sometimes return 0.) + + 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. + FUNCDEF for a function definition. Like NORMAL but a few different + error messages in each case. Return value may be zero meaning + this definition is too screwy to try to parse. + PARM for a parameter declaration (either within a function prototype + or before a function body). Make a PARM_DECL, or return void_type_node. + 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. + BITFIELD for a field with specified width. + INITIALIZED is 1 if the decl has an initializer. + + In the TYPENAME case, DECLARATOR is really an absolute declarator. + It may also be so in the PARM case, for a prototype where the + argument type is specified but not the name. + + This function is where the complicated C meanings of `static' + and `extern' are interpreted. */ + +static tree +grokdeclarator (declarator, declspecs, decl_context, initialized) + tree declspecs; + tree declarator; + enum decl_context decl_context; + int initialized; +{ + 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; + char *name; + tree typedef_type = 0; + int funcdef_flag = 0; + enum tree_code innermost_code = ERROR_MARK; + int bitfield = 0; + int size_varies = 0; + tree decl_machine_attr = NULL_TREE; + + if (decl_context == BITFIELD) + bitfield = 1, decl_context = FIELD; + + if (decl_context == FUNCDEF) + funcdef_flag = 1, decl_context = NORMAL; + + push_obstacks_nochange (); + + if (flag_traditional && allocation_temporary_p ()) + end_temporary_allocation (); + + /* Look inside a declarator for the name being declared + and get it as a string, for an error message. */ + { + register tree decl = declarator; + name = 0; + + while (decl) + switch (TREE_CODE (decl)) + { + case ARRAY_REF: + case INDIRECT_REF: + case CALL_EXPR: + innermost_code = TREE_CODE (decl); + decl = TREE_OPERAND (decl, 0); + break; + + case IDENTIFIER_NODE: + name = IDENTIFIER_POINTER (decl); + decl = 0; + break; + + default: + abort (); + } + if (name == 0) + name = "type name"; + } + + /* A function definition's declarator must have the form of + a function declarator. */ + + if (funcdef_flag && innermost_code != CALL_EXPR) + return 0; + + /* Anything declared one level down from the top level + must be one of the parameters of a function + (because the body is at least two levels down). */ + + /* 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_binding_level->parm_flag) + decl_context = PARM; + + /* 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'. + + 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)) + { + register int i; + register tree id = TREE_VALUE (spec); + + if (id == ridpointers[(int) RID_INT]) + explicit_int = 1; + if (id == ridpointers[(int) RID_CHAR]) + explicit_char = 1; + + if (TREE_CODE (id) == IDENTIFIER_NODE) + for (i = (int) RID_FIRST_MODIFIER; i < (int) RID_MAX; i++) + { + if (ridpointers[i] == id) + { + if (i == (int) RID_LONG && specbits & (1< 1) + pedwarn ("duplicate `const'"); + if (restrictp > 1) + pedwarn ("duplicate `restrict'"); + if (volatilep > 1) + pedwarn ("duplicate `volatile'"); + 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 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++; + if (specbits & 1 << (int) RID_ITERATOR) 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)))) + { + if (specbits & 1 << (int) RID_AUTO + && (pedantic || current_binding_level == global_binding_level)) + 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'"); + specbits &= ~ ((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER) + | (1 << (int) RID_AUTO)); + } + else if (decl_context != NORMAL && nclasses > 0) + { + if (decl_context == PARM && specbits & 1 << (int) RID_REGISTER) + ; + else + { + error ((decl_context == FIELD + ? "storage class specified for structure field `%s'" + : (decl_context == PARM + ? "storage class specified for parameter `%s'" + : "storage class specified for typename")), + name); + specbits &= ~ ((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER) + | (1 << (int) RID_AUTO) | (1 << (int) RID_STATIC) + | (1 << (int) RID_EXTERN)); + } + } + else if (specbits & 1 << (int) RID_EXTERN && initialized && ! funcdef_flag) + { + /* `extern' with initialization is invalid if not at top level. */ + if (current_binding_level == global_binding_level) + warning ("`%s' initialized and declared `extern'", name); + else + error ("`%s' has both `extern' and initializer", name); + } + else if (specbits & 1 << (int) RID_EXTERN && funcdef_flag + && current_binding_level != global_binding_level) + error ("nested function `%s' declared `extern'", name); + else if (current_binding_level == global_binding_level + && specbits & (1 << (int) RID_AUTO)) + error ("top-level declaration of `%s' specifies `auto'", name); + else if ((specbits & 1 << (int) RID_ITERATOR) + && TREE_CODE (declarator) != IDENTIFIER_NODE) + { + error ("iterator `%s' has derived type", name); + type = error_mark_node; + } + else if ((specbits & 1 << (int) RID_ITERATOR) + && TREE_CODE (type) != INTEGER_TYPE) + { + error ("iterator `%s' has noninteger type", name); + type = error_mark_node; + } + } + + /* 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). */ + + while (declarator && TREE_CODE (declarator) != IDENTIFIER_NODE) + { + if (type == error_mark_node) + { + declarator = TREE_OPERAND (declarator, 0); + continue; + } + + /* 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. + + 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. */ + + if (TREE_CODE (declarator) == ARRAY_REF) + { + register tree itype = NULL_TREE; + register tree size = TREE_OPERAND (declarator, 1); + /* An uninitialized decl with `extern' is a reference. */ + int extern_ref = !initialized && (specbits & (1 << (int) RID_EXTERN)); + /* The index is a signed object `sizetype' bits wide. */ + tree index_type = signed_type (sizetype); + + declarator = TREE_OPERAND (declarator, 0); + + /* Check for some types that there cannot be arrays of. */ + + if (TYPE_MAIN_VARIANT (type) == void_type_node) + { + error ("declaration of `%s' as array of voids", 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 (size == error_mark_node) + type = error_mark_node; + + if (type == error_mark_node) + continue; + + /* If this is a block level extern, it must live past the end + of the function so that we can check it against other extern + declarations (IDENTIFIER_LIMBO_VALUE). */ + if (extern_ref && allocation_temporary_p ()) + end_temporary_allocation (); + + /* 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 (TREE_CODE (TREE_TYPE (size)) != INTEGER_TYPE + && TREE_CODE (TREE_TYPE (size)) != ENUMERAL_TYPE) + { + error ("size of array `%s' has non-integer type", name); + size = integer_one_node; + } + + if (pedantic && integer_zerop (size)) + pedwarn ("ANSI 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 `%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 (pedantic) + { + if (TREE_CONSTANT (size)) + pedwarn ("ANSI C forbids array `%s' whose size can't be evaluated", name); + else + pedwarn ("ANSI C forbids variable-size array `%s'", name); + } + } + + /* Convert size to 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; + } + + if (size_varies) + itype = variable_size (itype); + itype = build_index_type (itype); + } + +#if 0 /* This had bad results for pointers to arrays, as in + union incomplete (*foo)[4]; */ + /* Complain about arrays of incomplete types, except in typedefs. */ + + if (TYPE_SIZE (type) == 0 + /* Avoid multiple warnings for nested array types. */ + && TREE_CODE (type) != ARRAY_TYPE + && !(specbits & (1 << (int) RID_TYPEDEF)) + && !C_TYPE_BEING_DEFINED (type)) + warning ("array type has incomplete element type"); +#endif + +#if 0 /* We shouldn't have a function type here at all! + Functions aren't allowed as array elements. */ + if (pedantic && TREE_CODE (type) == FUNCTION_TYPE + && (constp || volatilep)) + pedwarn ("ANSI C forbids const or volatile function types"); +#endif + + /* 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. */ + + type = build_array_type (type, itype); + if (type_quals) + type = c_build_qualified_type (type, type_quals); + +#if 0 /* don't clear these; leave them set so that the array type + or the variable is itself const or volatile. */ + type_quals = TYPE_UNQUALIFIED; +#endif + + if (size_varies) + C_TYPE_VARIABLE_SIZE (type) = 1; + } + else if (TREE_CODE (declarator) == CALL_EXPR) + { + int extern_ref = (!(specbits & (1 << (int) RID_AUTO)) + || current_binding_level == global_binding_level); + tree arg_types; + + /* Declaring a function type. + Make sure we have a valid type for the function to return. */ + if (type == error_mark_node) + continue; + + size_varies = 0; + + /* Warn about some types functions can't return. */ + + 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; + } + +#ifndef TRADITIONAL_RETURN_FLOAT + /* Traditionally, declaring return type float means double. */ + + if (flag_traditional && TYPE_MAIN_VARIANT (type) == float_type_node) + type = double_type_node; +#endif /* TRADITIONAL_RETURN_FLOAT */ + + /* If this is a block level extern, it must live past the end + of the function so that we can check it against other extern + declarations (IDENTIFIER_LIMBO_VALUE). */ + if (extern_ref && allocation_temporary_p ()) + end_temporary_allocation (); + + /* Construct the function type and go to the next + inner layer of declarator. */ + + arg_types = grokparms (TREE_OPERAND (declarator, 1), + funcdef_flag + /* Say it's a definition + only for the CALL_EXPR + closest to the identifier. */ + && TREE_CODE (TREE_OPERAND (declarator, 0)) == IDENTIFIER_NODE); +#if 0 /* This seems to be false. We turn off temporary allocation + above in this function if -traditional. + And this code caused inconsistent results with prototypes: + callers would ignore them, and pass arguments wrong. */ + + /* Omit the arg types if -traditional, since the arg types + and the list links might not be permanent. */ + type = build_function_type (type, + flag_traditional + ? NULL_TREE : arg_types); +#endif + /* Type qualifiers before the return type of the function + qualify the return type, not the function type. */ + if (type_quals) + type = c_build_qualified_type (type, type_quals); + 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. */ + + { + register tree link; + + 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. */ + + if (pedantic && TREE_CODE (type) == FUNCTION_TYPE + && type_quals) + pedwarn ("ANSI 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); + + /* Process a list of type modifier keywords + (such as const or volatile) that were given inside the `*'. */ + + if (TREE_TYPE (declarator)) + { + register 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 (qualifier == ridpointers[(int) RID_CONST]) + constp++; + else if (qualifier == ridpointers[(int) RID_VOLATILE]) + volatilep++; + else if (qualifier == ridpointers[(int) RID_RESTRICT]) + restrictp++; + 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_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. */ + + /* Did array size calculations overflow? */ + + if (TREE_CODE (type) == ARRAY_TYPE + && TYPE_SIZE (type) + && TREE_OVERFLOW (TYPE_SIZE (type))) + error ("size of array `%s' is too large", name); + + /* If this is declaring a typedef name, return a TYPE_DECL. */ + + 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 ("ANSI C forbids qualified function types"); + if (type_quals) + type = c_build_qualified_type (type, type_quals); + 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; + pop_obstacks (); + 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 + && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (typedef_type) + && TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type) == 0) + { + 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, fields or parameters */ + if (pedantic && TREE_CODE (type) == FUNCTION_TYPE + && type_quals) + pedwarn ("ANSI C forbids const or volatile function types"); + if (type_quals) + type = c_build_qualified_type (type, type_quals); + pop_obstacks (); + return type; + } + + /* Aside from typedefs and type names (handle above), + `void' at top level (not within pointer) + is allowed only in public variables. + We don't complain about parms either, but that is because + a better error message can be made later. */ + + if (TYPE_MAIN_VARIANT (type) == void_type_node && decl_context != PARM + && ! ((decl_context != FIELD && TREE_CODE (type) != FUNCTION_TYPE) + && ((specbits & (1 << (int) RID_EXTERN)) + || (current_binding_level == global_binding_level + && !(specbits + & ((1 << (int) RID_STATIC) | (1 << (int) RID_REGISTER))))))) + { + error ("variable or field `%s' declared void", name); + type = integer_type_node; + } + + /* Now create the decl, which may be a VAR_DECL, a PARM_DECL + or a FUNCTION_DECL, depending on DECL_CONTEXT and TYPE. */ + + { + register tree decl; + + if (decl_context == PARM) + { + tree type_as_written = type; + tree main_type; + + /* 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. */ + + if (TREE_CODE (type) == ARRAY_TYPE) + { + /* Transfer const-ness of array into that of type pointed to. */ + type = TREE_TYPE (type); + if (type_quals) + type = c_build_qualified_type (type, type_quals); + type = build_pointer_type (type); + type_quals = TYPE_UNQUALIFIED; + size_varies = 0; + } + else if (TREE_CODE (type) == FUNCTION_TYPE) + { + if (pedantic && type_quals) + pedwarn ("ANSI C forbids qualified function types"); + if (type_quals) + type = c_build_qualified_type (type, type_quals); + type = build_pointer_type (type); + type_quals = TYPE_UNQUALIFIED; + } + + decl = build_decl (PARM_DECL, declarator, type); + if (size_varies) + C_DECL_VARIABLE_SIZE (decl) = 1; + + /* Compute the type actually passed in the parmlist, + for the case where there is no prototype. + (For example, shorts and chars are passed as ints.) + When there is a prototype, this is overridden later. */ + + DECL_ARG_TYPE (decl) = type; + main_type = (type == error_mark_node + ? error_mark_node + : TYPE_MAIN_VARIANT (type)); + if (main_type == float_type_node) + DECL_ARG_TYPE (decl) = double_type_node; + /* Don't use TYPE_PRECISION to decide whether to promote, + because we should convert short if it's the same size as int, + but we should not convert long if it's the same size as int. */ + else if (TREE_CODE (main_type) != ERROR_MARK + && C_PROMOTING_INTEGER_TYPE_P (main_type)) + { + if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node) + && TREE_UNSIGNED (type)) + DECL_ARG_TYPE (decl) = unsigned_type_node; + else + DECL_ARG_TYPE (decl) = integer_type_node; + } + + DECL_ARG_TYPE_AS_WRITTEN (decl) = type_as_written; + } + else if (decl_context == FIELD) + { + /* Structure field. It may not be a function. */ + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + error ("field `%s' declared as a function", name); + type = build_pointer_type (type); + } + else if (TREE_CODE (type) != ERROR_MARK && TYPE_SIZE (type) == 0) + { + error ("field `%s' has incomplete type", name); + type = error_mark_node; + } + /* 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)); +#if 0 /* Leave the field const or volatile as well. */ + type_quals = TYPE_UNQUALIFIED; +#endif + } + decl = build_decl (FIELD_DECL, declarator, type); + if (size_varies) + C_DECL_VARIABLE_SIZE (decl) = 1; + } + else if (TREE_CODE (type) == FUNCTION_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_binding_level == global_binding_level); + + if (specbits & (1 << (int) RID_AUTO) + && (pedantic || current_binding_level == global_binding_level)) + pedwarn ("invalid storage class for function `%s'", name); + if (specbits & (1 << (int) RID_REGISTER)) + error ("invalid storage class for function `%s'", name); + /* Function declaration not at top level. + Storage classes other than `extern' are not allowed + and `extern' makes no difference. */ + if (current_binding_level != global_binding_level + && (specbits & ((1 << (int) RID_STATIC) | (1 << (int) RID_INLINE))) + && pedantic) + pedwarn ("invalid storage class for function `%s'", name); + + /* If this is a block level extern, it must live past the end + of the function so that we can check it against other + extern declarations (IDENTIFIER_LIMBO_VALUE). */ + if (extern_ref && allocation_temporary_p ()) + end_temporary_allocation (); + + decl = build_decl (FUNCTION_DECL, declarator, type); + decl = build_decl_attribute_variant (decl, decl_machine_attr); + + if (pedantic && type_quals && ! DECL_IN_SYSTEM_HEADER (decl)) + pedwarn ("ANSI C forbids qualified function types"); + + if (pedantic + && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl))) == void_type_node + && TYPE_QUALS (TREE_TYPE (TREE_TYPE (decl))) + && ! DECL_IN_SYSTEM_HEADER (decl)) + pedwarn ("ANSI C forbids qualified void function return type"); + + /* GNU C interprets a `volatile void' return type to indicate + that the function does not return. */ + if ((type_quals & TYPE_QUAL_VOLATILE) + && TREE_TYPE (TREE_TYPE (decl)) != void_type_node) + 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) + = !(specbits & ((1 << (int) RID_STATIC) | (1 << (int) RID_AUTO))); + + /* Record presence of `inline', if it is reasonable. */ + if (inlinep) + { + if (! strcmp (IDENTIFIER_POINTER (declarator), "main")) + warning ("cannot inline function `main'"); + else + /* Assume that otherwise the function can be inlined. */ + DECL_INLINE (decl) = 1; + + if (specbits & (1 << (int) RID_EXTERN)) + current_extern_inline = 1; + } + } + else + { + /* It's a variable. */ + /* An uninitialized decl with `extern' is a reference. */ + int extern_ref = !initialized && (specbits & (1 << (int) RID_EXTERN)); + + /* 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)); +#if 0 /* Leave the variable const or volatile as well. */ + type_quals = TYPE_UNQUALIFIED; +#endif + } + + /* If this is a block level extern, it must live past the end + of the function so that we can check it against other + extern declarations (IDENTIFIER_LIMBO_VALUE). */ + if (extern_ref && allocation_temporary_p ()) + end_temporary_allocation (); + + decl = build_decl (VAR_DECL, declarator, type); + if (size_varies) + C_DECL_VARIABLE_SIZE (decl) = 1; + + if (inlinep) + pedwarn_with_decl (decl, "variable `%s' declared `inline'"); + + DECL_EXTERNAL (decl) = extern_ref; + /* At top level, 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 both `static' and `register' makes it public. */ + if (current_binding_level == global_binding_level) + { + TREE_PUBLIC (decl) + = !(specbits + & ((1 << (int) RID_STATIC) | (1 << (int) RID_REGISTER))); + TREE_STATIC (decl) = ! DECL_EXTERNAL (decl); + } + /* Not at top level, only `static' makes a static definition. */ + else + { + TREE_STATIC (decl) = (specbits & (1 << (int) RID_STATIC)) != 0; + TREE_PUBLIC (decl) = DECL_EXTERNAL (decl); + } + + if (specbits & 1 << (int) RID_ITERATOR) + ITERATOR_P (decl) = 1; + } + + /* Record `register' declaration for warnings on & + and in case doing stupid register allocation. */ + + 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. */ + if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (decl))) + mark_addressable (decl); + + pop_obstacks (); + + return decl; + } +} + +/* 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 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 nonzero for a function definition, 0 for + a mere declaration. A nonempty identifier-list gets an error message + when FUNCDEF_FLAG is zero. */ + +static tree +grokparms (parms_info, funcdef_flag) + tree parms_info; + int funcdef_flag; +{ + tree first_parm = TREE_CHAIN (parms_info); + + last_function_parms = TREE_PURPOSE (parms_info); + last_function_parm_tags = TREE_VALUE (parms_info); + + if (warn_strict_prototypes && first_parm == 0 && !funcdef_flag + && !in_system_header) + warning ("function declaration isn't a prototype"); + + if (first_parm != 0 + && TREE_CODE (TREE_VALUE (first_parm)) == IDENTIFIER_NODE) + { + if (! funcdef_flag) + pedwarn ("parameter names (without types) in function declaration"); + + last_function_parms = first_parm; + return 0; + } + else + { + tree parm; + tree typelt; + /* We no longer test FUNCDEF_FLAG. + 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. */ +#if 0 + /* In a fcn definition, arg types must be complete. */ + if (funcdef_flag) +#endif + for (parm = last_function_parms, typelt = first_parm; + parm; + 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_SIZE (type) == 0) + { + 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; + } + } +#if 0 /* This has been replaced by parm_tags_warning + which uses a more accurate criterion for what to warn about. */ + else + { + /* Now warn if is a pointer to an incomplete type. */ + while (TREE_CODE (type) == POINTER_TYPE + || TREE_CODE (type) == REFERENCE_TYPE) + type = TREE_TYPE (type); + type = TYPE_MAIN_VARIANT (type); + if (TYPE_SIZE (type) == 0) + { + if (DECL_NAME (parm) != 0) + warning ("parameter `%s' points to incomplete type", + IDENTIFIER_POINTER (DECL_NAME (parm))); + else + warning ("parameter points to incomplete type"); + } + } +#endif + typelt = TREE_CHAIN (typelt); + } + + /* Allocate the list of types the way we allocate a type. */ + if (first_parm && ! TREE_PERMANENT (first_parm)) + { + /* Construct a copy of the list of types + on the saveable obstack. */ + tree result = NULL; + for (typelt = first_parm; typelt; typelt = TREE_CHAIN (typelt)) + result = saveable_tree_cons (NULL_TREE, TREE_VALUE (typelt), + result); + return nreverse (result); + } + else + /* The list we have is permanent already. */ + return first_parm; + } +} + + +/* Return a tree_list node with info on a parameter list just parsed. + The TREE_PURPOSE is a chain 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. + This tree_list node is later fed to `grokparms'. + + 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'. */ + +tree +get_parm_info (void_at_end) + int void_at_end; +{ + register tree decl, t; + register tree types = 0; + int erred = 0; + tree tags = gettags (); + tree parms = getdecls (); + tree new_parms = 0; + tree order = current_binding_level->parm_order; + + /* Just `void' (and no ellipsis) is special. There are really no parms. */ + if (void_at_end && parms != 0 + && TREE_CHAIN (parms) == 0 + && TYPE_MAIN_VARIANT (TREE_TYPE (parms)) == void_type_node + && DECL_NAME (parms) == 0) + { + parms = NULL_TREE; + storedecls (NULL_TREE); + return saveable_tree_cons (NULL_TREE, NULL_TREE, + saveable_tree_cons (NULL_TREE, void_type_node, NULL_TREE)); + } + + /* Extract enumerator values and other non-parms declared with the parms. + Likewise any forward parm decls that didn't have real parm decls. */ + for (decl = parms; decl; ) + { + tree next = TREE_CHAIN (decl); + + if (TREE_CODE (decl) != PARM_DECL) + { + TREE_CHAIN (decl) = new_parms; + new_parms = decl; + } + else if (TREE_ASM_WRITTEN (decl)) + { + error_with_decl (decl, "parameter `%s' has just a forward declaration"); + TREE_CHAIN (decl) = new_parms; + new_parms = decl; + } + decl = next; + } + + /* Put the parm decls back in the order they were in in the parm list. */ + for (t = order; t; t = TREE_CHAIN (t)) + { + if (TREE_CHAIN (t)) + TREE_CHAIN (TREE_VALUE (t)) = TREE_VALUE (TREE_CHAIN (t)); + else + TREE_CHAIN (TREE_VALUE (t)) = 0; + } + + new_parms = chainon (order ? nreverse (TREE_VALUE (order)) : 0, + new_parms); + + /* Store the parmlist in the binding level since the old one + is no longer a valid list. (We have changed the chain pointers.) */ + storedecls (new_parms); + + for (decl = new_parms; decl; decl = TREE_CHAIN (decl)) + /* There may also be declarations for enumerators if an enumeration + type is declared among the parms. Ignore them here. */ + if (TREE_CODE (decl) == PARM_DECL) + { + /* Since there is a prototype, + args are passed in their declared types. */ + tree type = TREE_TYPE (decl); + DECL_ARG_TYPE (decl) = type; +#ifdef PROMOTE_PROTOTYPES + if ((TREE_CODE (type) == INTEGER_TYPE + || TREE_CODE (type) == ENUMERAL_TYPE) + && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) + DECL_ARG_TYPE (decl) = integer_type_node; +#endif + + types = saveable_tree_cons (NULL_TREE, TREE_TYPE (decl), types); + if (TYPE_MAIN_VARIANT (TREE_VALUE (types)) == void_type_node && ! erred + && DECL_NAME (decl) == 0) + { + error ("`void' in parameter list must be the entire list"); + erred = 1; + } + } + + if (void_at_end) + return saveable_tree_cons (new_parms, tags, + nreverse (saveable_tree_cons (NULL_TREE, void_type_node, types))); + + return saveable_tree_cons (new_parms, tags, nreverse (types)); +} + +/* At end of parameter list, warn about any struct, union or enum tags + defined within. Do so because these types cannot ever become complete. */ + +void +parmlist_tags_warning () +{ + tree elt; + static int already; + + for (elt = current_binding_level->tags; elt; elt = TREE_CHAIN (elt)) + { + enum tree_code code = TREE_CODE (TREE_VALUE (elt)); + /* An anonymous union parm type is meaningful as a GNU extension. + So don't warn for that. */ + if (code == UNION_TYPE && TREE_PURPOSE (elt) == 0 && !pedantic) + continue; + if (TREE_PURPOSE (elt) != 0) + warning ("`%s %s' declared inside parameter list", + (code == RECORD_TYPE ? "struct" + : code == UNION_TYPE ? "union" + : "enum"), + IDENTIFIER_POINTER (TREE_PURPOSE (elt))); + else + warning ("anonymous %s declared inside parameter list", + (code == RECORD_TYPE ? "struct" + : code == UNION_TYPE ? "union" + : "enum")); + + if (! already) + { + warning ("its scope is only this definition or declaration,"); + warning ("which is probably not what you want."); + already = 1; + } + } +} + +/* Get the struct, enum or union (CODE says which) with tag NAME. + Define the tag as a forward-reference if it is not defined. */ + +tree +xref_tag (code, name) + enum tree_code code; + tree name; +{ + int temporary = allocation_temporary_p (); + + /* If a cross reference is requested, look up the type + already defined for this tag and return it. */ + + register tree ref = lookup_tag (code, name, current_binding_level, 0); + /* Even if this is the wrong type of tag, return what we found. + There will be an error message anyway, from pending_xref_error. + If we create an empty xref just for an invalid use of the type, + the main result is to create lots of superfluous error messages. */ + if (ref) + return ref; + + push_obstacks_nochange (); + + if (current_binding_level == global_binding_level && temporary) + end_temporary_allocation (); + + /* If no such tag is yet defined, create a forward-reference node + and record it as the "definition". + When a real declaration of this type is found, + the forward-reference will be altered into a real type. */ + + ref = make_node (code); + if (code == ENUMERAL_TYPE) + { + /* (In ANSI, Enums can be referred to only if already defined.) */ + if (pedantic) + pedwarn ("ANSI C forbids forward references to `enum' types"); + /* Give the type a default layout like unsigned int + to avoid crashing if it does not get defined. */ + TYPE_MODE (ref) = TYPE_MODE (unsigned_type_node); + TYPE_ALIGN (ref) = TYPE_ALIGN (unsigned_type_node); + 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); + } + + pushtag (name, ref); + + pop_obstacks (); + + return ref; +} + +/* Make sure that the tag NAME is defined *in the current binding level* + at least as a forward reference. + CODE says which kind of tag NAME ought to be. + + We also do a push_obstacks_nochange + whose matching pop is in finish_struct. */ + +tree +start_struct (code, name) + enum tree_code code; + tree name; +{ + /* If there is already a tag defined at this binding level + (as a forward reference), just return it. */ + + register tree ref = 0; + + push_obstacks_nochange (); + if (current_binding_level == global_binding_level) + end_temporary_allocation (); + + if (name != 0) + ref = lookup_tag (code, name, current_binding_level, 1); + if (ref && TREE_CODE (ref) == code) + { + C_TYPE_BEING_DEFINED (ref) = 1; + TYPE_PACKED (ref) = flag_pack_struct; + if (TYPE_FIELDS (ref)) + error ((code == UNION_TYPE ? "redefinition of `union %s'" + : "redefinition of `struct %s'"), + IDENTIFIER_POINTER (name)); + + return ref; + } + + /* Otherwise create a forward-reference just so the tag is in scope. */ + + ref = make_node (code); + pushtag (name, ref); + C_TYPE_BEING_DEFINED (ref) = 1; + TYPE_PACKED (ref) = flag_pack_struct; + return ref; +} + +/* 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. + + This is done during the parsing of the struct declaration. + The FIELD_DECL nodes are chained together and the lot of them + are ultimately passed to `build_struct' to make the RECORD_TYPE node. */ + +tree +grokfield (filename, line, declarator, declspecs, width) + char *filename; + int line; + tree declarator, declspecs, width; +{ + tree value; + + /* The corresponding pop_obstacks is in finish_decl. */ + push_obstacks_nochange (); + + value = grokdeclarator (declarator, declspecs, width ? BITFIELD : FIELD, 0); + + finish_decl (value, NULL_TREE, NULL_TREE); + DECL_INITIAL (value) = width; + + maybe_objc_check_decl (value); + return value; +} + +/* Function to help qsort sort FIELD_DECLs by name order. */ + +static int +field_decl_cmp (xp, yp) + const GENERIC_PTR xp; + const GENERIC_PTR yp; +{ + tree *x = (tree *)xp, *y = (tree *)yp; + + if (DECL_NAME (*x) == DECL_NAME (*y)) + return 0; + if (DECL_NAME (*x) == NULL) + return -1; + if (DECL_NAME (*y) == NULL) + return 1; + if (DECL_NAME (*x) < DECL_NAME (*y)) + return -1; + return 1; +} + +/* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T. + FIELDLIST is a chain of FIELD_DECL nodes for the fields. + ATTRIBUTES are attributes to be applied to the structure. + + We also do a pop_obstacks to match the push in start_struct. */ + +tree +finish_struct (t, fieldlist, attributes) + tree t; + tree fieldlist; + tree attributes; +{ + register tree x; + int old_momentary; + int toplevel = global_binding_level == current_binding_level; + + /* If this type was previously laid out as a forward reference, + make sure we lay it out again. */ + + TYPE_SIZE (t) = 0; + + decl_attributes (t, attributes, NULL_TREE); + + /* 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 ((TREE_CODE (t) == UNION_TYPE ? "union defined inside parms" + : "structure defined inside parms")); + else if (! flag_traditional) + warning ((TREE_CODE (t) == UNION_TYPE ? "union defined inside parms" + : "structure defined inside parms")); + } + + old_momentary = suspend_momentary (); + + if (pedantic) + { + for (x = fieldlist; x; x = TREE_CHAIN (x)) + if (DECL_NAME (x) != 0) + break; + + if (x == 0) + pedwarn ("%s has no %smembers", + (TREE_CODE (t) == UNION_TYPE ? "union" : "structure"), + (fieldlist ? "named " : "")); + } + + /* Install struct as DECL_CONTEXT of each field decl. + Also process specified field sizes. + Set DECL_FIELD_SIZE to the specified size, or 0 if none specified. + The specified size is found in the DECL_INITIAL. + Store 0 there, except for ": 0" fields (so we can find them + and delete them, below). */ + + for (x = fieldlist; x; x = TREE_CHAIN (x)) + { + DECL_CONTEXT (x) = t; + DECL_PACKED (x) |= TYPE_PACKED (t); + DECL_FIELD_SIZE (x) = 0; + + /* If any field is const, the structure type is pseudo-const. */ + if (TREE_READONLY (x)) + C_TYPE_FIELDS_READONLY (t) = 1; + else + { + /* A field that is pseudo-const makes the structure likewise. */ + tree t1 = TREE_TYPE (x); + while (TREE_CODE (t1) == ARRAY_TYPE) + t1 = TREE_TYPE (t1); + if ((TREE_CODE (t1) == RECORD_TYPE || TREE_CODE (t1) == UNION_TYPE) + && C_TYPE_FIELDS_READONLY (t1)) + C_TYPE_FIELDS_READONLY (t) = 1; + } + + /* Any field that is volatile means variables of this type must be + treated in some ways as volatile. */ + if (TREE_THIS_VOLATILE (x)) + C_TYPE_FIELDS_VOLATILE (t) = 1; + + /* Any field of nominal variable size implies structure is too. */ + if (C_DECL_VARIABLE_SIZE (x)) + C_TYPE_VARIABLE_SIZE (t) = 1; + + /* Detect invalid nested redefinition. */ + if (TREE_TYPE (x) == t) + error ("nested redefinition of `%s'", + IDENTIFIER_POINTER (TYPE_NAME (t))); + + /* Detect invalid bit-field size. */ + if (DECL_INITIAL (x)) + STRIP_NOPS (DECL_INITIAL (x)); + if (DECL_INITIAL (x)) + { + if (TREE_CODE (DECL_INITIAL (x)) == INTEGER_CST) + constant_expression_warning (DECL_INITIAL (x)); + else + { + error_with_decl (x, "bit-field `%s' width not an integer constant"); + DECL_INITIAL (x) = NULL; + } + } + + /* Detect invalid bit-field type. */ + if (DECL_INITIAL (x) + && TREE_CODE (TREE_TYPE (x)) != INTEGER_TYPE + && TREE_CODE (TREE_TYPE (x)) != ENUMERAL_TYPE) + { + error_with_decl (x, "bit-field `%s' has invalid type"); + DECL_INITIAL (x) = NULL; + } + if (DECL_INITIAL (x) && pedantic + && TYPE_MAIN_VARIANT (TREE_TYPE (x)) != integer_type_node + && TYPE_MAIN_VARIANT (TREE_TYPE (x)) != unsigned_type_node + /* Accept an enum that's equivalent to int or unsigned int. */ + && !(TREE_CODE (TREE_TYPE (x)) == ENUMERAL_TYPE + && (TYPE_PRECISION (TREE_TYPE (x)) + == TYPE_PRECISION (integer_type_node)))) + pedwarn_with_decl (x, "bit-field `%s' type invalid in ANSI C"); + + /* Detect and ignore out of range field width. */ + if (DECL_INITIAL (x)) + { + unsigned HOST_WIDE_INT width = TREE_INT_CST_LOW (DECL_INITIAL (x)); + + if (tree_int_cst_sgn (DECL_INITIAL (x)) < 0) + { + DECL_INITIAL (x) = NULL; + error_with_decl (x, "negative width in bit-field `%s'"); + } + else if (TREE_INT_CST_HIGH (DECL_INITIAL (x)) != 0 + || width > TYPE_PRECISION (TREE_TYPE (x))) + { + DECL_INITIAL (x) = NULL; + pedwarn_with_decl (x, "width of `%s' exceeds its type"); + } + else if (width == 0 && DECL_NAME (x) != 0) + { + error_with_decl (x, "zero width for bit-field `%s'"); + DECL_INITIAL (x) = NULL; + } + } + + /* Process valid field width. */ + if (DECL_INITIAL (x)) + { + register int width = TREE_INT_CST_LOW (DECL_INITIAL (x)); + + if (TREE_CODE (TREE_TYPE (x)) == ENUMERAL_TYPE + && (width < min_precision (TYPE_MIN_VALUE (TREE_TYPE (x)), + TREE_UNSIGNED (TREE_TYPE (x))) + || width < min_precision (TYPE_MAX_VALUE (TREE_TYPE (x)), + TREE_UNSIGNED (TREE_TYPE (x))))) + warning_with_decl (x, "`%s' is narrower than values of its type"); + + DECL_FIELD_SIZE (x) = width; + DECL_BIT_FIELD (x) = DECL_C_BIT_FIELD (x) = 1; + DECL_INITIAL (x) = NULL; + + if (width == 0) + { + /* field size 0 => force desired amount of alignment. */ +#ifdef EMPTY_FIELD_BOUNDARY + DECL_ALIGN (x) = MAX (DECL_ALIGN (x), EMPTY_FIELD_BOUNDARY); +#endif +#ifdef PCC_BITFIELD_TYPE_MATTERS + if (PCC_BITFIELD_TYPE_MATTERS) + DECL_ALIGN (x) = MAX (DECL_ALIGN (x), + TYPE_ALIGN (TREE_TYPE (x))); +#endif + } + } + else if (TREE_TYPE (x) != error_mark_node) + { + unsigned int min_align = (DECL_PACKED (x) ? BITS_PER_UNIT + : TYPE_ALIGN (TREE_TYPE (x))); + /* Non-bit-fields are aligned for their type, except packed + fields which require only BITS_PER_UNIT alignment. */ + DECL_ALIGN (x) = MAX (DECL_ALIGN (x), min_align); + } + } + + /* Now DECL_INITIAL is null on all members. */ + + /* Delete all duplicate fields from the fieldlist */ + for (x = fieldlist; x && TREE_CHAIN (x);) + /* Anonymous fields aren't duplicates. */ + if (DECL_NAME (TREE_CHAIN (x)) == 0) + x = TREE_CHAIN (x); + else + { + register tree y = fieldlist; + + while (1) + { + if (DECL_NAME (y) == DECL_NAME (TREE_CHAIN (x))) + break; + if (y == x) + break; + y = TREE_CHAIN (y); + } + if (DECL_NAME (y) == DECL_NAME (TREE_CHAIN (x))) + { + error_with_decl (TREE_CHAIN (x), "duplicate member `%s'"); + TREE_CHAIN (x) = TREE_CHAIN (TREE_CHAIN (x)); + } + else x = TREE_CHAIN (x); + } + + /* Now we have the nearly final fieldlist. Record it, + then lay out the structure or union (including the fields). */ + + TYPE_FIELDS (t) = fieldlist; + + layout_type (t); + + /* Delete all zero-width bit-fields from the front of the fieldlist */ + while (fieldlist + && DECL_INITIAL (fieldlist)) + fieldlist = TREE_CHAIN (fieldlist); + /* Delete all such members from the rest of the fieldlist */ + for (x = fieldlist; x;) + { + if (TREE_CHAIN (x) && DECL_INITIAL (TREE_CHAIN (x))) + TREE_CHAIN (x) = TREE_CHAIN (TREE_CHAIN (x)); + else x = TREE_CHAIN (x); + } + + /* Now we have the truly final field list. + Store it in this type and in the variants. */ + + TYPE_FIELDS (t) = fieldlist; + + /* If there are lots of fields, sort so we can look through them fast. + We arbitrarily consider 16 or more elts to be "a lot". */ + { + int len = 0; + + for (x = fieldlist; x; x = TREE_CHAIN (x)) + { + if (len > 15) + break; + len += 1; + } + if (len > 15) + { + tree *field_array; + char *space; + + 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. */ + if (allocation_temporary_p ()) + space = savealloc (sizeof (struct lang_type) + len * sizeof (tree)); + else + space = oballoc (sizeof (struct lang_type) + len * sizeof (tree)); + + TYPE_LANG_SPECIFIC (t) = (struct lang_type *) space; + TYPE_LANG_SPECIFIC (t)->len = len; + + field_array = &TYPE_LANG_SPECIFIC (t)->elts[0]; + len = 0; + for (x = fieldlist; x; x = TREE_CHAIN (x)) + field_array[len++] = x; + + qsort (field_array, len, sizeof (tree), field_decl_cmp); + } + } + + for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x)) + { + TYPE_FIELDS (x) = TYPE_FIELDS (t); + TYPE_LANG_SPECIFIC (x) = TYPE_LANG_SPECIFIC (t); + TYPE_ALIGN (x) = TYPE_ALIGN (t); + } + + /* If this was supposed to be a transparent union, but we can't + make it one, warn and turn off the flag. */ + if (TREE_CODE (t) == UNION_TYPE + && TYPE_TRANSPARENT_UNION (t) + && TYPE_MODE (t) != DECL_MODE (TYPE_FIELDS (t))) + { + TYPE_TRANSPARENT_UNION (t) = 0; + warning ("union cannot be made transparent"); + } + + /* If this structure or union completes the type of any previous + variable declaration, lay it out and output its rtl. */ + + if (current_binding_level->n_incomplete != 0) + { + tree decl; + for (decl = current_binding_level->names; decl; decl = TREE_CHAIN (decl)) + { + if (TREE_TYPE (decl) == t + && TREE_CODE (decl) != TYPE_DECL) + { + layout_decl (decl, 0); + /* This is a no-op in c-lang.c or something real in objc-actions.c. */ + maybe_objc_check_decl (decl); + rest_of_decl_compilation (decl, NULL_PTR, toplevel, 0); + if (! toplevel) + expand_decl (decl); + --current_binding_level->n_incomplete; + } + else if (TYPE_SIZE (TREE_TYPE (decl)) == 0 + && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) + { + tree element = TREE_TYPE (decl); + while (TREE_CODE (element) == ARRAY_TYPE) + element = TREE_TYPE (element); + if (element == t) + layout_array_type (TREE_TYPE (decl)); + } + } + } + + resume_momentary (old_momentary); + + /* Finish debugging output for this type. */ + rest_of_type_compilation (t, toplevel); + + /* The matching push is in start_struct. */ + pop_obstacks (); + + return t; +} + +/* Lay out the type T, and its element type, and so on. */ + +static void +layout_array_type (t) + tree t; +{ + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + layout_array_type (TREE_TYPE (t)); + layout_type (t); +} + +/* Begin compiling the definition of an enumeration type. + 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. */ + +tree +start_enum (name) + tree name; +{ + register tree enumtype = 0; + + /* 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. */ + + if (name != 0) + enumtype = lookup_tag (ENUMERAL_TYPE, name, current_binding_level, 1); + + /* The corresponding pop_obstacks is in finish_enum. */ + push_obstacks_nochange (); + /* If these symbols and types are global, make them permanent. */ + if (current_binding_level == global_binding_level) + end_temporary_allocation (); + + if (enumtype == 0 || TREE_CODE (enumtype) != ENUMERAL_TYPE) + { + enumtype = make_node (ENUMERAL_TYPE); + pushtag (name, enumtype); + } + + 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 %s'", IDENTIFIER_POINTER (name)); + + /* Completely replace its old definition. + The old enumerators remain defined, however. */ + TYPE_VALUES (enumtype) = 0; + } + + enum_next_value = integer_zero_node; + enum_overflow = 0; + + if (flag_short_enums) + TYPE_PACKED (enumtype) = 1; + + return enumtype; +} + +/* After processing and defining all the values of an enumeration type, + install their decls in the enumeration type and finish it off. + ENUMTYPE is the type object, VALUES a list of decl-value pairs, + and ATTRIBUTES are the specified attributes. + Returns ENUMTYPE. */ + +tree +finish_enum (enumtype, values, attributes) + tree enumtype; + tree values; + tree attributes; +{ + register tree pair, tem; + tree minnode = 0, maxnode = 0; + int lowprec, highprec, precision; + int toplevel = global_binding_level == current_binding_level; + + if (in_parm_level_p ()) + warning ("enum defined inside parms"); + + decl_attributes (enumtype, attributes, NULL_TREE); + + /* Calculate the maximum value of any enumerator in this type. */ + + if (values == error_mark_node) + minnode = maxnode = integer_zero_node; + else + for (pair = values; pair; pair = TREE_CHAIN (pair)) + { + tree value = TREE_VALUE (pair); + if (pair == values) + minnode = maxnode = TREE_VALUE (pair); + else + { + if (tree_int_cst_lt (maxnode, value)) + maxnode = value; + if (tree_int_cst_lt (value, minnode)) + minnode = value; + } + } + + TYPE_MIN_VALUE (enumtype) = minnode; + TYPE_MAX_VALUE (enumtype) = maxnode; + + /* An enum can have some negative values; then it is signed. */ + TREE_UNSIGNED (enumtype) = tree_int_cst_sgn (minnode) >= 0; + + /* Determine the precision this type needs. */ + + lowprec = min_precision (minnode, TREE_UNSIGNED (enumtype)); + highprec = min_precision (maxnode, TREE_UNSIGNED (enumtype)); + precision = MAX (lowprec, highprec); + + if (TYPE_PACKED (enumtype) || precision > TYPE_PRECISION (integer_type_node)) + { + tree narrowest = type_for_size (precision, 1); + if (narrowest == 0) + { + warning ("enumeration values exceed range of largest integer"); + narrowest = long_long_integer_type_node; + } + + TYPE_PRECISION (enumtype) = TYPE_PRECISION (narrowest); + } + else + TYPE_PRECISION (enumtype) = TYPE_PRECISION (integer_type_node); + + TYPE_SIZE (enumtype) = 0; + layout_type (enumtype); + + if (values != error_mark_node) + { + /* Change the type of the enumerators to be the enum type. + Formerly this was done only for enums that fit in an int, + but the comment said it was done only for enums wider than int. + It seems necessary to do this for wide enums, + and best not to change what's done for ordinary narrower ones. */ + for (pair = values; pair; pair = TREE_CHAIN (pair)) + { + TREE_TYPE (TREE_PURPOSE (pair)) = enumtype; + DECL_SIZE (TREE_PURPOSE (pair)) = TYPE_SIZE (enumtype); + if (TREE_CODE (TREE_PURPOSE (pair)) != FUNCTION_DECL) + DECL_ALIGN (TREE_PURPOSE (pair)) = TYPE_ALIGN (enumtype); + } + + /* Replace the decl nodes in VALUES with their names. */ + for (pair = values; pair; pair = TREE_CHAIN (pair)) + TREE_PURPOSE (pair) = DECL_NAME (TREE_PURPOSE (pair)); + + TYPE_VALUES (enumtype) = values; + } + + /* Fix up all variant types of this enum type. */ + for (tem = TYPE_MAIN_VARIANT (enumtype); tem; tem = TYPE_NEXT_VARIANT (tem)) + { + TYPE_VALUES (tem) = TYPE_VALUES (enumtype); + TYPE_MIN_VALUE (tem) = TYPE_MIN_VALUE (enumtype); + TYPE_MAX_VALUE (tem) = TYPE_MAX_VALUE (enumtype); + TYPE_SIZE (tem) = TYPE_SIZE (enumtype); + TYPE_SIZE_UNIT (tem) = TYPE_SIZE_UNIT (enumtype); + TYPE_MODE (tem) = TYPE_MODE (enumtype); + TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype); + TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype); + TREE_UNSIGNED (tem) = TREE_UNSIGNED (enumtype); + } + + /* Finish debugging output for this type. */ + rest_of_type_compilation (enumtype, toplevel); + + /* This matches a push in start_enum. */ + pop_obstacks (); + + return enumtype; +} + +/* Build and install a CONST_DECL for one value of the + current enumeration type (one that was begun with start_enum). + Return a tree-list containing the CONST_DECL and its value. + Assignment of sequential values by default is handled here. */ + +tree +build_enumerator (name, value) + tree name, value; +{ + register tree decl, type; + + /* Validate and default VALUE. */ + + /* Remove no-op casts from the value. */ + if (value) + STRIP_TYPE_NOPS (value); + + if (value != 0) + { + if (TREE_CODE (value) == INTEGER_CST) + { + value = default_conversion (value); + constant_expression_warning (value); + } + else + { + error ("enumerator value for `%s' not integer constant", + IDENTIFIER_POINTER (name)); + value = 0; + } + } + + /* Default based on previous value. */ + /* It should no longer be possible to have NON_LVALUE_EXPR + in the default. */ + if (value == 0) + { + value = enum_next_value; + if (enum_overflow) + error ("overflow in enumeration values"); + } + + if (pedantic && ! int_fits_type_p (value, integer_type_node)) + { + pedwarn ("ANSI C restricts enumerator values to range of `int'"); + value = integer_zero_node; + } + + /* Set basis for default for next value. */ + enum_next_value = build_binary_op (PLUS_EXPR, value, integer_one_node, 0); + enum_overflow = tree_int_cst_lt (enum_next_value, value); + + /* Now create a declaration for the enum value name. */ + + type = TREE_TYPE (value); + type = type_for_size (MAX (TYPE_PRECISION (type), + TYPE_PRECISION (integer_type_node)), + ((flag_traditional + || TYPE_PRECISION (type) >= TYPE_PRECISION (integer_type_node)) + && TREE_UNSIGNED (type))); + + decl = build_decl (CONST_DECL, name, type); + DECL_INITIAL (decl) = value; + TREE_TYPE (value) = type; + pushdecl (decl); + + return saveable_tree_cons (decl, value, NULL_TREE); +} + +/* Create the FUNCTION_DECL for a function definition. + DECLSPECS, DECLARATOR, PREFIX_ATTRIBUTES and ATTRIBUTES are the parts of + the declaration; they describe the function's name and the type it returns, + but twisted together in a fashion that parallels the syntax of C. + + 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. + + NESTED is nonzero for a function nested within another function. */ + +int +start_function (declspecs, declarator, prefix_attributes, attributes, nested) + tree declarator, declspecs, prefix_attributes, attributes; + int nested; +{ + tree decl1, old_decl; + 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; + warn_about_return_type = 0; + current_extern_inline = 0; + c_function_varargs = 0; + named_labels = 0; + shadowed_labels = 0; + + /* Don't expand any sizes in the return type of the function. */ + immediate_size_expand = 0; + + decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1); + + /* If the declarator is not suitable for a function definition, + cause a syntax error. */ + if (decl1 == 0) + { + immediate_size_expand = old_immediate_size_expand; + return 0; + } + + decl_attributes (decl1, prefix_attributes, attributes); + + announce_function (decl1); + + if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (decl1))) == 0) + { + error ("return-type is an incomplete type"); + /* Make it return void instead. */ + TREE_TYPE (decl1) + = build_function_type (void_type_node, + TYPE_ARG_TYPES (TREE_TYPE (decl1))); + } + + if (warn_about_return_type) + warning ("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; + + /* Make the init_value nonzero so pushdecl knows this is not tentative. + 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. + 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_file = DECL_SOURCE_FILE (old_decl); + current_function_prototype_line = DECL_SOURCE_LINE (old_decl); + } + + /* If there is no explicit declaration, look for any out-of-scope implicit + declarations. */ + if (old_decl == 0) + old_decl = IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)); + + /* Optionally warn of old-fashioned def with no previous prototype. */ + if (warn_strict_prototypes + && TYPE_ARG_TYPES (TREE_TYPE (decl1)) == 0 + && !(old_decl != 0 && TYPE_ARG_TYPES (TREE_TYPE (old_decl)) != 0)) + warning ("function declaration isn't a prototype"); + /* Optionally warn of any global def with no previous prototype. */ + else if (warn_missing_prototypes + && TREE_PUBLIC (decl1) + && !(old_decl != 0 && TYPE_ARG_TYPES (TREE_TYPE (old_decl)) != 0) + && strcmp ("main", IDENTIFIER_POINTER (DECL_NAME (decl1)))) + warning_with_decl (decl1, "no previous prototype for `%s'"); + /* Optionally warn of any def with no previous prototype + if the function has already been used. */ + else if (warn_missing_prototypes + && old_decl != 0 && TREE_USED (old_decl) + && TYPE_ARG_TYPES (TREE_TYPE (old_decl)) == 0) + warning_with_decl (decl1, + "`%s' was used with no prototype before its definition"); + /* Optionally warn of any global def with no previous declaration. */ + else if (warn_missing_declarations + && TREE_PUBLIC (decl1) + && old_decl == 0 + && strcmp ("main", IDENTIFIER_POINTER (DECL_NAME (decl1)))) + warning_with_decl (decl1, "no previous declaration for `%s'"); + /* Optionally warn of any def with no previous declaration + if the function has already been used. */ + else if (warn_missing_declarations + && old_decl != 0 && TREE_USED (old_decl) + && old_decl == IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1))) + warning_with_decl (decl1, + "`%s' was used with no declaration before its definition"); + + /* This is a definition, not a reference. + So normally clear DECL_EXTERNAL. + However, `extern inline' acts like a declaration + except for defining how to inline. So set DECL_EXTERNAL in that case. */ + DECL_EXTERNAL (decl1) = current_extern_inline; + +#ifdef SET_DEFAULT_DECL_ATTRIBUTES + SET_DEFAULT_DECL_ATTRIBUTES (decl1, attributes); +#endif + + /* This function exists in static storage. + (This does not mean `static' in the C sense!) */ + TREE_STATIC (decl1) = 1; + + /* A nested function is not global. */ + if (current_function_decl != 0) + TREE_PUBLIC (decl1) = 0; + + /* Warn for unlikely, improbable, or stupid declarations of `main'. */ + if (warn_main + && strcmp ("main", IDENTIFIER_POINTER (DECL_NAME (decl1))) == 0) + { + tree args; + int argct = 0; + + if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl1))) + != integer_type_node) + pedwarn_with_decl (decl1, "return type of `%s' is not `int'"); + + for (args = TYPE_ARG_TYPES (TREE_TYPE (decl1)); args; + args = TREE_CHAIN (args)) + { + tree type = args ? TREE_VALUE (args) : 0; + + if (type == void_type_node) + break; + + ++argct; + switch (argct) + { + case 1: + if (TYPE_MAIN_VARIANT (type) != integer_type_node) + pedwarn_with_decl (decl1, + "first argument of `%s' should be `int'"); + break; + + case 2: + if (TREE_CODE (type) != POINTER_TYPE + || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE + || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))) + != char_type_node)) + pedwarn_with_decl (decl1, + "second argument of `%s' should be `char **'"); + break; + + case 3: + if (TREE_CODE (type) != POINTER_TYPE + || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE + || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))) + != char_type_node)) + pedwarn_with_decl (decl1, + "third argument of `%s' should probably be `char **'"); + break; + } + } + + /* It is intentional that this message does not mention the third + argument, which is warned for only pedantically, because it's + blessed by mention in an appendix of the standard. */ + if (argct > 0 && (argct < 2 || argct > 3)) + pedwarn_with_decl (decl1, "`%s' takes only zero or two arguments"); + + if (argct == 3 && pedantic) + pedwarn_with_decl (decl1, "third argument of `%s' is deprecated"); + + if (! TREE_PUBLIC (decl1)) + pedwarn_with_decl (decl1, "`%s' is normally a non-static function"); + } + + /* Record the decl so that the function name is defined. + If we already have a decl for this name, and it is a FUNCTION_DECL, + use the old decl. */ + + current_function_decl = pushdecl (decl1); + + pushlevel (0); + declare_parm_level (1); + current_binding_level->subblocks_tag_transparent = 1; + + make_function_rtl (current_function_decl); + + 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 traditional + or if not really getting wider. */ + if (TREE_UNSIGNED (restype) + && (flag_traditional + || (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); + + if (!nested) + /* Allocate further tree nodes temporarily during compilation + of this function only. */ + temporary_allocation (); + + /* 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; + + return 1; +} + +/* Record that this function is going to be a varargs function. + This is called before store_parm_decls, which is too early + to call mark_varargs directly. */ + +void +c_mark_varargs () +{ + c_function_varargs = 1; +} + +/* Store the parameter declarations into the current function declaration. + This is called after parsing the parameter declarations, before + digesting the body of the function. + + For an old-style definition, modify the function's type + to specify at least the number of arguments. */ + +void +store_parm_decls () +{ + register tree fndecl = current_function_decl; + register tree parm; + + /* This is either a chain of PARM_DECLs (if a prototype was used) + or a list of IDENTIFIER_NODEs (for an old-fashioned C definition). */ + tree specparms = current_function_parms; + + /* This is a list of types declared among parms in a prototype. */ + tree parmtags = current_function_parm_tags; + + /* This is a chain of PARM_DECLs from old-style parm declarations. */ + register tree parmdecls = getdecls (); + + /* This is a chain of any other decls that came in among the parm + declarations. If a parm is declared with enum {foo, bar} x; + then CONST_DECLs for foo and bar are put here. */ + tree nonparms = 0; + + /* Nonzero if this definition is written with a prototype. */ + int prototype = 0; + + if (specparms != 0 && TREE_CODE (specparms) != TREE_LIST) + { + /* This case is when the function was defined with an ANSI prototype. + The parms already have decls, so we need not do anything here + except record them as in effect + and complain if any redundant old-style parm decls were written. */ + + register tree next; + tree others = 0; + + prototype = 1; + + if (parmdecls != 0) + { + tree decl, link; + + error_with_decl (fndecl, + "parm types given both in parmlist and separately"); + /* Get rid of the erroneous decls; don't keep them on + the list of parms, since they might not be PARM_DECLs. */ + for (decl = current_binding_level->names; + decl; decl = TREE_CHAIN (decl)) + if (DECL_NAME (decl)) + IDENTIFIER_LOCAL_VALUE (DECL_NAME (decl)) = 0; + for (link = current_binding_level->shadowed; + link; link = TREE_CHAIN (link)) + IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link); + current_binding_level->names = 0; + current_binding_level->shadowed = 0; + } + + specparms = nreverse (specparms); + for (parm = specparms; parm; parm = next) + { + next = TREE_CHAIN (parm); + if (TREE_CODE (parm) == PARM_DECL) + { + if (DECL_NAME (parm) == 0) + error_with_decl (parm, "parameter name omitted"); + else if (TYPE_MAIN_VARIANT (TREE_TYPE (parm)) == void_type_node) + { + error_with_decl (parm, "parameter `%s' declared void"); + /* Change the type to error_mark_node so this parameter + will be ignored by assign_parms. */ + TREE_TYPE (parm) = error_mark_node; + } + pushdecl (parm); + } + else + { + /* If we find an enum constant or a type tag, + put it aside for the moment. */ + TREE_CHAIN (parm) = 0; + others = chainon (others, parm); + } + } + + /* Get the decls in their original chain order + and record in the function. */ + DECL_ARGUMENTS (fndecl) = getdecls (); + +#if 0 + /* If this function takes a variable number of arguments, + add a phony parameter to the end of the parm list, + to represent the position of the first unnamed argument. */ + if (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (fndecl)))) + != void_type_node) + { + tree dummy = build_decl (PARM_DECL, NULL_TREE, void_type_node); + /* Let's hope the address of the unnamed parm + won't depend on its type. */ + TREE_TYPE (dummy) = integer_type_node; + DECL_ARG_TYPE (dummy) = integer_type_node; + DECL_ARGUMENTS (fndecl) + = chainon (DECL_ARGUMENTS (fndecl), dummy); + } +#endif + + /* Now pushdecl the enum constants. */ + for (parm = others; parm; parm = next) + { + next = TREE_CHAIN (parm); + if (DECL_NAME (parm) == 0) + ; + else if (TYPE_MAIN_VARIANT (TREE_TYPE (parm)) == void_type_node) + ; + else if (TREE_CODE (parm) != PARM_DECL) + pushdecl (parm); + } + + storetags (chainon (parmtags, gettags ())); + } + else + { + /* SPECPARMS is an identifier list--a chain of TREE_LIST nodes + each with a parm name as the TREE_VALUE. + + PARMDECLS is a chain of declarations for parameters. + Warning! It can also contain CONST_DECLs which are not parameters + but are names of enumerators of any enum types + declared among the parameters. + + First match each formal parameter name with its declaration. + Associate decls with the names and store the decls + into the TREE_PURPOSE slots. */ + + for (parm = parmdecls; parm; parm = TREE_CHAIN (parm)) + DECL_RESULT (parm) = 0; + + for (parm = specparms; parm; parm = TREE_CHAIN (parm)) + { + register tree tail, found = NULL; + + if (TREE_VALUE (parm) == 0) + { + error_with_decl (fndecl, "parameter name missing from parameter list"); + TREE_PURPOSE (parm) = 0; + continue; + } + + /* See if any of the parmdecls specifies this parm by name. + Ignore any enumerator decls. */ + for (tail = parmdecls; tail; tail = TREE_CHAIN (tail)) + if (DECL_NAME (tail) == TREE_VALUE (parm) + && TREE_CODE (tail) == PARM_DECL) + { + found = tail; + break; + } + + /* If declaration already marked, we have a duplicate name. + Complain, and don't use this decl twice. */ + if (found && DECL_RESULT (found) != 0) + { + error_with_decl (found, "multiple parameters named `%s'"); + found = 0; + } + + /* If the declaration says "void", complain and ignore it. */ + if (found && TYPE_MAIN_VARIANT (TREE_TYPE (found)) == void_type_node) + { + error_with_decl (found, "parameter `%s' declared void"); + TREE_TYPE (found) = integer_type_node; + DECL_ARG_TYPE (found) = integer_type_node; + layout_decl (found, 0); + } + + /* Traditionally, a parm declared float is actually a double. */ + if (found && flag_traditional + && TYPE_MAIN_VARIANT (TREE_TYPE (found)) == float_type_node) + { + TREE_TYPE (found) = double_type_node; + DECL_ARG_TYPE (found) = double_type_node; + layout_decl (found, 0); + } + + /* If no declaration found, default to int. */ + if (!found) + { + found = build_decl (PARM_DECL, TREE_VALUE (parm), + integer_type_node); + DECL_ARG_TYPE (found) = TREE_TYPE (found); + DECL_SOURCE_LINE (found) = DECL_SOURCE_LINE (fndecl); + DECL_SOURCE_FILE (found) = DECL_SOURCE_FILE (fndecl); + if (extra_warnings) + warning_with_decl (found, "type of `%s' defaults to `int'"); + pushdecl (found); + } + + TREE_PURPOSE (parm) = found; + + /* Mark this decl as "already found" -- see test, above. + It is safe to use DECL_RESULT for this + since it is not used in PARM_DECLs or CONST_DECLs. */ + DECL_RESULT (found) = error_mark_node; + } + + /* Put anything which is on the parmdecls chain and which is + not a PARM_DECL onto the list NONPARMS. (The types of + non-parm things which might appear on the list include + enumerators and NULL-named TYPE_DECL nodes.) Complain about + any actual PARM_DECLs not matched with any names. */ + + nonparms = 0; + for (parm = parmdecls; parm; ) + { + tree next = TREE_CHAIN (parm); + TREE_CHAIN (parm) = 0; + + if (TREE_CODE (parm) != PARM_DECL) + nonparms = chainon (nonparms, parm); + else + { + /* Complain about args with incomplete types. */ + if (TYPE_SIZE (TREE_TYPE (parm)) == 0) + { + error_with_decl (parm, "parameter `%s' has incomplete type"); + TREE_TYPE (parm) = error_mark_node; + } + + if (DECL_RESULT (parm) == 0) + { + error_with_decl (parm, + "declaration for parameter `%s' but no such parameter"); + /* Pretend the parameter was not missing. + This gets us to a standard state and minimizes + further error messages. */ + specparms + = chainon (specparms, + tree_cons (parm, NULL_TREE, NULL_TREE)); + } + } + + parm = next; + } + + /* Chain the declarations together in the order of the list of names. */ + /* Store that chain in the function decl, replacing the list of names. */ + parm = specparms; + DECL_ARGUMENTS (fndecl) = 0; + { + register tree last; + for (last = 0; parm; parm = TREE_CHAIN (parm)) + if (TREE_PURPOSE (parm)) + { + if (last == 0) + DECL_ARGUMENTS (fndecl) = TREE_PURPOSE (parm); + else + TREE_CHAIN (last) = TREE_PURPOSE (parm); + last = TREE_PURPOSE (parm); + TREE_CHAIN (last) = 0; + } + } + + /* 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 (TYPE_ARG_TYPES (TREE_TYPE (fndecl))) + { + register tree type; + for (parm = DECL_ARGUMENTS (fndecl), + 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)) + { + if (parm == 0 || type == 0 + || TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node) + { + error ("number of arguments doesn't match prototype"); + error_with_file_and_line (current_function_prototype_file, + current_function_prototype_line, + "prototype declaration"); + break; + } + /* Type for passing arg must be consistent + with that declared for the arg. */ + if (! comptypes (DECL_ARG_TYPE (parm), TREE_VALUE (type))) + { + if (TYPE_MAIN_VARIANT (TREE_TYPE (parm)) + == TYPE_MAIN_VARIANT (TREE_VALUE (type))) + { + /* Adjust argument to match prototype. E.g. a previous + `int foo(float);' prototype causes + `int foo(x) float x; {...}' to be treated like + `int foo(float x) {...}'. This is particularly + useful for argument types like uid_t. */ + DECL_ARG_TYPE (parm) = TREE_TYPE (parm); +#ifdef PROMOTE_PROTOTYPES + if ((TREE_CODE (TREE_TYPE (parm)) == INTEGER_TYPE + || TREE_CODE (TREE_TYPE (parm)) == ENUMERAL_TYPE) + && TYPE_PRECISION (TREE_TYPE (parm)) + < TYPE_PRECISION (integer_type_node)) + DECL_ARG_TYPE (parm) = integer_type_node; +#endif + if (pedantic) + { + pedwarn ("promoted argument `%s' doesn't match prototype", + IDENTIFIER_POINTER (DECL_NAME (parm))); + warning_with_file_and_line + (current_function_prototype_file, + current_function_prototype_line, + "prototype declaration"); + } + } + /* If -traditional, allow `int' argument to match + `unsigned' prototype. */ + else if (! (flag_traditional + && TYPE_MAIN_VARIANT (TREE_TYPE (parm)) == integer_type_node + && TYPE_MAIN_VARIANT (TREE_VALUE (type)) == unsigned_type_node)) + { + error ("argument `%s' doesn't match prototype", + IDENTIFIER_POINTER (DECL_NAME (parm))); + error_with_file_and_line (current_function_prototype_file, + current_function_prototype_line, + "prototype declaration"); + } + } + } + TYPE_ACTUAL_ARG_TYPES (TREE_TYPE (fndecl)) = 0; + } + + /* Otherwise, create a prototype that would match. */ + + else + { + tree actual = 0, last = 0, type; + + for (parm = DECL_ARGUMENTS (fndecl); parm; parm = TREE_CHAIN (parm)) + { + type = perm_tree_cons (NULL_TREE, DECL_ARG_TYPE (parm), + NULL_TREE); + if (last) + TREE_CHAIN (last) = type; + else + actual = type; + last = type; + } + type = perm_tree_cons (NULL_TREE, void_type_node, NULL_TREE); + if (last) + TREE_CHAIN (last) = type; + else + actual = type; + + /* We are going to assign a new value for the TYPE_ACTUAL_ARG_TYPES + of the type of this function, but we need to avoid having this + affect the types of other similarly-typed functions, so we must + first force the generation of an identical (but separate) type + node for the relevant function type. The new node we create + will be a variant of the main variant of the original function + type. */ + + TREE_TYPE (fndecl) = build_type_copy (TREE_TYPE (fndecl)); + + TYPE_ACTUAL_ARG_TYPES (TREE_TYPE (fndecl)) = actual; + } + + /* Now store the final chain of decls for the arguments + as the decl-chain of the current lexical scope. + Put the enumerators in as well, at the front so that + DECL_ARGUMENTS is not modified. */ + + storedecls (chainon (nonparms, DECL_ARGUMENTS (fndecl))); + } + + /* Make sure the binding level for the top of the function body + gets a BLOCK if there are any in the function. + Otherwise, the dbx output is wrong. */ + + keep_next_if_subblocks = 1; + + /* ??? This might be an improvement, + but needs to be thought about some more. */ +#if 0 + keep_next_level_flag = 1; +#endif + + /* Write a record describing this function definition to the prototypes + file (if requested). */ + + gen_aux_info_record (fndecl, 1, 0, prototype); + + /* Initialize the RTL code for the function. */ + + init_function_start (fndecl, input_filename, lineno); + + /* If this is a varargs function, inform function.c. */ + + if (c_function_varargs) + mark_varargs (); + + /* Declare __FUNCTION__ and __PRETTY_FUNCTION__ for this function. */ + + declare_function_name (); + + /* Set up parameters and prepare for return, for the function. */ + + expand_function_start (fndecl, 0); + + /* If this function is `main', emit a call to `__main' + to run global initializers, etc. */ + if (DECL_NAME (fndecl) + && strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "main") == 0 + && DECL_CONTEXT (fndecl) == NULL_TREE) + expand_main_function (); +} + +/* SPECPARMS is an identifier list--a chain of TREE_LIST nodes + each with a parm name as the TREE_VALUE. A null pointer as TREE_VALUE + stands for an ellipsis in the identifier list. + + PARMLIST is the data returned by get_parm_info for the + parmlist that follows the semicolon. + + We return a value of the same sort that get_parm_info returns, + except that it describes the combination of identifiers and parmlist. */ + +tree +combine_parm_decls (specparms, parmlist, void_at_end) + tree specparms, parmlist; + int void_at_end; +{ + register tree fndecl = current_function_decl; + register tree parm; + + tree parmdecls = TREE_PURPOSE (parmlist); + + /* This is a chain of any other decls that came in among the parm + declarations. They were separated already by get_parm_info, + so we just need to keep them separate. */ + tree nonparms = TREE_VALUE (parmlist); + + tree types = 0; + + for (parm = parmdecls; parm; parm = TREE_CHAIN (parm)) + DECL_RESULT (parm) = 0; + + for (parm = specparms; parm; parm = TREE_CHAIN (parm)) + { + register tree tail, found = NULL; + + /* See if any of the parmdecls specifies this parm by name. */ + for (tail = parmdecls; tail; tail = TREE_CHAIN (tail)) + if (DECL_NAME (tail) == TREE_VALUE (parm)) + { + found = tail; + break; + } + + /* If declaration already marked, we have a duplicate name. + Complain, and don't use this decl twice. */ + if (found && DECL_RESULT (found) != 0) + { + error_with_decl (found, "multiple parameters named `%s'"); + found = 0; + } + + /* If the declaration says "void", complain and ignore it. */ + if (found && TYPE_MAIN_VARIANT (TREE_TYPE (found)) == void_type_node) + { + error_with_decl (found, "parameter `%s' declared void"); + TREE_TYPE (found) = integer_type_node; + DECL_ARG_TYPE (found) = integer_type_node; + layout_decl (found, 0); + } + + /* Traditionally, a parm declared float is actually a double. */ + if (found && flag_traditional + && TYPE_MAIN_VARIANT (TREE_TYPE (found)) == float_type_node) + { + TREE_TYPE (found) = double_type_node; + DECL_ARG_TYPE (found) = double_type_node; + layout_decl (found, 0); + } + + /* If no declaration found, default to int. */ + if (!found) + { + found = build_decl (PARM_DECL, TREE_VALUE (parm), + integer_type_node); + DECL_ARG_TYPE (found) = TREE_TYPE (found); + DECL_SOURCE_LINE (found) = DECL_SOURCE_LINE (fndecl); + DECL_SOURCE_FILE (found) = DECL_SOURCE_FILE (fndecl); + error_with_decl (found, "type of parameter `%s' is not declared"); + pushdecl (found); + } + + TREE_PURPOSE (parm) = found; + + /* Mark this decl as "already found" -- see test, above. + It is safe to use DECL_RESULT for this + since it is not used in PARM_DECLs or CONST_DECLs. */ + DECL_RESULT (found) = error_mark_node; + } + + /* Complain about any actual PARM_DECLs not matched with any names. */ + + for (parm = parmdecls; parm; ) + { + tree next = TREE_CHAIN (parm); + TREE_CHAIN (parm) = 0; + + /* Complain about args with incomplete types. */ + if (TYPE_SIZE (TREE_TYPE (parm)) == 0) + { + error_with_decl (parm, "parameter `%s' has incomplete type"); + TREE_TYPE (parm) = error_mark_node; + } + + if (DECL_RESULT (parm) == 0) + { + error_with_decl (parm, + "declaration for parameter `%s' but no such parameter"); + /* Pretend the parameter was not missing. + This gets us to a standard state and minimizes + further error messages. */ + specparms + = chainon (specparms, + tree_cons (parm, NULL_TREE, NULL_TREE)); + } + + parm = next; + } + + /* Chain the declarations together in the order of the list of names. + At the same time, build up a list of their types, in reverse order. */ + + parm = specparms; + parmdecls = 0; + { + register tree last; + for (last = 0; parm; parm = TREE_CHAIN (parm)) + if (TREE_PURPOSE (parm)) + { + if (last == 0) + parmdecls = TREE_PURPOSE (parm); + else + TREE_CHAIN (last) = TREE_PURPOSE (parm); + last = TREE_PURPOSE (parm); + TREE_CHAIN (last) = 0; + + types = saveable_tree_cons (NULL_TREE, TREE_TYPE (parm), types); + } + } + + if (void_at_end) + return saveable_tree_cons (parmdecls, nonparms, + nreverse (saveable_tree_cons (NULL_TREE, + void_type_node, + types))); + + return saveable_tree_cons (parmdecls, nonparms, nreverse (types)); +} + +/* Finish up a function declaration and compile that function + all the way to assembler language output. The free the storage + for the function definition. + + This is called after parsing the body of the function definition. + + NESTED is nonzero if the function being finished is nested in another. */ + +void +finish_function (nested) + int nested; +{ + register tree fndecl = current_function_decl; + +/* TREE_READONLY (fndecl) = 1; + This caused &foo to be of type ptr-to-const-function + which then got a warning when stored in a ptr-to-function variable. */ + + poplevel (1, 0, 1); + BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; + + /* Must mark the RESULT_DECL as being in this function. */ + + DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl; + + /* Obey `register' declarations if `setjmp' is called in this fn. */ + if (flag_traditional && current_function_calls_setjmp) + { + setjmp_protect (DECL_INITIAL (fndecl)); + setjmp_protect_args (); + } + + if (! strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "main")) + { + if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl))) + != integer_type_node) + { + /* You would expect the sense of this test to be the other way + around, but if warn_main is set, we will already have warned, + so this would be a duplicate. This is the warning you get + in some environments even if you *don't* ask for it, because + these are environments where it may be more of a problem than + usual. */ + if (! warn_main) + pedwarn_with_decl (fndecl, "return type of `%s' is not `int'"); + } + else + { +#ifdef DEFAULT_MAIN_RETURN + /* Make it so that `main' always returns success by default. */ + DEFAULT_MAIN_RETURN; +#endif + } + } + + /* Generate rtl for function exit. */ + expand_function_end (input_filename, lineno, 0); + + /* So we can tell if jump_optimize sets it to 1. */ + can_reach_end = 0; + + /* Run the optimizers and output the assembler code for this function. */ + rest_of_compilation (fndecl); + + current_function_returns_null |= can_reach_end; + + if (warn_missing_noreturn + && !TREE_THIS_VOLATILE (fndecl) + && !current_function_returns_null + && !current_function_returns_value) + warning ("function might be possible candidate for attribute `noreturn'"); + + if (TREE_THIS_VOLATILE (fndecl) && current_function_returns_null) + warning ("`noreturn' function does return"); + else if (warn_return_type && can_reach_end + && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl))) != void_type_node) + /* If this function returns non-void and control can drop through, + complain. */ + warning ("control reaches end of non-void function"); + /* With just -W, complain only if function returns both with + and without a value. */ + else if (extra_warnings + && current_function_returns_value && current_function_returns_null) + warning ("this function may return with or without a value"); + + /* If requested, warn about function definitions where the function will + return a value (usually of some struct or union type) which itself will + take up a lot of stack space. */ + + if (warn_larger_than && !DECL_EXTERNAL (fndecl) && TREE_TYPE (fndecl)) + { + register tree ret_type = TREE_TYPE (TREE_TYPE (fndecl)); + + if (ret_type) + { + register tree ret_type_size = TYPE_SIZE (ret_type); + + if (TREE_CODE (ret_type_size) == INTEGER_CST) + { + unsigned units + = TREE_INT_CST_LOW (ret_type_size) / BITS_PER_UNIT; + + if (units > larger_than_size) + warning_with_decl (fndecl, + "size of return value of `%s' is %u bytes", + units); + } + } + } + + /* Free all the tree nodes making up this function. */ + /* Switch back to allocating nodes permanently + until we start another function. */ + if (! nested) + permanent_allocation (1); + + if (DECL_SAVED_INSNS (fndecl) == 0 && ! nested) + { + /* Stop pointing to the local nodes about to be freed. */ + /* But DECL_INITIAL must remain nonzero so we know this + was an actual function definition. */ + /* For a nested function, this is done in pop_c_function_context. */ + /* If rest_of_compilation set this to 0, leave it 0. */ + if (DECL_INITIAL (fndecl) != 0) + DECL_INITIAL (fndecl) = error_mark_node; + DECL_ARGUMENTS (fndecl) = 0; + } + + if (DECL_STATIC_CONSTRUCTOR (fndecl)) + { +#ifndef ASM_OUTPUT_CONSTRUCTOR + if (! flag_gnu_linker) + static_ctors = perm_tree_cons (NULL_TREE, fndecl, static_ctors); + else +#endif + assemble_constructor (IDENTIFIER_POINTER (DECL_NAME (fndecl))); + } + if (DECL_STATIC_DESTRUCTOR (fndecl)) + { +#ifndef ASM_OUTPUT_DESTRUCTOR + if (! flag_gnu_linker) + static_dtors = perm_tree_cons (NULL_TREE, fndecl, static_dtors); + else +#endif + assemble_destructor (IDENTIFIER_POINTER (DECL_NAME (fndecl))); + } + + if (! nested) + { + /* Let the error reporting routines know that we're outside a + function. For a nested function, this value is used in + pop_c_function_context and then reset via pop_function_context. */ + current_function_decl = NULL; + } +} + +/* Save and restore the variables in this file and elsewhere + that keep track of the progress of compilation of the current function. + Used for nested functions. */ + +struct c_function +{ + struct c_function *next; + tree named_labels; + tree shadowed_labels; + int returns_value; + int returns_null; + int warn_about_return_type; + int extern_inline; + struct binding_level *binding_level; +}; + +struct c_function *c_function_chain; + +/* Save and reinitialize the variables + used during compilation of a C function. */ + +void +push_c_function_context () +{ + struct c_function *p + = (struct c_function *) xmalloc (sizeof (struct c_function)); + + if (pedantic) + pedwarn ("ANSI C forbids nested functions"); + + push_function_context (); + + p->next = c_function_chain; + c_function_chain = p; + + p->named_labels = named_labels; + p->shadowed_labels = shadowed_labels; + p->returns_value = current_function_returns_value; + p->returns_null = current_function_returns_null; + p->warn_about_return_type = warn_about_return_type; + p->extern_inline = current_extern_inline; + p->binding_level = current_binding_level; +} + +/* Restore the variables used during compilation of a C function. */ + +void +pop_c_function_context () +{ + struct c_function *p = c_function_chain; + tree link; + + /* Bring back all the labels that were shadowed. */ + for (link = shadowed_labels; link; link = TREE_CHAIN (link)) + if (DECL_NAME (TREE_VALUE (link)) != 0) + IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link))) + = TREE_VALUE (link); + + if (DECL_SAVED_INSNS (current_function_decl) == 0) + { + /* Stop pointing to the local nodes about to be freed. */ + /* But DECL_INITIAL must remain nonzero so we know this + was an actual function definition. */ + DECL_INITIAL (current_function_decl) = error_mark_node; + DECL_ARGUMENTS (current_function_decl) = 0; + } + + pop_function_context (); + + c_function_chain = p->next; + + named_labels = p->named_labels; + shadowed_labels = p->shadowed_labels; + current_function_returns_value = p->returns_value; + current_function_returns_null = p->returns_null; + warn_about_return_type = p->warn_about_return_type; + current_extern_inline = p->extern_inline; + current_binding_level = p->binding_level; + + free (p); +} + +/* integrate_decl_tree calls this function, but since we don't use the + DECL_LANG_SPECIFIC field, this is a no-op. */ + +void +copy_lang_decl (node) + tree node ATTRIBUTE_UNUSED; +{ +} diff --git a/gcc_arm/c-gperf.h b/gcc_arm/c-gperf.h new file mode 100755 index 0000000..4d374b4 --- /dev/null +++ b/gcc_arm/c-gperf.h @@ -0,0 +1,192 @@ +/* KR-C code produced by gperf version 2.7.1 (19981006 egcs) */ +/* Command-line: gperf -L KR-C -F , 0, 0 -p -j1 -i 1 -g -o -t -G -N is_reserved_word -k1,3,$ ../../gcc/c-parse.gperf */ +/* Command-line: gperf -L KR-C -F ', 0, 0' -p -j1 -i 1 -g -o -t -N is_reserved_word -k1,3,$ c-parse.gperf */ +struct resword { char *name; short token; enum rid rid; }; + +#define TOTAL_KEYWORDS 83 +#define MIN_WORD_LENGTH 2 +#define MAX_WORD_LENGTH 20 +#define MIN_HASH_VALUE 8 +#define MAX_HASH_VALUE 141 +/* maximum key range = 134, duplicates = 0 */ + + +static inline unsigned int +hash (str, len) + register char *str; + register unsigned int len; +{ + static unsigned char asso_values[] = + { + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 35, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 1, 142, 90, 1, 28, + 40, 6, 1, 24, 3, 13, 142, 36, 60, 14, + 49, 3, 6, 142, 19, 8, 1, 50, 33, 11, + 2, 23, 4, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142 + }; + register int hval = len; + + switch (hval) + { + default: + case 3: + hval += asso_values[(unsigned char)str[2]]; + case 2: + case 1: + hval += asso_values[(unsigned char)str[0]]; + break; + } + return hval + asso_values[(unsigned char)str[len - 1]]; +} + +static struct resword wordlist[] = + { + {"", 0, 0}, {"", 0, 0}, {"", 0, 0}, {"", 0, 0}, {"", 0, 0}, {"", 0, 0}, {"", 0, 0}, {"", 0, 0}, + {"out", TYPE_QUAL, RID_OUT}, + {"", 0, 0}, + {"float", TYPESPEC, RID_FLOAT}, + {"__typeof", TYPEOF, NORID}, + {"", 0, 0}, + {"__typeof__", TYPEOF, NORID}, + {"typeof", TYPEOF, NORID}, + {"typedef", SCSPEC, RID_TYPEDEF}, + {"if", IF, NORID}, + {"short", TYPESPEC, RID_SHORT}, + {"int", TYPESPEC, RID_INT}, + {"sizeof", SIZEOF, NORID}, + {"__signed__", TYPESPEC, RID_SIGNED}, + {"__extension__", EXTENSION, NORID}, + {"inout", TYPE_QUAL, RID_INOUT}, + {"__imag__", IMAGPART, NORID}, + {"else", ELSE, NORID}, + {"__inline__", SCSPEC, RID_INLINE}, + {"byref", TYPE_QUAL, RID_BYREF}, + {"__iterator__", SCSPEC, RID_ITERATOR}, + {"__inline", SCSPEC, RID_INLINE}, + {"__real__", REALPART, NORID}, + {"switch", SWITCH, NORID}, + {"__restrict", TYPE_QUAL, RID_RESTRICT}, + {"goto", GOTO, NORID}, + {"__restrict__", TYPE_QUAL, RID_RESTRICT}, + {"struct", STRUCT, NORID}, + {"while", WHILE, NORID}, + {"restrict", TYPE_QUAL, RID_RESTRICT}, + {"__const", TYPE_QUAL, RID_CONST}, + {"oneway", TYPE_QUAL, RID_ONEWAY}, + {"__const__", TYPE_QUAL, RID_CONST}, + {"__complex", TYPESPEC, RID_COMPLEX}, + {"__complex__", TYPESPEC, RID_COMPLEX}, + {"for", FOR, NORID}, + {"__iterator", SCSPEC, RID_ITERATOR}, + {"__imag", IMAGPART, NORID}, + {"do", DO, NORID}, + {"case", CASE, NORID}, + {"__volatile__", TYPE_QUAL, RID_VOLATILE}, + {"break", BREAK, NORID}, + {"default", DEFAULT, NORID}, + {"__volatile", TYPE_QUAL, RID_VOLATILE}, + {"", 0, 0}, {"", 0, 0}, {"", 0, 0}, + {"@defs", DEFS, NORID}, + {"id", OBJECTNAME, RID_ID}, + {"", 0, 0}, + {"__signed", TYPESPEC, RID_SIGNED}, + {"bycopy", TYPE_QUAL, RID_BYCOPY}, + {"", 0, 0}, {"", 0, 0}, {"", 0, 0}, + {"extern", SCSPEC, RID_EXTERN}, + {"", 0, 0}, + {"in", TYPE_QUAL, RID_IN}, + {"", 0, 0}, + {"@compatibility_alias", ALIAS, NORID}, + {"", 0, 0}, + {"@private", PRIVATE, NORID}, + {"@selector", SELECTOR, NORID}, + {"register", SCSPEC, RID_REGISTER}, + {"__label__", LABEL, NORID}, + {"", 0, 0}, {"", 0, 0}, + {"enum", ENUM, NORID}, + {"return", RETURN, NORID}, + {"", 0, 0}, {"", 0, 0}, + {"signed", TYPESPEC, RID_SIGNED}, + {"", 0, 0}, {"", 0, 0}, {"", 0, 0}, {"", 0, 0}, + {"const", TYPE_QUAL, RID_CONST}, + {"", 0, 0}, + {"inline", SCSPEC, RID_INLINE}, + {"__real", REALPART, NORID}, + {"", 0, 0}, {"", 0, 0}, {"", 0, 0}, + {"void", TYPESPEC, RID_VOID}, + {"continue", CONTINUE, NORID}, + {"", 0, 0}, {"", 0, 0}, {"", 0, 0}, {"", 0, 0}, {"", 0, 0}, + {"@encode", ENCODE, NORID}, + {"auto", SCSPEC, RID_AUTO}, + {"__asm__", ASM_KEYWORD, NORID}, + {"@interface", INTERFACE, NORID}, + {"__alignof", ALIGNOF, NORID}, + {"double", TYPESPEC, RID_DOUBLE}, + {"__alignof__", ALIGNOF, NORID}, + {"@protected", PROTECTED, NORID}, + {"__attribute__", ATTRIBUTE, NORID}, + {"unsigned", TYPESPEC, RID_UNSIGNED}, + {"volatile", TYPE_QUAL, RID_VOLATILE}, + {"__attribute", ATTRIBUTE, NORID}, + {"@class", CLASS, NORID}, + {"__asm", ASM_KEYWORD, NORID}, + {"", 0, 0}, {"", 0, 0}, + {"@implementation", IMPLEMENTATION, NORID}, + {"", 0, 0}, {"", 0, 0}, {"", 0, 0}, + {"union", UNION, NORID}, + {"", 0, 0}, {"", 0, 0}, + {"@public", PUBLIC, NORID}, + {"asm", ASM_KEYWORD, NORID}, + {"", 0, 0}, + {"@protocol", PROTOCOL, NORID}, + {"", 0, 0}, {"", 0, 0}, {"", 0, 0}, {"", 0, 0}, + {"@end", END, NORID}, + {"", 0, 0}, {"", 0, 0}, {"", 0, 0}, + {"static", SCSPEC, RID_STATIC}, + {"", 0, 0}, {"", 0, 0}, {"", 0, 0}, {"", 0, 0}, + {"long", TYPESPEC, RID_LONG}, + {"", 0, 0}, {"", 0, 0}, {"", 0, 0}, + {"char", TYPESPEC, RID_CHAR} + }; + + +static inline struct resword * +is_reserved_word (str, len) + register char *str; + register unsigned int len; +{ + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) + { + register int key = hash (str, len); + + if (key <= MAX_HASH_VALUE && key >= 0) + { + register char *s = wordlist[key].name; + + if (*str == *s && !strcmp (str + 1, s + 1)) + return &wordlist[key]; + } + } + return 0; +} diff --git a/gcc_arm/c-iterate.c b/gcc_arm/c-iterate.c new file mode 100755 index 0000000..6f49e29 --- /dev/null +++ b/gcc_arm/c-iterate.c @@ -0,0 +1,604 @@ +/* Build expressions with type checking for C compiler. + Copyright (C) 1987, 88, 89, 92, 93, 96, 1997, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* This file is part of the C front end. + It is responsible for implementing iterators, + both their declarations and the expansion of statements using them. */ + +#include "config.h" +#include "system.h" +#include "tree.h" +#include "c-tree.h" +#include "flags.h" +#include "obstack.h" +#include "rtl.h" +#include "toplev.h" +#include "expr.h" + +/* + KEEPING TRACK OF EXPANSIONS + + In order to clean out expansions corresponding to statements inside + "{(...)}" constructs we have to keep track of all expansions. The + cleanup is needed when an automatic, or implicit, expansion on + iterator, say X, happens to a statement which contains a {(...)} + form with a statement already expanded on X. In this case we have + to go back and cleanup the inner expansion. This can be further + complicated by the fact that {(...)} can be nested. + + To make this cleanup possible, we keep lists of all expansions, and + to make it work for nested constructs, we keep a stack. The list at + the top of the stack (ITER_STACK.CURRENT_LEVEL) corresponds to the + currently parsed level. All expansions of the levels below the + current one are kept in one list whose head is pointed to by + ITER_STACK.SUBLEVEL_FIRST (SUBLEVEL_LAST is there for making merges + easy). The process works as follows: + + -- On "({" a new node is added to the stack by PUSH_ITERATOR_STACK. + The sublevel list is not changed at this point. + + -- On "})" the list for the current level is appended to the sublevel + list. + + -- On ";" sublevel lists are appended to the current level lists. + The reason is this: if they have not been superseded by the + expansion at the current level, they still might be + superseded later by the expansion on the higher level. + The levels do not have to distinguish levels below, so we + can merge the lists together. */ + +struct ixpansion +{ + tree ixdecl; /* Iterator decl */ + rtx ixprologue_start; /* First insn of epilogue. NULL means */ + /* explicit (FOR) expansion*/ + rtx ixprologue_end; + rtx ixepilogue_start; + rtx ixepilogue_end; + struct ixpansion *next; /* Next in the list */ +}; + +struct iter_stack_node +{ + struct ixpansion *first; /* Head of list of ixpansions */ + struct ixpansion *last; /* Last node in list of ixpansions */ + struct iter_stack_node *next; /* Next level iterator stack node */ +}; + +struct iter_stack_node *iter_stack; +struct iter_stack_node sublevel_ixpansions; + +/* A special obstack, and a pointer to the start of + all the data in it (so we can free everything easily). */ +static struct obstack ixp_obstack; +static char *ixp_firstobj; + +/* During collect_iterators, a list of SAVE_EXPRs already scanned. */ +static tree save_exprs; + +static void expand_stmt_with_iterators_1 PROTO((tree, tree)); +static tree collect_iterators PROTO((tree, tree)); +static void iterator_loop_prologue PROTO((tree, rtx *, rtx *)); +static void iterator_loop_epilogue PROTO((tree, rtx *, rtx *)); +static int top_level_ixpansion_p PROTO((void)); +static void isn_append PROTO((struct iter_stack_node *, + struct iter_stack_node *)); +static void istack_sublevel_to_current PROTO((void)); +static void add_ixpansion PROTO((tree, rtx, rtx, rtx, rtx)); +static void delete_ixpansion PROTO((tree)); + +/* Initialize our obstack once per compilation. */ + +void +init_iterators () +{ + gcc_obstack_init (&ixp_obstack); + ixp_firstobj = (char *) obstack_alloc (&ixp_obstack, 0); +} + +/* Handle the start of an explicit `for' loop for iterator IDECL. */ + +void +iterator_for_loop_start (idecl) + tree idecl; +{ + ITERATOR_BOUND_P (idecl) = 1; + add_ixpansion (idecl, 0, 0, 0, 0); + iterator_loop_prologue (idecl, 0, 0); +} + +/* Handle the end of an explicit `for' loop for iterator IDECL. */ + +void +iterator_for_loop_end (idecl) + tree idecl; +{ + iterator_loop_epilogue (idecl, 0, 0); + ITERATOR_BOUND_P (idecl) = 0; +} + +/* + ITERATOR RTL EXPANSIONS + + Expanding simple statements with iterators is straightforward: + collect the list of all free iterators in the statement, and + generate a loop for each of them. + + An iterator is "free" if it has not been "bound" by a FOR + operator. The DECL_RTL of the iterator is the loop counter. */ + +/* Expand a statement STMT, possibly containing iterator usage, into RTL. */ + +void +iterator_expand (stmt) + tree stmt; +{ + tree iter_list; + save_exprs = NULL_TREE; + iter_list = collect_iterators (stmt, NULL_TREE); + expand_stmt_with_iterators_1 (stmt, iter_list); + istack_sublevel_to_current (); +} + + +static void +expand_stmt_with_iterators_1 (stmt, iter_list) + tree stmt, iter_list; +{ + if (iter_list == 0) + expand_expr_stmt (stmt); + else + { + tree current_iterator = TREE_VALUE (iter_list); + tree iter_list_tail = TREE_CHAIN (iter_list); + rtx p_start, p_end, e_start, e_end; + + iterator_loop_prologue (current_iterator, &p_start, &p_end); + expand_stmt_with_iterators_1 (stmt, iter_list_tail); + iterator_loop_epilogue (current_iterator, &e_start, &e_end); + + /** Delete all inner expansions based on current_iterator **/ + /** before adding the outer one. **/ + + delete_ixpansion (current_iterator); + add_ixpansion (current_iterator, p_start, p_end, e_start, e_end); + } +} + + +/* Return a list containing all the free (i.e. not bound by a + containing `for' statement) iterators mentioned in EXP, plus those + in LIST. Do not add duplicate entries to the list. */ + +static tree +collect_iterators (exp, list) + tree exp, list; +{ + if (exp == 0) return list; + + switch (TREE_CODE (exp)) + { + case VAR_DECL: + if (! ITERATOR_P (exp) || ITERATOR_BOUND_P (exp)) + return list; + if (value_member (exp, list)) + return list; + return tree_cons (NULL_TREE, exp, list); + + case TREE_LIST: + { + tree tail; + for (tail = exp; tail; tail = TREE_CHAIN (tail)) + list = collect_iterators (TREE_VALUE (tail), list); + return list; + } + + case SAVE_EXPR: + /* In each scan, scan a given save_expr only once. */ + if (value_member (exp, save_exprs)) + return list; + + save_exprs = tree_cons (NULL_TREE, exp, save_exprs); + return collect_iterators (TREE_OPERAND (exp, 0), list); + + /* we do not automatically iterate blocks -- one must */ + /* use the FOR construct to do that */ + + case BLOCK: + return list; + + default: + switch (TREE_CODE_CLASS (TREE_CODE (exp))) + { + case '1': + return collect_iterators (TREE_OPERAND (exp, 0), list); + + case '2': + case '<': + return collect_iterators (TREE_OPERAND (exp, 0), + collect_iterators (TREE_OPERAND (exp, 1), + list)); + + case 'e': + case 'r': + { + int num_args = tree_code_length[(int) TREE_CODE (exp)]; + int i; + + /* Some tree codes have RTL, not trees, as operands. */ + switch (TREE_CODE (exp)) + { + case CALL_EXPR: + num_args = 2; + break; + case METHOD_CALL_EXPR: + num_args = 3; + break; + case WITH_CLEANUP_EXPR: + num_args = 1; + break; + case RTL_EXPR: + return list; + default: + break; + } + + for (i = 0; i < num_args; i++) + list = collect_iterators (TREE_OPERAND (exp, i), list); + return list; + } + default: + return list; + } + } +} + +/* Emit rtl for the start of a loop for iterator IDECL. + + If necessary, create loop counter rtx and store it as DECL_RTL of IDECL. + + The prologue normally starts and ends with notes, which are returned + by this function in *START_NOTE and *END_NODE. + If START_NOTE and END_NODE are 0, we don't make those notes. */ + +static void +iterator_loop_prologue (idecl, start_note, end_note) + tree idecl; + rtx *start_note, *end_note; +{ + tree expr; + + /* Force the save_expr in DECL_INITIAL to be calculated + if it hasn't been calculated yet. */ + expand_expr (DECL_INITIAL (idecl), const0_rtx, VOIDmode, + EXPAND_NORMAL); + + if (DECL_RTL (idecl) == 0) + expand_decl (idecl); + + if (start_note) + *start_note = emit_note (0, NOTE_INSN_DELETED); + + /* Initialize counter. */ + expr = build (MODIFY_EXPR, TREE_TYPE (idecl), idecl, integer_zero_node); + TREE_SIDE_EFFECTS (expr) = 1; + expand_expr (expr, const0_rtx, VOIDmode, EXPAND_NORMAL); + + expand_start_loop_continue_elsewhere (1); + + ITERATOR_BOUND_P (idecl) = 1; + + if (end_note) + *end_note = emit_note (0, NOTE_INSN_DELETED); +} + +/* Similar to the previous function, but for the end of the loop. + + DECL_RTL is zeroed unless we are inside "({...})". The reason for that is + described below. + + When we create two (or more) loops based on the same IDECL, and + both inside the same "({...})" construct, we must be prepared to + delete both of the loops and create a single one on the level + above, i.e. enclosing the "({...})". The new loop has to use the + same counter rtl because the references to the iterator decl + (IDECL) have already been expanded as references to the counter + rtl. + + It is incorrect to use the same counter reg in different functions, + and it is desirable to use different counters in disjoint loops + when we know there's no need to combine them (because then they can + get allocated separately). */ + +static void +iterator_loop_epilogue (idecl, start_note, end_note) + tree idecl; + rtx *start_note, *end_note; +{ + tree test, incr; + + if (start_note) + *start_note = emit_note (0, NOTE_INSN_DELETED); + expand_loop_continue_here (); + incr = build_binary_op (PLUS_EXPR, idecl, integer_one_node, 0); + incr = build (MODIFY_EXPR, TREE_TYPE (idecl), idecl, incr); + TREE_SIDE_EFFECTS (incr) = 1; + expand_expr (incr, const0_rtx, VOIDmode, EXPAND_NORMAL); + test = build_binary_op (LT_EXPR, idecl, DECL_INITIAL (idecl), 0); + expand_exit_loop_if_false (0, test); + expand_end_loop (); + + ITERATOR_BOUND_P (idecl) = 0; + /* we can reset rtl since there is not chance that this expansion */ + /* would be superseded by a higher level one */ + /* but don't do this if the decl is static, since we need to share */ + /* the same decl in that case. */ + if (top_level_ixpansion_p () && ! TREE_STATIC (idecl)) + DECL_RTL (idecl) = 0; + if (end_note) + *end_note = emit_note (0, NOTE_INSN_DELETED); +} + +/* Return true if we are not currently inside a "({...})" construct. */ + +static int +top_level_ixpansion_p () +{ + return iter_stack == 0; +} + +/* Given two chains of iter_stack_nodes, + append the nodes in X into Y. */ + +static void +isn_append (x, y) + struct iter_stack_node *x, *y; +{ + if (x->first == 0) + return; + + if (y->first == 0) + { + y->first = x->first; + y->last = x->last; + } + else + { + y->last->next = x->first; + y->last = x->last; + } +} + +/** Make X empty **/ + +#define ISN_ZERO(X) (X).first=(X).last=0 + +/* Move the ixpansions in sublevel_ixpansions into the current + node on the iter_stack, or discard them if the iter_stack is empty. + We do this at the end of a statement. */ + +static void +istack_sublevel_to_current () +{ + /* At the top level we can throw away sublevel's expansions **/ + /* because there is nobody above us to ask for a cleanup **/ + if (iter_stack != 0) + /** Merging with empty sublevel list is a no-op **/ + if (sublevel_ixpansions.last) + isn_append (&sublevel_ixpansions, iter_stack); + + if (iter_stack == 0) + obstack_free (&ixp_obstack, ixp_firstobj); + + ISN_ZERO (sublevel_ixpansions); +} + +/* Push a new node on the iter_stack, when we enter a ({...}). */ + +void +push_iterator_stack () +{ + struct iter_stack_node *new_top + = (struct iter_stack_node *) + obstack_alloc (&ixp_obstack, sizeof (struct iter_stack_node)); + + new_top->first = 0; + new_top->last = 0; + new_top->next = iter_stack; + iter_stack = new_top; +} + +/* Pop iter_stack, moving the ixpansions in the node being popped + into sublevel_ixpansions. */ + +void +pop_iterator_stack () +{ + if (iter_stack == 0) + abort (); + + isn_append (iter_stack, &sublevel_ixpansions); + /** Pop current level node: */ + iter_stack = iter_stack->next; +} + + +/* Record an iterator expansion ("ixpansion") for IDECL. + The remaining parameters are the notes in the loop entry + and exit rtl. */ + +static void +add_ixpansion (idecl, pro_start, pro_end, epi_start, epi_end) + tree idecl; + rtx pro_start, pro_end, epi_start, epi_end; +{ + struct ixpansion *newix; + + /* Do nothing if we are not inside "({...})", + as in that case this expansion can't need subsequent RTL modification. */ + if (iter_stack == 0) + return; + + newix = (struct ixpansion *) obstack_alloc (&ixp_obstack, + sizeof (struct ixpansion)); + newix->ixdecl = idecl; + newix->ixprologue_start = pro_start; + newix->ixprologue_end = pro_end; + newix->ixepilogue_start = epi_start; + newix->ixepilogue_end = epi_end; + + newix->next = iter_stack->first; + iter_stack->first = newix; + if (iter_stack->last == 0) + iter_stack->last = newix; +} + +/* Delete the RTL for all ixpansions for iterator IDECL + in our sublevels. We do this when we make a larger + containing expansion for IDECL. */ + +static void +delete_ixpansion (idecl) + tree idecl; +{ + struct ixpansion *previx = 0, *ix; + + for (ix = sublevel_ixpansions.first; ix; ix = ix->next) + if (ix->ixdecl == idecl) + { + /** zero means that this is a mark for FOR -- **/ + /** we do not delete anything, just issue an error. **/ + + if (ix->ixprologue_start == 0) + error_with_decl (idecl, + "`for (%s)' appears within implicit iteration"); + else + { + rtx insn; + /* We delete all insns, including notes because leaving loop */ + /* notes and barriers produced by iterator expansion would */ + /* be misleading to other phases */ + + for (insn = NEXT_INSN (ix->ixprologue_start); + insn != ix->ixprologue_end; + insn = NEXT_INSN (insn)) + delete_insn (insn); + for (insn = NEXT_INSN (ix->ixepilogue_start); + insn != ix->ixepilogue_end; + insn = NEXT_INSN (insn)) + delete_insn (insn); + } + + /* Delete this ixpansion from sublevel_ixpansions. */ + if (previx) + previx->next = ix->next; + else + sublevel_ixpansions.first = ix->next; + if (sublevel_ixpansions.last == ix) + sublevel_ixpansions.last = previx; + } + else + previx = ix; +} + +#ifdef DEBUG_ITERATORS + +/* The functions below are for use from source level debugger. + They print short forms of iterator lists and the iterator stack. */ + +/* Print the name of the iterator D. */ + +void +prdecl (d) + tree d; +{ + if (d) + { + if (TREE_CODE (d) == VAR_DECL) + { + tree tname = DECL_NAME (d); + char *dname = IDENTIFIER_POINTER (tname); + fprintf (stderr, dname); + } + else + fprintf (stderr, "<>"); + } + else + fprintf (stderr, "<>"); +} + +/* Print Iterator List -- names only */ + +tree +pil (head) + tree head; +{ + tree current, next; + for (current = head; current; current = next) + { + tree node = TREE_VALUE (current); + prdecl (node); + next = TREE_CHAIN (current); + if (next) fprintf (stderr, ","); + } + fprintf (stderr, "\n"); +} + +/* Print IXpansion List */ + +struct ixpansion * +pixl (head) + struct ixpansion *head; +{ + struct ixpansion *current, *next; + fprintf (stderr, "> "); + if (head == 0) + fprintf (stderr, "(empty)"); + + for (current=head; current; current = next) + { + tree node = current->ixdecl; + prdecl (node); + next = current->next; + if (next) + fprintf (stderr, ","); + } + fprintf (stderr, "\n"); + return head; +} + +/* Print Iterator Stack. */ + +void +pis () +{ + struct iter_stack_node *stack_node; + + fprintf (stderr, "--SubLevel: "); + pixl (sublevel_ixpansions.first); + fprintf (stderr, "--Stack:--\n"); + for (stack_node = iter_stack; + stack_node; + stack_node = stack_node->next) + pixl (stack_node->first); +} + +#endif /* DEBUG_ITERATORS */ diff --git a/gcc_arm/c-lang.c b/gcc_arm/c-lang.c new file mode 100755 index 0000000..ed2b9e4 --- /dev/null +++ b/gcc_arm/c-lang.c @@ -0,0 +1,213 @@ +/* Language-specific hook definitions for C front end. + Copyright (C) 1991, 1995, 1997, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include "config.h" +#include "system.h" +#include "tree.h" +#include "input.h" +#include "c-tree.h" +#include "c-lex.h" +#include "toplev.h" +#include "output.h" + +#if USE_CPPLIB +#include "cpplib.h" +extern char *yy_cur; +extern cpp_reader parse_in; +extern cpp_options parse_options; +#endif + +/* Each of the functions defined here + is an alternative to a function in objc-actions.c. */ + +int +lang_decode_option (argc, argv) + int argc; + char **argv; +{ + return c_decode_option (argc, argv); +} + +void +lang_init_options () +{ +#if USE_CPPLIB + cpp_reader_init (&parse_in); + parse_in.opts = &parse_options; + cpp_options_init (&parse_options); +#endif +} + +void +lang_init () +{ + /* the beginning of the file is a new line; check for # */ + /* With luck, we discover the real source file's name from that + and put it in input_filename. */ +#if !USE_CPPLIB + ungetc (check_newline (), finput); +#else + check_newline (); + yy_cur--; +#endif +} + +void +lang_finish () +{ +} + +char * +lang_identify () +{ + return "c"; +} + +void +print_lang_statistics () +{ +} + +/* used by print-tree.c */ + +void +lang_print_xnode (file, node, indent) + FILE *file ATTRIBUTE_UNUSED; + tree node ATTRIBUTE_UNUSED; + int indent ATTRIBUTE_UNUSED; +{ +} + +/* Used by c-lex.c, but only for objc. */ + +tree +lookup_interface (arg) + tree arg ATTRIBUTE_UNUSED; +{ + return 0; +} + +tree +is_class_name (arg) + tree arg ATTRIBUTE_UNUSED; +{ + return 0; +} + +void +maybe_objc_check_decl (decl) + tree decl ATTRIBUTE_UNUSED; +{ +} + +int +maybe_objc_comptypes (lhs, rhs, reflexive) + tree lhs ATTRIBUTE_UNUSED; + tree rhs ATTRIBUTE_UNUSED; + int reflexive ATTRIBUTE_UNUSED; +{ + return -1; +} + +tree +maybe_objc_method_name (decl) + tree decl ATTRIBUTE_UNUSED; +{ + return 0; +} + +tree +maybe_building_objc_message_expr () +{ + return 0; +} + +int +recognize_objc_keyword () +{ + return 0; +} + +tree +build_objc_string (len, str) + int len ATTRIBUTE_UNUSED; + char *str ATTRIBUTE_UNUSED; +{ + abort (); + return NULL_TREE; +} + +/* Called at end of parsing, but before end-of-file processing. */ + +void +finish_file () +{ +#ifndef ASM_OUTPUT_CONSTRUCTOR + extern tree static_ctors; +#endif +#ifndef ASM_OUTPUT_DESTRUCTOR + extern tree static_dtors; +#endif + extern tree build_function_call PROTO((tree, tree)); +#if !defined(ASM_OUTPUT_CONSTRUCTOR) || !defined(ASM_OUTPUT_DESTRUCTOR) + tree void_list_node = build_tree_list (NULL_TREE, void_type_node); +#endif +#ifndef ASM_OUTPUT_CONSTRUCTOR + if (static_ctors) + { + tree fnname = get_file_function_name ('I'); + start_function (void_list_node, + build_parse_node (CALL_EXPR, fnname, void_list_node, + NULL_TREE), + NULL_TREE, NULL_TREE, 0); + fnname = DECL_ASSEMBLER_NAME (current_function_decl); + store_parm_decls (); + + for (; static_ctors; static_ctors = TREE_CHAIN (static_ctors)) + expand_expr_stmt (build_function_call (TREE_VALUE (static_ctors), + NULL_TREE)); + + finish_function (0); + + assemble_constructor (IDENTIFIER_POINTER (fnname)); + } +#endif +#ifndef ASM_OUTPUT_DESTRUCTOR + if (static_dtors) + { + tree fnname = get_file_function_name ('D'); + start_function (void_list_node, + build_parse_node (CALL_EXPR, fnname, void_list_node, + NULL_TREE), + NULL_TREE, NULL_TREE, 0); + fnname = DECL_ASSEMBLER_NAME (current_function_decl); + store_parm_decls (); + + for (; static_dtors; static_dtors = TREE_CHAIN (static_dtors)) + expand_expr_stmt (build_function_call (TREE_VALUE (static_dtors), + NULL_TREE)); + + finish_function (0); + + assemble_destructor (IDENTIFIER_POINTER (fnname)); + } +#endif +} diff --git a/gcc_arm/c-lex.c b/gcc_arm/c-lex.c new file mode 100755 index 0000000..1b44817 --- /dev/null +++ b/gcc_arm/c-lex.c @@ -0,0 +1,2312 @@ +/* Lexical analyzer for C and Objective C. + Copyright (C) 1987, 88, 89, 92, 94-97, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include + +#include "rtl.h" +#include "tree.h" +#include "input.h" +#include "output.h" +#include "c-lex.h" +#include "c-tree.h" +#include "flags.h" +#include "c-parse.h" +#include "c-pragma.h" +#include "toplev.h" + +#ifdef MULTIBYTE_CHARS +#include "mbchar.h" +#include +#endif /* MULTIBYTE_CHARS */ + +#if USE_CPPLIB +#include "cpplib.h" +extern cpp_reader parse_in; +extern cpp_options parse_options; +#else +/* Stream for reading from the input file. */ +FILE *finput; +#endif + +extern void yyprint PROTO((FILE *, int, YYSTYPE)); + +/* The elements of `ridpointers' are identifier nodes + for the reserved type names and storage classes. + It is indexed by a RID_... value. */ +tree ridpointers[(int) RID_MAX]; + +/* Cause the `yydebug' variable to be defined. */ +#define YYDEBUG 1 + +#if USE_CPPLIB +extern unsigned char *yy_cur, *yy_lim; + +extern int yy_get_token (); + +#define GETC() (yy_cur < yy_lim ? *yy_cur++ : yy_get_token ()) +#define UNGETC(c) ((void)(c), yy_cur--) +#else +#define GETC() getc (finput) +#define UNGETC(c) ungetc (c, finput) +#endif + +/* the declaration found for the last IDENTIFIER token read in. + yylex must look this up to detect typedefs, which get token type TYPENAME, + so it is left around in case the identifier is not a typedef but is + used in a context which makes it a reference to a variable. */ +tree lastiddecl; + +/* Nonzero enables objc features. */ + +int doing_objc_thang; + +extern int yydebug; + +/* File used for outputting assembler code. */ +extern FILE *asm_out_file; + +#ifndef WCHAR_TYPE_SIZE +#ifdef INT_TYPE_SIZE +#define WCHAR_TYPE_SIZE INT_TYPE_SIZE +#else +#define WCHAR_TYPE_SIZE BITS_PER_WORD +#endif +#endif + +/* Number of bytes in a wide character. */ +#define WCHAR_BYTES (WCHAR_TYPE_SIZE / BITS_PER_UNIT) + +static int maxtoken; /* Current nominal length of token buffer. */ +char *token_buffer; /* Pointer to token buffer. + Actual allocated length is maxtoken + 2. + This is not static because objc-parse.y uses it. */ + +static int indent_level = 0; /* Number of { minus number of }. */ + +/* Nonzero if end-of-file has been seen on input. */ +static int end_of_file; + +#if !USE_CPPLIB +/* Buffered-back input character; faster than using ungetc. */ +static int nextchar = -1; +#endif + +#ifdef HANDLE_GENERIC_PRAGMAS +static int handle_generic_pragma PROTO((int)); +#endif /* HANDLE_GENERIC_PRAGMAS */ +static int whitespace_cr PROTO((int)); +static int skip_white_space PROTO((int)); +static int skip_white_space_on_line PROTO((void)); +static char *extend_token_buffer PROTO((char *)); +static int readescape PROTO((int *)); + +/* Do not insert generated code into the source, instead, include it. + This allows us to build gcc automatically even for targets that + need to add or modify the reserved keyword lists. */ +#include "c-gperf.h" + +/* Return something to represent absolute declarators containing a *. + TARGET is the absolute declarator that the * contains. + TYPE_QUALS is a list of modifiers such as const or volatile + to apply to the pointer type, represented as identifiers. + + We return an INDIRECT_REF whose "contents" are TARGET + and whose type is the modifier list. */ + +tree +make_pointer_declarator (type_quals, target) + tree type_quals, target; +{ + return build1 (INDIRECT_REF, type_quals, target); +} + +void +forget_protocol_qualifiers () +{ + int i, n = sizeof wordlist / sizeof (struct resword); + + for (i = 0; i < n; i++) + if ((int) wordlist[i].rid >= (int) RID_IN + && (int) wordlist[i].rid <= (int) RID_ONEWAY) + wordlist[i].name = ""; +} + +void +remember_protocol_qualifiers () +{ + int i, n = sizeof wordlist / sizeof (struct resword); + + for (i = 0; i < n; i++) + if (wordlist[i].rid == RID_IN) + wordlist[i].name = "in"; + else if (wordlist[i].rid == RID_OUT) + wordlist[i].name = "out"; + else if (wordlist[i].rid == RID_INOUT) + wordlist[i].name = "inout"; + else if (wordlist[i].rid == RID_BYCOPY) + wordlist[i].name = "bycopy"; + else if (wordlist[i].rid == RID_BYREF) + wordlist[i].name = "byref"; + else if (wordlist[i].rid == RID_ONEWAY) + wordlist[i].name = "oneway"; +} + +char * +init_parse (filename) + char *filename; +{ +#if !USE_CPPLIB + /* Open input file. */ + if (filename == 0 || !strcmp (filename, "-")) + { + finput = stdin; + filename = "stdin"; + } + else + finput = fopen (filename, "r"); + if (finput == 0) + pfatal_with_name (filename); + +#ifdef IO_BUFFER_SIZE + setvbuf (finput, (char *) xmalloc (IO_BUFFER_SIZE), _IOFBF, IO_BUFFER_SIZE); +#endif +#else /* !USE_CPPLIB */ + parse_in.show_column = 1; + if (! cpp_start_read (&parse_in, filename)) + abort (); + + if (filename == 0 || !strcmp (filename, "-")) + filename = "stdin"; + + /* cpp_start_read always puts at least one line directive into the + token buffer. We must arrange to read it out here. */ + yy_cur = parse_in.token_buffer; + yy_lim = CPP_PWRITTEN (&parse_in); +#endif + + init_lex (); + + return filename; +} + +void +finish_parse () +{ +#if USE_CPPLIB + cpp_finish (&parse_in); +#else + fclose (finput); +#endif +} + +void +init_lex () +{ + /* Make identifier nodes long enough for the language-specific slots. */ + set_identifier_size (sizeof (struct lang_identifier)); + + /* Start it at 0, because check_newline is called at the very beginning + and will increment it to 1. */ + lineno = 0; + +#ifdef MULTIBYTE_CHARS + /* Change to the native locale for multibyte conversions. */ + setlocale (LC_CTYPE, ""); + literal_codeset = getenv ("LANG"); +#endif + + maxtoken = 40; + token_buffer = (char *) xmalloc (maxtoken + 2); + + ridpointers[(int) RID_INT] = get_identifier ("int"); + ridpointers[(int) RID_CHAR] = get_identifier ("char"); + ridpointers[(int) RID_VOID] = get_identifier ("void"); + ridpointers[(int) RID_FLOAT] = get_identifier ("float"); + ridpointers[(int) RID_DOUBLE] = get_identifier ("double"); + ridpointers[(int) RID_SHORT] = get_identifier ("short"); + ridpointers[(int) RID_LONG] = get_identifier ("long"); + ridpointers[(int) RID_UNSIGNED] = get_identifier ("unsigned"); + ridpointers[(int) RID_SIGNED] = get_identifier ("signed"); + ridpointers[(int) RID_INLINE] = get_identifier ("inline"); + ridpointers[(int) RID_CONST] = get_identifier ("const"); + ridpointers[(int) RID_RESTRICT] = get_identifier ("restrict"); + ridpointers[(int) RID_VOLATILE] = get_identifier ("volatile"); + ridpointers[(int) RID_AUTO] = get_identifier ("auto"); + ridpointers[(int) RID_STATIC] = get_identifier ("static"); + ridpointers[(int) RID_EXTERN] = get_identifier ("extern"); + ridpointers[(int) RID_TYPEDEF] = get_identifier ("typedef"); + ridpointers[(int) RID_REGISTER] = get_identifier ("register"); + ridpointers[(int) RID_ITERATOR] = get_identifier ("iterator"); + ridpointers[(int) RID_COMPLEX] = get_identifier ("complex"); + ridpointers[(int) RID_ID] = get_identifier ("id"); + ridpointers[(int) RID_IN] = get_identifier ("in"); + ridpointers[(int) RID_OUT] = get_identifier ("out"); + ridpointers[(int) RID_INOUT] = get_identifier ("inout"); + ridpointers[(int) RID_BYCOPY] = get_identifier ("bycopy"); + ridpointers[(int) RID_BYREF] = get_identifier ("byref"); + ridpointers[(int) RID_ONEWAY] = get_identifier ("oneway"); + forget_protocol_qualifiers(); + + /* Some options inhibit certain reserved words. + Clear those words out of the hash table so they won't be recognized. */ +#define UNSET_RESERVED_WORD(STRING) \ + do { struct resword *s = is_reserved_word (STRING, sizeof (STRING) - 1); \ + if (s) s->name = ""; } while (0) + + if (! doing_objc_thang) + UNSET_RESERVED_WORD ("id"); + + if (flag_traditional) + { + UNSET_RESERVED_WORD ("const"); + UNSET_RESERVED_WORD ("restrict"); + UNSET_RESERVED_WORD ("volatile"); + UNSET_RESERVED_WORD ("typeof"); + UNSET_RESERVED_WORD ("signed"); + UNSET_RESERVED_WORD ("inline"); + UNSET_RESERVED_WORD ("iterator"); + UNSET_RESERVED_WORD ("complex"); + } + else if (!flag_isoc9x) + UNSET_RESERVED_WORD ("restrict"); + + if (flag_no_asm) + { + UNSET_RESERVED_WORD ("asm"); + UNSET_RESERVED_WORD ("typeof"); + UNSET_RESERVED_WORD ("inline"); + UNSET_RESERVED_WORD ("iterator"); + UNSET_RESERVED_WORD ("complex"); + } +} + +void +reinit_parse_for_function () +{ +} + +/* Function used when yydebug is set, to print a token in more detail. */ + +void +yyprint (file, yychar, yylval) + FILE *file; + int yychar; + YYSTYPE yylval; +{ + tree t; + switch (yychar) + { + case IDENTIFIER: + case TYPENAME: + case OBJECTNAME: + t = yylval.ttype; + if (IDENTIFIER_POINTER (t)) + fprintf (file, " `%s'", IDENTIFIER_POINTER (t)); + break; + + case CONSTANT: + t = yylval.ttype; + if (TREE_CODE (t) == INTEGER_CST) + fprintf (file, +#if HOST_BITS_PER_WIDE_INT == 64 +#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT + " 0x%x%016x", +#else +#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG + " 0x%lx%016lx", +#else + " 0x%llx%016llx", +#endif +#endif +#else +#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT + " 0x%lx%08lx", +#else + " 0x%x%08x", +#endif +#endif + TREE_INT_CST_HIGH (t), TREE_INT_CST_LOW (t)); + break; + } +} + +/* Iff C is a carriage return, warn about it - if appropriate - + and return nonzero. */ +static int +whitespace_cr (c) + int c; +{ + static int newline_warning = 0; + + if (c == '\r') + { + /* ANSI C says the effects of a carriage return in a source file + are undefined. */ + if (pedantic && !newline_warning) + { + warning ("carriage return in source file"); + warning ("(we only warn about the first carriage return)"); + newline_warning = 1; + } + return 1; + } + return 0; +} + +/* If C is not whitespace, return C. + Otherwise skip whitespace and return first nonwhite char read. */ + +static int +skip_white_space (c) + register int c; +{ + for (;;) + { + switch (c) + { + /* We don't recognize comments here, because + cpp output can include / and * consecutively as operators. + Also, there's no need, since cpp removes all comments. */ + + case '\n': + c = check_newline (); + break; + + case ' ': + case '\t': + case '\f': + case '\v': + case '\b': + c = GETC(); + break; + + case '\r': + whitespace_cr (c); + c = GETC(); + break; + + case '\\': + c = GETC(); + if (c == '\n') + lineno++; + else + error ("stray '\\' in program"); + c = GETC(); + break; + + default: + return (c); + } + } +} + +/* Skips all of the white space at the current location in the input file. + Must use and reset nextchar if it has the next character. */ + +void +position_after_white_space () +{ + register int c; + +#if !USE_CPPLIB + if (nextchar != -1) + c = nextchar, nextchar = -1; + else +#endif + c = GETC(); + + UNGETC (skip_white_space (c)); +} + +/* Like skip_white_space, but don't advance beyond the end of line. + Moreover, we don't get passed a character to start with. */ +static int +skip_white_space_on_line () +{ + register int c; + + while (1) + { + c = GETC(); + switch (c) + { + case '\n': + default: + break; + + case ' ': + case '\t': + case '\f': + case '\v': + case '\b': + continue; + + case '\r': + whitespace_cr (c); + continue; + } + break; + } + return c; +} + +/* Make the token buffer longer, preserving the data in it. + P should point to just beyond the last valid character in the old buffer. + The value we return is a pointer to the new buffer + at a place corresponding to P. */ + +static char * +extend_token_buffer (p) + char *p; +{ + int offset = p - token_buffer; + + maxtoken = maxtoken * 2 + 10; + token_buffer = (char *) xrealloc (token_buffer, maxtoken + 2); + + return token_buffer + offset; +} + +#if defined HANDLE_PRAGMA +/* Local versions of these macros, that can be passed as function pointers. */ +static int +pragma_getc () +{ + return GETC(); +} + +static void +pragma_ungetc (arg) + int arg; +{ + UNGETC (arg); +} +#endif + +/* At the beginning of a line, increment the line number + and process any #-directive on this line. + If the line is a #-directive, read the entire line and return a newline. + Otherwise, return the line's first non-whitespace character. */ + +int +check_newline () +{ + register int c; + register int token; + + lineno++; + + /* Read first nonwhite char on the line. */ + + c = GETC(); + while (c == ' ' || c == '\t') + c = GETC(); + + if (c != '#') + { + /* If not #, return it so caller will use it. */ + return c; + } + + /* Read first nonwhite char after the `#'. */ + + c = GETC(); + while (c == ' ' || c == '\t') + c = GETC(); + + /* If a letter follows, then if the word here is `line', skip + it and ignore it; otherwise, ignore the line, with an error + if the word isn't `pragma', `ident', `define', or `undef'. */ + + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) + { + if (c == 'p') + { + if (GETC() == 'r' + && GETC() == 'a' + && GETC() == 'g' + && GETC() == 'm' + && GETC() == 'a' + && ((c = GETC()) == ' ' || c == '\t' || c == '\n' + || whitespace_cr (c) )) + { + while (c == ' ' || c == '\t' || whitespace_cr (c)) + c = GETC (); + if (c == '\n') + return c; + +#if defined HANDLE_PRAGMA || defined HANDLE_GENERIC_PRAGMAS + UNGETC (c); + token = yylex (); + if (token != IDENTIFIER) + goto skipline; +#endif /* HANDLE_PRAGMA || HANDLE_GENERIC_PRAGMAS */ + +#ifdef HANDLE_PRAGMA + /* We invoke HANDLE_PRAGMA before HANDLE_GENERIC_PRAGMAS (if + both are defined), in order to give the back end a chance to + override the interpretation of generic style pragmas. */ +#if !USE_CPPLIB + if (nextchar >= 0) + { + c = nextchar, nextchar = -1; + UNGETC (c); + } +#endif /* !USE_CPPLIB */ + + if (TREE_CODE (yylval.ttype) != IDENTIFIER_NODE) + goto skipline; + + if (HANDLE_PRAGMA (pragma_getc, pragma_ungetc, + IDENTIFIER_POINTER (yylval.ttype))) + return GETC (); +#endif /* HANDLE_PRAGMA */ + +#ifdef HANDLE_GENERIC_PRAGMAS + if (handle_generic_pragma (token)) + return GETC (); +#endif /* HANDLE_GENERIC_PRAGMAS */ + + /* Issue a warning message if we have been asked to do so. + Ignoring unknown pragmas in system header file unless + an explcit -Wunknown-pragmas has been given. */ + if (warn_unknown_pragmas > 1 + || (warn_unknown_pragmas && ! in_system_header)) + warning ("ignoring pragma: %s", token_buffer); + + goto skipline; + } + } + + else if (c == 'd') + { + if (GETC() == 'e' + && GETC() == 'f' + && GETC() == 'i' + && GETC() == 'n' + && GETC() == 'e' + && ((c = GETC()) == ' ' || c == '\t' || c == '\n')) + { + if (c != '\n') + debug_define (lineno, GET_DIRECTIVE_LINE ()); + goto skipline; + } + } + else if (c == 'u') + { + if (GETC() == 'n' + && GETC() == 'd' + && GETC() == 'e' + && GETC() == 'f' + && ((c = GETC()) == ' ' || c == '\t' || c == '\n')) + { + if (c != '\n') + debug_undef (lineno, GET_DIRECTIVE_LINE ()); + goto skipline; + } + } + else if (c == 'l') + { + if (GETC() == 'i' + && GETC() == 'n' + && GETC() == 'e' + && ((c = GETC()) == ' ' || c == '\t')) + goto linenum; + } + else if (c == 'i') + { + if (GETC() == 'd' + && GETC() == 'e' + && GETC() == 'n' + && GETC() == 't' + && ((c = GETC()) == ' ' || c == '\t')) + { + /* #ident. The pedantic warning is now in cccp.c. */ + + /* Here we have just seen `#ident '. + A string constant should follow. */ + + c = skip_white_space_on_line (); + + /* If no argument, ignore the line. */ + if (c == '\n') + return c; + + UNGETC (c); + token = yylex (); + if (token != STRING + || TREE_CODE (yylval.ttype) != STRING_CST) + { + error ("invalid #ident"); + goto skipline; + } + + if (!flag_no_ident) + { +#ifdef ASM_OUTPUT_IDENT + ASM_OUTPUT_IDENT (asm_out_file, TREE_STRING_POINTER (yylval.ttype)); +#endif + } + + /* Skip the rest of this line. */ + goto skipline; + } + } + + error ("undefined or invalid # directive"); + goto skipline; + } + +linenum: + /* Here we have either `#line' or `# '. + In either case, it should be a line number; a digit should follow. */ + + /* Can't use skip_white_space here, but must handle all whitespace + that is not '\n', lest we get a recursion for '\r' '\n' when + calling yylex. */ + UNGETC (c); + c = skip_white_space_on_line (); + + /* If the # is the only nonwhite char on the line, + just ignore it. Check the new newline. */ + if (c == '\n') + return c; + + /* Something follows the #; read a token. */ + + UNGETC (c); + token = yylex (); + + if (token == CONSTANT + && TREE_CODE (yylval.ttype) == INTEGER_CST) + { + int old_lineno = lineno; + int used_up = 0; + /* subtract one, because it is the following line that + gets the specified number */ + + int l = TREE_INT_CST_LOW (yylval.ttype) - 1; + + /* Is this the last nonwhite stuff on the line? */ + c = skip_white_space_on_line (); + if (c == '\n') + { + /* No more: store the line number and check following line. */ + lineno = l; + return c; + } + UNGETC (c); + + /* More follows: it must be a string constant (filename). */ + + /* Read the string constant. */ + token = yylex (); + + if (token != STRING || TREE_CODE (yylval.ttype) != STRING_CST) + { + error ("invalid #line"); + goto skipline; + } + + input_filename + = (char *) permalloc (TREE_STRING_LENGTH (yylval.ttype) + 1); + strcpy (input_filename, TREE_STRING_POINTER (yylval.ttype)); + lineno = l; + + /* Each change of file name + reinitializes whether we are now in a system header. */ + in_system_header = 0; + + if (main_input_filename == 0) + main_input_filename = input_filename; + + /* Is this the last nonwhite stuff on the line? */ + c = skip_white_space_on_line (); + if (c == '\n') + { + /* Update the name in the top element of input_file_stack. */ + if (input_file_stack) + input_file_stack->name = input_filename; + + return c; + } + UNGETC (c); + + token = yylex (); + used_up = 0; + + /* `1' after file name means entering new file. + `2' after file name means just left a file. */ + + if (token == CONSTANT + && TREE_CODE (yylval.ttype) == INTEGER_CST) + { + if (TREE_INT_CST_LOW (yylval.ttype) == 1) + { + /* Pushing to a new file. */ + struct file_stack *p + = (struct file_stack *) xmalloc (sizeof (struct file_stack)); + input_file_stack->line = old_lineno; + p->next = input_file_stack; + p->name = input_filename; + p->indent_level = indent_level; + input_file_stack = p; + input_file_stack_tick++; + debug_start_source_file (input_filename); + used_up = 1; + } + else if (TREE_INT_CST_LOW (yylval.ttype) == 2) + { + /* Popping out of a file. */ + if (input_file_stack->next) + { + struct file_stack *p = input_file_stack; + if (indent_level != p->indent_level) + { + warning_with_file_and_line + (p->name, old_lineno, + "This file contains more `%c's than `%c's.", + indent_level > p->indent_level ? '{' : '}', + indent_level > p->indent_level ? '}' : '{'); + } + input_file_stack = p->next; + free (p); + input_file_stack_tick++; + debug_end_source_file (input_file_stack->line); + } + else + error ("#-lines for entering and leaving files don't match"); + + used_up = 1; + } + } + + /* Now that we've pushed or popped the input stack, + update the name in the top element. */ + if (input_file_stack) + input_file_stack->name = input_filename; + + /* If we have handled a `1' or a `2', + see if there is another number to read. */ + if (used_up) + { + /* Is this the last nonwhite stuff on the line? */ + c = skip_white_space_on_line (); + if (c == '\n') + return c; + UNGETC (c); + + token = yylex (); + used_up = 0; + } + + /* `3' after file name means this is a system header file. */ + + if (token == CONSTANT + && TREE_CODE (yylval.ttype) == INTEGER_CST + && TREE_INT_CST_LOW (yylval.ttype) == 3) + in_system_header = 1, used_up = 1; + + if (used_up) + { + /* Is this the last nonwhite stuff on the line? */ + c = skip_white_space_on_line (); + if (c == '\n') + return c; + UNGETC (c); + } + + warning ("unrecognized text at end of #line"); + } + else + error ("invalid #-line"); + + /* skip the rest of this line. */ + skipline: +#if !USE_CPPLIB + if (c != '\n' && c != EOF && nextchar >= 0) + c = nextchar, nextchar = -1; +#endif + while (c != '\n' && c != EOF) + c = GETC(); + return c; +} + +#ifdef HANDLE_GENERIC_PRAGMAS + +/* Handle a #pragma directive. + TOKEN is the token we read after `#pragma'. Processes the entire input + line and return non-zero iff the pragma has been successfully parsed. */ + +/* This function has to be in this file, in order to get at + the token types. */ + +static int +handle_generic_pragma (token) + register int token; +{ + register int c; + + for (;;) + { + switch (token) + { + case IDENTIFIER: + case TYPENAME: + case STRING: + case CONSTANT: + handle_pragma_token (token_buffer, yylval.ttype); + break; + default: + handle_pragma_token (token_buffer, NULL); + } +#if !USE_CPPLIB + if (nextchar >= 0) + c = nextchar, nextchar = -1; + else +#endif + c = GETC (); + + while (c == ' ' || c == '\t') + c = GETC (); + UNGETC (c); + + if (c == '\n' || c == EOF) + return handle_pragma_token (NULL, NULL); + + token = yylex (); + } +} + +#endif /* HANDLE_GENERIC_PRAGMAS */ + +#define ENDFILE -1 /* token that represents end-of-file */ + +/* Read an escape sequence, returning its equivalent as a character, + or store 1 in *ignore_ptr if it is backslash-newline. */ + +static int +readescape (ignore_ptr) + int *ignore_ptr; +{ + register int c = GETC(); + register int code; + register unsigned count; + unsigned firstdig = 0; + int nonnull; + + switch (c) + { + case 'x': + if (warn_traditional) + warning ("the meaning of `\\x' varies with -traditional"); + + if (flag_traditional) + return c; + + code = 0; + count = 0; + nonnull = 0; + while (1) + { + c = GETC(); + if (!(c >= 'a' && c <= 'f') + && !(c >= 'A' && c <= 'F') + && !(c >= '0' && c <= '9')) + { + UNGETC (c); + break; + } + code *= 16; + if (c >= 'a' && c <= 'f') + code += c - 'a' + 10; + if (c >= 'A' && c <= 'F') + code += c - 'A' + 10; + if (c >= '0' && c <= '9') + code += c - '0'; + if (code != 0 || count != 0) + { + if (count == 0) + firstdig = code; + count++; + } + nonnull = 1; + } + if (! nonnull) + error ("\\x used with no following hex digits"); + else if (count == 0) + /* Digits are all 0's. Ok. */ + ; + else if ((count - 1) * 4 >= TYPE_PRECISION (integer_type_node) + || (count > 1 + && (((unsigned)1 << (TYPE_PRECISION (integer_type_node) - (count - 1) * 4)) + <= firstdig))) + pedwarn ("hex escape out of range"); + return code; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': + code = 0; + count = 0; + while ((c <= '7') && (c >= '0') && (count++ < 3)) + { + code = (code * 8) + (c - '0'); + c = GETC(); + } + UNGETC (c); + return code; + + case '\\': case '\'': case '"': + return c; + + case '\n': + lineno++; + *ignore_ptr = 1; + return 0; + + case 'n': + return TARGET_NEWLINE; + + case 't': + return TARGET_TAB; + + case 'r': + return TARGET_CR; + + case 'f': + return TARGET_FF; + + case 'b': + return TARGET_BS; + + case 'a': + if (warn_traditional) + warning ("the meaning of `\\a' varies with -traditional"); + + if (flag_traditional) + return c; + return TARGET_BELL; + + case 'v': +#if 0 /* Vertical tab is present in common usage compilers. */ + if (flag_traditional) + return c; +#endif + return TARGET_VT; + + case 'e': + case 'E': + if (pedantic) + pedwarn ("non-ANSI-standard escape sequence, `\\%c'", c); + return 033; + + case '?': + return c; + + /* `\(', etc, are used at beginning of line to avoid confusing Emacs. */ + case '(': + case '{': + case '[': + /* `\%' is used to prevent SCCS from getting confused. */ + case '%': + if (pedantic) + pedwarn ("non-ANSI escape sequence `\\%c'", c); + return c; + } + if (c >= 040 && c < 0177) + pedwarn ("unknown escape sequence `\\%c'", c); + else + pedwarn ("unknown escape sequence: `\\' followed by char code 0x%x", c); + return c; +} + +void +yyerror (string) + char *string; +{ + char buf[200]; + + strcpy (buf, string); + + /* We can't print string and character constants well + because the token_buffer contains the result of processing escapes. */ + if (end_of_file) + strcat (buf, " at end of input"); + else if (token_buffer[0] == 0) + strcat (buf, " at null character"); + else if (token_buffer[0] == '"') + strcat (buf, " before string constant"); + else if (token_buffer[0] == '\'') + strcat (buf, " before character constant"); + else if (token_buffer[0] < 040 || (unsigned char) token_buffer[0] >= 0177) + sprintf (buf + strlen (buf), " before character 0%o", + (unsigned char) token_buffer[0]); + else + strcat (buf, " before `%s'"); + + error (buf, token_buffer); +} + +#if 0 + +struct try_type +{ + tree *node_var; + char unsigned_flag; + char long_flag; + char long_long_flag; +}; + +struct try_type type_sequence[] = +{ + { &integer_type_node, 0, 0, 0}, + { &unsigned_type_node, 1, 0, 0}, + { &long_integer_type_node, 0, 1, 0}, + { &long_unsigned_type_node, 1, 1, 0}, + { &long_long_integer_type_node, 0, 1, 1}, + { &long_long_unsigned_type_node, 1, 1, 1} +}; +#endif /* 0 */ + +int +yylex () +{ + register int c; + register char *p; + register int value; + int wide_flag = 0; + int objc_flag = 0; + +#if !USE_CPPLIB + if (nextchar >= 0) + c = nextchar, nextchar = -1; + else +#endif + c = GETC(); + + /* Effectively do c = skip_white_space (c) + but do it faster in the usual cases. */ + while (1) + switch (c) + { + case ' ': + case '\t': + case '\f': + case '\v': + case '\b': + c = GETC(); + break; + + case '\r': + /* Call skip_white_space so we can warn if appropriate. */ + + case '\n': + case '/': + case '\\': + c = skip_white_space (c); + default: + goto found_nonwhite; + } + found_nonwhite: + + token_buffer[0] = c; + token_buffer[1] = 0; + +/* yylloc.first_line = lineno; */ + + switch (c) + { + case EOF: + end_of_file = 1; + token_buffer[0] = 0; + value = ENDFILE; + break; + + case 'L': + /* Capital L may start a wide-string or wide-character constant. */ + { + register int c = GETC(); + if (c == '\'') + { + wide_flag = 1; + goto char_constant; + } + if (c == '"') + { + wide_flag = 1; + goto string_constant; + } + UNGETC (c); + } + goto letter; + + case '@': + if (!doing_objc_thang) + { + value = c; + break; + } + else + { + /* '@' may start a constant string object. */ + register int c = GETC (); + if (c == '"') + { + objc_flag = 1; + goto string_constant; + } + UNGETC (c); + /* Fall through to treat '@' as the start of an identifier. */ + } + + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': + case 'Z': + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'o': + case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': + case 'z': + case '_': + case '$': + letter: + p = token_buffer; + while (ISALNUM (c) || c == '_' || c == '$' || c == '@') + { + /* Make sure this char really belongs in an identifier. */ + if (c == '@' && ! doing_objc_thang) + break; + if (c == '$') + { + if (! dollars_in_ident) + error ("`$' in identifier"); + else if (pedantic) + pedwarn ("`$' in identifier"); + } + + if (p >= token_buffer + maxtoken) + p = extend_token_buffer (p); + + *p++ = c; + c = GETC(); + } + + *p = 0; +#if USE_CPPLIB + UNGETC (c); +#else + nextchar = c; +#endif + + value = IDENTIFIER; + yylval.itype = 0; + + /* Try to recognize a keyword. Uses minimum-perfect hash function */ + + { + register struct resword *ptr; + + if ((ptr = is_reserved_word (token_buffer, p - token_buffer))) + { + if (ptr->rid) + yylval.ttype = ridpointers[(int) ptr->rid]; + value = (int) ptr->token; + + /* Only return OBJECTNAME if it is a typedef. */ + if (doing_objc_thang && value == OBJECTNAME) + { + lastiddecl = lookup_name(yylval.ttype); + + if (lastiddecl == NULL_TREE + || TREE_CODE (lastiddecl) != TYPE_DECL) + value = IDENTIFIER; + } + + /* Even if we decided to recognize asm, still perhaps warn. */ + if (pedantic + && (value == ASM_KEYWORD || value == TYPEOF + || ptr->rid == RID_INLINE) + && token_buffer[0] != '_') + pedwarn ("ANSI does not permit the keyword `%s'", + token_buffer); + } + } + + /* If we did not find a keyword, look for an identifier + (or a typename). */ + + if (value == IDENTIFIER) + { + if (token_buffer[0] == '@') + error("invalid identifier `%s'", token_buffer); + + yylval.ttype = get_identifier (token_buffer); + lastiddecl = lookup_name (yylval.ttype); + + if (lastiddecl != 0 && TREE_CODE (lastiddecl) == TYPE_DECL) + value = TYPENAME; + /* A user-invisible read-only initialized variable + should be replaced by its value. + We handle only strings since that's the only case used in C. */ + else if (lastiddecl != 0 && TREE_CODE (lastiddecl) == VAR_DECL + && DECL_IGNORED_P (lastiddecl) + && TREE_READONLY (lastiddecl) + && DECL_INITIAL (lastiddecl) != 0 + && TREE_CODE (DECL_INITIAL (lastiddecl)) == STRING_CST) + { + tree stringval = DECL_INITIAL (lastiddecl); + + /* Copy the string value so that we won't clobber anything + if we put something in the TREE_CHAIN of this one. */ + yylval.ttype = build_string (TREE_STRING_LENGTH (stringval), + TREE_STRING_POINTER (stringval)); + value = STRING; + } + else if (doing_objc_thang) + { + tree objc_interface_decl = is_class_name (yylval.ttype); + + if (objc_interface_decl) + { + value = CLASSNAME; + yylval.ttype = objc_interface_decl; + } + } + } + + break; + + case '0': case '1': + { + int next_c; + /* Check first for common special case: single-digit 0 or 1. */ + + next_c = GETC (); + UNGETC (next_c); /* Always undo this lookahead. */ + if (!ISALNUM (next_c) && next_c != '.') + { + token_buffer[0] = (char)c, token_buffer[1] = '\0'; + yylval.ttype = (c == '0') ? integer_zero_node : integer_one_node; + value = CONSTANT; + break; + } + /*FALLTHRU*/ + } + case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '.': + { + int base = 10; + int count = 0; + int largest_digit = 0; + int numdigits = 0; + /* for multi-precision arithmetic, + we actually store only HOST_BITS_PER_CHAR bits in each part. + The number of parts is chosen so as to be sufficient to hold + the enough bits to fit into the two HOST_WIDE_INTs that contain + the integer value (this is always at least as many bits as are + in a target `long long' value, but may be wider). */ +#define TOTAL_PARTS ((HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR) * 2 + 2) + int parts[TOTAL_PARTS]; + int overflow = 0; + + enum anon1 { NOT_FLOAT, AFTER_POINT, TOO_MANY_POINTS, AFTER_EXPON} + floatflag = NOT_FLOAT; + + for (count = 0; count < TOTAL_PARTS; count++) + parts[count] = 0; + + p = token_buffer; + *p++ = c; + + if (c == '0') + { + *p++ = (c = GETC()); + if ((c == 'x') || (c == 'X')) + { + base = 16; + *p++ = (c = GETC()); + } + /* Leading 0 forces octal unless the 0 is the only digit. */ + else if (c >= '0' && c <= '9') + { + base = 8; + numdigits++; + } + else + numdigits++; + } + + /* Read all the digits-and-decimal-points. */ + + while (c == '.' + || (ISALNUM (c) && c != 'l' && c != 'L' + && c != 'u' && c != 'U' + && c != 'i' && c != 'I' && c != 'j' && c != 'J' + && (floatflag == NOT_FLOAT || ((c != 'f') && (c != 'F'))))) + { + if (c == '.') + { + if (base == 16 && pedantic) + error ("floating constant may not be in radix 16"); + if (floatflag == TOO_MANY_POINTS) + /* We have already emitted an error. Don't need another. */ + ; + else if (floatflag == AFTER_POINT || floatflag == AFTER_EXPON) + { + error ("malformed floating constant"); + floatflag = TOO_MANY_POINTS; + /* Avoid another error from atof by forcing all characters + from here on to be ignored. */ + p[-1] = '\0'; + } + else + floatflag = AFTER_POINT; + + if (base == 8) + base = 10; + *p++ = c = GETC(); + /* Accept '.' as the start of a floating-point number + only when it is followed by a digit. + Otherwise, unread the following non-digit + and use the '.' as a structural token. */ + if (p == token_buffer + 2 && !ISDIGIT (c)) + { + if (c == '.') + { + c = GETC(); + if (c == '.') + { + *p++ = c; + *p = 0; + return ELLIPSIS; + } + error ("parse error at `..'"); + } + UNGETC (c); + token_buffer[1] = 0; + value = '.'; + goto done; + } + } + else + { + /* It is not a decimal point. + It should be a digit (perhaps a hex digit). */ + + if (ISDIGIT (c)) + { + c = c - '0'; + } + else if (base <= 10) + { + if (c == 'e' || c == 'E') + { + base = 10; + floatflag = AFTER_EXPON; + break; /* start of exponent */ + } + error ("nondigits in number and not hexadecimal"); + c = 0; + } + else if (base == 16 && (c == 'p' || c == 'P')) + { + floatflag = AFTER_EXPON; + break; /* start of exponent */ + } + else if (c >= 'a') + { + c = c - 'a' + 10; + } + else + { + c = c - 'A' + 10; + } + if (c >= largest_digit) + largest_digit = c; + numdigits++; + + for (count = 0; count < TOTAL_PARTS; count++) + { + parts[count] *= base; + if (count) + { + parts[count] + += (parts[count-1] >> HOST_BITS_PER_CHAR); + parts[count-1] + &= (1 << HOST_BITS_PER_CHAR) - 1; + } + else + parts[0] += c; + } + + /* If the extra highest-order part ever gets anything in it, + the number is certainly too big. */ + if (parts[TOTAL_PARTS - 1] != 0) + overflow = 1; + + if (p >= token_buffer + maxtoken - 3) + p = extend_token_buffer (p); + *p++ = (c = GETC()); + } + } + + if (numdigits == 0) + error ("numeric constant with no digits"); + + if (largest_digit >= base) + error ("numeric constant contains digits beyond the radix"); + + /* Remove terminating char from the token buffer and delimit the string */ + *--p = 0; + + if (floatflag != NOT_FLOAT) + { + tree type = double_type_node; + int imag = 0; + int conversion_errno = 0; + REAL_VALUE_TYPE value; + jmp_buf handler; + + /* Read explicit exponent if any, and put it in tokenbuf. */ + + if ((base == 10 && ((c == 'e') || (c == 'E'))) + || (base == 16 && (c == 'p' || c == 'P'))) + { + if (p >= token_buffer + maxtoken - 3) + p = extend_token_buffer (p); + *p++ = c; + c = GETC(); + if ((c == '+') || (c == '-')) + { + *p++ = c; + c = GETC(); + } + /* Exponent is decimal, even if string is a hex float. */ + if (! ISDIGIT (c)) + error ("floating constant exponent has no digits"); + while (ISDIGIT (c)) + { + if (p >= token_buffer + maxtoken - 3) + p = extend_token_buffer (p); + *p++ = c; + c = GETC(); + } + } + if (base == 16 && floatflag != AFTER_EXPON) + error ("hexadecimal floating constant has no exponent"); + + *p = 0; + + /* Convert string to a double, checking for overflow. */ + if (setjmp (handler)) + { + error ("floating constant out of range"); + value = dconst0; + } + else + { + int fflag = 0, lflag = 0; + /* Copy token_buffer now, while it has just the number + and not the suffixes; once we add `f' or `i', + REAL_VALUE_ATOF may not work any more. */ + char *copy = (char *) alloca (p - token_buffer + 1); + bcopy (token_buffer, copy, p - token_buffer + 1); + + set_float_handler (handler); + + while (1) + { + int lose = 0; + + /* Read the suffixes to choose a data type. */ + switch (c) + { + case 'f': case 'F': + if (fflag) + error ("more than one `f' in numeric constant"); + fflag = 1; + break; + + case 'l': case 'L': + if (lflag) + error ("more than one `l' in numeric constant"); + lflag = 1; + break; + + case 'i': case 'I': + if (imag) + error ("more than one `i' or `j' in numeric constant"); + else if (pedantic) + pedwarn ("ANSI C forbids imaginary numeric constants"); + imag = 1; + break; + + default: + lose = 1; + } + + if (lose) + break; + + if (p >= token_buffer + maxtoken - 3) + p = extend_token_buffer (p); + *p++ = c; + *p = 0; + c = GETC(); + } + + /* The second argument, machine_mode, of REAL_VALUE_ATOF + tells the desired precision of the binary result + of decimal-to-binary conversion. */ + + if (fflag) + { + if (lflag) + error ("both `f' and `l' in floating constant"); + + type = float_type_node; + errno = 0; + if (base == 16) + value = REAL_VALUE_HTOF (copy, TYPE_MODE (type)); + else + value = REAL_VALUE_ATOF (copy, TYPE_MODE (type)); + conversion_errno = errno; + /* A diagnostic is required here by some ANSI C testsuites. + This is not pedwarn, because some people don't want + an error for this. */ + if (REAL_VALUE_ISINF (value) && pedantic) + warning ("floating point number exceeds range of `float'"); + } + else if (lflag) + { + type = long_double_type_node; + errno = 0; + if (base == 16) + value = REAL_VALUE_HTOF (copy, TYPE_MODE (type)); + else + value = REAL_VALUE_ATOF (copy, TYPE_MODE (type)); + conversion_errno = errno; + if (REAL_VALUE_ISINF (value) && pedantic) + warning ("floating point number exceeds range of `long double'"); + } + else + { + errno = 0; + if (base == 16) + value = REAL_VALUE_HTOF (copy, TYPE_MODE (type)); + else + value = REAL_VALUE_ATOF (copy, TYPE_MODE (type)); + conversion_errno = errno; + if (REAL_VALUE_ISINF (value) && pedantic) + warning ("floating point number exceeds range of `double'"); + } + + set_float_handler (NULL_PTR); + } +#ifdef ERANGE + /* ERANGE is also reported for underflow, + so test the value to distinguish overflow from that. */ + if (conversion_errno == ERANGE && !flag_traditional && pedantic + && (REAL_VALUES_LESS (dconst1, value) + || REAL_VALUES_LESS (value, dconstm1))) + warning ("floating point number exceeds range of `double'"); +#endif + + /* If the result is not a number, assume it must have been + due to some error message above, so silently convert + it to a zero. */ + if (REAL_VALUE_ISNAN (value)) + value = dconst0; + + /* Create a node with determined type and value. */ + if (imag) + yylval.ttype = build_complex (NULL_TREE, + convert (type, integer_zero_node), + build_real (type, value)); + else + yylval.ttype = build_real (type, value); + } + else + { + tree traditional_type, ansi_type, type; + HOST_WIDE_INT high, low; + int spec_unsigned = 0; + int spec_long = 0; + int spec_long_long = 0; + int spec_imag = 0; + int bytes, warn, i; + + traditional_type = ansi_type = type = NULL_TREE; + while (1) + { + if (c == 'u' || c == 'U') + { + if (spec_unsigned) + error ("two `u's in integer constant"); + spec_unsigned = 1; + } + else if (c == 'l' || c == 'L') + { + if (spec_long) + { + if (spec_long_long) + error ("three `l's in integer constant"); + else if (pedantic && ! in_system_header && warn_long_long) + pedwarn ("ANSI C forbids long long integer constants"); + spec_long_long = 1; + } + spec_long = 1; + } + else if (c == 'i' || c == 'j' || c == 'I' || c == 'J') + { + if (spec_imag) + error ("more than one `i' or `j' in numeric constant"); + else if (pedantic) + pedwarn ("ANSI C forbids imaginary numeric constants"); + spec_imag = 1; + } + else + break; + if (p >= token_buffer + maxtoken - 3) + p = extend_token_buffer (p); + *p++ = c; + c = GETC(); + } + + /* If the constant won't fit in an unsigned long long, + then warn that the constant is out of range. */ + + /* ??? This assumes that long long and long integer types are + a multiple of 8 bits. This better than the original code + though which assumed that long was exactly 32 bits and long + long was exactly 64 bits. */ + + bytes = TYPE_PRECISION (long_long_integer_type_node) / 8; + + warn = overflow; + for (i = bytes; i < TOTAL_PARTS; i++) + if (parts[i]) + warn = 1; + if (warn) + pedwarn ("integer constant out of range"); + + /* This is simplified by the fact that our constant + is always positive. */ + + high = low = 0; + + for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; i++) + { + high |= ((HOST_WIDE_INT) parts[i + (HOST_BITS_PER_WIDE_INT + / HOST_BITS_PER_CHAR)] + << (i * HOST_BITS_PER_CHAR)); + low |= (HOST_WIDE_INT) parts[i] << (i * HOST_BITS_PER_CHAR); + } + + yylval.ttype = build_int_2 (low, high); + TREE_TYPE (yylval.ttype) = long_long_unsigned_type_node; + + /* If warn_traditional, calculate both the ANSI type and the + traditional type, then see if they disagree. + Otherwise, calculate only the type for the dialect in use. */ + if (warn_traditional || flag_traditional) + { + /* Calculate the traditional type. */ + /* Traditionally, any constant is signed; + but if unsigned is specified explicitly, obey that. + Use the smallest size with the right number of bits, + except for one special case with decimal constants. */ + if (! spec_long && base != 10 + && int_fits_type_p (yylval.ttype, unsigned_type_node)) + traditional_type = (spec_unsigned ? unsigned_type_node + : integer_type_node); + /* A decimal constant must be long + if it does not fit in type int. + I think this is independent of whether + the constant is signed. */ + else if (! spec_long && base == 10 + && int_fits_type_p (yylval.ttype, integer_type_node)) + traditional_type = (spec_unsigned ? unsigned_type_node + : integer_type_node); + else if (! spec_long_long) + traditional_type = (spec_unsigned ? long_unsigned_type_node + : long_integer_type_node); + else + traditional_type = (spec_unsigned + ? long_long_unsigned_type_node + : long_long_integer_type_node); + } + if (warn_traditional || ! flag_traditional) + { + /* Calculate the ANSI type. */ + if (! spec_long && ! spec_unsigned + && int_fits_type_p (yylval.ttype, integer_type_node)) + ansi_type = integer_type_node; + else if (! spec_long && (base != 10 || spec_unsigned) + && int_fits_type_p (yylval.ttype, unsigned_type_node)) + ansi_type = unsigned_type_node; + else if (! spec_unsigned && !spec_long_long + && int_fits_type_p (yylval.ttype, long_integer_type_node)) + ansi_type = long_integer_type_node; + else if (! spec_long_long + && int_fits_type_p (yylval.ttype, + long_unsigned_type_node)) + ansi_type = long_unsigned_type_node; + else if (! spec_unsigned + && int_fits_type_p (yylval.ttype, + long_long_integer_type_node)) + ansi_type = long_long_integer_type_node; + else + ansi_type = long_long_unsigned_type_node; + } + + type = flag_traditional ? traditional_type : ansi_type; + + if (warn_traditional && traditional_type != ansi_type) + { + if (TYPE_PRECISION (traditional_type) + != TYPE_PRECISION (ansi_type)) + warning ("width of integer constant changes with -traditional"); + else if (TREE_UNSIGNED (traditional_type) + != TREE_UNSIGNED (ansi_type)) + warning ("integer constant is unsigned in ANSI C, signed with -traditional"); + else + warning ("width of integer constant may change on other systems with -traditional"); + } + + if (pedantic && !flag_traditional && !spec_long_long && !warn + && (TYPE_PRECISION (long_integer_type_node) + < TYPE_PRECISION (type))) + pedwarn ("integer constant out of range"); + + if (base == 10 && ! spec_unsigned && TREE_UNSIGNED (type)) + warning ("decimal constant is so large that it is unsigned"); + + if (spec_imag) + { + if (TYPE_PRECISION (type) + <= TYPE_PRECISION (integer_type_node)) + yylval.ttype + = build_complex (NULL_TREE, integer_zero_node, + convert (integer_type_node, + yylval.ttype)); + else + error ("complex integer constant is too wide for `complex int'"); + } + else if (flag_traditional && !int_fits_type_p (yylval.ttype, type)) + /* The traditional constant 0x80000000 is signed + but doesn't fit in the range of int. + This will change it to -0x80000000, which does fit. */ + { + TREE_TYPE (yylval.ttype) = unsigned_type (type); + yylval.ttype = convert (type, yylval.ttype); + TREE_OVERFLOW (yylval.ttype) + = TREE_CONSTANT_OVERFLOW (yylval.ttype) = 0; + } + else + TREE_TYPE (yylval.ttype) = type; + } + + UNGETC (c); + *p = 0; + + if (ISALNUM (c) || c == '.' || c == '_' || c == '$' + || (!flag_traditional && (c == '-' || c == '+') + && (p[-1] == 'e' || p[-1] == 'E'))) + error ("missing white space after number `%s'", token_buffer); + + value = CONSTANT; break; + } + + case '\'': + char_constant: + { + register int result = 0; + register int num_chars = 0; + int chars_seen = 0; + unsigned width = TYPE_PRECISION (char_type_node); + int max_chars; +#ifdef MULTIBYTE_CHARS + int longest_char = local_mb_cur_max (); + (void) local_mbtowc (NULL_PTR, NULL_PTR, 0); +#endif + + max_chars = TYPE_PRECISION (integer_type_node) / width; + if (wide_flag) + width = WCHAR_TYPE_SIZE; + + while (1) + { + tryagain: + c = GETC(); + + if (c == '\'' || c == EOF) + break; + + ++chars_seen; + if (c == '\\') + { + int ignore = 0; + c = readescape (&ignore); + if (ignore) + goto tryagain; + if (width < HOST_BITS_PER_INT + && (unsigned) c >= ((unsigned)1 << width)) + pedwarn ("escape sequence out of range for character"); +#ifdef MAP_CHARACTER + if (ISPRINT (c)) + c = MAP_CHARACTER (c); +#endif + } + else if (c == '\n') + { + if (pedantic) + pedwarn ("ANSI C forbids newline in character constant"); + lineno++; + } + else + { +#ifdef MULTIBYTE_CHARS + wchar_t wc; + int i; + int char_len = -1; + for (i = 1; i <= longest_char; ++i) + { + if (i > maxtoken - 4) + extend_token_buffer (token_buffer); + + token_buffer[i] = c; + char_len = local_mbtowc (& wc, + token_buffer + 1, + i); + if (char_len != -1) + break; + c = GETC (); + } + if (char_len > 1) + { + /* mbtowc sometimes needs an extra char before accepting */ + if (char_len < i) + UNGETC (c); + if (! wide_flag) + { + /* Merge character into result; ignore excess chars. */ + for (i = 1; i <= char_len; ++i) + { + if (i > max_chars) + break; + if (width < HOST_BITS_PER_INT) + result = (result << width) + | (token_buffer[i] + & ((1 << width) - 1)); + else + result = token_buffer[i]; + } + num_chars += char_len; + goto tryagain; + } + c = wc; + } + else + { + if (char_len == -1) + warning ("Ignoring invalid multibyte character"); + if (wide_flag) + c = wc; +#ifdef MAP_CHARACTER + else + c = MAP_CHARACTER (c); +#endif + } +#else /* ! MULTIBYTE_CHARS */ +#ifdef MAP_CHARACTER + c = MAP_CHARACTER (c); +#endif +#endif /* ! MULTIBYTE_CHARS */ + } + + if (wide_flag) + { + if (chars_seen == 1) /* only keep the first one */ + result = c; + goto tryagain; + } + + /* Merge character into result; ignore excess chars. */ + num_chars += (width / TYPE_PRECISION (char_type_node)); + if (num_chars < max_chars + 1) + { + if (width < HOST_BITS_PER_INT) + result = (result << width) | (c & ((1 << width) - 1)); + else + result = c; + } + } + + if (c != '\'') + error ("malformatted character constant"); + else if (chars_seen == 0) + error ("empty character constant"); + else if (num_chars > max_chars) + { + num_chars = max_chars; + error ("character constant too long"); + } + else if (chars_seen != 1 && ! flag_traditional && warn_multichar) + warning ("multi-character character constant"); + + /* If char type is signed, sign-extend the constant. */ + if (! wide_flag) + { + int num_bits = num_chars * width; + if (num_bits == 0) + /* We already got an error; avoid invalid shift. */ + yylval.ttype = build_int_2 (0, 0); + else if (TREE_UNSIGNED (char_type_node) + || ((result >> (num_bits - 1)) & 1) == 0) + yylval.ttype + = build_int_2 (result & (~(unsigned HOST_WIDE_INT) 0 + >> (HOST_BITS_PER_WIDE_INT - num_bits)), + 0); + else + yylval.ttype + = build_int_2 (result | ~(~(unsigned HOST_WIDE_INT) 0 + >> (HOST_BITS_PER_WIDE_INT - num_bits)), + -1); + TREE_TYPE (yylval.ttype) = integer_type_node; + } + else + { + yylval.ttype = build_int_2 (result, 0); + TREE_TYPE (yylval.ttype) = wchar_type_node; + } + + value = CONSTANT; + break; + } + + case '"': + string_constant: + { + unsigned width = wide_flag ? WCHAR_TYPE_SIZE + : TYPE_PRECISION (char_type_node); +#ifdef MULTIBYTE_CHARS + int longest_char = local_mb_cur_max (); + (void) local_mbtowc (NULL_PTR, NULL_PTR, 0); +#endif + c = GETC (); + p = token_buffer + 1; + + while (c != '"' && c >= 0) + { + if (c == '\\') + { + int ignore = 0; + c = readescape (&ignore); + if (ignore) + goto skipnewline; + if (width < HOST_BITS_PER_INT + && (unsigned) c >= ((unsigned)1 << width)) + pedwarn ("escape sequence out of range for character"); + } + else if (c == '\n') + { + if (pedantic) + pedwarn ("ANSI C forbids newline in string constant"); + lineno++; + } + else + { +#ifdef MULTIBYTE_CHARS + wchar_t wc; + int i; + int char_len = -1; + for (i = 0; i < longest_char; ++i) + { + if (p + i >= token_buffer + maxtoken) + p = extend_token_buffer (p); + p[i] = c; + + char_len = local_mbtowc (& wc, p, i + 1); + if (char_len != -1) + break; + c = GETC (); + } + if (char_len == -1) + warning ("Ignoring invalid multibyte character"); + else + { + /* mbtowc sometimes needs an extra char before accepting */ + if (char_len <= i) + UNGETC (c); + if (! wide_flag) + { + p += (i + 1); + c = GETC (); + continue; + } + c = wc; + } +#endif /* MULTIBYTE_CHARS */ + } + + /* Add this single character into the buffer either as a wchar_t + or as a single byte. */ + if (wide_flag) + { + unsigned width = TYPE_PRECISION (char_type_node); + unsigned bytemask = (1 << width) - 1; + int byte; + + if (p + WCHAR_BYTES > token_buffer + maxtoken) + p = extend_token_buffer (p); + + for (byte = 0; byte < WCHAR_BYTES; ++byte) + { + int value; + if (byte >= (int) sizeof (c)) + value = 0; + else + value = (c >> (byte * width)) & bytemask; + if (BYTES_BIG_ENDIAN) + p[WCHAR_BYTES - byte - 1] = value; + else + p[byte] = value; + } + p += WCHAR_BYTES; + } + else + { + if (p >= token_buffer + maxtoken) + p = extend_token_buffer (p); + *p++ = c; + } + + skipnewline: + c = GETC (); + } + + /* Terminate the string value, either with a single byte zero + or with a wide zero. */ + if (wide_flag) + { + if (p + WCHAR_BYTES > token_buffer + maxtoken) + p = extend_token_buffer (p); + bzero (p, WCHAR_BYTES); + p += WCHAR_BYTES; + } + else + { + if (p >= token_buffer + maxtoken) + p = extend_token_buffer (p); + *p++ = 0; + } + + if (c < 0) + error ("Unterminated string constant"); + + /* We have read the entire constant. + Construct a STRING_CST for the result. */ + + if (wide_flag) + { + yylval.ttype = build_string (p - (token_buffer + 1), + token_buffer + 1); + TREE_TYPE (yylval.ttype) = wchar_array_type_node; + value = STRING; + } + else if (objc_flag) + { + /* Return an Objective-C @"..." constant string object. */ + yylval.ttype = build_objc_string (p - (token_buffer + 1), + token_buffer + 1); + TREE_TYPE (yylval.ttype) = char_array_type_node; + value = OBJC_STRING; + } + else + { + yylval.ttype = build_string (p - (token_buffer + 1), + token_buffer + 1); + TREE_TYPE (yylval.ttype) = char_array_type_node; + value = STRING; + } + + break; + } + + case '+': + case '-': + case '&': + case '|': + case ':': + case '<': + case '>': + case '*': + case '/': + case '%': + case '^': + case '!': + case '=': + { + register int c1; + + combine: + + switch (c) + { + case '+': + yylval.code = PLUS_EXPR; break; + case '-': + yylval.code = MINUS_EXPR; break; + case '&': + yylval.code = BIT_AND_EXPR; break; + case '|': + yylval.code = BIT_IOR_EXPR; break; + case '*': + yylval.code = MULT_EXPR; break; + case '/': + yylval.code = TRUNC_DIV_EXPR; break; + case '%': + yylval.code = TRUNC_MOD_EXPR; break; + case '^': + yylval.code = BIT_XOR_EXPR; break; + case LSHIFT: + yylval.code = LSHIFT_EXPR; break; + case RSHIFT: + yylval.code = RSHIFT_EXPR; break; + case '<': + yylval.code = LT_EXPR; break; + case '>': + yylval.code = GT_EXPR; break; + } + + token_buffer[1] = c1 = GETC(); + token_buffer[2] = 0; + + if (c1 == '=') + { + switch (c) + { + case '<': + value = ARITHCOMPARE; yylval.code = LE_EXPR; goto done; + case '>': + value = ARITHCOMPARE; yylval.code = GE_EXPR; goto done; + case '!': + value = EQCOMPARE; yylval.code = NE_EXPR; goto done; + case '=': + value = EQCOMPARE; yylval.code = EQ_EXPR; goto done; + } + value = ASSIGN; goto done; + } + else if (c == c1) + switch (c) + { + case '+': + value = PLUSPLUS; goto done; + case '-': + value = MINUSMINUS; goto done; + case '&': + value = ANDAND; goto done; + case '|': + value = OROR; goto done; + case '<': + c = LSHIFT; + goto combine; + case '>': + c = RSHIFT; + goto combine; + } + else + switch (c) + { + case '-': + if (c1 == '>') + { value = POINTSAT; goto done; } + break; + case ':': + if (c1 == '>') + { value = ']'; goto done; } + break; + case '<': + if (c1 == '%') + { value = '{'; indent_level++; goto done; } + if (c1 == ':') + { value = '['; goto done; } + break; + case '%': + if (c1 == '>') + { value = '}'; indent_level--; goto done; } + break; + } + UNGETC (c1); + token_buffer[1] = 0; + + if ((c == '<') || (c == '>')) + value = ARITHCOMPARE; + else value = c; + goto done; + } + + case 0: + /* Don't make yyparse think this is eof. */ + value = 1; + break; + + case '{': + indent_level++; + value = c; + break; + + case '}': + indent_level--; + value = c; + break; + + default: + value = c; + } + +done: +/* yylloc.last_line = lineno; */ + + return value; +} + +/* Sets the value of the 'yydebug' variable to VALUE. + This is a function so we don't have to have YYDEBUG defined + in order to build the compiler. */ + +void +set_yydebug (value) + int value; +{ +#if YYDEBUG != 0 + yydebug = value; +#else + warning ("YYDEBUG not defined."); +#endif +} diff --git a/gcc_arm/c-lex.h b/gcc_arm/c-lex.h new file mode 100755 index 0000000..255de21 --- /dev/null +++ b/gcc_arm/c-lex.h @@ -0,0 +1,88 @@ +/* Define constants for communication with c-parse.y. + Copyright (C) 1987, 1992, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + + +enum rid +{ + RID_UNUSED, + RID_INT, + RID_CHAR, + RID_FLOAT, + RID_DOUBLE, + RID_VOID, + RID_UNUSED1, + + RID_UNSIGNED, + RID_SHORT, + RID_LONG, + RID_AUTO, + RID_STATIC, + RID_EXTERN, + RID_REGISTER, + RID_TYPEDEF, + RID_SIGNED, + RID_CONST, + RID_RESTRICT, + RID_VOLATILE, + RID_INLINE, + RID_NOALIAS, + RID_ITERATOR, + RID_COMPLEX, + + RID_IN, + RID_OUT, + RID_INOUT, + RID_BYCOPY, + RID_BYREF, + RID_ONEWAY, + RID_ID, + + RID_MAX +}; + +#define NORID RID_UNUSED + +#define RID_FIRST_MODIFIER RID_UNSIGNED + +/* The elements of `ridpointers' are identifier nodes + for the reserved type names and storage classes. + It is indexed by a RID_... value. */ +extern tree ridpointers[(int) RID_MAX]; + +/* the declaration found for the last IDENTIFIER token read in. + yylex must look this up to detect typedefs, which get token type TYPENAME, + so it is left around in case the identifier is not a typedef but is + used in a context which makes it a reference to a variable. */ +extern tree lastiddecl; + +extern char *token_buffer; /* Pointer to token buffer. */ + +extern tree make_pointer_declarator PROTO((tree, tree)); +extern void reinit_parse_for_function PROTO((void)); +extern void position_after_white_space PROTO((void)); +extern int check_newline PROTO((void)); + +extern int yylex PROTO((void)); +extern void yyerror PROTO((char *)); + +extern void forget_protocol_qualifiers PROTO((void)); +extern void remember_protocol_qualifiers PROTO((void)); +extern tree is_class_name PROTO((tree)); diff --git a/gcc_arm/c-parse.c b/gcc_arm/c-parse.c new file mode 100644 index 0000000..ee174d1 --- /dev/null +++ b/gcc_arm/c-parse.c @@ -0,0 +1,5078 @@ +/* A Bison parser, made by GNU Bison 2.3. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.3" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + IDENTIFIER = 258, + TYPENAME = 259, + SCSPEC = 260, + TYPESPEC = 261, + TYPE_QUAL = 262, + CONSTANT = 263, + STRING = 264, + ELLIPSIS = 265, + SIZEOF = 266, + ENUM = 267, + STRUCT = 268, + UNION = 269, + IF = 270, + ELSE = 271, + WHILE = 272, + DO = 273, + FOR = 274, + SWITCH = 275, + CASE = 276, + DEFAULT = 277, + BREAK = 278, + CONTINUE = 279, + RETURN = 280, + GOTO = 281, + ASM_KEYWORD = 282, + TYPEOF = 283, + ALIGNOF = 284, + ATTRIBUTE = 285, + EXTENSION = 286, + LABEL = 287, + REALPART = 288, + IMAGPART = 289, + ASSIGN = 290, + OROR = 291, + ANDAND = 292, + EQCOMPARE = 293, + ARITHCOMPARE = 294, + RSHIFT = 295, + LSHIFT = 296, + MINUSMINUS = 297, + PLUSPLUS = 298, + UNARY = 299, + HYPERUNARY = 300, + POINTSAT = 301, + INTERFACE = 302, + IMPLEMENTATION = 303, + END = 304, + SELECTOR = 305, + DEFS = 306, + ENCODE = 307, + CLASSNAME = 308, + PUBLIC = 309, + PRIVATE = 310, + PROTECTED = 311, + PROTOCOL = 312, + OBJECTNAME = 313, + CLASS = 314, + ALIAS = 315, + OBJC_STRING = 316 + }; +#endif +/* Tokens. */ +#define IDENTIFIER 258 +#define TYPENAME 259 +#define SCSPEC 260 +#define TYPESPEC 261 +#define TYPE_QUAL 262 +#define CONSTANT 263 +#define STRING 264 +#define ELLIPSIS 265 +#define SIZEOF 266 +#define ENUM 267 +#define STRUCT 268 +#define UNION 269 +#define IF 270 +#define ELSE 271 +#define WHILE 272 +#define DO 273 +#define FOR 274 +#define SWITCH 275 +#define CASE 276 +#define DEFAULT 277 +#define BREAK 278 +#define CONTINUE 279 +#define RETURN 280 +#define GOTO 281 +#define ASM_KEYWORD 282 +#define TYPEOF 283 +#define ALIGNOF 284 +#define ATTRIBUTE 285 +#define EXTENSION 286 +#define LABEL 287 +#define REALPART 288 +#define IMAGPART 289 +#define ASSIGN 290 +#define OROR 291 +#define ANDAND 292 +#define EQCOMPARE 293 +#define ARITHCOMPARE 294 +#define RSHIFT 295 +#define LSHIFT 296 +#define MINUSMINUS 297 +#define PLUSPLUS 298 +#define UNARY 299 +#define HYPERUNARY 300 +#define POINTSAT 301 +#define INTERFACE 302 +#define IMPLEMENTATION 303 +#define END 304 +#define SELECTOR 305 +#define DEFS 306 +#define ENCODE 307 +#define CLASSNAME 308 +#define PUBLIC 309 +#define PRIVATE 310 +#define PROTECTED 311 +#define PROTOCOL 312 +#define OBJECTNAME 313 +#define CLASS 314 +#define ALIAS 315 +#define OBJC_STRING 316 + + + + +/* Copy the first part of user declarations. */ + + +#include "config.h" +#include "system.h" +#include + +#include "tree.h" +#include "input.h" +#include "c-lex.h" +#include "c-tree.h" +#include "flags.h" +#include "output.h" +#include "toplev.h" + + +/* Since parsers are distinct for each language, put the language string + definition here. */ +char *language_string = "GNU C"; + +/* Like YYERROR but do call yyerror. */ +#define YYERROR1 { yyerror ("syntax error"); YYERROR; } + +/* Cause the `yydebug' variable to be defined. */ +#define YYDEBUG 1 + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE + +{long itype; tree ttype; enum tree_code code; + char *filename; int lineno; int ends_in_label; } +/* Line 187 of yacc.c. */ + + YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + +/* Copy the second part of user declarations. */ + + +/* Number of statements (loosely speaking) and compound statements + seen so far. */ +static int stmt_count; +static int compstmt_count; + +/* Input file and line number of the end of the body of last simple_if; + used by the stmt-rule immediately after simple_if returns. */ +static char *if_stmt_file; +static int if_stmt_line; + +/* List of types and structure classes of the current declaration. */ +static tree current_declspecs = NULL_TREE; +static tree prefix_attributes = NULL_TREE; + +/* Stack of saved values of current_declspecs and prefix_attributes. */ +static tree declspec_stack; + +/* 1 if we explained undeclared var errors. */ +static int undeclared_variable_notice; + + +/* Tell yyparse how to print a token's value, if yydebug is set. */ + +#define YYPRINT(FILE,YYCHAR,YYLVAL) yyprint(FILE,YYCHAR,YYLVAL) +extern void yyprint (FILE *, int, YYSTYPE); + + +/* Line 216 of yacc.c. */ + + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +#define YY_(msgid) msgid +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int i) +#else +static int +YYID (i) + int i; +#endif +{ + return i; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss; + YYSTYPE yyvs; + }; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 4 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 2427 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 84 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 158 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 404 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 689 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 316 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 80, 2, 2, 2, 52, 43, 2, + 58, 76, 50, 48, 81, 49, 57, 51, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 38, 77, + 2, 35, 2, 37, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 59, 2, 83, 42, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 82, 41, 78, 79, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 36, 39, 40, 44, 45, 46, 47, 53, 54, 55, + 56, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint16 yyprhs[] = +{ + 0, 0, 3, 4, 6, 7, 10, 11, 15, 17, + 19, 25, 28, 32, 37, 42, 45, 48, 51, 54, + 56, 57, 58, 66, 71, 72, 73, 81, 86, 87, + 88, 95, 99, 101, 103, 105, 107, 109, 111, 113, + 115, 117, 119, 120, 122, 124, 128, 130, 133, 136, + 139, 142, 145, 150, 153, 158, 161, 164, 166, 168, + 170, 175, 176, 184, 186, 190, 194, 198, 202, 206, + 210, 214, 218, 222, 226, 230, 234, 235, 240, 241, + 246, 247, 248, 256, 257, 263, 267, 271, 273, 275, + 277, 281, 285, 286, 291, 296, 301, 305, 309, 312, + 315, 317, 320, 321, 323, 326, 330, 332, 334, 337, + 340, 345, 350, 353, 356, 360, 362, 364, 367, 370, + 371, 372, 377, 382, 386, 390, 393, 396, 399, 402, + 406, 407, 410, 413, 416, 419, 423, 424, 427, 430, + 432, 434, 437, 440, 442, 444, 447, 450, 453, 457, + 458, 461, 463, 465, 467, 472, 477, 479, 481, 483, + 485, 489, 491, 495, 496, 501, 502, 509, 513, 514, + 521, 525, 526, 528, 530, 533, 540, 542, 546, 547, + 549, 554, 561, 566, 568, 570, 572, 574, 576, 577, + 582, 584, 585, 588, 590, 594, 598, 601, 602, 607, + 609, 610, 615, 617, 619, 621, 624, 627, 633, 637, + 638, 639, 645, 646, 647, 653, 655, 657, 661, 665, + 670, 674, 678, 682, 684, 688, 693, 698, 702, 706, + 710, 712, 716, 720, 724, 729, 734, 738, 742, 744, + 746, 749, 751, 754, 756, 759, 760, 768, 774, 777, + 778, 786, 792, 795, 796, 805, 806, 814, 817, 818, + 820, 821, 823, 825, 828, 829, 833, 836, 840, 842, + 846, 848, 850, 853, 855, 859, 864, 871, 877, 879, + 883, 885, 887, 891, 894, 897, 898, 900, 902, 905, + 906, 909, 913, 917, 920, 924, 929, 933, 936, 940, + 943, 945, 947, 950, 953, 954, 956, 959, 960, 961, + 963, 965, 968, 972, 974, 977, 979, 982, 989, 995, + 1001, 1004, 1007, 1012, 1013, 1018, 1019, 1020, 1024, 1029, + 1033, 1035, 1037, 1039, 1041, 1044, 1045, 1050, 1052, 1056, + 1057, 1058, 1066, 1072, 1075, 1076, 1077, 1078, 1091, 1092, + 1099, 1102, 1105, 1108, 1112, 1119, 1128, 1139, 1152, 1156, + 1161, 1163, 1165, 1166, 1173, 1177, 1183, 1186, 1190, 1191, + 1193, 1194, 1196, 1197, 1199, 1201, 1205, 1210, 1212, 1216, + 1217, 1220, 1223, 1224, 1229, 1232, 1233, 1235, 1237, 1241, + 1243, 1247, 1252, 1257, 1262, 1267, 1272, 1273, 1276, 1278, + 1281, 1283, 1287, 1289, 1293 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int16 yyrhs[] = +{ + 85, 0, -1, -1, 86, -1, -1, 87, 89, -1, + -1, 86, 88, 89, -1, 91, -1, 90, -1, 27, + 58, 100, 76, 77, -1, 241, 89, -1, 123, 137, + 77, -1, 130, 123, 137, 77, -1, 126, 123, 136, + 77, -1, 130, 77, -1, 126, 77, -1, 1, 77, + -1, 1, 78, -1, 77, -1, -1, -1, 126, 123, + 165, 92, 117, 93, 199, -1, 126, 123, 165, 1, + -1, -1, -1, 130, 123, 168, 94, 117, 95, 199, + -1, 130, 123, 168, 1, -1, -1, -1, 123, 168, + 96, 117, 97, 199, -1, 123, 168, 1, -1, 3, + -1, 4, -1, 43, -1, 49, -1, 48, -1, 54, + -1, 53, -1, 79, -1, 80, -1, 102, -1, -1, + 102, -1, 108, -1, 102, 81, 108, -1, 114, -1, + 50, 106, -1, 241, 106, -1, 99, 106, -1, 40, + 98, -1, 104, 103, -1, 104, 58, 186, 76, -1, + 105, 103, -1, 105, 58, 186, 76, -1, 33, 106, + -1, 34, 106, -1, 11, -1, 29, -1, 103, -1, + 58, 186, 76, 106, -1, -1, 58, 186, 76, 82, + 107, 151, 78, -1, 106, -1, 108, 48, 108, -1, + 108, 49, 108, -1, 108, 50, 108, -1, 108, 51, + 108, -1, 108, 52, 108, -1, 108, 47, 108, -1, + 108, 46, 108, -1, 108, 45, 108, -1, 108, 44, + 108, -1, 108, 43, 108, -1, 108, 41, 108, -1, + 108, 42, 108, -1, -1, 108, 40, 109, 108, -1, + -1, 108, 39, 110, 108, -1, -1, -1, 108, 37, + 111, 100, 38, 112, 108, -1, -1, 108, 37, 113, + 38, 108, -1, 108, 35, 108, -1, 108, 36, 108, + -1, 3, -1, 8, -1, 116, -1, 58, 100, 76, + -1, 58, 1, 76, -1, -1, 58, 115, 201, 76, + -1, 114, 58, 101, 76, -1, 114, 59, 100, 83, + -1, 114, 57, 98, -1, 114, 60, 98, -1, 114, + 54, -1, 114, 53, -1, 9, -1, 116, 9, -1, + -1, 119, -1, 119, 10, -1, 206, 207, 120, -1, + 118, -1, 194, -1, 119, 118, -1, 118, 194, -1, + 128, 123, 136, 77, -1, 131, 123, 137, 77, -1, + 128, 77, -1, 131, 77, -1, 206, 207, 125, -1, + 121, -1, 194, -1, 122, 121, -1, 121, 194, -1, + -1, -1, 126, 123, 136, 77, -1, 130, 123, 137, + 77, -1, 126, 123, 159, -1, 130, 123, 162, -1, + 126, 77, -1, 130, 77, -1, 241, 125, -1, 134, + 127, -1, 130, 134, 127, -1, -1, 127, 135, -1, + 127, 5, -1, 127, 144, -1, 134, 129, -1, 131, + 134, 129, -1, -1, 129, 135, -1, 129, 5, -1, + 131, -1, 144, -1, 130, 131, -1, 130, 144, -1, + 7, -1, 5, -1, 131, 7, -1, 131, 5, -1, + 134, 133, -1, 188, 134, 133, -1, -1, 133, 135, + -1, 6, -1, 172, -1, 4, -1, 28, 58, 100, + 76, -1, 28, 58, 186, 76, -1, 6, -1, 7, + -1, 172, -1, 139, -1, 136, 81, 139, -1, 141, + -1, 137, 81, 139, -1, -1, 27, 58, 116, 76, + -1, -1, 165, 138, 143, 35, 140, 149, -1, 165, + 138, 143, -1, -1, 168, 138, 143, 35, 142, 149, + -1, 168, 138, 143, -1, -1, 144, -1, 145, -1, + 144, 145, -1, 30, 58, 58, 146, 76, 76, -1, + 147, -1, 146, 81, 147, -1, -1, 148, -1, 148, + 58, 3, 76, -1, 148, 58, 3, 81, 102, 76, + -1, 148, 58, 101, 76, -1, 98, -1, 5, -1, + 6, -1, 7, -1, 108, -1, -1, 82, 150, 151, + 78, -1, 1, -1, -1, 152, 177, -1, 153, -1, + 152, 81, 153, -1, 157, 35, 155, -1, 158, 155, + -1, -1, 98, 38, 154, 155, -1, 155, -1, -1, + 82, 156, 151, 78, -1, 108, -1, 1, -1, 158, + -1, 157, 158, -1, 57, 98, -1, 59, 108, 10, + 108, 83, -1, 59, 108, 83, -1, -1, -1, 165, + 160, 117, 161, 201, -1, -1, -1, 168, 163, 117, + 164, 201, -1, 166, -1, 168, -1, 58, 166, 76, + -1, 166, 58, 236, -1, 166, 59, 100, 83, -1, + 166, 59, 83, -1, 50, 189, 166, -1, 144, 124, + 166, -1, 4, -1, 167, 58, 236, -1, 167, 59, + 50, 83, -1, 167, 59, 100, 83, -1, 167, 59, + 83, -1, 50, 189, 167, -1, 144, 124, 167, -1, + 4, -1, 168, 58, 236, -1, 58, 168, 76, -1, + 50, 189, 168, -1, 168, 59, 50, 83, -1, 168, + 59, 100, 83, -1, 168, 59, 83, -1, 144, 124, + 168, -1, 3, -1, 13, -1, 13, 144, -1, 14, + -1, 14, 144, -1, 12, -1, 12, 144, -1, -1, + 169, 98, 82, 173, 179, 78, 143, -1, 169, 82, + 179, 78, 143, -1, 169, 98, -1, -1, 170, 98, + 82, 174, 179, 78, 143, -1, 170, 82, 179, 78, + 143, -1, 170, 98, -1, -1, 171, 98, 82, 175, + 184, 178, 78, 143, -1, -1, 171, 82, 176, 184, + 178, 78, 143, -1, 171, 98, -1, -1, 81, -1, + -1, 81, -1, 180, -1, 180, 181, -1, -1, 180, + 181, 77, -1, 180, 77, -1, 132, 123, 182, -1, + 132, -1, 188, 123, 182, -1, 188, -1, 1, -1, + 241, 181, -1, 183, -1, 182, 81, 183, -1, 206, + 207, 165, 143, -1, 206, 207, 165, 38, 108, 143, + -1, 206, 207, 38, 108, 143, -1, 185, -1, 184, + 81, 185, -1, 1, -1, 98, -1, 98, 35, 108, + -1, 132, 187, -1, 188, 187, -1, -1, 190, -1, + 7, -1, 188, 7, -1, -1, 189, 7, -1, 58, + 190, 76, -1, 50, 189, 190, -1, 50, 189, -1, + 190, 58, 229, -1, 190, 59, 100, 83, -1, 190, + 59, 83, -1, 58, 229, -1, 59, 100, 83, -1, + 59, 83, -1, 192, -1, 209, -1, 192, 209, -1, + 192, 194, -1, -1, 191, -1, 1, 77, -1, -1, + -1, 197, -1, 198, -1, 197, 198, -1, 32, 240, + 77, -1, 201, -1, 1, 201, -1, 82, -1, 200, + 78, -1, 200, 195, 196, 122, 193, 78, -1, 200, + 195, 196, 1, 78, -1, 200, 195, 196, 191, 78, + -1, 203, 208, -1, 203, 1, -1, 15, 58, 100, + 76, -1, -1, 18, 205, 208, 17, -1, -1, -1, + 206, 207, 211, -1, 206, 207, 222, 208, -1, 206, + 207, 210, -1, 211, -1, 222, -1, 201, -1, 219, + -1, 100, 77, -1, -1, 202, 16, 212, 208, -1, + 202, -1, 202, 16, 1, -1, -1, -1, 17, 213, + 58, 100, 76, 214, 208, -1, 204, 58, 100, 76, + 77, -1, 204, 1, -1, -1, -1, -1, 19, 58, + 224, 77, 215, 224, 77, 216, 224, 76, 217, 208, + -1, -1, 20, 58, 100, 76, 218, 208, -1, 23, + 77, -1, 24, 77, -1, 25, 77, -1, 25, 100, + 77, -1, 27, 223, 58, 100, 76, 77, -1, 27, + 223, 58, 100, 38, 225, 76, 77, -1, 27, 223, + 58, 100, 38, 225, 38, 225, 76, 77, -1, 27, + 223, 58, 100, 38, 225, 38, 225, 38, 228, 76, + 77, -1, 26, 98, 77, -1, 26, 50, 100, 77, + -1, 77, -1, 220, -1, -1, 19, 58, 114, 76, + 221, 208, -1, 21, 108, 38, -1, 21, 108, 10, + 108, 38, -1, 22, 38, -1, 98, 38, 143, -1, + -1, 7, -1, -1, 100, -1, -1, 226, -1, 227, + -1, 226, 81, 227, -1, 9, 58, 100, 76, -1, + 116, -1, 228, 81, 116, -1, -1, 230, 231, -1, + 233, 76, -1, -1, 234, 77, 232, 231, -1, 1, + 76, -1, -1, 10, -1, 234, -1, 234, 81, 10, + -1, 235, -1, 234, 81, 235, -1, 126, 123, 167, + 143, -1, 126, 123, 168, 143, -1, 126, 123, 187, + 143, -1, 130, 123, 168, 143, -1, 130, 123, 187, + 143, -1, -1, 237, 238, -1, 231, -1, 239, 76, + -1, 3, -1, 239, 81, 3, -1, 98, -1, 240, + 81, 98, -1, 31, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 234, 234, 238, 253, 253, 254, 254, 258, 259, + 260, 268, 273, 283, 288, 293, 295, 297, 298, 299, + 306, 311, 305, 318, 324, 329, 323, 336, 342, 347, + 341, 354, 362, 363, 366, 368, 370, 372, 374, 376, + 378, 382, 388, 389, 393, 395, 400, 401, 404, 407, + 411, 439, 445, 448, 451, 454, 456, 461, 465, 469, + 470, 474, 473, 505, 506, 508, 510, 512, 514, 516, + 518, 520, 522, 524, 526, 528, 531, 530, 537, 536, + 543, 546, 542, 552, 551, 561, 564, 571, 669, 670, + 672, 678, 681, 680, 717, 719, 721, 725, 731, 733, + 739, 740, 745, 747, 748, 759, 764, 765, 766, 767, + 775, 780, 785, 788, 797, 802, 803, 804, 805, 813, + 824, 828, 833, 838, 843, 848, 850, 852, 862, 864, + 869, 870, 872, 877, 882, 884, 890, 891, 893, 906, + 908, 910, 912, 917, 920, 922, 925, 939, 941, 946, + 947, 955, 956, 957, 961, 963, 969, 970, 971, 975, + 976, 980, 981, 986, 987, 995, 994, 1002, 1011, 1010, + 1019, 1028, 1029, 1034, 1036, 1041, 1046, 1048, 1054, 1055, + 1057, 1059, 1061, 1069, 1070, 1071, 1072, 1078, 1080, 1079, + 1092, 1099, 1101, 1105, 1106, 1112, 1113, 1115, 1114, 1117, + 1122, 1121, 1125, 1127, 1131, 1132, 1136, 1141, 1143, 1149, + 1158, 1148, 1172, 1181, 1171, 1197, 1198, 1204, 1206, 1211, + 1213, 1215, 1222, 1224, 1233, 1238, 1243, 1245, 1247, 1254, + 1256, 1263, 1268, 1270, 1272, 1277, 1279, 1286, 1288, 1292, + 1294, 1299, 1301, 1306, 1308, 1314, 1313, 1319, 1323, 1326, + 1325, 1329, 1333, 1336, 1335, 1342, 1341, 1347, 1351, 1353, + 1356, 1358, 1364, 1366, 1372, 1373, 1375, 1390, 1396, 1401, + 1407, 1412, 1414, 1420, 1421, 1426, 1429, 1433, 1444, 1445, + 1450, 1456, 1458, 1463, 1465, 1471, 1472, 1476, 1478, 1484, + 1485, 1490, 1493, 1495, 1497, 1499, 1501, 1503, 1505, 1507, + 1518, 1526, 1527, 1529, 1533, 1535, 1538, 1542, 1552, 1554, + 1560, 1561, 1565, 1579, 1581, 1584, 1586, 1588, 1596, 1604, + 1616, 1620, 1624, 1639, 1638, 1651, 1655, 1659, 1664, 1669, + 1674, 1676, 1682, 1684, 1685, 1703, 1702, 1710, 1722, 1725, + 1735, 1724, 1745, 1753, 1758, 1770, 1773, 1756, 1800, 1799, + 1813, 1818, 1823, 1827, 1831, 1842, 1849, 1856, 1863, 1874, + 1880, 1884, 1890, 1889, 1945, 1976, 2007, 2022, 2038, 2040, + 2046, 2047, 2053, 2054, 2058, 2059, 2064, 2069, 2071, 2078, + 2078, 2088, 2090, 2089, 2099, 2106, 2107, 2117, 2119, 2124, + 2126, 2133, 2142, 2151, 2160, 2170, 2185, 2185, 2195, 2196, + 2206, 2208, 2214, 2216, 2221 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "IDENTIFIER", "TYPENAME", "SCSPEC", + "TYPESPEC", "TYPE_QUAL", "CONSTANT", "STRING", "ELLIPSIS", "SIZEOF", + "ENUM", "STRUCT", "UNION", "IF", "ELSE", "WHILE", "DO", "FOR", "SWITCH", + "CASE", "DEFAULT", "BREAK", "CONTINUE", "RETURN", "GOTO", "ASM_KEYWORD", + "TYPEOF", "ALIGNOF", "ATTRIBUTE", "EXTENSION", "LABEL", "REALPART", + "IMAGPART", "'='", "ASSIGN", "'?'", "':'", "OROR", "ANDAND", "'|'", + "'^'", "'&'", "EQCOMPARE", "ARITHCOMPARE", "RSHIFT", "LSHIFT", "'+'", + "'-'", "'*'", "'/'", "'%'", "MINUSMINUS", "PLUSPLUS", "UNARY", + "HYPERUNARY", "'.'", "'('", "'['", "POINTSAT", "INTERFACE", + "IMPLEMENTATION", "END", "SELECTOR", "DEFS", "ENCODE", "CLASSNAME", + "PUBLIC", "PRIVATE", "PROTECTED", "PROTOCOL", "OBJECTNAME", "CLASS", + "ALIAS", "OBJC_STRING", "')'", "';'", "'}'", "'~'", "'!'", "','", "'{'", + "']'", "$accept", "program", "extdefs", "@1", "@2", "extdef", "datadef", + "fndef", "@3", "@4", "@5", "@6", "@7", "@8", "identifier", "unop", + "expr", "exprlist", "nonnull_exprlist", "unary_expr", "sizeof", + "alignof", "cast_expr", "@9", "expr_no_commas", "@10", "@11", "@12", + "@13", "@14", "primary", "@15", "string", "old_style_parm_decls", + "lineno_datadecl", "datadecls", "datadecl", "lineno_decl", "decls", + "setspecs", "setattrs", "decl", "typed_declspecs", "reserved_declspecs", + "typed_declspecs_no_prefix_attr", "reserved_declspecs_no_prefix_attr", + "declmods", "declmods_no_prefix_attr", "typed_typespecs", + "reserved_typespecquals", "typespec", "typespecqual_reserved", + "initdecls", "notype_initdecls", "maybeasm", "initdcl", "@16", + "notype_initdcl", "@17", "maybe_attribute", "attributes", "attribute", + "attribute_list", "attrib", "any_word", "init", "@18", + "initlist_maybe_comma", "initlist1", "initelt", "@19", "initval", "@20", + "designator_list", "designator", "nested_function", "@21", "@22", + "notype_nested_function", "@23", "@24", "declarator", + "after_type_declarator", "parm_declarator", "notype_declarator", + "struct_head", "union_head", "enum_head", "structsp", "@25", "@26", + "@27", "@28", "maybecomma", "maybecomma_warn", "component_decl_list", + "component_decl_list2", "component_decl", "components", + "component_declarator", "enumlist", "enumerator", "typename", "absdcl", + "nonempty_type_quals", "type_quals", "absdcl1", "stmts", + "lineno_stmt_or_labels", "xstmts", "errstmt", "pushlevel", + "maybe_label_decls", "label_decls", "label_decl", "compstmt_or_error", + "compstmt_start", "compstmt", "simple_if", "if_prefix", "do_stmt_start", + "@29", "save_filename", "save_lineno", "lineno_labeled_stmt", + "lineno_stmt_or_label", "stmt_or_label", "stmt", "@30", "@31", "@32", + "@33", "@34", "@35", "@36", "all_iter_stmt", "all_iter_stmt_simple", + "@37", "label", "maybe_type_qual", "xexpr", "asm_operands", + "nonnull_asm_operands", "asm_operand", "asm_clobbers", "parmlist", "@38", + "parmlist_1", "@39", "parmlist_2", "parms", "parm", + "parmlist_or_identifiers", "@40", "parmlist_or_identifiers_1", + "identifiers", "identifiers_or_typenames", "extension", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 61, 290, 63, 58, 291, + 292, 124, 94, 38, 293, 294, 295, 296, 43, 45, + 42, 47, 37, 297, 298, 299, 300, 46, 40, 91, + 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 315, 316, 41, 59, 125, 126, + 33, 44, 123, 93 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 84, 85, 85, 87, 86, 88, 86, 89, 89, + 89, 89, 90, 90, 90, 90, 90, 90, 90, 90, + 92, 93, 91, 91, 94, 95, 91, 91, 96, 97, + 91, 91, 98, 98, 99, 99, 99, 99, 99, 99, + 99, 100, 101, 101, 102, 102, 103, 103, 103, 103, + 103, 103, 103, 103, 103, 103, 103, 104, 105, 106, + 106, 107, 106, 108, 108, 108, 108, 108, 108, 108, + 108, 108, 108, 108, 108, 108, 109, 108, 110, 108, + 111, 112, 108, 113, 108, 108, 108, 114, 114, 114, + 114, 114, 115, 114, 114, 114, 114, 114, 114, 114, + 116, 116, 117, 117, 117, 118, 119, 119, 119, 119, + 120, 120, 120, 120, 121, 122, 122, 122, 122, 123, + 124, 125, 125, 125, 125, 125, 125, 125, 126, 126, + 127, 127, 127, 127, 128, 128, 129, 129, 129, 130, + 130, 130, 130, 131, 131, 131, 131, 132, 132, 133, + 133, 134, 134, 134, 134, 134, 135, 135, 135, 136, + 136, 137, 137, 138, 138, 140, 139, 139, 142, 141, + 141, 143, 143, 144, 144, 145, 146, 146, 147, 147, + 147, 147, 147, 148, 148, 148, 148, 149, 150, 149, + 149, 151, 151, 152, 152, 153, 153, 154, 153, 153, + 156, 155, 155, 155, 157, 157, 158, 158, 158, 160, + 161, 159, 163, 164, 162, 165, 165, 166, 166, 166, + 166, 166, 166, 166, 167, 167, 167, 167, 167, 167, + 167, 168, 168, 168, 168, 168, 168, 168, 168, 169, + 169, 170, 170, 171, 171, 173, 172, 172, 172, 174, + 172, 172, 172, 175, 172, 176, 172, 172, 177, 177, + 178, 178, 179, 179, 180, 180, 180, 181, 181, 181, + 181, 181, 181, 182, 182, 183, 183, 183, 184, 184, + 184, 185, 185, 186, 186, 187, 187, 188, 188, 189, + 189, 190, 190, 190, 190, 190, 190, 190, 190, 190, + 191, 192, 192, 192, 193, 193, 194, 195, 196, 196, + 197, 197, 198, 199, 199, 200, 201, 201, 201, 201, + 202, 202, 203, 205, 204, 206, 207, 208, 208, 209, + 210, 210, 211, 211, 211, 212, 211, 211, 211, 213, + 214, 211, 211, 211, 215, 216, 217, 211, 218, 211, + 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, + 211, 219, 221, 220, 222, 222, 222, 222, 223, 223, + 224, 224, 225, 225, 226, 226, 227, 228, 228, 230, + 229, 231, 232, 231, 231, 233, 233, 233, 233, 234, + 234, 235, 235, 235, 235, 235, 237, 236, 238, 238, + 239, 239, 240, 240, 241 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 0, 1, 0, 2, 0, 3, 1, 1, + 5, 2, 3, 4, 4, 2, 2, 2, 2, 1, + 0, 0, 7, 4, 0, 0, 7, 4, 0, 0, + 6, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 1, 1, 3, 1, 2, 2, 2, + 2, 2, 4, 2, 4, 2, 2, 1, 1, 1, + 4, 0, 7, 1, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 0, 4, 0, 4, + 0, 0, 7, 0, 5, 3, 3, 1, 1, 1, + 3, 3, 0, 4, 4, 4, 3, 3, 2, 2, + 1, 2, 0, 1, 2, 3, 1, 1, 2, 2, + 4, 4, 2, 2, 3, 1, 1, 2, 2, 0, + 0, 4, 4, 3, 3, 2, 2, 2, 2, 3, + 0, 2, 2, 2, 2, 3, 0, 2, 2, 1, + 1, 2, 2, 1, 1, 2, 2, 2, 3, 0, + 2, 1, 1, 1, 4, 4, 1, 1, 1, 1, + 3, 1, 3, 0, 4, 0, 6, 3, 0, 6, + 3, 0, 1, 1, 2, 6, 1, 3, 0, 1, + 4, 6, 4, 1, 1, 1, 1, 1, 0, 4, + 1, 0, 2, 1, 3, 3, 2, 0, 4, 1, + 0, 4, 1, 1, 1, 2, 2, 5, 3, 0, + 0, 5, 0, 0, 5, 1, 1, 3, 3, 4, + 3, 3, 3, 1, 3, 4, 4, 3, 3, 3, + 1, 3, 3, 3, 4, 4, 3, 3, 1, 1, + 2, 1, 2, 1, 2, 0, 7, 5, 2, 0, + 7, 5, 2, 0, 8, 0, 7, 2, 0, 1, + 0, 1, 1, 2, 0, 3, 2, 3, 1, 3, + 1, 1, 2, 1, 3, 4, 6, 5, 1, 3, + 1, 1, 3, 2, 2, 0, 1, 1, 2, 0, + 2, 3, 3, 2, 3, 4, 3, 2, 3, 2, + 1, 1, 2, 2, 0, 1, 2, 0, 0, 1, + 1, 2, 3, 1, 2, 1, 2, 6, 5, 5, + 2, 2, 4, 0, 4, 0, 0, 3, 4, 3, + 1, 1, 1, 1, 2, 0, 4, 1, 3, 0, + 0, 7, 5, 2, 0, 0, 0, 12, 0, 6, + 2, 2, 2, 3, 6, 8, 10, 12, 3, 4, + 1, 1, 0, 6, 3, 5, 2, 3, 0, 1, + 0, 1, 0, 1, 1, 3, 4, 1, 3, 0, + 2, 2, 0, 4, 2, 0, 1, 1, 3, 1, + 3, 4, 4, 4, 4, 4, 0, 2, 1, 2, + 1, 3, 1, 3, 1 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint16 yydefact[] = +{ + 4, 0, 6, 0, 1, 0, 0, 153, 144, 151, + 143, 243, 239, 241, 0, 0, 0, 404, 19, 5, + 9, 8, 0, 119, 119, 139, 130, 140, 173, 0, + 0, 0, 152, 0, 7, 17, 18, 244, 240, 242, + 0, 0, 0, 238, 289, 0, 0, 161, 120, 0, + 16, 0, 15, 0, 141, 130, 142, 146, 145, 128, + 174, 32, 33, 264, 248, 264, 252, 255, 257, 11, + 87, 88, 100, 57, 58, 0, 0, 0, 34, 36, + 35, 0, 38, 37, 0, 39, 40, 0, 0, 41, + 59, 0, 0, 63, 44, 46, 89, 0, 287, 0, + 285, 149, 0, 285, 178, 0, 0, 12, 0, 0, + 31, 0, 396, 0, 0, 171, 223, 289, 0, 0, + 159, 120, 0, 215, 216, 0, 0, 129, 132, 156, + 157, 131, 133, 158, 0, 0, 245, 0, 249, 0, + 253, 55, 56, 50, 47, 0, 0, 0, 0, 49, + 0, 0, 0, 51, 0, 53, 0, 0, 80, 78, + 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 99, 98, 0, 42, 0, 0, 101, + 48, 154, 289, 379, 0, 283, 286, 147, 155, 288, + 149, 284, 184, 185, 186, 183, 0, 176, 179, 290, + 233, 232, 162, 163, 237, 0, 231, 0, 0, 236, + 0, 0, 29, 0, 325, 107, 326, 170, 172, 0, + 0, 14, 0, 0, 23, 0, 171, 396, 0, 13, + 27, 0, 171, 271, 266, 119, 263, 119, 0, 264, + 171, 264, 280, 281, 260, 278, 0, 91, 90, 315, + 307, 0, 0, 10, 45, 0, 0, 85, 86, 0, + 0, 0, 0, 74, 75, 73, 72, 71, 70, 69, + 64, 65, 66, 67, 68, 96, 0, 43, 0, 97, + 293, 0, 297, 0, 299, 0, 379, 0, 150, 148, + 0, 178, 42, 0, 0, 400, 386, 119, 119, 398, + 0, 387, 389, 397, 0, 234, 235, 306, 0, 109, + 104, 108, 0, 168, 221, 217, 160, 222, 21, 167, + 218, 220, 0, 25, 247, 325, 265, 325, 272, 0, + 251, 0, 0, 261, 0, 260, 316, 308, 93, 61, + 60, 52, 54, 0, 0, 79, 77, 94, 95, 292, + 291, 380, 298, 294, 296, 0, 175, 177, 87, 0, + 164, 384, 285, 285, 381, 382, 0, 399, 0, 0, + 30, 313, 105, 119, 119, 136, 0, 0, 165, 219, + 0, 267, 273, 326, 269, 171, 171, 282, 279, 171, + 0, 0, 0, 309, 310, 0, 81, 84, 295, 180, + 0, 182, 230, 289, 379, 120, 171, 171, 171, 289, + 171, 171, 0, 388, 390, 401, 314, 112, 0, 113, + 0, 136, 134, 190, 188, 187, 169, 22, 0, 26, + 325, 0, 246, 250, 256, 171, 402, 0, 0, 0, + 325, 0, 0, 116, 326, 301, 311, 203, 87, 0, + 0, 200, 0, 202, 0, 258, 193, 199, 0, 0, + 0, 0, 293, 0, 396, 0, 391, 392, 393, 293, + 394, 395, 383, 0, 0, 163, 135, 138, 137, 0, + 166, 274, 0, 171, 254, 312, 0, 318, 118, 117, + 305, 0, 319, 303, 326, 302, 0, 206, 0, 0, + 197, 62, 0, 192, 0, 205, 196, 82, 181, 228, + 289, 229, 224, 0, 227, 0, 110, 111, 0, 171, + 0, 275, 403, 317, 0, 153, 0, 339, 323, 0, + 0, 0, 0, 0, 0, 0, 0, 368, 360, 0, + 0, 114, 119, 119, 332, 337, 0, 0, 329, 330, + 333, 361, 331, 0, 0, 208, 0, 0, 194, 195, + 0, 225, 226, 189, 277, 171, 0, 0, 325, 370, + 0, 0, 366, 350, 351, 352, 0, 0, 0, 369, + 0, 171, 334, 125, 0, 126, 0, 0, 321, 326, + 320, 343, 0, 127, 0, 201, 198, 276, 0, 0, + 0, 371, 46, 0, 0, 0, 364, 353, 0, 358, + 0, 367, 0, 123, 209, 0, 124, 212, 338, 325, + 0, 0, 207, 322, 0, 324, 362, 344, 348, 0, + 359, 0, 121, 0, 122, 0, 336, 327, 325, 0, + 340, 325, 370, 325, 365, 372, 0, 210, 213, 328, + 342, 325, 363, 0, 349, 0, 0, 373, 374, 354, + 0, 0, 341, 345, 0, 372, 0, 0, 211, 214, + 370, 0, 0, 355, 375, 0, 376, 0, 0, 346, + 377, 0, 356, 325, 0, 0, 347, 357, 378 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 1, 2, 3, 5, 19, 20, 21, 225, 377, + 231, 380, 114, 308, 452, 87, 146, 276, 89, 90, + 91, 92, 93, 395, 94, 262, 261, 259, 460, 260, + 95, 147, 96, 212, 213, 214, 372, 439, 440, 22, + 109, 541, 297, 59, 373, 422, 298, 25, 100, 187, + 26, 131, 119, 46, 115, 120, 428, 47, 376, 217, + 218, 28, 196, 197, 198, 426, 479, 454, 455, 456, + 557, 457, 499, 458, 459, 613, 633, 660, 616, 635, + 661, 203, 123, 509, 124, 29, 30, 31, 32, 239, + 241, 246, 139, 503, 334, 134, 135, 236, 381, 382, + 244, 245, 102, 185, 103, 105, 186, 441, 442, 491, + 215, 337, 392, 393, 394, 370, 250, 371, 545, 546, + 547, 568, 589, 312, 590, 445, 548, 549, 619, 567, + 651, 642, 670, 683, 643, 550, 551, 641, 552, 580, + 603, 656, 657, 658, 681, 282, 283, 299, 412, 300, + 301, 302, 206, 207, 303, 304, 437, 97 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -470 +static const yytype_int16 yypact[] = +{ + 72, 86, 93, 2287, -470, 2287, 212, -470, -470, -470, + -470, 149, 149, 149, 67, 101, 135, -470, -470, -470, + -470, -470, 429, 141, 209, 228, -470, 149, -470, 57, + 60, 66, -470, 2287, -470, -470, -470, 149, 149, 149, + 2113, 2047, 138, -470, -470, 429, 99, -470, 149, 1376, + -470, 378, -470, 429, 228, -470, 149, -470, -470, 695, + -470, -470, -470, -470, 143, -470, 159, -470, 170, -470, + -470, -470, -470, -470, -470, 2113, 2113, 298, -470, -470, + -470, 2113, -470, -470, 1080, -470, -470, 2113, 182, 186, + -470, 2165, 2198, -470, 2375, 1369, 268, 2113, -470, 203, + 153, -470, 239, 575, 538, 459, 116, -470, 378, 429, + -470, 246, -470, 1451, 771, 149, -470, -470, 378, 118, + -470, 149, 328, 280, 387, 129, 1438, 695, -470, -470, + -470, -470, 149, -470, 267, 1577, -470, 272, -470, 436, + -470, -470, -470, -470, -470, 283, 290, 318, 302, -470, + 303, 2113, 1080, -470, 1080, -470, 2113, 2113, 350, -470, + -470, 2113, 2113, 2113, 2113, 2113, 2113, 2113, 2113, 2113, + 2113, 2113, 2113, -470, -470, 298, 2113, 2113, 298, -470, + -470, -470, -470, 153, 1513, -470, 405, 313, -470, -470, + -470, -470, -470, -470, -470, -470, 110, -470, 363, -470, + 387, -470, -470, 399, 387, 420, -470, 1628, 1566, -470, + 351, 380, -470, 468, 52, -470, -470, 403, 149, 178, + 217, -470, 378, 378, -470, 771, 149, -470, 1619, -470, + -470, 771, 149, -470, -470, 437, 384, 340, 1736, -470, + 149, -470, -470, 430, 390, -470, 436, -470, -470, -470, + 398, 392, 1991, -470, 2375, 407, 412, 2375, 2375, 2113, + 452, 2113, 2113, 2280, 757, 888, 1280, 1161, 547, 547, + 364, 364, -470, -470, -470, -470, 417, 186, 416, -470, + 119, 241, -470, 1681, -470, 418, -470, 1672, -470, 313, + 435, 538, 2231, 78, 440, -470, -470, -470, 1144, -470, + 451, 150, -470, -470, 162, -470, -470, -470, 56, -470, + -470, -470, 1345, -470, 280, -470, -470, 280, -470, 478, + -470, -470, 445, -470, -470, -470, -470, -470, -470, 460, + -470, 470, 2113, 298, 471, 390, -470, 486, -470, -470, + -470, -470, -470, 487, 2113, 1963, 2136, -470, -470, 405, + -470, -470, -470, -470, -470, 472, -470, -470, 168, 475, + -470, -470, 278, 361, -470, -470, 667, -470, 550, 318, + -470, -470, -470, 479, 1003, -470, 1313, 56, -470, -470, + 56, 483, -470, -470, 483, 149, 149, 2375, -470, 149, + 490, 298, 715, 486, -470, 1136, -470, 1751, -470, -470, + 2113, -470, -470, -470, 361, 149, 49, 53, 149, -470, + 53, 149, 1681, -470, -470, -470, -470, -470, 378, -470, + 429, -470, 579, -470, -470, 2375, -470, -470, 1313, -470, + -470, 293, -470, -470, -470, 149, -470, 232, 443, 635, + 491, 493, 809, -470, -470, -470, -470, -470, 535, 298, + 2113, -470, 536, 2375, 497, 496, -470, -470, 167, 1254, + 2113, 193, 394, 447, -470, 1725, -470, -470, -470, 354, + -470, -470, -470, 233, 296, 61, 579, -470, -470, 1136, + -470, -470, 2113, 37, -470, -470, 298, -470, -470, -470, + -470, 500, -470, -470, -470, -470, 1859, -470, 2311, 1136, + -470, -470, 1195, -470, 1367, -470, -470, 1751, -470, 465, + -470, 465, -470, 1778, -470, 507, -470, -470, 523, 2356, + 2113, -470, -470, -470, 1939, 566, 573, -470, -470, 574, + 577, 2113, 570, 560, 590, 2080, 77, 644, -470, 632, + 599, -470, 605, 899, -470, 670, 941, 65, -470, -470, + -470, -470, -470, 867, 2113, -470, 609, 1367, -470, -470, + 372, -470, -470, -470, -470, 2356, 2113, 633, -470, 2113, + 2113, 1803, -470, -470, -470, -470, 613, 2113, 615, -470, + 636, 149, -470, -470, 378, -470, 429, 1024, -470, -470, + -470, -470, 2113, -470, 2330, -470, -470, -470, 620, 2113, + 681, -470, 569, 622, 627, 2113, -470, -470, 628, -470, + 2113, -470, 306, -470, 477, 326, -470, 1041, -470, -470, + 1939, 630, -470, -470, 655, -470, -470, -470, -470, 1883, + -470, 39, -470, 771, -470, 771, -470, -470, -470, 673, + -470, -470, 2113, -470, -470, 738, 674, -470, -470, -470, + -470, -470, -470, 675, -470, 646, 54, 672, -470, -470, + 318, 318, -470, -470, 2113, 738, 677, 738, -470, -470, + 2113, 680, 95, -470, -470, 683, -470, 420, 684, -470, + 268, 197, -470, -470, 685, 420, -470, -470, 268 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -470, -470, -470, -470, -470, 157, -470, -470, -470, -470, + -470, -470, -470, -470, -26, -470, -40, 474, -128, 442, + -470, -470, 9, -470, 449, -470, -470, -470, -470, -470, + 188, -470, -183, -202, 546, -470, -470, 327, -470, -3, + -102, 218, 4, 719, -470, 349, 7, -7, -77, 589, + 18, -154, -377, -51, -106, -56, -470, -470, -470, -123, + 23, 62, -470, 489, -470, 358, -470, -363, -470, 285, + -470, -410, -470, -470, 324, -470, -470, -470, -470, -470, + -470, -37, -63, -312, -14, -470, -470, -470, -29, -470, + -470, -470, -470, -470, 453, -41, -470, 551, 463, 366, + 545, 481, -30, -92, -70, -111, -151, 371, -470, -470, + -188, -470, -470, -470, 422, -237, -470, -129, -470, -470, + -470, -470, -68, -339, -454, 356, -470, 196, -470, -470, + -470, -470, -470, -470, -470, -470, -470, -470, 199, -470, + -469, 156, -470, 155, -470, 537, -470, -245, -470, -470, + -470, 473, -200, -470, -470, -470, -470, 10 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -386 +static const yytype_int16 yytable[] = +{ + 88, 99, 125, 64, 66, 68, 219, 23, 49, 23, + 24, 191, 24, 33, 122, 33, 226, 54, 251, 223, + 51, 53, 293, 318, 137, 309, 27, 320, 27, 323, + 133, 106, 281, 288, 37, 38, 39, 23, 351, 126, + 24, 473, 55, 33, 431, 48, 216, 56, 277, 506, + 406, 143, 202, -103, 148, 220, 27, 369, 235, 101, + 61, 62, 310, 61, 62, 237, 591, 16, 48, 61, + 62, 280, -2, 210, 121, 520, 48, 645, 195, 16, + 61, 62, 132, 16, 141, 142, 4, 179, 111, 60, + 144, 200, 665, -3, 559, 204, 149, 226, 133, 60, + 60, 60, 101, 319, 106, 496, 180, 464, 465, 324, + 60, 112, 113, 243, 600, 646, 518, 330, 60, 112, + 113, 190, 255, 592, 256, 40, 199, 577, 48, 349, + 666, 121, 48, 677, -103, 288, 556, 278, 249, 63, + 427, 121, 65, 429, 285, 238, 216, 596, 67, 275, + 132, 511, 279, 101, 360, 524, 314, 216, 133, 41, + 317, 235, 34, 216, 277, 636, 316, 472, 237, 182, + 101, 678, 101, 653, 112, 113, 107, 183, 184, 16, + 108, 43, 116, 60, 649, 199, 290, 652, 322, 654, + 69, 291, 201, 42, 60, 221, 104, 662, 329, 222, + 331, 675, 504, 182, 443, 200, 229, 612, 16, 204, + 108, 183, 184, 7, 8, 9, 10, 144, 50, 343, + 243, 11, 12, 13, 449, 136, 450, 365, 117, 686, + 27, 366, 325, 57, 327, 58, 118, 15, 367, 16, + 416, 138, 121, 368, 399, 121, 121, 355, 238, 400, + 620, 488, 140, 281, 493, 190, 101, 383, 150, 383, + 133, 340, 432, 433, 512, 195, 434, 151, 478, 508, + 408, 411, 461, 684, 151, 227, 228, 179, 685, 181, + 60, 43, 402, 466, 467, 468, 52, 470, 471, 35, + 36, 54, 462, 315, 362, 363, 43, 116, 469, 286, + 287, 61, 62, 463, 205, 374, 27, 243, 16, 485, + 516, 349, 484, 486, 222, 188, 55, 350, 349, 129, + 130, 56, 478, 16, 444, 11, 12, 13, 403, 224, + 375, 482, -20, -20, -20, -20, 404, 184, 227, 228, + -20, -20, -20, 117, 7, 232, 9, 189, 407, 410, + 240, 118, 11, 12, 13, 111, -20, 43, -163, 247, + 521, 199, 383, -163, 43, 436, 248, 544, 15, 474, + 418, 420, 444, 517, 494, 43, 402, 108, 252, 199, + 253, 43, 116, 632, 16, 405, 48, 222, -83, 27, + 106, 16, 421, 133, 483, 544, 564, 43, 402, 560, + 249, 199, 16, 634, 409, -163, 475, 108, 16, -163, + -20, 409, 404, 184, 170, 171, 172, -270, -270, 404, + 184, 292, 510, 497, 16, 515, 111, 48, 117, 72, + 45, 647, 43, 648, 306, 27, 118, 242, 313, 61, + 62, 121, 597, 48, 403, 112, 113, 133, 200, 204, + 43, 402, 404, 184, 121, 200, 540, 307, 611, 16, + 522, 326, 43, 286, 287, 332, 199, 60, 338, 211, + 539, 333, -106, -106, -106, -106, 336, 16, -106, 44, + -106, -106, -106, 341, 540, 405, 405, 45, 342, 16, + 344, 544, 48, 347, 680, 576, -106, 510, 539, 348, + 542, 352, 688, 543, 111, 45, 553, -163, 226, 44, + 578, 356, -163, 378, -268, -268, 361, 45, 391, 27, + 307, 487, 144, 464, 465, 396, 598, 364, 379, 601, + 604, 668, 669, 153, 155, 615, 54, 608, 385, 584, + 586, 61, 62, 192, 193, 194, 200, 614, 386, 389, + -106, 401, 621, 415, -163, 398, 417, 542, -163, 624, + 543, 55, 180, 553, 430, 216, 56, 216, 435, -304, + 631, 492, 617, -32, 500, 501, 27, 502, 523, 7, + 540, 9, 189, 405, 477, 129, 130, 11, 12, 13, + 562, 11, 12, 13, 539, 168, 169, 170, 171, 172, + 254, 563, 601, 15, -33, 257, 258, 121, 572, 48, + 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 274, 173, 174, 671, 182, 175, 176, 177, 178, + 601, 566, 569, 183, 184, 570, 211, 573, -115, -115, + -115, -115, -115, -115, -115, 626, -115, -115, -115, -115, + -115, 579, -115, -115, -115, -115, -115, -115, -115, -115, + -115, -115, -115, -115, -115, -115, -115, 574, -115, -115, + 581, 7, 8, 9, 10, -115, 582, 413, -115, 11, + 12, 13, 583, -115, -115, -115, 587, 595, -115, -115, + 607, 599, 609, -115, 610, 15, 623, 16, 625, 627, + 128, 129, 130, 628, 664, 630, 639, 11, 12, 13, + 345, 346, -115, -115, -115, -115, 438, -115, -325, -325, + -325, -325, -325, -325, -325, 16, -325, -325, -325, -325, + -325, 640, -325, -325, -325, -325, -325, -325, -325, -325, + -325, -325, -325, -325, -325, -325, -325, 655, -325, -325, + 650, 659, 663, 667, 673, -325, 676, 602, -325, 679, + 311, 682, 687, -325, -325, -325, 359, 489, -325, -325, + 476, 593, 211, -325, 127, -325, -325, -325, -325, 289, + 357, 387, 505, -325, -325, -325, 480, 558, 390, 328, + 384, 335, -325, 397, -325, -325, 481, -325, 495, -325, + 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, + 211, 490, -325, -325, 388, 446, 637, -325, -325, 638, + -325, 672, 674, 353, -325, 425, -325, -325, -325, -325, + -325, -325, -325, -325, -325, -325, -325, 0, -325, 414, + -325, 0, -325, -325, 453, 0, 0, 0, 0, -325, + 0, 0, -325, -102, 0, 0, 0, -325, -325, -325, + 0, 0, -325, -325, 0, 0, 0, -325, 0, 0, + 70, 7, 8, 9, 10, 71, 72, 425, 73, 11, + 12, 13, 0, 0, 0, 0, -325, -300, -325, -325, + 0, -325, 0, 0, 0, 15, 74, 16, 17, 498, + 75, 76, 0, 7, 8, 9, 10, 77, 453, 507, + 78, 11, 12, 13, 0, 79, 80, 81, 0, 0, + 82, 83, 0, 0, 0, 84, 0, 15, 453, 16, + 0, 519, 164, 165, 166, 167, 168, 169, 170, 171, + 172, 0, 588, 0, -325, -325, 85, 86, 453, -325, + -325, 453, -325, 453, 0, 0, -325, 0, -325, -325, + -325, -325, -325, -325, -325, -325, -325, -325, -325, 565, + -325, 0, -325, 0, -325, -325, 585, 0, 0, 0, + 571, -325, 0, 0, -325, 0, 0, 0, 0, -325, + -325, -325, 0, 0, -325, -325, 0, 0, 0, -325, + 0, 0, 0, 594, 0, 0, 453, 7, 57, 9, + 58, 0, 0, 0, 0, 11, 12, 13, -325, 0, + -325, -325, 0, -325, 0, 618, 0, -335, -335, 0, + 0, 15, -335, -335, 0, -335, 0, 0, 0, -335, + 0, -335, -335, -335, -335, -335, -335, -335, -335, -335, + -335, -335, 0, -335, 629, -335, 0, -335, -335, 0, + 0, 0, 0, 0, -335, 0, 0, -335, 111, 0, + 0, -163, -335, -335, -335, 0, -163, -335, -335, 0, + 419, 145, -335, 70, 7, 0, 9, 98, 71, 72, + 0, 73, 11, 12, 13, 0, 0, 0, 0, 112, + 113, -335, 0, -335, -335, 0, -335, 0, 15, 74, + 0, 17, 0, 75, 76, 0, 0, 0, -163, 0, + 77, 0, -163, 78, 0, 0, 0, 0, 79, 80, + 81, 0, 0, 82, 83, 0, 0, 447, 84, 448, + 62, 0, 0, 0, 71, 72, 0, 73, 7, 8, + 9, 10, 0, 0, 0, 0, 11, 12, 13, 85, + 86, 0, -92, 0, 0, 74, 0, 17, 0, 75, + 76, 0, 15, 0, 16, 0, 77, 0, 0, 78, + 0, 0, 0, 0, 79, 80, 81, 0, 0, 82, + 83, 0, 0, 449, 84, 450, 447, 0, 448, 62, + 0, 0, 0, 71, 72, 0, 73, 166, 167, 168, + 169, 170, 171, 172, -191, 85, 86, 0, 451, 0, + 0, 0, 0, 0, 74, 0, 17, 0, 75, 76, + 0, 0, 0, 0, 0, 77, 0, 0, 78, 0, + 0, 0, 0, 79, 80, 81, 0, 0, 82, 83, + 0, 0, 449, 84, 450, 447, 0, 70, 0, 0, + 0, 0, 71, 72, 0, 73, 0, 0, 0, 0, + 0, 0, 0, -259, 85, 86, 0, 451, 0, 0, + 0, 0, 0, 74, 0, 17, 0, 75, 76, -204, + 0, 0, 0, 0, 77, 0, 0, 78, 0, 0, + 0, 0, 79, 80, 81, 0, 0, 82, 83, 0, + 0, -204, 84, -204, 423, 0, 70, 0, 0, 0, + 0, 71, 72, 0, 73, 165, 166, 167, 168, 169, + 170, 171, 172, 85, 86, 0, 451, 0, 0, 0, + 0, 0, 74, 0, 17, 0, 75, 76, 0, 7, + 8, 9, 10, 77, 0, 0, 78, 11, 12, 13, + 0, 79, 80, 81, 0, 0, 82, 83, 447, 0, + 70, 84, 0, 15, 0, 71, 72, 110, 73, 0, + -28, -28, -28, -28, 0, 0, 0, 0, -28, -28, + -28, 0, 85, 86, 0, 424, 74, 0, 17, 0, + 75, 76, 0, 111, -28, 0, -163, 77, 0, 0, + 78, -163, 0, 0, 0, 79, 80, 81, 0, 0, + 82, 83, 173, 174, 0, 84, 175, 176, 177, 178, + 0, 0, 0, 0, 112, 113, 0, 0, 0, 230, + 0, 0, -24, -24, -24, -24, 85, 86, 0, 451, + -24, -24, -24, -163, 70, 0, 0, -163, -28, 71, + 72, 0, 73, 0, 0, 111, -24, 0, -163, 0, + 0, 0, 0, -163, 0, 0, 0, 0, 0, 0, + 74, 0, 17, 0, 75, 76, 0, 0, 0, 0, + 0, 77, 0, 0, 78, 0, 112, 113, 0, 79, + 80, 208, 0, 0, 82, 83, 0, 0, 0, 84, + 0, 0, 0, 0, 0, -163, 70, 0, 0, -163, + -24, 71, 72, 0, 73, 0, 0, 0, 0, 0, + 85, 86, 0, 0, 209, 0, 0, 0, 0, 0, + 0, 0, 74, 0, 17, 0, 75, 76, 0, 0, + 0, 0, 0, 77, 0, 0, 78, 0, 0, 0, + 0, 79, 80, 81, 0, 0, 82, 83, 0, 70, + 0, 84, 0, 0, 71, 72, 0, 73, 233, 0, + 0, 7, 0, 9, 98, 0, 0, 0, 0, 11, + 12, 13, 85, 86, 0, 74, 284, 17, 0, 75, + 76, 0, 0, 0, 0, 15, 77, 0, 17, 78, + 0, 0, 0, 0, 79, 80, 81, 0, 0, 82, + 83, 0, 70, 0, 84, 0, 0, 71, 72, 294, + 73, 295, 7, 8, 9, 10, 0, 0, 296, 0, + 11, 12, 13, 0, 0, 85, 86, 0, 74, 305, + 17, 0, 75, 76, 234, -262, 15, 0, 16, 77, + 0, 0, 78, 0, 0, 0, 0, 79, 80, 81, + 0, 0, 82, 83, 0, 70, 0, 84, 0, 0, + 71, 72, 294, 73, 0, 7, 8, 9, 10, 0, + 0, 296, 0, 11, 12, 13, 0, 0, 85, 86, + 0, 74, 321, 17, -385, 75, 76, 0, 0, 15, + 0, 16, 77, 0, 0, 78, 0, 0, 0, 0, + 79, 80, 81, 0, 0, 82, 83, 0, 70, 0, + 84, 0, 0, 71, 72, 0, 73, 233, 0, 0, + 7, 0, 9, 98, 0, 0, 0, 0, 11, 12, + 13, 85, 86, 0, 74, 354, 17, -385, 75, 76, + 0, 0, 0, 0, 15, 77, 0, 17, 78, 0, + 0, 0, 0, 79, 80, 513, 0, 0, 82, 83, + 0, 70, 0, 84, 0, 0, 71, 72, 158, 73, + 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 85, 86, 0, 74, 514, 17, + 0, 75, 76, 605, 0, 0, 0, 0, 77, 0, + 0, 78, 0, 0, 0, 0, 79, 80, 81, 0, + 0, 82, 83, 0, 0, 0, 84, 0, 156, 157, + 158, 606, 159, 160, 161, 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 0, 85, 86, 0, + 0, 561, 448, 525, 8, 9, 10, 71, 72, 0, + 73, 11, 12, 13, 526, 0, 527, 528, 529, 530, + 531, 532, 533, 534, 535, 536, 537, 15, 74, 16, + 17, 0, 75, 76, 0, 0, 0, 0, 0, 77, + 0, 0, 78, 0, 0, 0, 0, 79, 80, 81, + 0, 0, 82, 83, 0, 0, 0, 84, 156, 157, + 158, 644, 159, 160, 161, 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 538, 0, 85, 86, + 0, 249, 448, 62, 0, 0, 0, 71, 72, 0, + 73, 0, 0, 0, 526, 0, 527, 528, 529, 530, + 531, 532, 533, 534, 535, 536, 537, 0, 74, 0, + 17, 0, 75, 76, 0, 0, 0, 0, 0, 77, + 0, 0, 78, 0, 0, 0, 0, 79, 80, 81, + 0, 0, 82, 83, 70, 0, 0, 84, 0, 71, + 72, 0, 73, 160, 161, 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 538, 0, 85, 86, + 74, 249, 17, 0, 75, 76, 0, 0, 0, 0, + 0, 77, 0, 0, 78, 0, 0, 0, 0, 79, + 80, 81, 0, 0, 82, 83, 0, 0, 0, 84, + 70, 7, 0, 9, 98, 71, 72, 0, 73, 11, + 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, + 85, 86, 0, 339, 0, 15, 74, 0, 17, 0, + 75, 76, 0, 70, 0, 0, 0, 77, 71, 72, + 78, 73, 0, 0, 0, 79, 80, 81, 0, 0, + 82, 83, 0, 0, 0, 84, 0, 0, 0, 74, + 0, 17, 0, 75, 76, 0, 70, 0, 0, 0, + 77, 71, 72, 78, 73, 0, 85, 86, 79, 80, + 81, 0, 0, 82, 83, 0, 0, 0, 84, 0, + 0, 0, 74, 0, 17, 0, 75, 76, 0, 0, + 0, 0, 0, 77, 0, 0, 78, 575, 0, 85, + 86, 79, 80, 81, 0, 0, 82, 83, 70, 0, + 0, 84, 0, 71, 72, 0, 73, 161, 162, 163, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, + 0, 0, 85, 86, 74, 0, 17, 0, 75, 76, + 0, 70, 0, 0, 0, 77, 71, 72, 78, 73, + 0, 0, 0, 79, 80, 81, 0, 0, 82, 83, + 0, 0, 0, 152, 0, 0, 0, 74, 0, 17, + 0, 75, 76, 0, 358, 0, 0, 0, 77, 71, + 72, 78, 73, 0, 85, 86, 79, 80, 81, 0, + 0, 82, 83, 0, 0, 0, 154, 0, 0, 0, + 74, 0, 17, 0, 75, 76, 0, 0, 0, 0, + 0, 77, 0, 0, 78, 0, 0, 85, 86, 79, + 80, 81, 0, 0, 82, 83, 0, 0, 6, 84, + -119, 7, 8, 9, 10, 0, 0, 0, 0, 11, + 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, + 85, 86, 0, 0, 14, 15, 0, 16, 17, 0, + 0, 554, 162, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 0, 0, 0, 0, -119, 0, 0, + 0, 0, 0, 0, 0, -119, 156, 157, 158, 0, + 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 18, 156, 157, 158, 0, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 0, 0, 0, 16, 0, 0, 0, + 0, 156, 157, 158, 555, 159, 160, 161, 162, 163, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, + 156, 157, 158, 622, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172 +}; + +static const yytype_int16 yycheck[] = +{ + 40, 41, 53, 29, 30, 31, 117, 3, 22, 5, + 3, 103, 5, 3, 51, 5, 122, 24, 147, 121, + 23, 24, 205, 225, 65, 213, 3, 227, 5, 231, + 59, 45, 183, 187, 11, 12, 13, 33, 283, 53, + 33, 418, 24, 33, 383, 22, 114, 24, 176, 459, + 362, 77, 108, 1, 84, 118, 33, 1, 135, 41, + 3, 4, 10, 3, 4, 135, 1, 30, 45, 3, + 4, 182, 0, 113, 51, 38, 53, 38, 104, 30, + 3, 4, 59, 30, 75, 76, 0, 9, 27, 27, + 81, 105, 38, 0, 504, 109, 87, 203, 127, 37, + 38, 39, 84, 226, 118, 444, 97, 58, 59, 232, + 48, 58, 59, 139, 568, 76, 479, 240, 56, 58, + 59, 103, 152, 58, 154, 58, 7, 50, 105, 280, + 76, 108, 109, 38, 82, 289, 499, 177, 82, 82, + 377, 118, 82, 380, 184, 135, 214, 557, 82, 175, + 127, 463, 178, 135, 76, 494, 219, 225, 187, 58, + 223, 238, 5, 231, 292, 619, 222, 412, 238, 50, + 152, 76, 154, 642, 58, 59, 77, 58, 59, 30, + 81, 3, 4, 121, 638, 7, 76, 641, 228, 643, + 33, 81, 76, 58, 132, 77, 58, 651, 239, 81, + 241, 670, 35, 50, 392, 219, 77, 584, 30, 223, + 81, 58, 59, 4, 5, 6, 7, 208, 77, 259, + 246, 12, 13, 14, 57, 82, 59, 77, 50, 683, + 207, 81, 235, 5, 237, 7, 58, 28, 76, 30, + 369, 82, 219, 81, 76, 222, 223, 287, 238, 81, + 589, 439, 82, 404, 442, 237, 238, 325, 76, 327, + 289, 252, 385, 386, 464, 291, 389, 81, 422, 76, + 362, 363, 400, 76, 81, 58, 59, 9, 81, 76, + 218, 3, 4, 406, 407, 408, 77, 410, 411, 77, + 78, 298, 403, 76, 297, 298, 3, 4, 409, 58, + 59, 3, 4, 405, 58, 312, 283, 333, 30, 77, + 77, 462, 435, 81, 81, 76, 298, 76, 469, 6, + 7, 298, 476, 30, 392, 12, 13, 14, 50, 1, + 312, 38, 4, 5, 6, 7, 58, 59, 58, 59, + 12, 13, 14, 50, 4, 78, 6, 7, 362, 363, + 78, 58, 12, 13, 14, 27, 28, 3, 30, 76, + 483, 7, 430, 35, 3, 391, 76, 496, 28, 420, + 373, 374, 440, 77, 442, 3, 4, 81, 76, 7, + 77, 3, 4, 77, 30, 362, 363, 81, 38, 366, + 404, 30, 374, 422, 431, 524, 519, 3, 4, 510, + 82, 7, 30, 77, 50, 77, 420, 81, 30, 81, + 82, 50, 58, 59, 50, 51, 52, 77, 78, 58, + 59, 58, 50, 449, 30, 465, 27, 404, 50, 9, + 58, 633, 3, 635, 83, 412, 58, 1, 35, 3, + 4, 418, 565, 420, 50, 58, 59, 476, 462, 463, + 3, 4, 58, 59, 431, 469, 496, 77, 581, 30, + 486, 77, 3, 58, 59, 35, 7, 405, 76, 1, + 496, 81, 4, 5, 6, 7, 78, 30, 10, 50, + 12, 13, 14, 76, 524, 462, 463, 58, 76, 30, + 38, 620, 469, 76, 677, 535, 28, 50, 524, 83, + 496, 83, 685, 496, 27, 58, 496, 30, 614, 50, + 536, 76, 35, 35, 77, 78, 76, 58, 32, 496, + 77, 78, 513, 58, 59, 38, 566, 76, 83, 569, + 570, 660, 661, 91, 92, 586, 543, 577, 78, 542, + 543, 3, 4, 5, 6, 7, 560, 584, 78, 78, + 82, 76, 592, 3, 77, 83, 77, 553, 81, 599, + 553, 543, 553, 553, 81, 633, 543, 635, 78, 78, + 610, 78, 586, 38, 38, 78, 553, 81, 78, 4, + 620, 6, 7, 560, 5, 6, 7, 12, 13, 14, + 83, 12, 13, 14, 620, 48, 49, 50, 51, 52, + 151, 78, 642, 28, 38, 156, 157, 584, 38, 586, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, + 171, 172, 53, 54, 664, 50, 57, 58, 59, 60, + 670, 58, 58, 58, 59, 58, 1, 77, 3, 4, + 5, 6, 7, 8, 9, 76, 11, 12, 13, 14, + 15, 7, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 77, 33, 34, + 38, 4, 5, 6, 7, 40, 77, 10, 43, 12, + 13, 14, 77, 48, 49, 50, 16, 78, 53, 54, + 77, 58, 77, 58, 58, 28, 76, 30, 17, 77, + 5, 6, 7, 76, 58, 77, 76, 12, 13, 14, + 261, 262, 77, 78, 79, 80, 1, 82, 3, 4, + 5, 6, 7, 8, 9, 30, 11, 12, 13, 14, + 15, 76, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 9, 33, 34, + 77, 77, 77, 81, 77, 40, 76, 569, 43, 76, + 214, 77, 77, 48, 49, 50, 292, 440, 53, 54, + 421, 553, 1, 58, 55, 4, 5, 6, 7, 190, + 291, 332, 458, 12, 13, 14, 428, 502, 335, 238, + 327, 246, 77, 344, 79, 80, 430, 82, 442, 28, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 1, 440, 3, 4, 333, 393, 620, 8, 9, 620, + 11, 665, 667, 286, 15, 376, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, -1, 29, 366, + 31, -1, 33, 34, 395, -1, -1, -1, -1, 40, + -1, -1, 43, 82, -1, -1, -1, 48, 49, 50, + -1, -1, 53, 54, -1, -1, -1, 58, -1, -1, + 3, 4, 5, 6, 7, 8, 9, 428, 11, 12, + 13, 14, -1, -1, -1, -1, 77, 78, 79, 80, + -1, 82, -1, -1, -1, 28, 29, 30, 31, 450, + 33, 34, -1, 4, 5, 6, 7, 40, 459, 460, + 43, 12, 13, 14, -1, 48, 49, 50, -1, -1, + 53, 54, -1, -1, -1, 58, -1, 28, 479, 30, + -1, 482, 44, 45, 46, 47, 48, 49, 50, 51, + 52, -1, 1, -1, 3, 4, 79, 80, 499, 8, + 9, 502, 11, 504, -1, -1, 15, -1, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 520, + 29, -1, 31, -1, 33, 34, 77, -1, -1, -1, + 531, 40, -1, -1, 43, -1, -1, -1, -1, 48, + 49, 50, -1, -1, 53, 54, -1, -1, -1, 58, + -1, -1, -1, 554, -1, -1, 557, 4, 5, 6, + 7, -1, -1, -1, -1, 12, 13, 14, 77, -1, + 79, 80, -1, 82, -1, 1, -1, 3, 4, -1, + -1, 28, 8, 9, -1, 11, -1, -1, -1, 15, + -1, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, -1, 29, 605, 31, -1, 33, 34, -1, + -1, -1, -1, -1, 40, -1, -1, 43, 27, -1, + -1, 30, 48, 49, 50, -1, 35, 53, 54, -1, + 77, 1, 58, 3, 4, -1, 6, 7, 8, 9, + -1, 11, 12, 13, 14, -1, -1, -1, -1, 58, + 59, 77, -1, 79, 80, -1, 82, -1, 28, 29, + -1, 31, -1, 33, 34, -1, -1, -1, 77, -1, + 40, -1, 81, 43, -1, -1, -1, -1, 48, 49, + 50, -1, -1, 53, 54, -1, -1, 1, 58, 3, + 4, -1, -1, -1, 8, 9, -1, 11, 4, 5, + 6, 7, -1, -1, -1, -1, 12, 13, 14, 79, + 80, -1, 82, -1, -1, 29, -1, 31, -1, 33, + 34, -1, 28, -1, 30, -1, 40, -1, -1, 43, + -1, -1, -1, -1, 48, 49, 50, -1, -1, 53, + 54, -1, -1, 57, 58, 59, 1, -1, 3, 4, + -1, -1, -1, 8, 9, -1, 11, 46, 47, 48, + 49, 50, 51, 52, 78, 79, 80, -1, 82, -1, + -1, -1, -1, -1, 29, -1, 31, -1, 33, 34, + -1, -1, -1, -1, -1, 40, -1, -1, 43, -1, + -1, -1, -1, 48, 49, 50, -1, -1, 53, 54, + -1, -1, 57, 58, 59, 1, -1, 3, -1, -1, + -1, -1, 8, 9, -1, 11, -1, -1, -1, -1, + -1, -1, -1, 78, 79, 80, -1, 82, -1, -1, + -1, -1, -1, 29, -1, 31, -1, 33, 34, 35, + -1, -1, -1, -1, 40, -1, -1, 43, -1, -1, + -1, -1, 48, 49, 50, -1, -1, 53, 54, -1, + -1, 57, 58, 59, 1, -1, 3, -1, -1, -1, + -1, 8, 9, -1, 11, 45, 46, 47, 48, 49, + 50, 51, 52, 79, 80, -1, 82, -1, -1, -1, + -1, -1, 29, -1, 31, -1, 33, 34, -1, 4, + 5, 6, 7, 40, -1, -1, 43, 12, 13, 14, + -1, 48, 49, 50, -1, -1, 53, 54, 1, -1, + 3, 58, -1, 28, -1, 8, 9, 1, 11, -1, + 4, 5, 6, 7, -1, -1, -1, -1, 12, 13, + 14, -1, 79, 80, -1, 82, 29, -1, 31, -1, + 33, 34, -1, 27, 28, -1, 30, 40, -1, -1, + 43, 35, -1, -1, -1, 48, 49, 50, -1, -1, + 53, 54, 53, 54, -1, 58, 57, 58, 59, 60, + -1, -1, -1, -1, 58, 59, -1, -1, -1, 1, + -1, -1, 4, 5, 6, 7, 79, 80, -1, 82, + 12, 13, 14, 77, 3, -1, -1, 81, 82, 8, + 9, -1, 11, -1, -1, 27, 28, -1, 30, -1, + -1, -1, -1, 35, -1, -1, -1, -1, -1, -1, + 29, -1, 31, -1, 33, 34, -1, -1, -1, -1, + -1, 40, -1, -1, 43, -1, 58, 59, -1, 48, + 49, 50, -1, -1, 53, 54, -1, -1, -1, 58, + -1, -1, -1, -1, -1, 77, 3, -1, -1, 81, + 82, 8, 9, -1, 11, -1, -1, -1, -1, -1, + 79, 80, -1, -1, 83, -1, -1, -1, -1, -1, + -1, -1, 29, -1, 31, -1, 33, 34, -1, -1, + -1, -1, -1, 40, -1, -1, 43, -1, -1, -1, + -1, 48, 49, 50, -1, -1, 53, 54, -1, 3, + -1, 58, -1, -1, 8, 9, -1, 11, 1, -1, + -1, 4, -1, 6, 7, -1, -1, -1, -1, 12, + 13, 14, 79, 80, -1, 29, 83, 31, -1, 33, + 34, -1, -1, -1, -1, 28, 40, -1, 31, 43, + -1, -1, -1, -1, 48, 49, 50, -1, -1, 53, + 54, -1, 3, -1, 58, -1, -1, 8, 9, 1, + 11, 3, 4, 5, 6, 7, -1, -1, 10, -1, + 12, 13, 14, -1, -1, 79, 80, -1, 29, 83, + 31, -1, 33, 34, 77, 78, 28, -1, 30, 40, + -1, -1, 43, -1, -1, -1, -1, 48, 49, 50, + -1, -1, 53, 54, -1, 3, -1, 58, -1, -1, + 8, 9, 1, 11, -1, 4, 5, 6, 7, -1, + -1, 10, -1, 12, 13, 14, -1, -1, 79, 80, + -1, 29, 83, 31, 76, 33, 34, -1, -1, 28, + -1, 30, 40, -1, -1, 43, -1, -1, -1, -1, + 48, 49, 50, -1, -1, 53, 54, -1, 3, -1, + 58, -1, -1, 8, 9, -1, 11, 1, -1, -1, + 4, -1, 6, 7, -1, -1, -1, -1, 12, 13, + 14, 79, 80, -1, 29, 83, 31, 76, 33, 34, + -1, -1, -1, -1, 28, 40, -1, 31, 43, -1, + -1, -1, -1, 48, 49, 50, -1, -1, 53, 54, + -1, 3, -1, 58, -1, -1, 8, 9, 37, 11, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 79, 80, -1, 29, 83, 31, + -1, 33, 34, 10, -1, -1, -1, -1, 40, -1, + -1, 43, -1, -1, -1, -1, 48, 49, 50, -1, + -1, 53, 54, -1, -1, -1, 58, -1, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, -1, 79, 80, -1, + -1, 83, 3, 4, 5, 6, 7, 8, 9, -1, + 11, 12, 13, 14, 15, -1, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, -1, 33, 34, -1, -1, -1, -1, -1, 40, + -1, -1, 43, -1, -1, -1, -1, 48, 49, 50, + -1, -1, 53, 54, -1, -1, -1, 58, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 77, -1, 79, 80, + -1, 82, 3, 4, -1, -1, -1, 8, 9, -1, + 11, -1, -1, -1, 15, -1, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, -1, 29, -1, + 31, -1, 33, 34, -1, -1, -1, -1, -1, 40, + -1, -1, 43, -1, -1, -1, -1, 48, 49, 50, + -1, -1, 53, 54, 3, -1, -1, 58, -1, 8, + 9, -1, 11, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 77, -1, 79, 80, + 29, 82, 31, -1, 33, 34, -1, -1, -1, -1, + -1, 40, -1, -1, 43, -1, -1, -1, -1, 48, + 49, 50, -1, -1, 53, 54, -1, -1, -1, 58, + 3, 4, -1, 6, 7, 8, 9, -1, 11, 12, + 13, 14, -1, -1, -1, -1, -1, -1, -1, -1, + 79, 80, -1, 82, -1, 28, 29, -1, 31, -1, + 33, 34, -1, 3, -1, -1, -1, 40, 8, 9, + 43, 11, -1, -1, -1, 48, 49, 50, -1, -1, + 53, 54, -1, -1, -1, 58, -1, -1, -1, 29, + -1, 31, -1, 33, 34, -1, 3, -1, -1, -1, + 40, 8, 9, 43, 11, -1, 79, 80, 48, 49, + 50, -1, -1, 53, 54, -1, -1, -1, 58, -1, + -1, -1, 29, -1, 31, -1, 33, 34, -1, -1, + -1, -1, -1, 40, -1, -1, 43, 77, -1, 79, + 80, 48, 49, 50, -1, -1, 53, 54, 3, -1, + -1, 58, -1, 8, 9, -1, 11, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, -1, + -1, -1, 79, 80, 29, -1, 31, -1, 33, 34, + -1, 3, -1, -1, -1, 40, 8, 9, 43, 11, + -1, -1, -1, 48, 49, 50, -1, -1, 53, 54, + -1, -1, -1, 58, -1, -1, -1, 29, -1, 31, + -1, 33, 34, -1, 3, -1, -1, -1, 40, 8, + 9, 43, 11, -1, 79, 80, 48, 49, 50, -1, + -1, 53, 54, -1, -1, -1, 58, -1, -1, -1, + 29, -1, 31, -1, 33, 34, -1, -1, -1, -1, + -1, 40, -1, -1, 43, -1, -1, 79, 80, 48, + 49, 50, -1, -1, 53, 54, -1, -1, 1, 58, + 3, 4, 5, 6, 7, -1, -1, -1, -1, 12, + 13, 14, -1, -1, -1, -1, -1, -1, -1, -1, + 79, 80, -1, -1, 27, 28, -1, 30, 31, -1, + -1, 10, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, -1, -1, -1, -1, 50, -1, -1, + -1, -1, -1, -1, -1, 58, 35, 36, 37, -1, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 77, 35, 36, 37, -1, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, -1, -1, -1, 30, -1, -1, -1, + -1, 35, 36, 37, 83, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, -1, + 35, 36, 37, 83, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 85, 86, 87, 0, 88, 1, 4, 5, 6, + 7, 12, 13, 14, 27, 28, 30, 31, 77, 89, + 90, 91, 123, 126, 130, 131, 134, 144, 145, 169, + 170, 171, 172, 241, 89, 77, 78, 144, 144, 144, + 58, 58, 58, 3, 50, 58, 137, 141, 144, 168, + 77, 123, 77, 123, 131, 134, 144, 5, 7, 127, + 145, 3, 4, 82, 98, 82, 98, 82, 98, 89, + 3, 8, 9, 11, 29, 33, 34, 40, 43, 48, + 49, 50, 53, 54, 58, 79, 80, 99, 100, 102, + 103, 104, 105, 106, 108, 114, 116, 241, 7, 100, + 132, 134, 186, 188, 58, 189, 168, 77, 81, 124, + 1, 27, 58, 59, 96, 138, 4, 50, 58, 136, + 139, 144, 165, 166, 168, 137, 168, 127, 5, 6, + 7, 135, 144, 172, 179, 180, 82, 179, 82, 176, + 82, 106, 106, 98, 106, 1, 100, 115, 186, 106, + 76, 81, 58, 103, 58, 103, 35, 36, 37, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 57, 58, 59, 60, 9, + 106, 76, 50, 58, 59, 187, 190, 133, 76, 7, + 134, 187, 5, 6, 7, 98, 146, 147, 148, 7, + 168, 76, 139, 165, 168, 58, 236, 237, 50, 83, + 100, 1, 117, 118, 119, 194, 206, 143, 144, 189, + 166, 77, 81, 124, 1, 92, 138, 58, 59, 77, + 1, 94, 78, 1, 77, 132, 181, 188, 241, 173, + 78, 174, 1, 98, 184, 185, 175, 76, 76, 82, + 200, 201, 76, 77, 108, 186, 186, 108, 108, 111, + 113, 110, 109, 108, 108, 108, 108, 108, 108, 108, + 108, 108, 108, 108, 108, 98, 101, 102, 100, 98, + 189, 190, 229, 230, 83, 100, 58, 59, 135, 133, + 76, 81, 58, 116, 1, 3, 10, 126, 130, 231, + 233, 234, 235, 238, 239, 83, 83, 77, 97, 194, + 10, 118, 207, 35, 166, 76, 139, 166, 117, 143, + 236, 83, 100, 117, 143, 123, 77, 123, 181, 179, + 143, 179, 35, 81, 178, 184, 78, 195, 76, 82, + 106, 76, 76, 100, 38, 108, 108, 76, 83, 190, + 76, 231, 83, 229, 83, 100, 76, 147, 3, 101, + 76, 76, 123, 123, 76, 77, 81, 76, 81, 1, + 199, 201, 120, 128, 131, 134, 142, 93, 35, 83, + 95, 182, 183, 206, 182, 78, 78, 108, 185, 78, + 178, 32, 196, 197, 198, 107, 38, 108, 83, 76, + 81, 76, 4, 50, 58, 144, 167, 168, 187, 50, + 168, 187, 232, 10, 235, 3, 201, 77, 123, 77, + 123, 134, 129, 1, 82, 108, 149, 199, 140, 199, + 81, 207, 143, 143, 143, 78, 98, 240, 1, 121, + 122, 191, 192, 194, 206, 209, 198, 1, 3, 57, + 59, 82, 98, 108, 151, 152, 153, 155, 157, 158, + 112, 102, 189, 124, 58, 59, 143, 143, 143, 189, + 143, 143, 231, 136, 137, 168, 129, 5, 135, 150, + 149, 183, 38, 165, 143, 77, 81, 78, 194, 121, + 191, 193, 78, 194, 206, 209, 207, 98, 108, 156, + 38, 78, 81, 177, 35, 158, 155, 108, 76, 167, + 50, 167, 236, 50, 83, 100, 77, 77, 151, 108, + 38, 143, 98, 78, 207, 4, 15, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 77, 98, + 100, 125, 126, 130, 201, 202, 203, 204, 210, 211, + 219, 220, 222, 241, 10, 83, 151, 154, 153, 155, + 189, 83, 83, 78, 143, 108, 58, 213, 205, 58, + 58, 108, 38, 77, 77, 77, 100, 50, 98, 7, + 223, 38, 77, 77, 123, 77, 123, 16, 1, 206, + 208, 1, 58, 125, 108, 78, 155, 143, 100, 58, + 208, 100, 114, 224, 100, 10, 38, 77, 100, 77, + 58, 143, 136, 159, 165, 137, 162, 168, 1, 212, + 207, 100, 83, 76, 100, 17, 76, 77, 76, 108, + 77, 100, 77, 160, 77, 163, 208, 211, 222, 76, + 76, 221, 215, 218, 38, 38, 76, 117, 117, 208, + 77, 214, 208, 224, 208, 9, 225, 226, 227, 77, + 161, 164, 208, 77, 58, 38, 76, 81, 201, 201, + 216, 100, 225, 77, 227, 224, 76, 38, 76, 76, + 116, 228, 77, 217, 76, 81, 208, 77, 116 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) +#else +static void +yy_stack_print (bottom, top) + yytype_int16 *bottom; + yytype_int16 *top; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + fprintf (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + fprintf (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ + +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + +/* The look-ahead symbol. */ +int yychar; + +/* The semantic value of the look-ahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + + int yystate; + int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Look-ahead token as an internal (translated) token number. */ + int yytoken = 0; +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss = yyssa; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp; + + + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + look-ahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to look-ahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a look-ahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + if (yyn == YYFINAL) + YYACCEPT; + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the look-ahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: + + { if (pedantic) + pedwarn ("ANSI C forbids an empty source file"); + ;} + break; + + case 3: + + { + /* In case there were missing closebraces, + get us back to the global binding level. */ + while (! global_bindings_p ()) + poplevel (0, 0, 0); + ;} + break; + + case 4: + + {(yyval.ttype) = NULL_TREE; ;} + break; + + case 6: + + {(yyval.ttype) = NULL_TREE; ;} + break; + + case 10: + + { STRIP_NOPS ((yyvsp[(3) - (5)].ttype)); + if ((TREE_CODE ((yyvsp[(3) - (5)].ttype)) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND ((yyvsp[(3) - (5)].ttype), 0)) == STRING_CST) + || TREE_CODE ((yyvsp[(3) - (5)].ttype)) == STRING_CST) + assemble_asm ((yyvsp[(3) - (5)].ttype)); + else + error ("argument of `asm' is not a constant string"); ;} + break; + + case 11: + + { pedantic = (yyvsp[(1) - (2)].itype); ;} + break; + + case 12: + + { if (pedantic) + error ("ANSI C forbids data definition with no type or storage class"); + else if (!flag_traditional) + warning ("data definition has no type or storage class"); + + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(1) - (3)].itype)); ;} + break; + + case 13: + + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(2) - (4)].itype)); ;} + break; + + case 14: + + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(2) - (4)].itype)); ;} + break; + + case 15: + + { pedwarn ("empty declaration"); ;} + break; + + case 16: + + { shadow_tag ((yyvsp[(1) - (2)].ttype)); ;} + break; + + case 19: + + { if (pedantic) + pedwarn ("ANSI C does not allow extra `;' outside of a function"); ;} + break; + + case 20: + + { if (! start_function (current_declspecs, (yyvsp[(3) - (3)].ttype), + prefix_attributes, NULL_TREE, 0)) + YYERROR1; + reinit_parse_for_function (); ;} + break; + + case 21: + + { store_parm_decls (); ;} + break; + + case 22: + + { finish_function (0); + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(2) - (7)].itype)); ;} + break; + + case 23: + + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(2) - (4)].itype)); ;} + break; + + case 24: + + { if (! start_function (current_declspecs, (yyvsp[(3) - (3)].ttype), + prefix_attributes, NULL_TREE, 0)) + YYERROR1; + reinit_parse_for_function (); ;} + break; + + case 25: + + { store_parm_decls (); ;} + break; + + case 26: + + { finish_function (0); + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(2) - (7)].itype)); ;} + break; + + case 27: + + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(2) - (4)].itype)); ;} + break; + + case 28: + + { if (! start_function (NULL_TREE, (yyvsp[(2) - (2)].ttype), + prefix_attributes, NULL_TREE, 0)) + YYERROR1; + reinit_parse_for_function (); ;} + break; + + case 29: + + { store_parm_decls (); ;} + break; + + case 30: + + { finish_function (0); + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(1) - (6)].itype)); ;} + break; + + case 31: + + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(1) - (3)].itype)); ;} + break; + + case 34: + + { (yyval.code) = ADDR_EXPR; ;} + break; + + case 35: + + { (yyval.code) = NEGATE_EXPR; ;} + break; + + case 36: + + { (yyval.code) = CONVERT_EXPR; ;} + break; + + case 37: + + { (yyval.code) = PREINCREMENT_EXPR; ;} + break; + + case 38: + + { (yyval.code) = PREDECREMENT_EXPR; ;} + break; + + case 39: + + { (yyval.code) = BIT_NOT_EXPR; ;} + break; + + case 40: + + { (yyval.code) = TRUTH_NOT_EXPR; ;} + break; + + case 41: + + { (yyval.ttype) = build_compound_expr ((yyvsp[(1) - (1)].ttype)); ;} + break; + + case 42: + + { (yyval.ttype) = NULL_TREE; ;} + break; + + case 44: + + { (yyval.ttype) = build_tree_list (NULL_TREE, (yyvsp[(1) - (1)].ttype)); ;} + break; + + case 45: + + { chainon ((yyvsp[(1) - (3)].ttype), build_tree_list (NULL_TREE, (yyvsp[(3) - (3)].ttype))); ;} + break; + + case 47: + + { (yyval.ttype) = build_indirect_ref ((yyvsp[(2) - (2)].ttype), "unary *"); ;} + break; + + case 48: + + { (yyval.ttype) = (yyvsp[(2) - (2)].ttype); + pedantic = (yyvsp[(1) - (2)].itype); ;} + break; + + case 49: + + { (yyval.ttype) = build_unary_op ((yyvsp[(1) - (2)].code), (yyvsp[(2) - (2)].ttype), 0); + overflow_warning ((yyval.ttype)); ;} + break; + + case 50: + + { tree label = lookup_label ((yyvsp[(2) - (2)].ttype)); + if (pedantic) + pedwarn ("ANSI C forbids `&&'"); + if (label == 0) + (yyval.ttype) = null_pointer_node; + else + { + TREE_USED (label) = 1; + (yyval.ttype) = build1 (ADDR_EXPR, ptr_type_node, label); + TREE_CONSTANT ((yyval.ttype)) = 1; + } + ;} + break; + + case 51: + + { skip_evaluation--; + if (TREE_CODE ((yyvsp[(2) - (2)].ttype)) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND ((yyvsp[(2) - (2)].ttype), 1))) + error ("`sizeof' applied to a bit-field"); + (yyval.ttype) = c_sizeof (TREE_TYPE ((yyvsp[(2) - (2)].ttype))); ;} + break; + + case 52: + + { skip_evaluation--; + (yyval.ttype) = c_sizeof (groktypename ((yyvsp[(3) - (4)].ttype))); ;} + break; + + case 53: + + { skip_evaluation--; + (yyval.ttype) = c_alignof_expr ((yyvsp[(2) - (2)].ttype)); ;} + break; + + case 54: + + { skip_evaluation--; + (yyval.ttype) = c_alignof (groktypename ((yyvsp[(3) - (4)].ttype))); ;} + break; + + case 55: + + { (yyval.ttype) = build_unary_op (REALPART_EXPR, (yyvsp[(2) - (2)].ttype), 0); ;} + break; + + case 56: + + { (yyval.ttype) = build_unary_op (IMAGPART_EXPR, (yyvsp[(2) - (2)].ttype), 0); ;} + break; + + case 57: + + { skip_evaluation++; ;} + break; + + case 58: + + { skip_evaluation++; ;} + break; + + case 60: + + { tree type = groktypename ((yyvsp[(2) - (4)].ttype)); + (yyval.ttype) = build_c_cast (type, (yyvsp[(4) - (4)].ttype)); ;} + break; + + case 61: + + { start_init (NULL_TREE, NULL, 0); + (yyvsp[(2) - (4)].ttype) = groktypename ((yyvsp[(2) - (4)].ttype)); + really_start_incremental_init ((yyvsp[(2) - (4)].ttype)); ;} + break; + + case 62: + + { char *name; + tree result = pop_init_level (0); + tree type = (yyvsp[(2) - (7)].ttype); + finish_init (); + + if (pedantic && ! flag_isoc9x) + pedwarn ("ANSI C forbids constructor expressions"); + if (TYPE_NAME (type) != 0) + { + if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) + name = IDENTIFIER_POINTER (TYPE_NAME (type)); + else + name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); + } + else + name = ""; + (yyval.ttype) = result; + if (TREE_CODE (type) == ARRAY_TYPE && TYPE_SIZE (type) == 0) + { + int failure = complete_array_type (type, (yyval.ttype), 1); + if (failure) + abort (); + } + ;} + break; + + case 64: + + { (yyval.ttype) = parser_build_binary_op ((yyvsp[(2) - (3)].code), (yyvsp[(1) - (3)].ttype), (yyvsp[(3) - (3)].ttype)); ;} + break; + + case 65: + + { (yyval.ttype) = parser_build_binary_op ((yyvsp[(2) - (3)].code), (yyvsp[(1) - (3)].ttype), (yyvsp[(3) - (3)].ttype)); ;} + break; + + case 66: + + { (yyval.ttype) = parser_build_binary_op ((yyvsp[(2) - (3)].code), (yyvsp[(1) - (3)].ttype), (yyvsp[(3) - (3)].ttype)); ;} + break; + + case 67: + + { (yyval.ttype) = parser_build_binary_op ((yyvsp[(2) - (3)].code), (yyvsp[(1) - (3)].ttype), (yyvsp[(3) - (3)].ttype)); ;} + break; + + case 68: + + { (yyval.ttype) = parser_build_binary_op ((yyvsp[(2) - (3)].code), (yyvsp[(1) - (3)].ttype), (yyvsp[(3) - (3)].ttype)); ;} + break; + + case 69: + + { (yyval.ttype) = parser_build_binary_op ((yyvsp[(2) - (3)].code), (yyvsp[(1) - (3)].ttype), (yyvsp[(3) - (3)].ttype)); ;} + break; + + case 70: + + { (yyval.ttype) = parser_build_binary_op ((yyvsp[(2) - (3)].code), (yyvsp[(1) - (3)].ttype), (yyvsp[(3) - (3)].ttype)); ;} + break; + + case 71: + + { (yyval.ttype) = parser_build_binary_op ((yyvsp[(2) - (3)].code), (yyvsp[(1) - (3)].ttype), (yyvsp[(3) - (3)].ttype)); ;} + break; + + case 72: + + { (yyval.ttype) = parser_build_binary_op ((yyvsp[(2) - (3)].code), (yyvsp[(1) - (3)].ttype), (yyvsp[(3) - (3)].ttype)); ;} + break; + + case 73: + + { (yyval.ttype) = parser_build_binary_op ((yyvsp[(2) - (3)].code), (yyvsp[(1) - (3)].ttype), (yyvsp[(3) - (3)].ttype)); ;} + break; + + case 74: + + { (yyval.ttype) = parser_build_binary_op ((yyvsp[(2) - (3)].code), (yyvsp[(1) - (3)].ttype), (yyvsp[(3) - (3)].ttype)); ;} + break; + + case 75: + + { (yyval.ttype) = parser_build_binary_op ((yyvsp[(2) - (3)].code), (yyvsp[(1) - (3)].ttype), (yyvsp[(3) - (3)].ttype)); ;} + break; + + case 76: + + { (yyvsp[(1) - (2)].ttype) = truthvalue_conversion (default_conversion ((yyvsp[(1) - (2)].ttype))); + skip_evaluation += (yyvsp[(1) - (2)].ttype) == boolean_false_node; ;} + break; + + case 77: + + { skip_evaluation -= (yyvsp[(1) - (4)].ttype) == boolean_false_node; + (yyval.ttype) = parser_build_binary_op (TRUTH_ANDIF_EXPR, (yyvsp[(1) - (4)].ttype), (yyvsp[(4) - (4)].ttype)); ;} + break; + + case 78: + + { (yyvsp[(1) - (2)].ttype) = truthvalue_conversion (default_conversion ((yyvsp[(1) - (2)].ttype))); + skip_evaluation += (yyvsp[(1) - (2)].ttype) == boolean_true_node; ;} + break; + + case 79: + + { skip_evaluation -= (yyvsp[(1) - (4)].ttype) == boolean_true_node; + (yyval.ttype) = parser_build_binary_op (TRUTH_ORIF_EXPR, (yyvsp[(1) - (4)].ttype), (yyvsp[(4) - (4)].ttype)); ;} + break; + + case 80: + + { (yyvsp[(1) - (2)].ttype) = truthvalue_conversion (default_conversion ((yyvsp[(1) - (2)].ttype))); + skip_evaluation += (yyvsp[(1) - (2)].ttype) == boolean_false_node; ;} + break; + + case 81: + + { skip_evaluation += (((yyvsp[(1) - (5)].ttype) == boolean_true_node) + - ((yyvsp[(1) - (5)].ttype) == boolean_false_node)); ;} + break; + + case 82: + + { skip_evaluation -= (yyvsp[(1) - (7)].ttype) == boolean_true_node; + (yyval.ttype) = build_conditional_expr ((yyvsp[(1) - (7)].ttype), (yyvsp[(4) - (7)].ttype), (yyvsp[(7) - (7)].ttype)); ;} + break; + + case 83: + + { if (pedantic) + pedwarn ("ANSI C forbids omitting the middle term of a ?: expression"); + /* Make sure first operand is calculated only once. */ + (yyvsp[(2) - (2)].ttype) = save_expr ((yyvsp[(1) - (2)].ttype)); + (yyvsp[(1) - (2)].ttype) = truthvalue_conversion (default_conversion ((yyvsp[(2) - (2)].ttype))); + skip_evaluation += (yyvsp[(1) - (2)].ttype) == boolean_true_node; ;} + break; + + case 84: + + { skip_evaluation -= (yyvsp[(1) - (5)].ttype) == boolean_true_node; + (yyval.ttype) = build_conditional_expr ((yyvsp[(1) - (5)].ttype), (yyvsp[(2) - (5)].ttype), (yyvsp[(5) - (5)].ttype)); ;} + break; + + case 85: + + { (yyval.ttype) = build_modify_expr ((yyvsp[(1) - (3)].ttype), NOP_EXPR, (yyvsp[(3) - (3)].ttype)); + C_SET_EXP_ORIGINAL_CODE ((yyval.ttype), MODIFY_EXPR); ;} + break; + + case 86: + + { (yyval.ttype) = build_modify_expr ((yyvsp[(1) - (3)].ttype), (yyvsp[(2) - (3)].code), (yyvsp[(3) - (3)].ttype)); + /* This inhibits warnings in truthvalue_conversion. */ + C_SET_EXP_ORIGINAL_CODE ((yyval.ttype), ERROR_MARK); ;} + break; + + case 87: + + { + (yyval.ttype) = lastiddecl; + if (!(yyval.ttype) || (yyval.ttype) == error_mark_node) + { + if (yychar == YYEMPTY) + yychar = YYLEX; + if (yychar == '(') + { + { + /* Ordinary implicit function declaration. */ + (yyval.ttype) = implicitly_declare ((yyvsp[(1) - (1)].ttype)); + assemble_external ((yyval.ttype)); + TREE_USED ((yyval.ttype)) = 1; + } + } + else if (current_function_decl == 0) + { + error ("`%s' undeclared here (not in a function)", + IDENTIFIER_POINTER ((yyvsp[(1) - (1)].ttype))); + (yyval.ttype) = error_mark_node; + } + else + { + { + if (IDENTIFIER_GLOBAL_VALUE ((yyvsp[(1) - (1)].ttype)) != error_mark_node + || IDENTIFIER_ERROR_LOCUS ((yyvsp[(1) - (1)].ttype)) != current_function_decl) + { + error ("`%s' undeclared (first use in this function)", + IDENTIFIER_POINTER ((yyvsp[(1) - (1)].ttype))); + + if (! undeclared_variable_notice) + { + error ("(Each undeclared identifier is reported only once"); + error ("for each function it appears in.)"); + undeclared_variable_notice = 1; + } + } + (yyval.ttype) = error_mark_node; + /* Prevent repeated error messages. */ + IDENTIFIER_GLOBAL_VALUE ((yyvsp[(1) - (1)].ttype)) = error_mark_node; + IDENTIFIER_ERROR_LOCUS ((yyvsp[(1) - (1)].ttype)) = current_function_decl; + } + } + } + else if (TREE_TYPE ((yyval.ttype)) == error_mark_node) + (yyval.ttype) = error_mark_node; + else if (C_DECL_ANTICIPATED ((yyval.ttype))) + { + /* The first time we see a build-in function used, + if it has not been declared. */ + C_DECL_ANTICIPATED ((yyval.ttype)) = 0; + if (yychar == YYEMPTY) + yychar = YYLEX; + if (yychar == '(') + { + /* Omit the implicit declaration we + would ordinarily do, so we don't lose + the actual built in type. + But print a diagnostic for the mismatch. */ + if (TREE_CODE ((yyval.ttype)) != FUNCTION_DECL) + error ("`%s' implicitly declared as function", + IDENTIFIER_POINTER (DECL_NAME ((yyval.ttype)))); + else if ((TYPE_MODE (TREE_TYPE (TREE_TYPE ((yyval.ttype)))) + != TYPE_MODE (integer_type_node)) + && (TREE_TYPE (TREE_TYPE ((yyval.ttype))) + != void_type_node)) + pedwarn ("type mismatch in implicit declaration for built-in function `%s'", + IDENTIFIER_POINTER (DECL_NAME ((yyval.ttype)))); + /* If it really returns void, change that to int. */ + if (TREE_TYPE (TREE_TYPE ((yyval.ttype))) == void_type_node) + TREE_TYPE ((yyval.ttype)) + = build_function_type (integer_type_node, + TYPE_ARG_TYPES (TREE_TYPE ((yyval.ttype)))); + } + else + pedwarn ("built-in function `%s' used without declaration", + IDENTIFIER_POINTER (DECL_NAME ((yyval.ttype)))); + + /* Do what we would ordinarily do when a fn is used. */ + assemble_external ((yyval.ttype)); + TREE_USED ((yyval.ttype)) = 1; + } + else + { + assemble_external ((yyval.ttype)); + TREE_USED ((yyval.ttype)) = 1; + } + + if (TREE_CODE ((yyval.ttype)) == CONST_DECL) + { + (yyval.ttype) = DECL_INITIAL ((yyval.ttype)); + /* This is to prevent an enum whose value is 0 + from being considered a null pointer constant. */ + (yyval.ttype) = build1 (NOP_EXPR, TREE_TYPE ((yyval.ttype)), (yyval.ttype)); + TREE_CONSTANT ((yyval.ttype)) = 1; + } + ;} + break; + + case 89: + + { (yyval.ttype) = combine_strings ((yyvsp[(1) - (1)].ttype)); ;} + break; + + case 90: + + { char class = TREE_CODE_CLASS (TREE_CODE ((yyvsp[(2) - (3)].ttype))); + if (class == 'e' || class == '1' + || class == '2' || class == '<') + C_SET_EXP_ORIGINAL_CODE ((yyvsp[(2) - (3)].ttype), ERROR_MARK); + (yyval.ttype) = (yyvsp[(2) - (3)].ttype); ;} + break; + + case 91: + + { (yyval.ttype) = error_mark_node; ;} + break; + + case 92: + + { if (current_function_decl == 0) + { + error ("braced-group within expression allowed only inside a function"); + YYERROR; + } + /* We must force a BLOCK for this level + so that, if it is not expanded later, + there is a way to turn off the entire subtree of blocks + that are contained in it. */ + keep_next_level (); + push_iterator_stack (); + push_label_level (); + (yyval.ttype) = expand_start_stmt_expr (); ;} + break; + + case 93: + + { tree rtl_exp; + if (pedantic) + pedwarn ("ANSI C forbids braced-groups within expressions"); + pop_iterator_stack (); + pop_label_level (); + rtl_exp = expand_end_stmt_expr ((yyvsp[(2) - (4)].ttype)); + /* The statements have side effects, so the group does. */ + TREE_SIDE_EFFECTS (rtl_exp) = 1; + + if (TREE_CODE ((yyvsp[(3) - (4)].ttype)) == BLOCK) + { + /* Make a BIND_EXPR for the BLOCK already made. */ + (yyval.ttype) = build (BIND_EXPR, TREE_TYPE (rtl_exp), + NULL_TREE, rtl_exp, (yyvsp[(3) - (4)].ttype)); + /* Remove the block from the tree at this point. + It gets put back at the proper place + when the BIND_EXPR is expanded. */ + delete_block ((yyvsp[(3) - (4)].ttype)); + } + else + (yyval.ttype) = (yyvsp[(3) - (4)].ttype); + ;} + break; + + case 94: + + { (yyval.ttype) = build_function_call ((yyvsp[(1) - (4)].ttype), (yyvsp[(3) - (4)].ttype)); ;} + break; + + case 95: + + { (yyval.ttype) = build_array_ref ((yyvsp[(1) - (4)].ttype), (yyvsp[(3) - (4)].ttype)); ;} + break; + + case 96: + + { + (yyval.ttype) = build_component_ref ((yyvsp[(1) - (3)].ttype), (yyvsp[(3) - (3)].ttype)); + ;} + break; + + case 97: + + { + tree expr = build_indirect_ref ((yyvsp[(1) - (3)].ttype), "->"); + + (yyval.ttype) = build_component_ref (expr, (yyvsp[(3) - (3)].ttype)); + ;} + break; + + case 98: + + { (yyval.ttype) = build_unary_op (POSTINCREMENT_EXPR, (yyvsp[(1) - (2)].ttype), 0); ;} + break; + + case 99: + + { (yyval.ttype) = build_unary_op (POSTDECREMENT_EXPR, (yyvsp[(1) - (2)].ttype), 0); ;} + break; + + case 101: + + { (yyval.ttype) = chainon ((yyvsp[(1) - (2)].ttype), (yyvsp[(2) - (2)].ttype)); ;} + break; + + case 104: + + { c_mark_varargs (); + if (pedantic) + pedwarn ("ANSI C does not permit use of `varargs.h'"); ;} + break; + + case 105: + + { ;} + break; + + case 110: + + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(2) - (4)].itype)); ;} + break; + + case 111: + + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(2) - (4)].itype)); ;} + break; + + case 112: + + { shadow_tag_warned ((yyvsp[(1) - (2)].ttype), 1); + pedwarn ("empty declaration"); ;} + break; + + case 113: + + { pedwarn ("empty declaration"); ;} + break; + + case 114: + + { ;} + break; + + case 119: + + { (yyval.itype) = suspend_momentary (); + pending_xref_error (); + declspec_stack = tree_cons (prefix_attributes, + current_declspecs, + declspec_stack); + split_specs_attrs ((yyvsp[(0) - (0)].ttype), + ¤t_declspecs, &prefix_attributes); ;} + break; + + case 120: + + { prefix_attributes = chainon (prefix_attributes, (yyvsp[(0) - (0)].ttype)); ;} + break; + + case 121: + + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(2) - (4)].itype)); ;} + break; + + case 122: + + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(2) - (4)].itype)); ;} + break; + + case 123: + + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(2) - (3)].itype)); ;} + break; + + case 124: + + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(2) - (3)].itype)); ;} + break; + + case 125: + + { shadow_tag ((yyvsp[(1) - (2)].ttype)); ;} + break; + + case 126: + + { pedwarn ("empty declaration"); ;} + break; + + case 127: + + { pedantic = (yyvsp[(1) - (2)].itype); ;} + break; + + case 128: + + { (yyval.ttype) = tree_cons (NULL_TREE, (yyvsp[(1) - (2)].ttype), (yyvsp[(2) - (2)].ttype)); ;} + break; + + case 129: + + { (yyval.ttype) = chainon ((yyvsp[(3) - (3)].ttype), tree_cons (NULL_TREE, (yyvsp[(2) - (3)].ttype), (yyvsp[(1) - (3)].ttype))); ;} + break; + + case 130: + + { (yyval.ttype) = NULL_TREE; ;} + break; + + case 131: + + { (yyval.ttype) = tree_cons (NULL_TREE, (yyvsp[(2) - (2)].ttype), (yyvsp[(1) - (2)].ttype)); ;} + break; + + case 132: + + { if (extra_warnings) + warning ("`%s' is not at beginning of declaration", + IDENTIFIER_POINTER ((yyvsp[(2) - (2)].ttype))); + (yyval.ttype) = tree_cons (NULL_TREE, (yyvsp[(2) - (2)].ttype), (yyvsp[(1) - (2)].ttype)); ;} + break; + + case 133: + + { (yyval.ttype) = tree_cons ((yyvsp[(2) - (2)].ttype), NULL_TREE, (yyvsp[(1) - (2)].ttype)); ;} + break; + + case 134: + + { (yyval.ttype) = tree_cons (NULL_TREE, (yyvsp[(1) - (2)].ttype), (yyvsp[(2) - (2)].ttype)); ;} + break; + + case 135: + + { (yyval.ttype) = chainon ((yyvsp[(3) - (3)].ttype), tree_cons (NULL_TREE, (yyvsp[(2) - (3)].ttype), (yyvsp[(1) - (3)].ttype))); ;} + break; + + case 136: + + { (yyval.ttype) = NULL_TREE; ;} + break; + + case 137: + + { (yyval.ttype) = tree_cons (NULL_TREE, (yyvsp[(2) - (2)].ttype), (yyvsp[(1) - (2)].ttype)); ;} + break; + + case 138: + + { if (extra_warnings) + warning ("`%s' is not at beginning of declaration", + IDENTIFIER_POINTER ((yyvsp[(2) - (2)].ttype))); + (yyval.ttype) = tree_cons (NULL_TREE, (yyvsp[(2) - (2)].ttype), (yyvsp[(1) - (2)].ttype)); ;} + break; + + case 139: + + { (yyval.ttype) = (yyvsp[(1) - (1)].ttype); ;} + break; + + case 140: + + { (yyval.ttype) = tree_cons ((yyvsp[(1) - (1)].ttype), NULL_TREE, NULL_TREE); ;} + break; + + case 141: + + { (yyval.ttype) = chainon ((yyvsp[(2) - (2)].ttype), (yyvsp[(1) - (2)].ttype)); ;} + break; + + case 142: + + { (yyval.ttype) = tree_cons ((yyvsp[(2) - (2)].ttype), NULL_TREE, (yyvsp[(1) - (2)].ttype)); ;} + break; + + case 143: + + { (yyval.ttype) = tree_cons (NULL_TREE, (yyvsp[(1) - (1)].ttype), NULL_TREE); + TREE_STATIC ((yyval.ttype)) = 1; ;} + break; + + case 144: + + { (yyval.ttype) = tree_cons (NULL_TREE, (yyvsp[(1) - (1)].ttype), NULL_TREE); ;} + break; + + case 145: + + { (yyval.ttype) = tree_cons (NULL_TREE, (yyvsp[(2) - (2)].ttype), (yyvsp[(1) - (2)].ttype)); + TREE_STATIC ((yyval.ttype)) = 1; ;} + break; + + case 146: + + { if (extra_warnings && TREE_STATIC ((yyvsp[(1) - (2)].ttype))) + warning ("`%s' is not at beginning of declaration", + IDENTIFIER_POINTER ((yyvsp[(2) - (2)].ttype))); + (yyval.ttype) = tree_cons (NULL_TREE, (yyvsp[(2) - (2)].ttype), (yyvsp[(1) - (2)].ttype)); + TREE_STATIC ((yyval.ttype)) = TREE_STATIC ((yyvsp[(1) - (2)].ttype)); ;} + break; + + case 147: + + { (yyval.ttype) = tree_cons (NULL_TREE, (yyvsp[(1) - (2)].ttype), (yyvsp[(2) - (2)].ttype)); ;} + break; + + case 148: + + { (yyval.ttype) = chainon ((yyvsp[(3) - (3)].ttype), tree_cons (NULL_TREE, (yyvsp[(2) - (3)].ttype), (yyvsp[(1) - (3)].ttype))); ;} + break; + + case 149: + + { (yyval.ttype) = NULL_TREE; ;} + break; + + case 150: + + { (yyval.ttype) = tree_cons (NULL_TREE, (yyvsp[(2) - (2)].ttype), (yyvsp[(1) - (2)].ttype)); ;} + break; + + case 153: + + { /* For a typedef name, record the meaning, not the name. + In case of `foo foo, bar;'. */ + (yyval.ttype) = lookup_name ((yyvsp[(1) - (1)].ttype)); ;} + break; + + case 154: + + { (yyval.ttype) = TREE_TYPE ((yyvsp[(3) - (4)].ttype)); ;} + break; + + case 155: + + { (yyval.ttype) = groktypename ((yyvsp[(3) - (4)].ttype)); ;} + break; + + case 163: + + { (yyval.ttype) = NULL_TREE; ;} + break; + + case 164: + + { if (TREE_CHAIN ((yyvsp[(3) - (4)].ttype))) (yyvsp[(3) - (4)].ttype) = combine_strings ((yyvsp[(3) - (4)].ttype)); + (yyval.ttype) = (yyvsp[(3) - (4)].ttype); + ;} + break; + + case 165: + + { (yyval.ttype) = start_decl ((yyvsp[(1) - (4)].ttype), current_declspecs, 1, + (yyvsp[(3) - (4)].ttype), prefix_attributes); + start_init ((yyval.ttype), (yyvsp[(2) - (4)].ttype), global_bindings_p ()); ;} + break; + + case 166: + + { finish_init (); + finish_decl ((yyvsp[(5) - (6)].ttype), (yyvsp[(6) - (6)].ttype), (yyvsp[(2) - (6)].ttype)); ;} + break; + + case 167: + + { tree d = start_decl ((yyvsp[(1) - (3)].ttype), current_declspecs, 0, + (yyvsp[(3) - (3)].ttype), prefix_attributes); + finish_decl (d, NULL_TREE, (yyvsp[(2) - (3)].ttype)); + ;} + break; + + case 168: + + { (yyval.ttype) = start_decl ((yyvsp[(1) - (4)].ttype), current_declspecs, 1, + (yyvsp[(3) - (4)].ttype), prefix_attributes); + start_init ((yyval.ttype), (yyvsp[(2) - (4)].ttype), global_bindings_p ()); ;} + break; + + case 169: + + { finish_init (); + decl_attributes ((yyvsp[(5) - (6)].ttype), (yyvsp[(3) - (6)].ttype), prefix_attributes); + finish_decl ((yyvsp[(5) - (6)].ttype), (yyvsp[(6) - (6)].ttype), (yyvsp[(2) - (6)].ttype)); ;} + break; + + case 170: + + { tree d = start_decl ((yyvsp[(1) - (3)].ttype), current_declspecs, 0, + (yyvsp[(3) - (3)].ttype), prefix_attributes); + finish_decl (d, NULL_TREE, (yyvsp[(2) - (3)].ttype)); ;} + break; + + case 171: + + { (yyval.ttype) = NULL_TREE; ;} + break; + + case 172: + + { (yyval.ttype) = (yyvsp[(1) - (1)].ttype); ;} + break; + + case 173: + + { (yyval.ttype) = (yyvsp[(1) - (1)].ttype); ;} + break; + + case 174: + + { (yyval.ttype) = chainon ((yyvsp[(1) - (2)].ttype), (yyvsp[(2) - (2)].ttype)); ;} + break; + + case 175: + + { (yyval.ttype) = (yyvsp[(4) - (6)].ttype); ;} + break; + + case 176: + + { (yyval.ttype) = (yyvsp[(1) - (1)].ttype); ;} + break; + + case 177: + + { (yyval.ttype) = chainon ((yyvsp[(1) - (3)].ttype), (yyvsp[(3) - (3)].ttype)); ;} + break; + + case 178: + + { (yyval.ttype) = NULL_TREE; ;} + break; + + case 179: + + { (yyval.ttype) = build_tree_list ((yyvsp[(1) - (1)].ttype), NULL_TREE); ;} + break; + + case 180: + + { (yyval.ttype) = build_tree_list ((yyvsp[(1) - (4)].ttype), build_tree_list (NULL_TREE, (yyvsp[(3) - (4)].ttype))); ;} + break; + + case 181: + + { (yyval.ttype) = build_tree_list ((yyvsp[(1) - (6)].ttype), tree_cons (NULL_TREE, (yyvsp[(3) - (6)].ttype), (yyvsp[(5) - (6)].ttype))); ;} + break; + + case 182: + + { (yyval.ttype) = build_tree_list ((yyvsp[(1) - (4)].ttype), (yyvsp[(3) - (4)].ttype)); ;} + break; + + case 188: + + { really_start_incremental_init (NULL_TREE); + /* Note that the call to clear_momentary + is in process_init_element. */ + push_momentary (); ;} + break; + + case 189: + + { (yyval.ttype) = pop_init_level (0); + if ((yyval.ttype) == error_mark_node + && ! (yychar == STRING || yychar == CONSTANT)) + pop_momentary (); + else + pop_momentary_nofree (); ;} + break; + + case 190: + + { (yyval.ttype) = error_mark_node; ;} + break; + + case 191: + + { if (pedantic) + pedwarn ("ANSI C forbids empty initializer braces"); ;} + break; + + case 197: + + { set_init_label ((yyvsp[(1) - (2)].ttype)); ;} + break; + + case 200: + + { push_init_level (0); ;} + break; + + case 201: + + { process_init_element (pop_init_level (0)); ;} + break; + + case 202: + + { process_init_element ((yyvsp[(1) - (1)].ttype)); ;} + break; + + case 206: + + { set_init_label ((yyvsp[(2) - (2)].ttype)); ;} + break; + + case 207: + + { set_init_index ((yyvsp[(2) - (5)].ttype), (yyvsp[(4) - (5)].ttype)); ;} + break; + + case 208: + + { set_init_index ((yyvsp[(2) - (3)].ttype), NULL_TREE); ;} + break; + + case 209: + + { push_c_function_context (); + if (! start_function (current_declspecs, (yyvsp[(1) - (1)].ttype), + prefix_attributes, NULL_TREE, 1)) + { + pop_c_function_context (); + YYERROR1; + } + reinit_parse_for_function (); ;} + break; + + case 210: + + { store_parm_decls (); ;} + break; + + case 211: + + { finish_function (1); + pop_c_function_context (); ;} + break; + + case 212: + + { push_c_function_context (); + if (! start_function (current_declspecs, (yyvsp[(1) - (1)].ttype), + prefix_attributes, NULL_TREE, 1)) + { + pop_c_function_context (); + YYERROR1; + } + reinit_parse_for_function (); ;} + break; + + case 213: + + { store_parm_decls (); ;} + break; + + case 214: + + { finish_function (1); + pop_c_function_context (); ;} + break; + + case 217: + + { (yyval.ttype) = (yyvsp[(2) - (3)].ttype); ;} + break; + + case 218: + + { (yyval.ttype) = build_nt (CALL_EXPR, (yyvsp[(1) - (3)].ttype), (yyvsp[(3) - (3)].ttype), NULL_TREE); ;} + break; + + case 219: + + { (yyval.ttype) = build_nt (ARRAY_REF, (yyvsp[(1) - (4)].ttype), (yyvsp[(3) - (4)].ttype)); ;} + break; + + case 220: + + { (yyval.ttype) = build_nt (ARRAY_REF, (yyvsp[(1) - (3)].ttype), NULL_TREE); ;} + break; + + case 221: + + { (yyval.ttype) = make_pointer_declarator ((yyvsp[(2) - (3)].ttype), (yyvsp[(3) - (3)].ttype)); ;} + break; + + case 222: + + { (yyval.ttype) = (yyvsp[(3) - (3)].ttype); ;} + break; + + case 224: + + { (yyval.ttype) = build_nt (CALL_EXPR, (yyvsp[(1) - (3)].ttype), (yyvsp[(3) - (3)].ttype), NULL_TREE); ;} + break; + + case 225: + + { (yyval.ttype) = build_nt (ARRAY_REF, (yyvsp[(1) - (4)].ttype), NULL_TREE); + if (! flag_isoc9x) + error ("`[*]' in parameter declaration only allowed in ISO C 9x"); + ;} + break; + + case 226: + + { (yyval.ttype) = build_nt (ARRAY_REF, (yyvsp[(1) - (4)].ttype), (yyvsp[(3) - (4)].ttype)); ;} + break; + + case 227: + + { (yyval.ttype) = build_nt (ARRAY_REF, (yyvsp[(1) - (3)].ttype), NULL_TREE); ;} + break; + + case 228: + + { (yyval.ttype) = make_pointer_declarator ((yyvsp[(2) - (3)].ttype), (yyvsp[(3) - (3)].ttype)); ;} + break; + + case 229: + + { (yyval.ttype) = (yyvsp[(3) - (3)].ttype); ;} + break; + + case 231: + + { (yyval.ttype) = build_nt (CALL_EXPR, (yyvsp[(1) - (3)].ttype), (yyvsp[(3) - (3)].ttype), NULL_TREE); ;} + break; + + case 232: + + { (yyval.ttype) = (yyvsp[(2) - (3)].ttype); ;} + break; + + case 233: + + { (yyval.ttype) = make_pointer_declarator ((yyvsp[(2) - (3)].ttype), (yyvsp[(3) - (3)].ttype)); ;} + break; + + case 234: + + { (yyval.ttype) = build_nt (ARRAY_REF, (yyvsp[(1) - (4)].ttype), NULL_TREE); + if (! flag_isoc9x) + error ("`[*]' in parameter declaration only allowed in ISO C 9x"); + ;} + break; + + case 235: + + { (yyval.ttype) = build_nt (ARRAY_REF, (yyvsp[(1) - (4)].ttype), (yyvsp[(3) - (4)].ttype)); ;} + break; + + case 236: + + { (yyval.ttype) = build_nt (ARRAY_REF, (yyvsp[(1) - (3)].ttype), NULL_TREE); ;} + break; + + case 237: + + { (yyval.ttype) = (yyvsp[(3) - (3)].ttype); ;} + break; + + case 239: + + { (yyval.ttype) = NULL_TREE; ;} + break; + + case 240: + + { (yyval.ttype) = (yyvsp[(2) - (2)].ttype); ;} + break; + + case 241: + + { (yyval.ttype) = NULL_TREE; ;} + break; + + case 242: + + { (yyval.ttype) = (yyvsp[(2) - (2)].ttype); ;} + break; + + case 243: + + { (yyval.ttype) = NULL_TREE; ;} + break; + + case 244: + + { (yyval.ttype) = (yyvsp[(2) - (2)].ttype); ;} + break; + + case 245: + + { (yyval.ttype) = start_struct (RECORD_TYPE, (yyvsp[(2) - (3)].ttype)); + /* Start scope of tag before parsing components. */ + ;} + break; + + case 246: + + { (yyval.ttype) = finish_struct ((yyvsp[(4) - (7)].ttype), (yyvsp[(5) - (7)].ttype), chainon ((yyvsp[(1) - (7)].ttype), (yyvsp[(7) - (7)].ttype))); ;} + break; + + case 247: + + { (yyval.ttype) = finish_struct (start_struct (RECORD_TYPE, NULL_TREE), + (yyvsp[(3) - (5)].ttype), chainon ((yyvsp[(1) - (5)].ttype), (yyvsp[(5) - (5)].ttype))); + ;} + break; + + case 248: + + { (yyval.ttype) = xref_tag (RECORD_TYPE, (yyvsp[(2) - (2)].ttype)); ;} + break; + + case 249: + + { (yyval.ttype) = start_struct (UNION_TYPE, (yyvsp[(2) - (3)].ttype)); ;} + break; + + case 250: + + { (yyval.ttype) = finish_struct ((yyvsp[(4) - (7)].ttype), (yyvsp[(5) - (7)].ttype), chainon ((yyvsp[(1) - (7)].ttype), (yyvsp[(7) - (7)].ttype))); ;} + break; + + case 251: + + { (yyval.ttype) = finish_struct (start_struct (UNION_TYPE, NULL_TREE), + (yyvsp[(3) - (5)].ttype), chainon ((yyvsp[(1) - (5)].ttype), (yyvsp[(5) - (5)].ttype))); + ;} + break; + + case 252: + + { (yyval.ttype) = xref_tag (UNION_TYPE, (yyvsp[(2) - (2)].ttype)); ;} + break; + + case 253: + + { (yyvsp[(3) - (3)].itype) = suspend_momentary (); + (yyval.ttype) = start_enum ((yyvsp[(2) - (3)].ttype)); ;} + break; + + case 254: + + { (yyval.ttype)= finish_enum ((yyvsp[(4) - (8)].ttype), nreverse ((yyvsp[(5) - (8)].ttype)), chainon ((yyvsp[(1) - (8)].ttype), (yyvsp[(8) - (8)].ttype))); + resume_momentary ((yyvsp[(3) - (8)].itype)); ;} + break; + + case 255: + + { (yyvsp[(2) - (2)].itype) = suspend_momentary (); + (yyval.ttype) = start_enum (NULL_TREE); ;} + break; + + case 256: + + { (yyval.ttype)= finish_enum ((yyvsp[(3) - (7)].ttype), nreverse ((yyvsp[(4) - (7)].ttype)), chainon ((yyvsp[(1) - (7)].ttype), (yyvsp[(7) - (7)].ttype))); + resume_momentary ((yyvsp[(2) - (7)].itype)); ;} + break; + + case 257: + + { (yyval.ttype) = xref_tag (ENUMERAL_TYPE, (yyvsp[(2) - (2)].ttype)); ;} + break; + + case 261: + + { if (pedantic && ! flag_isoc9x) + pedwarn ("comma at end of enumerator list"); ;} + break; + + case 262: + + { (yyval.ttype) = (yyvsp[(1) - (1)].ttype); ;} + break; + + case 263: + + { (yyval.ttype) = chainon ((yyvsp[(1) - (2)].ttype), (yyvsp[(2) - (2)].ttype)); + pedwarn ("no semicolon at end of struct or union"); ;} + break; + + case 264: + + { (yyval.ttype) = NULL_TREE; ;} + break; + + case 265: + + { (yyval.ttype) = chainon ((yyvsp[(1) - (3)].ttype), (yyvsp[(2) - (3)].ttype)); ;} + break; + + case 266: + + { if (pedantic) + pedwarn ("extra semicolon in struct or union specified"); ;} + break; + + case 267: + + { (yyval.ttype) = (yyvsp[(3) - (3)].ttype); + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(2) - (3)].itype)); ;} + break; + + case 268: + + { if (pedantic) + pedwarn ("ANSI C forbids member declarations with no members"); + shadow_tag((yyvsp[(1) - (1)].ttype)); + (yyval.ttype) = NULL_TREE; ;} + break; + + case 269: + + { (yyval.ttype) = (yyvsp[(3) - (3)].ttype); + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(2) - (3)].itype)); ;} + break; + + case 270: + + { if (pedantic) + pedwarn ("ANSI C forbids member declarations with no members"); + shadow_tag((yyvsp[(1) - (1)].ttype)); + (yyval.ttype) = NULL_TREE; ;} + break; + + case 271: + + { (yyval.ttype) = NULL_TREE; ;} + break; + + case 272: + + { (yyval.ttype) = (yyvsp[(2) - (2)].ttype); + pedantic = (yyvsp[(1) - (2)].itype); ;} + break; + + case 274: + + { (yyval.ttype) = chainon ((yyvsp[(1) - (3)].ttype), (yyvsp[(3) - (3)].ttype)); ;} + break; + + case 275: + + { (yyval.ttype) = grokfield ((yyvsp[(1) - (4)].filename), (yyvsp[(2) - (4)].lineno), (yyvsp[(3) - (4)].ttype), current_declspecs, NULL_TREE); + decl_attributes ((yyval.ttype), (yyvsp[(4) - (4)].ttype), prefix_attributes); ;} + break; + + case 276: + + { (yyval.ttype) = grokfield ((yyvsp[(1) - (6)].filename), (yyvsp[(2) - (6)].lineno), (yyvsp[(3) - (6)].ttype), current_declspecs, (yyvsp[(5) - (6)].ttype)); + decl_attributes ((yyval.ttype), (yyvsp[(6) - (6)].ttype), prefix_attributes); ;} + break; + + case 277: + + { (yyval.ttype) = grokfield ((yyvsp[(1) - (5)].filename), (yyvsp[(2) - (5)].lineno), NULL_TREE, current_declspecs, (yyvsp[(4) - (5)].ttype)); + decl_attributes ((yyval.ttype), (yyvsp[(5) - (5)].ttype), prefix_attributes); ;} + break; + + case 279: + + { if ((yyvsp[(1) - (3)].ttype) == error_mark_node) + (yyval.ttype) = (yyvsp[(1) - (3)].ttype); + else + (yyval.ttype) = chainon ((yyvsp[(3) - (3)].ttype), (yyvsp[(1) - (3)].ttype)); ;} + break; + + case 280: + + { (yyval.ttype) = error_mark_node; ;} + break; + + case 281: + + { (yyval.ttype) = build_enumerator ((yyvsp[(1) - (1)].ttype), NULL_TREE); ;} + break; + + case 282: + + { (yyval.ttype) = build_enumerator ((yyvsp[(1) - (3)].ttype), (yyvsp[(3) - (3)].ttype)); ;} + break; + + case 283: + + { (yyval.ttype) = build_tree_list ((yyvsp[(1) - (2)].ttype), (yyvsp[(2) - (2)].ttype)); ;} + break; + + case 284: + + { (yyval.ttype) = build_tree_list ((yyvsp[(1) - (2)].ttype), (yyvsp[(2) - (2)].ttype)); ;} + break; + + case 285: + + { (yyval.ttype) = NULL_TREE; ;} + break; + + case 287: + + { (yyval.ttype) = tree_cons (NULL_TREE, (yyvsp[(1) - (1)].ttype), NULL_TREE); ;} + break; + + case 288: + + { (yyval.ttype) = tree_cons (NULL_TREE, (yyvsp[(2) - (2)].ttype), (yyvsp[(1) - (2)].ttype)); ;} + break; + + case 289: + + { (yyval.ttype) = NULL_TREE; ;} + break; + + case 290: + + { (yyval.ttype) = tree_cons (NULL_TREE, (yyvsp[(2) - (2)].ttype), (yyvsp[(1) - (2)].ttype)); ;} + break; + + case 291: + + { (yyval.ttype) = (yyvsp[(2) - (3)].ttype); ;} + break; + + case 292: + + { (yyval.ttype) = make_pointer_declarator ((yyvsp[(2) - (3)].ttype), (yyvsp[(3) - (3)].ttype)); ;} + break; + + case 293: + + { (yyval.ttype) = make_pointer_declarator ((yyvsp[(2) - (2)].ttype), NULL_TREE); ;} + break; + + case 294: + + { (yyval.ttype) = build_nt (CALL_EXPR, (yyvsp[(1) - (3)].ttype), (yyvsp[(3) - (3)].ttype), NULL_TREE); ;} + break; + + case 295: + + { (yyval.ttype) = build_nt (ARRAY_REF, (yyvsp[(1) - (4)].ttype), (yyvsp[(3) - (4)].ttype)); ;} + break; + + case 296: + + { (yyval.ttype) = build_nt (ARRAY_REF, (yyvsp[(1) - (3)].ttype), NULL_TREE); ;} + break; + + case 297: + + { (yyval.ttype) = build_nt (CALL_EXPR, NULL_TREE, (yyvsp[(2) - (2)].ttype), NULL_TREE); ;} + break; + + case 298: + + { (yyval.ttype) = build_nt (ARRAY_REF, NULL_TREE, (yyvsp[(2) - (3)].ttype)); ;} + break; + + case 299: + + { (yyval.ttype) = build_nt (ARRAY_REF, NULL_TREE, NULL_TREE); ;} + break; + + case 300: + + { + if (pedantic && (yyvsp[(1) - (1)].ends_in_label)) + pedwarn ("ANSI C forbids label at end of compound statement"); + ;} + break; + + case 302: + + { (yyval.ends_in_label) = (yyvsp[(2) - (2)].ends_in_label); ;} + break; + + case 303: + + { (yyval.ends_in_label) = 0; ;} + break; + + case 307: + + { emit_line_note (input_filename, lineno); + pushlevel (0); + clear_last_expr (); + push_momentary (); + expand_start_bindings (0); + ;} + break; + + case 309: + + { if (pedantic) + pedwarn ("ANSI C forbids label declarations"); ;} + break; + + case 312: + + { tree link; + for (link = (yyvsp[(2) - (3)].ttype); link; link = TREE_CHAIN (link)) + { + tree label = shadow_label (TREE_VALUE (link)); + C_DECLARED_LABEL_FLAG (label) = 1; + declare_nonlocal_label (label); + } + ;} + break; + + case 313: + + {;} + break; + + case 315: + + { compstmt_count++; ;} + break; + + case 316: + + { (yyval.ttype) = convert (void_type_node, integer_zero_node); ;} + break; + + case 317: + + { emit_line_note (input_filename, lineno); + expand_end_bindings (getdecls (), 1, 0); + (yyval.ttype) = poplevel (1, 1, 0); + if (yychar == CONSTANT || yychar == STRING) + pop_momentary_nofree (); + else + pop_momentary (); ;} + break; + + case 318: + + { emit_line_note (input_filename, lineno); + expand_end_bindings (getdecls (), kept_level_p (), 0); + (yyval.ttype) = poplevel (kept_level_p (), 0, 0); + if (yychar == CONSTANT || yychar == STRING) + pop_momentary_nofree (); + else + pop_momentary (); ;} + break; + + case 319: + + { emit_line_note (input_filename, lineno); + expand_end_bindings (getdecls (), kept_level_p (), 0); + (yyval.ttype) = poplevel (kept_level_p (), 0, 0); + if (yychar == CONSTANT || yychar == STRING) + pop_momentary_nofree (); + else + pop_momentary (); ;} + break; + + case 322: + + { emit_line_note ((yyvsp[(-1) - (4)].filename), (yyvsp[(0) - (4)].lineno)); + c_expand_start_cond (truthvalue_conversion ((yyvsp[(3) - (4)].ttype)), 0, + compstmt_count); + (yyval.itype) = stmt_count; + if_stmt_file = (yyvsp[(-1) - (4)].filename); + if_stmt_line = (yyvsp[(0) - (4)].lineno); + position_after_white_space (); ;} + break; + + case 323: + + { stmt_count++; + compstmt_count++; + emit_line_note ((yyvsp[(-1) - (1)].filename), (yyvsp[(0) - (1)].lineno)); + /* See comment in `while' alternative, above. */ + emit_nop (); + expand_start_loop_continue_elsewhere (1); + position_after_white_space (); ;} + break; + + case 324: + + { expand_loop_continue_here (); ;} + break; + + case 325: + + { (yyval.filename) = input_filename; ;} + break; + + case 326: + + { (yyval.lineno) = lineno; ;} + break; + + case 327: + + { ;} + break; + + case 328: + + { ;} + break; + + case 329: + + { (yyval.ends_in_label) = (yyvsp[(3) - (3)].ends_in_label); ;} + break; + + case 330: + + { (yyval.ends_in_label) = 0; ;} + break; + + case 331: + + { (yyval.ends_in_label) = 1; ;} + break; + + case 332: + + { stmt_count++; ;} + break; + + case 334: + + { stmt_count++; + emit_line_note ((yyvsp[(-1) - (2)].filename), (yyvsp[(0) - (2)].lineno)); +/* It appears that this should not be done--that a non-lvalue array + shouldn't get an error if the value isn't used. + Section 3.2.2.1 says that an array lvalue gets converted to a pointer + if it appears as a top-level expression, + but says nothing about non-lvalue arrays. */ +#if 0 + /* Call default_conversion to get an error + on referring to a register array if pedantic. */ + if (TREE_CODE (TREE_TYPE ((yyvsp[(1) - (2)].ttype))) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE ((yyvsp[(1) - (2)].ttype))) == FUNCTION_TYPE) + (yyvsp[(1) - (2)].ttype) = default_conversion ((yyvsp[(1) - (2)].ttype)); +#endif + iterator_expand ((yyvsp[(1) - (2)].ttype)); + clear_momentary (); ;} + break; + + case 335: + + { c_expand_start_else (); + (yyvsp[(1) - (2)].itype) = stmt_count; + position_after_white_space (); ;} + break; + + case 336: + + { c_expand_end_cond (); + if (extra_warnings && stmt_count == (yyvsp[(1) - (4)].itype)) + warning ("empty body in an else-statement"); ;} + break; + + case 337: + + { c_expand_end_cond (); + /* This warning is here instead of in simple_if, because we + do not want a warning if an empty if is followed by an + else statement. Increment stmt_count so we don't + give a second error if this is a nested `if'. */ + if (extra_warnings && stmt_count++ == (yyvsp[(1) - (1)].itype)) + warning_with_file_and_line (if_stmt_file, if_stmt_line, + "empty body in an if-statement"); ;} + break; + + case 338: + + { c_expand_end_cond (); ;} + break; + + case 339: + + { stmt_count++; + emit_line_note ((yyvsp[(-1) - (1)].filename), (yyvsp[(0) - (1)].lineno)); + /* The emit_nop used to come before emit_line_note, + but that made the nop seem like part of the preceding line. + And that was confusing when the preceding line was + inside of an if statement and was not really executed. + I think it ought to work to put the nop after the line number. + We will see. --rms, July 15, 1991. */ + emit_nop (); ;} + break; + + case 340: + + { /* Don't start the loop till we have succeeded + in parsing the end test. This is to make sure + that we end every loop we start. */ + expand_start_loop (1); + emit_line_note (input_filename, lineno); + expand_exit_loop_if_false (NULL, + truthvalue_conversion ((yyvsp[(4) - (5)].ttype))); + position_after_white_space (); ;} + break; + + case 341: + + { expand_end_loop (); ;} + break; + + case 342: + + { emit_line_note (input_filename, lineno); + expand_exit_loop_if_false (NULL, + truthvalue_conversion ((yyvsp[(3) - (5)].ttype))); + expand_end_loop (); + clear_momentary (); ;} + break; + + case 343: + + { expand_end_loop (); + clear_momentary (); ;} + break; + + case 344: + + { stmt_count++; + emit_line_note ((yyvsp[(-1) - (4)].filename), (yyvsp[(0) - (4)].lineno)); + /* See comment in `while' alternative, above. */ + emit_nop (); + if ((yyvsp[(3) - (4)].ttype)) c_expand_expr_stmt ((yyvsp[(3) - (4)].ttype)); + /* Next step is to call expand_start_loop_continue_elsewhere, + but wait till after we parse the entire for (...). + Otherwise, invalid input might cause us to call that + fn without calling expand_end_loop. */ + ;} + break; + + case 345: + + { (yyvsp[(7) - (7)].lineno) = lineno; + (yyval.filename) = input_filename; ;} + break; + + case 346: + + { + /* Start the loop. Doing this after parsing + all the expressions ensures we will end the loop. */ + expand_start_loop_continue_elsewhere (1); + /* Emit the end-test, with a line number. */ + emit_line_note ((yyvsp[(8) - (10)].filename), (yyvsp[(7) - (10)].lineno)); + if ((yyvsp[(6) - (10)].ttype)) + expand_exit_loop_if_false (NULL, + truthvalue_conversion ((yyvsp[(6) - (10)].ttype))); + /* Don't let the tree nodes for $9 be discarded by + clear_momentary during the parsing of the next stmt. */ + push_momentary (); + (yyvsp[(7) - (10)].lineno) = lineno; + (yyvsp[(8) - (10)].filename) = input_filename; + position_after_white_space (); ;} + break; + + case 347: + + { /* Emit the increment expression, with a line number. */ + emit_line_note ((yyvsp[(8) - (12)].filename), (yyvsp[(7) - (12)].lineno)); + expand_loop_continue_here (); + if ((yyvsp[(9) - (12)].ttype)) + c_expand_expr_stmt ((yyvsp[(9) - (12)].ttype)); + if (yychar == CONSTANT || yychar == STRING) + pop_momentary_nofree (); + else + pop_momentary (); + expand_end_loop (); ;} + break; + + case 348: + + { stmt_count++; + emit_line_note ((yyvsp[(-1) - (4)].filename), (yyvsp[(0) - (4)].lineno)); + c_expand_start_case ((yyvsp[(3) - (4)].ttype)); + /* Don't let the tree nodes for $3 be discarded by + clear_momentary during the parsing of the next stmt. */ + push_momentary (); + position_after_white_space (); ;} + break; + + case 349: + + { expand_end_case ((yyvsp[(3) - (6)].ttype)); + if (yychar == CONSTANT || yychar == STRING) + pop_momentary_nofree (); + else + pop_momentary (); ;} + break; + + case 350: + + { stmt_count++; + emit_line_note ((yyvsp[(-1) - (2)].filename), (yyvsp[(0) - (2)].lineno)); + if ( ! expand_exit_something ()) + error ("break statement not within loop or switch"); ;} + break; + + case 351: + + { stmt_count++; + emit_line_note ((yyvsp[(-1) - (2)].filename), (yyvsp[(0) - (2)].lineno)); + if (! expand_continue_loop (NULL)) + error ("continue statement not within a loop"); ;} + break; + + case 352: + + { stmt_count++; + emit_line_note ((yyvsp[(-1) - (2)].filename), (yyvsp[(0) - (2)].lineno)); + c_expand_return (NULL_TREE); ;} + break; + + case 353: + + { stmt_count++; + emit_line_note ((yyvsp[(-1) - (3)].filename), (yyvsp[(0) - (3)].lineno)); + c_expand_return ((yyvsp[(2) - (3)].ttype)); ;} + break; + + case 354: + + { stmt_count++; + emit_line_note ((yyvsp[(-1) - (6)].filename), (yyvsp[(0) - (6)].lineno)); + STRIP_NOPS ((yyvsp[(4) - (6)].ttype)); + if ((TREE_CODE ((yyvsp[(4) - (6)].ttype)) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND ((yyvsp[(4) - (6)].ttype), 0)) == STRING_CST) + || TREE_CODE ((yyvsp[(4) - (6)].ttype)) == STRING_CST) + expand_asm ((yyvsp[(4) - (6)].ttype)); + else + error ("argument of `asm' is not a constant string"); ;} + break; + + case 355: + + { stmt_count++; + emit_line_note ((yyvsp[(-1) - (8)].filename), (yyvsp[(0) - (8)].lineno)); + c_expand_asm_operands ((yyvsp[(4) - (8)].ttype), (yyvsp[(6) - (8)].ttype), NULL_TREE, NULL_TREE, + (yyvsp[(2) - (8)].ttype) == ridpointers[(int)RID_VOLATILE], + input_filename, lineno); ;} + break; + + case 356: + + { stmt_count++; + emit_line_note ((yyvsp[(-1) - (10)].filename), (yyvsp[(0) - (10)].lineno)); + c_expand_asm_operands ((yyvsp[(4) - (10)].ttype), (yyvsp[(6) - (10)].ttype), (yyvsp[(8) - (10)].ttype), NULL_TREE, + (yyvsp[(2) - (10)].ttype) == ridpointers[(int)RID_VOLATILE], + input_filename, lineno); ;} + break; + + case 357: + + { stmt_count++; + emit_line_note ((yyvsp[(-1) - (12)].filename), (yyvsp[(0) - (12)].lineno)); + c_expand_asm_operands ((yyvsp[(4) - (12)].ttype), (yyvsp[(6) - (12)].ttype), (yyvsp[(8) - (12)].ttype), (yyvsp[(10) - (12)].ttype), + (yyvsp[(2) - (12)].ttype) == ridpointers[(int)RID_VOLATILE], + input_filename, lineno); ;} + break; + + case 358: + + { tree decl; + stmt_count++; + emit_line_note ((yyvsp[(-1) - (3)].filename), (yyvsp[(0) - (3)].lineno)); + decl = lookup_label ((yyvsp[(2) - (3)].ttype)); + if (decl != 0) + { + TREE_USED (decl) = 1; + expand_goto (decl); + } + ;} + break; + + case 359: + + { if (pedantic) + pedwarn ("ANSI C forbids `goto *expr;'"); + stmt_count++; + emit_line_note ((yyvsp[(-1) - (4)].filename), (yyvsp[(0) - (4)].lineno)); + expand_computed_goto (convert (ptr_type_node, (yyvsp[(3) - (4)].ttype))); ;} + break; + + case 362: + + { + /* The value returned by this action is */ + /* 1 if everything is OK */ + /* 0 in case of error or already bound iterator */ + + (yyval.itype) = 0; + if (TREE_CODE ((yyvsp[(3) - (4)].ttype)) != VAR_DECL) + error ("invalid `for (ITERATOR)' syntax"); + else if (! ITERATOR_P ((yyvsp[(3) - (4)].ttype))) + error ("`%s' is not an iterator", + IDENTIFIER_POINTER (DECL_NAME ((yyvsp[(3) - (4)].ttype)))); + else if (ITERATOR_BOUND_P ((yyvsp[(3) - (4)].ttype))) + error ("`for (%s)' inside expansion of same iterator", + IDENTIFIER_POINTER (DECL_NAME ((yyvsp[(3) - (4)].ttype)))); + else + { + (yyval.itype) = 1; + iterator_for_loop_start ((yyvsp[(3) - (4)].ttype)); + } + ;} + break; + + case 363: + + { + if ((yyvsp[(5) - (6)].itype)) + iterator_for_loop_end ((yyvsp[(3) - (6)].ttype)); + ;} + break; + + case 364: + + { register tree value = check_case_value ((yyvsp[(2) - (3)].ttype)); + register tree label + = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + + stmt_count++; + + if (value != error_mark_node) + { + tree duplicate; + int success; + + if (pedantic && ! INTEGRAL_TYPE_P (TREE_TYPE (value))) + pedwarn ("label must have integral type in ANSI C"); + + success = pushcase (value, convert_and_check, + label, &duplicate); + + if (success == 1) + error ("case label not within a switch statement"); + else if (success == 2) + { + error ("duplicate case value"); + error_with_decl (duplicate, "this is the first entry for that value"); + } + else if (success == 3) + warning ("case value out of range"); + else if (success == 5) + error ("case label within scope of cleanup or variable array"); + } + position_after_white_space (); ;} + break; + + case 365: + + { register tree value1 = check_case_value ((yyvsp[(2) - (5)].ttype)); + register tree value2 = check_case_value ((yyvsp[(4) - (5)].ttype)); + register tree label + = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + + if (pedantic) + pedwarn ("ANSI C forbids case ranges"); + stmt_count++; + + if (value1 != error_mark_node && value2 != error_mark_node) + { + tree duplicate; + int success = pushcase_range (value1, value2, + convert_and_check, label, + &duplicate); + if (success == 1) + error ("case label not within a switch statement"); + else if (success == 2) + { + error ("duplicate case value"); + error_with_decl (duplicate, "this is the first entry for that value"); + } + else if (success == 3) + warning ("case value out of range"); + else if (success == 4) + warning ("empty case range"); + else if (success == 5) + error ("case label within scope of cleanup or variable array"); + } + position_after_white_space (); ;} + break; + + case 366: + + { + tree duplicate; + register tree label + = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + int success = pushcase (NULL_TREE, 0, label, &duplicate); + stmt_count++; + if (success == 1) + error ("default label not within a switch statement"); + else if (success == 2) + { + error ("multiple default labels in one switch"); + error_with_decl (duplicate, "this is the first default label"); + } + position_after_white_space (); ;} + break; + + case 367: + + { tree label = define_label (input_filename, lineno, (yyvsp[(1) - (3)].ttype)); + stmt_count++; + emit_nop (); + if (label) + { + expand_label (label); + decl_attributes (label, (yyvsp[(3) - (3)].ttype), NULL_TREE); + } + position_after_white_space (); ;} + break; + + case 368: + + { emit_line_note (input_filename, lineno); + (yyval.ttype) = NULL_TREE; ;} + break; + + case 369: + + { emit_line_note (input_filename, lineno); ;} + break; + + case 370: + + { (yyval.ttype) = NULL_TREE; ;} + break; + + case 372: + + { (yyval.ttype) = NULL_TREE; ;} + break; + + case 375: + + { (yyval.ttype) = chainon ((yyvsp[(1) - (3)].ttype), (yyvsp[(3) - (3)].ttype)); ;} + break; + + case 376: + + { (yyval.ttype) = build_tree_list ((yyvsp[(1) - (4)].ttype), (yyvsp[(3) - (4)].ttype)); ;} + break; + + case 377: + + { (yyval.ttype) = tree_cons (NULL_TREE, combine_strings ((yyvsp[(1) - (1)].ttype)), NULL_TREE); ;} + break; + + case 378: + + { (yyval.ttype) = tree_cons (NULL_TREE, combine_strings ((yyvsp[(3) - (3)].ttype)), (yyvsp[(1) - (3)].ttype)); ;} + break; + + case 379: + + { pushlevel (0); + clear_parm_order (); + declare_parm_level (0); ;} + break; + + case 380: + + { (yyval.ttype) = (yyvsp[(2) - (2)].ttype); + parmlist_tags_warning (); + poplevel (0, 0, 0); ;} + break; + + case 382: + + { tree parm; + if (pedantic) + pedwarn ("ANSI C forbids forward parameter declarations"); + /* Mark the forward decls as such. */ + for (parm = getdecls (); parm; parm = TREE_CHAIN (parm)) + TREE_ASM_WRITTEN (parm) = 1; + clear_parm_order (); ;} + break; + + case 383: + + { (yyval.ttype) = (yyvsp[(4) - (4)].ttype); ;} + break; + + case 384: + + { (yyval.ttype) = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE); ;} + break; + + case 385: + + { (yyval.ttype) = get_parm_info (0); ;} + break; + + case 386: + + { (yyval.ttype) = get_parm_info (0); + /* Gcc used to allow this as an extension. However, it does + not work for all targets, and thus has been disabled. + Also, since func (...) and func () are indistinguishable, + it caused problems with the code in expand_builtin which + tries to verify that BUILT_IN_NEXT_ARG is being used + correctly. */ + error ("ANSI C requires a named argument before `...'"); + ;} + break; + + case 387: + + { (yyval.ttype) = get_parm_info (1); ;} + break; + + case 388: + + { (yyval.ttype) = get_parm_info (0); ;} + break; + + case 389: + + { push_parm_decl ((yyvsp[(1) - (1)].ttype)); ;} + break; + + case 390: + + { push_parm_decl ((yyvsp[(3) - (3)].ttype)); ;} + break; + + case 391: + + { (yyval.ttype) = build_tree_list (build_tree_list (current_declspecs, + (yyvsp[(3) - (4)].ttype)), + build_tree_list (prefix_attributes, + (yyvsp[(4) - (4)].ttype))); + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(2) - (4)].itype)); ;} + break; + + case 392: + + { (yyval.ttype) = build_tree_list (build_tree_list (current_declspecs, + (yyvsp[(3) - (4)].ttype)), + build_tree_list (prefix_attributes, + (yyvsp[(4) - (4)].ttype))); + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(2) - (4)].itype)); ;} + break; + + case 393: + + { (yyval.ttype) = build_tree_list (build_tree_list (current_declspecs, + (yyvsp[(3) - (4)].ttype)), + build_tree_list (prefix_attributes, + (yyvsp[(4) - (4)].ttype))); + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(2) - (4)].itype)); ;} + break; + + case 394: + + { (yyval.ttype) = build_tree_list (build_tree_list (current_declspecs, + (yyvsp[(3) - (4)].ttype)), + build_tree_list (prefix_attributes, + (yyvsp[(4) - (4)].ttype))); + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(2) - (4)].itype)); ;} + break; + + case 395: + + { (yyval.ttype) = build_tree_list (build_tree_list (current_declspecs, + (yyvsp[(3) - (4)].ttype)), + build_tree_list (prefix_attributes, + (yyvsp[(4) - (4)].ttype))); + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ((yyvsp[(2) - (4)].itype)); ;} + break; + + case 396: + + { pushlevel (0); + clear_parm_order (); + declare_parm_level (1); ;} + break; + + case 397: + + { (yyval.ttype) = (yyvsp[(2) - (2)].ttype); + parmlist_tags_warning (); + poplevel (0, 0, 0); ;} + break; + + case 399: + + { tree t; + for (t = (yyvsp[(1) - (2)].ttype); t; t = TREE_CHAIN (t)) + if (TREE_VALUE (t) == NULL_TREE) + error ("`...' in old-style identifier list"); + (yyval.ttype) = tree_cons (NULL_TREE, NULL_TREE, (yyvsp[(1) - (2)].ttype)); ;} + break; + + case 400: + + { (yyval.ttype) = build_tree_list (NULL_TREE, (yyvsp[(1) - (1)].ttype)); ;} + break; + + case 401: + + { (yyval.ttype) = chainon ((yyvsp[(1) - (3)].ttype), build_tree_list (NULL_TREE, (yyvsp[(3) - (3)].ttype))); ;} + break; + + case 402: + + { (yyval.ttype) = build_tree_list (NULL_TREE, (yyvsp[(1) - (1)].ttype)); ;} + break; + + case 403: + + { (yyval.ttype) = chainon ((yyvsp[(1) - (3)].ttype), build_tree_list (NULL_TREE, (yyvsp[(3) - (3)].ttype))); ;} + break; + + case 404: + + { (yyval.itype) = pedantic; + pedantic = 0; ;} + break; + + +/* Line 1267 of yacc.c. */ + + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (yymsg); + } + else + { + yyerror (YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse look-ahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse look-ahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + if (yyn == YYFINAL) + YYACCEPT; + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#ifndef yyoverflow +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEOF && yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + + + diff --git a/gcc_arm/c-parse.gperf b/gcc_arm/c-parse.gperf new file mode 100755 index 0000000..324bd24 --- /dev/null +++ b/gcc_arm/c-parse.gperf @@ -0,0 +1,88 @@ +%{ +/* Command-line: gperf -L KR-C -F ', 0, 0' -p -j1 -i 1 -g -o -t -N is_reserved_word -k1,3,$ c-parse.gperf */ +%} +struct resword { char *name; short token; enum rid rid; }; +%% +@class, CLASS, NORID +@compatibility_alias, ALIAS, NORID +@defs, DEFS, NORID +@encode, ENCODE, NORID +@end, END, NORID +@implementation, IMPLEMENTATION, NORID +@interface, INTERFACE, NORID +@private, PRIVATE, NORID +@protected, PROTECTED, NORID +@protocol, PROTOCOL, NORID +@public, PUBLIC, NORID +@selector, SELECTOR, NORID +__alignof, ALIGNOF, NORID +__alignof__, ALIGNOF, NORID +__asm, ASM_KEYWORD, NORID +__asm__, ASM_KEYWORD, NORID +__attribute, ATTRIBUTE, NORID +__attribute__, ATTRIBUTE, NORID +__complex, TYPESPEC, RID_COMPLEX +__complex__, TYPESPEC, RID_COMPLEX +__const, TYPE_QUAL, RID_CONST +__const__, TYPE_QUAL, RID_CONST +__extension__, EXTENSION, NORID +__imag, IMAGPART, NORID +__imag__, IMAGPART, NORID +__inline, SCSPEC, RID_INLINE +__inline__, SCSPEC, RID_INLINE +__iterator, SCSPEC, RID_ITERATOR +__iterator__, SCSPEC, RID_ITERATOR +__label__, LABEL, NORID +__real, REALPART, NORID +__real__, REALPART, NORID +__restrict, TYPE_QUAL, RID_RESTRICT +__restrict__, TYPE_QUAL, RID_RESTRICT +__signed, TYPESPEC, RID_SIGNED +__signed__, TYPESPEC, RID_SIGNED +__typeof, TYPEOF, NORID +__typeof__, TYPEOF, NORID +__volatile, TYPE_QUAL, RID_VOLATILE +__volatile__, TYPE_QUAL, RID_VOLATILE +asm, ASM_KEYWORD, NORID +auto, SCSPEC, RID_AUTO +break, BREAK, NORID +bycopy, TYPE_QUAL, RID_BYCOPY +byref, TYPE_QUAL, RID_BYREF +case, CASE, NORID +char, TYPESPEC, RID_CHAR +const, TYPE_QUAL, RID_CONST +continue, CONTINUE, NORID +default, DEFAULT, NORID +do, DO, NORID +double, TYPESPEC, RID_DOUBLE +else, ELSE, NORID +enum, ENUM, NORID +extern, SCSPEC, RID_EXTERN +float, TYPESPEC, RID_FLOAT +for, FOR, NORID +goto, GOTO, NORID +id, OBJECTNAME, RID_ID +if, IF, NORID +in, TYPE_QUAL, RID_IN +inout, TYPE_QUAL, RID_INOUT +inline, SCSPEC, RID_INLINE +int, TYPESPEC, RID_INT +long, TYPESPEC, RID_LONG +oneway, TYPE_QUAL, RID_ONEWAY +out, TYPE_QUAL, RID_OUT +register, SCSPEC, RID_REGISTER +restrict, TYPE_QUAL, RID_RESTRICT +return, RETURN, NORID +short, TYPESPEC, RID_SHORT +signed, TYPESPEC, RID_SIGNED +sizeof, SIZEOF, NORID +static, SCSPEC, RID_STATIC +struct, STRUCT, NORID +switch, SWITCH, NORID +typedef, SCSPEC, RID_TYPEDEF +typeof, TYPEOF, NORID +union, UNION, NORID +unsigned, TYPESPEC, RID_UNSIGNED +void, TYPESPEC, RID_VOID +volatile, TYPE_QUAL, RID_VOLATILE +while, WHILE, NORID diff --git a/gcc_arm/c-parse.h b/gcc_arm/c-parse.h new file mode 100644 index 0000000..e8521ac --- /dev/null +++ b/gcc_arm/c-parse.h @@ -0,0 +1,114 @@ +/* A Bison parser, made by GNU Bison 2.3. */ + +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* Tokens. */ +#define IDENTIFIER 258 +#define TYPENAME 259 +#define SCSPEC 260 +#define TYPESPEC 261 +#define TYPE_QUAL 262 +#define CONSTANT 263 +#define STRING 264 +#define ELLIPSIS 265 +#define SIZEOF 266 +#define ENUM 267 +#define STRUCT 268 +#define UNION 269 +#define IF 270 +#define ELSE 271 +#define WHILE 272 +#define DO 273 +#define FOR 274 +#define SWITCH 275 +#define CASE 276 +#define DEFAULT 277 +#define BREAK 278 +#define CONTINUE 279 +#define RETURN 280 +#define GOTO 281 +#define ASM_KEYWORD 282 +#define TYPEOF 283 +#define ALIGNOF 284 +#define ATTRIBUTE 285 +#define EXTENSION 286 +#define LABEL 287 +#define REALPART 288 +#define IMAGPART 289 +#define ASSIGN 290 +#define OROR 291 +#define ANDAND 292 +#define EQCOMPARE 293 +#define ARITHCOMPARE 294 +#define RSHIFT 295 +#define LSHIFT 296 +#define MINUSMINUS 297 +#define PLUSPLUS 298 +#define UNARY 299 +#define HYPERUNARY 300 +#define POINTSAT 301 +#define INTERFACE 302 +#define IMPLEMENTATION 303 +#define END 304 +#define SELECTOR 305 +#define DEFS 306 +#define ENCODE 307 +#define CLASSNAME 308 +#define PUBLIC 309 +#define PRIVATE 310 +#define PROTECTED 311 +#define PROTOCOL 312 +#define OBJECTNAME 313 +#define CLASS 314 +#define ALIAS 315 +#define OBJC_STRING 316 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +#line 87 "c-parse.y" +{long itype; tree ttype; enum tree_code code; + char *filename; int lineno; int ends_in_label; } +/* Line 1489 of yacc.c. */ +#line 174 "c-parse.h" + YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + +extern YYSTYPE yylval; + diff --git a/gcc_arm/c-parse.in b/gcc_arm/c-parse.in new file mode 100755 index 0000000..8e70770 --- /dev/null +++ b/gcc_arm/c-parse.in @@ -0,0 +1,3079 @@ +/* YACC parser for C syntax and for Objective C. -*-c-*- + Copyright (C) 1987, 88, 89, 92-98, 1999 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* This file defines the grammar of C and that of Objective C. + ifobjc ... end ifobjc conditionals contain code for Objective C only. + ifc ... end ifc conditionals contain code for C only. + Sed commands in Makefile.in are used to convert this file into + c-parse.y and into objc-parse.y. */ + +/* To whomever it may concern: I have heard that such a thing was once + written by AT&T, but I have never seen it. */ + +ifobjc +%expect 66 +end ifobjc +ifc +%expect 46 + +/* These are the 23 conflicts you should get in parse.output; + the state numbers may vary if minor changes in the grammar are made. + +State 42 contains 1 shift/reduce conflict. (Two ways to parse ATTRIBUTE.) +State 44 contains 1 shift/reduce conflict. (Two ways to recover from error.) +State 103 contains 1 shift/reduce conflict. (Two ways to recover from error.) +State 110 contains 1 shift/reduce conflict. (Two ways to parse ATTRIBUTE.) +State 111 contains 1 shift/reduce conflict. (Two ways to recover from error.) +State 115 contains 1 shift/reduce conflict. (Two ways to recover from error.) +State 132 contains 1 shift/reduce conflict. (See comment at component_decl.) +State 180 contains 1 shift/reduce conflict. (Two ways to parse ATTRIBUTE.) +State 194 contains 2 shift/reduce conflict. (Four ways to parse this.) +State 202 contains 1 shift/reduce conflict. (Two ways to recover from error.) +State 214 contains 1 shift/reduce conflict. (Two ways to recover from error.) +State 220 contains 1 shift/reduce conflict. (Two ways to recover from error.) +State 304 contains 2 shift/reduce conflicts. (Four ways to parse this.) +State 335 contains 2 shift/reduce conflicts. (Four ways to parse this.) +State 347 contains 1 shift/reduce conflict. (Two ways to parse ATTRIBUTES.) +State 352 contains 1 shift/reduce conflict. (Two ways to parse ATTRIBUTES.) +State 383 contains 2 shift/reduce conflicts. (Four ways to parse this.) +State 434 contains 2 shift/reduce conflicts. (Four ways to parse this.) */ + +end ifc + +%{ +#include "config.h" +#include "system.h" +#include + +#include "tree.h" +#include "input.h" +#include "c-lex.h" +#include "c-tree.h" +#include "flags.h" +#include "output.h" +#include "toplev.h" + +#ifdef MULTIBYTE_CHARS +#include +#endif + +ifobjc +#include "objc-act.h" +end ifobjc + +/* Since parsers are distinct for each language, put the language string + definition here. */ +ifobjc +char *language_string = "GNU Obj-C"; +end ifobjc +ifc +char *language_string = "GNU C"; +end ifc + +/* Like YYERROR but do call yyerror. */ +#define YYERROR1 { yyerror ("syntax error"); YYERROR; } + +/* Cause the `yydebug' variable to be defined. */ +#define YYDEBUG 1 +%} + +%start program + +%union {long itype; tree ttype; enum tree_code code; + char *filename; int lineno; int ends_in_label; } + +/* All identifiers that are not reserved words + and are not declared typedefs in the current block */ +%token IDENTIFIER + +/* All identifiers that are declared typedefs in the current block. + In some contexts, they are treated just like IDENTIFIER, + but they can also serve as typespecs in declarations. */ +%token TYPENAME + +/* Reserved words that specify storage class. + yylval contains an IDENTIFIER_NODE which indicates which one. */ +%token SCSPEC + +/* Reserved words that specify type. + yylval contains an IDENTIFIER_NODE which indicates which one. */ +%token TYPESPEC + +/* Reserved words that qualify type: "const", "volatile", or "restrict". + yylval contains an IDENTIFIER_NODE which indicates which one. */ +%token TYPE_QUAL + +/* Character or numeric constants. + yylval is the node for the constant. */ +%token CONSTANT + +/* String constants in raw form. + yylval is a STRING_CST node. */ +%token STRING + +/* "...", used for functions with variable arglists. */ +%token ELLIPSIS + +/* the reserved words */ +/* SCO include files test "ASM", so use something else. */ +%token SIZEOF ENUM STRUCT UNION IF ELSE WHILE DO FOR SWITCH CASE DEFAULT +%token BREAK CONTINUE RETURN GOTO ASM_KEYWORD TYPEOF ALIGNOF +%token ATTRIBUTE EXTENSION LABEL +%token REALPART IMAGPART + +/* Add precedence rules to solve dangling else s/r conflict */ +%nonassoc IF +%nonassoc ELSE + +/* Define the operator tokens and their precedences. + The value is an integer because, if used, it is the tree code + to use in the expression made from the operator. */ + +%right ASSIGN '=' +%right '?' ':' +%left OROR +%left ANDAND +%left '|' +%left '^' +%left '&' +%left EQCOMPARE +%left ARITHCOMPARE +%left LSHIFT RSHIFT +%left '+' '-' +%left '*' '/' '%' +%right UNARY PLUSPLUS MINUSMINUS +%left HYPERUNARY +%left POINTSAT '.' '(' '[' + +/* The Objective-C keywords. These are included in C and in + Objective C, so that the token codes are the same in both. */ +%token INTERFACE IMPLEMENTATION END SELECTOR DEFS ENCODE +%token CLASSNAME PUBLIC PRIVATE PROTECTED PROTOCOL OBJECTNAME CLASS ALIAS + +/* Objective-C string constants in raw form. + yylval is an OBJC_STRING_CST node. */ +%token OBJC_STRING + + +%type unop + +%type identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist exprlist +%type expr_no_commas cast_expr unary_expr primary string STRING +%type typed_declspecs reserved_declspecs +%type typed_typespecs reserved_typespecquals +%type declmods typespec typespecqual_reserved +%type typed_declspecs_no_prefix_attr reserved_declspecs_no_prefix_attr +%type declmods_no_prefix_attr +%type SCSPEC TYPESPEC TYPE_QUAL nonempty_type_quals maybe_type_qual +%type initdecls notype_initdecls initdcl notype_initdcl +%type init maybeasm +%type asm_operands nonnull_asm_operands asm_operand asm_clobbers +%type maybe_attribute attributes attribute attribute_list attrib +%type any_word + +%type compstmt + +%type declarator +%type notype_declarator after_type_declarator +%type parm_declarator + +%type structsp component_decl_list component_decl_list2 +%type component_decl components component_declarator +%type enumlist enumerator +%type struct_head union_head enum_head +%type typename absdcl absdcl1 type_quals +%type xexpr parms parm identifiers + +%type parmlist parmlist_1 parmlist_2 +%type parmlist_or_identifiers parmlist_or_identifiers_1 +%type identifiers_or_typenames + +%type setspecs + +%type lineno_stmt_or_label lineno_stmt_or_labels stmt_or_label + +%type save_filename +%type save_lineno + +ifobjc +/* the Objective-C nonterminals */ + +%type ivar_decl_list ivar_decls ivar_decl ivars ivar_declarator +%type methoddecl unaryselector keywordselector selector +%type keyworddecl receiver objcmessageexpr messageargs +%type keywordexpr keywordarglist keywordarg +%type myparms myparm optparmlist reservedwords objcselectorexpr +%type selectorarg keywordnamelist keywordname objcencodeexpr +%type objc_string non_empty_protocolrefs protocolrefs identifier_list objcprotocolexpr + +%type CLASSNAME OBJC_STRING OBJECTNAME +end ifobjc + +%{ +/* Number of statements (loosely speaking) and compound statements + seen so far. */ +static int stmt_count; +static int compstmt_count; + +/* Input file and line number of the end of the body of last simple_if; + used by the stmt-rule immediately after simple_if returns. */ +static char *if_stmt_file; +static int if_stmt_line; + +/* List of types and structure classes of the current declaration. */ +static tree current_declspecs = NULL_TREE; +static tree prefix_attributes = NULL_TREE; + +/* Stack of saved values of current_declspecs and prefix_attributes. */ +static tree declspec_stack; + +/* 1 if we explained undeclared var errors. */ +static int undeclared_variable_notice; + +ifobjc +/* Objective-C specific information */ + +tree objc_interface_context; +tree objc_implementation_context; +tree objc_method_context; +tree objc_ivar_chain; +tree objc_ivar_context; +enum tree_code objc_inherit_code; +int objc_receiver_context; +int objc_public_flag; + +end ifobjc + +/* Tell yyparse how to print a token's value, if yydebug is set. */ + +#define YYPRINT(FILE,YYCHAR,YYLVAL) yyprint(FILE,YYCHAR,YYLVAL) +extern void yyprint PROTO ((FILE *, int, YYSTYPE)); +%} + +%% +program: /* empty */ + { if (pedantic) + pedwarn ("ANSI C forbids an empty source file"); + finish_file (); + } + | extdefs + { + /* In case there were missing closebraces, + get us back to the global binding level. */ + while (! global_bindings_p ()) + poplevel (0, 0, 0); + finish_file (); + } + ; + +/* the reason for the strange actions in this rule + is so that notype_initdecls when reached via datadef + can find a valid list of type and sc specs in $0. */ + +extdefs: + {$$ = NULL_TREE; } extdef + | extdefs {$$ = NULL_TREE; } extdef + ; + +extdef: + fndef + | datadef +ifobjc + | objcdef +end ifobjc + | ASM_KEYWORD '(' expr ')' ';' + { STRIP_NOPS ($3); + if ((TREE_CODE ($3) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND ($3, 0)) == STRING_CST) + || TREE_CODE ($3) == STRING_CST) + assemble_asm ($3); + else + error ("argument of `asm' is not a constant string"); } + | extension extdef + { pedantic = $1; } + ; + +datadef: + setspecs notype_initdecls ';' + { if (pedantic) + error ("ANSI C forbids data definition with no type or storage class"); + else if (!flag_traditional) + warning ("data definition has no type or storage class"); + + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($1); } + | declmods setspecs notype_initdecls ';' + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | typed_declspecs setspecs initdecls ';' + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | declmods ';' + { pedwarn ("empty declaration"); } + | typed_declspecs ';' + { shadow_tag ($1); } + | error ';' + | error '}' + | ';' + { if (pedantic) + pedwarn ("ANSI C does not allow extra `;' outside of a function"); } + ; + +fndef: + typed_declspecs setspecs declarator + { if (! start_function (current_declspecs, $3, + prefix_attributes, NULL_TREE, 0)) + YYERROR1; + reinit_parse_for_function (); } + old_style_parm_decls + { store_parm_decls (); } + compstmt_or_error + { finish_function (0); + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | typed_declspecs setspecs declarator error + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | declmods setspecs notype_declarator + { if (! start_function (current_declspecs, $3, + prefix_attributes, NULL_TREE, 0)) + YYERROR1; + reinit_parse_for_function (); } + old_style_parm_decls + { store_parm_decls (); } + compstmt_or_error + { finish_function (0); + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | declmods setspecs notype_declarator error + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | setspecs notype_declarator + { if (! start_function (NULL_TREE, $2, + prefix_attributes, NULL_TREE, 0)) + YYERROR1; + reinit_parse_for_function (); } + old_style_parm_decls + { store_parm_decls (); } + compstmt_or_error + { finish_function (0); + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($1); } + | setspecs notype_declarator error + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($1); } + ; + +identifier: + IDENTIFIER + | TYPENAME +ifobjc + | OBJECTNAME + | CLASSNAME +end ifobjc + ; + +unop: '&' + { $$ = ADDR_EXPR; } + | '-' + { $$ = NEGATE_EXPR; } + | '+' + { $$ = CONVERT_EXPR; } + | PLUSPLUS + { $$ = PREINCREMENT_EXPR; } + | MINUSMINUS + { $$ = PREDECREMENT_EXPR; } + | '~' + { $$ = BIT_NOT_EXPR; } + | '!' + { $$ = TRUTH_NOT_EXPR; } + ; + +expr: nonnull_exprlist + { $$ = build_compound_expr ($1); } + ; + +exprlist: + /* empty */ + { $$ = NULL_TREE; } + | nonnull_exprlist + ; + +nonnull_exprlist: + expr_no_commas + { $$ = build_tree_list (NULL_TREE, $1); } + | nonnull_exprlist ',' expr_no_commas + { chainon ($1, build_tree_list (NULL_TREE, $3)); } + ; + +unary_expr: + primary + | '*' cast_expr %prec UNARY + { $$ = build_indirect_ref ($2, "unary *"); } + /* __extension__ turns off -pedantic for following primary. */ + | extension cast_expr %prec UNARY + { $$ = $2; + pedantic = $1; } + | unop cast_expr %prec UNARY + { $$ = build_unary_op ($1, $2, 0); + overflow_warning ($$); } + /* Refer to the address of a label as a pointer. */ + | ANDAND identifier + { tree label = lookup_label ($2); + if (pedantic) + pedwarn ("ANSI C forbids `&&'"); + if (label == 0) + $$ = null_pointer_node; + else + { + TREE_USED (label) = 1; + $$ = build1 (ADDR_EXPR, ptr_type_node, label); + TREE_CONSTANT ($$) = 1; + } + } +/* This seems to be impossible on some machines, so let's turn it off. + You can use __builtin_next_arg to find the anonymous stack args. + | '&' ELLIPSIS + { tree types = TYPE_ARG_TYPES (TREE_TYPE (current_function_decl)); + $$ = error_mark_node; + if (TREE_VALUE (tree_last (types)) == void_type_node) + error ("`&...' used in function with fixed number of arguments"); + else + { + if (pedantic) + pedwarn ("ANSI C forbids `&...'"); + $$ = tree_last (DECL_ARGUMENTS (current_function_decl)); + $$ = build_unary_op (ADDR_EXPR, $$, 0); + } } +*/ + | sizeof unary_expr %prec UNARY + { skip_evaluation--; + if (TREE_CODE ($2) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND ($2, 1))) + error ("`sizeof' applied to a bit-field"); + $$ = c_sizeof (TREE_TYPE ($2)); } + | sizeof '(' typename ')' %prec HYPERUNARY + { skip_evaluation--; + $$ = c_sizeof (groktypename ($3)); } + | alignof unary_expr %prec UNARY + { skip_evaluation--; + $$ = c_alignof_expr ($2); } + | alignof '(' typename ')' %prec HYPERUNARY + { skip_evaluation--; + $$ = c_alignof (groktypename ($3)); } + | REALPART cast_expr %prec UNARY + { $$ = build_unary_op (REALPART_EXPR, $2, 0); } + | IMAGPART cast_expr %prec UNARY + { $$ = build_unary_op (IMAGPART_EXPR, $2, 0); } + ; + +sizeof: + SIZEOF { skip_evaluation++; } + ; + +alignof: + ALIGNOF { skip_evaluation++; } + ; + +cast_expr: + unary_expr + | '(' typename ')' cast_expr %prec UNARY + { tree type = groktypename ($2); + $$ = build_c_cast (type, $4); } + | '(' typename ')' '{' + { start_init (NULL_TREE, NULL, 0); + $2 = groktypename ($2); + really_start_incremental_init ($2); } + initlist_maybe_comma '}' %prec UNARY + { char *name; + tree result = pop_init_level (0); + tree type = $2; + finish_init (); + + if (pedantic && ! flag_isoc9x) + pedwarn ("ANSI C forbids constructor expressions"); + if (TYPE_NAME (type) != 0) + { + if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) + name = IDENTIFIER_POINTER (TYPE_NAME (type)); + else + name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); + } + else + name = ""; + $$ = result; + if (TREE_CODE (type) == ARRAY_TYPE && TYPE_SIZE (type) == 0) + { + int failure = complete_array_type (type, $$, 1); + if (failure) + abort (); + } + } + ; + +expr_no_commas: + cast_expr + | expr_no_commas '+' expr_no_commas + { $$ = parser_build_binary_op ($2, $1, $3); } + | expr_no_commas '-' expr_no_commas + { $$ = parser_build_binary_op ($2, $1, $3); } + | expr_no_commas '*' expr_no_commas + { $$ = parser_build_binary_op ($2, $1, $3); } + | expr_no_commas '/' expr_no_commas + { $$ = parser_build_binary_op ($2, $1, $3); } + | expr_no_commas '%' expr_no_commas + { $$ = parser_build_binary_op ($2, $1, $3); } + | expr_no_commas LSHIFT expr_no_commas + { $$ = parser_build_binary_op ($2, $1, $3); } + | expr_no_commas RSHIFT expr_no_commas + { $$ = parser_build_binary_op ($2, $1, $3); } + | expr_no_commas ARITHCOMPARE expr_no_commas + { $$ = parser_build_binary_op ($2, $1, $3); } + | expr_no_commas EQCOMPARE expr_no_commas + { $$ = parser_build_binary_op ($2, $1, $3); } + | expr_no_commas '&' expr_no_commas + { $$ = parser_build_binary_op ($2, $1, $3); } + | expr_no_commas '|' expr_no_commas + { $$ = parser_build_binary_op ($2, $1, $3); } + | expr_no_commas '^' expr_no_commas + { $$ = parser_build_binary_op ($2, $1, $3); } + | expr_no_commas ANDAND + { $1 = truthvalue_conversion (default_conversion ($1)); + skip_evaluation += $1 == boolean_false_node; } + expr_no_commas + { skip_evaluation -= $1 == boolean_false_node; + $$ = parser_build_binary_op (TRUTH_ANDIF_EXPR, $1, $4); } + | expr_no_commas OROR + { $1 = truthvalue_conversion (default_conversion ($1)); + skip_evaluation += $1 == boolean_true_node; } + expr_no_commas + { skip_evaluation -= $1 == boolean_true_node; + $$ = parser_build_binary_op (TRUTH_ORIF_EXPR, $1, $4); } + | expr_no_commas '?' + { $1 = truthvalue_conversion (default_conversion ($1)); + skip_evaluation += $1 == boolean_false_node; } + expr ':' + { skip_evaluation += (($1 == boolean_true_node) + - ($1 == boolean_false_node)); } + expr_no_commas + { skip_evaluation -= $1 == boolean_true_node; + $$ = build_conditional_expr ($1, $4, $7); } + | expr_no_commas '?' + { if (pedantic) + pedwarn ("ANSI C forbids omitting the middle term of a ?: expression"); + /* Make sure first operand is calculated only once. */ + $2 = save_expr ($1); + $1 = truthvalue_conversion (default_conversion ($2)); + skip_evaluation += $1 == boolean_true_node; } + ':' expr_no_commas + { skip_evaluation -= $1 == boolean_true_node; + $$ = build_conditional_expr ($1, $2, $5); } + | expr_no_commas '=' expr_no_commas + { $$ = build_modify_expr ($1, NOP_EXPR, $3); + C_SET_EXP_ORIGINAL_CODE ($$, MODIFY_EXPR); } + | expr_no_commas ASSIGN expr_no_commas + { $$ = build_modify_expr ($1, $2, $3); + /* This inhibits warnings in truthvalue_conversion. */ + C_SET_EXP_ORIGINAL_CODE ($$, ERROR_MARK); } + ; + +primary: + IDENTIFIER + { + $$ = lastiddecl; + if (!$$ || $$ == error_mark_node) + { + if (yychar == YYEMPTY) + yychar = YYLEX; + if (yychar == '(') + { +ifobjc + tree decl; + + if (objc_receiver_context + && ! (objc_receiver_context + && strcmp (IDENTIFIER_POINTER ($1), "super"))) + /* we have a message to super */ + $$ = get_super_receiver (); + else if (objc_method_context + && (decl = is_ivar (objc_ivar_chain, $1))) + { + if (is_private (decl)) + $$ = error_mark_node; + else + $$ = build_ivar_reference ($1); + } + else +end ifobjc + { + /* Ordinary implicit function declaration. */ + $$ = implicitly_declare ($1); + assemble_external ($$); + TREE_USED ($$) = 1; + } + } + else if (current_function_decl == 0) + { + error ("`%s' undeclared here (not in a function)", + IDENTIFIER_POINTER ($1)); + $$ = error_mark_node; + } + else + { +ifobjc + tree decl; + + if (objc_receiver_context + && ! strcmp (IDENTIFIER_POINTER ($1), "super")) + /* we have a message to super */ + $$ = get_super_receiver (); + else if (objc_method_context + && (decl = is_ivar (objc_ivar_chain, $1))) + { + if (is_private (decl)) + $$ = error_mark_node; + else + $$ = build_ivar_reference ($1); + } + else +end ifobjc + { + if (IDENTIFIER_GLOBAL_VALUE ($1) != error_mark_node + || IDENTIFIER_ERROR_LOCUS ($1) != current_function_decl) + { + error ("`%s' undeclared (first use in this function)", + IDENTIFIER_POINTER ($1)); + + if (! undeclared_variable_notice) + { + error ("(Each undeclared identifier is reported only once"); + error ("for each function it appears in.)"); + undeclared_variable_notice = 1; + } + } + $$ = error_mark_node; + /* Prevent repeated error messages. */ + IDENTIFIER_GLOBAL_VALUE ($1) = error_mark_node; + IDENTIFIER_ERROR_LOCUS ($1) = current_function_decl; + } + } + } + else if (TREE_TYPE ($$) == error_mark_node) + $$ = error_mark_node; + else if (C_DECL_ANTICIPATED ($$)) + { + /* The first time we see a build-in function used, + if it has not been declared. */ + C_DECL_ANTICIPATED ($$) = 0; + if (yychar == YYEMPTY) + yychar = YYLEX; + if (yychar == '(') + { + /* Omit the implicit declaration we + would ordinarily do, so we don't lose + the actual built in type. + But print a diagnostic for the mismatch. */ +ifobjc + if (objc_method_context + && is_ivar (objc_ivar_chain, $1)) + error ("Instance variable `%s' implicitly declared as function", + IDENTIFIER_POINTER (DECL_NAME ($$))); + else +end ifobjc + if (TREE_CODE ($$) != FUNCTION_DECL) + error ("`%s' implicitly declared as function", + IDENTIFIER_POINTER (DECL_NAME ($$))); + else if ((TYPE_MODE (TREE_TYPE (TREE_TYPE ($$))) + != TYPE_MODE (integer_type_node)) + && (TREE_TYPE (TREE_TYPE ($$)) + != void_type_node)) + pedwarn ("type mismatch in implicit declaration for built-in function `%s'", + IDENTIFIER_POINTER (DECL_NAME ($$))); + /* If it really returns void, change that to int. */ + if (TREE_TYPE (TREE_TYPE ($$)) == void_type_node) + TREE_TYPE ($$) + = build_function_type (integer_type_node, + TYPE_ARG_TYPES (TREE_TYPE ($$))); + } + else + pedwarn ("built-in function `%s' used without declaration", + IDENTIFIER_POINTER (DECL_NAME ($$))); + + /* Do what we would ordinarily do when a fn is used. */ + assemble_external ($$); + TREE_USED ($$) = 1; + } + else + { + assemble_external ($$); + TREE_USED ($$) = 1; +ifobjc + /* we have a definition - still check if iVariable */ + + if (!objc_receiver_context + || (objc_receiver_context + && strcmp (IDENTIFIER_POINTER ($1), "super"))) + { + tree decl; + + if (objc_method_context + && (decl = is_ivar (objc_ivar_chain, $1))) + { + if (IDENTIFIER_LOCAL_VALUE ($1)) + warning ("local declaration of `%s' hides instance variable", + IDENTIFIER_POINTER ($1)); + else + { + if (is_private (decl)) + $$ = error_mark_node; + else + $$ = build_ivar_reference ($1); + } + } + } + else /* we have a message to super */ + $$ = get_super_receiver (); +end ifobjc + } + + if (TREE_CODE ($$) == CONST_DECL) + { + $$ = DECL_INITIAL ($$); + /* This is to prevent an enum whose value is 0 + from being considered a null pointer constant. */ + $$ = build1 (NOP_EXPR, TREE_TYPE ($$), $$); + TREE_CONSTANT ($$) = 1; + } + } + | CONSTANT + | string + { $$ = combine_strings ($1); } + | '(' expr ')' + { char class = TREE_CODE_CLASS (TREE_CODE ($2)); + if (class == 'e' || class == '1' + || class == '2' || class == '<') + C_SET_EXP_ORIGINAL_CODE ($2, ERROR_MARK); + $$ = $2; } + | '(' error ')' + { $$ = error_mark_node; } + | '(' + { if (current_function_decl == 0) + { + error ("braced-group within expression allowed only inside a function"); + YYERROR; + } + /* We must force a BLOCK for this level + so that, if it is not expanded later, + there is a way to turn off the entire subtree of blocks + that are contained in it. */ + keep_next_level (); + push_iterator_stack (); + push_label_level (); + $$ = expand_start_stmt_expr (); } + compstmt ')' + { tree rtl_exp; + if (pedantic) + pedwarn ("ANSI C forbids braced-groups within expressions"); + pop_iterator_stack (); + pop_label_level (); + rtl_exp = expand_end_stmt_expr ($2); + /* The statements have side effects, so the group does. */ + TREE_SIDE_EFFECTS (rtl_exp) = 1; + + if (TREE_CODE ($3) == BLOCK) + { + /* Make a BIND_EXPR for the BLOCK already made. */ + $$ = build (BIND_EXPR, TREE_TYPE (rtl_exp), + NULL_TREE, rtl_exp, $3); + /* Remove the block from the tree at this point. + It gets put back at the proper place + when the BIND_EXPR is expanded. */ + delete_block ($3); + } + else + $$ = $3; + } + | primary '(' exprlist ')' %prec '.' + { $$ = build_function_call ($1, $3); } + | primary '[' expr ']' %prec '.' + { $$ = build_array_ref ($1, $3); } + | primary '.' identifier + { +ifobjc + if (doing_objc_thang) + { + if (is_public ($1, $3)) + $$ = build_component_ref ($1, $3); + else + $$ = error_mark_node; + } + else +end ifobjc + $$ = build_component_ref ($1, $3); + } + | primary POINTSAT identifier + { + tree expr = build_indirect_ref ($1, "->"); + +ifobjc + if (doing_objc_thang) + { + if (is_public (expr, $3)) + $$ = build_component_ref (expr, $3); + else + $$ = error_mark_node; + } + else +end ifobjc + $$ = build_component_ref (expr, $3); + } + | primary PLUSPLUS + { $$ = build_unary_op (POSTINCREMENT_EXPR, $1, 0); } + | primary MINUSMINUS + { $$ = build_unary_op (POSTDECREMENT_EXPR, $1, 0); } +ifobjc + | objcmessageexpr + { $$ = build_message_expr ($1); } + | objcselectorexpr + { $$ = build_selector_expr ($1); } + | objcprotocolexpr + { $$ = build_protocol_expr ($1); } + | objcencodeexpr + { $$ = build_encode_expr ($1); } + | objc_string + { $$ = build_objc_string_object ($1); } +end ifobjc + ; + +/* Produces a STRING_CST with perhaps more STRING_CSTs chained onto it. */ +string: + STRING + | string STRING + { $$ = chainon ($1, $2); } + ; + +ifobjc +/* Produces an OBJC_STRING_CST with perhaps more OBJC_STRING_CSTs chained + onto it. */ +objc_string: + OBJC_STRING + | objc_string OBJC_STRING + { $$ = chainon ($1, $2); } + ; +end ifobjc + +old_style_parm_decls: + /* empty */ + | datadecls + | datadecls ELLIPSIS + /* ... is used here to indicate a varargs function. */ + { c_mark_varargs (); + if (pedantic) + pedwarn ("ANSI C does not permit use of `varargs.h'"); } + ; + +/* The following are analogous to lineno_decl, decls and decl + except that they do not allow nested functions. + They are used for old-style parm decls. */ +lineno_datadecl: + save_filename save_lineno datadecl + { } + ; + +datadecls: + lineno_datadecl + | errstmt + | datadecls lineno_datadecl + | lineno_datadecl errstmt + ; + +/* We don't allow prefix attributes here because they cause reduce/reduce + conflicts: we can't know whether we're parsing a function decl with + attribute suffix, or function defn with attribute prefix on first old + style parm. */ +datadecl: + typed_declspecs_no_prefix_attr setspecs initdecls ';' + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | declmods_no_prefix_attr setspecs notype_initdecls ';' + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | typed_declspecs_no_prefix_attr ';' + { shadow_tag_warned ($1, 1); + pedwarn ("empty declaration"); } + | declmods_no_prefix_attr ';' + { pedwarn ("empty declaration"); } + ; + +/* This combination which saves a lineno before a decl + is the normal thing to use, rather than decl itself. + This is to avoid shift/reduce conflicts in contexts + where statement labels are allowed. */ +lineno_decl: + save_filename save_lineno decl + { } + ; + +decls: + lineno_decl + | errstmt + | decls lineno_decl + | lineno_decl errstmt + ; + +/* records the type and storage class specs to use for processing + the declarators that follow. + Maintains a stack of outer-level values of current_declspecs, + for the sake of parm declarations nested in function declarators. */ +setspecs: /* empty */ + { $$ = suspend_momentary (); + pending_xref_error (); + declspec_stack = tree_cons (prefix_attributes, + current_declspecs, + declspec_stack); + split_specs_attrs ($0, + ¤t_declspecs, &prefix_attributes); } + ; + +/* ??? Yuck. See after_type_declarator. */ +setattrs: /* empty */ + { prefix_attributes = chainon (prefix_attributes, $0); } + ; + +decl: + typed_declspecs setspecs initdecls ';' + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | declmods setspecs notype_initdecls ';' + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | typed_declspecs setspecs nested_function + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | declmods setspecs notype_nested_function + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | typed_declspecs ';' + { shadow_tag ($1); } + | declmods ';' + { pedwarn ("empty declaration"); } + | extension decl + { pedantic = $1; } + ; + +/* Declspecs which contain at least one type specifier or typedef name. + (Just `const' or `volatile' is not enough.) + A typedef'd name following these is taken as a name to be declared. + Declspecs have a non-NULL TREE_VALUE, attributes do not. */ + +typed_declspecs: + typespec reserved_declspecs + { $$ = tree_cons (NULL_TREE, $1, $2); } + | declmods typespec reserved_declspecs + { $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); } + ; + +reserved_declspecs: /* empty */ + { $$ = NULL_TREE; } + | reserved_declspecs typespecqual_reserved + { $$ = tree_cons (NULL_TREE, $2, $1); } + | reserved_declspecs SCSPEC + { if (extra_warnings) + warning ("`%s' is not at beginning of declaration", + IDENTIFIER_POINTER ($2)); + $$ = tree_cons (NULL_TREE, $2, $1); } + | reserved_declspecs attributes + { $$ = tree_cons ($2, NULL_TREE, $1); } + ; + +typed_declspecs_no_prefix_attr: + typespec reserved_declspecs_no_prefix_attr + { $$ = tree_cons (NULL_TREE, $1, $2); } + | declmods_no_prefix_attr typespec reserved_declspecs_no_prefix_attr + { $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); } + ; + +reserved_declspecs_no_prefix_attr: + /* empty */ + { $$ = NULL_TREE; } + | reserved_declspecs_no_prefix_attr typespecqual_reserved + { $$ = tree_cons (NULL_TREE, $2, $1); } + | reserved_declspecs_no_prefix_attr SCSPEC + { if (extra_warnings) + warning ("`%s' is not at beginning of declaration", + IDENTIFIER_POINTER ($2)); + $$ = tree_cons (NULL_TREE, $2, $1); } + ; + +/* List of just storage classes, type modifiers, and prefix attributes. + A declaration can start with just this, but then it cannot be used + to redeclare a typedef-name. + Declspecs have a non-NULL TREE_VALUE, attributes do not. */ + +declmods: + declmods_no_prefix_attr + { $$ = $1; } + | attributes + { $$ = tree_cons ($1, NULL_TREE, NULL_TREE); } + | declmods declmods_no_prefix_attr + { $$ = chainon ($2, $1); } + | declmods attributes + { $$ = tree_cons ($2, NULL_TREE, $1); } + ; + +declmods_no_prefix_attr: + TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); + TREE_STATIC ($$) = 1; } + | SCSPEC + { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); } + | declmods_no_prefix_attr TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declmods_no_prefix_attr SCSPEC + { if (extra_warnings && TREE_STATIC ($1)) + warning ("`%s' is not at beginning of declaration", + IDENTIFIER_POINTER ($2)); + $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } + ; + + +/* Used instead of declspecs where storage classes are not allowed + (that is, for typenames and structure components). + Don't accept a typedef-name if anything but a modifier precedes it. */ + +typed_typespecs: + typespec reserved_typespecquals + { $$ = tree_cons (NULL_TREE, $1, $2); } + | nonempty_type_quals typespec reserved_typespecquals + { $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); } + ; + +reserved_typespecquals: /* empty */ + { $$ = NULL_TREE; } + | reserved_typespecquals typespecqual_reserved + { $$ = tree_cons (NULL_TREE, $2, $1); } + ; + +/* A typespec (but not a type qualifier). + Once we have seen one of these in a declaration, + if a typedef name appears then it is being redeclared. */ + +typespec: TYPESPEC + | structsp + | TYPENAME + { /* For a typedef name, record the meaning, not the name. + In case of `foo foo, bar;'. */ + $$ = lookup_name ($1); } +ifobjc + | CLASSNAME protocolrefs + { $$ = get_static_reference ($1, $2); } + | OBJECTNAME protocolrefs + { $$ = get_object_reference ($2); } + +/* Make "" equivalent to "id " + - nisse@lysator.liu.se */ + | non_empty_protocolrefs + { $$ = get_object_reference ($1); } +end ifobjc + | TYPEOF '(' expr ')' + { $$ = TREE_TYPE ($3); } + | TYPEOF '(' typename ')' + { $$ = groktypename ($3); } + ; + +/* A typespec that is a reserved word, or a type qualifier. */ + +typespecqual_reserved: TYPESPEC + | TYPE_QUAL + | structsp + ; + +initdecls: + initdcl + | initdecls ',' initdcl + ; + +notype_initdecls: + notype_initdcl + | notype_initdecls ',' initdcl + ; + +maybeasm: + /* empty */ + { $$ = NULL_TREE; } + | ASM_KEYWORD '(' string ')' + { if (TREE_CHAIN ($3)) $3 = combine_strings ($3); + $$ = $3; + } + ; + +initdcl: + declarator maybeasm maybe_attribute '=' + { $$ = start_decl ($1, current_declspecs, 1, + $3, prefix_attributes); + start_init ($$, $2, global_bindings_p ()); } + init +/* Note how the declaration of the variable is in effect while its init is parsed! */ + { finish_init (); + finish_decl ($5, $6, $2); } + | declarator maybeasm maybe_attribute + { tree d = start_decl ($1, current_declspecs, 0, + $3, prefix_attributes); + finish_decl (d, NULL_TREE, $2); + } + ; + +notype_initdcl: + notype_declarator maybeasm maybe_attribute '=' + { $$ = start_decl ($1, current_declspecs, 1, + $3, prefix_attributes); + start_init ($$, $2, global_bindings_p ()); } + init +/* Note how the declaration of the variable is in effect while its init is parsed! */ + { finish_init (); + decl_attributes ($5, $3, prefix_attributes); + finish_decl ($5, $6, $2); } + | notype_declarator maybeasm maybe_attribute + { tree d = start_decl ($1, current_declspecs, 0, + $3, prefix_attributes); + finish_decl (d, NULL_TREE, $2); } + ; +/* the * rules are dummies to accept the Apollo extended syntax + so that the header files compile. */ +maybe_attribute: + /* empty */ + { $$ = NULL_TREE; } + | attributes + { $$ = $1; } + ; + +attributes: + attribute + { $$ = $1; } + | attributes attribute + { $$ = chainon ($1, $2); } + ; + +attribute: + ATTRIBUTE '(' '(' attribute_list ')' ')' + { $$ = $4; } + ; + +attribute_list: + attrib + { $$ = $1; } + | attribute_list ',' attrib + { $$ = chainon ($1, $3); } + ; + +attrib: + /* empty */ + { $$ = NULL_TREE; } + | any_word + { $$ = build_tree_list ($1, NULL_TREE); } + | any_word '(' IDENTIFIER ')' + { $$ = build_tree_list ($1, build_tree_list (NULL_TREE, $3)); } + | any_word '(' IDENTIFIER ',' nonnull_exprlist ')' + { $$ = build_tree_list ($1, tree_cons (NULL_TREE, $3, $5)); } + | any_word '(' exprlist ')' + { $$ = build_tree_list ($1, $3); } + ; + +/* This still leaves out most reserved keywords, + shouldn't we include them? */ + +any_word: + identifier + | SCSPEC + | TYPESPEC + | TYPE_QUAL + ; + +/* Initializers. `init' is the entry point. */ + +init: + expr_no_commas + | '{' + { really_start_incremental_init (NULL_TREE); + /* Note that the call to clear_momentary + is in process_init_element. */ + push_momentary (); } + initlist_maybe_comma '}' + { $$ = pop_init_level (0); + if ($$ == error_mark_node + && ! (yychar == STRING || yychar == CONSTANT)) + pop_momentary (); + else + pop_momentary_nofree (); } + + | error + { $$ = error_mark_node; } + ; + +/* `initlist_maybe_comma' is the guts of an initializer in braces. */ +initlist_maybe_comma: + /* empty */ + { if (pedantic) + pedwarn ("ANSI C forbids empty initializer braces"); } + | initlist1 maybecomma + ; + +initlist1: + initelt + | initlist1 ',' initelt + ; + +/* `initelt' is a single element of an initializer. + It may use braces. */ +initelt: + designator_list '=' initval + | designator initval + | identifier ':' + { set_init_label ($1); } + initval + | initval + ; + +initval: + '{' + { push_init_level (0); } + initlist_maybe_comma '}' + { process_init_element (pop_init_level (0)); } + | expr_no_commas + { process_init_element ($1); } + | error + ; + +designator_list: + designator + | designator_list designator + ; + +designator: + '.' identifier + { set_init_label ($2); } + /* These are for labeled elements. The syntax for an array element + initializer conflicts with the syntax for an Objective-C message, + so don't include these productions in the Objective-C grammar. */ +ifc + | '[' expr_no_commas ELLIPSIS expr_no_commas ']' + { set_init_index ($2, $4); } + | '[' expr_no_commas ']' + { set_init_index ($2, NULL_TREE); } +end ifc + ; + +nested_function: + declarator + { push_c_function_context (); + if (! start_function (current_declspecs, $1, + prefix_attributes, NULL_TREE, 1)) + { + pop_c_function_context (); + YYERROR1; + } + reinit_parse_for_function (); } + old_style_parm_decls + { store_parm_decls (); } +/* This used to use compstmt_or_error. + That caused a bug with input `f(g) int g {}', + where the use of YYERROR1 above caused an error + which then was handled by compstmt_or_error. + There followed a repeated execution of that same rule, + which called YYERROR1 again, and so on. */ + compstmt + { finish_function (1); + pop_c_function_context (); } + ; + +notype_nested_function: + notype_declarator + { push_c_function_context (); + if (! start_function (current_declspecs, $1, + prefix_attributes, NULL_TREE, 1)) + { + pop_c_function_context (); + YYERROR1; + } + reinit_parse_for_function (); } + old_style_parm_decls + { store_parm_decls (); } +/* This used to use compstmt_or_error. + That caused a bug with input `f(g) int g {}', + where the use of YYERROR1 above caused an error + which then was handled by compstmt_or_error. + There followed a repeated execution of that same rule, + which called YYERROR1 again, and so on. */ + compstmt + { finish_function (1); + pop_c_function_context (); } + ; + +/* Any kind of declarator (thus, all declarators allowed + after an explicit typespec). */ + +declarator: + after_type_declarator + | notype_declarator + ; + +/* A declarator that is allowed only after an explicit typespec. */ + +after_type_declarator: + '(' after_type_declarator ')' + { $$ = $2; } + | after_type_declarator '(' parmlist_or_identifiers %prec '.' + { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); } +/* | after_type_declarator '(' error ')' %prec '.' + { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE); + poplevel (0, 0, 0); } */ + | after_type_declarator '[' expr ']' %prec '.' + { $$ = build_nt (ARRAY_REF, $1, $3); } + | after_type_declarator '[' ']' %prec '.' + { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } + | '*' type_quals after_type_declarator %prec UNARY + { $$ = make_pointer_declarator ($2, $3); } + /* ??? Yuck. setattrs is a quick hack. We can't use + prefix_attributes because $1 only applies to this + declarator. We assume setspecs has already been done. + setattrs also avoids 5 reduce/reduce conflicts (otherwise multiple + attributes could be recognized here or in `attributes'). */ + | attributes setattrs after_type_declarator + { $$ = $3; } + | TYPENAME +ifobjc + | OBJECTNAME +end ifobjc + ; + +/* Kinds of declarator that can appear in a parameter list + in addition to notype_declarator. This is like after_type_declarator + but does not allow a typedef name in parentheses as an identifier + (because it would conflict with a function with that typedef as arg). */ + +parm_declarator: + parm_declarator '(' parmlist_or_identifiers %prec '.' + { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); } +/* | parm_declarator '(' error ')' %prec '.' + { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE); + poplevel (0, 0, 0); } */ +ifc + | parm_declarator '[' '*' ']' %prec '.' + { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); + if (! flag_isoc9x) + error ("`[*]' in parameter declaration only allowed in ISO C 9x"); + } +end ifc + | parm_declarator '[' expr ']' %prec '.' + { $$ = build_nt (ARRAY_REF, $1, $3); } + | parm_declarator '[' ']' %prec '.' + { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } + | '*' type_quals parm_declarator %prec UNARY + { $$ = make_pointer_declarator ($2, $3); } + /* ??? Yuck. setattrs is a quick hack. We can't use + prefix_attributes because $1 only applies to this + declarator. We assume setspecs has already been done. + setattrs also avoids 5 reduce/reduce conflicts (otherwise multiple + attributes could be recognized here or in `attributes'). */ + | attributes setattrs parm_declarator + { $$ = $3; } + | TYPENAME + ; + +/* A declarator allowed whether or not there has been + an explicit typespec. These cannot redeclare a typedef-name. */ + +notype_declarator: + notype_declarator '(' parmlist_or_identifiers %prec '.' + { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); } +/* | notype_declarator '(' error ')' %prec '.' + { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE); + poplevel (0, 0, 0); } */ + | '(' notype_declarator ')' + { $$ = $2; } + | '*' type_quals notype_declarator %prec UNARY + { $$ = make_pointer_declarator ($2, $3); } +ifc + | notype_declarator '[' '*' ']' %prec '.' + { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); + if (! flag_isoc9x) + error ("`[*]' in parameter declaration only allowed in ISO C 9x"); + } +end ifc + | notype_declarator '[' expr ']' %prec '.' + { $$ = build_nt (ARRAY_REF, $1, $3); } + | notype_declarator '[' ']' %prec '.' + { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } + /* ??? Yuck. setattrs is a quick hack. We can't use + prefix_attributes because $1 only applies to this + declarator. We assume setspecs has already been done. + setattrs also avoids 5 reduce/reduce conflicts (otherwise multiple + attributes could be recognized here or in `attributes'). */ + | attributes setattrs notype_declarator + { $$ = $3; } + | IDENTIFIER + ; + +struct_head: + STRUCT + { $$ = NULL_TREE; } + | STRUCT attributes + { $$ = $2; } + ; + +union_head: + UNION + { $$ = NULL_TREE; } + | UNION attributes + { $$ = $2; } + ; + +enum_head: + ENUM + { $$ = NULL_TREE; } + | ENUM attributes + { $$ = $2; } + ; + +structsp: + struct_head identifier '{' + { $$ = start_struct (RECORD_TYPE, $2); + /* Start scope of tag before parsing components. */ + } + component_decl_list '}' maybe_attribute + { $$ = finish_struct ($4, $5, chainon ($1, $7)); } + | struct_head '{' component_decl_list '}' maybe_attribute + { $$ = finish_struct (start_struct (RECORD_TYPE, NULL_TREE), + $3, chainon ($1, $5)); + } + | struct_head identifier + { $$ = xref_tag (RECORD_TYPE, $2); } + | union_head identifier '{' + { $$ = start_struct (UNION_TYPE, $2); } + component_decl_list '}' maybe_attribute + { $$ = finish_struct ($4, $5, chainon ($1, $7)); } + | union_head '{' component_decl_list '}' maybe_attribute + { $$ = finish_struct (start_struct (UNION_TYPE, NULL_TREE), + $3, chainon ($1, $5)); + } + | union_head identifier + { $$ = xref_tag (UNION_TYPE, $2); } + | enum_head identifier '{' + { $3 = suspend_momentary (); + $$ = start_enum ($2); } + enumlist maybecomma_warn '}' maybe_attribute + { $$= finish_enum ($4, nreverse ($5), chainon ($1, $8)); + resume_momentary ($3); } + | enum_head '{' + { $2 = suspend_momentary (); + $$ = start_enum (NULL_TREE); } + enumlist maybecomma_warn '}' maybe_attribute + { $$= finish_enum ($3, nreverse ($4), chainon ($1, $7)); + resume_momentary ($2); } + | enum_head identifier + { $$ = xref_tag (ENUMERAL_TYPE, $2); } + ; + +maybecomma: + /* empty */ + | ',' + ; + +maybecomma_warn: + /* empty */ + | ',' + { if (pedantic && ! flag_isoc9x) + pedwarn ("comma at end of enumerator list"); } + ; + +component_decl_list: + component_decl_list2 + { $$ = $1; } + | component_decl_list2 component_decl + { $$ = chainon ($1, $2); + pedwarn ("no semicolon at end of struct or union"); } + ; + +component_decl_list2: /* empty */ + { $$ = NULL_TREE; } + | component_decl_list2 component_decl ';' + { $$ = chainon ($1, $2); } + | component_decl_list2 ';' + { if (pedantic) + pedwarn ("extra semicolon in struct or union specified"); } +ifobjc + /* foo(sizeof(struct{ @defs(ClassName)})); */ + | DEFS '(' CLASSNAME ')' + { + tree interface = lookup_interface ($3); + + if (interface) + $$ = get_class_ivars (interface); + else + { + error ("Cannot find interface declaration for `%s'", + IDENTIFIER_POINTER ($3)); + $$ = NULL_TREE; + } + } +end ifobjc + ; + +/* There is a shift-reduce conflict here, because `components' may + start with a `typename'. It happens that shifting (the default resolution) + does the right thing, because it treats the `typename' as part of + a `typed_typespecs'. + + It is possible that this same technique would allow the distinction + between `notype_initdecls' and `initdecls' to be eliminated. + But I am being cautious and not trying it. */ + +component_decl: + typed_typespecs setspecs components + { $$ = $3; + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | typed_typespecs + { if (pedantic) + pedwarn ("ANSI C forbids member declarations with no members"); + shadow_tag($1); + $$ = NULL_TREE; } + | nonempty_type_quals setspecs components + { $$ = $3; + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | nonempty_type_quals + { if (pedantic) + pedwarn ("ANSI C forbids member declarations with no members"); + shadow_tag($1); + $$ = NULL_TREE; } + | error + { $$ = NULL_TREE; } + | extension component_decl + { $$ = $2; + pedantic = $1; } + ; + +components: + component_declarator + | components ',' component_declarator + { $$ = chainon ($1, $3); } + ; + +component_declarator: + save_filename save_lineno declarator maybe_attribute + { $$ = grokfield ($1, $2, $3, current_declspecs, NULL_TREE); + decl_attributes ($$, $4, prefix_attributes); } + | save_filename save_lineno + declarator ':' expr_no_commas maybe_attribute + { $$ = grokfield ($1, $2, $3, current_declspecs, $5); + decl_attributes ($$, $6, prefix_attributes); } + | save_filename save_lineno ':' expr_no_commas maybe_attribute + { $$ = grokfield ($1, $2, NULL_TREE, current_declspecs, $4); + decl_attributes ($$, $5, prefix_attributes); } + ; + +/* We chain the enumerators in reverse order. + They are put in forward order where enumlist is used. + (The order used to be significant, but no longer is so. + However, we still maintain the order, just to be clean.) */ + +enumlist: + enumerator + | enumlist ',' enumerator + { if ($1 == error_mark_node) + $$ = $1; + else + $$ = chainon ($3, $1); } + | error + { $$ = error_mark_node; } + ; + + +enumerator: + identifier + { $$ = build_enumerator ($1, NULL_TREE); } + | identifier '=' expr_no_commas + { $$ = build_enumerator ($1, $3); } + ; + +typename: + typed_typespecs absdcl + { $$ = build_tree_list ($1, $2); } + | nonempty_type_quals absdcl + { $$ = build_tree_list ($1, $2); } + ; + +absdcl: /* an absolute declarator */ + /* empty */ + { $$ = NULL_TREE; } + | absdcl1 + ; + +nonempty_type_quals: + TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); } + | nonempty_type_quals TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); } + ; + +type_quals: + /* empty */ + { $$ = NULL_TREE; } + | type_quals TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); } + ; + +absdcl1: /* a nonempty absolute declarator */ + '(' absdcl1 ')' + { $$ = $2; } + /* `(typedef)1' is `int'. */ + | '*' type_quals absdcl1 %prec UNARY + { $$ = make_pointer_declarator ($2, $3); } + | '*' type_quals %prec UNARY + { $$ = make_pointer_declarator ($2, NULL_TREE); } + | absdcl1 '(' parmlist %prec '.' + { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); } + | absdcl1 '[' expr ']' %prec '.' + { $$ = build_nt (ARRAY_REF, $1, $3); } + | absdcl1 '[' ']' %prec '.' + { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } + | '(' parmlist %prec '.' + { $$ = build_nt (CALL_EXPR, NULL_TREE, $2, NULL_TREE); } + | '[' expr ']' %prec '.' + { $$ = build_nt (ARRAY_REF, NULL_TREE, $2); } + | '[' ']' %prec '.' + { $$ = build_nt (ARRAY_REF, NULL_TREE, NULL_TREE); } + /* ??? It appears we have to support attributes here, however + using prefix_attributes is wrong. */ + ; + +/* at least one statement, the first of which parses without error. */ +/* stmts is used only after decls, so an invalid first statement + is actually regarded as an invalid decl and part of the decls. */ + +stmts: + lineno_stmt_or_labels + { + if (pedantic && $1) + pedwarn ("ANSI C forbids label at end of compound statement"); + } + ; + +lineno_stmt_or_labels: + lineno_stmt_or_label + | lineno_stmt_or_labels lineno_stmt_or_label + { $$ = $2; } + | lineno_stmt_or_labels errstmt + { $$ = 0; } + ; + +xstmts: + /* empty */ + | stmts + ; + +errstmt: error ';' + ; + +pushlevel: /* empty */ + { emit_line_note (input_filename, lineno); + pushlevel (0); + clear_last_expr (); + push_momentary (); + expand_start_bindings (0); +ifobjc + if (objc_method_context) + add_objc_decls (); +end ifobjc + } + ; + +/* Read zero or more forward-declarations for labels + that nested functions can jump to. */ +maybe_label_decls: + /* empty */ + | label_decls + { if (pedantic) + pedwarn ("ANSI C forbids label declarations"); } + ; + +label_decls: + label_decl + | label_decls label_decl + ; + +label_decl: + LABEL identifiers_or_typenames ';' + { tree link; + for (link = $2; link; link = TREE_CHAIN (link)) + { + tree label = shadow_label (TREE_VALUE (link)); + C_DECLARED_LABEL_FLAG (label) = 1; + declare_nonlocal_label (label); + } + } + ; + +/* This is the body of a function definition. + It causes syntax errors to ignore to the next openbrace. */ +compstmt_or_error: + compstmt + {} + | error compstmt + ; + +compstmt_start: '{' { compstmt_count++; } + +compstmt: compstmt_start '}' + { $$ = convert (void_type_node, integer_zero_node); } + | compstmt_start pushlevel maybe_label_decls decls xstmts '}' + { emit_line_note (input_filename, lineno); + expand_end_bindings (getdecls (), 1, 0); + $$ = poplevel (1, 1, 0); + if (yychar == CONSTANT || yychar == STRING) + pop_momentary_nofree (); + else + pop_momentary (); } + | compstmt_start pushlevel maybe_label_decls error '}' + { emit_line_note (input_filename, lineno); + expand_end_bindings (getdecls (), kept_level_p (), 0); + $$ = poplevel (kept_level_p (), 0, 0); + if (yychar == CONSTANT || yychar == STRING) + pop_momentary_nofree (); + else + pop_momentary (); } + | compstmt_start pushlevel maybe_label_decls stmts '}' + { emit_line_note (input_filename, lineno); + expand_end_bindings (getdecls (), kept_level_p (), 0); + $$ = poplevel (kept_level_p (), 0, 0); + if (yychar == CONSTANT || yychar == STRING) + pop_momentary_nofree (); + else + pop_momentary (); } + ; + +/* Value is number of statements counted as of the closeparen. */ +simple_if: + if_prefix lineno_labeled_stmt +/* Make sure c_expand_end_cond is run once + for each call to c_expand_start_cond. + Otherwise a crash is likely. */ + | if_prefix error + ; + +if_prefix: + IF '(' expr ')' + { emit_line_note ($-1, $0); + c_expand_start_cond (truthvalue_conversion ($3), 0, + compstmt_count); + $$ = stmt_count; + if_stmt_file = $-1; + if_stmt_line = $0; + position_after_white_space (); } + ; + +/* This is a subroutine of stmt. + It is used twice, once for valid DO statements + and once for catching errors in parsing the end test. */ +do_stmt_start: + DO + { stmt_count++; + compstmt_count++; + emit_line_note ($-1, $0); + /* See comment in `while' alternative, above. */ + emit_nop (); + expand_start_loop_continue_elsewhere (1); + position_after_white_space (); } + lineno_labeled_stmt WHILE + { expand_loop_continue_here (); } + ; + +save_filename: + { $$ = input_filename; } + ; + +save_lineno: + { $$ = lineno; } + ; + +lineno_labeled_stmt: + save_filename save_lineno stmt + { } +/* | save_filename save_lineno error + { } +*/ + | save_filename save_lineno label lineno_labeled_stmt + { } + ; + +lineno_stmt_or_label: + save_filename save_lineno stmt_or_label + { $$ = $3; } + ; + +stmt_or_label: + stmt + { $$ = 0; } + | label + { $$ = 1; } + ; + +/* Parse a single real statement, not including any labels. */ +stmt: + compstmt + { stmt_count++; } + | all_iter_stmt + | expr ';' + { stmt_count++; + emit_line_note ($-1, $0); +/* It appears that this should not be done--that a non-lvalue array + shouldn't get an error if the value isn't used. + Section 3.2.2.1 says that an array lvalue gets converted to a pointer + if it appears as a top-level expression, + but says nothing about non-lvalue arrays. */ +#if 0 + /* Call default_conversion to get an error + on referring to a register array if pedantic. */ + if (TREE_CODE (TREE_TYPE ($1)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE ($1)) == FUNCTION_TYPE) + $1 = default_conversion ($1); +#endif + iterator_expand ($1); + clear_momentary (); } + | simple_if ELSE + { c_expand_start_else (); + $1 = stmt_count; + position_after_white_space (); } + lineno_labeled_stmt + { c_expand_end_cond (); + if (extra_warnings && stmt_count == $1) + warning ("empty body in an else-statement"); } + | simple_if %prec IF + { c_expand_end_cond (); + /* This warning is here instead of in simple_if, because we + do not want a warning if an empty if is followed by an + else statement. Increment stmt_count so we don't + give a second error if this is a nested `if'. */ + if (extra_warnings && stmt_count++ == $1) + warning_with_file_and_line (if_stmt_file, if_stmt_line, + "empty body in an if-statement"); } +/* Make sure c_expand_end_cond is run once + for each call to c_expand_start_cond. + Otherwise a crash is likely. */ + | simple_if ELSE error + { c_expand_end_cond (); } + | WHILE + { stmt_count++; + emit_line_note ($-1, $0); + /* The emit_nop used to come before emit_line_note, + but that made the nop seem like part of the preceding line. + And that was confusing when the preceding line was + inside of an if statement and was not really executed. + I think it ought to work to put the nop after the line number. + We will see. --rms, July 15, 1991. */ + emit_nop (); } + '(' expr ')' + { /* Don't start the loop till we have succeeded + in parsing the end test. This is to make sure + that we end every loop we start. */ + expand_start_loop (1); + emit_line_note (input_filename, lineno); + expand_exit_loop_if_false (NULL_PTR, + truthvalue_conversion ($4)); + position_after_white_space (); } + lineno_labeled_stmt + { expand_end_loop (); } + | do_stmt_start + '(' expr ')' ';' + { emit_line_note (input_filename, lineno); + expand_exit_loop_if_false (NULL_PTR, + truthvalue_conversion ($3)); + expand_end_loop (); + clear_momentary (); } +/* This rule is needed to make sure we end every loop we start. */ + | do_stmt_start error + { expand_end_loop (); + clear_momentary (); } + | FOR + '(' xexpr ';' + { stmt_count++; + emit_line_note ($-1, $0); + /* See comment in `while' alternative, above. */ + emit_nop (); + if ($3) c_expand_expr_stmt ($3); + /* Next step is to call expand_start_loop_continue_elsewhere, + but wait till after we parse the entire for (...). + Otherwise, invalid input might cause us to call that + fn without calling expand_end_loop. */ + } + xexpr ';' + /* Can't emit now; wait till after expand_start_loop... */ + { $7 = lineno; + $$ = input_filename; } + xexpr ')' + { + /* Start the loop. Doing this after parsing + all the expressions ensures we will end the loop. */ + expand_start_loop_continue_elsewhere (1); + /* Emit the end-test, with a line number. */ + emit_line_note ($8, $7); + if ($6) + expand_exit_loop_if_false (NULL_PTR, + truthvalue_conversion ($6)); + /* Don't let the tree nodes for $9 be discarded by + clear_momentary during the parsing of the next stmt. */ + push_momentary (); + $7 = lineno; + $8 = input_filename; + position_after_white_space (); } + lineno_labeled_stmt + { /* Emit the increment expression, with a line number. */ + emit_line_note ($8, $7); + expand_loop_continue_here (); + if ($9) + c_expand_expr_stmt ($9); + if (yychar == CONSTANT || yychar == STRING) + pop_momentary_nofree (); + else + pop_momentary (); + expand_end_loop (); } + | SWITCH '(' expr ')' + { stmt_count++; + emit_line_note ($-1, $0); + c_expand_start_case ($3); + /* Don't let the tree nodes for $3 be discarded by + clear_momentary during the parsing of the next stmt. */ + push_momentary (); + position_after_white_space (); } + lineno_labeled_stmt + { expand_end_case ($3); + if (yychar == CONSTANT || yychar == STRING) + pop_momentary_nofree (); + else + pop_momentary (); } + | BREAK ';' + { stmt_count++; + emit_line_note ($-1, $0); + if ( ! expand_exit_something ()) + error ("break statement not within loop or switch"); } + | CONTINUE ';' + { stmt_count++; + emit_line_note ($-1, $0); + if (! expand_continue_loop (NULL_PTR)) + error ("continue statement not within a loop"); } + | RETURN ';' + { stmt_count++; + emit_line_note ($-1, $0); + c_expand_return (NULL_TREE); } + | RETURN expr ';' + { stmt_count++; + emit_line_note ($-1, $0); + c_expand_return ($2); } + | ASM_KEYWORD maybe_type_qual '(' expr ')' ';' + { stmt_count++; + emit_line_note ($-1, $0); + STRIP_NOPS ($4); + if ((TREE_CODE ($4) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND ($4, 0)) == STRING_CST) + || TREE_CODE ($4) == STRING_CST) + expand_asm ($4); + else + error ("argument of `asm' is not a constant string"); } + /* This is the case with just output operands. */ + | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ')' ';' + { stmt_count++; + emit_line_note ($-1, $0); + c_expand_asm_operands ($4, $6, NULL_TREE, NULL_TREE, + $2 == ridpointers[(int)RID_VOLATILE], + input_filename, lineno); } + /* This is the case with input operands as well. */ + | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ':' asm_operands ')' ';' + { stmt_count++; + emit_line_note ($-1, $0); + c_expand_asm_operands ($4, $6, $8, NULL_TREE, + $2 == ridpointers[(int)RID_VOLATILE], + input_filename, lineno); } + /* This is the case with clobbered registers as well. */ + | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ':' + asm_operands ':' asm_clobbers ')' ';' + { stmt_count++; + emit_line_note ($-1, $0); + c_expand_asm_operands ($4, $6, $8, $10, + $2 == ridpointers[(int)RID_VOLATILE], + input_filename, lineno); } + | GOTO identifier ';' + { tree decl; + stmt_count++; + emit_line_note ($-1, $0); + decl = lookup_label ($2); + if (decl != 0) + { + TREE_USED (decl) = 1; + expand_goto (decl); + } + } + | GOTO '*' expr ';' + { if (pedantic) + pedwarn ("ANSI C forbids `goto *expr;'"); + stmt_count++; + emit_line_note ($-1, $0); + expand_computed_goto (convert (ptr_type_node, $3)); } + | ';' + ; + +all_iter_stmt: + all_iter_stmt_simple +/* | all_iter_stmt_with_decl */ + ; + +all_iter_stmt_simple: + FOR '(' primary ')' + { + /* The value returned by this action is */ + /* 1 if everything is OK */ + /* 0 in case of error or already bound iterator */ + + $$ = 0; + if (TREE_CODE ($3) != VAR_DECL) + error ("invalid `for (ITERATOR)' syntax"); + else if (! ITERATOR_P ($3)) + error ("`%s' is not an iterator", + IDENTIFIER_POINTER (DECL_NAME ($3))); + else if (ITERATOR_BOUND_P ($3)) + error ("`for (%s)' inside expansion of same iterator", + IDENTIFIER_POINTER (DECL_NAME ($3))); + else + { + $$ = 1; + iterator_for_loop_start ($3); + } + } + lineno_labeled_stmt + { + if ($5) + iterator_for_loop_end ($3); + } + +/* This really should allow any kind of declaration, + for generality. Fix it before turning it back on. + +all_iter_stmt_with_decl: + FOR '(' ITERATOR pushlevel setspecs iterator_spec ')' + { +*/ /* The value returned by this action is */ + /* 1 if everything is OK */ + /* 0 in case of error or already bound iterator */ +/* + iterator_for_loop_start ($6); + } + lineno_labeled_stmt + { + iterator_for_loop_end ($6); + emit_line_note (input_filename, lineno); + expand_end_bindings (getdecls (), 1, 0); + $$ = poplevel (1, 1, 0); + if (yychar == CONSTANT || yychar == STRING) + pop_momentary_nofree (); + else + pop_momentary (); + } +*/ + +/* Any kind of label, including jump labels and case labels. + ANSI C accepts labels only before statements, but we allow them + also at the end of a compound statement. */ + +label: CASE expr_no_commas ':' + { register tree value = check_case_value ($2); + register tree label + = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + + stmt_count++; + + if (value != error_mark_node) + { + tree duplicate; + int success; + + if (pedantic && ! INTEGRAL_TYPE_P (TREE_TYPE (value))) + pedwarn ("label must have integral type in ANSI C"); + + success = pushcase (value, convert_and_check, + label, &duplicate); + + if (success == 1) + error ("case label not within a switch statement"); + else if (success == 2) + { + error ("duplicate case value"); + error_with_decl (duplicate, "this is the first entry for that value"); + } + else if (success == 3) + warning ("case value out of range"); + else if (success == 5) + error ("case label within scope of cleanup or variable array"); + } + position_after_white_space (); } + | CASE expr_no_commas ELLIPSIS expr_no_commas ':' + { register tree value1 = check_case_value ($2); + register tree value2 = check_case_value ($4); + register tree label + = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + + if (pedantic) + pedwarn ("ANSI C forbids case ranges"); + stmt_count++; + + if (value1 != error_mark_node && value2 != error_mark_node) + { + tree duplicate; + int success = pushcase_range (value1, value2, + convert_and_check, label, + &duplicate); + if (success == 1) + error ("case label not within a switch statement"); + else if (success == 2) + { + error ("duplicate case value"); + error_with_decl (duplicate, "this is the first entry for that value"); + } + else if (success == 3) + warning ("case value out of range"); + else if (success == 4) + warning ("empty case range"); + else if (success == 5) + error ("case label within scope of cleanup or variable array"); + } + position_after_white_space (); } + | DEFAULT ':' + { + tree duplicate; + register tree label + = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + int success = pushcase (NULL_TREE, 0, label, &duplicate); + stmt_count++; + if (success == 1) + error ("default label not within a switch statement"); + else if (success == 2) + { + error ("multiple default labels in one switch"); + error_with_decl (duplicate, "this is the first default label"); + } + position_after_white_space (); } + | identifier ':' maybe_attribute + { tree label = define_label (input_filename, lineno, $1); + stmt_count++; + emit_nop (); + if (label) + { + expand_label (label); + decl_attributes (label, $3, NULL_TREE); + } + position_after_white_space (); } + ; + +/* Either a type-qualifier or nothing. First thing in an `asm' statement. */ + +maybe_type_qual: + /* empty */ + { emit_line_note (input_filename, lineno); + $$ = NULL_TREE; } + | TYPE_QUAL + { emit_line_note (input_filename, lineno); } + ; + +xexpr: + /* empty */ + { $$ = NULL_TREE; } + | expr + ; + +/* These are the operands other than the first string and colon + in asm ("addextend %2,%1": "=dm" (x), "0" (y), "g" (*x)) */ +asm_operands: /* empty */ + { $$ = NULL_TREE; } + | nonnull_asm_operands + ; + +nonnull_asm_operands: + asm_operand + | nonnull_asm_operands ',' asm_operand + { $$ = chainon ($1, $3); } + ; + +asm_operand: + STRING '(' expr ')' + { $$ = build_tree_list ($1, $3); } + ; + +asm_clobbers: + string + { $$ = tree_cons (NULL_TREE, combine_strings ($1), NULL_TREE); } + | asm_clobbers ',' string + { $$ = tree_cons (NULL_TREE, combine_strings ($3), $1); } + ; + +/* This is what appears inside the parens in a function declarator. + Its value is a list of ..._TYPE nodes. */ +parmlist: + { pushlevel (0); + clear_parm_order (); + declare_parm_level (0); } + parmlist_1 + { $$ = $2; + parmlist_tags_warning (); + poplevel (0, 0, 0); } + ; + +parmlist_1: + parmlist_2 ')' + | parms ';' + { tree parm; + if (pedantic) + pedwarn ("ANSI C forbids forward parameter declarations"); + /* Mark the forward decls as such. */ + for (parm = getdecls (); parm; parm = TREE_CHAIN (parm)) + TREE_ASM_WRITTEN (parm) = 1; + clear_parm_order (); } + parmlist_1 + { $$ = $4; } + | error ')' + { $$ = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE); } + ; + +/* This is what appears inside the parens in a function declarator. + Is value is represented in the format that grokdeclarator expects. */ +parmlist_2: /* empty */ + { $$ = get_parm_info (0); } + | ELLIPSIS + { $$ = get_parm_info (0); + /* Gcc used to allow this as an extension. However, it does + not work for all targets, and thus has been disabled. + Also, since func (...) and func () are indistinguishable, + it caused problems with the code in expand_builtin which + tries to verify that BUILT_IN_NEXT_ARG is being used + correctly. */ + error ("ANSI C requires a named argument before `...'"); + } + | parms + { $$ = get_parm_info (1); } + | parms ',' ELLIPSIS + { $$ = get_parm_info (0); } + ; + +parms: + parm + { push_parm_decl ($1); } + | parms ',' parm + { push_parm_decl ($3); } + ; + +/* A single parameter declaration or parameter type name, + as found in a parmlist. */ +parm: + typed_declspecs setspecs parm_declarator maybe_attribute + { $$ = build_tree_list (build_tree_list (current_declspecs, + $3), + build_tree_list (prefix_attributes, + $4)); + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | typed_declspecs setspecs notype_declarator maybe_attribute + { $$ = build_tree_list (build_tree_list (current_declspecs, + $3), + build_tree_list (prefix_attributes, + $4)); + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | typed_declspecs setspecs absdcl maybe_attribute + { $$ = build_tree_list (build_tree_list (current_declspecs, + $3), + build_tree_list (prefix_attributes, + $4)); + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | declmods setspecs notype_declarator maybe_attribute + { $$ = build_tree_list (build_tree_list (current_declspecs, + $3), + build_tree_list (prefix_attributes, + $4)); + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + + | declmods setspecs absdcl maybe_attribute + { $$ = build_tree_list (build_tree_list (current_declspecs, + $3), + build_tree_list (prefix_attributes, + $4)); + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + ; + +/* This is used in a function definition + where either a parmlist or an identifier list is ok. + Its value is a list of ..._TYPE nodes or a list of identifiers. */ +parmlist_or_identifiers: + { pushlevel (0); + clear_parm_order (); + declare_parm_level (1); } + parmlist_or_identifiers_1 + { $$ = $2; + parmlist_tags_warning (); + poplevel (0, 0, 0); } + ; + +parmlist_or_identifiers_1: + parmlist_1 + | identifiers ')' + { tree t; + for (t = $1; t; t = TREE_CHAIN (t)) + if (TREE_VALUE (t) == NULL_TREE) + error ("`...' in old-style identifier list"); + $$ = tree_cons (NULL_TREE, NULL_TREE, $1); } + ; + +/* A nonempty list of identifiers. */ +identifiers: + IDENTIFIER + { $$ = build_tree_list (NULL_TREE, $1); } + | identifiers ',' IDENTIFIER + { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); } + ; + +/* A nonempty list of identifiers, including typenames. */ +identifiers_or_typenames: + identifier + { $$ = build_tree_list (NULL_TREE, $1); } + | identifiers_or_typenames ',' identifier + { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); } + ; + +extension: + EXTENSION + { $$ = pedantic; + pedantic = 0; } + ; + +ifobjc +/* Objective-C productions. */ + +objcdef: + classdef + | classdecl + | aliasdecl + | protocoldef + | methoddef + | END + { + if (objc_implementation_context) + { + finish_class (objc_implementation_context); + objc_ivar_chain = NULL_TREE; + objc_implementation_context = NULL_TREE; + } + else + warning ("`@end' must appear in an implementation context"); + } + ; + +/* A nonempty list of identifiers. */ +identifier_list: + identifier + { $$ = build_tree_list (NULL_TREE, $1); } + | identifier_list ',' identifier + { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); } + ; + +classdecl: + CLASS identifier_list ';' + { + objc_declare_class ($2); + } + +aliasdecl: + ALIAS identifier identifier ';' + { + objc_declare_alias ($2, $3); + } + +classdef: + INTERFACE identifier protocolrefs '{' + { + objc_interface_context = objc_ivar_context + = start_class (CLASS_INTERFACE_TYPE, $2, NULL_TREE, $3); + objc_public_flag = 0; + } + ivar_decl_list '}' + { + continue_class (objc_interface_context); + } + methodprotolist + END + { + finish_class (objc_interface_context); + objc_interface_context = NULL_TREE; + } + + | INTERFACE identifier protocolrefs + { + objc_interface_context + = start_class (CLASS_INTERFACE_TYPE, $2, NULL_TREE, $3); + continue_class (objc_interface_context); + } + methodprotolist + END + { + finish_class (objc_interface_context); + objc_interface_context = NULL_TREE; + } + + | INTERFACE identifier ':' identifier protocolrefs '{' + { + objc_interface_context = objc_ivar_context + = start_class (CLASS_INTERFACE_TYPE, $2, $4, $5); + objc_public_flag = 0; + } + ivar_decl_list '}' + { + continue_class (objc_interface_context); + } + methodprotolist + END + { + finish_class (objc_interface_context); + objc_interface_context = NULL_TREE; + } + + | INTERFACE identifier ':' identifier protocolrefs + { + objc_interface_context + = start_class (CLASS_INTERFACE_TYPE, $2, $4, $5); + continue_class (objc_interface_context); + } + methodprotolist + END + { + finish_class (objc_interface_context); + objc_interface_context = NULL_TREE; + } + + | IMPLEMENTATION identifier '{' + { + objc_implementation_context = objc_ivar_context + = start_class (CLASS_IMPLEMENTATION_TYPE, $2, NULL_TREE, NULL_TREE); + objc_public_flag = 0; + } + ivar_decl_list '}' + { + objc_ivar_chain + = continue_class (objc_implementation_context); + } + + | IMPLEMENTATION identifier + { + objc_implementation_context + = start_class (CLASS_IMPLEMENTATION_TYPE, $2, NULL_TREE, NULL_TREE); + objc_ivar_chain + = continue_class (objc_implementation_context); + } + + | IMPLEMENTATION identifier ':' identifier '{' + { + objc_implementation_context = objc_ivar_context + = start_class (CLASS_IMPLEMENTATION_TYPE, $2, $4, NULL_TREE); + objc_public_flag = 0; + } + ivar_decl_list '}' + { + objc_ivar_chain + = continue_class (objc_implementation_context); + } + + | IMPLEMENTATION identifier ':' identifier + { + objc_implementation_context + = start_class (CLASS_IMPLEMENTATION_TYPE, $2, $4, NULL_TREE); + objc_ivar_chain + = continue_class (objc_implementation_context); + } + + | INTERFACE identifier '(' identifier ')' protocolrefs + { + objc_interface_context + = start_class (CATEGORY_INTERFACE_TYPE, $2, $4, $6); + continue_class (objc_interface_context); + } + methodprotolist + END + { + finish_class (objc_interface_context); + objc_interface_context = NULL_TREE; + } + + | IMPLEMENTATION identifier '(' identifier ')' + { + objc_implementation_context + = start_class (CATEGORY_IMPLEMENTATION_TYPE, $2, $4, NULL_TREE); + objc_ivar_chain + = continue_class (objc_implementation_context); + } + ; + +protocoldef: + PROTOCOL identifier protocolrefs + { + remember_protocol_qualifiers (); + objc_interface_context + = start_protocol(PROTOCOL_INTERFACE_TYPE, $2, $3); + } + methodprotolist END + { + forget_protocol_qualifiers(); + finish_protocol(objc_interface_context); + objc_interface_context = NULL_TREE; + } + ; + +protocolrefs: + /* empty */ + { + $$ = NULL_TREE; + } + | non_empty_protocolrefs + ; + +non_empty_protocolrefs: + ARITHCOMPARE identifier_list ARITHCOMPARE + { + if ($1 == LT_EXPR && $3 == GT_EXPR) + $$ = $2; + else + YYERROR1; + } + ; + +ivar_decl_list: + ivar_decl_list visibility_spec ivar_decls + | ivar_decls + ; + +visibility_spec: + PRIVATE { objc_public_flag = 2; } + | PROTECTED { objc_public_flag = 0; } + | PUBLIC { objc_public_flag = 1; } + ; + +ivar_decls: + /* empty */ + { + $$ = NULL_TREE; + } + | ivar_decls ivar_decl ';' + | ivar_decls ';' + { + if (pedantic) + pedwarn ("extra semicolon in struct or union specified"); + } + ; + + +/* There is a shift-reduce conflict here, because `components' may + start with a `typename'. It happens that shifting (the default resolution) + does the right thing, because it treats the `typename' as part of + a `typed_typespecs'. + + It is possible that this same technique would allow the distinction + between `notype_initdecls' and `initdecls' to be eliminated. + But I am being cautious and not trying it. */ + +ivar_decl: + typed_typespecs setspecs ivars + { $$ = $3; + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | nonempty_type_quals setspecs ivars + { $$ = $3; + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | error + { $$ = NULL_TREE; } + ; + +ivars: + /* empty */ + { $$ = NULL_TREE; } + | ivar_declarator + | ivars ',' ivar_declarator + ; + +ivar_declarator: + declarator + { + $$ = add_instance_variable (objc_ivar_context, + objc_public_flag, + $1, current_declspecs, + NULL_TREE); + } + | declarator ':' expr_no_commas + { + $$ = add_instance_variable (objc_ivar_context, + objc_public_flag, + $1, current_declspecs, $3); + } + | ':' expr_no_commas + { + $$ = add_instance_variable (objc_ivar_context, + objc_public_flag, + NULL_TREE, + current_declspecs, $2); + } + ; + +methoddef: + '+' + { + remember_protocol_qualifiers (); + if (objc_implementation_context) + objc_inherit_code = CLASS_METHOD_DECL; + else + fatal ("method definition not in class context"); + } + methoddecl + { + forget_protocol_qualifiers (); + add_class_method (objc_implementation_context, $3); + start_method_def ($3); + objc_method_context = $3; + } + optarglist + { + continue_method_def (); + } + compstmt_or_error + { + finish_method_def (); + objc_method_context = NULL_TREE; + } + + | '-' + { + remember_protocol_qualifiers (); + if (objc_implementation_context) + objc_inherit_code = INSTANCE_METHOD_DECL; + else + fatal ("method definition not in class context"); + } + methoddecl + { + forget_protocol_qualifiers (); + add_instance_method (objc_implementation_context, $3); + start_method_def ($3); + objc_method_context = $3; + } + optarglist + { + continue_method_def (); + } + compstmt_or_error + { + finish_method_def (); + objc_method_context = NULL_TREE; + } + ; + +/* the reason for the strange actions in this rule + is so that notype_initdecls when reached via datadef + can find a valid list of type and sc specs in $0. */ + +methodprotolist: + /* empty */ + | {$$ = NULL_TREE; } methodprotolist2 + ; + +methodprotolist2: /* eliminates a shift/reduce conflict */ + methodproto + | datadef + | methodprotolist2 methodproto + | methodprotolist2 {$$ = NULL_TREE; } datadef + ; + +semi_or_error: + ';' + | error + ; + +methodproto: + '+' + { + /* Remember protocol qualifiers in prototypes. */ + remember_protocol_qualifiers (); + objc_inherit_code = CLASS_METHOD_DECL; + } + methoddecl + { + /* Forget protocol qualifiers here. */ + forget_protocol_qualifiers (); + add_class_method (objc_interface_context, $3); + } + semi_or_error + + | '-' + { + /* Remember protocol qualifiers in prototypes. */ + remember_protocol_qualifiers (); + objc_inherit_code = INSTANCE_METHOD_DECL; + } + methoddecl + { + /* Forget protocol qualifiers here. */ + forget_protocol_qualifiers (); + add_instance_method (objc_interface_context, $3); + } + semi_or_error + ; + +methoddecl: + '(' typename ')' unaryselector + { + $$ = build_method_decl (objc_inherit_code, $2, $4, NULL_TREE); + } + + | unaryselector + { + $$ = build_method_decl (objc_inherit_code, NULL_TREE, $1, NULL_TREE); + } + + | '(' typename ')' keywordselector optparmlist + { + $$ = build_method_decl (objc_inherit_code, $2, $4, $5); + } + + | keywordselector optparmlist + { + $$ = build_method_decl (objc_inherit_code, NULL_TREE, $1, $2); + } + ; + +/* "optarglist" assumes that start_method_def has already been called... + if it is not, the "xdecls" will not be placed in the proper scope */ + +optarglist: + /* empty */ + | ';' myxdecls + ; + +/* to get around the following situation: "int foo (int a) int b; {}" that + is synthesized when parsing "- a:a b:b; id c; id d; { ... }" */ + +myxdecls: + /* empty */ + | mydecls + ; + +mydecls: + mydecl + | errstmt + | mydecls mydecl + | mydecl errstmt + ; + +mydecl: + typed_declspecs setspecs myparms ';' + { current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | typed_declspecs ';' + { shadow_tag ($1); } + | declmods ';' + { pedwarn ("empty declaration"); } + ; + +myparms: + myparm + { push_parm_decl ($1); } + | myparms ',' myparm + { push_parm_decl ($3); } + ; + +/* A single parameter declaration or parameter type name, + as found in a parmlist. DOES NOT ALLOW AN INITIALIZER OR ASMSPEC */ + +myparm: + parm_declarator maybe_attribute + { $$ = build_tree_list (build_tree_list (current_declspecs, + $1), + build_tree_list (prefix_attributes, + $2)); } + | notype_declarator maybe_attribute + { $$ = build_tree_list (build_tree_list (current_declspecs, + $1), + build_tree_list (prefix_attributes, + $2)); } + | absdcl maybe_attribute + { $$ = build_tree_list (build_tree_list (current_declspecs, + $1), + build_tree_list (prefix_attributes, + $2)); } + ; + +optparmlist: + /* empty */ + { + $$ = NULL_TREE; + } + | ',' ELLIPSIS + { + /* oh what a kludge! */ + $$ = (tree)1; + } + | ',' + { + pushlevel (0); + } + parmlist_2 + { + /* returns a tree list node generated by get_parm_info */ + $$ = $3; + poplevel (0, 0, 0); + } + ; + +unaryselector: + selector + ; + +keywordselector: + keyworddecl + + | keywordselector keyworddecl + { + $$ = chainon ($1, $2); + } + ; + +selector: + IDENTIFIER + | TYPENAME + | OBJECTNAME + | reservedwords + ; + +reservedwords: + ENUM { $$ = get_identifier (token_buffer); } + | STRUCT { $$ = get_identifier (token_buffer); } + | UNION { $$ = get_identifier (token_buffer); } + | IF { $$ = get_identifier (token_buffer); } + | ELSE { $$ = get_identifier (token_buffer); } + | WHILE { $$ = get_identifier (token_buffer); } + | DO { $$ = get_identifier (token_buffer); } + | FOR { $$ = get_identifier (token_buffer); } + | SWITCH { $$ = get_identifier (token_buffer); } + | CASE { $$ = get_identifier (token_buffer); } + | DEFAULT { $$ = get_identifier (token_buffer); } + | BREAK { $$ = get_identifier (token_buffer); } + | CONTINUE { $$ = get_identifier (token_buffer); } + | RETURN { $$ = get_identifier (token_buffer); } + | GOTO { $$ = get_identifier (token_buffer); } + | ASM_KEYWORD { $$ = get_identifier (token_buffer); } + | SIZEOF { $$ = get_identifier (token_buffer); } + | TYPEOF { $$ = get_identifier (token_buffer); } + | ALIGNOF { $$ = get_identifier (token_buffer); } + | TYPESPEC | TYPE_QUAL + ; + +keyworddecl: + selector ':' '(' typename ')' identifier + { + $$ = build_keyword_decl ($1, $4, $6); + } + + | selector ':' identifier + { + $$ = build_keyword_decl ($1, NULL_TREE, $3); + } + + | ':' '(' typename ')' identifier + { + $$ = build_keyword_decl (NULL_TREE, $3, $5); + } + + | ':' identifier + { + $$ = build_keyword_decl (NULL_TREE, NULL_TREE, $2); + } + ; + +messageargs: + selector + | keywordarglist + ; + +keywordarglist: + keywordarg + | keywordarglist keywordarg + { + $$ = chainon ($1, $2); + } + ; + + +keywordexpr: + nonnull_exprlist + { + if (TREE_CHAIN ($1) == NULL_TREE) + /* just return the expr., remove a level of indirection */ + $$ = TREE_VALUE ($1); + else + /* we have a comma expr., we will collapse later */ + $$ = $1; + } + ; + +keywordarg: + selector ':' keywordexpr + { + $$ = build_tree_list ($1, $3); + } + | ':' keywordexpr + { + $$ = build_tree_list (NULL_TREE, $2); + } + ; + +receiver: + expr + | CLASSNAME + { + $$ = get_class_reference ($1); + } + ; + +objcmessageexpr: + '[' + { objc_receiver_context = 1; } + receiver + { objc_receiver_context = 0; } + messageargs ']' + { + $$ = build_tree_list ($3, $5); + } + ; + +selectorarg: + selector + | keywordnamelist + ; + +keywordnamelist: + keywordname + | keywordnamelist keywordname + { + $$ = chainon ($1, $2); + } + ; + +keywordname: + selector ':' + { + $$ = build_tree_list ($1, NULL_TREE); + } + | ':' + { + $$ = build_tree_list (NULL_TREE, NULL_TREE); + } + ; + +objcselectorexpr: + SELECTOR '(' selectorarg ')' + { + $$ = $3; + } + ; + +objcprotocolexpr: + PROTOCOL '(' identifier ')' + { + $$ = $3; + } + ; + +/* extension to support C-structures in the archiver */ + +objcencodeexpr: + ENCODE '(' typename ')' + { + $$ = groktypename ($3); + } + ; + +end ifobjc +%% diff --git a/gcc_arm/c-pragma.c b/gcc_arm/c-pragma.c new file mode 100755 index 0000000..f9bfbe7 --- /dev/null +++ b/gcc_arm/c-pragma.c @@ -0,0 +1,452 @@ +/* Handle #pragma, system V.4 style. Supports #pragma weak and #pragma pack. + Copyright (C) 1992, 1997, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "rtl.h" +#include "tree.h" +#include "except.h" +#include "function.h" +#include "defaults.h" +#include "c-pragma.h" +#include "flags.h" +#include "toplev.h" + +#ifdef HANDLE_GENERIC_PRAGMAS + +#ifdef HANDLE_PRAGMA_PACK +/* When structure field packing is in effect, this variable is the + number of bits to use as the maximum alignment. When packing is not + in effect, this is zero. */ + +extern int maximum_field_alignment; +#endif + + +#ifdef HANDLE_PRAGMA_PACK_PUSH_POP +typedef struct align_stack +{ + int alignment; + unsigned int num_pushes; + struct align_stack * prev; +} align_stack; + +static struct align_stack * alignment_stack = NULL; + +static int push_alignment PROTO((int)); +static int pop_alignment PROTO((void)); + +/* Push an alignment value onto the stack. */ +static int +push_alignment (alignment) + int alignment; +{ + switch (alignment) + { + case 0: + case 1: + case 2: + case 4: + case 8: + case 16: + break; + default: + warning ("\ +Alignment must be a small power of two, not %d, in #pragma pack", + alignment); + return 0; + } + + if (alignment_stack == NULL + || alignment_stack->alignment != alignment) + { + align_stack * entry; + + entry = (align_stack *) xmalloc (sizeof (* entry)); + + if (entry == NULL) + { + warning ("Out of memory pushing #pragma pack"); + return 0; + } + + entry->alignment = alignment; + entry->num_pushes = 1; + entry->prev = alignment_stack; + + alignment_stack = entry; + + if (alignment < 8) + maximum_field_alignment = alignment * 8; + else + /* MSVC ignores alignments > 4. */ + maximum_field_alignment = 0; + } + else + alignment_stack->num_pushes ++; + + return 1; +} + +/* Undo a push of an alignment onto the stack. */ +static int +pop_alignment () +{ + if (alignment_stack == NULL) + { + warning ("\ +#pragma pack(pop) encountered without corresponding #pragma pack(push,)"); + return 0; + } + + if (-- alignment_stack->num_pushes == 0) + { + align_stack * entry; + + entry = alignment_stack->prev; + + if (entry == NULL || entry->alignment > 4) + maximum_field_alignment = 0; + else + maximum_field_alignment = entry->alignment * 8; + + free (alignment_stack); + + alignment_stack = entry; + } + + return 1; +} + +/* Generate 'packed' and 'aligned' attributes for decls whilst a + #pragma pack(push... is in effect. */ +void +insert_pack_attributes (node, attributes, prefix) + tree node; + tree * attributes; + tree * prefix; +{ + tree a; + + /* If we are not packing, then there is nothing to do. */ + if (maximum_field_alignment == 0 + || alignment_stack == NULL) + return; + + /* We are only interested in fields. */ + if (TREE_CODE_CLASS (TREE_CODE (node)) != 'd' + || TREE_CODE (node) != FIELD_DECL) + return; + + /* Add a 'packed' attribute. */ + * attributes = tree_cons (get_identifier ("packed"), NULL, * attributes); + + /* If the alignment is > 8 then add an alignment attribute as well. */ + if (maximum_field_alignment > 8) + { + /* If the aligned attribute is already present then do not override it. */ + for (a = * attributes; a; a = TREE_CHAIN (a)) + { + tree name = TREE_PURPOSE (a); + if (strcmp (IDENTIFIER_POINTER (name), "aligned") == 0) + break; + } + + if (a == NULL) + for (a = * prefix; a; a = TREE_CHAIN (a)) + { + tree name = TREE_PURPOSE (a); + if (strcmp (IDENTIFIER_POINTER (name), "aligned") == 0) + break; + } + + if (a == NULL) + { + * attributes = tree_cons + (get_identifier ("aligned"), + tree_cons (NULL, + build_int_2 (maximum_field_alignment / 8, 0), + NULL), + * attributes); + } + } + + return; +} +#endif /* HANDLE_PRAGMA_PACK_PUSH_POP */ + +#ifdef HANDLE_PRAGMA_WEAK +static int add_weak PROTO((char *, char *)); + +static int +add_weak (name, value) + char * name; + char * value; +{ + struct weak_syms * weak; + + weak = (struct weak_syms *) permalloc (sizeof (struct weak_syms)); + + if (weak == NULL) + return 0; + + weak->next = weak_decls; + weak->name = name; + weak->value = value; + weak_decls = weak; + + return 1; +} +#endif /* HANDLE_PRAGMA_WEAK */ + +/* Handle one token of a pragma directive. TOKEN is the current token, and + STRING is its printable form. Some front ends do not support generating + tokens, and will only pass in a STRING. Also some front ends will reuse + the buffer containing STRING, so it must be copied to a local buffer if + it needs to be preserved. + + If STRING is non-NULL, then the return value will be ignored, and there + will be futher calls to handle_pragma_token() in order to handle the rest of + the line containing the #pragma directive. If STRING is NULL, the entire + line has now been presented to handle_pragma_token() and the return value + should be zero if the pragma flawed in some way, or if the pragma was not + recognised, and non-zero if it was successfully handled. */ + +int +handle_pragma_token (string, token) + char * string; + tree token; +{ + static enum pragma_state state = ps_start; + static enum pragma_state type; + static char * name; + static char * value; + static int align; + + /* If we have reached the end of the #pragma directive then + determine what value we should return. */ + + if (string == NULL) + { + int ret_val = 0; + + switch (type) + { + default: + abort (); + break; + + case ps_done: + /* The pragma was not recognised. */ + break; + +#ifdef HANDLE_PRAGMA_PACK + case ps_pack: + if (state == ps_right) + { + maximum_field_alignment = align * 8; + ret_val = 1; + } + else + warning ("malformed `#pragma pack'"); + break; +#endif /* HANDLE_PRAGMA_PACK */ + +#ifdef HANDLE_PRAGMA_PACK_PUSH_POP + case ps_push: + if (state == ps_right) + ret_val = push_alignment (align); + else + warning ("incomplete '#pragma pack(push,)'"); + break; + + case ps_pop: + if (state == ps_right) + ret_val = pop_alignment (); + else + warning ("missing closing parenthesis in '#pragma pack(pop)'"); + break; +#endif /* HANDLE_PRAGMA_PACK_PUSH_POP */ + +#ifdef HANDLE_PRAGMA_WEAK + case ps_weak: + if (HANDLE_PRAGMA_WEAK) + { + if (state == ps_name) + ret_val = add_weak (name, NULL); + else if (state == ps_value) + ret_val = add_weak (name, value); + else + warning ("malformed `#pragma weak'"); + } + else + ret_val = 1; /* Ignore the pragma. */ + break; +#endif /* HANDLE_PRAGMA_WEAK */ + } + + type = state = ps_start; + + return ret_val; + } + + /* If we have been given a token, but it is not an identifier, + or a small constant, then something has gone wrong. */ + if (token) + { + switch (TREE_CODE (token)) + { + case IDENTIFIER_NODE: + break; + + case INTEGER_CST: + if (TREE_INT_CST_HIGH (token) != 0) + return 0; + break; + + default: + return 0; + } + } + + switch (state) + { + case ps_start: + type = state = ps_done; +#ifdef HANDLE_PRAGMA_PACK + if (strcmp (string, "pack") == 0) + type = state = ps_pack; +#endif +#ifdef HANDLE_PRAGMA_WEAK + if (strcmp (string, "weak") == 0) + type = state = ps_weak; +#endif + break; + +#ifdef HANDLE_PRAGMA_WEAK + case ps_weak: + name = permalloc (strlen (string) + 1); + if (name == NULL) + { + warning ("Out of memory parsing #pragma weak"); + state = ps_bad; + } + else + { + strcpy (name, string); + state = ps_name; + } + break; + + case ps_name: + state = (strcmp (string, "=") ? ps_bad : ps_equals); + break; + + case ps_equals: + value = permalloc (strlen (string) + 1); + if (value == NULL) + { + warning ("Out of memory parsing #pragma weak"); + state = ps_bad; + } + else + { + strcpy (value, string); + state = ps_value; + } + break; + + case ps_value: + state = ps_bad; + break; +#endif /* HANDLE_PRAGMA_WEAK */ + +#ifdef HANDLE_PRAGMA_PACK + case ps_pack: + state = (strcmp (string, "(") ? ps_bad : ps_left); + break; + + case ps_left: + + if (token && TREE_CODE(token) == INTEGER_CST) + align = TREE_INT_CST_LOW(token); + else + align = atoi (string); + switch (align) + { + case 1: + case 2: + case 4: + state = ps_align; + break; + + case 0: + state = (strcmp (string, ")") ? ps_bad : ps_right); +#ifdef HANDLE_PRAGMA_PACK_PUSH_POP + if (state == ps_bad) + { + if (strcmp (string, "push") == 0) + type = state = ps_push; + else if (strcmp (string, "pop") == 0) + type = state = ps_pop; + } +#endif + break; + + default: + state = ps_bad; + break; + } + break; + +#ifdef HANDLE_PRAGMA_PACK_PUSH_POP + case ps_pop: +#endif + case ps_align: + state = (strcmp (string, ")") ? ps_bad : ps_right); + break; + + case ps_right: + state = ps_bad; + break; +#endif /* HANDLE_PRAGMA_PACK */ + +#ifdef HANDLE_PRAGMA_PACK_PUSH_POP + case ps_push: + state = (strcmp (string, ",") ? ps_bad : ps_comma); + break; + + case ps_comma: + align = atoi (string); + state = ps_align; + break; +#endif /* HANDLE_PRAGMA_PACK_PUSH_POP */ + + case ps_bad: + case ps_done: + break; + + default: + abort (); + } + + return 1; +} +#endif /* HANDLE_GENERIC_PRAGMAS */ diff --git a/gcc_arm/c-pragma.h b/gcc_arm/c-pragma.h new file mode 100755 index 0000000..685f54a --- /dev/null +++ b/gcc_arm/c-pragma.h @@ -0,0 +1,100 @@ +/* Pragma related interfaces. + Copyright (C) 1995, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifndef _C_PRAGMA_H +#define _C_PRAGMA_H + +#ifdef HANDLE_SYSV_PRAGMA +/* Support #pragma weak iff ASM_WEAKEN_LABEL and ASM_OUTPUT_DEF are + defined. */ +#if defined (ASM_WEAKEN_LABEL) && defined (ASM_OUTPUT_DEF) +#define HANDLE_PRAGMA_WEAK SUPPORTS_WEAK +#endif + +/* We always support #pragma pack for SYSV pragmas. */ +#ifndef HANDLE_PRAGMA_PACK +#define HANDLE_PRAGMA_PACK 1 +#endif +#endif /* HANDLE_SYSV_PRAGMA */ + + +#ifdef HANDLE_PRAGMA_PACK_PUSH_POP +/* If we are supporting #pragma pack(push... then we automatically + support #pragma pack() */ +#define HANDLE_PRAGMA_PACK 1 +#define PRAGMA_INSERT_ATTRIBUTES(node, pattr, prefix_attr) \ + insert_pack_attributes (node, pattr, prefix_attr) +extern void insert_pack_attributes PROTO((tree, tree *, tree *)); +#endif /* HANDLE_PRAGMA_PACK_PUSH_POP */ + + +#ifdef HANDLE_PRAGMA_WEAK +/* This structure contains any weak symbol declarations waiting to be emitted. */ +struct weak_syms +{ + struct weak_syms * next; + char * name; + char * value; +}; + +/* Declared in varasm.c */ +extern struct weak_syms * weak_decls; +#endif /* HANDLE_PRAGMA_WEAK */ + + +#if defined HANDLE_PRAGMA_PACK || defined HANDLE_PRAGMA_WEAK +/* Define HANDLE_GENERIC_PRAGMAS if any kind of front-end pragma + parsing is to be done. The code in GCC's generic C source files + will only look for the definition of this constant. They will + ignore definitions of HANDLE_PRAGMA_PACK and so on. */ +#define HANDLE_GENERIC_PRAGMAS 1 +#endif + + +#ifdef HANDLE_GENERIC_PRAGMAS +enum pragma_state +{ + ps_start, + ps_done, +#ifdef HANDLE_PRAGMA_WEAK + ps_weak, + ps_name, + ps_equals, + ps_value, +#endif +#ifdef HANDLE_PRAGMA_PACK + ps_pack, + ps_left, + ps_align, + ps_right, +#endif +#ifdef HANDLE_PRAGMA_PACK_PUSH_POP + ps_push, + ps_pop, + ps_comma, +#endif + ps_bad +}; + +/* Handle a C style pragma */ +extern int handle_pragma_token PROTO((char *, tree)); + +#endif /* HANDLE_GENERIC_PRAGMAS */ +#endif /* _C_PRAGMA_H */ diff --git a/gcc_arm/c-tree.h b/gcc_arm/c-tree.h new file mode 100755 index 0000000..0249ef5 --- /dev/null +++ b/gcc_arm/c-tree.h @@ -0,0 +1,560 @@ +/* Definitions for C parsing and type checking. + Copyright (C) 1987, 1993, 1994, 1995, 1997, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifndef _C_TREE_H +#define _C_TREE_H + +/* 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. */ + +struct lang_identifier +{ + struct tree_identifier ignore; + tree global_value, local_value, label_value, implicit_decl; + tree error_locus, limbo_value; +}; + +/* Macros for access to language-specific slots in an identifier. */ +/* Each of these slots contains a DECL node or null. */ + +/* This represents the value which the identifier has in the + file-scope namespace. */ +#define IDENTIFIER_GLOBAL_VALUE(NODE) \ + (((struct lang_identifier *) (NODE))->global_value) +/* This represents the value which the identifier has in the current + scope. */ +#define IDENTIFIER_LOCAL_VALUE(NODE) \ + (((struct lang_identifier *) (NODE))->local_value) +/* This represents the value which the identifier has as a label in + the current label scope. */ +#define IDENTIFIER_LABEL_VALUE(NODE) \ + (((struct lang_identifier *) (NODE))->label_value) +/* This records the extern decl of this identifier, if it has had one + at any point in this compilation. */ +#define IDENTIFIER_LIMBO_VALUE(NODE) \ + (((struct lang_identifier *) (NODE))->limbo_value) +/* This records the implicit function decl of this identifier, if it + has had one at any point in this compilation. */ +#define IDENTIFIER_IMPLICIT_DECL(NODE) \ + (((struct lang_identifier *) (NODE))->implicit_decl) +/* This is the last function in which we printed an "undefined variable" + message for this identifier. Value is a FUNCTION_DECL or null. */ +#define IDENTIFIER_ERROR_LOCUS(NODE) \ + (((struct lang_identifier *) (NODE))->error_locus) + +/* 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. */ + +/* Nonzero means reject anything that ANSI standard C forbids. */ +extern int pedantic; + +/* 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) + +/* In a RECORD_TYPE or UNION_TYPE, nonzero if any component is volatile. */ +#define C_TYPE_FIELDS_VOLATILE(type) TREE_LANG_FLAG_2 (type) + +/* In a RECORD_TYPE or UNION_TYPE or ENUMERAL_TYPE + nonzero if the definition of the type has already started. */ +#define C_TYPE_BEING_DEFINED(type) TYPE_LANG_FLAG_0 (type) + +/* C types are partitioned into three subsets: object, function, and + incomplete types. */ +#define C_TYPE_OBJECT_P(type) \ + (TREE_CODE (type) != FUNCTION_TYPE && TYPE_SIZE (type)) + +#define C_TYPE_FUNCTION_P(type) \ + (TREE_CODE (type) == FUNCTION_TYPE) + +#define C_TYPE_INCOMPLETE_P(type) \ + (TREE_CODE (type) != FUNCTION_TYPE && TYPE_SIZE (type) == 0) + +/* For convenience we define a single macro to identify the class of + object or incomplete types. */ +#define C_TYPE_OBJECT_OR_INCOMPLETE_P(type) \ + (!C_TYPE_FUNCTION_P (type)) + +/* In a RECORD_TYPE, a sorted array of the fields of the type. */ +struct lang_type +{ + int len; + tree elts[1]; +}; + +/* Mark which labels are explicitly declared. + These may be shadowed, and may be referenced from nested functions. */ +#define C_DECLARED_LABEL_FLAG(label) TREE_LANG_FLAG_1 (label) + +/* Record whether a type or decl was written with nonconstant size. + Note that TYPE_SIZE may have simplified to a constant. */ +#define C_TYPE_VARIABLE_SIZE(type) TYPE_LANG_FLAG_1 (type) +#define C_DECL_VARIABLE_SIZE(type) DECL_LANG_FLAG_0 (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)) + +#if 0 /* Not used. */ +/* Record whether a decl for a function or function pointer has + already been mentioned (in a warning) because it was called + but didn't have a prototype. */ +#define C_MISSING_PROTOTYPE_WARNED(decl) DECL_LANG_FLAG_2(decl) +#endif + +/* 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)) + +/* Nonzero for a declaration of a built in function if there has been no + occasion that would declare the function in ordinary C. + Using the function draws a pedantic warning in this case. */ +#define C_DECL_ANTICIPATED(exp) DECL_LANG_FLAG_3 ((exp)) + +/* 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_NONCOPIED_PARTS (NODE) + +/* In a FIELD_DECL, nonzero if the decl was originally a bitfield. */ +#define DECL_C_BIT_FIELD(NODE) DECL_LANG_FLAG_4 (NODE) + +/* Nonzero if the type T promotes to itself. + ANSI C states explicitly the list of types that promote; + in particular, short promotes to int even if they have the same width. */ +#define C_PROMOTING_INTEGER_TYPE_P(t) \ + (TREE_CODE ((t)) == INTEGER_TYPE \ + && (TYPE_MAIN_VARIANT (t) == char_type_node \ + || TYPE_MAIN_VARIANT (t) == signed_char_type_node \ + || TYPE_MAIN_VARIANT (t) == unsigned_char_type_node \ + || TYPE_MAIN_VARIANT (t) == short_integer_type_node \ + || TYPE_MAIN_VARIANT (t) == short_unsigned_type_node)) + +/* In a VAR_DECL, means the variable is really an iterator. */ +#define ITERATOR_P(D) (DECL_LANG_FLAG_4(D)) + +/* In a VAR_DECL for an iterator, means we are within + an explicit loop over that iterator. */ +#define ITERATOR_BOUND_P(NODE) ((NODE)->common.readonly_flag) + +/* in c-lang.c and objc-act.c */ +extern tree lookup_interface PROTO((tree)); +extern tree is_class_name PROTO((tree)); +extern void maybe_objc_check_decl PROTO((tree)); +extern void finish_file PROTO((void)); +extern int maybe_objc_comptypes PROTO((tree, tree, int)); +extern tree maybe_building_objc_message_expr PROTO((void)); +extern tree maybe_objc_method_name PROTO((tree)); +extern int recognize_objc_keyword PROTO((void)); +extern tree build_objc_string PROTO((int, char *)); + +/* in c-aux-info.c */ +extern void gen_aux_info_record PROTO((tree, int, int, int)); + +/* in c-common.c */ +extern void declare_function_name PROTO((void)); +extern void decl_attributes PROTO((tree, tree, tree)); +extern void init_function_format_info PROTO((void)); +extern void check_function_format PROTO((tree, tree, tree)); +extern int c_get_alias_set PROTO((tree)); +extern void c_apply_type_quals_to_decl PROTO((int, 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 PROTO((enum tree_code)); +extern void c_expand_expr_stmt PROTO((tree)); +extern void c_expand_start_cond PROTO((tree, int, int)); +extern void c_expand_start_else PROTO((void)); +extern void c_expand_end_cond PROTO((void)); +/* Validate the expression after `case' and apply default promotions. */ +extern tree check_case_value PROTO((tree)); +/* Concatenate a list of STRING_CST nodes into one STRING_CST. */ +extern tree combine_strings PROTO((tree)); +extern void constant_expression_warning PROTO((tree)); +extern tree convert_and_check PROTO((tree, tree)); +extern void overflow_warning PROTO((tree)); +extern void unsigned_conversion_warning PROTO((tree, tree)); +/* Read the rest of the current #-directive line. */ +#if USE_CPPLIB +extern char *get_directive_line PROTO((void)); +#define GET_DIRECTIVE_LINE() get_directive_line () +#else +extern char *get_directive_line PROTO((FILE *)); +#define GET_DIRECTIVE_LINE() get_directive_line (finput) +#endif + +/* Subroutine of build_binary_op, used for comparison operations. + See if the operands have both been converted from subword integer types + and, if so, perhaps change them both back to their original type. */ +extern tree shorten_compare PROTO((tree *, tree *, tree *, enum tree_code *)); +/* Prepare expr to be an argument of a TRUTH_NOT_EXPR, + or validate its data type for an `if' or `while' statement or ?..: exp. */ +extern tree truthvalue_conversion PROTO((tree)); +extern tree type_for_mode PROTO((enum machine_mode, int)); +extern tree type_for_size PROTO((unsigned, int)); + +/* in c-convert.c */ +extern tree convert PROTO((tree, tree)); + +/* in c-decl.c */ +/* Standard named or nameless data types of the C compiler. */ +extern tree char_array_type_node; +extern tree char_type_node; +extern tree const_ptr_type_node; +extern tree const_string_type_node; +extern tree default_function_type; +extern tree double_ftype_double; +extern tree double_ftype_double_double; +extern tree double_type_node; +extern tree float_type_node; +#if HOST_BITS_PER_WIDE_INT >= 64 +extern tree intTI_type_node; +#endif +extern tree intDI_type_node; +extern tree intHI_type_node; +extern tree intQI_type_node; +extern tree intSI_type_node; +extern tree int_array_type_node; +extern tree int_ftype_cptr_cptr_sizet; +extern tree int_ftype_int; +extern tree int_ftype_ptr_ptr_int; +extern tree int_ftype_string_string; +extern tree integer_type_node; +extern tree long_double_type_node; +extern tree long_ftype_long; +extern tree long_integer_type_node; +extern tree long_long_integer_type_node; +extern tree long_long_unsigned_type_node; +extern tree long_unsigned_type_node; +extern tree complex_integer_type_node; +extern tree complex_float_type_node; +extern tree complex_double_type_node; +extern tree complex_long_double_type_node; +extern tree ptr_type_node; +extern tree ptrdiff_type_node; +extern tree short_integer_type_node; +extern tree short_unsigned_type_node; +extern tree signed_char_type_node; +extern tree signed_wchar_type_node; +extern tree string_ftype_ptr_ptr; +extern tree string_type_node; +extern tree unsigned_char_type_node; +#if HOST_BITS_PER_WIDE_INT >= 64 +extern tree unsigned_intTI_type_node; +#endif +extern tree unsigned_intDI_type_node; +extern tree unsigned_intHI_type_node; +extern tree unsigned_intQI_type_node; +extern tree unsigned_intSI_type_node; +extern tree unsigned_type_node; +extern tree unsigned_wchar_type_node; +extern tree void_ftype_ptr_int_int; +extern tree void_ftype_ptr_ptr_int; +extern tree void_type_node; +extern tree wchar_array_type_node; +extern tree wchar_type_node; +extern tree boolean_type_node; +extern tree boolean_true_node; +extern tree boolean_false_node; + +extern tree build_enumerator PROTO((tree, tree)); +/* Declare a predefined function. Return the declaration. */ +extern tree builtin_function PROTO((char *, tree, enum built_in_function function_, char *)); +/* Add qualifiers to a type, in the fashion for C. */ +extern tree c_build_qualified_type PROTO((tree, int)); +#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)) +extern int c_decode_option PROTO((int, char **)); +extern void c_mark_varargs PROTO((void)); +extern tree check_identifier PROTO((tree, tree)); +extern void clear_parm_order PROTO((void)); +extern tree combine_parm_decls PROTO((tree, tree, int)); +extern int complete_array_type PROTO((tree, tree, int)); +extern void declare_parm_level PROTO((int)); +extern tree define_label PROTO((char *, int, tree)); +extern void delete_block PROTO((tree)); +extern void finish_decl PROTO((tree, tree, tree)); +extern void finish_decl_top_level PROTO((tree, tree, tree)); +extern tree finish_enum PROTO((tree, tree, tree)); +extern void finish_function PROTO((int)); +extern tree finish_struct PROTO((tree, tree, tree)); +extern tree get_parm_info PROTO((int)); +extern tree getdecls PROTO((void)); +extern tree gettags PROTO((void)); +extern int global_bindings_p PROTO((void)); +extern tree grokfield PROTO((char *, int, tree, tree, tree)); +extern tree groktypename PROTO((tree)); +extern tree groktypename_in_parm_context PROTO((tree)); +extern tree implicitly_declare PROTO((tree)); +extern int in_parm_level_p PROTO((void)); +extern void init_decl_processing PROTO((void)); +extern void insert_block PROTO((tree)); +extern void keep_next_level PROTO((void)); +extern int kept_level_p PROTO((void)); +extern tree lookup_label PROTO((tree)); +extern tree lookup_name PROTO((tree)); +extern tree lookup_name_current_level PROTO((tree)); +extern tree lookup_name_current_level_global PROTO((tree)); +extern tree maybe_build_cleanup PROTO((tree)); +extern void parmlist_tags_warning PROTO((void)); +extern void pending_xref_error PROTO((void)); +extern void pop_c_function_context PROTO((void)); +extern void pop_label_level PROTO((void)); +extern tree poplevel PROTO((int, int, int)); +extern void print_lang_decl PROTO((FILE *, tree, int)); +extern void print_lang_identifier PROTO((FILE *, tree, int)); +extern void print_lang_type PROTO((FILE *, tree, int)); +extern void push_c_function_context PROTO((void)); +extern void push_label_level PROTO((void)); +extern void push_parm_decl PROTO((tree)); +extern tree pushdecl PROTO((tree)); +extern tree pushdecl_top_level PROTO((tree)); +extern void pushlevel PROTO((int)); +extern void pushtag PROTO((tree, tree)); +extern void set_block PROTO((tree)); +extern tree shadow_label PROTO((tree)); +extern void shadow_record_fields PROTO((tree)); +extern void shadow_tag PROTO((tree)); +extern void shadow_tag_warned PROTO((tree, int)); +extern tree start_enum PROTO((tree)); +extern int start_function PROTO((tree, tree, tree, + tree, int)); +extern tree start_decl PROTO((tree, tree, int, + tree, tree)); +extern tree start_struct PROTO((enum tree_code, tree)); +extern void store_parm_decls PROTO((void)); +extern tree xref_tag PROTO((enum tree_code, tree)); + +/* in c-typeck.c */ +extern tree require_complete_type PROTO((tree)); +extern void incomplete_type_error PROTO((tree, tree)); +/* Given two integer or real types, return the type for their sum. + Given two compatible ANSI C types, returns the merged type. */ +extern tree common_type PROTO((tree, tree)); +extern int comptypes PROTO((tree, tree)); +extern int self_promoting_args_p PROTO((tree)); +extern tree c_sizeof PROTO((tree)); +extern tree c_sizeof_nowarn PROTO((tree)); +extern tree c_size_in_bytes PROTO((tree)); +extern tree c_alignof PROTO((tree)); +extern tree c_alignof_expr PROTO((tree)); +extern tree default_conversion PROTO((tree)); +extern tree build_component_ref PROTO((tree, tree)); +extern tree build_indirect_ref PROTO((tree, char *)); +extern tree build_array_ref PROTO((tree, tree)); +extern tree build_function_call PROTO((tree, tree)); +extern tree parser_build_binary_op PROTO((enum tree_code, + tree, tree)); +extern tree build_binary_op PROTO((enum tree_code, + tree, tree, int)); +extern tree build_unary_op PROTO((enum tree_code, + tree, int)); +extern int lvalue_p PROTO((tree)); +extern int lvalue_or_else PROTO((tree, char *)); +extern void readonly_warning PROTO((tree, char *)); +extern int mark_addressable PROTO((tree)); +extern tree build_conditional_expr PROTO((tree, tree, tree)); +extern tree build_compound_expr PROTO((tree)); +extern tree build_c_cast PROTO((tree, tree)); +extern tree build_modify_expr PROTO((tree, enum tree_code, + tree)); +extern tree initializer_constant_valid_p PROTO((tree, tree)); +extern void store_init_value PROTO((tree, tree)); +extern void error_init PROTO((char *, char *, + char *)); +extern void pedwarn_init PROTO((char *, char *, + char *)); +extern void start_init PROTO((tree, tree, int)); +extern void finish_init PROTO((void)); +extern void really_start_incremental_init PROTO((tree)); +extern void push_init_level PROTO((int)); +extern tree pop_init_level PROTO((int)); +extern void set_init_index PROTO((tree, tree)); +extern void set_init_label PROTO((tree)); +extern void process_init_element PROTO((tree)); +extern void c_expand_asm_operands PROTO((tree, tree, tree, tree, + int, char *, int)); +extern void c_expand_return PROTO((tree)); +extern tree c_expand_start_case PROTO((tree)); + +/* in c-iterate.c */ +extern void init_iterators PROTO((void)); +extern void iterator_expand PROTO((tree)); +extern void iterator_for_loop_start PROTO((tree)); +extern void iterator_for_loop_end PROTO((tree)); +extern void iterator_for_loop_record PROTO((tree)); +extern void push_iterator_stack PROTO((void)); +extern void pop_iterator_stack PROTO((void)); + +/* Set to 0 at beginning of a function definition, set to 1 if + a return statement that specifies a return value is seen. */ + +extern int current_function_returns_value; + +/* Set to 0 at beginning of a function definition, set to 1 if + a return statement with no argument is seen. */ + +extern int current_function_returns_null; + +/* Nonzero means the expression being parsed will never be evaluated. + This is a count, since unevaluated expressions can nest. */ + +extern int skip_evaluation; + +/* Nonzero means `$' can be in an identifier. */ + +extern int dollars_in_ident; + +/* Nonzero means allow type mismatches in conditional expressions; + just make their values `void'. */ + +extern int flag_cond_mismatch; + +/* Nonzero means don't recognize the keyword `asm'. */ + +extern int flag_no_asm; + +/* Nonzero means environment is hosted (i.e., not freestanding) */ + +extern int flag_hosted; + +/* Nonzero means ignore `#ident' directives. */ + +extern int flag_no_ident; + +/* Nonzero means warn about implicit declarations. */ + +extern int warn_implicit; + +/* Nonzero means give string constants the type `const char *' + to get extra warnings from them. These warnings will be too numerous + to be useful, except in thoroughly ANSIfied programs. */ + +extern int flag_const_strings; + +/* Nonzero means warn about sizeof (function) or addition/subtraction + of function pointers. */ + +extern int warn_pointer_arith; + +/* Nonzero means warn for all old-style non-prototype function decls. */ + +extern int warn_strict_prototypes; + +/* Nonzero means warn about multiple (redundant) decls for the same single + variable or function. */ + +extern int warn_redundant_decls; + +/* 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; + +/* Nonzero means warn about pointer casts that can drop a type qualifier + from the pointer target type. */ + +extern int warn_cast_qual; + +/* 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 functions which might be candidates for attribute noreturn. */ + +extern int warn_missing_noreturn; + +/* Warn about traditional constructs whose meanings changed in ANSI C. */ + +extern int warn_traditional; + +/* Warn about *printf or *scanf format/argument anomalies. */ + +extern int warn_format; + +/* 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 if main is suspicious. */ + +extern int warn_main; + +/* Nonzero means do some things the same way PCC does. */ + +extern int flag_traditional; + +/* Nonzero means use the ISO C9x dialect of C. */ + +extern int flag_isoc9x; + +/* Nonzero means to allow single precision math even if we're generally + being traditional. */ +extern int flag_allow_single_precision; + +/* Nonzero means warn about suggesting putting in ()'s. */ + +extern int warn_parentheses; + +/* Warn if initializer is not completely bracketed. */ + +extern int warn_missing_braces; + +/* Warn about comparison of signed and unsigned values. */ + +extern int warn_sign_compare; + +/* Warn about multicharacter constants. */ + +extern int warn_multichar; + +/* Warn about long long. */ + +extern int warn_long_long; + +/* Nonzero means we are reading code that came from a system header file. */ + +extern int system_header_p; + +/* Nonzero enables objc features. */ + +extern int doing_objc_thang; + +/* In c-decl.c */ +extern void finish_incomplete_decl PROTO((tree)); + +#endif /* not _C_TREE_H */ diff --git a/gcc_arm/c-typeck.c b/gcc_arm/c-typeck.c new file mode 100755 index 0000000..ab3ede7 --- /dev/null +++ b/gcc_arm/c-typeck.c @@ -0,0 +1,7022 @@ +/* Build expressions with type checking for C compiler. + Copyright (C) 1987, 88, 91-97, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* This file is part of the C front end. + It contains routines to build C expressions given their operands, + including computing the types of the result, C-specific error checks, + and some optimization. + + There are also routines to build RETURN_STMT nodes and CASE_STMT nodes, + and to process initializations in declarations (since they work + like a strange sort of assignment). */ + +#include "config.h" +#include "system.h" +#include "tree.h" +#include "c-tree.h" +#include "flags.h" +#include "output.h" +#include "rtl.h" +#include "expr.h" +#include "toplev.h" + +/* Nonzero if we've already printed a "missing braces around initializer" + message within this initializer. */ +static int missing_braces_mentioned; + +static tree qualify_type PROTO((tree, tree)); +static int comp_target_types PROTO((tree, tree)); +static int function_types_compatible_p PROTO((tree, tree)); +static int type_lists_compatible_p PROTO((tree, tree)); +static int self_promoting_type_p PROTO((tree)); +static tree decl_constant_value PROTO((tree)); +static tree lookup_field PROTO((tree, tree, tree *)); +static tree convert_arguments PROTO((tree, tree, tree, tree)); +static tree pointer_int_sum PROTO((enum tree_code, tree, tree)); +static tree pointer_diff PROTO((tree, tree)); +static tree unary_complex_lvalue PROTO((enum tree_code, tree)); +static void pedantic_lvalue_warning PROTO((enum tree_code)); +static tree internal_build_compound_expr PROTO((tree, int)); +static tree convert_for_assignment PROTO((tree, tree, char *, tree, + tree, int)); +static void warn_for_assignment PROTO((char *, char *, tree, int)); +static tree valid_compound_expr_initializer PROTO((tree, tree)); +static void push_string PROTO((char *)); +static void push_member_name PROTO((tree)); +static void push_array_bounds PROTO((int)); +static int spelling_length PROTO((void)); +static char *print_spelling PROTO((char *)); +static char *get_spelling PROTO((char *)); +static void warning_init PROTO((char *, char *, + char *)); +static tree digest_init PROTO((tree, tree, int, int)); +static void check_init_type_bitfields PROTO((tree)); +static void output_init_element PROTO((tree, tree, tree, int)); +static void output_pending_init_elements PROTO((int)); +static void add_pending_init PROTO((tree, tree)); +static int pending_init_member PROTO((tree)); + +/* Do `exp = require_complete_type (exp);' to make sure exp + does not have an incomplete type. (That includes void types.) */ + +tree +require_complete_type (value) + tree value; +{ + tree type = TREE_TYPE (value); + + /* First, detect a valid value with a complete type. */ + if (TYPE_SIZE (type) != 0 + && type != void_type_node) + return value; + + incomplete_type_error (value, type); + return error_mark_node; +} + +/* Print an error message for invalid use of an incomplete type. + VALUE is the expression that was used (or 0 if that isn't known) + and TYPE is the type that was invalid. */ + +void +incomplete_type_error (value, type) + tree value; + tree type; +{ + char *errmsg; + + /* Avoid duplicate error message. */ + if (TREE_CODE (type) == ERROR_MARK) + return; + + if (value != 0 && (TREE_CODE (value) == VAR_DECL + || TREE_CODE (value) == PARM_DECL)) + error ("`%s' has an incomplete type", + IDENTIFIER_POINTER (DECL_NAME (value))); + else + { + retry: + /* We must print an error message. Be clever about what it says. */ + + switch (TREE_CODE (type)) + { + case RECORD_TYPE: + errmsg = "invalid use of undefined type `struct %s'"; + break; + + case UNION_TYPE: + errmsg = "invalid use of undefined type `union %s'"; + break; + + case ENUMERAL_TYPE: + errmsg = "invalid use of undefined type `enum %s'"; + break; + + case VOID_TYPE: + error ("invalid use of void expression"); + return; + + case ARRAY_TYPE: + if (TYPE_DOMAIN (type)) + { + type = TREE_TYPE (type); + goto retry; + } + error ("invalid use of array with unspecified bounds"); + return; + + default: + abort (); + } + + if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) + error (errmsg, IDENTIFIER_POINTER (TYPE_NAME (type))); + else + /* If this type has a typedef-name, the TYPE_NAME is a TYPE_DECL. */ + error ("invalid use of incomplete typedef `%s'", + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)))); + } +} + +/* Return a variant of TYPE which has all the type qualifiers of LIKE + as well as those of TYPE. */ + +static tree +qualify_type (type, like) + tree type, like; +{ + return c_build_qualified_type (type, TYPE_QUALS (like)); +} + +/* Return the common type of two types. + We assume that comptypes has already been done and returned 1; + if that isn't so, this may crash. In particular, we assume that qualifiers + match. + + This is the type for the result of most arithmetic operations + if the operands have the given two types. */ + +tree +common_type (t1, t2) + tree t1, t2; +{ + register enum tree_code code1; + register enum tree_code code2; + tree attributes; + + /* Save time if the two types are the same. */ + + if (t1 == t2) return t1; + + /* If one type is nonsense, use the other. */ + if (t1 == error_mark_node) + return t2; + if (t2 == error_mark_node) + return t1; + + /* Merge the attributes. */ + attributes = merge_machine_type_attributes (t1, t2); + + /* Treat an enum type as the unsigned integer type of the same width. */ + + if (TREE_CODE (t1) == ENUMERAL_TYPE) + t1 = type_for_size (TYPE_PRECISION (t1), 1); + if (TREE_CODE (t2) == ENUMERAL_TYPE) + t2 = type_for_size (TYPE_PRECISION (t2), 1); + + code1 = TREE_CODE (t1); + code2 = TREE_CODE (t2); + + /* If one type is complex, form the common type of the non-complex + components, then make that complex. Use T1 or T2 if it is the + required type. */ + if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE) + { + tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1; + tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2; + tree subtype = common_type (subtype1, subtype2); + + if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype) + return build_type_attribute_variant (t1, attributes); + else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype) + return build_type_attribute_variant (t2, attributes); + else + return build_type_attribute_variant (build_complex_type (subtype), + attributes); + } + + switch (code1) + { + case INTEGER_TYPE: + case REAL_TYPE: + /* If only one is real, use it as the result. */ + + if (code1 == REAL_TYPE && code2 != REAL_TYPE) + return build_type_attribute_variant (t1, attributes); + + if (code2 == REAL_TYPE && code1 != REAL_TYPE) + return build_type_attribute_variant (t2, attributes); + + /* Both real or both integers; use the one with greater precision. */ + + if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2)) + return build_type_attribute_variant (t1, attributes); + else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1)) + return build_type_attribute_variant (t2, attributes); + + /* Same precision. Prefer longs to ints even when same size. */ + + if (TYPE_MAIN_VARIANT (t1) == long_unsigned_type_node + || TYPE_MAIN_VARIANT (t2) == long_unsigned_type_node) + return build_type_attribute_variant (long_unsigned_type_node, + attributes); + + if (TYPE_MAIN_VARIANT (t1) == long_integer_type_node + || TYPE_MAIN_VARIANT (t2) == long_integer_type_node) + { + /* But preserve unsignedness from the other type, + since long cannot hold all the values of an unsigned int. */ + if (TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2)) + t1 = long_unsigned_type_node; + else + t1 = long_integer_type_node; + return build_type_attribute_variant (t1, attributes); + } + + /* Likewise, prefer long double to double even if same size. */ + if (TYPE_MAIN_VARIANT (t1) == long_double_type_node + || TYPE_MAIN_VARIANT (t2) == long_double_type_node) + return build_type_attribute_variant (long_double_type_node, + attributes); + + /* Otherwise prefer the unsigned one. */ + + if (TREE_UNSIGNED (t1)) + return build_type_attribute_variant (t1, attributes); + else + return build_type_attribute_variant (t2, attributes); + + case POINTER_TYPE: + /* For two pointers, do this recursively on the target type, + and combine the qualifiers of the two types' targets. */ + /* This code was turned off; I don't know why. + But ANSI C specifies doing this with the qualifiers. + So I turned it on again. */ + { + tree pointed_to_1 = TREE_TYPE (t1); + tree pointed_to_2 = TREE_TYPE (t2); + tree target = common_type (TYPE_MAIN_VARIANT (pointed_to_1), + TYPE_MAIN_VARIANT (pointed_to_2)); + t1 = build_pointer_type (c_build_qualified_type + (target, + TYPE_QUALS (pointed_to_1) | + TYPE_QUALS (pointed_to_2))); + return build_type_attribute_variant (t1, attributes); + } +#if 0 + t1 = build_pointer_type (common_type (TREE_TYPE (t1), TREE_TYPE (t2))); + return build_type_attribute_variant (t1, attributes); +#endif + + case ARRAY_TYPE: + { + tree elt = common_type (TREE_TYPE (t1), TREE_TYPE (t2)); + /* Save space: see if the result is identical to one of the args. */ + if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1)) + return build_type_attribute_variant (t1, attributes); + if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2)) + return build_type_attribute_variant (t2, attributes); + /* Merge the element types, and have a size if either arg has one. */ + t1 = build_array_type (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2)); + return build_type_attribute_variant (t1, attributes); + } + + case FUNCTION_TYPE: + /* Function types: prefer the one that specified arg types. + If both do, merge the arg types. Also merge the return types. */ + { + tree valtype = common_type (TREE_TYPE (t1), TREE_TYPE (t2)); + tree p1 = TYPE_ARG_TYPES (t1); + tree p2 = TYPE_ARG_TYPES (t2); + int len; + tree newargs, n; + int i; + + /* Save space: see if the result is identical to one of the args. */ + if (valtype == TREE_TYPE (t1) && ! TYPE_ARG_TYPES (t2)) + return build_type_attribute_variant (t1, attributes); + if (valtype == TREE_TYPE (t2) && ! TYPE_ARG_TYPES (t1)) + return build_type_attribute_variant (t2, attributes); + + /* Simple way if one arg fails to specify argument types. */ + if (TYPE_ARG_TYPES (t1) == 0) + { + t1 = build_function_type (valtype, TYPE_ARG_TYPES (t2)); + return build_type_attribute_variant (t1, attributes); + } + if (TYPE_ARG_TYPES (t2) == 0) + { + t1 = build_function_type (valtype, TYPE_ARG_TYPES (t1)); + return build_type_attribute_variant (t1, attributes); + } + + /* If both args specify argument types, we must merge the two + lists, argument by argument. */ + + len = list_length (p1); + newargs = 0; + + for (i = 0; i < len; i++) + newargs = tree_cons (NULL_TREE, NULL_TREE, newargs); + + n = newargs; + + for (; p1; + p1 = TREE_CHAIN (p1), p2 = TREE_CHAIN (p2), n = TREE_CHAIN (n)) + { + /* A null type means arg type is not specified. + Take whatever the other function type has. */ + if (TREE_VALUE (p1) == 0) + { + TREE_VALUE (n) = TREE_VALUE (p2); + goto parm_done; + } + if (TREE_VALUE (p2) == 0) + { + TREE_VALUE (n) = TREE_VALUE (p1); + goto parm_done; + } + + /* Given wait (union {union wait *u; int *i} *) + and wait (union wait *), + prefer union wait * as type of parm. */ + if (TREE_CODE (TREE_VALUE (p1)) == UNION_TYPE + && TREE_VALUE (p1) != TREE_VALUE (p2)) + { + tree memb; + for (memb = TYPE_FIELDS (TREE_VALUE (p1)); + memb; memb = TREE_CHAIN (memb)) + if (comptypes (TREE_TYPE (memb), TREE_VALUE (p2))) + { + TREE_VALUE (n) = TREE_VALUE (p2); + if (pedantic) + pedwarn ("function types not truly compatible in ANSI C"); + goto parm_done; + } + } + if (TREE_CODE (TREE_VALUE (p2)) == UNION_TYPE + && TREE_VALUE (p2) != TREE_VALUE (p1)) + { + tree memb; + for (memb = TYPE_FIELDS (TREE_VALUE (p2)); + memb; memb = TREE_CHAIN (memb)) + if (comptypes (TREE_TYPE (memb), TREE_VALUE (p1))) + { + TREE_VALUE (n) = TREE_VALUE (p1); + if (pedantic) + pedwarn ("function types not truly compatible in ANSI C"); + goto parm_done; + } + } + TREE_VALUE (n) = common_type (TREE_VALUE (p1), TREE_VALUE (p2)); + parm_done: ; + } + + t1 = build_function_type (valtype, newargs); + /* ... falls through ... */ + } + + default: + return build_type_attribute_variant (t1, attributes); + } + +} + +/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment + or various other operations. Return 2 if they are compatible + but a warning may be needed if you use them together. */ + +int +comptypes (type1, type2) + tree type1, type2; +{ + register tree t1 = type1; + register tree t2 = type2; + int attrval, val; + + /* Suppress errors caused by previously reported errors. */ + + if (t1 == t2 || !t1 || !t2 + || TREE_CODE (t1) == ERROR_MARK || TREE_CODE (t2) == ERROR_MARK) + return 1; + + /* Treat an enum type as the integer type of the same width and + signedness. */ + + if (TREE_CODE (t1) == ENUMERAL_TYPE) + t1 = type_for_size (TYPE_PRECISION (t1), TREE_UNSIGNED (t1)); + if (TREE_CODE (t2) == ENUMERAL_TYPE) + t2 = type_for_size (TYPE_PRECISION (t2), TREE_UNSIGNED (t2)); + + if (t1 == t2) + return 1; + + /* Different classes of types can't be compatible. */ + + if (TREE_CODE (t1) != TREE_CODE (t2)) return 0; + + /* Qualifiers must match. */ + + if (TYPE_QUALS (t1) != TYPE_QUALS (t2)) + return 0; + + /* Allow for two different type nodes which have essentially the same + definition. Note that we already checked for equality of the type + qualifiers (just above). */ + + if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2)) + return 1; + +#ifndef COMP_TYPE_ATTRIBUTES +#define COMP_TYPE_ATTRIBUTES(t1,t2) 1 +#endif + + /* 1 if no need for warning yet, 2 if warning cause has been seen. */ + if (! (attrval = COMP_TYPE_ATTRIBUTES (t1, t2))) + return 0; + + /* 1 if no need for warning yet, 2 if warning cause has been seen. */ + val = 0; + + switch (TREE_CODE (t1)) + { + case POINTER_TYPE: + val = (TREE_TYPE (t1) == TREE_TYPE (t2) + ? 1 : comptypes (TREE_TYPE (t1), TREE_TYPE (t2))); + break; + + case FUNCTION_TYPE: + val = function_types_compatible_p (t1, t2); + break; + + case ARRAY_TYPE: + { + tree d1 = TYPE_DOMAIN (t1); + tree d2 = TYPE_DOMAIN (t2); + val = 1; + + /* Target types must match incl. qualifiers. */ + if (TREE_TYPE (t1) != TREE_TYPE (t2) + && 0 == (val = comptypes (TREE_TYPE (t1), TREE_TYPE (t2)))) + return 0; + + /* Sizes must match unless one is missing or variable. */ + if (d1 == 0 || d2 == 0 || d1 == d2 + || TREE_CODE (TYPE_MIN_VALUE (d1)) != INTEGER_CST + || TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST + || TREE_CODE (TYPE_MAX_VALUE (d1)) != INTEGER_CST + || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST) + break; + + if (! ((TREE_INT_CST_LOW (TYPE_MIN_VALUE (d1)) + == TREE_INT_CST_LOW (TYPE_MIN_VALUE (d2))) + && (TREE_INT_CST_HIGH (TYPE_MIN_VALUE (d1)) + == TREE_INT_CST_HIGH (TYPE_MIN_VALUE (d2))) + && (TREE_INT_CST_LOW (TYPE_MAX_VALUE (d1)) + == TREE_INT_CST_LOW (TYPE_MAX_VALUE (d2))) + && (TREE_INT_CST_HIGH (TYPE_MAX_VALUE (d1)) + == TREE_INT_CST_HIGH (TYPE_MAX_VALUE (d2))))) + val = 0; + break; + } + + case RECORD_TYPE: + if (maybe_objc_comptypes (t1, t2, 0) == 1) + val = 1; + break; + + default: + break; + } + return attrval == 2 && val == 1 ? 2 : val; +} + +/* Return 1 if TTL and TTR are pointers to types that are equivalent, + ignoring their qualifiers. */ + +static int +comp_target_types (ttl, ttr) + tree ttl, ttr; +{ + int val; + + /* Give maybe_objc_comptypes a crack at letting these types through. */ + if ((val = maybe_objc_comptypes (ttl, ttr, 1)) >= 0) + return val; + + val = comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (ttl)), + TYPE_MAIN_VARIANT (TREE_TYPE (ttr))); + + if (val == 2 && pedantic) + pedwarn ("types are not quite compatible"); + return val; +} + +/* Subroutines of `comptypes'. */ + +/* Return 1 if two function types F1 and F2 are compatible. + If either type specifies no argument types, + the other must specify a fixed number of self-promoting arg types. + Otherwise, if one type specifies only the number of arguments, + the other must specify that number of self-promoting arg types. + Otherwise, the argument types must match. */ + +static int +function_types_compatible_p (f1, f2) + tree f1, f2; +{ + tree args1, args2; + /* 1 if no need for warning yet, 2 if warning cause has been seen. */ + int val = 1; + int val1; + + if (!(TREE_TYPE (f1) == TREE_TYPE (f2) + || (val = comptypes (TREE_TYPE (f1), TREE_TYPE (f2))))) + return 0; + + args1 = TYPE_ARG_TYPES (f1); + args2 = TYPE_ARG_TYPES (f2); + + /* An unspecified parmlist matches any specified parmlist + whose argument types don't need default promotions. */ + + if (args1 == 0) + { + if (!self_promoting_args_p (args2)) + return 0; + /* If one of these types comes from a non-prototype fn definition, + compare that with the other type's arglist. + If they don't match, ask for a warning (but no error). */ + if (TYPE_ACTUAL_ARG_TYPES (f1) + && 1 != type_lists_compatible_p (args2, TYPE_ACTUAL_ARG_TYPES (f1))) + val = 2; + return val; + } + if (args2 == 0) + { + if (!self_promoting_args_p (args1)) + return 0; + if (TYPE_ACTUAL_ARG_TYPES (f2) + && 1 != type_lists_compatible_p (args1, TYPE_ACTUAL_ARG_TYPES (f2))) + val = 2; + return val; + } + + /* Both types have argument lists: compare them and propagate results. */ + val1 = type_lists_compatible_p (args1, args2); + return val1 != 1 ? val1 : val; +} + +/* Check two lists of types for compatibility, + returning 0 for incompatible, 1 for compatible, + or 2 for compatible with warning. */ + +static int +type_lists_compatible_p (args1, args2) + tree args1, args2; +{ + /* 1 if no need for warning yet, 2 if warning cause has been seen. */ + int val = 1; + int newval = 0; + + while (1) + { + if (args1 == 0 && args2 == 0) + return val; + /* If one list is shorter than the other, + they fail to match. */ + if (args1 == 0 || args2 == 0) + return 0; + /* A null pointer instead of a type + means there is supposed to be an argument + but nothing is specified about what type it has. + So match anything that self-promotes. */ + if (TREE_VALUE (args1) == 0) + { + if (! self_promoting_type_p (TREE_VALUE (args2))) + return 0; + } + else if (TREE_VALUE (args2) == 0) + { + if (! self_promoting_type_p (TREE_VALUE (args1))) + return 0; + } + else if (! (newval = comptypes (TREE_VALUE (args1), TREE_VALUE (args2)))) + { + /* Allow wait (union {union wait *u; int *i} *) + and wait (union wait *) to be compatible. */ + if (TREE_CODE (TREE_VALUE (args1)) == UNION_TYPE + && (TYPE_NAME (TREE_VALUE (args1)) == 0 + || TYPE_TRANSPARENT_UNION (TREE_VALUE (args1))) + && TREE_CODE (TYPE_SIZE (TREE_VALUE (args1))) == INTEGER_CST + && tree_int_cst_equal (TYPE_SIZE (TREE_VALUE (args1)), + TYPE_SIZE (TREE_VALUE (args2)))) + { + tree memb; + for (memb = TYPE_FIELDS (TREE_VALUE (args1)); + memb; memb = TREE_CHAIN (memb)) + if (comptypes (TREE_TYPE (memb), TREE_VALUE (args2))) + break; + if (memb == 0) + return 0; + } + else if (TREE_CODE (TREE_VALUE (args2)) == UNION_TYPE + && (TYPE_NAME (TREE_VALUE (args2)) == 0 + || TYPE_TRANSPARENT_UNION (TREE_VALUE (args2))) + && TREE_CODE (TYPE_SIZE (TREE_VALUE (args2))) == INTEGER_CST + && tree_int_cst_equal (TYPE_SIZE (TREE_VALUE (args2)), + TYPE_SIZE (TREE_VALUE (args1)))) + { + tree memb; + for (memb = TYPE_FIELDS (TREE_VALUE (args2)); + memb; memb = TREE_CHAIN (memb)) + if (comptypes (TREE_TYPE (memb), TREE_VALUE (args1))) + break; + if (memb == 0) + return 0; + } + else + return 0; + } + + /* comptypes said ok, but record if it said to warn. */ + if (newval > val) + val = newval; + + args1 = TREE_CHAIN (args1); + args2 = TREE_CHAIN (args2); + } +} + +/* Return 1 if PARMS specifies a fixed number of parameters + and none of their types is affected by default promotions. */ + +int +self_promoting_args_p (parms) + tree parms; +{ + register tree t; + for (t = parms; t; t = TREE_CHAIN (t)) + { + register tree type = TREE_VALUE (t); + + if (TREE_CHAIN (t) == 0 && type != void_type_node) + return 0; + + if (type == 0) + return 0; + + if (TYPE_MAIN_VARIANT (type) == float_type_node) + return 0; + + if (C_PROMOTING_INTEGER_TYPE_P (type)) + return 0; + } + return 1; +} + +/* Return 1 if TYPE is not affected by default promotions. */ + +static int +self_promoting_type_p (type) + tree type; +{ + if (TYPE_MAIN_VARIANT (type) == float_type_node) + return 0; + + if (C_PROMOTING_INTEGER_TYPE_P (type)) + return 0; + + return 1; +} + +/* Return an unsigned type the same as TYPE in other respects. */ + +tree +unsigned_type (type) + tree type; +{ + tree type1 = TYPE_MAIN_VARIANT (type); + if (type1 == signed_char_type_node || type1 == char_type_node) + return unsigned_char_type_node; + if (type1 == integer_type_node) + return unsigned_type_node; + if (type1 == short_integer_type_node) + return short_unsigned_type_node; + if (type1 == long_integer_type_node) + return long_unsigned_type_node; + if (type1 == long_long_integer_type_node) + return long_long_unsigned_type_node; + if (type1 == intDI_type_node) + return unsigned_intDI_type_node; + if (type1 == intSI_type_node) + return unsigned_intSI_type_node; + if (type1 == intHI_type_node) + return unsigned_intHI_type_node; + if (type1 == intQI_type_node) + return unsigned_intQI_type_node; + + return signed_or_unsigned_type (1, type); +} + +/* Return a signed type the same as TYPE in other respects. */ + +tree +signed_type (type) + tree type; +{ + tree type1 = TYPE_MAIN_VARIANT (type); + if (type1 == unsigned_char_type_node || type1 == char_type_node) + return signed_char_type_node; + if (type1 == unsigned_type_node) + return integer_type_node; + if (type1 == short_unsigned_type_node) + return short_integer_type_node; + if (type1 == long_unsigned_type_node) + return long_integer_type_node; + if (type1 == long_long_unsigned_type_node) + return long_long_integer_type_node; + if (type1 == unsigned_intDI_type_node) + return intDI_type_node; + if (type1 == unsigned_intSI_type_node) + return intSI_type_node; + if (type1 == unsigned_intHI_type_node) + return intHI_type_node; + if (type1 == unsigned_intQI_type_node) + return intQI_type_node; + + return signed_or_unsigned_type (0, type); +} + +/* Return a type the same as TYPE except unsigned or + signed according to UNSIGNEDP. */ + +tree +signed_or_unsigned_type (unsignedp, type) + int unsignedp; + tree type; +{ + if ((! INTEGRAL_TYPE_P (type) && ! POINTER_TYPE_P (type)) + || TREE_UNSIGNED (type) == unsignedp) + return type; + if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node)) + return unsignedp ? unsigned_char_type_node : signed_char_type_node; + if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + if (TYPE_PRECISION (type) == TYPE_PRECISION (short_integer_type_node)) + return unsignedp ? short_unsigned_type_node : short_integer_type_node; + if (TYPE_PRECISION (type) == TYPE_PRECISION (long_integer_type_node)) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + if (TYPE_PRECISION (type) == TYPE_PRECISION (long_long_integer_type_node)) + return (unsignedp ? long_long_unsigned_type_node + : long_long_integer_type_node); + return type; +} + +/* Compute the value of the `sizeof' operator. */ + +tree +c_sizeof (type) + tree type; +{ + enum tree_code code = TREE_CODE (type); + tree t; + + if (code == FUNCTION_TYPE) + { + if (pedantic || warn_pointer_arith) + pedwarn ("sizeof applied to a function type"); + return size_int (1); + } + if (code == VOID_TYPE) + { + if (pedantic || warn_pointer_arith) + pedwarn ("sizeof applied to a void type"); + return size_int (1); + } + if (code == ERROR_MARK) + return size_int (1); + if (TYPE_SIZE (type) == 0) + { + error ("sizeof applied to an incomplete type"); + return size_int (0); + } + + /* Convert in case a char is more than one unit. */ + t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), + size_int (TYPE_PRECISION (char_type_node))); + t = convert (sizetype, t); + /* size_binop does not put the constant in range, so do it now. */ + if (TREE_CODE (t) == INTEGER_CST && force_fit_type (t, 0)) + TREE_CONSTANT_OVERFLOW (t) = TREE_OVERFLOW (t) = 1; + return t; +} + +tree +c_sizeof_nowarn (type) + tree type; +{ + enum tree_code code = TREE_CODE (type); + tree t; + + if (code == FUNCTION_TYPE + || code == VOID_TYPE + || code == ERROR_MARK) + return size_int (1); + if (TYPE_SIZE (type) == 0) + return size_int (0); + + /* Convert in case a char is more than one unit. */ + t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), + size_int (TYPE_PRECISION (char_type_node))); + t = convert (sizetype, t); + force_fit_type (t, 0); + return t; +} + +/* Compute the size to increment a pointer by. */ + +tree +c_size_in_bytes (type) + tree type; +{ + enum tree_code code = TREE_CODE (type); + tree t; + + if (code == FUNCTION_TYPE) + return size_int (1); + if (code == VOID_TYPE) + return size_int (1); + if (code == ERROR_MARK) + return size_int (1); + if (TYPE_SIZE (type) == 0) + { + error ("arithmetic on pointer to an incomplete type"); + return size_int (1); + } + + /* Convert in case a char is more than one unit. */ + t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), + size_int (BITS_PER_UNIT)); + t = convert (sizetype, t); + force_fit_type (t, 0); + return t; +} + +/* Implement the __alignof keyword: Return the minimum required + alignment of TYPE, measured in bytes. */ + +tree +c_alignof (type) + tree type; +{ + enum tree_code code = TREE_CODE (type); + + if (code == FUNCTION_TYPE) + return size_int (FUNCTION_BOUNDARY / BITS_PER_UNIT); + + if (code == VOID_TYPE || code == ERROR_MARK) + return size_int (1); + + return size_int (TYPE_ALIGN (type) / BITS_PER_UNIT); +} + +/* Implement the __alignof keyword: Return the minimum required + alignment of EXPR, measured in bytes. For VAR_DECL's and + FIELD_DECL's return DECL_ALIGN (which can be set from an + "aligned" __attribute__ specification). */ + +tree +c_alignof_expr (expr) + tree expr; +{ + if (TREE_CODE (expr) == VAR_DECL) + return size_int (DECL_ALIGN (expr) / BITS_PER_UNIT); + + if (TREE_CODE (expr) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND (expr, 1))) + { + error ("`__alignof' applied to a bit-field"); + return size_int (1); + } + else if (TREE_CODE (expr) == COMPONENT_REF + && TREE_CODE (TREE_OPERAND (expr, 1)) == FIELD_DECL) + return size_int (DECL_ALIGN (TREE_OPERAND (expr, 1)) / BITS_PER_UNIT); + + if (TREE_CODE (expr) == INDIRECT_REF) + { + tree t = TREE_OPERAND (expr, 0); + tree best = t; + int bestalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t))); + + while (TREE_CODE (t) == NOP_EXPR + && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == POINTER_TYPE) + { + int thisalign; + + t = TREE_OPERAND (t, 0); + thisalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t))); + if (thisalign > bestalign) + best = t, bestalign = thisalign; + } + return c_alignof (TREE_TYPE (TREE_TYPE (best))); + } + else + return c_alignof (TREE_TYPE (expr)); +} + +/* Return either DECL or its known constant value (if it has one). */ + +static tree +decl_constant_value (decl) + tree decl; +{ + if (/* Don't change a variable array bound or initial value to a constant + in a place where a variable is invalid. */ + current_function_decl != 0 + && ! pedantic + && ! TREE_THIS_VOLATILE (decl) + && TREE_READONLY (decl) && ! ITERATOR_P (decl) + && DECL_INITIAL (decl) != 0 + && TREE_CODE (DECL_INITIAL (decl)) != ERROR_MARK + /* This is invalid if initial value is not constant. + If it has either a function call, a memory reference, + or a variable, then re-evaluating it could give different results. */ + && TREE_CONSTANT (DECL_INITIAL (decl)) + /* Check for cases where this is sub-optimal, even though valid. */ + && TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR + && DECL_MODE (decl) != BLKmode) + return DECL_INITIAL (decl); + return decl; +} + +/* Perform default promotions for C data used in expressions. + Arrays and functions are converted to pointers; + enumeral types or short or char, to int. + In addition, manifest constants symbols are replaced by their values. */ + +tree +default_conversion (exp) + tree exp; +{ + register tree type = TREE_TYPE (exp); + register enum tree_code code = TREE_CODE (type); + + /* Constants can be used directly unless they're not loadable. */ + if (TREE_CODE (exp) == CONST_DECL) + exp = DECL_INITIAL (exp); + + /* Replace a nonvolatile const static variable with its value unless + it is an array, in which case we must be sure that taking the + address of the array produces consistent results. */ + else if (optimize && TREE_CODE (exp) == VAR_DECL && code != ARRAY_TYPE) + { + exp = decl_constant_value (exp); + type = TREE_TYPE (exp); + } + + /* Strip NON_LVALUE_EXPRs and no-op conversions, since we aren't using as + an lvalue. */ + /* Do not use STRIP_NOPS here! It will remove conversions from pointer + to integer and cause infinite recursion. */ + while (TREE_CODE (exp) == NON_LVALUE_EXPR + || (TREE_CODE (exp) == NOP_EXPR + && TREE_TYPE (TREE_OPERAND (exp, 0)) == TREE_TYPE (exp))) + exp = TREE_OPERAND (exp, 0); + + /* Normally convert enums to int, + but convert wide enums to something wider. */ + if (code == ENUMERAL_TYPE) + { + type = type_for_size (MAX (TYPE_PRECISION (type), + TYPE_PRECISION (integer_type_node)), + ((flag_traditional + || (TYPE_PRECISION (type) + >= TYPE_PRECISION (integer_type_node))) + && TREE_UNSIGNED (type))); + return convert (type, exp); + } + + if (TREE_CODE (exp) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND (exp, 1))) + { + tree width = DECL_SIZE (TREE_OPERAND (exp, 1)); + HOST_WIDE_INT low = TREE_INT_CST_LOW (width); + + /* If it's thinner than an int, promote it like a + C_PROMOTING_INTEGER_TYPE_P, otherwise leave it alone. */ + + if (low < TYPE_PRECISION (integer_type_node)) + { + if (flag_traditional && TREE_UNSIGNED (type)) + return convert (unsigned_type_node, exp); + else + return convert (integer_type_node, exp); + } + } + + if (C_PROMOTING_INTEGER_TYPE_P (type)) + { + /* Traditionally, unsignedness is preserved in default promotions. + Also preserve unsignedness if not really getting any wider. */ + if (TREE_UNSIGNED (type) + && (flag_traditional + || TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))) + return convert (unsigned_type_node, exp); + return convert (integer_type_node, exp); + } + if (flag_traditional && !flag_allow_single_precision + && TYPE_MAIN_VARIANT (type) == float_type_node) + return convert (double_type_node, exp); + if (code == VOID_TYPE) + { + error ("void value not ignored as it ought to be"); + return error_mark_node; + } + if (code == FUNCTION_TYPE) + { + return build_unary_op (ADDR_EXPR, exp, 0); + } + if (code == ARRAY_TYPE) + { + register tree adr; + tree restype = TREE_TYPE (type); + tree ptrtype; + int constp = 0; + int volatilep = 0; + + if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'r' + || TREE_CODE_CLASS (TREE_CODE (exp)) == 'd') + { + constp = TREE_READONLY (exp); + volatilep = TREE_THIS_VOLATILE (exp); + } + + if (TYPE_QUALS (type) || constp || volatilep) + restype + = c_build_qualified_type (restype, + TYPE_QUALS (type) + | (constp * TYPE_QUAL_CONST) + | (volatilep * TYPE_QUAL_VOLATILE)); + + if (TREE_CODE (exp) == INDIRECT_REF) + return convert (TYPE_POINTER_TO (restype), + TREE_OPERAND (exp, 0)); + + if (TREE_CODE (exp) == COMPOUND_EXPR) + { + tree op1 = default_conversion (TREE_OPERAND (exp, 1)); + return build (COMPOUND_EXPR, TREE_TYPE (op1), + TREE_OPERAND (exp, 0), op1); + } + + if (! lvalue_p (exp) + && ! (TREE_CODE (exp) == CONSTRUCTOR && TREE_STATIC (exp))) + { + error ("invalid use of non-lvalue array"); + return error_mark_node; + } + + ptrtype = build_pointer_type (restype); + + if (TREE_CODE (exp) == VAR_DECL) + { + /* ??? This is not really quite correct + in that the type of the operand of ADDR_EXPR + is not the target type of the type of the ADDR_EXPR itself. + Question is, can this lossage be avoided? */ + adr = build1 (ADDR_EXPR, ptrtype, exp); + if (mark_addressable (exp) == 0) + return error_mark_node; + TREE_CONSTANT (adr) = staticp (exp); + TREE_SIDE_EFFECTS (adr) = 0; /* Default would be, same as EXP. */ + return adr; + } + /* This way is better for a COMPONENT_REF since it can + simplify the offset for a component. */ + adr = build_unary_op (ADDR_EXPR, exp, 1); + return convert (ptrtype, adr); + } + return exp; +} + +/* Look up component name in the structure type definition. + + If this component name is found indirectly within an anonymous union, + store in *INDIRECT the component which directly contains + that anonymous union. Otherwise, set *INDIRECT to 0. */ + +static tree +lookup_field (type, component, indirect) + tree type, component; + tree *indirect; +{ + tree field; + + /* If TYPE_LANG_SPECIFIC is set, then it is a sorted array of pointers + to the field elements. Use a binary search on this array to quickly + find the element. Otherwise, do a linear search. TYPE_LANG_SPECIFIC + will always be set for structures which have many elements. */ + + if (TYPE_LANG_SPECIFIC (type)) + { + int bot, top, half; + tree *field_array = &TYPE_LANG_SPECIFIC (type)->elts[0]; + + field = TYPE_FIELDS (type); + bot = 0; + top = TYPE_LANG_SPECIFIC (type)->len; + while (top - bot > 1) + { + half = (top - bot + 1) >> 1; + field = field_array[bot+half]; + + if (DECL_NAME (field) == NULL_TREE) + { + /* Step through all anon unions in linear fashion. */ + while (DECL_NAME (field_array[bot]) == NULL_TREE) + { + tree anon = 0, junk; + + field = field_array[bot++]; + if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE) + anon = lookup_field (TREE_TYPE (field), component, &junk); + + if (anon != NULL_TREE) + { + *indirect = field; + return anon; + } + } + + /* Entire record is only anon unions. */ + if (bot > top) + return NULL_TREE; + + /* Restart the binary search, with new lower bound. */ + continue; + } + + if (DECL_NAME (field) == component) + break; + if (DECL_NAME (field) < component) + bot += half; + else + top = bot + half; + } + + if (DECL_NAME (field_array[bot]) == component) + field = field_array[bot]; + else if (DECL_NAME (field) != component) + field = 0; + } + else + { + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + { + if (DECL_NAME (field) == NULL_TREE) + { + tree junk; + tree anon = 0; + + if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE) + anon = lookup_field (TREE_TYPE (field), component, &junk); + + if (anon != NULL_TREE) + { + *indirect = field; + return anon; + } + } + + if (DECL_NAME (field) == component) + break; + } + } + + *indirect = NULL_TREE; + return field; +} + +/* Make an expression to refer to the COMPONENT field of + structure or union value DATUM. COMPONENT is an IDENTIFIER_NODE. */ + +tree +build_component_ref (datum, component) + tree datum, component; +{ + register tree type = TREE_TYPE (datum); + register enum tree_code code = TREE_CODE (type); + register tree field = NULL; + register tree ref; + + /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference inside it + unless we are not to support things not strictly ANSI. */ + switch (TREE_CODE (datum)) + { + case COMPOUND_EXPR: + { + tree value = build_component_ref (TREE_OPERAND (datum, 1), component); + return build (COMPOUND_EXPR, TREE_TYPE (value), + TREE_OPERAND (datum, 0), value); + } + case COND_EXPR: + return build_conditional_expr + (TREE_OPERAND (datum, 0), + build_component_ref (TREE_OPERAND (datum, 1), component), + build_component_ref (TREE_OPERAND (datum, 2), component)); + + default: + break; + } + + /* See if there is a field or component with name COMPONENT. */ + + if (code == RECORD_TYPE || code == UNION_TYPE) + { + tree indirect = 0; + + if (TYPE_SIZE (type) == 0) + { + incomplete_type_error (NULL_TREE, type); + return error_mark_node; + } + + field = lookup_field (type, component, &indirect); + + if (!field) + { + error (code == RECORD_TYPE + ? "structure has no member named `%s'" + : "union has no member named `%s'", + IDENTIFIER_POINTER (component)); + return error_mark_node; + } + if (TREE_TYPE (field) == error_mark_node) + return error_mark_node; + + /* If FIELD was found buried within an anonymous union, + make one COMPONENT_REF to get that anonymous union, + then fall thru to make a second COMPONENT_REF to get FIELD. */ + if (indirect != 0) + { + ref = build (COMPONENT_REF, TREE_TYPE (indirect), datum, indirect); + if (TREE_READONLY (datum) || TREE_READONLY (indirect)) + TREE_READONLY (ref) = 1; + if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (indirect)) + TREE_THIS_VOLATILE (ref) = 1; + datum = ref; + } + + ref = build (COMPONENT_REF, TREE_TYPE (field), datum, field); + + if (TREE_READONLY (datum) || TREE_READONLY (field)) + TREE_READONLY (ref) = 1; + if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (field)) + TREE_THIS_VOLATILE (ref) = 1; + + return ref; + } + else if (code != ERROR_MARK) + error ("request for member `%s' in something not a structure or union", + IDENTIFIER_POINTER (component)); + + return error_mark_node; +} + +/* Given an expression PTR for a pointer, return an expression + for the value pointed to. + ERRORSTRING is the name of the operator to appear in error messages. */ + +tree +build_indirect_ref (ptr, errorstring) + tree ptr; + char *errorstring; +{ + register tree pointer = default_conversion (ptr); + register tree type = TREE_TYPE (pointer); + + if (TREE_CODE (type) == POINTER_TYPE) + { + if (TREE_CODE (pointer) == ADDR_EXPR + && !flag_volatile + && (TREE_TYPE (TREE_OPERAND (pointer, 0)) + == TREE_TYPE (type))) + return TREE_OPERAND (pointer, 0); + else + { + tree t = TREE_TYPE (type); + register tree ref = build1 (INDIRECT_REF, + TYPE_MAIN_VARIANT (t), pointer); + + if (TYPE_SIZE (t) == 0 && TREE_CODE (t) != ARRAY_TYPE) + { + error ("dereferencing pointer to incomplete type"); + return error_mark_node; + } + if (TREE_CODE (t) == VOID_TYPE && skip_evaluation == 0) + warning ("dereferencing `void *' pointer"); + + /* We *must* set TREE_READONLY when dereferencing a pointer to const, + so that we get the proper error message if the result is used + to assign to. Also, &* is supposed to be a no-op. + And ANSI C seems to specify that the type of the result + should be the const type. */ + /* A de-reference of a pointer to const is not a const. It is valid + to change it via some other pointer. */ + TREE_READONLY (ref) = TYPE_READONLY (t); + TREE_SIDE_EFFECTS (ref) + = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer) || flag_volatile; + TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t); + return ref; + } + } + else if (TREE_CODE (pointer) != ERROR_MARK) + error ("invalid type argument of `%s'", errorstring); + return error_mark_node; +} + +/* This handles expressions of the form "a[i]", which denotes + an array reference. + + This is logically equivalent in C to *(a+i), but we may do it differently. + If A is a variable or a member, we generate a primitive ARRAY_REF. + This avoids forcing the array out of registers, and can work on + arrays that are not lvalues (for example, members of structures returned + by functions). */ + +tree +build_array_ref (array, index) + tree array, index; +{ + if (index == 0) + { + error ("subscript missing in array reference"); + return error_mark_node; + } + + if (TREE_TYPE (array) == error_mark_node + || TREE_TYPE (index) == error_mark_node) + return error_mark_node; + + if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE + && TREE_CODE (array) != INDIRECT_REF) + { + tree rval, type; + + /* 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. */ + if (warn_char_subscripts + && TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node) + warning ("array subscript has type `char'"); + + /* Apply default promotions *after* noticing character types. */ + index = default_conversion (index); + + /* Require integer *after* promotion, for sake of enums. */ + if (TREE_CODE (TREE_TYPE (index)) != INTEGER_TYPE) + { + error ("array subscript is not an integer"); + return error_mark_node; + } + + /* An array that is indexed by a non-constant + cannot be stored in a register; we must be able to do + address arithmetic on its address. + Likewise an array of elements of variable size. */ + if (TREE_CODE (index) != INTEGER_CST + || (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array))) != 0 + && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array)))) != INTEGER_CST)) + { + if (mark_addressable (array) == 0) + return error_mark_node; + } + /* An array that is indexed by a constant value which is not within + the array bounds cannot be stored in a register either; because we + would get a crash in store_bit_field/extract_bit_field when trying + to access a non-existent part of the register. */ + if (TREE_CODE (index) == INTEGER_CST + && TYPE_VALUES (TREE_TYPE (array)) + && ! int_fits_type_p (index, TYPE_VALUES (TREE_TYPE (array)))) + { + if (mark_addressable (array) == 0) + return error_mark_node; + } + + if (pedantic && !lvalue_p (array)) + { + if (DECL_REGISTER (array)) + pedwarn ("ANSI C forbids subscripting `register' array"); + else + pedwarn ("ANSI C forbids subscripting non-lvalue array"); + } + + if (pedantic) + { + tree foo = array; + while (TREE_CODE (foo) == COMPONENT_REF) + foo = TREE_OPERAND (foo, 0); + if (TREE_CODE (foo) == VAR_DECL && DECL_REGISTER (foo)) + pedwarn ("ANSI C forbids subscripting non-lvalue array"); + } + + type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array))); + rval = build (ARRAY_REF, type, array, index); + /* Array ref is const/volatile if the array elements are + or if the array is. */ + TREE_READONLY (rval) + |= (TYPE_READONLY (TREE_TYPE (TREE_TYPE (array))) + | TREE_READONLY (array)); + TREE_SIDE_EFFECTS (rval) + |= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (array))) + | TREE_SIDE_EFFECTS (array)); + TREE_THIS_VOLATILE (rval) + |= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (array))) + /* This was added by rms on 16 Nov 91. + It fixes vol struct foo *a; a->elts[1] + in an inline function. + Hope it doesn't break something else. */ + | TREE_THIS_VOLATILE (array)); + return require_complete_type (fold (rval)); + } + + { + tree ar = default_conversion (array); + tree ind = default_conversion (index); + + /* Do the same warning check as above, but only on the part that's + syntactically the index and only if it is also semantically + the index. */ + if (warn_char_subscripts + && TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE + && TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node) + warning ("subscript has type `char'"); + + /* Put the integer in IND to simplify error checking. */ + if (TREE_CODE (TREE_TYPE (ar)) == INTEGER_TYPE) + { + tree temp = ar; + ar = ind; + ind = temp; + } + + if (ar == error_mark_node) + return ar; + + if (TREE_CODE (TREE_TYPE (ar)) != POINTER_TYPE + || TREE_CODE (TREE_TYPE (TREE_TYPE (ar))) == FUNCTION_TYPE) + { + error ("subscripted value is neither array nor pointer"); + return error_mark_node; + } + if (TREE_CODE (TREE_TYPE (ind)) != INTEGER_TYPE) + { + error ("array subscript is not an integer"); + return error_mark_node; + } + + return build_indirect_ref (build_binary_op (PLUS_EXPR, ar, ind, 0), + "array indexing"); + } +} + +/* Build a function call to function FUNCTION with parameters PARAMS. + PARAMS is a list--a chain of TREE_LIST nodes--in which the + TREE_VALUE of each node is a parameter-expression. + FUNCTION's data type may be a function type or a pointer-to-function. */ + +tree +build_function_call (function, params) + tree function, params; +{ + register tree fntype, fundecl = 0; + register tree coerced_params; + tree name = NULL_TREE, assembler_name = NULL_TREE; + + /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */ + STRIP_TYPE_NOPS (function); + + /* Convert anything with function type to a pointer-to-function. */ + if (TREE_CODE (function) == FUNCTION_DECL) + { + name = DECL_NAME (function); + assembler_name = DECL_ASSEMBLER_NAME (function); + + /* Differs from default_conversion by not setting TREE_ADDRESSABLE + (because calling an inline function does not mean the function + needs to be separately compiled). */ + fntype = build_type_variant (TREE_TYPE (function), + TREE_READONLY (function), + TREE_THIS_VOLATILE (function)); + fundecl = function; + function = build1 (ADDR_EXPR, build_pointer_type (fntype), function); + } + else + function = default_conversion (function); + + fntype = TREE_TYPE (function); + + if (TREE_CODE (fntype) == ERROR_MARK) + return error_mark_node; + + if (!(TREE_CODE (fntype) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE)) + { + error ("called object is not a function"); + return error_mark_node; + } + + /* fntype now gets the type of function pointed to. */ + fntype = TREE_TYPE (fntype); + + /* Convert the parameters to the types declared in the + function prototype, or apply default promotions. */ + + coerced_params + = convert_arguments (TYPE_ARG_TYPES (fntype), params, name, fundecl); + + /* Check for errors in format strings. */ + + if (warn_format && (name || assembler_name)) + check_function_format (name, assembler_name, coerced_params); + + /* 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. */ + + if (TREE_CODE (function) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL + && DECL_BUILT_IN (TREE_OPERAND (function, 0))) + switch (DECL_FUNCTION_CODE (TREE_OPERAND (function, 0))) + { + case BUILT_IN_ABS: + case BUILT_IN_LABS: + case BUILT_IN_FABS: + if (coerced_params == 0) + return integer_zero_node; + return build_unary_op (ABS_EXPR, TREE_VALUE (coerced_params), 0); + default: + break; + } + + { + register tree result + = build (CALL_EXPR, TREE_TYPE (fntype), + function, coerced_params, NULL_TREE); + + TREE_SIDE_EFFECTS (result) = 1; + if (TREE_TYPE (result) == void_type_node) + return result; + return require_complete_type (result); + } +} + +/* Convert the argument expressions in the list VALUES + to the types in the list TYPELIST. The result is a list of converted + argument expressions. + + If TYPELIST is exhausted, or when an element has NULL as its type, + perform the default conversions. + + PARMLIST is the chain of parm decls for the function being called. + It may be 0, if that info is not available. + It is used only for generating error messages. + + NAME is an IDENTIFIER_NODE or 0. It is used only for error messages. + + This is also where warnings about wrong number of args are generated. + + Both VALUES and the returned value are chains of TREE_LIST nodes + with the elements of the list in the TREE_VALUE slots of those nodes. */ + +static tree +convert_arguments (typelist, values, name, fundecl) + tree typelist, values, name, fundecl; +{ + register tree typetail, valtail; + register tree result = NULL; + int parmnum; + + /* Scan the given expressions and types, producing individual + converted arguments and pushing them on RESULT in reverse order. */ + + for (valtail = values, typetail = typelist, parmnum = 0; + valtail; + valtail = TREE_CHAIN (valtail), parmnum++) + { + register tree type = typetail ? TREE_VALUE (typetail) : 0; + register tree val = TREE_VALUE (valtail); + + if (type == void_type_node) + { + if (name) + error ("too many arguments to function `%s'", + IDENTIFIER_POINTER (name)); + else + error ("too many arguments to function"); + break; + } + + /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ + /* Do not use STRIP_NOPS here! We do not want an enumerator with value 0 + to convert automatically to a pointer. */ + if (TREE_CODE (val) == NON_LVALUE_EXPR) + val = TREE_OPERAND (val, 0); + + if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE) + val = default_conversion (val); + + val = require_complete_type (val); + + if (type != 0) + { + /* Formal parm type is specified by a function prototype. */ + tree parmval; + + if (TYPE_SIZE (type) == 0) + { + error ("type of formal parameter %d is incomplete", parmnum + 1); + parmval = val; + } + else + { + /* Optionally warn about conversions that + differ from the default conversions. */ + if (warn_conversion) + { + int formal_prec = TYPE_PRECISION (type); + + if (INTEGRAL_TYPE_P (type) + && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE) + warn_for_assignment ("%s as integer rather than floating due to prototype", (char *) 0, name, parmnum + 1); + else if (TREE_CODE (type) == COMPLEX_TYPE + && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE) + warn_for_assignment ("%s as complex rather than floating due to prototype", (char *) 0, name, parmnum + 1); + else if (TREE_CODE (type) == REAL_TYPE + && INTEGRAL_TYPE_P (TREE_TYPE (val))) + warn_for_assignment ("%s as floating rather than integer due to prototype", (char *) 0, name, parmnum + 1); + else if (TREE_CODE (type) == REAL_TYPE + && TREE_CODE (TREE_TYPE (val)) == COMPLEX_TYPE) + warn_for_assignment ("%s as floating rather than complex due to prototype", (char *) 0, name, parmnum + 1); + /* ??? At some point, messages should be written about + conversions between complex types, but that's too messy + to do now. */ + else if (TREE_CODE (type) == REAL_TYPE + && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE) + { + /* Warn if any argument is passed as `float', + since without a prototype it would be `double'. */ + if (formal_prec == TYPE_PRECISION (float_type_node)) + warn_for_assignment ("%s as `float' rather than `double' due to prototype", (char *) 0, name, parmnum + 1); + } + /* Detect integer changing in width or signedness. */ + else if (INTEGRAL_TYPE_P (type) + && INTEGRAL_TYPE_P (TREE_TYPE (val))) + { + tree would_have_been = default_conversion (val); + tree type1 = TREE_TYPE (would_have_been); + + if (TREE_CODE (type) == ENUMERAL_TYPE + && type == TREE_TYPE (val)) + /* No warning if function asks for enum + and the actual arg is that enum type. */ + ; + else if (formal_prec != TYPE_PRECISION (type1)) + warn_for_assignment ("%s with different width due to prototype", (char *) 0, name, parmnum + 1); + else if (TREE_UNSIGNED (type) == TREE_UNSIGNED (type1)) + ; + /* Don't complain if the formal parameter type + is an enum, because we can't tell now whether + the value was an enum--even the same enum. */ + else if (TREE_CODE (type) == ENUMERAL_TYPE) + ; + else if (TREE_CODE (val) == INTEGER_CST + && int_fits_type_p (val, type)) + /* Change in signedness doesn't matter + if a constant value is unaffected. */ + ; + /* Likewise for a constant in a NOP_EXPR. */ + else if (TREE_CODE (val) == NOP_EXPR + && TREE_CODE (TREE_OPERAND (val, 0)) == INTEGER_CST + && int_fits_type_p (TREE_OPERAND (val, 0), type)) + ; +#if 0 /* We never get such tree structure here. */ + else if (TREE_CODE (TREE_TYPE (val)) == ENUMERAL_TYPE + && int_fits_type_p (TYPE_MIN_VALUE (TREE_TYPE (val)), type) + && int_fits_type_p (TYPE_MAX_VALUE (TREE_TYPE (val)), type)) + /* Change in signedness doesn't matter + if an enum value is unaffected. */ + ; +#endif + /* If the value is extended from a narrower + unsigned type, it doesn't matter whether we + pass it as signed or unsigned; the value + certainly is the same either way. */ + else if (TYPE_PRECISION (TREE_TYPE (val)) < TYPE_PRECISION (type) + && TREE_UNSIGNED (TREE_TYPE (val))) + ; + else if (TREE_UNSIGNED (type)) + warn_for_assignment ("%s as unsigned due to prototype", (char *) 0, name, parmnum + 1); + else + warn_for_assignment ("%s as signed due to prototype", (char *) 0, name, parmnum + 1); + } + } + + parmval = convert_for_assignment (type, val, + (char *) 0, /* arg passing */ + fundecl, name, parmnum + 1); + +#ifdef PROMOTE_PROTOTYPES + if ((TREE_CODE (type) == INTEGER_TYPE + || TREE_CODE (type) == ENUMERAL_TYPE) + && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))) + parmval = default_conversion (parmval); +#endif + } + result = tree_cons (NULL_TREE, parmval, result); + } + else if (TREE_CODE (TREE_TYPE (val)) == REAL_TYPE + && (TYPE_PRECISION (TREE_TYPE (val)) + < TYPE_PRECISION (double_type_node))) + /* Convert `float' to `double'. */ + result = tree_cons (NULL_TREE, convert (double_type_node, val), result); + else + /* Convert `short' and `char' to full-size `int'. */ + result = tree_cons (NULL_TREE, default_conversion (val), result); + + if (typetail) + typetail = TREE_CHAIN (typetail); + } + + if (typetail != 0 && TREE_VALUE (typetail) != void_type_node) + { + if (name) + error ("too few arguments to function `%s'", + IDENTIFIER_POINTER (name)); + else + error ("too few arguments to function"); + } + + return nreverse (result); +} + +/* This is the entry point used by the parser + for binary operators in the input. + In addition to constructing the expression, + we check for operands that were written with other binary operators + in a way that is likely to confuse the user. */ + +tree +parser_build_binary_op (code, arg1, arg2) + enum tree_code code; + tree arg1, arg2; +{ + tree result = build_binary_op (code, arg1, arg2, 1); + + char class; + char class1 = TREE_CODE_CLASS (TREE_CODE (arg1)); + char class2 = TREE_CODE_CLASS (TREE_CODE (arg2)); + enum tree_code code1 = ERROR_MARK; + enum tree_code code2 = ERROR_MARK; + + if (class1 == 'e' || class1 == '1' + || class1 == '2' || class1 == '<') + code1 = C_EXP_ORIGINAL_CODE (arg1); + if (class2 == 'e' || class2 == '1' + || class2 == '2' || class2 == '<') + code2 = C_EXP_ORIGINAL_CODE (arg2); + + /* Check for cases such as x+y< TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op1, 0))) + && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op1, 0)))) + { + final_type = result_type; + op1 = TREE_OPERAND (op1, 0); + result_type = TREE_TYPE (op1); + } + if (TREE_CODE (op1) == INTEGER_CST + && TREE_CODE (op0) == NOP_EXPR + && TYPE_PRECISION (type0) > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op0, 0))) + && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op0, 0)))) + { + final_type = result_type; + op0 = TREE_OPERAND (op0, 0); + result_type = TREE_TYPE (op0); + } + break; + + case TRUNC_MOD_EXPR: + case FLOOR_MOD_EXPR: + if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + { + /* Although it would be tempting to shorten always here, that loses + on some targets, since the modulo instruction is undefined if the + quotient can't be represented in the computation mode. We shorten + only if unsigned or if dividing by something we know != -1. */ + shorten = (TREE_UNSIGNED (TREE_TYPE (orig_op0)) + || (TREE_CODE (op1) == INTEGER_CST + && (TREE_INT_CST_LOW (op1) != -1 + || TREE_INT_CST_HIGH (op1) != -1))); + common = 1; + } + break; + + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_XOR_EXPR: + if ((code0 == INTEGER_TYPE || code0 == POINTER_TYPE + || code0 == REAL_TYPE || code0 == COMPLEX_TYPE) + && (code1 == INTEGER_TYPE || code1 == POINTER_TYPE + || code1 == REAL_TYPE || code1 == COMPLEX_TYPE)) + { + /* Result of these operations is always an int, + but that does not mean the operands should be + converted to ints! */ + result_type = integer_type_node; + op0 = truthvalue_conversion (op0); + op1 = truthvalue_conversion (op1); + converted = 1; + } + break; + + /* Shift operations: result has same type as first operand; + always convert second operand to int. + Also set SHORT_SHIFT if shifting rightward. */ + + case RSHIFT_EXPR: + if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + { + if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0) + { + if (tree_int_cst_sgn (op1) < 0) + warning ("right shift count is negative"); + else + { + if (TREE_INT_CST_LOW (op1) | TREE_INT_CST_HIGH (op1)) + short_shift = 1; + if (TREE_INT_CST_HIGH (op1) != 0 + || ((unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (op1) + >= TYPE_PRECISION (type0))) + warning ("right shift count >= width of type"); + } + } + /* Use the type of the value to be shifted. + This is what most traditional C compilers do. */ + result_type = type0; + /* Unless traditional, convert the shift-count to an integer, + regardless of size of value being shifted. */ + if (! flag_traditional) + { + if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node) + op1 = convert (integer_type_node, op1); + /* Avoid converting op1 to result_type later. */ + converted = 1; + } + } + break; + + case LSHIFT_EXPR: + if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + { + if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0) + { + if (tree_int_cst_sgn (op1) < 0) + warning ("left shift count is negative"); + else if (TREE_INT_CST_HIGH (op1) != 0 + || ((unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (op1) + >= TYPE_PRECISION (type0))) + warning ("left shift count >= width of type"); + } + /* Use the type of the value to be shifted. + This is what most traditional C compilers do. */ + result_type = type0; + /* Unless traditional, convert the shift-count to an integer, + regardless of size of value being shifted. */ + if (! flag_traditional) + { + if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node) + op1 = convert (integer_type_node, op1); + /* Avoid converting op1 to result_type later. */ + converted = 1; + } + } + break; + + case RROTATE_EXPR: + case LROTATE_EXPR: + if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + { + if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0) + { + if (tree_int_cst_sgn (op1) < 0) + warning ("shift count is negative"); + else if (TREE_INT_CST_HIGH (op1) != 0 + || ((unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (op1) + >= TYPE_PRECISION (type0))) + warning ("shift count >= width of type"); + } + /* Use the type of the value to be shifted. + This is what most traditional C compilers do. */ + result_type = type0; + /* Unless traditional, convert the shift-count to an integer, + regardless of size of value being shifted. */ + if (! flag_traditional) + { + if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node) + op1 = convert (integer_type_node, op1); + /* Avoid converting op1 to result_type later. */ + converted = 1; + } + } + break; + + case EQ_EXPR: + case NE_EXPR: + /* Result of comparison is always int, + but don't convert the args to int! */ + build_type = integer_type_node; + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE + || code0 == COMPLEX_TYPE) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE + || code1 == COMPLEX_TYPE)) + short_compare = 1; + else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) + { + register tree tt0 = TREE_TYPE (type0); + register tree tt1 = TREE_TYPE (type1); + /* Anything compares with void *. void * compares with anything. + Otherwise, the targets must be compatible + and both must be object or both incomplete. */ + if (comp_target_types (type0, type1)) + result_type = common_type (type0, type1); + else if (TYPE_MAIN_VARIANT (tt0) == void_type_node) + { + /* op0 != orig_op0 detects the case of something + whose value is 0 but which isn't a valid null ptr const. */ + if (pedantic && (!integer_zerop (op0) || op0 != orig_op0) + && TREE_CODE (tt1) == FUNCTION_TYPE) + pedwarn ("ANSI C forbids comparison of `void *' with function pointer"); + } + else if (TYPE_MAIN_VARIANT (tt1) == void_type_node) + { + if (pedantic && (!integer_zerop (op1) || op1 != orig_op1) + && TREE_CODE (tt0) == FUNCTION_TYPE) + pedwarn ("ANSI C forbids comparison of `void *' with function pointer"); + } + else + pedwarn ("comparison of distinct pointer types lacks a cast"); + + if (result_type == NULL_TREE) + result_type = ptr_type_node; + } + else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST + && integer_zerop (op1)) + result_type = type0; + else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST + && integer_zerop (op0)) + result_type = type1; + else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + result_type = type0; + if (! flag_traditional) + pedwarn ("comparison between pointer and integer"); + } + else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE) + { + result_type = type1; + if (! flag_traditional) + pedwarn ("comparison between pointer and integer"); + } + break; + + case MAX_EXPR: + case MIN_EXPR: + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE)) + shorten = 1; + else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) + { + if (comp_target_types (type0, type1)) + { + result_type = common_type (type0, type1); + if (pedantic + && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE) + pedwarn ("ANSI C forbids ordered comparisons of pointers to functions"); + } + else + { + result_type = ptr_type_node; + pedwarn ("comparison of distinct pointer types lacks a cast"); + } + } + break; + + case LE_EXPR: + case GE_EXPR: + case LT_EXPR: + case GT_EXPR: + build_type = integer_type_node; + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE)) + short_compare = 1; + else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) + { + if (comp_target_types (type0, type1)) + { + result_type = common_type (type0, type1); + if ((TYPE_SIZE (TREE_TYPE (type0)) != 0) + != (TYPE_SIZE (TREE_TYPE (type1)) != 0)) + pedwarn ("comparison of complete and incomplete pointers"); + else if (pedantic + && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE) + pedwarn ("ANSI C forbids ordered comparisons of pointers to functions"); + } + else + { + result_type = ptr_type_node; + pedwarn ("comparison of distinct pointer types lacks a cast"); + } + } + else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST + && integer_zerop (op1)) + { + result_type = type0; + if (pedantic || extra_warnings) + pedwarn ("ordered comparison of pointer with integer zero"); + } + else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST + && integer_zerop (op0)) + { + result_type = type1; + if (pedantic) + pedwarn ("ordered comparison of pointer with integer zero"); + } + else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + result_type = type0; + if (! flag_traditional) + pedwarn ("comparison between pointer and integer"); + } + else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE) + { + result_type = type1; + if (! flag_traditional) + pedwarn ("comparison between pointer and integer"); + } + break; + + default: + break; + } + + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE) + && + (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE)) + { + int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE); + + if (shorten || common || short_compare) + result_type = common_type (type0, type1); + + /* For certain operations (which identify themselves by shorten != 0) + if both args were extended from the same smaller type, + do the arithmetic in that type and then extend. + + shorten !=0 and !=1 indicates a bitwise operation. + For them, this optimization is safe only if + both args are zero-extended or both are sign-extended. + Otherwise, we might change the result. + Eg, (short)-1 | (unsigned short)-1 is (int)-1 + but calculated in (unsigned short) it would be (unsigned short)-1. */ + + if (shorten && none_complex) + { + int unsigned0, unsigned1; + tree arg0 = get_narrower (op0, &unsigned0); + tree arg1 = get_narrower (op1, &unsigned1); + /* UNS is 1 if the operation to be done is an unsigned one. */ + int uns = TREE_UNSIGNED (result_type); + tree type; + + final_type = result_type; + + /* Handle the case that OP0 (or OP1) does not *contain* a conversion + but it *requires* conversion to FINAL_TYPE. */ + + if ((TYPE_PRECISION (TREE_TYPE (op0)) + == TYPE_PRECISION (TREE_TYPE (arg0))) + && TREE_TYPE (op0) != final_type) + unsigned0 = TREE_UNSIGNED (TREE_TYPE (op0)); + if ((TYPE_PRECISION (TREE_TYPE (op1)) + == TYPE_PRECISION (TREE_TYPE (arg1))) + && TREE_TYPE (op1) != final_type) + unsigned1 = TREE_UNSIGNED (TREE_TYPE (op1)); + + /* Now UNSIGNED0 is 1 if ARG0 zero-extends to FINAL_TYPE. */ + + /* For bitwise operations, signedness of nominal type + does not matter. Consider only how operands were extended. */ + if (shorten == -1) + uns = unsigned0; + + /* Note that in all three cases below we refrain from optimizing + an unsigned operation on sign-extended args. + That would not be valid. */ + + /* Both args variable: if both extended in same way + from same width, do it in that width. + Do it unsigned if args were zero-extended. */ + if ((TYPE_PRECISION (TREE_TYPE (arg0)) + < TYPE_PRECISION (result_type)) + && (TYPE_PRECISION (TREE_TYPE (arg1)) + == TYPE_PRECISION (TREE_TYPE (arg0))) + && unsigned0 == unsigned1 + && (unsigned0 || !uns)) + result_type + = signed_or_unsigned_type (unsigned0, + common_type (TREE_TYPE (arg0), TREE_TYPE (arg1))); + else if (TREE_CODE (arg0) == INTEGER_CST + && (unsigned1 || !uns) + && (TYPE_PRECISION (TREE_TYPE (arg1)) + < TYPE_PRECISION (result_type)) + && (type = signed_or_unsigned_type (unsigned1, + TREE_TYPE (arg1)), + int_fits_type_p (arg0, type))) + result_type = type; + else if (TREE_CODE (arg1) == INTEGER_CST + && (unsigned0 || !uns) + && (TYPE_PRECISION (TREE_TYPE (arg0)) + < TYPE_PRECISION (result_type)) + && (type = signed_or_unsigned_type (unsigned0, + TREE_TYPE (arg0)), + int_fits_type_p (arg1, type))) + result_type = type; + } + + /* Shifts can be shortened if shifting right. */ + + if (short_shift) + { + int unsigned_arg; + tree arg0 = get_narrower (op0, &unsigned_arg); + + final_type = result_type; + + if (arg0 == op0 && final_type == TREE_TYPE (op0)) + unsigned_arg = TREE_UNSIGNED (TREE_TYPE (op0)); + + if (TYPE_PRECISION (TREE_TYPE (arg0)) < TYPE_PRECISION (result_type) + /* We can shorten only if the shift count is less than the + number of bits in the smaller type size. */ + && TREE_INT_CST_HIGH (op1) == 0 + && TYPE_PRECISION (TREE_TYPE (arg0)) > TREE_INT_CST_LOW (op1) + /* If arg is sign-extended and then unsigned-shifted, + we can simulate this with a signed shift in arg's type + only if the extended result is at least twice as wide + as the arg. Otherwise, the shift could use up all the + ones made by sign-extension and bring in zeros. + We can't optimize that case at all, but in most machines + it never happens because available widths are 2**N. */ + && (!TREE_UNSIGNED (final_type) + || unsigned_arg + || 2 * TYPE_PRECISION (TREE_TYPE (arg0)) <= TYPE_PRECISION (result_type))) + { + /* Do an unsigned shift if the operand was zero-extended. */ + result_type + = signed_or_unsigned_type (unsigned_arg, + TREE_TYPE (arg0)); + /* Convert value-to-be-shifted to that type. */ + if (TREE_TYPE (op0) != result_type) + op0 = convert (result_type, op0); + converted = 1; + } + } + + /* Comparison operations are shortened too but differently. + They identify themselves by setting short_compare = 1. */ + + if (short_compare) + { + /* Don't write &op0, etc., because that would prevent op0 + from being kept in a register. + Instead, make copies of the our local variables and + pass the copies by reference, then copy them back afterward. */ + tree xop0 = op0, xop1 = op1, xresult_type = result_type; + enum tree_code xresultcode = resultcode; + tree val + = shorten_compare (&xop0, &xop1, &xresult_type, &xresultcode); + if (val != 0) + return val; + op0 = xop0, op1 = xop1; + converted = 1; + resultcode = xresultcode; + + if ((warn_sign_compare < 0 ? extra_warnings : warn_sign_compare != 0) + && skip_evaluation == 0) + { + int op0_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op0)); + int op1_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op1)); + + int unsignedp0, unsignedp1; + tree primop0 = get_narrower (op0, &unsignedp0); + tree primop1 = get_narrower (op1, &unsignedp1); + + /* Avoid spurious warnings for comparison with enumerators. */ + + xop0 = orig_op0; + xop1 = orig_op1; + STRIP_TYPE_NOPS (xop0); + STRIP_TYPE_NOPS (xop1); + + /* Give warnings for comparisons between signed and unsigned + quantities that may fail. */ + /* Do the checking based on the original operand trees, so that + casts will be considered, but default promotions won't be. */ + + /* Do not warn if the comparison is being done in a signed type, + since the signed type will only be chosen if it can represent + all the values of the unsigned type. */ + if (! TREE_UNSIGNED (result_type)) + /* OK */; + /* Do not warn if both operands are unsigned. */ + else if (op0_signed == op1_signed) + /* OK */; + /* Do not warn if the signed quantity is an unsuffixed + integer literal (or some static constant expression + involving such literals) and it is non-negative. */ + else if ((op0_signed && TREE_CODE (xop0) == INTEGER_CST + && tree_int_cst_sgn (xop0) >= 0) + || (op1_signed && TREE_CODE (xop1) == INTEGER_CST + && tree_int_cst_sgn (xop1) >= 0)) + /* OK */; + /* Do not warn if the comparison is an equality operation, + the unsigned quantity is an integral constant and it does + not use the most significant bit of result_type. */ + else if ((resultcode == EQ_EXPR || resultcode == NE_EXPR) + && ((op0_signed && TREE_CODE (xop1) == INTEGER_CST + && int_fits_type_p (xop1, signed_type (result_type))) + || (op1_signed && TREE_CODE (xop0) == INTEGER_CST + && int_fits_type_p (xop0, signed_type (result_type))))) + /* OK */; + else + warning ("comparison between signed and unsigned"); + + /* Warn if two unsigned values are being compared in a size + larger than their original size, and one (and only one) is the + result of a `~' operator. This comparison will always fail. + + Also warn if one operand is a constant, and the constant + does not have all bits set that are set in the ~ operand + when it is extended. */ + + if ((TREE_CODE (primop0) == BIT_NOT_EXPR) + != (TREE_CODE (primop1) == BIT_NOT_EXPR)) + { + if (TREE_CODE (primop0) == BIT_NOT_EXPR) + primop0 = get_narrower (TREE_OPERAND (primop0, 0), + &unsignedp0); + else + primop1 = get_narrower (TREE_OPERAND (primop1, 0), + &unsignedp1); + + if (TREE_CODE (primop0) == INTEGER_CST + || TREE_CODE (primop1) == INTEGER_CST) + { + tree primop; + long constant, mask; + int unsignedp, bits; + + if (TREE_CODE (primop0) == INTEGER_CST) + { + primop = primop1; + unsignedp = unsignedp1; + constant = TREE_INT_CST_LOW (primop0); + } + else + { + primop = primop0; + unsignedp = unsignedp0; + constant = TREE_INT_CST_LOW (primop1); + } + + bits = TYPE_PRECISION (TREE_TYPE (primop)); + if (bits < TYPE_PRECISION (result_type) + && bits < HOST_BITS_PER_LONG && unsignedp) + { + mask = (~0L) << bits; + if ((mask & constant) != mask) + warning ("comparison of promoted ~unsigned with constant"); + } + } + else if (unsignedp0 && unsignedp1 + && (TYPE_PRECISION (TREE_TYPE (primop0)) + < TYPE_PRECISION (result_type)) + && (TYPE_PRECISION (TREE_TYPE (primop1)) + < TYPE_PRECISION (result_type))) + warning ("comparison of promoted ~unsigned with unsigned"); + } + } + } + } + + /* At this point, RESULT_TYPE must be nonzero to avoid an error message. + If CONVERTED is zero, both args will be converted to type RESULT_TYPE. + Then the expression will be built. + It will be given type FINAL_TYPE if that is nonzero; + otherwise, it will be given type RESULT_TYPE. */ + + if (!result_type) + { + binary_op_error (code); + return error_mark_node; + } + + if (! converted) + { + if (TREE_TYPE (op0) != result_type) + op0 = convert (result_type, op0); + if (TREE_TYPE (op1) != result_type) + op1 = convert (result_type, op1); + } + + if (build_type == NULL_TREE) + build_type = result_type; + + { + register tree result = build (resultcode, build_type, op0, op1); + register tree folded; + + folded = fold (result); + if (folded == result) + TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1); + if (final_type != 0) + return convert (final_type, folded); + return folded; + } +} + +/* Return a tree for the sum or difference (RESULTCODE says which) + of pointer PTROP and integer INTOP. */ + +static tree +pointer_int_sum (resultcode, ptrop, intop) + enum tree_code resultcode; + register tree ptrop, intop; +{ + tree size_exp; + + register tree result; + register tree folded; + + /* The result is a pointer of the same type that is being added. */ + + register tree result_type = TREE_TYPE (ptrop); + + if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE) + { + if (pedantic || warn_pointer_arith) + pedwarn ("pointer of type `void *' used in arithmetic"); + size_exp = integer_one_node; + } + else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE) + { + if (pedantic || warn_pointer_arith) + pedwarn ("pointer to a function used in arithmetic"); + size_exp = integer_one_node; + } + else + size_exp = c_size_in_bytes (TREE_TYPE (result_type)); + + /* 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 (TREE_OPERAND (intop, 1)) + && TREE_CONSTANT (size_exp) + /* If the constant comes from pointer subtraction, + skip this optimization--it would cause an error. */ + && TREE_CODE (TREE_TYPE (TREE_OPERAND (intop, 0))) == INTEGER_TYPE + /* 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. */ + && (! TREE_UNSIGNED (TREE_TYPE (intop)) + || (TYPE_PRECISION (TREE_TYPE (intop)) + == TYPE_PRECISION (TREE_TYPE (ptrop))))) + { + enum tree_code subcode = resultcode; + tree int_type = TREE_TYPE (intop); + if (TREE_CODE (intop) == MINUS_EXPR) + subcode = (subcode == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR); + /* Convert both subexpression types to the type of intop, + because weird cases involving pointer arithmetic + can result in a sum or difference with different type args. */ + ptrop = build_binary_op (subcode, ptrop, + convert (int_type, TREE_OPERAND (intop, 1)), 1); + intop = convert (int_type, TREE_OPERAND (intop, 0)); + } + + /* Convert the integer argument to a type the same size as sizetype + so the multiply won't overflow spuriously. */ + + if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype) + || TREE_UNSIGNED (TREE_TYPE (intop)) != TREE_UNSIGNED (sizetype)) + intop = convert (type_for_size (TYPE_PRECISION (sizetype), + 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 + pointer type (actually unsigned integral). */ + + intop = convert (result_type, + build_binary_op (MULT_EXPR, intop, + convert (TREE_TYPE (intop), size_exp), 1)); + + /* Create the sum or difference. */ + + result = build (resultcode, result_type, ptrop, intop); + + folded = fold (result); + if (folded == result) + TREE_CONSTANT (folded) = TREE_CONSTANT (ptrop) & TREE_CONSTANT (intop); + return folded; +} + +/* Return a tree for the difference of pointers OP0 and OP1. + The resulting tree has type int. */ + +static tree +pointer_diff (op0, op1) + register tree op0, op1; +{ + register tree result, folded; + tree restype = ptrdiff_type_node; + + tree target_type = TREE_TYPE (TREE_TYPE (op0)); + + if (pedantic || warn_pointer_arith) + { + if (TREE_CODE (target_type) == VOID_TYPE) + pedwarn ("pointer of type `void *' used in subtraction"); + if (TREE_CODE (target_type) == FUNCTION_TYPE) + pedwarn ("pointer to a function used in subtraction"); + } + + /* First do the subtraction as integers; + then drop through to build the divide operator. + Do not do default conversions on the minus operator + in case restype is a short type. */ + + op0 = build_binary_op (MINUS_EXPR, convert (restype, op0), + convert (restype, op1), 0); + /* This generates an error if op1 is pointer to incomplete type. */ + if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (op1))) == 0) + error ("arithmetic on pointer to an incomplete type"); + + /* This generates an error if op0 is pointer to incomplete type. */ + op1 = c_size_in_bytes (target_type); + + /* Divide by the size, in easiest possible way. */ + + result = build (EXACT_DIV_EXPR, restype, op0, convert (restype, op1)); + + folded = fold (result); + if (folded == result) + TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1); + return folded; +} + +/* Construct and perhaps optimize a tree representation + for a unary operation. CODE, a tree_code, specifies the operation + and XARG is the operand. NOCONVERT nonzero suppresses + the default promotions (such as from short to int). */ + +tree +build_unary_op (code, xarg, noconvert) + enum tree_code code; + tree xarg; + int noconvert; +{ + /* No default_conversion here. It causes trouble for ADDR_EXPR. */ + register tree arg = xarg; + register tree argtype = 0; + register enum tree_code typecode = TREE_CODE (TREE_TYPE (arg)); + char *errstring = NULL; + tree val; + + if (typecode == ERROR_MARK) + return error_mark_node; + if (typecode == ENUMERAL_TYPE) + typecode = INTEGER_TYPE; + + switch (code) + { + case CONVERT_EXPR: + /* This is used for unary plus, because a CONVERT_EXPR + is enough to prevent anybody from looking inside for + associativity, but won't generate any code. */ + if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE + || typecode == COMPLEX_TYPE)) + errstring = "wrong type argument to unary plus"; + else if (!noconvert) + arg = default_conversion (arg); + break; + + case NEGATE_EXPR: + if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE + || typecode == COMPLEX_TYPE)) + errstring = "wrong type argument to unary minus"; + else if (!noconvert) + arg = default_conversion (arg); + break; + + case BIT_NOT_EXPR: + if (typecode == COMPLEX_TYPE) + { + code = CONJ_EXPR; + if (!noconvert) + arg = default_conversion (arg); + } + else if (typecode != INTEGER_TYPE) + errstring = "wrong type argument to bit-complement"; + else if (!noconvert) + arg = default_conversion (arg); + break; + + case ABS_EXPR: + if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE + || typecode == COMPLEX_TYPE)) + errstring = "wrong type argument to abs"; + else if (!noconvert) + arg = default_conversion (arg); + break; + + case CONJ_EXPR: + /* Conjugating a real value is a no-op, but allow it anyway. */ + if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE + || typecode == COMPLEX_TYPE)) + errstring = "wrong type argument to conjugation"; + else if (!noconvert) + arg = default_conversion (arg); + break; + + case TRUTH_NOT_EXPR: + if (typecode != INTEGER_TYPE + && typecode != REAL_TYPE && typecode != POINTER_TYPE + && typecode != COMPLEX_TYPE + /* These will convert to a pointer. */ + && typecode != ARRAY_TYPE && typecode != FUNCTION_TYPE) + { + errstring = "wrong type argument to unary exclamation mark"; + break; + } + arg = truthvalue_conversion (arg); + return invert_truthvalue (arg); + + case NOP_EXPR: + break; + + case REALPART_EXPR: + if (TREE_CODE (arg) == COMPLEX_CST) + return TREE_REALPART (arg); + else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE) + return fold (build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg)); + else + return arg; + + case IMAGPART_EXPR: + if (TREE_CODE (arg) == COMPLEX_CST) + return TREE_IMAGPART (arg); + else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE) + return fold (build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg)); + else + return convert (TREE_TYPE (arg), integer_zero_node); + + case PREINCREMENT_EXPR: + case POSTINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case POSTDECREMENT_EXPR: + /* Handle complex lvalues (when permitted) + by reduction to simpler cases. */ + + val = unary_complex_lvalue (code, arg); + if (val != 0) + return val; + + /* Increment or decrement the real part of the value, + and don't change the imaginary part. */ + if (typecode == COMPLEX_TYPE) + { + tree real, imag; + + arg = stabilize_reference (arg); + real = build_unary_op (REALPART_EXPR, arg, 1); + imag = build_unary_op (IMAGPART_EXPR, arg, 1); + return build (COMPLEX_EXPR, TREE_TYPE (arg), + build_unary_op (code, real, 1), imag); + } + + /* Report invalid types. */ + + if (typecode != POINTER_TYPE + && typecode != INTEGER_TYPE && typecode != REAL_TYPE) + { + if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) + errstring ="wrong type argument to increment"; + else + errstring ="wrong type argument to decrement"; + break; + } + + { + register tree inc; + tree result_type = TREE_TYPE (arg); + + arg = get_unwidened (arg, 0); + argtype = TREE_TYPE (arg); + + /* Compute the increment. */ + + if (typecode == POINTER_TYPE) + { + /* If pointer target is an undefined struct, + we just cannot know how to do the arithmetic. */ + if (TYPE_SIZE (TREE_TYPE (result_type)) == 0) + error ("%s of pointer to unknown structure", + ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? "increment" : "decrement")); + else if ((pedantic || warn_pointer_arith) + && (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE + || TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)) + pedwarn ("wrong type argument to %s", + ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? "increment" : "decrement")); + inc = c_size_in_bytes (TREE_TYPE (result_type)); + } + else + inc = integer_one_node; + + inc = convert (argtype, inc); + + /* Handle incrementing a cast-expression. */ + + while (1) + switch (TREE_CODE (arg)) + { + case NOP_EXPR: + case CONVERT_EXPR: + case FLOAT_EXPR: + case FIX_TRUNC_EXPR: + case FIX_FLOOR_EXPR: + case FIX_ROUND_EXPR: + case FIX_CEIL_EXPR: + pedantic_lvalue_warning (CONVERT_EXPR); + /* If the real type has the same machine representation + as the type it is cast to, we can make better output + by adding directly to the inside of the cast. */ + if ((TREE_CODE (TREE_TYPE (arg)) + == TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 0)))) + && (TYPE_MODE (TREE_TYPE (arg)) + == TYPE_MODE (TREE_TYPE (TREE_OPERAND (arg, 0))))) + arg = TREE_OPERAND (arg, 0); + else + { + tree incremented, modify, value; + arg = stabilize_reference (arg); + if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR) + value = arg; + else + value = save_expr (arg); + incremented = build (((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? PLUS_EXPR : MINUS_EXPR), + argtype, value, inc); + TREE_SIDE_EFFECTS (incremented) = 1; + modify = build_modify_expr (arg, NOP_EXPR, incremented); + value = build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value); + TREE_USED (value) = 1; + return value; + } + break; + + default: + goto give_up; + } + give_up: + + /* Complain about anything else that is not a true lvalue. */ + if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? "increment" : "decrement"))) + return error_mark_node; + + /* Report a read-only lvalue. */ + if (TREE_READONLY (arg)) + readonly_warning (arg, + ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? "increment" : "decrement")); + + val = build (code, TREE_TYPE (arg), arg, inc); + TREE_SIDE_EFFECTS (val) = 1; + val = convert (result_type, val); + if (TREE_CODE (val) != code) + TREE_NO_UNUSED_WARNING (val) = 1; + return val; + } + + case ADDR_EXPR: + /* Note that this operation never does default_conversion + regardless of NOCONVERT. */ + + /* Let &* cancel out to simplify resulting code. */ + if (TREE_CODE (arg) == INDIRECT_REF) + { + /* Don't let this be an lvalue. */ + if (lvalue_p (TREE_OPERAND (arg, 0))) + return non_lvalue (TREE_OPERAND (arg, 0)); + return TREE_OPERAND (arg, 0); + } + + /* For &x[y], return x+y */ + if (TREE_CODE (arg) == ARRAY_REF) + { + if (mark_addressable (TREE_OPERAND (arg, 0)) == 0) + return error_mark_node; + return build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0), + TREE_OPERAND (arg, 1), 1); + } + + /* Handle complex lvalues (when permitted) + by reduction to simpler cases. */ + val = unary_complex_lvalue (code, arg); + if (val != 0) + return val; + +#if 0 /* Turned off because inconsistent; + float f; *&(int)f = 3.4 stores in int format + whereas (int)f = 3.4 stores in float format. */ + /* Address of a cast is just a cast of the address + of the operand of the cast. */ + switch (TREE_CODE (arg)) + { + case NOP_EXPR: + case CONVERT_EXPR: + case FLOAT_EXPR: + case FIX_TRUNC_EXPR: + case FIX_FLOOR_EXPR: + case FIX_ROUND_EXPR: + case FIX_CEIL_EXPR: + if (pedantic) + pedwarn ("ANSI C forbids the address of a cast expression"); + return convert (build_pointer_type (TREE_TYPE (arg)), + build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), + 0)); + } +#endif + + /* Allow the address of a constructor if all the elements + are constant. */ + if (TREE_CODE (arg) == CONSTRUCTOR && TREE_CONSTANT (arg)) + ; + /* Anything not already handled and not a true memory reference + is an error. */ + else if (typecode != FUNCTION_TYPE && !lvalue_or_else (arg, "unary `&'")) + return error_mark_node; + + /* Ordinary case; arg is a COMPONENT_REF or a decl. */ + argtype = TREE_TYPE (arg); + /* If the lvalue is const or volatile, merge that into the type + to which the address will point. Note that you can't get a + restricted pointer by taking the address of something, so we + only have to deal with `const' and `volatile' here. */ + if (TREE_CODE_CLASS (TREE_CODE (arg)) == 'd' + || TREE_CODE_CLASS (TREE_CODE (arg)) == 'r') + { + if (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg)) + argtype = c_build_type_variant (argtype, + TREE_READONLY (arg), + TREE_THIS_VOLATILE (arg)); + } + + argtype = build_pointer_type (argtype); + + if (mark_addressable (arg) == 0) + return error_mark_node; + + { + tree addr; + + if (TREE_CODE (arg) == COMPONENT_REF) + { + tree field = TREE_OPERAND (arg, 1); + + addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0); + + if (DECL_C_BIT_FIELD (field)) + { + error ("attempt to take address of bit-field structure member `%s'", + IDENTIFIER_POINTER (DECL_NAME (field))); + return error_mark_node; + } + + addr = convert (argtype, addr); + + if (! integer_zerop (DECL_FIELD_BITPOS (field))) + { + tree offset + = size_binop (EASY_DIV_EXPR, DECL_FIELD_BITPOS (field), + size_int (BITS_PER_UNIT)); + int flag = TREE_CONSTANT (addr); + addr = fold (build (PLUS_EXPR, argtype, + addr, convert (argtype, offset))); + TREE_CONSTANT (addr) = flag; + } + } + else + addr = build1 (code, argtype, arg); + + /* Address of a static or external variable or + file-scope function counts as a constant. */ + if (staticp (arg) + && ! (TREE_CODE (arg) == FUNCTION_DECL + && DECL_CONTEXT (arg) != 0)) + TREE_CONSTANT (addr) = 1; + return addr; + } + + default: + break; + } + + if (!errstring) + { + if (argtype == 0) + argtype = TREE_TYPE (arg); + return fold (build1 (code, argtype, arg)); + } + + error (errstring); + return error_mark_node; +} + +#if 0 +/* If CONVERSIONS is a conversion expression or a nested sequence of such, + convert ARG with the same conversions in the same order + and return the result. */ + +static tree +convert_sequence (conversions, arg) + tree conversions; + tree arg; +{ + switch (TREE_CODE (conversions)) + { + case NOP_EXPR: + case CONVERT_EXPR: + case FLOAT_EXPR: + case FIX_TRUNC_EXPR: + case FIX_FLOOR_EXPR: + case FIX_ROUND_EXPR: + case FIX_CEIL_EXPR: + return convert (TREE_TYPE (conversions), + convert_sequence (TREE_OPERAND (conversions, 0), + arg)); + + default: + return arg; + } +} +#endif /* 0 */ + +/* Return nonzero if REF is an lvalue valid for this language. + Lvalues can be assigned, unless their type has TYPE_READONLY. + Lvalues can have their address taken, unless they have DECL_REGISTER. */ + +int +lvalue_p (ref) + tree ref; +{ + register enum tree_code code = TREE_CODE (ref); + + switch (code) + { + case REALPART_EXPR: + case IMAGPART_EXPR: + case COMPONENT_REF: + return lvalue_p (TREE_OPERAND (ref, 0)); + + case STRING_CST: + return 1; + + case INDIRECT_REF: + case ARRAY_REF: + case VAR_DECL: + case PARM_DECL: + case RESULT_DECL: + case ERROR_MARK: + return (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE + && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE); + + case BIND_EXPR: + case RTL_EXPR: + return TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE; + + default: + return 0; + } +} + +/* Return nonzero if REF is an lvalue valid for this language; + otherwise, print an error message and return zero. */ + +int +lvalue_or_else (ref, string) + tree ref; + char *string; +{ + int win = lvalue_p (ref); + if (! win) + error ("invalid lvalue in %s", string); + return win; +} + +/* Apply unary lvalue-demanding operator CODE to the expression ARG + for certain kinds of expressions which are not really lvalues + but which we can accept as lvalues. + + If ARG is not a kind of expression we can handle, return zero. */ + +static tree +unary_complex_lvalue (code, arg) + enum tree_code code; + tree arg; +{ + /* Handle (a, b) used as an "lvalue". */ + if (TREE_CODE (arg) == COMPOUND_EXPR) + { + tree real_result = build_unary_op (code, TREE_OPERAND (arg, 1), 0); + + /* If this returns a function type, it isn't really being used as + an lvalue, so don't issue a warning about it. */ + if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE) + pedantic_lvalue_warning (COMPOUND_EXPR); + + return build (COMPOUND_EXPR, TREE_TYPE (real_result), + TREE_OPERAND (arg, 0), real_result); + } + + /* Handle (a ? b : c) used as an "lvalue". */ + if (TREE_CODE (arg) == COND_EXPR) + { + pedantic_lvalue_warning (COND_EXPR); + if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE) + pedantic_lvalue_warning (COMPOUND_EXPR); + + return (build_conditional_expr + (TREE_OPERAND (arg, 0), + build_unary_op (code, TREE_OPERAND (arg, 1), 0), + build_unary_op (code, TREE_OPERAND (arg, 2), 0))); + } + + return 0; +} + +/* If pedantic, warn about improper lvalue. CODE is either COND_EXPR + COMPOUND_EXPR, or CONVERT_EXPR (for casts). */ + +static void +pedantic_lvalue_warning (code) + enum tree_code code; +{ + if (pedantic) + pedwarn ("ANSI C forbids use of %s expressions as lvalues", + code == COND_EXPR ? "conditional" + : code == COMPOUND_EXPR ? "compound" : "cast"); +} + +/* Warn about storing in something that is `const'. */ + +void +readonly_warning (arg, string) + tree arg; + char *string; +{ + char buf[80]; + strcpy (buf, string); + + /* Forbid assignments to iterators. */ + if (TREE_CODE (arg) == VAR_DECL && ITERATOR_P (arg)) + { + strcat (buf, " of iterator `%s'"); + pedwarn (buf, IDENTIFIER_POINTER (DECL_NAME (arg))); + } + + if (TREE_CODE (arg) == COMPONENT_REF) + { + if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0)))) + readonly_warning (TREE_OPERAND (arg, 0), string); + else + { + strcat (buf, " of read-only member `%s'"); + pedwarn (buf, IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (arg, 1)))); + } + } + else if (TREE_CODE (arg) == VAR_DECL) + { + strcat (buf, " of read-only variable `%s'"); + pedwarn (buf, IDENTIFIER_POINTER (DECL_NAME (arg))); + } + else + { + pedwarn ("%s of read-only location", buf); + } +} + +/* Mark EXP saying that we need to be able to take the + address of it; it should not be allocated in a register. + Value is 1 if successful. */ + +int +mark_addressable (exp) + tree exp; +{ + register tree x = exp; + while (1) + switch (TREE_CODE (x)) + { + case COMPONENT_REF: + if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1))) + { + error ("cannot take address of bitfield `%s'", + IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (x, 1)))); + return 0; + } + + /* ... fall through ... */ + + case ADDR_EXPR: + case ARRAY_REF: + case REALPART_EXPR: + case IMAGPART_EXPR: + x = TREE_OPERAND (x, 0); + break; + + case CONSTRUCTOR: + TREE_ADDRESSABLE (x) = 1; + return 1; + + case VAR_DECL: + case CONST_DECL: + case PARM_DECL: + case RESULT_DECL: + if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x) + && DECL_NONLOCAL (x)) + { + if (TREE_PUBLIC (x)) + { + error ("global register variable `%s' used in nested function", + IDENTIFIER_POINTER (DECL_NAME (x))); + return 0; + } + pedwarn ("register variable `%s' used in nested function", + IDENTIFIER_POINTER (DECL_NAME (x))); + } + else if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)) + { + if (TREE_PUBLIC (x)) + { + error ("address of global register variable `%s' requested", + IDENTIFIER_POINTER (DECL_NAME (x))); + return 0; + } + + /* If we are making this addressable due to its having + volatile components, give a different error message. Also + handle the case of an unnamed parameter by not trying + to give the name. */ + + else if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (x))) + { + error ("cannot put object with volatile field into register"); + return 0; + } + + pedwarn ("address of register variable `%s' requested", + IDENTIFIER_POINTER (DECL_NAME (x))); + } + put_var_into_stack (x); + + /* drops in */ + case FUNCTION_DECL: + TREE_ADDRESSABLE (x) = 1; +#if 0 /* poplevel deals with this now. */ + if (DECL_CONTEXT (x) == 0) + TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (x)) = 1; +#endif + + default: + return 1; + } +} + +/* Build and return a conditional expression IFEXP ? OP1 : OP2. */ + +tree +build_conditional_expr (ifexp, op1, op2) + tree ifexp, op1, op2; +{ + register tree type1; + register tree type2; + register enum tree_code code1; + register enum tree_code code2; + register tree result_type = NULL; + tree orig_op1 = op1, orig_op2 = op2; + + ifexp = truthvalue_conversion (default_conversion (ifexp)); + +#if 0 /* Produces wrong result if within sizeof. */ + /* Don't promote the operands separately if they promote + the same way. Return the unpromoted type and let the combined + value get promoted if necessary. */ + + if (TREE_TYPE (op1) == TREE_TYPE (op2) + && TREE_CODE (TREE_TYPE (op1)) != ARRAY_TYPE + && TREE_CODE (TREE_TYPE (op1)) != ENUMERAL_TYPE + && TREE_CODE (TREE_TYPE (op1)) != FUNCTION_TYPE) + { + if (TREE_CODE (ifexp) == INTEGER_CST) + return pedantic_non_lvalue (integer_zerop (ifexp) ? op2 : op1); + + return fold (build (COND_EXPR, TREE_TYPE (op1), ifexp, op1, op2)); + } +#endif + + /* Promote both alternatives. */ + + if (TREE_CODE (TREE_TYPE (op1)) != VOID_TYPE) + op1 = default_conversion (op1); + if (TREE_CODE (TREE_TYPE (op2)) != VOID_TYPE) + op2 = default_conversion (op2); + + if (TREE_CODE (ifexp) == ERROR_MARK + || TREE_CODE (TREE_TYPE (op1)) == ERROR_MARK + || TREE_CODE (TREE_TYPE (op2)) == ERROR_MARK) + return error_mark_node; + + type1 = TREE_TYPE (op1); + code1 = TREE_CODE (type1); + type2 = TREE_TYPE (op2); + code2 = TREE_CODE (type2); + + /* Quickly detect the usual case where op1 and op2 have the same type + after promotion. */ + if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2)) + { + if (type1 == type2) + result_type = type1; + else + result_type = TYPE_MAIN_VARIANT (type1); + } + else if ((code1 == INTEGER_TYPE || code1 == REAL_TYPE) + && (code2 == INTEGER_TYPE || code2 == REAL_TYPE)) + { + result_type = common_type (type1, type2); + } + else if (code1 == VOID_TYPE || code2 == VOID_TYPE) + { + if (pedantic && (code1 != VOID_TYPE || code2 != VOID_TYPE)) + pedwarn ("ANSI C forbids conditional expr with only one void side"); + result_type = void_type_node; + } + else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE) + { + if (comp_target_types (type1, type2)) + result_type = common_type (type1, type2); + else if (integer_zerop (op1) && TREE_TYPE (type1) == void_type_node + && TREE_CODE (orig_op1) != NOP_EXPR) + result_type = qualify_type (type2, type1); + else if (integer_zerop (op2) && TREE_TYPE (type2) == void_type_node + && TREE_CODE (orig_op2) != NOP_EXPR) + result_type = qualify_type (type1, type2); + else if (TYPE_MAIN_VARIANT (TREE_TYPE (type1)) == void_type_node) + { + if (pedantic && TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE) + pedwarn ("ANSI C forbids conditional expr between `void *' and function pointer"); + result_type = qualify_type (type1, type2); + } + else if (TYPE_MAIN_VARIANT (TREE_TYPE (type2)) == void_type_node) + { + if (pedantic && TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE) + pedwarn ("ANSI C forbids conditional expr between `void *' and function pointer"); + result_type = qualify_type (type2, type1); + } + else + { + pedwarn ("pointer type mismatch in conditional expression"); + result_type = build_pointer_type (void_type_node); + } + } + else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE) + { + if (! integer_zerop (op2)) + pedwarn ("pointer/integer type mismatch in conditional expression"); + else + { + op2 = null_pointer_node; +#if 0 /* The spec seems to say this is permitted. */ + if (pedantic && TREE_CODE (type1) == FUNCTION_TYPE) + pedwarn ("ANSI C forbids conditional expr between 0 and function pointer"); +#endif + } + result_type = type1; + } + else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + if (!integer_zerop (op1)) + pedwarn ("pointer/integer type mismatch in conditional expression"); + else + { + op1 = null_pointer_node; +#if 0 /* The spec seems to say this is permitted. */ + if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE) + pedwarn ("ANSI C forbids conditional expr between 0 and function pointer"); +#endif + } + result_type = type2; + } + + if (!result_type) + { + if (flag_cond_mismatch) + result_type = void_type_node; + else + { + error ("type mismatch in conditional expression"); + return error_mark_node; + } + } + + /* Merge const and volatile flags of the incoming types. */ + result_type + = build_type_variant (result_type, + TREE_READONLY (op1) || TREE_READONLY (op2), + TREE_THIS_VOLATILE (op1) || TREE_THIS_VOLATILE (op2)); + + if (result_type != TREE_TYPE (op1)) + op1 = convert_and_check (result_type, op1); + if (result_type != TREE_TYPE (op2)) + op2 = convert_and_check (result_type, op2); + +#if 0 + if (code1 == RECORD_TYPE || code1 == UNION_TYPE) + { + result_type = TREE_TYPE (op1); + if (TREE_CONSTANT (ifexp)) + return pedantic_non_lvalue (integer_zerop (ifexp) ? op2 : op1); + + if (TYPE_MODE (result_type) == BLKmode) + { + register tree tempvar + = build_decl (VAR_DECL, NULL_TREE, result_type); + register tree xop1 = build_modify_expr (tempvar, op1); + register tree xop2 = build_modify_expr (tempvar, op2); + register tree result = fold (build (COND_EXPR, result_type, + ifexp, xop1, xop2)); + + layout_decl (tempvar, TYPE_ALIGN (result_type)); + /* No way to handle variable-sized objects here. + I fear that the entire handling of BLKmode conditional exprs + needs to be redone. */ + if (TREE_CODE (DECL_SIZE (tempvar)) != INTEGER_CST) + abort (); + DECL_RTL (tempvar) + = assign_stack_local (DECL_MODE (tempvar), + (TREE_INT_CST_LOW (DECL_SIZE (tempvar)) + + BITS_PER_UNIT - 1) + / BITS_PER_UNIT, + 0); + + TREE_SIDE_EFFECTS (result) + = TREE_SIDE_EFFECTS (ifexp) | TREE_SIDE_EFFECTS (op1) + | TREE_SIDE_EFFECTS (op2); + return build (COMPOUND_EXPR, result_type, result, tempvar); + } + } +#endif /* 0 */ + + if (TREE_CODE (ifexp) == INTEGER_CST) + return pedantic_non_lvalue (integer_zerop (ifexp) ? op2 : op1); + + return fold (build (COND_EXPR, result_type, ifexp, op1, op2)); +} + +/* Given a list of expressions, return a compound expression + that performs them all and returns the value of the last of them. */ + +tree +build_compound_expr (list) + tree list; +{ + return internal_build_compound_expr (list, TRUE); +} + +static tree +internal_build_compound_expr (list, first_p) + tree list; + int first_p; +{ + register tree rest; + + if (TREE_CHAIN (list) == 0) + { +#if 0 /* If something inside inhibited lvalueness, we should not override. */ + /* Consider (x, y+0), which is not an lvalue since y+0 is not. */ + + /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ + if (TREE_CODE (list) == NON_LVALUE_EXPR) + list = TREE_OPERAND (list, 0); +#endif + + /* Don't let (0, 0) be null pointer constant. */ + if (!first_p && integer_zerop (TREE_VALUE (list))) + return non_lvalue (TREE_VALUE (list)); + return TREE_VALUE (list); + } + + if (TREE_CHAIN (list) != 0 && TREE_CHAIN (TREE_CHAIN (list)) == 0) + { + /* Convert arrays to pointers when there really is a comma operator. */ + if (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (list)))) == ARRAY_TYPE) + TREE_VALUE (TREE_CHAIN (list)) + = default_conversion (TREE_VALUE (TREE_CHAIN (list))); + } + + rest = internal_build_compound_expr (TREE_CHAIN (list), FALSE); + + if (! TREE_SIDE_EFFECTS (TREE_VALUE (list))) + { + /* The left-hand operand of a comma expression is like an expression + statement: with -W or -Wunused, we should warn if it doesn't have + any side-effects, unless it was explicitly cast to (void). */ + if ((extra_warnings || warn_unused) + && ! (TREE_CODE (TREE_VALUE (list)) == CONVERT_EXPR + && TREE_TYPE (TREE_VALUE (list)) == void_type_node)) + warning ("left-hand operand of comma expression has no effect"); + + /* When pedantic, a compound expression can be neither an lvalue + nor an integer constant expression. */ + if (! pedantic) + return rest; + } + + /* With -Wunused, we should also warn if the left-hand operand does have + side-effects, but computes a value which is not used. For example, in + `foo() + bar(), baz()' the result of the `+' operator is not used, + so we should issue a warning. */ + else if (warn_unused) + warn_if_unused_value (TREE_VALUE (list)); + + return build (COMPOUND_EXPR, TREE_TYPE (rest), TREE_VALUE (list), rest); +} + +/* Build an expression representing a cast to type TYPE of expression EXPR. */ + +tree +build_c_cast (type, expr) + register tree type; + tree expr; +{ + register tree value = expr; + + if (type == error_mark_node || expr == error_mark_node) + return error_mark_node; + type = TYPE_MAIN_VARIANT (type); + +#if 0 + /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ + if (TREE_CODE (value) == NON_LVALUE_EXPR) + value = TREE_OPERAND (value, 0); +#endif + + if (TREE_CODE (type) == ARRAY_TYPE) + { + error ("cast specifies array type"); + return error_mark_node; + } + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + error ("cast specifies function type"); + return error_mark_node; + } + + if (type == TREE_TYPE (value)) + { + if (pedantic) + { + if (TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE) + pedwarn ("ANSI C forbids casting nonscalar to the same type"); + } + } + else if (TREE_CODE (type) == UNION_TYPE) + { + tree field; + if (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE) + value = default_conversion (value); + + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)), + TYPE_MAIN_VARIANT (TREE_TYPE (value)))) + break; + + if (field) + { + char *name; + tree t; + + if (pedantic) + pedwarn ("ANSI C forbids casts to union type"); + if (TYPE_NAME (type) != 0) + { + if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) + name = IDENTIFIER_POINTER (TYPE_NAME (type)); + else + name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); + } + else + name = ""; + t = digest_init (type, build (CONSTRUCTOR, type, NULL_TREE, + build_tree_list (field, value)), + 0, 0); + TREE_CONSTANT (t) = TREE_CONSTANT (value); + return t; + } + error ("cast to union type from type not present in union"); + return error_mark_node; + } + else + { + tree otype, ovalue; + + /* If casting to void, avoid the error that would come + from default_conversion in the case of a non-lvalue array. */ + if (type == void_type_node) + return build1 (CONVERT_EXPR, type, value); + + /* Convert functions and arrays to pointers, + but don't convert any other types. */ + if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE + || TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE) + value = default_conversion (value); + otype = TREE_TYPE (value); + + /* Optionally warn about potentially worrisome casts. */ + + if (warn_cast_qual + && TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE) + { + /* Go to the innermost object being pointed to. */ + tree in_type = type; + tree in_otype = otype; + + while (TREE_CODE (in_type) == POINTER_TYPE) + in_type = TREE_TYPE (in_type); + while (TREE_CODE (in_otype) == POINTER_TYPE) + in_otype = TREE_TYPE (in_otype); + + if (TYPE_QUALS (in_otype) & ~TYPE_QUALS (in_type)) + /* There are qualifiers present in IN_OTYPE that are not + present in IN_TYPE. */ + pedwarn ("cast discards qualifiers from pointer target type"); + } + + /* Warn about possible alignment problems. */ + if (STRICT_ALIGNMENT && warn_cast_align + && TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (otype)) != VOID_TYPE + && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE + /* Don't warn about opaque types, where the actual alignment + restriction is unknown. */ + && !((TREE_CODE (TREE_TYPE (otype)) == UNION_TYPE + || TREE_CODE (TREE_TYPE (otype)) == RECORD_TYPE) + && TYPE_MODE (TREE_TYPE (otype)) == VOIDmode) + && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype))) + warning ("cast increases required alignment of target type"); + + if (TREE_CODE (type) == INTEGER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && TYPE_PRECISION (type) != TYPE_PRECISION (otype) + && !TREE_CONSTANT (value)) + warning ("cast from pointer to integer of different size"); + + if (warn_bad_function_cast + && TREE_CODE (value) == CALL_EXPR + && TREE_CODE (type) != TREE_CODE (otype)) + warning ("cast does not match function type"); + + if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == INTEGER_TYPE + && TYPE_PRECISION (type) != TYPE_PRECISION (otype) +#if 0 + /* Don't warn about converting 0 to pointer, + provided the 0 was explicit--not cast or made by folding. */ + && !(TREE_CODE (value) == INTEGER_CST && integer_zerop (value)) +#endif + /* Don't warn about converting any constant. */ + && !TREE_CONSTANT (value)) + warning ("cast to pointer from integer of different size"); + + ovalue = value; + value = convert (type, value); + + /* Ignore any integer overflow caused by the cast. */ + if (TREE_CODE (value) == INTEGER_CST) + { + TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue); + TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue); + } + } + + /* Pedantically, don't ley (void *) (FOO *) 0 be a null pointer constant. */ + if (pedantic && TREE_CODE (value) == INTEGER_CST + && TREE_CODE (expr) == INTEGER_CST + && TREE_CODE (TREE_TYPE (expr)) != INTEGER_TYPE) + value = non_lvalue (value); + + /* If pedantic, don't let a cast be an lvalue. */ + if (value == expr && pedantic) + value = non_lvalue (value); + + return value; +} + +/* Build an assignment expression of lvalue LHS from value RHS. + MODIFYCODE is the code for a binary operator that we use + to combine the old value of LHS with RHS to get the new value. + Or else MODIFYCODE is NOP_EXPR meaning do a simple assignment. */ + +tree +build_modify_expr (lhs, modifycode, rhs) + tree lhs, rhs; + enum tree_code modifycode; +{ + register tree result; + tree newrhs; + tree lhstype = TREE_TYPE (lhs); + tree olhstype = lhstype; + + /* Types that aren't fully specified cannot be used in assignments. */ + lhs = require_complete_type (lhs); + + /* Avoid duplicate error messages from operands that had errors. */ + if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK) + return error_mark_node; + + /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ + /* Do not use STRIP_NOPS here. We do not want an enumerator + whose value is 0 to count as a null pointer constant. */ + if (TREE_CODE (rhs) == NON_LVALUE_EXPR) + rhs = TREE_OPERAND (rhs, 0); + + newrhs = rhs; + + /* Handle control structure constructs used as "lvalues". */ + + switch (TREE_CODE (lhs)) + { + /* Handle (a, b) used as an "lvalue". */ + case COMPOUND_EXPR: + pedantic_lvalue_warning (COMPOUND_EXPR); + newrhs = build_modify_expr (TREE_OPERAND (lhs, 1), + modifycode, rhs); + if (TREE_CODE (newrhs) == ERROR_MARK) + return error_mark_node; + return build (COMPOUND_EXPR, lhstype, + TREE_OPERAND (lhs, 0), newrhs); + + /* Handle (a ? b : c) used as an "lvalue". */ + case COND_EXPR: + pedantic_lvalue_warning (COND_EXPR); + rhs = save_expr (rhs); + { + /* Produce (a ? (b = rhs) : (c = rhs)) + except that the RHS goes through a save-expr + so the code to compute it is only emitted once. */ + tree cond + = build_conditional_expr (TREE_OPERAND (lhs, 0), + build_modify_expr (TREE_OPERAND (lhs, 1), + modifycode, rhs), + build_modify_expr (TREE_OPERAND (lhs, 2), + modifycode, rhs)); + if (TREE_CODE (cond) == ERROR_MARK) + return cond; + /* Make sure the code to compute the rhs comes out + before the split. */ + return build (COMPOUND_EXPR, TREE_TYPE (lhs), + /* But cast it to void to avoid an "unused" error. */ + convert (void_type_node, rhs), cond); + } + default: + break; + } + + /* If a binary op has been requested, combine the old LHS value with the RHS + producing the value we should actually store into the LHS. */ + + if (modifycode != NOP_EXPR) + { + lhs = stabilize_reference (lhs); + newrhs = build_binary_op (modifycode, lhs, rhs, 1); + } + + /* Handle a cast used as an "lvalue". + We have already performed any binary operator using the value as cast. + Now convert the result to the cast type of the lhs, + and then true type of the lhs and store it there; + then convert result back to the cast type to be the value + of the assignment. */ + + switch (TREE_CODE (lhs)) + { + case NOP_EXPR: + case CONVERT_EXPR: + case FLOAT_EXPR: + case FIX_TRUNC_EXPR: + case FIX_FLOOR_EXPR: + case FIX_ROUND_EXPR: + case FIX_CEIL_EXPR: + if (TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (newrhs)) == FUNCTION_TYPE) + newrhs = default_conversion (newrhs); + { + tree inner_lhs = TREE_OPERAND (lhs, 0); + tree result; + result = build_modify_expr (inner_lhs, NOP_EXPR, + convert (TREE_TYPE (inner_lhs), + convert (lhstype, newrhs))); + if (TREE_CODE (result) == ERROR_MARK) + return result; + pedantic_lvalue_warning (CONVERT_EXPR); + return convert (TREE_TYPE (lhs), result); + } + + default: + break; + } + + /* Now we have handled acceptable kinds of LHS that are not truly lvalues. + Reject anything strange now. */ + + if (!lvalue_or_else (lhs, "assignment")) + return error_mark_node; + + /* Warn about storing in something that is `const'. */ + + if (TREE_READONLY (lhs) || TYPE_READONLY (lhstype) + || ((TREE_CODE (lhstype) == RECORD_TYPE + || TREE_CODE (lhstype) == UNION_TYPE) + && C_TYPE_FIELDS_READONLY (lhstype))) + readonly_warning (lhs, "assignment"); + + /* If storing into a structure or union member, + it has probably been given type `int'. + Compute the type that would go with + the actual amount of storage the member occupies. */ + + if (TREE_CODE (lhs) == COMPONENT_REF + && (TREE_CODE (lhstype) == INTEGER_TYPE + || TREE_CODE (lhstype) == REAL_TYPE + || TREE_CODE (lhstype) == ENUMERAL_TYPE)) + lhstype = TREE_TYPE (get_unwidened (lhs, 0)); + + /* If storing in a field that is in actuality a short or narrower than one, + we must store in the field in its actual type. */ + + if (lhstype != TREE_TYPE (lhs)) + { + lhs = copy_node (lhs); + TREE_TYPE (lhs) = lhstype; + } + + /* Convert new value to destination type. */ + + newrhs = convert_for_assignment (lhstype, newrhs, "assignment", + NULL_TREE, NULL_TREE, 0); + if (TREE_CODE (newrhs) == ERROR_MARK) + return error_mark_node; + + result = build (MODIFY_EXPR, lhstype, lhs, newrhs); + TREE_SIDE_EFFECTS (result) = 1; + + /* If we got the LHS in a different type for storing in, + convert the result back to the nominal type of LHS + so that the value we return always has the same type + as the LHS argument. */ + + if (olhstype == TREE_TYPE (result)) + return result; + return convert_for_assignment (olhstype, result, "assignment", + NULL_TREE, NULL_TREE, 0); +} + +/* Convert value RHS to type TYPE as preparation for an assignment + to an lvalue of type TYPE. + The real work of conversion is done by `convert'. + The purpose of this function is to generate error messages + for assignments that are not allowed in C. + ERRTYPE is a string to use in error messages: + "assignment", "return", etc. If it is null, this is parameter passing + for a function call (and different error messages are output). Otherwise, + it may be a name stored in the spelling stack and interpreted by + get_spelling. + + FUNNAME is the name of the function being called, + as an IDENTIFIER_NODE, or null. + PARMNUM is the number of the argument, for printing in error messages. */ + +static tree +convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum) + tree type, rhs; + char *errtype; + tree fundecl, funname; + int parmnum; +{ + register enum tree_code codel = TREE_CODE (type); + register tree rhstype; + register enum tree_code coder; + + /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ + /* Do not use STRIP_NOPS here. We do not want an enumerator + whose value is 0 to count as a null pointer constant. */ + if (TREE_CODE (rhs) == NON_LVALUE_EXPR) + rhs = TREE_OPERAND (rhs, 0); + + if (TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE) + rhs = default_conversion (rhs); + else if (optimize && TREE_CODE (rhs) == VAR_DECL) + rhs = decl_constant_value (rhs); + + rhstype = TREE_TYPE (rhs); + coder = TREE_CODE (rhstype); + + if (coder == ERROR_MARK) + return error_mark_node; + + if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype)) + { + overflow_warning (rhs); + /* Check for Objective-C protocols. This will issue a warning if + there are protocol violations. No need to use the return value. */ + maybe_objc_comptypes (type, rhstype, 0); + return rhs; + } + + if (coder == VOID_TYPE) + { + error ("void value not ignored as it ought to be"); + return error_mark_node; + } + /* Arithmetic types all interconvert, and enum is treated like int. */ + if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == ENUMERAL_TYPE + || codel == COMPLEX_TYPE) + && (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == ENUMERAL_TYPE + || coder == COMPLEX_TYPE)) + return convert_and_check (type, rhs); + + /* Conversion to a transparent union from its member types. + This applies only to function arguments. */ + else if (codel == UNION_TYPE && TYPE_TRANSPARENT_UNION (type) && ! errtype) + { + tree memb_types; + tree marginal_memb_type = 0; + + for (memb_types = TYPE_FIELDS (type); memb_types; + memb_types = TREE_CHAIN (memb_types)) + { + tree memb_type = TREE_TYPE (memb_types); + + if (comptypes (TYPE_MAIN_VARIANT (memb_type), + TYPE_MAIN_VARIANT (rhstype))) + break; + + if (TREE_CODE (memb_type) != POINTER_TYPE) + continue; + + if (coder == POINTER_TYPE) + { + register tree ttl = TREE_TYPE (memb_type); + register tree ttr = TREE_TYPE (rhstype); + + /* Any non-function converts to a [const][volatile] void * + and vice versa; otherwise, targets must be the same. + Meanwhile, the lhs target must have all the qualifiers of + the rhs. */ + if (TYPE_MAIN_VARIANT (ttl) == void_type_node + || TYPE_MAIN_VARIANT (ttr) == void_type_node + || comp_target_types (memb_type, rhstype)) + { + /* If this type won't generate any warnings, use it. */ + if (TYPE_QUALS (ttl) == TYPE_QUALS (ttr) + || ((TREE_CODE (ttr) == FUNCTION_TYPE + && TREE_CODE (ttl) == FUNCTION_TYPE) + ? ((TYPE_QUALS (ttl) | TYPE_QUALS (ttr)) + == TYPE_QUALS (ttr)) + : ((TYPE_QUALS (ttl) | TYPE_QUALS (ttr)) + == TYPE_QUALS (ttl)))) + break; + + /* Keep looking for a better type, but remember this one. */ + if (! marginal_memb_type) + marginal_memb_type = memb_type; + } + } + + /* Can convert integer zero to any pointer type. */ + if (integer_zerop (rhs) + || (TREE_CODE (rhs) == NOP_EXPR + && integer_zerop (TREE_OPERAND (rhs, 0)))) + { + rhs = null_pointer_node; + break; + } + } + + if (memb_types || marginal_memb_type) + { + if (! memb_types) + { + /* We have only a marginally acceptable member type; + it needs a warning. */ + register tree ttl = TREE_TYPE (marginal_memb_type); + register tree ttr = TREE_TYPE (rhstype); + + /* Const and volatile mean something different for function + types, so the usual warnings are not appropriate. */ + if (TREE_CODE (ttr) == FUNCTION_TYPE + && TREE_CODE (ttl) == FUNCTION_TYPE) + { + /* Because const and volatile on functions are + restrictions that say the function will not do + certain things, it is okay to use a const or volatile + function where an ordinary one is wanted, but not + vice-versa. */ + if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr)) + warn_for_assignment ("%s makes qualified function pointer from unqualified", + get_spelling (errtype), funname, + parmnum); + } + else if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)) + warn_for_assignment ("%s discards qualifiers from pointer target type", + get_spelling (errtype), funname, + parmnum); + } + + if (pedantic && ! DECL_IN_SYSTEM_HEADER (fundecl)) + pedwarn ("ANSI C prohibits argument conversion to union type"); + + return build1 (NOP_EXPR, type, rhs); + } + } + + /* Conversions among pointers */ + else if (codel == POINTER_TYPE && coder == POINTER_TYPE) + { + register tree ttl = TREE_TYPE (type); + register tree ttr = TREE_TYPE (rhstype); + + /* Any non-function converts to a [const][volatile] void * + and vice versa; otherwise, targets must be the same. + Meanwhile, the lhs target must have all the qualifiers of the rhs. */ + if (TYPE_MAIN_VARIANT (ttl) == void_type_node + || TYPE_MAIN_VARIANT (ttr) == void_type_node + || comp_target_types (type, rhstype) + || (unsigned_type (TYPE_MAIN_VARIANT (ttl)) + == unsigned_type (TYPE_MAIN_VARIANT (ttr)))) + { + if (pedantic + && ((TYPE_MAIN_VARIANT (ttl) == void_type_node + && TREE_CODE (ttr) == FUNCTION_TYPE) + || + (TYPE_MAIN_VARIANT (ttr) == void_type_node + /* Check TREE_CODE to catch cases like (void *) (char *) 0 + which are not ANSI null ptr constants. */ + && (!integer_zerop (rhs) || TREE_CODE (rhs) == NOP_EXPR) + && TREE_CODE (ttl) == FUNCTION_TYPE))) + warn_for_assignment ("ANSI forbids %s between function pointer and `void *'", + get_spelling (errtype), funname, parmnum); + /* Const and volatile mean something different for function types, + so the usual warnings are not appropriate. */ + else if (TREE_CODE (ttr) != FUNCTION_TYPE + && TREE_CODE (ttl) != FUNCTION_TYPE) + { + if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)) + warn_for_assignment ("%s discards qualifiers from pointer target type", + get_spelling (errtype), funname, parmnum); + /* If this is not a case of ignoring a mismatch in signedness, + no warning. */ + else if (TYPE_MAIN_VARIANT (ttl) == void_type_node + || TYPE_MAIN_VARIANT (ttr) == void_type_node + || comp_target_types (type, rhstype)) + ; + /* If there is a mismatch, do warn. */ + else if (pedantic) + warn_for_assignment ("pointer targets in %s differ in signedness", + get_spelling (errtype), funname, parmnum); + } + else if (TREE_CODE (ttl) == FUNCTION_TYPE + && TREE_CODE (ttr) == FUNCTION_TYPE) + { + /* Because const and volatile on functions are restrictions + that say the function will not do certain things, + it is okay to use a const or volatile function + where an ordinary one is wanted, but not vice-versa. */ + if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr)) + warn_for_assignment ("%s makes qualified function pointer from unqualified", + get_spelling (errtype), funname, parmnum); + } + } + else + warn_for_assignment ("%s from incompatible pointer type", + get_spelling (errtype), funname, parmnum); + return convert (type, rhs); + } + else if (codel == POINTER_TYPE && coder == INTEGER_TYPE) + { + /* An explicit constant 0 can convert to a pointer, + or one that results from arithmetic, even including + a cast to integer type. */ + if (! (TREE_CODE (rhs) == INTEGER_CST && integer_zerop (rhs)) + && + ! (TREE_CODE (rhs) == NOP_EXPR + && TREE_CODE (TREE_TYPE (rhs)) == INTEGER_TYPE + && TREE_CODE (TREE_OPERAND (rhs, 0)) == INTEGER_CST + && integer_zerop (TREE_OPERAND (rhs, 0)))) + { + warn_for_assignment ("%s makes pointer from integer without a cast", + get_spelling (errtype), funname, parmnum); + return convert (type, rhs); + } + return null_pointer_node; + } + else if (codel == INTEGER_TYPE && coder == POINTER_TYPE) + { + warn_for_assignment ("%s makes integer from pointer without a cast", + get_spelling (errtype), funname, parmnum); + return convert (type, rhs); + } + + if (!errtype) + { + if (funname) + { + tree selector = maybe_building_objc_message_expr (); + + if (selector && parmnum > 2) + error ("incompatible type for argument %d of `%s'", + parmnum - 2, IDENTIFIER_POINTER (selector)); + else + error ("incompatible type for argument %d of `%s'", + parmnum, IDENTIFIER_POINTER (funname)); + } + else + error ("incompatible type for argument %d of indirect function call", + parmnum); + } + else + error ("incompatible types in %s", get_spelling (errtype)); + + return error_mark_node; +} + +/* Print a warning using MSG. + It gets OPNAME as its one parameter. + If OPNAME is null, it is replaced by "passing arg ARGNUM of `FUNCTION'". + FUNCTION and ARGNUM are handled specially if we are building an + Objective-C selector. */ + +static void +warn_for_assignment (msg, opname, function, argnum) + char *msg; + char *opname; + tree function; + int argnum; +{ + static char argstring[] = "passing arg %d of `%s'"; + static char argnofun[] = "passing arg %d"; + + if (opname == 0) + { + tree selector = maybe_building_objc_message_expr (); + + if (selector && argnum > 2) + { + function = selector; + argnum -= 2; + } + if (function) + { + /* Function name is known; supply it. */ + opname = (char *) alloca (IDENTIFIER_LENGTH (function) + + sizeof (argstring) + 25 /*%d*/ + 1); + sprintf (opname, argstring, argnum, IDENTIFIER_POINTER (function)); + } + else + { + /* Function name unknown (call through ptr); just give arg number. */ + opname = (char *) alloca (sizeof (argnofun) + 25 /*%d*/ + 1); + sprintf (opname, argnofun, argnum); + } + } + pedwarn (msg, opname); +} + +/* Return nonzero if VALUE is a valid constant-valued expression + for use in initializing a static variable; one that can be an + element of a "constant" initializer. + + Return null_pointer_node if the value is absolute; + if it is relocatable, return the variable that determines the relocation. + We assume that VALUE has been folded as much as possible; + therefore, we do not need to check for such things as + arithmetic-combinations of integers. */ + +tree +initializer_constant_valid_p (value, endtype) + tree value; + tree endtype; +{ + switch (TREE_CODE (value)) + { + case CONSTRUCTOR: + if ((TREE_CODE (TREE_TYPE (value)) == UNION_TYPE + || TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE) + && TREE_CONSTANT (value) + && CONSTRUCTOR_ELTS (value)) + return + initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)), + endtype); + + return TREE_STATIC (value) ? null_pointer_node : 0; + + case INTEGER_CST: + case REAL_CST: + case STRING_CST: + case COMPLEX_CST: + return null_pointer_node; + + case ADDR_EXPR: + return TREE_OPERAND (value, 0); + + case NON_LVALUE_EXPR: + return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype); + + case CONVERT_EXPR: + case NOP_EXPR: + /* Allow conversions between pointer types. */ + if (TREE_CODE (TREE_TYPE (value)) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == POINTER_TYPE) + return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype); + + /* Allow conversions between real types. */ + if (TREE_CODE (TREE_TYPE (value)) == REAL_TYPE + && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == REAL_TYPE) + return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype); + + /* Allow length-preserving conversions between integer types. */ + if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE + && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE + && (TYPE_PRECISION (TREE_TYPE (value)) + == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0))))) + return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype); + + /* Allow conversions between other integer types only if + explicit value. */ + if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE + && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE) + { + tree inner = initializer_constant_valid_p (TREE_OPERAND (value, 0), + endtype); + if (inner == null_pointer_node) + return null_pointer_node; + return 0; + } + + /* Allow (int) &foo provided int is as wide as a pointer. */ + if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE + && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == POINTER_TYPE + && (TYPE_PRECISION (TREE_TYPE (value)) + >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0))))) + return initializer_constant_valid_p (TREE_OPERAND (value, 0), + endtype); + + /* Likewise conversions from int to pointers, but also allow + conversions from 0. */ + if (TREE_CODE (TREE_TYPE (value)) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE) + { + if (integer_zerop (TREE_OPERAND (value, 0))) + return null_pointer_node; + else if (TYPE_PRECISION (TREE_TYPE (value)) + <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))) + return initializer_constant_valid_p (TREE_OPERAND (value, 0), + endtype); + } + + /* Allow conversions to union types if the value inside is okay. */ + if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE) + return initializer_constant_valid_p (TREE_OPERAND (value, 0), + endtype); + return 0; + + case PLUS_EXPR: + if (TREE_CODE (endtype) == INTEGER_TYPE + && TYPE_PRECISION (endtype) < POINTER_SIZE) + return 0; + { + tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0), + endtype); + tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1), + endtype); + /* If either term is absolute, use the other terms relocation. */ + if (valid0 == null_pointer_node) + return valid1; + if (valid1 == null_pointer_node) + return valid0; + return 0; + } + + case MINUS_EXPR: + if (TREE_CODE (endtype) == INTEGER_TYPE + && TYPE_PRECISION (endtype) < POINTER_SIZE) + return 0; + { + tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0), + endtype); + tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1), + endtype); + /* Win if second argument is absolute. */ + if (valid1 == null_pointer_node) + return valid0; + /* Win if both arguments have the same relocation. + Then the value is absolute. */ + if (valid0 == valid1) + return null_pointer_node; + return 0; + } + + default: + return 0; + } +} + +/* If VALUE is a compound expr all of whose expressions are constant, then + return its value. Otherwise, return error_mark_node. + + This is for handling COMPOUND_EXPRs as initializer elements + which is allowed with a warning when -pedantic is specified. */ + +static tree +valid_compound_expr_initializer (value, endtype) + tree value; + tree endtype; +{ + if (TREE_CODE (value) == COMPOUND_EXPR) + { + if (valid_compound_expr_initializer (TREE_OPERAND (value, 0), endtype) + == error_mark_node) + return error_mark_node; + return valid_compound_expr_initializer (TREE_OPERAND (value, 1), + endtype); + } + else if (! TREE_CONSTANT (value) + && ! initializer_constant_valid_p (value, endtype)) + return error_mark_node; + else + return value; +} + +/* Perform appropriate conversions on the initial value of a variable, + store it in the declaration DECL, + and print any error messages that are appropriate. + If the init is invalid, store an ERROR_MARK. */ + +void +store_init_value (decl, init) + tree decl, init; +{ + register tree value, type; + + /* If variable's type was invalidly declared, just ignore it. */ + + type = TREE_TYPE (decl); + if (TREE_CODE (type) == ERROR_MARK) + return; + + /* Digest the specified initializer into an expression. */ + + value = digest_init (type, init, TREE_STATIC (decl), + TREE_STATIC (decl) || pedantic); + + /* Store the expression if valid; else report error. */ + +#if 0 + /* Note that this is the only place we can detect the error + in a case such as struct foo bar = (struct foo) { x, y }; + where there is one initial value which is a constructor expression. */ + if (value == error_mark_node) + ; + else if (TREE_STATIC (decl) && ! TREE_CONSTANT (value)) + { + error ("initializer for static variable is not constant"); + value = error_mark_node; + } + else if (TREE_STATIC (decl) + && initializer_constant_valid_p (value, TREE_TYPE (value)) == 0) + { + error ("initializer for static variable uses complicated arithmetic"); + value = error_mark_node; + } + else + { + if (pedantic && TREE_CODE (value) == CONSTRUCTOR) + { + if (! TREE_CONSTANT (value)) + pedwarn ("aggregate initializer is not constant"); + else if (! TREE_STATIC (value)) + pedwarn ("aggregate initializer uses complicated arithmetic"); + } + } +#endif + + DECL_INITIAL (decl) = value; + + /* ANSI wants warnings about out-of-range constant initializers. */ + STRIP_TYPE_NOPS (value); + constant_expression_warning (value); +} + +/* Methods for storing and printing names for error messages. */ + +/* Implement a spelling stack that allows components of a name to be pushed + and popped. Each element on the stack is this structure. */ + +struct spelling +{ + int kind; + union + { + int i; + char *s; + } u; +}; + +#define SPELLING_STRING 1 +#define SPELLING_MEMBER 2 +#define SPELLING_BOUNDS 3 + +static struct spelling *spelling; /* Next stack element (unused). */ +static struct spelling *spelling_base; /* Spelling stack base. */ +static int spelling_size; /* Size of the spelling stack. */ + +/* Macros to save and restore the spelling stack around push_... functions. + Alternative to SAVE_SPELLING_STACK. */ + +#define SPELLING_DEPTH() (spelling - spelling_base) +#define RESTORE_SPELLING_DEPTH(depth) (spelling = spelling_base + depth) + +/* Save and restore the spelling stack around arbitrary C code. */ + +#define SAVE_SPELLING_DEPTH(code) \ +{ \ + int __depth = SPELLING_DEPTH (); \ + code; \ + RESTORE_SPELLING_DEPTH (__depth); \ +} + +/* Push an element on the spelling stack with type KIND and assign VALUE + to MEMBER. */ + +#define PUSH_SPELLING(KIND, VALUE, MEMBER) \ +{ \ + int depth = SPELLING_DEPTH (); \ + \ + if (depth >= spelling_size) \ + { \ + spelling_size += 10; \ + if (spelling_base == 0) \ + spelling_base \ + = (struct spelling *) xmalloc (spelling_size * sizeof (struct spelling)); \ + else \ + spelling_base \ + = (struct spelling *) xrealloc (spelling_base, \ + spelling_size * sizeof (struct spelling)); \ + RESTORE_SPELLING_DEPTH (depth); \ + } \ + \ + spelling->kind = (KIND); \ + spelling->MEMBER = (VALUE); \ + spelling++; \ +} + +/* Push STRING on the stack. Printed literally. */ + +static void +push_string (string) + char *string; +{ + PUSH_SPELLING (SPELLING_STRING, string, u.s); +} + +/* Push a member name on the stack. Printed as '.' STRING. */ + +static void +push_member_name (decl) + tree decl; + +{ + char *string + = DECL_NAME (decl) ? IDENTIFIER_POINTER (DECL_NAME (decl)) : ""; + PUSH_SPELLING (SPELLING_MEMBER, string, u.s); +} + +/* Push an array bounds on the stack. Printed as [BOUNDS]. */ + +static void +push_array_bounds (bounds) + int bounds; +{ + PUSH_SPELLING (SPELLING_BOUNDS, bounds, u.i); +} + +/* Compute the maximum size in bytes of the printed spelling. */ + +static int +spelling_length () +{ + register int size = 0; + register struct spelling *p; + + for (p = spelling_base; p < spelling; p++) + { + if (p->kind == SPELLING_BOUNDS) + size += 25; + else + size += strlen (p->u.s) + 1; + } + + return size; +} + +/* Print the spelling to BUFFER and return it. */ + +static char * +print_spelling (buffer) + register char *buffer; +{ + register char *d = buffer; + register char *s; + register struct spelling *p; + + for (p = spelling_base; p < spelling; p++) + if (p->kind == SPELLING_BOUNDS) + { + sprintf (d, "[%d]", p->u.i); + d += strlen (d); + } + else + { + if (p->kind == SPELLING_MEMBER) + *d++ = '.'; + for (s = p->u.s; (*d = *s++); d++) + ; + } + *d++ = '\0'; + return buffer; +} + +/* Provide a means to pass component names derived from the spelling stack. */ + +char initialization_message; + +/* Interpret the spelling of the given ERRTYPE message. */ + +static char * +get_spelling (errtype) + char *errtype; +{ + static char *buffer; + static int size = -1; + + if (errtype == &initialization_message) + { + /* Avoid counting chars */ + static char message[] = "initialization of `%s'"; + register int needed = sizeof (message) + spelling_length () + 1; + char *temp; + + if (size < 0) + buffer = (char *) xmalloc (size = needed); + if (needed > size) + buffer = (char *) xrealloc (buffer, size = needed); + + temp = (char *) alloca (needed); + sprintf (buffer, message, print_spelling (temp)); + return buffer; + } + + return errtype; +} + +/* Issue an error message for a bad initializer component. + FORMAT describes the message. OFWHAT is the name for the component. + LOCAL is a format string for formatting the insertion of the name + into the message. + + If OFWHAT is null, the component name is stored on the spelling stack. + If the component name is a null string, then LOCAL is omitted entirely. */ + +void +error_init (format, local, ofwhat) + char *format, *local, *ofwhat; +{ + char *buffer; + + if (ofwhat == 0) + ofwhat = print_spelling ((char *) alloca (spelling_length () + 1)); + buffer = (char *) alloca (strlen (local) + strlen (ofwhat) + 2); + + if (*ofwhat) + sprintf (buffer, local, ofwhat); + else + buffer[0] = 0; + + error (format, buffer); +} + +/* Issue a pedantic warning for a bad initializer component. + FORMAT describes the message. OFWHAT is the name for the component. + LOCAL is a format string for formatting the insertion of the name + into the message. + + If OFWHAT is null, the component name is stored on the spelling stack. + If the component name is a null string, then LOCAL is omitted entirely. */ + +void +pedwarn_init (format, local, ofwhat) + char *format, *local, *ofwhat; +{ + char *buffer; + + if (ofwhat == 0) + ofwhat = print_spelling ((char *) alloca (spelling_length () + 1)); + buffer = (char *) alloca (strlen (local) + strlen (ofwhat) + 2); + + if (*ofwhat) + sprintf (buffer, local, ofwhat); + else + buffer[0] = 0; + + pedwarn (format, buffer); +} + +/* Issue a warning for a bad initializer component. + FORMAT describes the message. OFWHAT is the name for the component. + LOCAL is a format string for formatting the insertion of the name + into the message. + + If OFWHAT is null, the component name is stored on the spelling stack. + If the component name is a null string, then LOCAL is omitted entirely. */ + +static void +warning_init (format, local, ofwhat) + char *format, *local, *ofwhat; +{ + char *buffer; + + if (ofwhat == 0) + ofwhat = print_spelling ((char *) alloca (spelling_length () + 1)); + buffer = (char *) alloca (strlen (local) + strlen (ofwhat) + 2); + + if (*ofwhat) + sprintf (buffer, local, ofwhat); + else + buffer[0] = 0; + + warning (format, buffer); +} + +/* Digest the parser output INIT as an initializer for type TYPE. + Return a C expression of type TYPE to represent the initial value. + + The arguments REQUIRE_CONSTANT and CONSTRUCTOR_CONSTANT request errors + if non-constant initializers or elements are seen. CONSTRUCTOR_CONSTANT + applies only to elements of constructors. */ + +static tree +digest_init (type, init, require_constant, constructor_constant) + tree type, init; + int require_constant, constructor_constant; +{ + enum tree_code code = TREE_CODE (type); + tree inside_init = init; + + if (init == error_mark_node) + return init; + + /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ + /* Do not use STRIP_NOPS here. We do not want an enumerator + whose value is 0 to count as a null pointer constant. */ + if (TREE_CODE (init) == NON_LVALUE_EXPR) + inside_init = TREE_OPERAND (init, 0); + + /* Initialization of an array of chars from a string constant + optionally enclosed in braces. */ + + if (code == ARRAY_TYPE) + { + tree typ1 = TYPE_MAIN_VARIANT (TREE_TYPE (type)); + if ((typ1 == char_type_node + || typ1 == signed_char_type_node + || typ1 == unsigned_char_type_node + || typ1 == unsigned_wchar_type_node + || typ1 == signed_wchar_type_node) + && ((inside_init && TREE_CODE (inside_init) == STRING_CST))) + { + if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)), + TYPE_MAIN_VARIANT (type))) + return inside_init; + + if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init))) + != char_type_node) + && TYPE_PRECISION (typ1) == TYPE_PRECISION (char_type_node)) + { + error_init ("char-array%s initialized from wide string", + " `%s'", NULL); + return error_mark_node; + } + if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init))) + == char_type_node) + && TYPE_PRECISION (typ1) != TYPE_PRECISION (char_type_node)) + { + error_init ("int-array%s initialized from non-wide string", + " `%s'", NULL); + return error_mark_node; + } + + TREE_TYPE (inside_init) = type; + if (TYPE_DOMAIN (type) != 0 + && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST) + { + register int size = TREE_INT_CST_LOW (TYPE_SIZE (type)); + size = (size + BITS_PER_UNIT - 1) / BITS_PER_UNIT; + /* Subtract 1 (or sizeof (wchar_t)) + because it's ok to ignore the terminating null char + that is counted in the length of the constant. */ + if (size < TREE_STRING_LENGTH (inside_init) + - (TYPE_PRECISION (typ1) != TYPE_PRECISION (char_type_node) + ? TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT + : 1)) + pedwarn_init ( + "initializer-string for array of chars%s is too long", + " `%s'", NULL); + } + return inside_init; + } + } + + /* Any type can be initialized + from an expression of the same type, optionally with braces. */ + + if (inside_init && TREE_TYPE (inside_init) != 0 + && (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)), + TYPE_MAIN_VARIANT (type)) + || (code == ARRAY_TYPE + && comptypes (TREE_TYPE (inside_init), type)) + || (code == POINTER_TYPE + && (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (inside_init)) == FUNCTION_TYPE) + && comptypes (TREE_TYPE (TREE_TYPE (inside_init)), + TREE_TYPE (type))))) + { + if (code == POINTER_TYPE + && (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (inside_init)) == FUNCTION_TYPE)) + inside_init = default_conversion (inside_init); + else if (code == ARRAY_TYPE && TREE_CODE (inside_init) != STRING_CST + && TREE_CODE (inside_init) != CONSTRUCTOR) + { + error_init ("array%s initialized from non-constant array expression", + " `%s'", NULL); + return error_mark_node; + } + + if (optimize && TREE_CODE (inside_init) == VAR_DECL) + inside_init = decl_constant_value (inside_init); + + /* Compound expressions can only occur here if -pedantic or + -pedantic-errors is specified. In the later case, we always want + an error. In the former case, we simply want a warning. */ + if (require_constant && pedantic + && TREE_CODE (inside_init) == COMPOUND_EXPR) + { + inside_init + = valid_compound_expr_initializer (inside_init, + TREE_TYPE (inside_init)); + if (inside_init == error_mark_node) + error_init ("initializer element%s is not constant", + " for `%s'", NULL); + else + pedwarn_init ("initializer element%s is not constant", + " for `%s'", NULL); + if (flag_pedantic_errors) + inside_init = error_mark_node; + } + else if (require_constant && ! TREE_CONSTANT (inside_init)) + { + error_init ("initializer element%s is not constant", + " for `%s'", NULL); + inside_init = error_mark_node; + } + else if (require_constant + && initializer_constant_valid_p (inside_init, TREE_TYPE (inside_init)) == 0) + { + error_init ("initializer element%s is not computable at load time", + " for `%s'", NULL); + inside_init = error_mark_node; + } + + return inside_init; + } + + /* Handle scalar types, including conversions. */ + + if (code == INTEGER_TYPE || code == REAL_TYPE || code == POINTER_TYPE + || code == ENUMERAL_TYPE || code == COMPLEX_TYPE) + { + /* Note that convert_for_assignment calls default_conversion + for arrays and functions. We must not call it in the + case where inside_init is a null pointer constant. */ + inside_init + = convert_for_assignment (type, init, "initialization", + NULL_TREE, NULL_TREE, 0); + + if (require_constant && ! TREE_CONSTANT (inside_init)) + { + error_init ("initializer element%s is not constant", + " for `%s'", NULL); + inside_init = error_mark_node; + } + else if (require_constant + && initializer_constant_valid_p (inside_init, TREE_TYPE (inside_init)) == 0) + { + error_init ("initializer element%s is not computable at load time", + " for `%s'", NULL); + inside_init = error_mark_node; + } + + return inside_init; + } + + /* Come here only for records and arrays. */ + + if (TYPE_SIZE (type) && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) + { + error_init ("variable-sized object%s may not be initialized", + " `%s'", NULL); + return error_mark_node; + } + + /* Traditionally, you can write struct foo x = 0; + and it initializes the first element of x to 0. */ + if (flag_traditional) + { + tree top = 0, prev = 0, otype = type; + while (TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == ARRAY_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE + || TREE_CODE (type) == UNION_TYPE) + { + tree temp = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE); + if (prev == 0) + top = temp; + else + TREE_OPERAND (prev, 1) = build_tree_list (NULL_TREE, temp); + prev = temp; + if (TREE_CODE (type) == ARRAY_TYPE) + type = TREE_TYPE (type); + else if (TYPE_FIELDS (type)) + type = TREE_TYPE (TYPE_FIELDS (type)); + else + { + error_init ("invalid initializer%s", " for `%s'", NULL); + return error_mark_node; + } + } + + if (otype != type) + { + TREE_OPERAND (prev, 1) + = build_tree_list (NULL_TREE, + digest_init (type, init, require_constant, + constructor_constant)); + return top; + } + else + return error_mark_node; + } + error_init ("invalid initializer%s", " for `%s'", NULL); + return error_mark_node; +} + +/* Handle initializers that use braces. */ + +/* Type of object we are accumulating a constructor for. + This type is always a RECORD_TYPE, UNION_TYPE or ARRAY_TYPE. */ +static tree constructor_type; + +/* For a RECORD_TYPE or UNION_TYPE, this is the chain of fields + left to fill. */ +static tree constructor_fields; + +/* For an ARRAY_TYPE, this is the specified index + at which to store the next element we get. + This is a special INTEGER_CST node that we modify in place. */ +static tree constructor_index; + +/* For an ARRAY_TYPE, this is the end index of the range + to initialize with the next element, or NULL in the ordinary case + where the element is used just once. */ +static tree constructor_range_end; + +/* For an ARRAY_TYPE, this is the maximum index. */ +static tree constructor_max_index; + +/* For a RECORD_TYPE, this is the first field not yet written out. */ +static tree constructor_unfilled_fields; + +/* For an ARRAY_TYPE, this is the index of the first element + not yet written out. + This is a special INTEGER_CST node that we modify in place. */ +static tree constructor_unfilled_index; + +/* In a RECORD_TYPE, the byte index of the next consecutive field. + This is so we can generate gaps between fields, when appropriate. + This is a special INTEGER_CST node that we modify in place. */ +static tree constructor_bit_index; + +/* If we are saving up the elements rather than allocating them, + this is the list of elements so far (in reverse order, + most recent first). */ +static tree constructor_elements; + +/* 1 if so far this constructor's elements are all compile-time constants. */ +static int constructor_constant; + +/* 1 if so far this constructor's elements are all valid address constants. */ +static int constructor_simple; + +/* 1 if this constructor is erroneous so far. */ +static int constructor_erroneous; + +/* 1 if have called defer_addressed_constants. */ +static int constructor_subconstants_deferred; + +/* Structure for managing pending initializer elements, organized as an + AVL tree. */ + +struct init_node +{ + struct init_node *left, *right; + struct init_node *parent; + int balance; + tree purpose; + tree value; +}; + +/* Tree of pending elements at this constructor level. + These are elements encountered out of order + which belong at places we haven't reached yet in actually + writing the output. */ +static struct init_node *constructor_pending_elts; + +/* The SPELLING_DEPTH of this constructor. */ +static int constructor_depth; + +/* 0 if implicitly pushing constructor levels is allowed. */ +int constructor_no_implicit = 0; /* 0 for C; 1 for some other languages. */ + +static int require_constant_value; +static int require_constant_elements; + +/* 1 if it is ok to output this constructor as we read it. + 0 means must accumulate a CONSTRUCTOR expression. */ +static int constructor_incremental; + +/* DECL node for which an initializer is being read. + 0 means we are reading a constructor expression + such as (struct foo) {...}. */ +static tree constructor_decl; + +/* start_init saves the ASMSPEC arg here for really_start_incremental_init. */ +static char *constructor_asmspec; + +/* Nonzero if this is an initializer for a top-level decl. */ +static int constructor_top_level; + + +/* This stack has a level for each implicit or explicit level of + structuring in the initializer, including the outermost one. It + saves the values of most of the variables above. */ + +struct constructor_stack +{ + struct constructor_stack *next; + tree type; + tree fields; + tree index; + tree range_end; + tree max_index; + tree unfilled_index; + tree unfilled_fields; + tree bit_index; + tree elements; + int offset; + struct init_node *pending_elts; + int depth; + /* If nonzero, this value should replace the entire + constructor at this level. */ + tree replacement_value; + char constant; + char simple; + char implicit; + char incremental; + char erroneous; + char outer; +}; + +struct constructor_stack *constructor_stack; + +/* This stack records separate initializers that are nested. + Nested initializers can't happen in ANSI C, but GNU C allows them + in cases like { ... (struct foo) { ... } ... }. */ + +struct initializer_stack +{ + struct initializer_stack *next; + tree decl; + char *asmspec; + struct constructor_stack *constructor_stack; + tree elements; + struct spelling *spelling; + struct spelling *spelling_base; + int spelling_size; + char top_level; + char incremental; + char require_constant_value; + char require_constant_elements; + char deferred; +}; + +struct initializer_stack *initializer_stack; + +/* Prepare to parse and output the initializer for variable DECL. */ + +void +start_init (decl, asmspec_tree, top_level) + tree decl; + tree asmspec_tree; + int top_level; +{ + char *locus; + struct initializer_stack *p + = (struct initializer_stack *) xmalloc (sizeof (struct initializer_stack)); + char *asmspec = 0; + + if (asmspec_tree) + asmspec = TREE_STRING_POINTER (asmspec_tree); + + p->decl = constructor_decl; + p->asmspec = constructor_asmspec; + p->incremental = constructor_incremental; + p->require_constant_value = require_constant_value; + p->require_constant_elements = require_constant_elements; + p->constructor_stack = constructor_stack; + p->elements = constructor_elements; + p->spelling = spelling; + p->spelling_base = spelling_base; + p->spelling_size = spelling_size; + p->deferred = constructor_subconstants_deferred; + p->top_level = constructor_top_level; + p->next = initializer_stack; + initializer_stack = p; + + constructor_decl = decl; + constructor_incremental = top_level; + constructor_asmspec = asmspec; + constructor_subconstants_deferred = 0; + constructor_top_level = top_level; + + if (decl != 0) + { + require_constant_value = TREE_STATIC (decl); + require_constant_elements + = ((TREE_STATIC (decl) || pedantic) + /* For a scalar, you can always use any value to initialize, + even within braces. */ + && (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE + || TREE_CODE (TREE_TYPE (decl)) == QUAL_UNION_TYPE)); + locus = IDENTIFIER_POINTER (DECL_NAME (decl)); + constructor_incremental |= TREE_STATIC (decl); + } + else + { + require_constant_value = 0; + require_constant_elements = 0; + locus = "(anonymous)"; + } + + constructor_stack = 0; + + missing_braces_mentioned = 0; + + spelling_base = 0; + spelling_size = 0; + RESTORE_SPELLING_DEPTH (0); + + if (locus) + push_string (locus); +} + +void +finish_init () +{ + struct initializer_stack *p = initializer_stack; + + /* Output subconstants (string constants, usually) + that were referenced within this initializer and saved up. + Must do this if and only if we called defer_addressed_constants. */ + if (constructor_subconstants_deferred) + output_deferred_addressed_constants (); + + /* Free the whole constructor stack of this initializer. */ + while (constructor_stack) + { + struct constructor_stack *q = constructor_stack; + constructor_stack = q->next; + free (q); + } + + /* Pop back to the data of the outer initializer (if any). */ + constructor_decl = p->decl; + constructor_asmspec = p->asmspec; + constructor_incremental = p->incremental; + require_constant_value = p->require_constant_value; + require_constant_elements = p->require_constant_elements; + constructor_stack = p->constructor_stack; + constructor_elements = p->elements; + spelling = p->spelling; + spelling_base = p->spelling_base; + spelling_size = p->spelling_size; + constructor_subconstants_deferred = p->deferred; + constructor_top_level = p->top_level; + initializer_stack = p->next; + free (p); +} + +/* Call here when we see the initializer is surrounded by braces. + This is instead of a call to push_init_level; + it is matched by a call to pop_init_level. + + TYPE is the type to initialize, for a constructor expression. + For an initializer for a decl, TYPE is zero. */ + +void +really_start_incremental_init (type) + tree type; +{ + struct constructor_stack *p + = (struct constructor_stack *) xmalloc (sizeof (struct constructor_stack)); + + if (type == 0) + type = TREE_TYPE (constructor_decl); + + /* Turn off constructor_incremental if type is a struct with bitfields. + Do this before the first push, so that the corrected value + is available in finish_init. */ + check_init_type_bitfields (type); + + p->type = constructor_type; + p->fields = constructor_fields; + p->index = constructor_index; + p->range_end = constructor_range_end; + p->max_index = constructor_max_index; + p->unfilled_index = constructor_unfilled_index; + p->unfilled_fields = constructor_unfilled_fields; + p->bit_index = constructor_bit_index; + p->elements = constructor_elements; + p->constant = constructor_constant; + p->simple = constructor_simple; + p->erroneous = constructor_erroneous; + p->pending_elts = constructor_pending_elts; + p->depth = constructor_depth; + p->replacement_value = 0; + p->implicit = 0; + p->incremental = constructor_incremental; + p->outer = 0; + p->next = 0; + constructor_stack = p; + + constructor_constant = 1; + constructor_simple = 1; + constructor_depth = SPELLING_DEPTH (); + constructor_elements = 0; + constructor_pending_elts = 0; + constructor_type = type; + + if (TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + { + constructor_fields = TYPE_FIELDS (constructor_type); + /* Skip any nameless bit fields at the beginning. */ + while (constructor_fields != 0 && DECL_C_BIT_FIELD (constructor_fields) + && DECL_NAME (constructor_fields) == 0) + constructor_fields = TREE_CHAIN (constructor_fields); + constructor_unfilled_fields = constructor_fields; + constructor_bit_index = copy_node (integer_zero_node); + TREE_TYPE (constructor_bit_index) = sbitsizetype; + } + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + constructor_range_end = 0; + if (TYPE_DOMAIN (constructor_type)) + { + constructor_max_index + = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)); + constructor_index + = copy_node (TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type))); + } + else + constructor_index = copy_node (integer_zero_node); + constructor_unfilled_index = copy_node (constructor_index); + } + else + { + /* Handle the case of int x = {5}; */ + constructor_fields = constructor_type; + constructor_unfilled_fields = constructor_type; + } + + if (constructor_incremental) + { + int momentary = suspend_momentary (); + push_obstacks_nochange (); + if (TREE_PERMANENT (constructor_decl)) + end_temporary_allocation (); + make_decl_rtl (constructor_decl, constructor_asmspec, + constructor_top_level); + assemble_variable (constructor_decl, constructor_top_level, 0, 1); + pop_obstacks (); + resume_momentary (momentary); + } + + if (constructor_incremental) + { + defer_addressed_constants (); + constructor_subconstants_deferred = 1; + } +} + +/* Push down into a subobject, for initialization. + If this is for an explicit set of braces, IMPLICIT is 0. + If it is because the next element belongs at a lower level, + IMPLICIT is 1. */ + +void +push_init_level (implicit) + int implicit; +{ + struct constructor_stack *p; + + /* If we've exhausted any levels that didn't have braces, + pop them now. */ + while (constructor_stack->implicit) + { + if ((TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + && constructor_fields == 0) + process_init_element (pop_init_level (1)); + else if (TREE_CODE (constructor_type) == ARRAY_TYPE + && tree_int_cst_lt (constructor_max_index, constructor_index)) + process_init_element (pop_init_level (1)); + else + break; + } + + /* Structure elements may require alignment. Do this now if necessary + for the subaggregate, and if it comes next in sequence. Don't do + this for subaggregates that will go on the pending list. */ + if (constructor_incremental && constructor_type != 0 + && TREE_CODE (constructor_type) == RECORD_TYPE && constructor_fields + && constructor_fields == constructor_unfilled_fields) + { + /* Advance to offset of this element. */ + if (! tree_int_cst_equal (constructor_bit_index, + DECL_FIELD_BITPOS (constructor_fields))) + { + /* By using unsigned arithmetic, the result will be correct even + in case of overflows, if BITS_PER_UNIT is a power of two. */ + unsigned next = (TREE_INT_CST_LOW + (DECL_FIELD_BITPOS (constructor_fields)) + / (unsigned)BITS_PER_UNIT); + unsigned here = (TREE_INT_CST_LOW (constructor_bit_index) + / (unsigned)BITS_PER_UNIT); + + assemble_zeros ((next - here) + * (unsigned)BITS_PER_UNIT + / (unsigned)BITS_PER_UNIT); + } + /* Indicate that we have now filled the structure up to the current + field. */ + constructor_unfilled_fields = constructor_fields; + } + + p = (struct constructor_stack *) xmalloc (sizeof (struct constructor_stack)); + p->type = constructor_type; + p->fields = constructor_fields; + p->index = constructor_index; + p->range_end = constructor_range_end; + p->max_index = constructor_max_index; + p->unfilled_index = constructor_unfilled_index; + p->unfilled_fields = constructor_unfilled_fields; + p->bit_index = constructor_bit_index; + p->elements = constructor_elements; + p->constant = constructor_constant; + p->simple = constructor_simple; + p->erroneous = constructor_erroneous; + p->pending_elts = constructor_pending_elts; + p->depth = constructor_depth; + p->replacement_value = 0; + p->implicit = implicit; + p->incremental = constructor_incremental; + p->outer = 0; + p->next = constructor_stack; + constructor_stack = p; + + constructor_constant = 1; + constructor_simple = 1; + constructor_depth = SPELLING_DEPTH (); + constructor_elements = 0; + constructor_pending_elts = 0; + + /* Don't die if an entire brace-pair level is superfluous + in the containing level. */ + if (constructor_type == 0) + ; + else if (TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + { + /* Don't die if there are extra init elts at the end. */ + if (constructor_fields == 0) + constructor_type = 0; + else + { + constructor_type = TREE_TYPE (constructor_fields); + push_member_name (constructor_fields); + constructor_depth++; + if (constructor_fields != constructor_unfilled_fields) + constructor_incremental = 0; + } + } + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + constructor_type = TREE_TYPE (constructor_type); + push_array_bounds (TREE_INT_CST_LOW (constructor_index)); + constructor_depth++; + if (! tree_int_cst_equal (constructor_index, constructor_unfilled_index) + || constructor_range_end != 0) + constructor_incremental = 0; + } + + if (constructor_type == 0) + { + error_init ("extra brace group at end of initializer%s", + " for `%s'", NULL); + constructor_fields = 0; + constructor_unfilled_fields = 0; + return; + } + + /* Turn off constructor_incremental if type is a struct with bitfields. */ + check_init_type_bitfields (constructor_type); + + if (implicit && warn_missing_braces && !missing_braces_mentioned) + { + missing_braces_mentioned = 1; + warning_init ("missing braces around initializer%s", " for `%s'", NULL); + } + + if (TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + { + constructor_fields = TYPE_FIELDS (constructor_type); + /* Skip any nameless bit fields at the beginning. */ + while (constructor_fields != 0 && DECL_C_BIT_FIELD (constructor_fields) + && DECL_NAME (constructor_fields) == 0) + constructor_fields = TREE_CHAIN (constructor_fields); + constructor_unfilled_fields = constructor_fields; + constructor_bit_index = copy_node (integer_zero_node); + TREE_TYPE (constructor_bit_index) = sbitsizetype; + } + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + constructor_range_end = 0; + if (TYPE_DOMAIN (constructor_type)) + { + constructor_max_index + = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)); + constructor_index + = copy_node (TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type))); + } + else + constructor_index = copy_node (integer_zero_node); + constructor_unfilled_index = copy_node (constructor_index); + } + else + { + warning_init ("braces around scalar initializer%s", " for `%s'", NULL); + constructor_fields = constructor_type; + constructor_unfilled_fields = constructor_type; + } +} + +/* Don't read a struct incrementally if it has any bitfields, + because the incremental reading code doesn't know how to + handle bitfields yet. */ + +static void +check_init_type_bitfields (type) + tree type; +{ + if (TREE_CODE (type) == RECORD_TYPE) + { + tree tail; + for (tail = TYPE_FIELDS (type); tail; + tail = TREE_CHAIN (tail)) + { + if (DECL_C_BIT_FIELD (tail) + /* This catches cases like `int foo : 8;'. */ + || DECL_MODE (tail) != TYPE_MODE (TREE_TYPE (tail))) + { + constructor_incremental = 0; + break; + } + + check_init_type_bitfields (TREE_TYPE (tail)); + } + } + + else if (TREE_CODE (type) == ARRAY_TYPE) + check_init_type_bitfields (TREE_TYPE (type)); +} + +/* At the end of an implicit or explicit brace level, + finish up that level of constructor. + If we were outputting the elements as they are read, return 0 + from inner levels (process_init_element ignores that), + but return error_mark_node from the outermost level + (that's what we want to put in DECL_INITIAL). + Otherwise, return a CONSTRUCTOR expression. */ + +tree +pop_init_level (implicit) + int implicit; +{ + struct constructor_stack *p; + int size = 0; + tree constructor = 0; + + if (implicit == 0) + { + /* When we come to an explicit close brace, + pop any inner levels that didn't have explicit braces. */ + while (constructor_stack->implicit) + process_init_element (pop_init_level (1)); + } + + p = constructor_stack; + + if (constructor_type != 0) + size = int_size_in_bytes (constructor_type); + + /* Warn when some struct elements are implicitly initialized to zero. */ + if (extra_warnings + && constructor_type + && TREE_CODE (constructor_type) == RECORD_TYPE + && constructor_unfilled_fields) + { + push_member_name (constructor_unfilled_fields); + warning_init ("missing initializer%s", " for `%s'", NULL); + RESTORE_SPELLING_DEPTH (constructor_depth); + } + + /* Now output all pending elements. */ + output_pending_init_elements (1); + +#if 0 /* c-parse.in warns about {}. */ + /* In ANSI, each brace level must have at least one element. */ + if (! implicit && pedantic + && (TREE_CODE (constructor_type) == ARRAY_TYPE + ? integer_zerop (constructor_unfilled_index) + : constructor_unfilled_fields == TYPE_FIELDS (constructor_type))) + pedwarn_init ("empty braces in initializer%s", " for `%s'", NULL); +#endif + + /* Pad out the end of the structure. */ + + if (p->replacement_value) + { + /* If this closes a superfluous brace pair, + just pass out the element between them. */ + constructor = p->replacement_value; + /* If this is the top level thing within the initializer, + and it's for a variable, then since we already called + assemble_variable, we must output the value now. */ + if (p->next == 0 && constructor_decl != 0 + && constructor_incremental) + { + constructor = digest_init (constructor_type, constructor, + require_constant_value, + require_constant_elements); + + /* If initializing an array of unknown size, + determine the size now. */ + if (TREE_CODE (constructor_type) == ARRAY_TYPE + && TYPE_DOMAIN (constructor_type) == 0) + { + int failure; + int momentary_p; + + push_obstacks_nochange (); + if (TREE_PERMANENT (constructor_type)) + end_temporary_allocation (); + + momentary_p = suspend_momentary (); + + /* We shouldn't have an incomplete array type within + some other type. */ + if (constructor_stack->next) + abort (); + + failure + = complete_array_type (constructor_type, + constructor, 0); + if (failure) + abort (); + + size = int_size_in_bytes (constructor_type); + resume_momentary (momentary_p); + pop_obstacks (); + } + + output_constant (constructor, size); + } + } + else if (constructor_type == 0) + ; + else if (TREE_CODE (constructor_type) != RECORD_TYPE + && TREE_CODE (constructor_type) != UNION_TYPE + && TREE_CODE (constructor_type) != ARRAY_TYPE + && ! constructor_incremental) + { + /* A nonincremental scalar initializer--just return + the element, after verifying there is just one. */ + if (constructor_elements == 0) + { + error_init ("empty scalar initializer%s", + " for `%s'", NULL); + constructor = error_mark_node; + } + else if (TREE_CHAIN (constructor_elements) != 0) + { + error_init ("extra elements in scalar initializer%s", + " for `%s'", NULL); + constructor = TREE_VALUE (constructor_elements); + } + else + constructor = TREE_VALUE (constructor_elements); + } + else if (! constructor_incremental) + { + if (constructor_erroneous) + constructor = error_mark_node; + else + { + int momentary = suspend_momentary (); + + constructor = build (CONSTRUCTOR, constructor_type, NULL_TREE, + nreverse (constructor_elements)); + if (constructor_constant) + TREE_CONSTANT (constructor) = 1; + if (constructor_constant && constructor_simple) + TREE_STATIC (constructor) = 1; + + resume_momentary (momentary); + } + } + else + { + tree filled; + int momentary = suspend_momentary (); + + if (TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + { + /* Find the offset of the end of that field. */ + filled = size_binop (CEIL_DIV_EXPR, + constructor_bit_index, + size_int (BITS_PER_UNIT)); + } + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + /* If initializing an array of unknown size, + determine the size now. */ + if (TREE_CODE (constructor_type) == ARRAY_TYPE + && TYPE_DOMAIN (constructor_type) == 0) + { + tree maxindex + = size_binop (MINUS_EXPR, + constructor_unfilled_index, + integer_one_node); + + push_obstacks_nochange (); + if (TREE_PERMANENT (constructor_type)) + end_temporary_allocation (); + maxindex = copy_node (maxindex); + TYPE_DOMAIN (constructor_type) = build_index_type (maxindex); + TREE_TYPE (maxindex) = TYPE_DOMAIN (constructor_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. */ + if (pedantic + && (tree_int_cst_sgn (TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type))) + < 0)) + error_with_decl (constructor_decl, + "zero or negative array size `%s'"); + layout_type (constructor_type); + size = int_size_in_bytes (constructor_type); + pop_obstacks (); + } + + filled = size_binop (MULT_EXPR, constructor_unfilled_index, + size_in_bytes (TREE_TYPE (constructor_type))); + } + else + filled = 0; + + if (filled != 0) + assemble_zeros (size - TREE_INT_CST_LOW (filled)); + + resume_momentary (momentary); + } + + + constructor_type = p->type; + constructor_fields = p->fields; + constructor_index = p->index; + constructor_range_end = p->range_end; + constructor_max_index = p->max_index; + constructor_unfilled_index = p->unfilled_index; + constructor_unfilled_fields = p->unfilled_fields; + constructor_bit_index = p->bit_index; + constructor_elements = p->elements; + constructor_constant = p->constant; + constructor_simple = p->simple; + constructor_erroneous = p->erroneous; + constructor_pending_elts = p->pending_elts; + constructor_depth = p->depth; + constructor_incremental = p->incremental; + RESTORE_SPELLING_DEPTH (constructor_depth); + + constructor_stack = p->next; + free (p); + + if (constructor == 0) + { + if (constructor_stack == 0) + return error_mark_node; + return NULL_TREE; + } + return constructor; +} + +/* Within an array initializer, specify the next index to be initialized. + FIRST is that index. If LAST is nonzero, then initialize a range + of indices, running from FIRST through LAST. */ + +void +set_init_index (first, last) + tree first, last; +{ + while ((TREE_CODE (first) == NOP_EXPR + || TREE_CODE (first) == CONVERT_EXPR + || TREE_CODE (first) == NON_LVALUE_EXPR) + && (TYPE_MODE (TREE_TYPE (first)) + == TYPE_MODE (TREE_TYPE (TREE_OPERAND (first, 0))))) + (first) = TREE_OPERAND (first, 0); + if (last) + while ((TREE_CODE (last) == NOP_EXPR + || TREE_CODE (last) == CONVERT_EXPR + || TREE_CODE (last) == NON_LVALUE_EXPR) + && (TYPE_MODE (TREE_TYPE (last)) + == TYPE_MODE (TREE_TYPE (TREE_OPERAND (last, 0))))) + (last) = TREE_OPERAND (last, 0); + + if (TREE_CODE (first) != INTEGER_CST) + error_init ("nonconstant array index in initializer%s", " for `%s'", NULL); + else if (last != 0 && TREE_CODE (last) != INTEGER_CST) + error_init ("nonconstant array index in initializer%s", " for `%s'", NULL); + else if (! constructor_unfilled_index) + error_init ("array index in non-array initializer%s", " for `%s'", NULL); + else if (tree_int_cst_lt (first, constructor_unfilled_index)) + error_init ("duplicate array index in initializer%s", " for `%s'", NULL); + else + { + TREE_INT_CST_LOW (constructor_index) = TREE_INT_CST_LOW (first); + TREE_INT_CST_HIGH (constructor_index) = TREE_INT_CST_HIGH (first); + + if (last != 0 && tree_int_cst_lt (last, first)) + error_init ("empty index range in initializer%s", " for `%s'", NULL); + else + { + if (pedantic) + pedwarn ("ANSI C forbids specifying element to initialize"); + constructor_range_end = last; + } + } +} + +/* Within a struct initializer, specify the next field to be initialized. */ + +void +set_init_label (fieldname) + tree fieldname; +{ + tree tail; + int passed = 0; + + /* Don't die if an entire brace-pair level is superfluous + in the containing level. */ + if (constructor_type == 0) + return; + + for (tail = TYPE_FIELDS (constructor_type); tail; + tail = TREE_CHAIN (tail)) + { + if (tail == constructor_unfilled_fields) + passed = 1; + if (DECL_NAME (tail) == fieldname) + break; + } + + if (tail == 0) + error ("unknown field `%s' specified in initializer", + IDENTIFIER_POINTER (fieldname)); + else if (!passed) + error ("field `%s' already initialized", + IDENTIFIER_POINTER (fieldname)); + else + { + constructor_fields = tail; + if (pedantic) + pedwarn ("ANSI C forbids specifying structure member to initialize"); + } +} + +/* Add a new initializer to the tree of pending initializers. PURPOSE + indentifies the initializer, either array index or field in a structure. + VALUE is the value of that index or field. */ + +static void +add_pending_init (purpose, value) + tree purpose, value; +{ + struct init_node *p, **q, *r; + + q = &constructor_pending_elts; + p = 0; + + if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + while (*q != 0) + { + p = *q; + if (tree_int_cst_lt (purpose, p->purpose)) + q = &p->left; + else if (tree_int_cst_lt (p->purpose, purpose)) + q = &p->right; + else + abort (); + } + } + else + { + while (*q != NULL) + { + p = *q; + if (tree_int_cst_lt (DECL_FIELD_BITPOS (purpose), + DECL_FIELD_BITPOS (p->purpose))) + q = &p->left; + else if (tree_int_cst_lt (DECL_FIELD_BITPOS (p->purpose), + DECL_FIELD_BITPOS (purpose))) + q = &p->right; + else + abort (); + } + } + + r = (struct init_node *) oballoc (sizeof (struct init_node)); + r->purpose = purpose; + r->value = value; + + *q = r; + r->parent = p; + r->left = 0; + r->right = 0; + r->balance = 0; + + while (p) + { + struct init_node *s; + + if (r == p->left) + { + if (p->balance == 0) + p->balance = -1; + else if (p->balance < 0) + { + if (r->balance < 0) + { + /* L rotation. */ + p->left = r->right; + if (p->left) + p->left->parent = p; + r->right = p; + + p->balance = 0; + r->balance = 0; + + s = p->parent; + p->parent = r; + r->parent = s; + if (s) + { + if (s->left == p) + s->left = r; + else + s->right = r; + } + else + constructor_pending_elts = r; + } + else + { + /* LR rotation. */ + struct init_node *t = r->right; + + r->right = t->left; + if (r->right) + r->right->parent = r; + t->left = r; + + p->left = t->right; + if (p->left) + p->left->parent = p; + t->right = p; + + p->balance = t->balance < 0; + r->balance = -(t->balance > 0); + t->balance = 0; + + s = p->parent; + p->parent = t; + r->parent = t; + t->parent = s; + if (s) + { + if (s->left == p) + s->left = t; + else + s->right = t; + } + else + constructor_pending_elts = t; + } + break; + } + else + { + /* p->balance == +1; growth of left side balances the node. */ + p->balance = 0; + break; + } + } + else /* r == p->right */ + { + if (p->balance == 0) + /* Growth propagation from right side. */ + p->balance++; + else if (p->balance > 0) + { + if (r->balance > 0) + { + /* R rotation. */ + p->right = r->left; + if (p->right) + p->right->parent = p; + r->left = p; + + p->balance = 0; + r->balance = 0; + + s = p->parent; + p->parent = r; + r->parent = s; + if (s) + { + if (s->left == p) + s->left = r; + else + s->right = r; + } + else + constructor_pending_elts = r; + } + else /* r->balance == -1 */ + { + /* RL rotation */ + struct init_node *t = r->left; + + r->left = t->right; + if (r->left) + r->left->parent = r; + t->right = r; + + p->right = t->left; + if (p->right) + p->right->parent = p; + t->left = p; + + r->balance = (t->balance < 0); + p->balance = -(t->balance > 0); + t->balance = 0; + + s = p->parent; + p->parent = t; + r->parent = t; + t->parent = s; + if (s) + { + if (s->left == p) + s->left = t; + else + s->right = t; + } + else + constructor_pending_elts = t; + } + break; + } + else + { + /* p->balance == -1; growth of right side balances the node. */ + p->balance = 0; + break; + } + } + + r = p; + p = p->parent; + } +} + +/* Return nonzero if FIELD is equal to the index of a pending initializer. */ + +static int +pending_init_member (field) + tree field; +{ + struct init_node *p; + + p = constructor_pending_elts; + if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + while (p) + { + if (tree_int_cst_equal (field, p->purpose)) + return 1; + else if (tree_int_cst_lt (field, p->purpose)) + p = p->left; + else + p = p->right; + } + } + else + { + while (p) + { + if (field == p->purpose) + return 1; + else if (tree_int_cst_lt (DECL_FIELD_BITPOS (field), + DECL_FIELD_BITPOS (p->purpose))) + p = p->left; + else + p = p->right; + } + } + + return 0; +} + +/* "Output" the next constructor element. + At top level, really output it to assembler code now. + Otherwise, collect it in a list from which we will make a CONSTRUCTOR. + TYPE is the data type that the containing data type wants here. + FIELD is the field (a FIELD_DECL) or the index that this element fills. + + PENDING if non-nil means output pending elements that belong + right after this element. (PENDING is normally 1; + it is 0 while outputting pending elements, to avoid recursion.) */ + +static void +output_init_element (value, type, field, pending) + tree value, type, field; + int pending; +{ + int duplicate = 0; + + if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE + || (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE + && !(TREE_CODE (value) == STRING_CST + && TREE_CODE (type) == ARRAY_TYPE + && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE) + && !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (value)), + TYPE_MAIN_VARIANT (type)))) + value = default_conversion (value); + + if (value == error_mark_node) + constructor_erroneous = 1; + else if (!TREE_CONSTANT (value)) + constructor_constant = 0; + else if (initializer_constant_valid_p (value, TREE_TYPE (value)) == 0 + || ((TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + && DECL_C_BIT_FIELD (field) + && TREE_CODE (value) != INTEGER_CST)) + constructor_simple = 0; + + if (require_constant_value && ! TREE_CONSTANT (value)) + { + error_init ("initializer element%s is not constant", + " for `%s'", NULL); + value = error_mark_node; + } + else if (require_constant_elements + && initializer_constant_valid_p (value, TREE_TYPE (value)) == 0) + { + error_init ("initializer element%s is not computable at load time", + " for `%s'", NULL); + value = error_mark_node; + } + + /* If this element duplicates one on constructor_pending_elts, + print a message and ignore it. Don't do this when we're + processing elements taken off constructor_pending_elts, + because we'd always get spurious errors. */ + if (pending) + { + if (TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE + || TREE_CODE (constructor_type) == ARRAY_TYPE) + { + if (pending_init_member (field)) + { + error_init ("duplicate initializer%s", " for `%s'", NULL); + duplicate = 1; + } + } + } + + /* If this element doesn't come next in sequence, + put it on constructor_pending_elts. */ + if (TREE_CODE (constructor_type) == ARRAY_TYPE + && !tree_int_cst_equal (field, constructor_unfilled_index)) + { + if (! duplicate) + /* The copy_node is needed in case field is actually + constructor_index, which is modified in place. */ + add_pending_init (copy_node (field), + digest_init (type, value, require_constant_value, + require_constant_elements)); + } + else if (TREE_CODE (constructor_type) == RECORD_TYPE + && field != constructor_unfilled_fields) + { + /* We do this for records but not for unions. In a union, + no matter which field is specified, it can be initialized + right away since it starts at the beginning of the union. */ + if (!duplicate) + add_pending_init (field, + digest_init (type, value, require_constant_value, + require_constant_elements)); + } + else + { + /* Otherwise, output this element either to + constructor_elements or to the assembler file. */ + + if (!duplicate) + { + if (! constructor_incremental) + { + if (field && TREE_CODE (field) == INTEGER_CST) + field = copy_node (field); + constructor_elements + = tree_cons (field, digest_init (type, value, + require_constant_value, + require_constant_elements), + constructor_elements); + } + else + { + /* Structure elements may require alignment. + Do this, if necessary. */ + if (TREE_CODE (constructor_type) == RECORD_TYPE) + { + /* Advance to offset of this element. */ + if (! tree_int_cst_equal (constructor_bit_index, + DECL_FIELD_BITPOS (field))) + { + /* By using unsigned arithmetic, the result will be + correct even in case of overflows, if BITS_PER_UNIT + is a power of two. */ + unsigned next = (TREE_INT_CST_LOW + (DECL_FIELD_BITPOS (field)) + / (unsigned)BITS_PER_UNIT); + unsigned here = (TREE_INT_CST_LOW + (constructor_bit_index) + / (unsigned)BITS_PER_UNIT); + + assemble_zeros ((next - here) + * (unsigned)BITS_PER_UNIT + / (unsigned)BITS_PER_UNIT); + } + } + output_constant (digest_init (type, value, + require_constant_value, + require_constant_elements), + int_size_in_bytes (type)); + + /* For a record or union, + keep track of end position of last field. */ + if (TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + { + tree temp = size_binop (PLUS_EXPR, DECL_FIELD_BITPOS (field), + DECL_SIZE (field)); + TREE_INT_CST_LOW (constructor_bit_index) + = TREE_INT_CST_LOW (temp); + TREE_INT_CST_HIGH (constructor_bit_index) + = TREE_INT_CST_HIGH (temp); + } + } + } + + /* Advance the variable that indicates sequential elements output. */ + if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + tree tem = size_binop (PLUS_EXPR, constructor_unfilled_index, + integer_one_node); + TREE_INT_CST_LOW (constructor_unfilled_index) + = TREE_INT_CST_LOW (tem); + TREE_INT_CST_HIGH (constructor_unfilled_index) + = TREE_INT_CST_HIGH (tem); + } + else if (TREE_CODE (constructor_type) == RECORD_TYPE) + constructor_unfilled_fields = TREE_CHAIN (constructor_unfilled_fields); + else if (TREE_CODE (constructor_type) == UNION_TYPE) + constructor_unfilled_fields = 0; + + /* Now output any pending elements which have become next. */ + if (pending) + output_pending_init_elements (0); + } +} + +/* Output any pending elements which have become next. + As we output elements, constructor_unfilled_{fields,index} + advances, which may cause other elements to become next; + if so, they too are output. + + If ALL is 0, we return when there are + no more pending elements to output now. + + If ALL is 1, we output space as necessary so that + we can output all the pending elements. */ + +static void +output_pending_init_elements (all) + int all; +{ + struct init_node *elt = constructor_pending_elts; + tree next; + + retry: + + /* Look thru the whole pending tree. + If we find an element that should be output now, + output it. Otherwise, set NEXT to the element + that comes first among those still pending. */ + + next = 0; + while (elt) + { + if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + if (tree_int_cst_equal (elt->purpose, + constructor_unfilled_index)) + output_init_element (elt->value, + TREE_TYPE (constructor_type), + constructor_unfilled_index, 0); + else if (tree_int_cst_lt (constructor_unfilled_index, + elt->purpose)) + { + /* Advance to the next smaller node. */ + if (elt->left) + elt = elt->left; + else + { + /* We have reached the smallest node bigger than the + current unfilled index. Fill the space first. */ + next = elt->purpose; + break; + } + } + else + { + /* Advance to the next bigger node. */ + if (elt->right) + elt = elt->right; + else + { + /* We have reached the biggest node in a subtree. Find + the parent of it, which is the next bigger node. */ + while (elt->parent && elt->parent->right == elt) + elt = elt->parent; + elt = elt->parent; + if (elt && tree_int_cst_lt (constructor_unfilled_index, + elt->purpose)) + { + next = elt->purpose; + break; + } + } + } + } + else if (TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + { + /* If the current record is complete we are done. */ + if (constructor_unfilled_fields == 0) + break; + if (elt->purpose == constructor_unfilled_fields) + { + output_init_element (elt->value, + TREE_TYPE (constructor_unfilled_fields), + constructor_unfilled_fields, + 0); + } + else if (tree_int_cst_lt (DECL_FIELD_BITPOS (constructor_unfilled_fields), + DECL_FIELD_BITPOS (elt->purpose))) + { + /* Advance to the next smaller node. */ + if (elt->left) + elt = elt->left; + else + { + /* We have reached the smallest node bigger than the + current unfilled field. Fill the space first. */ + next = elt->purpose; + break; + } + } + else + { + /* Advance to the next bigger node. */ + if (elt->right) + elt = elt->right; + else + { + /* We have reached the biggest node in a subtree. Find + the parent of it, which is the next bigger node. */ + while (elt->parent && elt->parent->right == elt) + elt = elt->parent; + elt = elt->parent; + if (elt + && tree_int_cst_lt (DECL_FIELD_BITPOS (constructor_unfilled_fields), + DECL_FIELD_BITPOS (elt->purpose))) + { + next = elt->purpose; + break; + } + } + } + } + } + + /* Ordinarily return, but not if we want to output all + and there are elements left. */ + if (! (all && next != 0)) + return; + + /* Generate space up to the position of NEXT. */ + if (constructor_incremental) + { + tree filled; + tree nextpos_tree = size_int (0); + + if (TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + { + tree tail; + /* Find the last field written out, if any. */ + for (tail = TYPE_FIELDS (constructor_type); tail; + tail = TREE_CHAIN (tail)) + if (TREE_CHAIN (tail) == constructor_unfilled_fields) + break; + + if (tail) + /* Find the offset of the end of that field. */ + filled = size_binop (CEIL_DIV_EXPR, + size_binop (PLUS_EXPR, + DECL_FIELD_BITPOS (tail), + DECL_SIZE (tail)), + size_int (BITS_PER_UNIT)); + else + filled = size_int (0); + + nextpos_tree = size_binop (CEIL_DIV_EXPR, + DECL_FIELD_BITPOS (next), + size_int (BITS_PER_UNIT)); + + TREE_INT_CST_HIGH (constructor_bit_index) + = TREE_INT_CST_HIGH (DECL_FIELD_BITPOS (next)); + TREE_INT_CST_LOW (constructor_bit_index) + = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (next)); + constructor_unfilled_fields = next; + } + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + filled = size_binop (MULT_EXPR, constructor_unfilled_index, + size_in_bytes (TREE_TYPE (constructor_type))); + nextpos_tree + = size_binop (MULT_EXPR, next, + size_in_bytes (TREE_TYPE (constructor_type))); + TREE_INT_CST_LOW (constructor_unfilled_index) + = TREE_INT_CST_LOW (next); + TREE_INT_CST_HIGH (constructor_unfilled_index) + = TREE_INT_CST_HIGH (next); + } + else + filled = 0; + + if (filled) + { + int nextpos = TREE_INT_CST_LOW (nextpos_tree); + + assemble_zeros (nextpos - TREE_INT_CST_LOW (filled)); + } + } + else + { + /* If it's not incremental, just skip over the gap, + so that after jumping to retry we will output the next + successive element. */ + if (TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + constructor_unfilled_fields = next; + else if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + TREE_INT_CST_LOW (constructor_unfilled_index) + = TREE_INT_CST_LOW (next); + TREE_INT_CST_HIGH (constructor_unfilled_index) + = TREE_INT_CST_HIGH (next); + } + } + + /* ELT now points to the node in the pending tree with the next + initializer to output. */ + goto retry; +} + +/* Add one non-braced element to the current constructor level. + This adjusts the current position within the constructor's type. + This may also start or terminate implicit levels + to handle a partly-braced initializer. + + Once this has found the correct level for the new element, + it calls output_init_element. + + Note: if we are incrementally outputting this constructor, + this function may be called with a null argument + representing a sub-constructor that was already incrementally output. + When that happens, we output nothing, but we do the bookkeeping + to skip past that element of the current constructor. */ + +void +process_init_element (value) + tree value; +{ + tree orig_value = value; + int string_flag = value != 0 && TREE_CODE (value) == STRING_CST; + + /* Handle superfluous braces around string cst as in + char x[] = {"foo"}; */ + if (string_flag + && constructor_type + && TREE_CODE (constructor_type) == ARRAY_TYPE + && TREE_CODE (TREE_TYPE (constructor_type)) == INTEGER_TYPE + && integer_zerop (constructor_unfilled_index)) + { + constructor_stack->replacement_value = value; + return; + } + + if (constructor_stack->replacement_value != 0) + { + error_init ("excess elements in struct initializer%s", + " after `%s'", NULL_PTR); + return; + } + + /* Ignore elements of a brace group if it is entirely superfluous + and has already been diagnosed. */ + if (constructor_type == 0) + return; + + /* If we've exhausted any levels that didn't have braces, + pop them now. */ + while (constructor_stack->implicit) + { + if ((TREE_CODE (constructor_type) == RECORD_TYPE + || TREE_CODE (constructor_type) == UNION_TYPE) + && constructor_fields == 0) + process_init_element (pop_init_level (1)); + else if (TREE_CODE (constructor_type) == ARRAY_TYPE + && (constructor_max_index == 0 + || tree_int_cst_lt (constructor_max_index, + constructor_index))) + process_init_element (pop_init_level (1)); + else + break; + } + + while (1) + { + if (TREE_CODE (constructor_type) == RECORD_TYPE) + { + tree fieldtype; + enum tree_code fieldcode; + + if (constructor_fields == 0) + { + pedwarn_init ("excess elements in struct initializer%s", + " after `%s'", NULL_PTR); + break; + } + + fieldtype = TREE_TYPE (constructor_fields); + if (fieldtype != error_mark_node) + fieldtype = TYPE_MAIN_VARIANT (fieldtype); + fieldcode = TREE_CODE (fieldtype); + + /* Accept a string constant to initialize a subarray. */ + if (value != 0 + && fieldcode == ARRAY_TYPE + && TREE_CODE (TREE_TYPE (fieldtype)) == INTEGER_TYPE + && string_flag) + value = orig_value; + /* Otherwise, if we have come to a subaggregate, + and we don't have an element of its type, push into it. */ + else if (value != 0 && !constructor_no_implicit + && value != error_mark_node + && TYPE_MAIN_VARIANT (TREE_TYPE (value)) != fieldtype + && (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE + || fieldcode == UNION_TYPE)) + { + push_init_level (1); + continue; + } + + if (value) + { + push_member_name (constructor_fields); + output_init_element (value, fieldtype, constructor_fields, 1); + RESTORE_SPELLING_DEPTH (constructor_depth); + } + else + /* Do the bookkeeping for an element that was + directly output as a constructor. */ + { + /* For a record, keep track of end position of last field. */ + tree temp = size_binop (PLUS_EXPR, + DECL_FIELD_BITPOS (constructor_fields), + DECL_SIZE (constructor_fields)); + TREE_INT_CST_LOW (constructor_bit_index) + = TREE_INT_CST_LOW (temp); + TREE_INT_CST_HIGH (constructor_bit_index) + = TREE_INT_CST_HIGH (temp); + + constructor_unfilled_fields = TREE_CHAIN (constructor_fields); + } + + constructor_fields = TREE_CHAIN (constructor_fields); + /* Skip any nameless bit fields at the beginning. */ + while (constructor_fields != 0 + && DECL_C_BIT_FIELD (constructor_fields) + && DECL_NAME (constructor_fields) == 0) + constructor_fields = TREE_CHAIN (constructor_fields); + break; + } + if (TREE_CODE (constructor_type) == UNION_TYPE) + { + tree fieldtype; + enum tree_code fieldcode; + + if (constructor_fields == 0) + { + pedwarn_init ("excess elements in union initializer%s", + " after `%s'", NULL_PTR); + break; + } + + fieldtype = TREE_TYPE (constructor_fields); + if (fieldtype != error_mark_node) + fieldtype = TYPE_MAIN_VARIANT (fieldtype); + fieldcode = TREE_CODE (fieldtype); + + /* Accept a string constant to initialize a subarray. */ + if (value != 0 + && fieldcode == ARRAY_TYPE + && TREE_CODE (TREE_TYPE (fieldtype)) == INTEGER_TYPE + && string_flag) + value = orig_value; + /* Otherwise, if we have come to a subaggregate, + and we don't have an element of its type, push into it. */ + else if (value != 0 && !constructor_no_implicit + && value != error_mark_node + && TYPE_MAIN_VARIANT (TREE_TYPE (value)) != fieldtype + && (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE + || fieldcode == UNION_TYPE)) + { + push_init_level (1); + continue; + } + + if (value) + { + push_member_name (constructor_fields); + output_init_element (value, fieldtype, constructor_fields, 1); + RESTORE_SPELLING_DEPTH (constructor_depth); + } + else + /* Do the bookkeeping for an element that was + directly output as a constructor. */ + { + TREE_INT_CST_LOW (constructor_bit_index) + = TREE_INT_CST_LOW (DECL_SIZE (constructor_fields)); + TREE_INT_CST_HIGH (constructor_bit_index) + = TREE_INT_CST_HIGH (DECL_SIZE (constructor_fields)); + + constructor_unfilled_fields = TREE_CHAIN (constructor_fields); + } + + constructor_fields = 0; + break; + } + if (TREE_CODE (constructor_type) == ARRAY_TYPE) + { + tree elttype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type)); + enum tree_code eltcode = TREE_CODE (elttype); + + /* Accept a string constant to initialize a subarray. */ + if (value != 0 + && eltcode == ARRAY_TYPE + && TREE_CODE (TREE_TYPE (elttype)) == INTEGER_TYPE + && string_flag) + value = orig_value; + /* Otherwise, if we have come to a subaggregate, + and we don't have an element of its type, push into it. */ + else if (value != 0 && !constructor_no_implicit + && value != error_mark_node + && TYPE_MAIN_VARIANT (TREE_TYPE (value)) != elttype + && (eltcode == RECORD_TYPE || eltcode == ARRAY_TYPE + || eltcode == UNION_TYPE)) + { + push_init_level (1); + continue; + } + + if (constructor_max_index != 0 + && tree_int_cst_lt (constructor_max_index, constructor_index)) + { + pedwarn_init ("excess elements in array initializer%s", + " after `%s'", NULL_PTR); + break; + } + + /* In the case of [LO .. HI] = VALUE, only evaluate VALUE once. */ + if (constructor_range_end) + { + if (constructor_max_index != 0 + && tree_int_cst_lt (constructor_max_index, + constructor_range_end)) + { + pedwarn_init ("excess elements in array initializer%s", + " after `%s'", NULL_PTR); + TREE_INT_CST_HIGH (constructor_range_end) + = TREE_INT_CST_HIGH (constructor_max_index); + TREE_INT_CST_LOW (constructor_range_end) + = TREE_INT_CST_LOW (constructor_max_index); + } + + value = save_expr (value); + } + + /* Now output the actual element. + Ordinarily, output once. + If there is a range, repeat it till we advance past the range. */ + do + { + tree tem; + + if (value) + { + push_array_bounds (TREE_INT_CST_LOW (constructor_index)); + output_init_element (value, elttype, constructor_index, 1); + RESTORE_SPELLING_DEPTH (constructor_depth); + } + + tem = size_binop (PLUS_EXPR, constructor_index, + integer_one_node); + TREE_INT_CST_LOW (constructor_index) = TREE_INT_CST_LOW (tem); + TREE_INT_CST_HIGH (constructor_index) = TREE_INT_CST_HIGH (tem); + + if (!value) + /* If we are doing the bookkeeping for an element that was + directly output as a constructor, + we must update constructor_unfilled_index. */ + { + TREE_INT_CST_LOW (constructor_unfilled_index) + = TREE_INT_CST_LOW (constructor_index); + TREE_INT_CST_HIGH (constructor_unfilled_index) + = TREE_INT_CST_HIGH (constructor_index); + } + } + while (! (constructor_range_end == 0 + || tree_int_cst_lt (constructor_range_end, + constructor_index))); + + break; + } + + /* Handle the sole element allowed in a braced initializer + for a scalar variable. */ + if (constructor_fields == 0) + { + pedwarn_init ("excess elements in scalar initializer%s", + " after `%s'", NULL_PTR); + break; + } + + if (value) + output_init_element (value, constructor_type, NULL_TREE, 1); + constructor_fields = 0; + break; + } + + /* If the (lexically) previous elments are not now saved, + we can discard the storage for them. */ + if (constructor_incremental && constructor_pending_elts == 0 && value != 0 + && constructor_stack == 0) + clear_momentary (); +} + +/* Expand an ASM statement with operands, handling output operands + that are not variables or INDIRECT_REFS by transforming such + cases into cases that expand_asm_operands can handle. + + Arguments are same as for expand_asm_operands. */ + +void +c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line) + tree string, outputs, inputs, clobbers; + int vol; + char *filename; + int line; +{ + int noutputs = list_length (outputs); + register int i; + /* o[I] is the place that output number I should be written. */ + register tree *o = (tree *) alloca (noutputs * sizeof (tree)); + register tree tail; + + if (TREE_CODE (string) == ADDR_EXPR) + string = TREE_OPERAND (string, 0); + if (TREE_CODE (string) != STRING_CST) + { + error ("asm template is not a string constant"); + return; + } + + /* Record the contents of OUTPUTS before it is modified. */ + for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) + o[i] = TREE_VALUE (tail); + + /* Perform default conversions on array and function inputs. */ + /* Don't do this for other types-- + it would screw up operands expected to be in memory. */ + for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), i++) + if (TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == FUNCTION_TYPE) + TREE_VALUE (tail) = default_conversion (TREE_VALUE (tail)); + + /* Generate the ASM_OPERANDS insn; + store into the TREE_VALUEs of OUTPUTS some trees for + where the values were actually stored. */ + expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line); + + /* Copy all the intermediate outputs into the specified outputs. */ + for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) + { + if (o[i] != TREE_VALUE (tail)) + { + expand_expr (build_modify_expr (o[i], NOP_EXPR, TREE_VALUE (tail)), + NULL_RTX, VOIDmode, EXPAND_NORMAL); + free_temp_slots (); + } + /* Detect modification of read-only values. + (Otherwise done by build_modify_expr.) */ + else + { + tree type = TREE_TYPE (o[i]); + if (TREE_READONLY (o[i]) + || TYPE_READONLY (type) + || ((TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE) + && C_TYPE_FIELDS_READONLY (type))) + readonly_warning (o[i], "modification by `asm'"); + } + } + + /* Those MODIFY_EXPRs could do autoincrements. */ + emit_queue (); +} + +/* Expand a C `return' statement. + RETVAL is the expression for what to return, + or a null pointer for `return;' with no value. */ + +void +c_expand_return (retval) + tree retval; +{ + tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl)); + + if (TREE_THIS_VOLATILE (current_function_decl)) + warning ("function declared `noreturn' has a `return' statement"); + + if (!retval) + { + current_function_returns_null = 1; + if (warn_return_type && valtype != 0 && TREE_CODE (valtype) != VOID_TYPE) + warning ("`return' with no value, in function returning non-void"); + expand_null_return (); + } + else if (valtype == 0 || TREE_CODE (valtype) == VOID_TYPE) + { + current_function_returns_null = 1; + if (pedantic || TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE) + pedwarn ("`return' with a value, in function returning void"); + expand_return (retval); + } + else + { + tree t = convert_for_assignment (valtype, retval, "return", + NULL_TREE, NULL_TREE, 0); + tree res = DECL_RESULT (current_function_decl); + tree inner; + + if (t == error_mark_node) + return; + + inner = t = convert (TREE_TYPE (res), t); + + /* Strip any conversions, additions, and subtractions, and see if + we are returning the address of a local variable. Warn if so. */ + while (1) + { + switch (TREE_CODE (inner)) + { + case NOP_EXPR: case NON_LVALUE_EXPR: case CONVERT_EXPR: + case PLUS_EXPR: + inner = TREE_OPERAND (inner, 0); + continue; + + case MINUS_EXPR: + /* If the second operand of the MINUS_EXPR has a pointer + type (or is converted from it), this may be valid, so + don't give a warning. */ + { + tree op1 = TREE_OPERAND (inner, 1); + + while (! POINTER_TYPE_P (TREE_TYPE (op1)) + && (TREE_CODE (op1) == NOP_EXPR + || TREE_CODE (op1) == NON_LVALUE_EXPR + || TREE_CODE (op1) == CONVERT_EXPR)) + op1 = TREE_OPERAND (op1, 0); + + if (POINTER_TYPE_P (TREE_TYPE (op1))) + break; + + inner = TREE_OPERAND (inner, 0); + continue; + } + + case ADDR_EXPR: + inner = TREE_OPERAND (inner, 0); + + while (TREE_CODE_CLASS (TREE_CODE (inner)) == 'r') + inner = TREE_OPERAND (inner, 0); + + if (TREE_CODE (inner) == VAR_DECL + && ! DECL_EXTERNAL (inner) + && ! TREE_STATIC (inner) + && DECL_CONTEXT (inner) == current_function_decl) + warning ("function returns address of local variable"); + break; + + default: + break; + } + + break; + } + + t = build (MODIFY_EXPR, TREE_TYPE (res), res, t); + TREE_SIDE_EFFECTS (t) = 1; + expand_return (t); + current_function_returns_value = 1; + } +} + +/* Start a C switch statement, testing expression EXP. + Return EXP if it is valid, an error node otherwise. */ + +tree +c_expand_start_case (exp) + tree exp; +{ + register enum tree_code code = TREE_CODE (TREE_TYPE (exp)); + tree type = TREE_TYPE (exp); + + if (code != INTEGER_TYPE && code != ENUMERAL_TYPE && code != ERROR_MARK) + { + error ("switch quantity not an integer"); + exp = error_mark_node; + } + else + { + tree index; + type = TYPE_MAIN_VARIANT (TREE_TYPE (exp)); + + if (warn_traditional + && (type == long_integer_type_node + || type == long_unsigned_type_node)) + pedwarn ("`long' switch expression not converted to `int' in ANSI C"); + + exp = default_conversion (exp); + type = TREE_TYPE (exp); + index = get_unwidened (exp, NULL_TREE); + /* We can't strip a conversion from a signed type to an unsigned, + because if we did, int_fits_type_p would do the wrong thing + when checking case values for being in range, + and it's too hard to do the right thing. */ + if (TREE_UNSIGNED (TREE_TYPE (exp)) + == TREE_UNSIGNED (TREE_TYPE (index))) + exp = index; + } + + expand_start_case (1, exp, type, "switch statement"); + + return exp; +} diff --git a/gcc_arm/caller-save.c b/gcc_arm/caller-save.c new file mode 100755 index 0000000..7c390a5 --- /dev/null +++ b/gcc_arm/caller-save.c @@ -0,0 +1,757 @@ +/* Save and restore call-clobbered registers which are live across a call. + Copyright (C) 1989, 1992, 94-95, 97, 98, 1999 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "rtl.h" +#include "insn-config.h" +#include "flags.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "recog.h" +#include "basic-block.h" +#include "reload.h" +#include "expr.h" +#include "toplev.h" + +#ifndef MAX_MOVE_MAX +#define MAX_MOVE_MAX MOVE_MAX +#endif + +#ifndef MIN_UNITS_PER_WORD +#define MIN_UNITS_PER_WORD UNITS_PER_WORD +#endif + +#define MOVE_MAX_WORDS (MOVE_MAX / UNITS_PER_WORD) + +/* Modes for each hard register that we can save. The smallest mode is wide + enough to save the entire contents of the register. When saving the + register because it is live we first try to save in multi-register modes. + If that is not possible the save is done one register at a time. */ + +static enum machine_mode + regno_save_mode[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MIN_UNITS_PER_WORD + 1]; + +/* For each hard register, a place on the stack where it can be saved, + if needed. */ + +static rtx + regno_save_mem[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MIN_UNITS_PER_WORD + 1]; + +/* We will only make a register eligible for caller-save if it can be + saved in its widest mode with a simple SET insn as long as the memory + address is valid. We record the INSN_CODE is those insns here since + when we emit them, the addresses might not be valid, so they might not + be recognized. */ + +static enum insn_code + reg_save_code[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MIN_UNITS_PER_WORD + 1]; +static enum insn_code + reg_restore_code[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MIN_UNITS_PER_WORD + 1]; + +/* Set of hard regs currently residing in save area (during insn scan). */ + +static HARD_REG_SET hard_regs_saved; + +/* Number of registers currently in hard_regs_saved. */ + +static int n_regs_saved; + +/* Computed by mark_referenced_regs, all regs referenced in a given + insn. */ +static HARD_REG_SET referenced_regs; + +/* Computed in mark_set_regs, holds all registers set by the current + instruction. */ +static HARD_REG_SET this_insn_sets; + + +static void mark_set_regs PROTO((rtx, rtx)); +static void mark_referenced_regs PROTO((rtx)); +static int insert_save PROTO((struct insn_chain *, int, int, + HARD_REG_SET *)); +static int insert_restore PROTO((struct insn_chain *, int, int, + int)); +static void insert_one_insn PROTO((struct insn_chain *, int, + enum insn_code, rtx)); + +/* Initialize for caller-save. + + Look at all the hard registers that are used by a call and for which + regclass.c has not already excluded from being used across a call. + + Ensure that we can find a mode to save the register and that there is a + simple insn to save and restore the register. This latter check avoids + problems that would occur if we tried to save the MQ register of some + machines directly into memory. */ + +void +init_caller_save () +{ + char *first_obj = (char *) oballoc (0); + rtx addr_reg; + int offset; + rtx address; + int i, j; + + /* First find all the registers that we need to deal with and all + the modes that they can have. If we can't find a mode to use, + we can't have the register live over calls. */ + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + { + if (call_used_regs[i] && ! call_fixed_regs[i]) + { + for (j = 1; j <= MOVE_MAX_WORDS; j++) + { + regno_save_mode[i][j] = HARD_REGNO_CALLER_SAVE_MODE (i, j); + if (regno_save_mode[i][j] == VOIDmode && j == 1) + { + call_fixed_regs[i] = 1; + SET_HARD_REG_BIT (call_fixed_reg_set, i); + } + } + } + else + regno_save_mode[i][1] = VOIDmode; + } + + /* The following code tries to approximate the conditions under which + we can easily save and restore a register without scratch registers or + other complexities. It will usually work, except under conditions where + the validity of an insn operand is dependent on the address offset. + No such cases are currently known. + + We first find a typical offset from some BASE_REG_CLASS register. + This address is chosen by finding the first register in the class + and by finding the smallest power of two that is a valid offset from + that register in every mode we will use to save registers. */ + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (TEST_HARD_REG_BIT (reg_class_contents[(int) BASE_REG_CLASS], i)) + break; + + if (i == FIRST_PSEUDO_REGISTER) + abort (); + + addr_reg = gen_rtx_REG (Pmode, i); + + for (offset = 1 << (HOST_BITS_PER_INT / 2); offset; offset >>= 1) + { + address = gen_rtx_PLUS (Pmode, addr_reg, GEN_INT (offset)); + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (regno_save_mode[i][1] != VOIDmode + && ! strict_memory_address_p (regno_save_mode[i][1], address)) + break; + + if (i == FIRST_PSEUDO_REGISTER) + break; + } + + /* If we didn't find a valid address, we must use register indirect. */ + if (offset == 0) + address = addr_reg; + + /* Next we try to form an insn to save and restore the register. We + see if such an insn is recognized and meets its constraints. */ + + start_sequence (); + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + for (j = 1; j <= MOVE_MAX_WORDS; j++) + if (regno_save_mode[i][j] != VOIDmode) + { + rtx mem = gen_rtx_MEM (regno_save_mode[i][j], address); + rtx reg = gen_rtx_REG (regno_save_mode[i][j], i); + rtx savepat = gen_rtx_SET (VOIDmode, mem, reg); + rtx restpat = gen_rtx_SET (VOIDmode, reg, mem); + rtx saveinsn = emit_insn (savepat); + rtx restinsn = emit_insn (restpat); + int ok; + + reg_save_code[i][j] = recog_memoized (saveinsn); + reg_restore_code[i][j] = recog_memoized (restinsn); + + /* Now extract both insns and see if we can meet their + constraints. */ + ok = (reg_save_code[i][j] != (enum insn_code)-1 + && reg_restore_code[i][j] != (enum insn_code)-1); + if (ok) + { + extract_insn (saveinsn); + ok = constrain_operands (1); + extract_insn (restinsn); + ok &= constrain_operands (1); + } + + if (! ok) + { + regno_save_mode[i][j] = VOIDmode; + if (j == 1) + { + call_fixed_regs[i] = 1; + SET_HARD_REG_BIT (call_fixed_reg_set, i); + } + } + } + + end_sequence (); + + obfree (first_obj); +} + +/* Initialize save areas by showing that we haven't allocated any yet. */ + +void +init_save_areas () +{ + int i, j; + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + for (j = 1; j <= MOVE_MAX_WORDS; j++) + regno_save_mem[i][j] = 0; +} + +/* Allocate save areas for any hard registers that might need saving. + We take a conservative approach here and look for call-clobbered hard + registers that are assigned to pseudos that cross calls. This may + overestimate slightly (especially if some of these registers are later + used as spill registers), but it should not be significant. + + Future work: + + In the fallback case we should iterate backwards across all possible + modes for the save, choosing the largest available one instead of + falling back to the smallest mode immediately. (eg TF -> DF -> SF). + + We do not try to use "move multiple" instructions that exist + on some machines (such as the 68k moveml). It could be a win to try + and use them when possible. The hard part is doing it in a way that is + machine independent since they might be saving non-consecutive + registers. (imagine caller-saving d0,d1,a0,a1 on the 68k) */ + +void +setup_save_areas () +{ + int i, j, k; + HARD_REG_SET hard_regs_used; + + /* Allocate space in the save area for the largest multi-register + pseudos first, then work backwards to single register + pseudos. */ + + /* Find and record all call-used hard-registers in this function. */ + CLEAR_HARD_REG_SET (hard_regs_used); + for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) + if (reg_renumber[i] >= 0 && REG_N_CALLS_CROSSED (i) > 0) + { + int regno = reg_renumber[i]; + int endregno + = regno + HARD_REGNO_NREGS (regno, GET_MODE (regno_reg_rtx[i])); + int nregs = endregno - regno; + + for (j = 0; j < nregs; j++) + { + if (call_used_regs[regno+j]) + SET_HARD_REG_BIT (hard_regs_used, regno+j); + } + } + + /* Now run through all the call-used hard-registers and allocate + space for them in the caller-save area. Try to allocate space + in a manner which allows multi-register saves/restores to be done. */ + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + for (j = MOVE_MAX_WORDS; j > 0; j--) + { + int do_save = 1; + + /* If no mode exists for this size, try another. Also break out + if we have already saved this hard register. */ + if (regno_save_mode[i][j] == VOIDmode || regno_save_mem[i][1] != 0) + continue; + + /* See if any register in this group has been saved. */ + for (k = 0; k < j; k++) + if (regno_save_mem[i + k][1]) + { + do_save = 0; + break; + } + if (! do_save) + continue; + + for (k = 0; k < j; k++) + if (! TEST_HARD_REG_BIT (hard_regs_used, i + k)) + { + do_save = 0; + break; + } + if (! do_save) + continue; + + /* We have found an acceptable mode to store in. */ + regno_save_mem[i][j] + = assign_stack_local (regno_save_mode[i][j], + GET_MODE_SIZE (regno_save_mode[i][j]), 0); + + /* Setup single word save area just in case... */ + for (k = 0; k < j; k++) + { + /* This should not depend on WORDS_BIG_ENDIAN. + The order of words in regs is the same as in memory. */ + rtx temp = gen_rtx_MEM (regno_save_mode[i+k][1], + XEXP (regno_save_mem[i][j], 0)); + + regno_save_mem[i+k][1] + = adj_offsettable_operand (temp, k * UNITS_PER_WORD); + } + } +} + +/* Find the places where hard regs are live across calls and save them. */ +void +save_call_clobbered_regs () +{ + struct insn_chain *chain, *next; + + CLEAR_HARD_REG_SET (hard_regs_saved); + n_regs_saved = 0; + + for (chain = reload_insn_chain; chain != 0; chain = next) + { + rtx insn = chain->insn; + enum rtx_code code = GET_CODE (insn); + + next = chain->next; + + if (chain->is_caller_save_insn) + abort (); + + if (GET_RTX_CLASS (code) == 'i') + { + /* If some registers have been saved, see if INSN references + any of them. We must restore them before the insn if so. */ + + if (n_regs_saved) + { + int regno; + + if (code == JUMP_INSN) + /* Restore all registers if this is a JUMP_INSN. */ + COPY_HARD_REG_SET (referenced_regs, hard_regs_saved); + else + { + CLEAR_HARD_REG_SET (referenced_regs); + mark_referenced_regs (PATTERN (insn)); + AND_HARD_REG_SET (referenced_regs, hard_regs_saved); + } + + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if (TEST_HARD_REG_BIT (referenced_regs, regno)) + regno += insert_restore (chain, 1, regno, MOVE_MAX_WORDS); + } + + if (code == CALL_INSN) + { + rtx x; + int regno, nregs; + HARD_REG_SET hard_regs_to_save; + + /* Use the register life information in CHAIN to compute which + regs are live before the call. */ + REG_SET_TO_HARD_REG_SET (hard_regs_to_save, chain->live_before); + compute_use_by_pseudos (&hard_regs_to_save, chain->live_before); + + /* Record all registers set in this call insn. These don't need + to be saved. */ + CLEAR_HARD_REG_SET (this_insn_sets); + note_stores (PATTERN (insn), mark_set_regs); + + /* Compute which hard regs must be saved before this call. */ + AND_COMPL_HARD_REG_SET (hard_regs_to_save, call_fixed_reg_set); + AND_COMPL_HARD_REG_SET (hard_regs_to_save, this_insn_sets); + AND_COMPL_HARD_REG_SET (hard_regs_to_save, hard_regs_saved); + AND_HARD_REG_SET (hard_regs_to_save, call_used_reg_set); + + /* Registers used for function parameters need not be saved. */ + for (x = CALL_INSN_FUNCTION_USAGE (insn); x != 0; + x = XEXP (x, 1)) + { + rtx y; + + if (GET_CODE (XEXP (x, 0)) != USE) + continue; + y = XEXP (XEXP (x, 0), 0); + if (GET_CODE (y) != REG) + abort (); + regno = REGNO (y); + if (REGNO (y) >= FIRST_PSEUDO_REGISTER) + abort (); + nregs = HARD_REGNO_NREGS (regno, GET_MODE (y)); + while (nregs-- > 0) + CLEAR_HARD_REG_BIT (hard_regs_to_save, regno + nregs); + } + + /* Neither do registers for which we find a death note. */ + for (x = REG_NOTES (insn); x != 0; x = XEXP (x, 1)) + { + rtx y = XEXP (x, 0); + + if (REG_NOTE_KIND (x) != REG_DEAD) + continue; + if (GET_CODE (y) != REG) + abort (); + regno = REGNO (y); + + if (regno >= FIRST_PSEUDO_REGISTER) + regno = reg_renumber[regno]; + if (regno < 0) + continue; + nregs = HARD_REGNO_NREGS (regno, GET_MODE (y)); + while (nregs-- > 0) + CLEAR_HARD_REG_BIT (hard_regs_to_save, regno + nregs); + } + + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if (TEST_HARD_REG_BIT (hard_regs_to_save, regno)) + regno += insert_save (chain, 1, regno, &hard_regs_to_save); + + /* Must recompute n_regs_saved. */ + n_regs_saved = 0; + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if (TEST_HARD_REG_BIT (hard_regs_saved, regno)) + n_regs_saved++; + } + } + + if (chain->next == 0 || chain->next->block > chain->block) + { + int regno; + /* At the end of the basic block, we must restore any registers that + remain saved. If the last insn in the block is a JUMP_INSN, put + the restore before the insn, otherwise, put it after the insn. */ + + if (n_regs_saved) + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if (TEST_HARD_REG_BIT (hard_regs_saved, regno)) + regno += insert_restore (chain, GET_CODE (insn) == JUMP_INSN, + regno, MOVE_MAX_WORDS); + } + } +} + +/* Here from note_stores when an insn stores a value in a register. + Set the proper bit or bits in this_insn_sets. All pseudos that have + been assigned hard regs have had their register number changed already, + so we can ignore pseudos. */ +static void +mark_set_regs (reg, setter) + rtx reg; + rtx setter ATTRIBUTE_UNUSED; +{ + register int regno, endregno, i; + enum machine_mode mode = GET_MODE (reg); + int word = 0; + + if (GET_CODE (reg) == SUBREG) + { + word = SUBREG_WORD (reg); + reg = SUBREG_REG (reg); + } + + if (GET_CODE (reg) != REG || REGNO (reg) >= FIRST_PSEUDO_REGISTER) + return; + + regno = REGNO (reg) + word; + endregno = regno + HARD_REGNO_NREGS (regno, mode); + + for (i = regno; i < endregno; i++) + SET_HARD_REG_BIT (this_insn_sets, i); +} + +/* Walk X and record all referenced registers in REFERENCED_REGS. */ +static void +mark_referenced_regs (x) + rtx x; +{ + enum rtx_code code = GET_CODE (x); + char *fmt; + int i, j; + + if (code == SET) + mark_referenced_regs (SET_SRC (x)); + if (code == SET || code == CLOBBER) + { + x = SET_DEST (x); + code = GET_CODE (x); + if (code == REG || code == PC || code == CC0 + || (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG)) + return; + } + if (code == MEM || code == SUBREG) + { + x = XEXP (x, 0); + code = GET_CODE (x); + } + + if (code == REG) + { + int regno = REGNO (x); + int hardregno = (regno < FIRST_PSEUDO_REGISTER ? regno + : reg_renumber[regno]); + + if (hardregno >= 0) + { + int nregs = HARD_REGNO_NREGS (hardregno, GET_MODE (x)); + while (nregs-- > 0) + SET_HARD_REG_BIT (referenced_regs, hardregno + nregs); + } + /* If this is a pseudo that did not get a hard register, scan its + memory location, since it might involve the use of another + register, which might be saved. */ + else if (reg_equiv_mem[regno] != 0) + mark_referenced_regs (XEXP (reg_equiv_mem[regno], 0)); + else if (reg_equiv_address[regno] != 0) + mark_referenced_regs (reg_equiv_address[regno]); + return; + } + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + mark_referenced_regs (XEXP (x, i)); + else if (fmt[i] == 'E') + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + mark_referenced_regs (XVECEXP (x, i, j)); + } +} + +/* Insert a sequence of insns to restore. Place these insns in front of + CHAIN if BEFORE_P is nonzero, behind the insn otherwise. MAXRESTORE is + the maximum number of registers which should be restored during this call. + It should never be less than 1 since we only work with entire registers. + + Note that we have verified in init_caller_save that we can do this + with a simple SET, so use it. Set INSN_CODE to what we save there + since the address might not be valid so the insn might not be recognized. + These insns will be reloaded and have register elimination done by + find_reload, so we need not worry about that here. + + Return the extra number of registers saved. */ + +static int +insert_restore (chain, before_p, regno, maxrestore) + struct insn_chain *chain; + int before_p; + int regno; + int maxrestore; +{ + int i; + rtx pat = NULL_RTX; + enum insn_code code = CODE_FOR_nothing; + int numregs = 0; + + /* A common failure mode if register status is not correct in the RTL + is for this routine to be called with a REGNO we didn't expect to + save. That will cause us to write an insn with a (nil) SET_DEST + or SET_SRC. Instead of doing so and causing a crash later, check + for this common case and abort here instead. This will remove one + step in debugging such problems. */ + + if (regno_save_mem[regno][1] == 0) + abort (); + + /* Get the pattern to emit and update our status. + + See if we can restore `maxrestore' registers at once. Work + backwards to the single register case. */ + for (i = maxrestore; i > 0; i--) + { + int j, k; + int ok = 1; + + if (regno_save_mem[regno][i] == 0) + continue; + + for (j = 0; j < i; j++) + if (! TEST_HARD_REG_BIT (hard_regs_saved, regno + j)) + { + ok = 0; + break; + } + /* Must do this one restore at a time */ + if (! ok) + continue; + + pat = gen_rtx_SET (VOIDmode, + gen_rtx_REG (GET_MODE (regno_save_mem[regno][i]), + regno), + regno_save_mem[regno][i]); + code = reg_restore_code[regno][i]; + + /* Clear status for all registers we restored. */ + for (k = 0; k < i; k++) + { + CLEAR_HARD_REG_BIT (hard_regs_saved, regno + k); + n_regs_saved--; + } + + numregs = i; + break; + } + + insert_one_insn (chain, before_p, code, pat); + + /* Tell our callers how many extra registers we saved/restored */ + return numregs - 1; +} + +/* Like insert_restore above, but save registers instead. */ +static int +insert_save (chain, before_p, regno, to_save) + struct insn_chain *chain; + int before_p; + int regno; + HARD_REG_SET *to_save; +{ + int i; + rtx pat = NULL_RTX; + enum insn_code code = CODE_FOR_nothing; + int numregs = 0; + + /* A common failure mode if register status is not correct in the RTL + is for this routine to be called with a REGNO we didn't expect to + save. That will cause us to write an insn with a (nil) SET_DEST + or SET_SRC. Instead of doing so and causing a crash later, check + for this common case and abort here instead. This will remove one + step in debugging such problems. */ + + if (regno_save_mem[regno][1] == 0) + abort (); + + /* Get the pattern to emit and update our status. + + See if we can save several registers with a single instruction. + Work backwards to the single register case. */ + for (i = MOVE_MAX_WORDS; i > 0; i--) + { + int j, k; + int ok = 1; + if (regno_save_mem[regno][i] == 0) + continue; + + for (j = 0; j < i; j++) + if (! TEST_HARD_REG_BIT (*to_save, regno + j)) + { + ok = 0; + break; + } + /* Must do this one save at a time */ + if (! ok) + continue; + + pat = gen_rtx_SET (VOIDmode, regno_save_mem[regno][i], + gen_rtx_REG (GET_MODE (regno_save_mem[regno][i]), + regno)); + code = reg_save_code[regno][i]; + + /* Set hard_regs_saved for all the registers we saved. */ + for (k = 0; k < i; k++) + { + SET_HARD_REG_BIT (hard_regs_saved, regno + k); + n_regs_saved++; + } + + numregs = i; + break; + } + + insert_one_insn (chain, before_p, code, pat); + + /* Tell our callers how many extra registers we saved/restored */ + return numregs - 1; +} + +/* Emit a new caller-save insn and set the code. */ +static void +insert_one_insn (chain, before_p, code, pat) + struct insn_chain *chain; + int before_p; + enum insn_code code; + rtx pat; +{ + rtx insn = chain->insn; + struct insn_chain *new; + +#ifdef HAVE_cc0 + /* If INSN references CC0, put our insns in front of the insn that sets + CC0. This is always safe, since the only way we could be passed an + insn that references CC0 is for a restore, and doing a restore earlier + isn't a problem. We do, however, assume here that CALL_INSNs don't + reference CC0. Guard against non-INSN's like CODE_LABEL. */ + + if ((GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN) + && before_p + && reg_referenced_p (cc0_rtx, PATTERN (insn))) + chain = chain->prev, insn = chain->insn; +#endif + + new = new_insn_chain (); + if (before_p) + { + new->prev = chain->prev; + if (new->prev != 0) + new->prev->next = new; + else + reload_insn_chain = new; + + chain->prev = new; + new->next = chain; + new->insn = emit_insn_before (pat, insn); + /* ??? It would be nice if we could exclude the already / still saved + registers from the live sets. */ + COPY_REG_SET (new->live_before, chain->live_before); + COPY_REG_SET (new->live_after, chain->live_before); + if (chain->insn == BLOCK_HEAD (chain->block)) + BLOCK_HEAD (chain->block) = new->insn; + } + else + { + new->next = chain->next; + if (new->next != 0) + new->next->prev = new; + chain->next = new; + new->prev = chain; + new->insn = emit_insn_after (pat, insn); + /* ??? It would be nice if we could exclude the already / still saved + registers from the live sets, and observe REG_UNUSED notes. */ + COPY_REG_SET (new->live_before, chain->live_after); + COPY_REG_SET (new->live_after, chain->live_after); + if (chain->insn == BLOCK_END (chain->block)) + BLOCK_END (chain->block) = new->insn; + } + new->block = chain->block; + new->is_caller_save_insn = 1; + + INSN_CODE (new->insn) = code; +} diff --git a/gcc_arm/calls.c b/gcc_arm/calls.c new file mode 100755 index 0000000..4c01729 --- /dev/null +++ b/gcc_arm/calls.c @@ -0,0 +1,3743 @@ +/* Convert function calls to rtl insns, for GNU C compiler. + Copyright (C) 1989, 92-97, 1998, 1999 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "rtl.h" +#include "tree.h" +#include "flags.h" +#include "expr.h" +#include "regs.h" +#include "insn-flags.h" +#include "toplev.h" +#include "output.h" + +#if !defined PREFERRED_STACK_BOUNDARY && defined STACK_BOUNDARY +#define PREFERRED_STACK_BOUNDARY STACK_BOUNDARY +#endif + +/* Decide whether a function's arguments should be processed + from first to last or from last to first. + + They should if the stack and args grow in opposite directions, but + only if we have push insns. */ + +#ifdef PUSH_ROUNDING + +#if defined (STACK_GROWS_DOWNWARD) != defined (ARGS_GROW_DOWNWARD) +#define PUSH_ARGS_REVERSED /* If it's last to first */ +#endif + +#endif + +/* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits. */ +#define STACK_BYTES (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT) + +/* Data structure and subroutines used within expand_call. */ + +struct arg_data +{ + /* Tree node for this argument. */ + tree tree_value; + /* Mode for value; TYPE_MODE unless promoted. */ + enum machine_mode mode; + /* Current RTL value for argument, or 0 if it isn't precomputed. */ + rtx value; + /* Initially-compute RTL value for argument; only for const functions. */ + rtx initial_value; + /* Register to pass this argument in, 0 if passed on stack, or an + PARALLEL if the arg is to be copied into multiple non-contiguous + registers. */ + rtx reg; + /* If REG was promoted from the actual mode of the argument expression, + indicates whether the promotion is sign- or zero-extended. */ + int unsignedp; + /* Number of registers to use. 0 means put the whole arg in registers. + Also 0 if not passed in registers. */ + int partial; + /* Non-zero if argument must be passed on stack. + Note that some arguments may be passed on the stack + even though pass_on_stack is zero, just because FUNCTION_ARG says so. + pass_on_stack identifies arguments that *cannot* go in registers. */ + int pass_on_stack; + /* Offset of this argument from beginning of stack-args. */ + struct args_size offset; + /* Similar, but offset to the start of the stack slot. Different from + OFFSET if this arg pads downward. */ + struct args_size slot_offset; + /* Size of this argument on the stack, rounded up for any padding it gets, + parts of the argument passed in registers do not count. + If REG_PARM_STACK_SPACE is defined, then register parms + are counted here as well. */ + struct args_size size; + /* Location on the stack at which parameter should be stored. The store + has already been done if STACK == VALUE. */ + rtx stack; + /* Location on the stack of the start of this argument slot. This can + differ from STACK if this arg pads downward. This location is known + to be aligned to FUNCTION_ARG_BOUNDARY. */ + rtx stack_slot; +#ifdef ACCUMULATE_OUTGOING_ARGS + /* Place that this stack area has been saved, if needed. */ + rtx save_area; +#endif + /* If an argument's alignment does not permit direct copying into registers, + copy in smaller-sized pieces into pseudos. These are stored in a + block pointed to by this field. The next field says how many + word-sized pseudos we made. */ + rtx *aligned_regs; + int n_aligned_regs; +}; + +#ifdef ACCUMULATE_OUTGOING_ARGS +/* A vector of one char per byte of stack space. A byte if non-zero if + the corresponding stack location has been used. + This vector is used to prevent a function call within an argument from + clobbering any stack already set up. */ +static char *stack_usage_map; + +/* Size of STACK_USAGE_MAP. */ +static int highest_outgoing_arg_in_use; + +/* stack_arg_under_construction is nonzero when an argument may be + initialized with a constructor call (including a C function that + returns a BLKmode struct) and expand_call must take special action + to make sure the object being constructed does not overlap the + argument list for the constructor call. */ +int stack_arg_under_construction; +#endif + +static int calls_function PROTO ((tree, int)); +static int calls_function_1 PROTO ((tree, int)); +static void emit_call_1 PROTO ((rtx, tree, tree, HOST_WIDE_INT, + HOST_WIDE_INT, rtx, rtx, + int, rtx, int)); +static void special_function_p PROTO ((char *, tree, int *, int *, + int *, int *)); +static void precompute_register_parameters PROTO ((int, struct arg_data *, + int *)); +static void store_one_arg PROTO ((struct arg_data *, rtx, int, int, + int)); +static void store_unaligned_arguments_into_pseudos PROTO ((struct arg_data *, + int)); + +#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE) +static rtx save_fixed_argument_area PROTO ((int, rtx, int *, int *)); +static void restore_fixed_argument_area PROTO ((rtx, rtx, int, int)); +#endif + +/* If WHICH is 1, return 1 if EXP contains a call to the built-in function + `alloca'. + + If WHICH is 0, return 1 if EXP contains a call to any function. + Actually, we only need return 1 if evaluating EXP would require pushing + arguments on the stack, but that is too difficult to compute, so we just + assume any function call might require the stack. */ + +static tree calls_function_save_exprs; + +static int +calls_function (exp, which) + tree exp; + int which; +{ + int val; + calls_function_save_exprs = 0; + val = calls_function_1 (exp, which); + calls_function_save_exprs = 0; + return val; +} + +static int +calls_function_1 (exp, which) + tree exp; + int which; +{ + register int i; + enum tree_code code = TREE_CODE (exp); + int type = TREE_CODE_CLASS (code); + int length = tree_code_length[(int) code]; + + /* If this code is language-specific, we don't know what it will do. */ + if ((int) code >= NUM_TREE_CODES) + return 1; + + /* Only expressions and references can contain calls. */ + if (type != 'e' && type != '<' && type != '1' && type != '2' && type != 'r' + && type != 'b') + return 0; + + switch (code) + { + case CALL_EXPR: + if (which == 0) + return 1; + else if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR + && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) + == FUNCTION_DECL)) + { + tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); + + if ((DECL_BUILT_IN (fndecl) + && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ALLOCA) + || (DECL_SAVED_INSNS (fndecl) + && (FUNCTION_FLAGS (DECL_SAVED_INSNS (fndecl)) + & FUNCTION_FLAGS_CALLS_ALLOCA))) + return 1; + } + + /* Third operand is RTL. */ + length = 2; + break; + + case SAVE_EXPR: + if (SAVE_EXPR_RTL (exp) != 0) + return 0; + if (value_member (exp, calls_function_save_exprs)) + return 0; + calls_function_save_exprs = tree_cons (NULL_TREE, exp, + calls_function_save_exprs); + return (TREE_OPERAND (exp, 0) != 0 + && calls_function_1 (TREE_OPERAND (exp, 0), which)); + + case BLOCK: + { + register tree local; + + for (local = BLOCK_VARS (exp); local; local = TREE_CHAIN (local)) + if (DECL_INITIAL (local) != 0 + && calls_function_1 (DECL_INITIAL (local), which)) + return 1; + } + { + register tree subblock; + + for (subblock = BLOCK_SUBBLOCKS (exp); + subblock; + subblock = TREE_CHAIN (subblock)) + if (calls_function_1 (subblock, which)) + return 1; + } + return 0; + + case METHOD_CALL_EXPR: + length = 3; + break; + + case WITH_CLEANUP_EXPR: + length = 1; + break; + + case RTL_EXPR: + return 0; + + default: + break; + } + + for (i = 0; i < length; i++) + if (TREE_OPERAND (exp, i) != 0 + && calls_function_1 (TREE_OPERAND (exp, i), which)) + return 1; + + return 0; +} + +/* Force FUNEXP into a form suitable for the address of a CALL, + and return that as an rtx. Also load the static chain register + if FNDECL is a nested function. + + CALL_FUSAGE points to a variable holding the prospective + CALL_INSN_FUNCTION_USAGE information. */ + +rtx +prepare_call_address (funexp, fndecl, call_fusage, reg_parm_seen) + rtx funexp; + tree fndecl; + rtx *call_fusage; + int reg_parm_seen; +{ + rtx static_chain_value = 0; + + funexp = protect_from_queue (funexp, 0); + + if (fndecl != 0) + /* Get possible static chain value for nested function in C. */ + static_chain_value = lookup_static_chain (fndecl); + + /* Make a valid memory address and copy constants thru pseudo-regs, + but not for a constant address if -fno-function-cse. */ + if (GET_CODE (funexp) != SYMBOL_REF) + /* If we are using registers for parameters, force the + function address into a register now. */ + funexp = ((SMALL_REGISTER_CLASSES && reg_parm_seen) + ? force_not_mem (memory_address (FUNCTION_MODE, funexp)) + : memory_address (FUNCTION_MODE, funexp)); + else + { +#ifndef NO_FUNCTION_CSE + if (optimize && ! flag_no_function_cse) +#ifdef NO_RECURSIVE_FUNCTION_CSE + if (fndecl != current_function_decl) +#endif + funexp = force_reg (Pmode, funexp); +#endif + } + + if (static_chain_value != 0) + { + emit_move_insn (static_chain_rtx, static_chain_value); + + if (GET_CODE (static_chain_rtx) == REG) + use_reg (call_fusage, static_chain_rtx); + } + + return funexp; +} + +/* Generate instructions to call function FUNEXP, + and optionally pop the results. + The CALL_INSN is the first insn generated. + + FNDECL is the declaration node of the function. This is given to the + macro RETURN_POPS_ARGS to determine whether this function pops its own args. + + FUNTYPE is the data type of the function. This is given to the macro + RETURN_POPS_ARGS to determine whether this function pops its own args. + We used to allow an identifier for library functions, but that doesn't + work when the return type is an aggregate type and the calling convention + says that the pointer to this aggregate is to be popped by the callee. + + STACK_SIZE is the number of bytes of arguments on the stack, + rounded up to PREFERRED_STACK_BOUNDARY; zero if the size is variable. + This is both to put into the call insn and + to generate explicit popping code if necessary. + + STRUCT_VALUE_SIZE is the number of bytes wanted in a structure value. + It is zero if this call doesn't want a structure value. + + NEXT_ARG_REG is the rtx that results from executing + FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1) + just after all the args have had their registers assigned. + This could be whatever you like, but normally it is the first + arg-register beyond those used for args in this call, + or 0 if all the arg-registers are used in this call. + It is passed on to `gen_call' so you can put this info in the call insn. + + VALREG is a hard register in which a value is returned, + or 0 if the call does not return a value. + + OLD_INHIBIT_DEFER_POP is the value that `inhibit_defer_pop' had before + the args to this call were processed. + We restore `inhibit_defer_pop' to that value. + + CALL_FUSAGE is either empty or an EXPR_LIST of USE expressions that + denote registers used by the called function. + + IS_CONST is true if this is a `const' call. */ + +static void +emit_call_1 (funexp, fndecl, funtype, stack_size, struct_value_size, + next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage, + is_const) + rtx funexp; + tree fndecl ATTRIBUTE_UNUSED; + tree funtype ATTRIBUTE_UNUSED; + HOST_WIDE_INT stack_size; + HOST_WIDE_INT struct_value_size; + rtx next_arg_reg; + rtx valreg; + int old_inhibit_defer_pop; + rtx call_fusage; + int is_const; +{ + rtx stack_size_rtx = GEN_INT (stack_size); + rtx struct_value_size_rtx = GEN_INT (struct_value_size); + rtx call_insn; +#ifndef ACCUMULATE_OUTGOING_ARGS + int already_popped = 0; +#endif + + /* 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, + because prepare_call_address already did it if it should be done. */ + if (GET_CODE (funexp) != SYMBOL_REF) + funexp = memory_address (FUNCTION_MODE, funexp); + +#ifndef ACCUMULATE_OUTGOING_ARGS +#if defined (HAVE_call_pop) && defined (HAVE_call_value_pop) + if (HAVE_call_pop && HAVE_call_value_pop + && (RETURN_POPS_ARGS (fndecl, funtype, stack_size) > 0 + || stack_size == 0)) + { + rtx n_pop = GEN_INT (RETURN_POPS_ARGS (fndecl, funtype, stack_size)); + rtx pat; + + /* If this subroutine pops its own args, record that in the call insn + if possible, for the sake of frame pointer elimination. */ + + if (valreg) + pat = gen_call_value_pop (valreg, + gen_rtx_MEM (FUNCTION_MODE, funexp), + stack_size_rtx, next_arg_reg, n_pop); + else + pat = gen_call_pop (gen_rtx_MEM (FUNCTION_MODE, funexp), + stack_size_rtx, next_arg_reg, n_pop); + + emit_call_insn (pat); + already_popped = 1; + } + else +#endif +#endif + +#if defined (HAVE_call) && defined (HAVE_call_value) + if (HAVE_call && HAVE_call_value) + { + if (valreg) + emit_call_insn (gen_call_value (valreg, + gen_rtx_MEM (FUNCTION_MODE, funexp), + stack_size_rtx, next_arg_reg, + NULL_RTX)); + else + emit_call_insn (gen_call (gen_rtx_MEM (FUNCTION_MODE, funexp), + stack_size_rtx, next_arg_reg, + struct_value_size_rtx)); + } + else +#endif + abort (); + + /* Find the CALL insn we just emitted. */ + for (call_insn = get_last_insn (); + call_insn && GET_CODE (call_insn) != CALL_INSN; + call_insn = PREV_INSN (call_insn)) + ; + + if (! call_insn) + abort (); + + /* Put the register usage information on the CALL. If there is already + some usage information, put ours at the end. */ + if (CALL_INSN_FUNCTION_USAGE (call_insn)) + { + rtx link; + + for (link = CALL_INSN_FUNCTION_USAGE (call_insn); XEXP (link, 1) != 0; + link = XEXP (link, 1)) + ; + + XEXP (link, 1) = call_fusage; + } + else + CALL_INSN_FUNCTION_USAGE (call_insn) = call_fusage; + + /* If this is a const call, then set the insn's unchanging bit. */ + if (is_const) + CONST_CALL_P (call_insn) = 1; + + /* Restore this now, so that we do defer pops for this call's args + if the context of the call as a whole permits. */ + inhibit_defer_pop = old_inhibit_defer_pop; + +#ifndef ACCUMULATE_OUTGOING_ARGS + /* If returning from the subroutine does not automatically pop the args, + we need an instruction to pop them sooner or later. + Perhaps do it now; perhaps just record how much space to pop later. + + If returning from the subroutine does pop the args, indicate that the + stack pointer will be changed. */ + + if (stack_size != 0 && RETURN_POPS_ARGS (fndecl, funtype, stack_size) > 0) + { + if (!already_popped) + CALL_INSN_FUNCTION_USAGE (call_insn) + = gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_CLOBBER (VOIDmode, stack_pointer_rtx), + CALL_INSN_FUNCTION_USAGE (call_insn)); + stack_size -= RETURN_POPS_ARGS (fndecl, funtype, stack_size); + stack_size_rtx = GEN_INT (stack_size); + } + + if (stack_size != 0) + { + if (flag_defer_pop && inhibit_defer_pop == 0 && !is_const) + pending_stack_adjust += stack_size; + else + adjust_stack (stack_size_rtx); + } +#endif +} + +/* Determine if the function identified by NAME and FNDECL is one with + special properties we wish to know about. + + For example, if the function might return more than one time (setjmp), then + set RETURNS_TWICE to a nonzero value. + + Similarly set IS_LONGJMP for if the function is in the longjmp family. + + Set IS_MALLOC for any of the standard memory allocation functions which + allocate from the heap. + + Set MAY_BE_ALLOCA for any memory allocation function that might allocate + space from the stack such as alloca. */ + +static void +special_function_p (name, fndecl, returns_twice, is_longjmp, + is_malloc, may_be_alloca) + char *name; + tree fndecl; + int *returns_twice; + int *is_longjmp; + int *is_malloc; + int *may_be_alloca; +{ + *returns_twice = 0; + *is_longjmp = 0; + *is_malloc = 0; + *may_be_alloca = 0; + + if (name != 0 && IDENTIFIER_LENGTH (DECL_NAME (fndecl)) <= 17 + /* Exclude functions not at the file scope, or not `extern', + since they are not the magic functions we would otherwise + think they are. */ + && DECL_CONTEXT (fndecl) == NULL_TREE && TREE_PUBLIC (fndecl)) + { + char *tname = name; + + /* We assume that alloca will always be called by name. It + makes no sense to pass it as a pointer-to-function to + anything that does not understand its behavior. */ + *may_be_alloca + = (((IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 6 + && name[0] == 'a' + && ! strcmp (name, "alloca")) + || (IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 16 + && name[0] == '_' + && ! strcmp (name, "__builtin_alloca")))); + + /* Disregard prefix _, __ or __x. */ + if (name[0] == '_') + { + if (name[1] == '_' && name[2] == 'x') + tname += 3; + else if (name[1] == '_') + tname += 2; + else + tname += 1; + } + + if (tname[0] == 's') + { + *returns_twice + = ((tname[1] == 'e' + && (! strcmp (tname, "setjmp") + || ! strcmp (tname, "setjmp_syscall"))) + || (tname[1] == 'i' + && ! strcmp (tname, "sigsetjmp")) + || (tname[1] == 'a' + && ! strcmp (tname, "savectx"))); + if (tname[1] == 'i' + && ! strcmp (tname, "siglongjmp")) + *is_longjmp = 1; + } + else if ((tname[0] == 'q' && tname[1] == 's' + && ! strcmp (tname, "qsetjmp")) + || (tname[0] == 'v' && tname[1] == 'f' + && ! strcmp (tname, "vfork"))) + *returns_twice = 1; + + else if (tname[0] == 'l' && tname[1] == 'o' + && ! strcmp (tname, "longjmp")) + *is_longjmp = 1; + /* XXX should have "malloc" attribute on functions instead + of recognizing them by name. */ + else if (! strcmp (tname, "malloc") + || ! strcmp (tname, "calloc") + || ! strcmp (tname, "realloc") + /* Note use of NAME rather than TNAME here. These functions + are only reserved when preceded with __. */ + || ! strcmp (name, "__vn") /* mangled __builtin_vec_new */ + || ! strcmp (name, "__nw") /* mangled __builtin_new */ + || ! strcmp (name, "__builtin_new") + || ! strcmp (name, "__builtin_vec_new")) + *is_malloc = 1; + } +} + +/* Precompute all register parameters as described by ARGS, storing values + into fields within the ARGS array. + + NUM_ACTUALS indicates the total number elements in the ARGS array. + + Set REG_PARM_SEEN if we encounter a register parameter. */ + +static void +precompute_register_parameters (num_actuals, args, reg_parm_seen) + int num_actuals; + struct arg_data *args; + int *reg_parm_seen; +{ + int i; + + *reg_parm_seen = 0; + + for (i = 0; i < num_actuals; i++) + if (args[i].reg != 0 && ! args[i].pass_on_stack) + { + *reg_parm_seen = 1; + + if (args[i].value == 0) + { + push_temp_slots (); + args[i].value = expand_expr (args[i].tree_value, NULL_RTX, + VOIDmode, 0); + preserve_temp_slots (args[i].value); + pop_temp_slots (); + + /* ANSI doesn't require a sequence point here, + but PCC has one, so this will avoid some problems. */ + emit_queue (); + } + + /* If we are to promote the function arg to a wider mode, + do it now. */ + + if (args[i].mode != TYPE_MODE (TREE_TYPE (args[i].tree_value))) + args[i].value + = convert_modes (args[i].mode, + TYPE_MODE (TREE_TYPE (args[i].tree_value)), + args[i].value, args[i].unsignedp); + + /* If the value is expensive, and we are inside an appropriately + short loop, put the value into a pseudo and then put the pseudo + into the hard reg. + + For small register classes, also do this if this call uses + register parameters. This is to avoid reload conflicts while + loading the parameters registers. */ + + if ((! (GET_CODE (args[i].value) == REG + || (GET_CODE (args[i].value) == SUBREG + && GET_CODE (SUBREG_REG (args[i].value)) == REG))) + && args[i].mode != BLKmode + && rtx_cost (args[i].value, SET) > 2 + && ((SMALL_REGISTER_CLASSES && *reg_parm_seen) + || preserve_subexpressions_p ())) + args[i].value = copy_to_mode_reg (args[i].mode, args[i].value); + } +} + +#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE) + + /* The argument list is the property of the called routine and it + may clobber it. If the fixed area has been used for previous + parameters, we must save and restore it. */ +static rtx +save_fixed_argument_area (reg_parm_stack_space, argblock, + low_to_save, high_to_save) + int reg_parm_stack_space; + rtx argblock; + int *low_to_save; + int *high_to_save; +{ + int i; + rtx save_area = NULL_RTX; + + /* Compute the boundary of the that needs to be saved, if any. */ +#ifdef ARGS_GROW_DOWNWARD + for (i = 0; i < reg_parm_stack_space + 1; i++) +#else + for (i = 0; i < reg_parm_stack_space; i++) +#endif + { + if (i >= highest_outgoing_arg_in_use + || stack_usage_map[i] == 0) + continue; + + if (*low_to_save == -1) + *low_to_save = i; + + *high_to_save = i; + } + + if (*low_to_save >= 0) + { + int num_to_save = *high_to_save - *low_to_save + 1; + enum machine_mode save_mode + = mode_for_size (num_to_save * BITS_PER_UNIT, MODE_INT, 1); + rtx stack_area; + + /* If we don't have the required alignment, must do this in BLKmode. */ + if ((*low_to_save & (MIN (GET_MODE_SIZE (save_mode), + BIGGEST_ALIGNMENT / UNITS_PER_WORD) - 1))) + save_mode = BLKmode; + +#ifdef ARGS_GROW_DOWNWARD + stack_area = gen_rtx_MEM (save_mode, + memory_address (save_mode, + plus_constant (argblock, + - *high_to_save))); +#else + stack_area = gen_rtx_MEM (save_mode, + memory_address (save_mode, + plus_constant (argblock, + *low_to_save))); +#endif + if (save_mode == BLKmode) + { + save_area = assign_stack_temp (BLKmode, num_to_save, 0); + emit_block_move (validize_mem (save_area), stack_area, + GEN_INT (num_to_save), + PARM_BOUNDARY / BITS_PER_UNIT); + } + else + { + save_area = gen_reg_rtx (save_mode); + emit_move_insn (save_area, stack_area); + } + } + return save_area; +} + +static void +restore_fixed_argument_area (save_area, argblock, high_to_save, low_to_save) + rtx save_area; + rtx argblock; + int high_to_save; + int low_to_save; +{ + enum machine_mode save_mode = GET_MODE (save_area); +#ifdef ARGS_GROW_DOWNWARD + rtx stack_area + = gen_rtx_MEM (save_mode, + memory_address (save_mode, + plus_constant (argblock, + - high_to_save))); +#else + rtx stack_area + = gen_rtx_MEM (save_mode, + memory_address (save_mode, + plus_constant (argblock, + low_to_save))); +#endif + + if (save_mode != BLKmode) + emit_move_insn (stack_area, save_area); + else + emit_block_move (stack_area, validize_mem (save_area), + GEN_INT (high_to_save - low_to_save + 1), + PARM_BOUNDARY / BITS_PER_UNIT); +} +#endif + +/* If any elements in ARGS refer to parameters that are to be passed in + registers, but not in memory, and whose alignment does not permit a + direct copy into registers. Copy the values into a group of pseudos + which we will later copy into the appropriate hard registers. + + Pseudos for each unaligned argument will be stored into the array + args[argnum].aligned_regs. The caller is responsible for deallocating + the aligned_regs array if it is nonzero. */ + +static void +store_unaligned_arguments_into_pseudos (args, num_actuals) + struct arg_data *args; + int num_actuals; +{ + int i, j; + + for (i = 0; i < num_actuals; i++) + if (args[i].reg != 0 && ! args[i].pass_on_stack + && args[i].mode == BLKmode + && (TYPE_ALIGN (TREE_TYPE (args[i].tree_value)) + < (unsigned int) MIN (BIGGEST_ALIGNMENT, BITS_PER_WORD))) + { + int bytes = int_size_in_bytes (TREE_TYPE (args[i].tree_value)); + int big_endian_correction = 0; + + args[i].n_aligned_regs + = args[i].partial ? args[i].partial + : (bytes + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD; + + args[i].aligned_regs = (rtx *) xmalloc (sizeof (rtx) + * args[i].n_aligned_regs); + + /* Structures smaller than a word are aligned to the least + significant byte (to the right). On a BYTES_BIG_ENDIAN machine, + this means we must skip the empty high order bytes when + calculating the bit offset. */ + if (BYTES_BIG_ENDIAN && bytes < UNITS_PER_WORD) + big_endian_correction = (BITS_PER_WORD - (bytes * BITS_PER_UNIT)); + + for (j = 0; j < args[i].n_aligned_regs; j++) + { + rtx reg = gen_reg_rtx (word_mode); + rtx word = operand_subword_force (args[i].value, j, BLKmode); + int bitsize = MIN (bytes * BITS_PER_UNIT, BITS_PER_WORD); + int bitalign = TYPE_ALIGN (TREE_TYPE (args[i].tree_value)); + + args[i].aligned_regs[j] = reg; + + /* There is no need to restrict this code to loading items + in TYPE_ALIGN sized hunks. The bitfield instructions can + load up entire word sized registers efficiently. + + ??? This may not be needed anymore. + We use to emit a clobber here but that doesn't let later + passes optimize the instructions we emit. By storing 0 into + the register later passes know the first AND to zero out the + bitfield being set in the register is unnecessary. The store + of 0 will be deleted as will at least the first AND. */ + + emit_move_insn (reg, const0_rtx); + + bytes -= bitsize / BITS_PER_UNIT; + store_bit_field (reg, bitsize, big_endian_correction, word_mode, + extract_bit_field (word, bitsize, 0, 1, + NULL_RTX, word_mode, + word_mode, + bitalign / BITS_PER_UNIT, + BITS_PER_WORD), + bitalign / BITS_PER_UNIT, BITS_PER_WORD); + } + } +} + +/* Generate all the code for a function call + and return an rtx for its value. + Store the value in TARGET (specified as an rtx) if convenient. + If the value is stored in TARGET then TARGET is returned. + If IGNORE is nonzero, then we ignore the value of the function call. */ + +rtx +expand_call (exp, target, ignore) + tree exp; + rtx target; + int ignore; +{ + /* List of actual parameters. */ + tree actparms = TREE_OPERAND (exp, 1); + /* RTX for the function to be called. */ + rtx funexp; + /* Data type of the function. */ + tree funtype; + /* Declaration of the function being called, + or 0 if the function is computed (not known by name). */ + tree fndecl = 0; + char *name = 0; + + /* Register in which non-BLKmode value will be returned, + or 0 if no value or if value is BLKmode. */ + rtx valreg; + /* Address where we should return a BLKmode value; + 0 if value not BLKmode. */ + rtx structure_value_addr = 0; + /* Nonzero if that address is being passed by treating it as + an extra, implicit first parameter. Otherwise, + it is passed by being copied directly into struct_value_rtx. */ + int structure_value_addr_parm = 0; + /* Size of aggregate value wanted, or zero if none wanted + or if we are using the non-reentrant PCC calling convention + or expecting the value in registers. */ + HOST_WIDE_INT struct_value_size = 0; + /* Nonzero if called function returns an aggregate in memory PCC style, + by returning the address of where to find it. */ + int pcc_struct_value = 0; + + /* Number of actual parameters in this call, including struct value addr. */ + int num_actuals; + /* Number of named args. Args after this are anonymous ones + and they must all go on the stack. */ + int n_named_args; + /* Count arg position in order args appear. */ + int argpos; + + /* Vector of information about each argument. + Arguments are numbered in the order they will be pushed, + not the order they are written. */ + struct arg_data *args; + + /* Total size in bytes of all the stack-parms scanned so far. */ + struct args_size args_size; + /* Size of arguments before any adjustments (such as rounding). */ + struct args_size original_args_size; + /* Data on reg parms scanned so far. */ + CUMULATIVE_ARGS args_so_far; + /* Nonzero if a reg parm has been scanned. */ + int reg_parm_seen; + /* Nonzero if this is an indirect function call. */ + + /* Nonzero if we must avoid push-insns in the args for this call. + If stack space is allocated for register parameters, but not by the + caller, then it is preallocated in the fixed part of the stack frame. + So the entire argument block must then be preallocated (i.e., we + ignore PUSH_ROUNDING in that case). */ + +#ifdef PUSH_ROUNDING + int must_preallocate = 0; +#else + int must_preallocate = 1; +#endif + + /* Size of the stack reserved for parameter registers. */ + int reg_parm_stack_space = 0; + + /* 1 if scanning parms front to back, -1 if scanning back to front. */ + int inc; + /* Address of space preallocated for stack parms + (on machines that lack push insns), or 0 if space not preallocated. */ + rtx argblock = 0; + + /* Nonzero if it is plausible that this is a call to alloca. */ + int may_be_alloca; + /* Nonzero if this is a call to malloc or a related function. */ + int is_malloc; + /* Nonzero if this is a call to setjmp or a related function. */ + int returns_twice; + /* Nonzero if this is a call to `longjmp'. */ + int is_longjmp; + /* Nonzero if this is a call to an inline function. */ + int is_integrable = 0; + /* Nonzero if this is a call to a `const' function. + Note that only explicitly named functions are handled as `const' here. */ + int is_const = 0; + /* Nonzero if this is a call to a `volatile' function. */ + int is_volatile = 0; +#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE) + /* Define the boundary of the register parm stack space that needs to be + save, if any. */ + int low_to_save = -1, high_to_save; + rtx save_area = 0; /* Place that it is saved */ +#endif + +#ifdef ACCUMULATE_OUTGOING_ARGS + int initial_highest_arg_in_use = highest_outgoing_arg_in_use; + char *initial_stack_usage_map = stack_usage_map; + int old_stack_arg_under_construction; +#endif + + rtx old_stack_level = 0; + int old_pending_adj = 0; + int old_inhibit_defer_pop = inhibit_defer_pop; + rtx call_fusage = 0; + register tree p; + register int i, j; + + /* The value of the function call can be put in a hard register. But + if -fcheck-memory-usage, code which invokes functions (and thus + damages some hard registers) can be inserted before using the value. + So, target is always a pseudo-register in that case. */ + if (current_function_check_memory_usage) + target = 0; + + /* See if we can find a DECL-node for the actual function. + As a result, decide whether this is a call to an integrable function. */ + + p = TREE_OPERAND (exp, 0); + if (TREE_CODE (p) == ADDR_EXPR) + { + fndecl = TREE_OPERAND (p, 0); + if (TREE_CODE (fndecl) != FUNCTION_DECL) + fndecl = 0; + else + { + if (!flag_no_inline + && fndecl != current_function_decl + && DECL_INLINE (fndecl) + && DECL_SAVED_INSNS (fndecl) + && RTX_INTEGRATED_P (DECL_SAVED_INSNS (fndecl))) + is_integrable = 1; + else if (! TREE_ADDRESSABLE (fndecl)) + { + /* In case this function later becomes inlinable, + record that there was already a non-inline call to it. + + Use abstraction instead of setting TREE_ADDRESSABLE + directly. */ + if (DECL_INLINE (fndecl) && warn_inline && !flag_no_inline + && optimize > 0) + { + warning_with_decl (fndecl, "can't inline call to `%s'"); + warning ("called from here"); + } + mark_addressable (fndecl); + } + + if (TREE_READONLY (fndecl) && ! TREE_THIS_VOLATILE (fndecl) + && TYPE_MODE (TREE_TYPE (exp)) != VOIDmode) + is_const = 1; + + if (TREE_THIS_VOLATILE (fndecl)) + is_volatile = 1; + } + } + + /* If we don't have specific function to call, see if we have a + constant or `noreturn' function from the type. */ + if (fndecl == 0) + { + is_const = TREE_READONLY (TREE_TYPE (TREE_TYPE (p))); + is_volatile = TREE_THIS_VOLATILE (TREE_TYPE (TREE_TYPE (p))); + } + +#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 + +#if defined(PUSH_ROUNDING) && ! defined(OUTGOING_REG_PARM_STACK_SPACE) + if (reg_parm_stack_space > 0) + must_preallocate = 1; +#endif + + /* Warn if this value is an aggregate type, + regardless of which calling convention we are using for it. */ + if (warn_aggregate_return && AGGREGATE_TYPE_P (TREE_TYPE (exp))) + warning ("function call has aggregate value"); + + /* Set up a place to return a structure. */ + + /* Cater to broken compilers. */ + if (aggregate_value_p (exp)) + { + /* This call returns a big structure. */ + is_const = 0; + +#ifdef PCC_STATIC_STRUCT_RETURN + { + pcc_struct_value = 1; + /* Easier than making that case work right. */ + if (is_integrable) + { + /* In case this is a static function, note that it has been + used. */ + if (! TREE_ADDRESSABLE (fndecl)) + mark_addressable (fndecl); + is_integrable = 0; + } + } +#else /* not PCC_STATIC_STRUCT_RETURN */ + { + struct_value_size = int_size_in_bytes (TREE_TYPE (exp)); + + if (target && GET_CODE (target) == MEM) + structure_value_addr = XEXP (target, 0); + else + { + /* Assign a temporary to hold the value. */ + tree d; + + /* For variable-sized objects, we must be called with a target + specified. If we were to allocate space on the stack here, + we would have no way of knowing when to free it. */ + + if (struct_value_size < 0) + abort (); + + /* This DECL is just something to feed to mark_addressable; + it doesn't get pushed. */ + d = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (exp)); + DECL_RTL (d) = assign_temp (TREE_TYPE (exp), 1, 0, 1); + mark_addressable (d); + structure_value_addr = XEXP (DECL_RTL (d), 0); + TREE_USED (d) = 1; + target = 0; + } + } +#endif /* not PCC_STATIC_STRUCT_RETURN */ + } + + /* If called function is inline, try to integrate it. */ + + if (is_integrable) + { + rtx temp; +#ifdef ACCUMULATE_OUTGOING_ARGS + rtx before_call = get_last_insn (); +#endif + + temp = expand_inline_function (fndecl, actparms, target, + ignore, TREE_TYPE (exp), + structure_value_addr); + + /* If inlining succeeded, return. */ + if (temp != (rtx) (HOST_WIDE_INT) -1) + { +#ifdef ACCUMULATE_OUTGOING_ARGS + /* If the outgoing argument list must be preserved, push + the stack before executing the inlined function if it + makes any calls. */ + + for (i = reg_parm_stack_space - 1; i >= 0; i--) + if (i < highest_outgoing_arg_in_use && stack_usage_map[i] != 0) + break; + + if (stack_arg_under_construction || i >= 0) + { + rtx first_insn + = before_call ? NEXT_INSN (before_call) : get_insns (); + rtx insn, seq; + + /* Look for a call in the inline function code. + If OUTGOING_ARGS_SIZE (DECL_SAVED_INSNS (fndecl)) is + nonzero then there is a call and it is not necessary + to scan the insns. */ + + if (OUTGOING_ARGS_SIZE (DECL_SAVED_INSNS (fndecl)) == 0) + for (insn = first_insn; insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == CALL_INSN) + break; + + if (insn) + { + /* Reserve enough stack space so that the largest + argument list of any function call in the inline + function does not overlap the argument list being + evaluated. This is usually an overestimate because + allocate_dynamic_stack_space reserves space for an + outgoing argument list in addition to the requested + space, but there is no way to ask for stack space such + that an argument list of a certain length can be + safely constructed. + + Add the stack space reserved for register arguments, if + any, in the inline function. What is really needed is the + largest value of reg_parm_stack_space in the inline + function, but that is not available. Using the current + value of reg_parm_stack_space is wrong, but gives + correct results on all supported machines. */ + + int adjust = (OUTGOING_ARGS_SIZE (DECL_SAVED_INSNS (fndecl)) + + reg_parm_stack_space); + + start_sequence (); + emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX); + allocate_dynamic_stack_space (GEN_INT (adjust), + NULL_RTX, BITS_PER_UNIT); + seq = get_insns (); + end_sequence (); + emit_insns_before (seq, first_insn); + emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX); + } + } +#endif + + /* If the result is equivalent to TARGET, return TARGET to simplify + checks in store_expr. They can be equivalent but not equal in the + case of a function that returns BLKmode. */ + if (temp != target && rtx_equal_p (temp, target)) + return target; + return temp; + } + + /* If inlining failed, mark FNDECL as needing to be compiled + separately after all. If function was declared inline, + give a warning. */ + if (DECL_INLINE (fndecl) && warn_inline && !flag_no_inline + && optimize > 0 && ! TREE_ADDRESSABLE (fndecl)) + { + warning_with_decl (fndecl, "inlining failed in call to `%s'"); + warning ("called from here"); + } + mark_addressable (fndecl); + } + + /* When calling a const function, we must pop the stack args right away, + so that the pop is deleted or moved with the call. */ + if (is_const) + NO_DEFER_POP; + + function_call_count++; + + if (fndecl && DECL_NAME (fndecl)) + name = IDENTIFIER_POINTER (DECL_NAME (fndecl)); + + /* See if this is a call to a function that can return more than once + or a call to longjmp or malloc. */ + special_function_p (name, fndecl, &returns_twice, &is_longjmp, + &is_malloc, &may_be_alloca); + + if (may_be_alloca) + current_function_calls_alloca = 1; + + /* Don't let pending stack adjusts add up to too much. + Also, do all pending adjustments now + if there is any chance this might be a call to alloca. */ + + if (pending_stack_adjust >= 32 + || (pending_stack_adjust > 0 && may_be_alloca)) + do_pending_stack_adjust (); + + /* Operand 0 is a pointer-to-function; get the type of the function. */ + funtype = TREE_TYPE (TREE_OPERAND (exp, 0)); + if (TREE_CODE (funtype) != POINTER_TYPE) + abort (); + funtype = TREE_TYPE (funtype); + + /* Push the temporary stack slot level so that we can free any temporaries + we make. */ + push_temp_slots (); + + /* Start updating where the next arg would go. + + On some machines (such as the PA) indirect calls have a different + calling convention than normal calls. The last argument in + INIT_CUMULATIVE_ARGS tells the backend if this is an indirect call + or not. */ + INIT_CUMULATIVE_ARGS (args_so_far, funtype, NULL_RTX, (fndecl == 0)); + + /* If struct_value_rtx is 0, it means pass the address + as if it were an extra parameter. */ + if (structure_value_addr && struct_value_rtx == 0) + { + /* If structure_value_addr is a REG other than + virtual_outgoing_args_rtx, we can use always use it. If it + is not a REG, we must always copy it into a register. + If it is virtual_outgoing_args_rtx, we must copy it to another + register in some cases. */ + rtx temp = (GET_CODE (structure_value_addr) != REG +#ifdef ACCUMULATE_OUTGOING_ARGS + || (stack_arg_under_construction + && structure_value_addr == virtual_outgoing_args_rtx) +#endif + ? copy_addr_to_reg (structure_value_addr) + : structure_value_addr); + + actparms + = tree_cons (error_mark_node, + make_tree (build_pointer_type (TREE_TYPE (funtype)), + temp), + actparms); + structure_value_addr_parm = 1; + } + + /* Count the arguments and set NUM_ACTUALS. */ + for (p = actparms, i = 0; p; p = TREE_CHAIN (p)) i++; + num_actuals = i; + + /* Compute number of named args. + Normally, don't include the last named arg if anonymous args follow. + We do include the last named arg if STRICT_ARGUMENT_NAMING is nonzero. + (If no anonymous args follow, the result of list_length is actually + one too large. This is harmless.) + + If SETUP_INCOMING_VARARGS is defined and STRICT_ARGUMENT_NAMING is zero, + this machine will be able to place unnamed args that were passed in + registers into the stack. So treat all args as named. This allows the + insns emitting for a specific argument list to be independent of the + function declaration. + + If SETUP_INCOMING_VARARGS is not defined, we do not have any reliable + way to pass unnamed args in registers, so we must force them into + memory. */ + + if ((STRICT_ARGUMENT_NAMING +#ifndef SETUP_INCOMING_VARARGS + || 1 +#endif + ) + && TYPE_ARG_TYPES (funtype) != 0) + n_named_args + = (list_length (TYPE_ARG_TYPES (funtype)) + /* Don't include the last named arg. */ + - (STRICT_ARGUMENT_NAMING ? 0 : 1) + /* Count the struct value address, if it is passed as a parm. */ + + structure_value_addr_parm); + else + /* If we know nothing, treat all args as named. */ + n_named_args = num_actuals; + + /* Make a vector to hold all the information about each arg. */ + args = (struct arg_data *) alloca (num_actuals * sizeof (struct arg_data)); + bzero ((char *) args, num_actuals * sizeof (struct arg_data)); + + args_size.constant = 0; + args_size.var = 0; + + /* In this loop, we consider args in the order they are written. + We fill up ARGS from the front or from the back if necessary + so that in any case the first arg to be pushed ends up at the front. */ + +#ifdef PUSH_ARGS_REVERSED + i = num_actuals - 1, inc = -1; + /* In this case, must reverse order of args + so that we compute and push the last arg first. */ +#else + i = 0, inc = 1; +#endif + + /* I counts args in order (to be) pushed; ARGPOS counts in order written. */ + for (p = actparms, argpos = 0; p; p = TREE_CHAIN (p), i += inc, argpos++) + { + tree type = TREE_TYPE (TREE_VALUE (p)); + int unsignedp; + enum machine_mode mode; + + args[i].tree_value = TREE_VALUE (p); + + /* Replace erroneous argument with constant zero. */ + if (type == error_mark_node || TYPE_SIZE (type) == 0) + args[i].tree_value = integer_zero_node, type = integer_type_node; + + /* If TYPE is a transparent union, pass things the way we would + pass the first field of the union. We have already verified that + the modes are the same. */ + if (TYPE_TRANSPARENT_UNION (type)) + type = TREE_TYPE (TYPE_FIELDS (type)); + + /* Decide where to pass this arg. + + args[i].reg is nonzero if all or part is passed in registers. + + args[i].partial is nonzero if part but not all is passed in registers, + and the exact value says how many words are passed in registers. + + args[i].pass_on_stack is nonzero if the argument must at least be + computed on the stack. It may then be loaded back into registers + if args[i].reg is nonzero. + + These decisions are driven by the FUNCTION_... macros and must agree + with those made by function.c. */ + + /* See if this argument should be passed by invisible reference. */ + if ((TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST + && contains_placeholder_p (TYPE_SIZE (type))) + || TREE_ADDRESSABLE (type) +#ifdef FUNCTION_ARG_PASS_BY_REFERENCE + || FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, TYPE_MODE (type), + type, argpos < n_named_args) +#endif + ) + { + /* If we're compiling a thunk, pass through invisible + references instead of making a copy. */ + if (current_function_is_thunk +#ifdef FUNCTION_ARG_CALLEE_COPIES + || (FUNCTION_ARG_CALLEE_COPIES (args_so_far, TYPE_MODE (type), + type, argpos < n_named_args) + /* If it's in a register, we must make a copy of it too. */ + /* ??? Is this a sufficient test? Is there a better one? */ + && !(TREE_CODE (args[i].tree_value) == VAR_DECL + && REG_P (DECL_RTL (args[i].tree_value))) + && ! TREE_ADDRESSABLE (type)) +#endif + ) + { + /* C++ uses a TARGET_EXPR to indicate that we want to make a + new object from the argument. If we are passing by + invisible reference, the callee will do that for us, so we + can strip off the TARGET_EXPR. This is not always safe, + but it is safe in the only case where this is a useful + optimization; namely, when the argument is a plain object. + In that case, the frontend is just asking the backend to + make a bitwise copy of the argument. */ + + if (TREE_CODE (args[i].tree_value) == TARGET_EXPR + && (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND + (args[i].tree_value, 1))) + == 'd') + && ! REG_P (DECL_RTL (TREE_OPERAND (args[i].tree_value, 1)))) + args[i].tree_value = TREE_OPERAND (args[i].tree_value, 1); + + args[i].tree_value = build1 (ADDR_EXPR, + build_pointer_type (type), + args[i].tree_value); + type = build_pointer_type (type); + } + else + { + /* We make a copy of the object and pass the address to the + function being called. */ + rtx copy; + + if (TYPE_SIZE (type) == 0 + || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST + || (flag_stack_check && ! STACK_CHECK_BUILTIN + && (TREE_INT_CST_HIGH (TYPE_SIZE (type)) != 0 + || (TREE_INT_CST_LOW (TYPE_SIZE (type)) + > STACK_CHECK_MAX_VAR_SIZE * BITS_PER_UNIT)))) + { + /* This is a variable-sized object. Make space on the stack + for it. */ + rtx size_rtx = expr_size (TREE_VALUE (p)); + + if (old_stack_level == 0) + { + emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX); + old_pending_adj = pending_stack_adjust; + pending_stack_adjust = 0; + } + + copy = gen_rtx_MEM (BLKmode, + allocate_dynamic_stack_space (size_rtx, + NULL_RTX, + TYPE_ALIGN (type))); + } + else + { + int size = int_size_in_bytes (type); + copy = assign_stack_temp (TYPE_MODE (type), size, 0); + } + + MEM_SET_IN_STRUCT_P (copy, AGGREGATE_TYPE_P (type)); + + store_expr (args[i].tree_value, copy, 0); + is_const = 0; + + args[i].tree_value = build1 (ADDR_EXPR, + build_pointer_type (type), + make_tree (type, copy)); + type = build_pointer_type (type); + } + } + + mode = TYPE_MODE (type); + unsignedp = TREE_UNSIGNED (type); + +#ifdef PROMOTE_FUNCTION_ARGS + mode = promote_mode (type, mode, &unsignedp, 1); +#endif + + args[i].unsignedp = unsignedp; + args[i].mode = mode; + args[i].reg = FUNCTION_ARG (args_so_far, mode, type, + argpos < n_named_args); +#ifdef FUNCTION_ARG_PARTIAL_NREGS + if (args[i].reg) + args[i].partial + = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, type, + argpos < n_named_args); +#endif + + args[i].pass_on_stack = MUST_PASS_IN_STACK (mode, type); + + /* If FUNCTION_ARG returned a (parallel [(expr_list (nil) ...) ...]), + it means that we are to pass this arg in the register(s) designated + by the PARALLEL, but also to pass it in the stack. */ + if (args[i].reg && GET_CODE (args[i].reg) == PARALLEL + && XEXP (XVECEXP (args[i].reg, 0, 0), 0) == 0) + args[i].pass_on_stack = 1; + + /* If this is an addressable type, we must preallocate the stack + since we must evaluate the object into its final location. + + If this is to be passed in both registers and the stack, it is simpler + to preallocate. */ + if (TREE_ADDRESSABLE (type) + || (args[i].pass_on_stack && args[i].reg != 0)) + must_preallocate = 1; + + /* If this is an addressable type, we cannot pre-evaluate it. Thus, + we cannot consider this function call constant. */ + if (TREE_ADDRESSABLE (type)) + is_const = 0; + + /* Compute the stack-size of this argument. */ + if (args[i].reg == 0 || args[i].partial != 0 + || reg_parm_stack_space > 0 + || args[i].pass_on_stack) + locate_and_pad_parm (mode, type, +#ifdef STACK_PARMS_IN_REG_PARM_AREA + 1, +#else + args[i].reg != 0, +#endif + fndecl, &args_size, &args[i].offset, + &args[i].size); + +#ifndef ARGS_GROW_DOWNWARD + args[i].slot_offset = args_size; +#endif + + /* If a part of the arg was put into registers, + don't include that part in the amount pushed. */ + if (reg_parm_stack_space == 0 && ! args[i].pass_on_stack) + args[i].size.constant -= ((args[i].partial * UNITS_PER_WORD) + / (PARM_BOUNDARY / BITS_PER_UNIT) + * (PARM_BOUNDARY / BITS_PER_UNIT)); + + /* Update ARGS_SIZE, the total stack space for args so far. */ + + args_size.constant += args[i].size.constant; + if (args[i].size.var) + { + ADD_PARM_SIZE (args_size, args[i].size.var); + } + + /* Since the slot offset points to the bottom of the slot, + we must record it after incrementing if the args grow down. */ +#ifdef ARGS_GROW_DOWNWARD + args[i].slot_offset = args_size; + + args[i].slot_offset.constant = -args_size.constant; + if (args_size.var) + { + SUB_PARM_SIZE (args[i].slot_offset, args_size.var); + } +#endif + + /* Increment ARGS_SO_FAR, which has info about which arg-registers + have been used, etc. */ + + FUNCTION_ARG_ADVANCE (args_so_far, TYPE_MODE (type), type, + argpos < n_named_args); + } + +#ifdef FINAL_REG_PARM_STACK_SPACE + reg_parm_stack_space = FINAL_REG_PARM_STACK_SPACE (args_size.constant, + args_size.var); +#endif + + /* Compute the actual size of the argument block required. The variable + and constant sizes must be combined, the size may have to be rounded, + and there may be a minimum required size. */ + + original_args_size = args_size; + if (args_size.var) + { + /* If this function requires a variable-sized argument list, don't try to + make a cse'able block for this call. We may be able to do this + eventually, but it is too complicated to keep track of what insns go + in the cse'able block and which don't. */ + + is_const = 0; + must_preallocate = 1; + + args_size.var = ARGS_SIZE_TREE (args_size); + args_size.constant = 0; + +#ifdef PREFERRED_STACK_BOUNDARY + if (PREFERRED_STACK_BOUNDARY != BITS_PER_UNIT) + args_size.var = round_up (args_size.var, STACK_BYTES); +#endif + + if (reg_parm_stack_space > 0) + { + args_size.var + = size_binop (MAX_EXPR, args_size.var, + size_int (reg_parm_stack_space)); + +#ifndef OUTGOING_REG_PARM_STACK_SPACE + /* The area corresponding to register parameters is not to count in + the size of the block we need. So make the adjustment. */ + args_size.var + = size_binop (MINUS_EXPR, args_size.var, + size_int (reg_parm_stack_space)); +#endif + } + } + else + { +#ifdef PREFERRED_STACK_BOUNDARY + args_size.constant = (((args_size.constant + (STACK_BYTES - 1)) + / STACK_BYTES) * STACK_BYTES); +#endif + + args_size.constant = MAX (args_size.constant, + reg_parm_stack_space); + +#ifdef MAYBE_REG_PARM_STACK_SPACE + if (reg_parm_stack_space == 0) + args_size.constant = 0; +#endif + +#ifndef OUTGOING_REG_PARM_STACK_SPACE + args_size.constant -= reg_parm_stack_space; +#endif + } + + /* See if we have or want to preallocate stack space. + + If we would have to push a partially-in-regs parm + before other stack parms, preallocate stack space instead. + + If the size of some parm is not a multiple of the required stack + alignment, we must preallocate. + + If the total size of arguments that would otherwise create a copy in + a temporary (such as a CALL) is more than half the total argument list + size, preallocation is faster. + + Another reason to preallocate is if we have a machine (like the m88k) + where stack alignment is required to be maintained between every + pair of insns, not just when the call is made. However, we assume here + that such machines either do not have push insns (and hence preallocation + would occur anyway) or the problem is taken care of with + PUSH_ROUNDING. */ + + if (! must_preallocate) + { + int partial_seen = 0; + int copy_to_evaluate_size = 0; + + for (i = 0; i < num_actuals && ! must_preallocate; i++) + { + if (args[i].partial > 0 && ! args[i].pass_on_stack) + partial_seen = 1; + else if (partial_seen && args[i].reg == 0) + must_preallocate = 1; + + if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) == BLKmode + && (TREE_CODE (args[i].tree_value) == CALL_EXPR + || TREE_CODE (args[i].tree_value) == TARGET_EXPR + || TREE_CODE (args[i].tree_value) == COND_EXPR + || TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value)))) + copy_to_evaluate_size + += int_size_in_bytes (TREE_TYPE (args[i].tree_value)); + } + + if (copy_to_evaluate_size * 2 >= args_size.constant + && args_size.constant > 0) + must_preallocate = 1; + } + + /* If the structure value address will reference the stack pointer, we must + stabilize it. We don't need to do this if we know that we are not going + to adjust the stack pointer in processing this call. */ + + if (structure_value_addr + && (reg_mentioned_p (virtual_stack_dynamic_rtx, structure_value_addr) + || reg_mentioned_p (virtual_outgoing_args_rtx, structure_value_addr)) + && (args_size.var +#ifndef ACCUMULATE_OUTGOING_ARGS + || args_size.constant +#endif + )) + structure_value_addr = copy_to_reg (structure_value_addr); + + /* If this function call is cse'able, precompute all the parameters. + Note that if the parameter is constructed into a temporary, this will + cause an additional copy because the parameter will be constructed + into a temporary location and then copied into the outgoing arguments. + If a parameter contains a call to alloca and this function uses the + stack, precompute the parameter. */ + + /* If we preallocated the stack space, and some arguments must be passed + on the stack, then we must precompute any parameter which contains a + function call which will store arguments on the stack. + Otherwise, evaluating the parameter may clobber previous parameters + which have already been stored into the stack. */ + + for (i = 0; i < num_actuals; i++) + if (is_const + || ((args_size.var != 0 || args_size.constant != 0) + && calls_function (args[i].tree_value, 1)) + || (must_preallocate && (args_size.var != 0 || args_size.constant != 0) + && calls_function (args[i].tree_value, 0))) + { + /* If this is an addressable type, we cannot pre-evaluate it. */ + if (TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value))) + abort (); + + push_temp_slots (); + + args[i].initial_value = args[i].value + = expand_expr (args[i].tree_value, NULL_RTX, VOIDmode, 0); + + preserve_temp_slots (args[i].value); + pop_temp_slots (); + + /* ANSI doesn't require a sequence point here, + but PCC has one, so this will avoid some problems. */ + emit_queue (); + + args[i].initial_value = args[i].value + = protect_from_queue (args[i].initial_value, 0); + + if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) != args[i].mode) + args[i].value + = convert_modes (args[i].mode, + TYPE_MODE (TREE_TYPE (args[i].tree_value)), + args[i].value, args[i].unsignedp); + } + + /* Now we are about to start emitting insns that can be deleted + if a libcall is deleted. */ + if (is_const || is_malloc) + start_sequence (); + + /* If we have no actual push instructions, or shouldn't use them, + make space for all args right now. */ + + if (args_size.var != 0) + { + if (old_stack_level == 0) + { + emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX); + old_pending_adj = pending_stack_adjust; + pending_stack_adjust = 0; +#ifdef ACCUMULATE_OUTGOING_ARGS + /* stack_arg_under_construction says whether a stack arg is + being constructed at the old stack level. Pushing the stack + gets a clean outgoing argument block. */ + old_stack_arg_under_construction = stack_arg_under_construction; + stack_arg_under_construction = 0; +#endif + } + argblock = push_block (ARGS_SIZE_RTX (args_size), 0, 0); + } + else + { + /* Note that we must go through the motions of allocating an argument + block even if the size is zero because we may be storing args + in the area reserved for register arguments, which may be part of + the stack frame. */ + + int needed = args_size.constant; + + /* Store the maximum argument space used. It will be pushed by + the prologue (if ACCUMULATE_OUTGOING_ARGS, or stack overflow + checking). */ + + if (needed > current_function_outgoing_args_size) + current_function_outgoing_args_size = needed; + + if (must_preallocate) + { +#ifdef ACCUMULATE_OUTGOING_ARGS + /* Since the stack pointer will never be pushed, it is possible for + the evaluation of a parm to clobber something we have already + written to the stack. Since most function calls on RISC machines + do not use the stack, this is uncommon, but must work correctly. + + Therefore, we save any area of the stack that was already written + and that we are using. Here we set up to do this by making a new + stack usage map from the old one. The actual save will be done + by store_one_arg. + + Another approach might be to try to reorder the argument + evaluations to avoid this conflicting stack usage. */ + +#ifndef OUTGOING_REG_PARM_STACK_SPACE + /* Since we will be writing into the entire argument area, the + map must be allocated for its entire size, not just the part that + is the responsibility of the caller. */ + needed += reg_parm_stack_space; +#endif + +#ifdef ARGS_GROW_DOWNWARD + highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use, + needed + 1); +#else + highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use, + needed); +#endif + stack_usage_map = (char *) alloca (highest_outgoing_arg_in_use); + + if (initial_highest_arg_in_use) + bcopy (initial_stack_usage_map, stack_usage_map, + initial_highest_arg_in_use); + + if (initial_highest_arg_in_use != highest_outgoing_arg_in_use) + bzero (&stack_usage_map[initial_highest_arg_in_use], + highest_outgoing_arg_in_use - initial_highest_arg_in_use); + needed = 0; + + /* The address of the outgoing argument list must not be copied to a + register here, because argblock would be left pointing to the + wrong place after the call to allocate_dynamic_stack_space below. + */ + + argblock = virtual_outgoing_args_rtx; + +#else /* not ACCUMULATE_OUTGOING_ARGS */ + if (inhibit_defer_pop == 0) + { + /* Try to reuse some or all of the pending_stack_adjust + to get this space. Maybe we can avoid any pushing. */ + if (needed > pending_stack_adjust) + { + needed -= pending_stack_adjust; + pending_stack_adjust = 0; + } + else + { + pending_stack_adjust -= needed; + needed = 0; + } + } + /* Special case this because overhead of `push_block' in this + case is non-trivial. */ + if (needed == 0) + argblock = virtual_outgoing_args_rtx; + else + argblock = push_block (GEN_INT (needed), 0, 0); + + /* We only really need to call `copy_to_reg' in the case where push + insns are going to be used to pass ARGBLOCK to a function + call in ARGS. In that case, the stack pointer changes value + from the allocation point to the call point, and hence + the value of VIRTUAL_OUTGOING_ARGS_RTX changes as well. + But might as well always do it. */ + argblock = copy_to_reg (argblock); +#endif /* not ACCUMULATE_OUTGOING_ARGS */ + } + } + +#ifdef ACCUMULATE_OUTGOING_ARGS + /* The save/restore code in store_one_arg handles all cases except one: + a constructor call (including a C function returning a BLKmode struct) + to initialize an argument. */ + if (stack_arg_under_construction) + { +#ifndef OUTGOING_REG_PARM_STACK_SPACE + rtx push_size = GEN_INT (reg_parm_stack_space + args_size.constant); +#else + rtx push_size = GEN_INT (args_size.constant); +#endif + if (old_stack_level == 0) + { + emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX); + old_pending_adj = pending_stack_adjust; + pending_stack_adjust = 0; + /* stack_arg_under_construction says whether a stack arg is + being constructed at the old stack level. Pushing the stack + gets a clean outgoing argument block. */ + old_stack_arg_under_construction = stack_arg_under_construction; + stack_arg_under_construction = 0; + /* Make a new map for the new argument list. */ + stack_usage_map = (char *)alloca (highest_outgoing_arg_in_use); + bzero (stack_usage_map, highest_outgoing_arg_in_use); + highest_outgoing_arg_in_use = 0; + } + allocate_dynamic_stack_space (push_size, NULL_RTX, BITS_PER_UNIT); + } + /* If argument evaluation might modify the stack pointer, copy the + address of the argument list to a register. */ + for (i = 0; i < num_actuals; i++) + if (args[i].pass_on_stack) + { + argblock = copy_addr_to_reg (argblock); + break; + } +#endif + + + /* If we preallocated stack space, compute the address of each argument. + We need not ensure it is a valid memory address here; it will be + validized when it is used. */ + if (argblock) + { + rtx arg_reg = argblock; + int arg_offset = 0; + + if (GET_CODE (argblock) == PLUS) + arg_reg = XEXP (argblock, 0), arg_offset = INTVAL (XEXP (argblock, 1)); + + for (i = 0; i < num_actuals; i++) + { + rtx offset = ARGS_SIZE_RTX (args[i].offset); + rtx slot_offset = ARGS_SIZE_RTX (args[i].slot_offset); + rtx addr; + + /* Skip this parm if it will not be passed on the stack. */ + if (! args[i].pass_on_stack && args[i].reg != 0) + continue; + + if (GET_CODE (offset) == CONST_INT) + addr = plus_constant (arg_reg, INTVAL (offset)); + else + addr = gen_rtx_PLUS (Pmode, arg_reg, offset); + + addr = plus_constant (addr, arg_offset); + args[i].stack = gen_rtx_MEM (args[i].mode, addr); + MEM_SET_IN_STRUCT_P + (args[i].stack, + AGGREGATE_TYPE_P (TREE_TYPE (args[i].tree_value))); + + if (GET_CODE (slot_offset) == CONST_INT) + addr = plus_constant (arg_reg, INTVAL (slot_offset)); + else + addr = gen_rtx_PLUS (Pmode, arg_reg, slot_offset); + + addr = plus_constant (addr, arg_offset); + args[i].stack_slot = gen_rtx_MEM (args[i].mode, addr); + } + } + +#ifdef PUSH_ARGS_REVERSED +#ifdef PREFERRED_STACK_BOUNDARY + /* If we push args individually in reverse order, perform stack alignment + before the first push (the last arg). */ + if (argblock == 0) + anti_adjust_stack (GEN_INT (args_size.constant + - original_args_size.constant)); +#endif +#endif + + /* Don't try to defer pops if preallocating, not even from the first arg, + since ARGBLOCK probably refers to the SP. */ + if (argblock) + NO_DEFER_POP; + + /* Get the function to call, in the form of RTL. */ + if (fndecl) + { + /* If this is the first use of the function, see if we need to + make an external definition for it. */ + if (! TREE_USED (fndecl)) + { + assemble_external (fndecl); + TREE_USED (fndecl) = 1; + } + + /* Get a SYMBOL_REF rtx for the function address. */ + funexp = XEXP (DECL_RTL (fndecl), 0); + } + else + /* Generate an rtx (probably a pseudo-register) for the address. */ + { + push_temp_slots (); + funexp = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0); + pop_temp_slots (); /* FUNEXP can't be BLKmode */ + + /* Check the function is executable. */ + if (current_function_check_memory_usage) + emit_library_call (chkr_check_exec_libfunc, 1, + VOIDmode, 1, + funexp, ptr_mode); + emit_queue (); + } + + /* Figure out the register where the value, if any, will come back. */ + valreg = 0; + if (TYPE_MODE (TREE_TYPE (exp)) != VOIDmode + && ! structure_value_addr) + { + if (pcc_struct_value) + valreg = hard_function_value (build_pointer_type (TREE_TYPE (exp)), + fndecl); + else + valreg = hard_function_value (TREE_TYPE (exp), fndecl); + } + + /* Precompute all register parameters. It isn't safe to compute anything + once we have started filling any specific hard regs. */ + precompute_register_parameters (num_actuals, args, ®_parm_seen); + +#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE) + + /* Save the fixed argument area if it's part of the caller's frame and + is clobbered by argument setup for this call. */ + save_area = save_fixed_argument_area (reg_parm_stack_space, argblock, + &low_to_save, &high_to_save); +#endif + + + /* Now store (and compute if necessary) all non-register parms. + These come before register parms, since they can require block-moves, + which could clobber the registers used for register parms. + Parms which have partial registers are not stored here, + but we do preallocate space here if they want that. */ + + for (i = 0; i < num_actuals; i++) + if (args[i].reg == 0 || args[i].pass_on_stack) + store_one_arg (&args[i], argblock, may_be_alloca, + args_size.var != 0, reg_parm_stack_space); + + /* If we have a parm that is passed in registers but not in memory + and whose alignment does not permit a direct copy into registers, + make a group of pseudos that correspond to each register that we + will later fill. */ + if (STRICT_ALIGNMENT) + store_unaligned_arguments_into_pseudos (args, num_actuals); + + /* Now store any partially-in-registers parm. + This is the last place a block-move can happen. */ + if (reg_parm_seen) + for (i = 0; i < num_actuals; i++) + if (args[i].partial != 0 && ! args[i].pass_on_stack) + store_one_arg (&args[i], argblock, may_be_alloca, + args_size.var != 0, reg_parm_stack_space); + +#ifndef PUSH_ARGS_REVERSED +#ifdef PREFERRED_STACK_BOUNDARY + /* If we pushed args in forward order, perform stack alignment + after pushing the last arg. */ + if (argblock == 0) + anti_adjust_stack (GEN_INT (args_size.constant + - original_args_size.constant)); +#endif +#endif + + /* If register arguments require space on the stack and stack space + was not preallocated, allocate stack space here for arguments + passed in registers. */ +#if ! defined(ACCUMULATE_OUTGOING_ARGS) && defined(OUTGOING_REG_PARM_STACK_SPACE) + if (must_preallocate == 0 && reg_parm_stack_space > 0) + anti_adjust_stack (GEN_INT (reg_parm_stack_space)); +#endif + + /* Pass the function the address in which to return a structure value. */ + if (structure_value_addr && ! structure_value_addr_parm) + { + emit_move_insn (struct_value_rtx, + force_reg (Pmode, + force_operand (structure_value_addr, + NULL_RTX))); + + /* Mark the memory for the aggregate as write-only. */ + if (current_function_check_memory_usage) + emit_library_call (chkr_set_right_libfunc, 1, + VOIDmode, 3, + structure_value_addr, ptr_mode, + GEN_INT (struct_value_size), TYPE_MODE (sizetype), + GEN_INT (MEMORY_USE_WO), + TYPE_MODE (integer_type_node)); + + if (GET_CODE (struct_value_rtx) == REG) + use_reg (&call_fusage, struct_value_rtx); + } + + funexp = prepare_call_address (funexp, fndecl, &call_fusage, reg_parm_seen); + + /* Now do the register loads required for any wholly-register parms or any + parms which are passed both on the stack and in a register. Their + expressions were already evaluated. + + Mark all register-parms as living through the call, putting these USE + insns in the CALL_INSN_FUNCTION_USAGE field. */ + +#ifdef LOAD_ARGS_REVERSED + for (i = num_actuals - 1; i >= 0; i--) +#else + for (i = 0; i < num_actuals; i++) +#endif + { + rtx reg = args[i].reg; + int partial = args[i].partial; + int nregs; + + if (reg) + { + /* Set to non-negative if must move a word at a time, even if just + one word (e.g, partial == 1 && mode == DFmode). Set to -1 if + we just use a normal move insn. This value can be zero if the + argument is a zero size structure with no fields. */ + nregs = (partial ? partial + : (TYPE_MODE (TREE_TYPE (args[i].tree_value)) == BLKmode + ? ((int_size_in_bytes (TREE_TYPE (args[i].tree_value)) + + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD) + : -1)); + + /* Handle calls that pass values in multiple non-contiguous + locations. The Irix 6 ABI has examples of this. */ + + if (GET_CODE (reg) == PARALLEL) + { + emit_group_load (reg, args[i].value, + int_size_in_bytes (TREE_TYPE (args[i].tree_value)), + (TYPE_ALIGN (TREE_TYPE (args[i].tree_value)) + / BITS_PER_UNIT)); + } + + /* If simple case, just do move. If normal partial, store_one_arg + has already loaded the register for us. In all other cases, + load the register(s) from memory. */ + + else if (nregs == -1) + emit_move_insn (reg, args[i].value); + + /* If we have pre-computed the values to put in the registers in + the case of non-aligned structures, copy them in now. */ + + else if (args[i].n_aligned_regs != 0) + for (j = 0; j < args[i].n_aligned_regs; j++) + emit_move_insn (gen_rtx_REG (word_mode, REGNO (reg) + j), + args[i].aligned_regs[j]); + + else if (partial == 0 || args[i].pass_on_stack) + move_block_to_reg (REGNO (reg), + validize_mem (args[i].value), nregs, + args[i].mode); + + /* Handle calls that pass values in multiple non-contiguous + locations. The Irix 6 ABI has examples of this. */ + if (GET_CODE (reg) == PARALLEL) + use_group_regs (&call_fusage, reg); + else if (nregs == -1) + use_reg (&call_fusage, reg); + else + use_regs (&call_fusage, REGNO (reg), nregs == 0 ? 1 : nregs); + } + } + + /* Perform postincrements before actually calling the function. */ + emit_queue (); + + /* All arguments and registers used for the call must be set up by now! */ + + /* Generate the actual call instruction. */ + emit_call_1 (funexp, fndecl, funtype, args_size.constant, struct_value_size, + FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1), + valreg, old_inhibit_defer_pop, call_fusage, is_const); + + /* If call is cse'able, make appropriate pair of reg-notes around it. + Test valreg so we don't crash; may safely ignore `const' + if return type is void. Disable for PARALLEL return values, because + we have no way to move such values into a pseudo register. */ + if (is_const && valreg != 0 && GET_CODE (valreg) != PARALLEL) + { + rtx note = 0; + rtx temp = gen_reg_rtx (GET_MODE (valreg)); + rtx insns; + + /* Mark the return value as a pointer if needed. */ + if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE) + { + tree pointed_to = TREE_TYPE (TREE_TYPE (exp)); + mark_reg_pointer (temp, TYPE_ALIGN (pointed_to) / BITS_PER_UNIT); + } + + /* Construct an "equal form" for the value which mentions all the + arguments in order as well as the function name. */ +#ifdef PUSH_ARGS_REVERSED + for (i = 0; i < num_actuals; i++) + note = gen_rtx_EXPR_LIST (VOIDmode, args[i].initial_value, note); +#else + for (i = num_actuals - 1; i >= 0; i--) + note = gen_rtx_EXPR_LIST (VOIDmode, args[i].initial_value, note); +#endif + note = gen_rtx_EXPR_LIST (VOIDmode, funexp, note); + + insns = get_insns (); + end_sequence (); + + emit_libcall_block (insns, temp, valreg, note); + + valreg = temp; + } + else if (is_const) + { + /* Otherwise, just write out the sequence without a note. */ + rtx insns = get_insns (); + + end_sequence (); + emit_insns (insns); + } + else if (is_malloc) + { + rtx temp = gen_reg_rtx (GET_MODE (valreg)); + rtx last, insns; + + /* The return value from a malloc-like function is a pointer. */ + if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE) + mark_reg_pointer (temp, BIGGEST_ALIGNMENT / BITS_PER_UNIT); + + emit_move_insn (temp, valreg); + + /* The return value from a malloc-like function can not alias + anything else. */ + last = get_last_insn (); + REG_NOTES (last) = + gen_rtx_EXPR_LIST (REG_NOALIAS, temp, REG_NOTES (last)); + + /* Write out the sequence. */ + insns = get_insns (); + end_sequence (); + emit_insns (insns); + valreg = temp; + } + + /* For calls to `setjmp', etc., inform flow.c it should complain + if nonvolatile values are live. */ + + if (returns_twice) + { + emit_note (name, NOTE_INSN_SETJMP); + current_function_calls_setjmp = 1; + } + + if (is_longjmp) + current_function_calls_longjmp = 1; + + /* Notice functions that cannot return. + If optimizing, insns emitted below will be dead. + If not optimizing, they will exist, which is useful + if the user uses the `return' command in the debugger. */ + + if (is_volatile || is_longjmp) + emit_barrier (); + + /* If value type not void, return an rtx for the value. */ + + /* If there are cleanups to be called, don't use a hard reg as target. + We need to double check this and see if it matters anymore. */ + if (any_pending_cleanups (1) + && target && REG_P (target) + && REGNO (target) < FIRST_PSEUDO_REGISTER) + target = 0; + + if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode + || ignore) + { + target = const0_rtx; + } + else if (structure_value_addr) + { + if (target == 0 || GET_CODE (target) != MEM) + { + target = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)), + memory_address (TYPE_MODE (TREE_TYPE (exp)), + structure_value_addr)); + MEM_SET_IN_STRUCT_P (target, + AGGREGATE_TYPE_P (TREE_TYPE (exp))); + } + } + else if (pcc_struct_value) + { + /* This is the special C++ case where we need to + know what the true target was. We take care to + never use this value more than once in one expression. */ + target = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)), + copy_to_reg (valreg)); + MEM_SET_IN_STRUCT_P (target, AGGREGATE_TYPE_P (TREE_TYPE (exp))); + } + /* Handle calls that return values in multiple non-contiguous locations. + The Irix 6 ABI has examples of this. */ + else if (GET_CODE (valreg) == PARALLEL) + { + int bytes = int_size_in_bytes (TREE_TYPE (exp)); + + if (target == 0) + { + target = assign_stack_temp (TYPE_MODE (TREE_TYPE (exp)), bytes, 0); + MEM_SET_IN_STRUCT_P (target, AGGREGATE_TYPE_P (TREE_TYPE (exp))); + preserve_temp_slots (target); + } + + emit_group_store (target, valreg, bytes, + TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT); + } + else if (target && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp)) + && GET_MODE (target) == GET_MODE (valreg)) + /* TARGET and VALREG cannot be equal at this point because the latter + would not have REG_FUNCTION_VALUE_P true, while the former would if + it were referring to the same register. + + If they refer to the same register, this move will be a no-op, except + when function inlining is being done. */ + emit_move_insn (target, valreg); + else if (TYPE_MODE (TREE_TYPE (exp)) == BLKmode) + target = copy_blkmode_from_reg (target, valreg, TREE_TYPE (exp)); + else + target = copy_to_reg (valreg); + +#ifdef PROMOTE_FUNCTION_RETURN + /* If we promoted this return value, make the proper SUBREG. TARGET + might be const0_rtx here, so be careful. */ + if (GET_CODE (target) == REG + && TYPE_MODE (TREE_TYPE (exp)) != BLKmode + && GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp))) + { + tree type = TREE_TYPE (exp); + int unsignedp = TREE_UNSIGNED (type); + + /* If we don't promote as expected, something is wrong. */ + if (GET_MODE (target) + != promote_mode (type, TYPE_MODE (type), &unsignedp, 1)) + abort (); + + target = gen_rtx_SUBREG (TYPE_MODE (type), target, 0); + SUBREG_PROMOTED_VAR_P (target) = 1; + SUBREG_PROMOTED_UNSIGNED_P (target) = unsignedp; + } +#endif + + /* If size of args is variable or this was a constructor call for a stack + argument, restore saved stack-pointer value. */ + + if (old_stack_level) + { + emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX); + pending_stack_adjust = old_pending_adj; +#ifdef ACCUMULATE_OUTGOING_ARGS + stack_arg_under_construction = old_stack_arg_under_construction; + highest_outgoing_arg_in_use = initial_highest_arg_in_use; + stack_usage_map = initial_stack_usage_map; +#endif + } +#ifdef ACCUMULATE_OUTGOING_ARGS + else + { +#ifdef REG_PARM_STACK_SPACE + if (save_area) + restore_fixed_argument_area (save_area, argblock, + high_to_save, low_to_save); +#endif + + /* If we saved any argument areas, restore them. */ + for (i = 0; i < num_actuals; i++) + if (args[i].save_area) + { + enum machine_mode save_mode = GET_MODE (args[i].save_area); + rtx stack_area + = gen_rtx_MEM (save_mode, + memory_address (save_mode, + XEXP (args[i].stack_slot, 0))); + + if (save_mode != BLKmode) + emit_move_insn (stack_area, args[i].save_area); + else + emit_block_move (stack_area, validize_mem (args[i].save_area), + GEN_INT (args[i].size.constant), + PARM_BOUNDARY / BITS_PER_UNIT); + } + + highest_outgoing_arg_in_use = initial_highest_arg_in_use; + stack_usage_map = initial_stack_usage_map; + } +#endif + + /* If this was alloca, record the new stack level for nonlocal gotos. + Check for the handler slots since we might not have a save area + for non-local gotos. */ + + if (may_be_alloca && nonlocal_goto_handler_slots != 0) + emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, NULL_RTX); + + pop_temp_slots (); + + /* Free up storage we no longer need. */ + for (i = 0; i < num_actuals; ++i) + if (args[i].aligned_regs) + free (args[i].aligned_regs); + + return target; +} + +/* Output a library call to function FUN (a SYMBOL_REF rtx) + (emitting the queue unless NO_QUEUE is nonzero), + for a value of mode OUTMODE, + with NARGS different arguments, passed as alternating rtx values + and machine_modes to convert them to. + The rtx values should have been passed through protect_from_queue already. + + NO_QUEUE will be true if and only if the library call is a `const' call + which will be enclosed in REG_LIBCALL/REG_RETVAL notes; it is equivalent + to the variable is_const in expand_call. + + NO_QUEUE must be true for const calls, because if it isn't, then + any pending increment will be emitted between REG_LIBCALL/REG_RETVAL notes, + and will be lost if the libcall sequence is optimized away. + + NO_QUEUE must be false for non-const calls, because if it isn't, the + call insn will have its CONST_CALL_P bit set, and it will be incorrectly + optimized. For instance, the instruction scheduler may incorrectly + move memory references across the non-const call. */ + +void +emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode, + int nargs, ...)) +{ +#ifndef ANSI_PROTOTYPES + rtx orgfun; + int no_queue; + enum machine_mode outmode; + int nargs; +#endif + va_list p; + /* Total size in bytes of all the stack-parms scanned so far. */ + struct args_size args_size; + /* Size of arguments before any adjustments (such as rounding). */ + struct args_size original_args_size; + register int argnum; + rtx fun; + int inc; + int count; + rtx argblock = 0; + CUMULATIVE_ARGS args_so_far; + struct arg { rtx value; enum machine_mode mode; rtx reg; int partial; + struct args_size offset; struct args_size size; rtx save_area; }; + struct arg *argvec; + int old_inhibit_defer_pop = inhibit_defer_pop; + rtx call_fusage = 0; + int reg_parm_stack_space = 0; +#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE) + /* Define the boundary of the register parm stack space that needs to be + save, if any. */ + int low_to_save = -1, high_to_save; + rtx save_area = 0; /* Place that it is saved */ +#endif + +#ifdef ACCUMULATE_OUTGOING_ARGS + int initial_highest_arg_in_use = highest_outgoing_arg_in_use; + char *initial_stack_usage_map = stack_usage_map; + int needed; +#endif + +#ifdef REG_PARM_STACK_SPACE + /* Size of the stack reserved for parameter registers. */ +#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 + + VA_START (p, nargs); + +#ifndef ANSI_PROTOTYPES + orgfun = va_arg (p, rtx); + no_queue = va_arg (p, int); + outmode = va_arg (p, enum machine_mode); + nargs = va_arg (p, int); +#endif + + fun = orgfun; + + /* Copy all the libcall-arguments out of the varargs data + and into a vector ARGVEC. + + Compute how to pass each argument. We only support a very small subset + of the full argument passing conventions to limit complexity here since + library functions shouldn't have many args. */ + + argvec = (struct arg *) alloca (nargs * sizeof (struct arg)); + bzero ((char *) argvec, nargs * sizeof (struct arg)); + + + INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun, 0); + + args_size.constant = 0; + args_size.var = 0; + + push_temp_slots (); + + for (count = 0; count < nargs; count++) + { + rtx val = va_arg (p, rtx); + enum machine_mode mode = va_arg (p, enum machine_mode); + + /* We cannot convert the arg value to the mode the library wants here; + must do it earlier where we know the signedness of the arg. */ + if (mode == BLKmode + || (GET_MODE (val) != mode && GET_MODE (val) != VOIDmode)) + abort (); + + /* On some machines, there's no way to pass a float to a library fcn. + Pass it as a double instead. */ +#ifdef LIBGCC_NEEDS_DOUBLE + if (LIBGCC_NEEDS_DOUBLE && mode == SFmode) + val = convert_modes (DFmode, SFmode, val, 0), mode = DFmode; +#endif + + /* There's no need to call protect_from_queue, because + either emit_move_insn or emit_push_insn will do that. */ + + /* Make sure it is a reasonable operand for a move or push insn. */ + if (GET_CODE (val) != REG && GET_CODE (val) != MEM + && ! (CONSTANT_P (val) && LEGITIMATE_CONSTANT_P (val))) + val = force_operand (val, NULL_RTX); + +#ifdef FUNCTION_ARG_PASS_BY_REFERENCE + if (FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, mode, NULL_TREE, 1)) + { + /* We do not support FUNCTION_ARG_CALLEE_COPIES here since it can + be viewed as just an efficiency improvement. */ + rtx slot = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0); + emit_move_insn (slot, val); + val = force_operand (XEXP (slot, 0), NULL_RTX); + mode = Pmode; + } +#endif + + argvec[count].value = val; + argvec[count].mode = mode; + + argvec[count].reg = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1); + if (argvec[count].reg && GET_CODE (argvec[count].reg) == PARALLEL) + abort (); +#ifdef FUNCTION_ARG_PARTIAL_NREGS + argvec[count].partial + = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, NULL_TREE, 1); +#else + argvec[count].partial = 0; +#endif + + locate_and_pad_parm (mode, NULL_TREE, + argvec[count].reg && argvec[count].partial == 0, + NULL_TREE, &args_size, &argvec[count].offset, + &argvec[count].size); + + if (argvec[count].size.var) + abort (); + + if (reg_parm_stack_space == 0 && argvec[count].partial) + argvec[count].size.constant -= argvec[count].partial * UNITS_PER_WORD; + + if (argvec[count].reg == 0 || argvec[count].partial != 0 + || reg_parm_stack_space > 0) + args_size.constant += argvec[count].size.constant; + + FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree) 0, 1); + } + va_end (p); + +#ifdef FINAL_REG_PARM_STACK_SPACE + reg_parm_stack_space = FINAL_REG_PARM_STACK_SPACE (args_size.constant, + args_size.var); +#endif + + /* If this machine requires an external definition for library + functions, write one out. */ + assemble_external_libcall (fun); + + original_args_size = args_size; +#ifdef PREFERRED_STACK_BOUNDARY + args_size.constant = (((args_size.constant + (STACK_BYTES - 1)) + / STACK_BYTES) * STACK_BYTES); +#endif + + args_size.constant = MAX (args_size.constant, + reg_parm_stack_space); + +#ifndef OUTGOING_REG_PARM_STACK_SPACE + args_size.constant -= reg_parm_stack_space; +#endif + + if (args_size.constant > current_function_outgoing_args_size) + current_function_outgoing_args_size = args_size.constant; + +#ifdef ACCUMULATE_OUTGOING_ARGS + /* Since the stack pointer will never be pushed, it is possible for + the evaluation of a parm to clobber something we have already + written to the stack. Since most function calls on RISC machines + do not use the stack, this is uncommon, but must work correctly. + + Therefore, we save any area of the stack that was already written + and that we are using. Here we set up to do this by making a new + stack usage map from the old one. + + Another approach might be to try to reorder the argument + evaluations to avoid this conflicting stack usage. */ + + needed = args_size.constant; + +#ifndef OUTGOING_REG_PARM_STACK_SPACE + /* Since we will be writing into the entire argument area, the + map must be allocated for its entire size, not just the part that + is the responsibility of the caller. */ + needed += reg_parm_stack_space; +#endif + +#ifdef ARGS_GROW_DOWNWARD + highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use, + needed + 1); +#else + highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use, + needed); +#endif + stack_usage_map = (char *) alloca (highest_outgoing_arg_in_use); + + if (initial_highest_arg_in_use) + bcopy (initial_stack_usage_map, stack_usage_map, + initial_highest_arg_in_use); + + if (initial_highest_arg_in_use != highest_outgoing_arg_in_use) + bzero (&stack_usage_map[initial_highest_arg_in_use], + highest_outgoing_arg_in_use - initial_highest_arg_in_use); + needed = 0; + + /* The address of the outgoing argument list must not be copied to a + register here, because argblock would be left pointing to the + wrong place after the call to allocate_dynamic_stack_space below. + */ + + argblock = virtual_outgoing_args_rtx; +#else /* not ACCUMULATE_OUTGOING_ARGS */ +#ifndef PUSH_ROUNDING + argblock = push_block (GEN_INT (args_size.constant), 0, 0); +#endif +#endif + +#ifdef PUSH_ARGS_REVERSED +#ifdef PREFERRED_STACK_BOUNDARY + /* If we push args individually in reverse order, perform stack alignment + before the first push (the last arg). */ + if (argblock == 0) + anti_adjust_stack (GEN_INT (args_size.constant + - original_args_size.constant)); +#endif +#endif + +#ifdef PUSH_ARGS_REVERSED + inc = -1; + argnum = nargs - 1; +#else + inc = 1; + argnum = 0; +#endif + +#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE) + /* The argument list is the property of the called routine and it + may clobber it. If the fixed area has been used for previous + parameters, we must save and restore it. + + Here we compute the boundary of the that needs to be saved, if any. */ + +#ifdef ARGS_GROW_DOWNWARD + for (count = 0; count < reg_parm_stack_space + 1; count++) +#else + for (count = 0; count < reg_parm_stack_space; count++) +#endif + { + if (count >= highest_outgoing_arg_in_use + || stack_usage_map[count] == 0) + continue; + + if (low_to_save == -1) + low_to_save = count; + + high_to_save = count; + } + + if (low_to_save >= 0) + { + int num_to_save = high_to_save - low_to_save + 1; + enum machine_mode save_mode + = mode_for_size (num_to_save * BITS_PER_UNIT, MODE_INT, 1); + rtx stack_area; + + /* If we don't have the required alignment, must do this in BLKmode. */ + if ((low_to_save & (MIN (GET_MODE_SIZE (save_mode), + BIGGEST_ALIGNMENT / UNITS_PER_WORD) - 1))) + save_mode = BLKmode; + +#ifdef ARGS_GROW_DOWNWARD + stack_area = gen_rtx_MEM (save_mode, + memory_address (save_mode, + plus_constant (argblock, + - high_to_save))); +#else + stack_area = gen_rtx_MEM (save_mode, + memory_address (save_mode, + plus_constant (argblock, + low_to_save))); +#endif + if (save_mode == BLKmode) + { + save_area = assign_stack_temp (BLKmode, num_to_save, 0); + emit_block_move (validize_mem (save_area), stack_area, + GEN_INT (num_to_save), + PARM_BOUNDARY / BITS_PER_UNIT); + } + else + { + save_area = gen_reg_rtx (save_mode); + emit_move_insn (save_area, stack_area); + } + } +#endif + + /* Push the args that need to be pushed. */ + + /* ARGNUM indexes the ARGVEC array in the order in which the arguments + are to be pushed. */ + for (count = 0; count < nargs; count++, argnum += inc) + { + register enum machine_mode mode = argvec[argnum].mode; + register rtx val = argvec[argnum].value; + rtx reg = argvec[argnum].reg; + int partial = argvec[argnum].partial; +#ifdef ACCUMULATE_OUTGOING_ARGS + int lower_bound, upper_bound, i; +#endif + + if (! (reg != 0 && partial == 0)) + { +#ifdef ACCUMULATE_OUTGOING_ARGS + /* If this is being stored into a pre-allocated, fixed-size, stack + area, save any previous data at that location. */ + +#ifdef ARGS_GROW_DOWNWARD + /* stack_slot is negative, but we want to index stack_usage_map + with positive values. */ + upper_bound = -argvec[argnum].offset.constant + 1; + lower_bound = upper_bound - argvec[argnum].size.constant; +#else + lower_bound = argvec[argnum].offset.constant; + upper_bound = lower_bound + argvec[argnum].size.constant; +#endif + + for (i = lower_bound; i < upper_bound; i++) + if (stack_usage_map[i] + /* Don't store things in the fixed argument area at this point; + it has already been saved. */ + && i > reg_parm_stack_space) + break; + + if (i != upper_bound) + { + /* We need to make a save area. See what mode we can make it. */ + enum machine_mode save_mode + = mode_for_size (argvec[argnum].size.constant * BITS_PER_UNIT, + MODE_INT, 1); + rtx stack_area + = gen_rtx_MEM (save_mode, + memory_address (save_mode, + plus_constant (argblock, argvec[argnum].offset.constant))); + argvec[argnum].save_area = gen_reg_rtx (save_mode); + emit_move_insn (argvec[argnum].save_area, stack_area); + } +#endif + emit_push_insn (val, mode, NULL_TREE, NULL_RTX, 0, partial, reg, 0, + argblock, GEN_INT (argvec[argnum].offset.constant), + reg_parm_stack_space); + +#ifdef ACCUMULATE_OUTGOING_ARGS + /* Now mark the segment we just used. */ + for (i = lower_bound; i < upper_bound; i++) + stack_usage_map[i] = 1; +#endif + + NO_DEFER_POP; + } + } + +#ifndef PUSH_ARGS_REVERSED +#ifdef PREFERRED_STACK_BOUNDARY + /* If we pushed args in forward order, perform stack alignment + after pushing the last arg. */ + if (argblock == 0) + anti_adjust_stack (GEN_INT (args_size.constant + - original_args_size.constant)); +#endif +#endif + +#ifdef PUSH_ARGS_REVERSED + argnum = nargs - 1; +#else + argnum = 0; +#endif + + fun = prepare_call_address (fun, NULL_TREE, &call_fusage, 0); + + /* Now load any reg parms into their regs. */ + + /* ARGNUM indexes the ARGVEC array in the order in which the arguments + are to be pushed. */ + for (count = 0; count < nargs; count++, argnum += inc) + { + register rtx val = argvec[argnum].value; + rtx reg = argvec[argnum].reg; + int partial = argvec[argnum].partial; + + if (reg != 0 && partial == 0) + emit_move_insn (reg, val); + NO_DEFER_POP; + } + + /* For version 1.37, try deleting this entirely. */ + if (! no_queue) + emit_queue (); + + /* Any regs containing parms remain in use through the call. */ + for (count = 0; count < nargs; count++) + if (argvec[count].reg != 0) + use_reg (&call_fusage, argvec[count].reg); + + /* Don't allow popping to be deferred, since then + cse'ing of library calls could delete a call and leave the pop. */ + NO_DEFER_POP; + + /* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which + will set inhibit_defer_pop to that value. */ + + /* The return type is needed to decide how many bytes the function pops. + Signedness plays no role in that, so for simplicity, we pretend it's + always signed. We also assume that the list of arguments passed has + no impact, so we pretend it is unknown. */ + + emit_call_1 (fun, + get_identifier (XSTR (orgfun, 0)), + build_function_type (outmode == VOIDmode ? void_type_node + : type_for_mode (outmode, 0), NULL_TREE), + args_size.constant, 0, + FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1), + outmode != VOIDmode ? hard_libcall_value (outmode) : NULL_RTX, + old_inhibit_defer_pop + 1, call_fusage, no_queue); + + pop_temp_slots (); + + /* Now restore inhibit_defer_pop to its actual original value. */ + OK_DEFER_POP; + +#ifdef ACCUMULATE_OUTGOING_ARGS +#ifdef REG_PARM_STACK_SPACE + if (save_area) + { + enum machine_mode save_mode = GET_MODE (save_area); +#ifdef ARGS_GROW_DOWNWARD + rtx stack_area + = gen_rtx_MEM (save_mode, + memory_address (save_mode, + plus_constant (argblock, + - high_to_save))); +#else + rtx stack_area + = gen_rtx_MEM (save_mode, + memory_address (save_mode, + plus_constant (argblock, low_to_save))); +#endif + + if (save_mode != BLKmode) + emit_move_insn (stack_area, save_area); + else + emit_block_move (stack_area, validize_mem (save_area), + GEN_INT (high_to_save - low_to_save + 1), + PARM_BOUNDARY / BITS_PER_UNIT); + } +#endif + + /* If we saved any argument areas, restore them. */ + for (count = 0; count < nargs; count++) + if (argvec[count].save_area) + { + enum machine_mode save_mode = GET_MODE (argvec[count].save_area); + rtx stack_area + = gen_rtx_MEM (save_mode, + memory_address (save_mode, + plus_constant (argblock, argvec[count].offset.constant))); + + emit_move_insn (stack_area, argvec[count].save_area); + } + + highest_outgoing_arg_in_use = initial_highest_arg_in_use; + stack_usage_map = initial_stack_usage_map; +#endif +} + +/* Like emit_library_call except that an extra argument, VALUE, + comes second and says where to store the result. + (If VALUE is zero, this function chooses a convenient way + to return the value. + + This function returns an rtx for where the value is to be found. + If VALUE is nonzero, VALUE is returned. */ + +rtx +emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue, + enum machine_mode outmode, int nargs, ...)) +{ +#ifndef ANSI_PROTOTYPES + rtx orgfun; + rtx value; + int no_queue; + enum machine_mode outmode; + int nargs; +#endif + va_list p; + /* Total size in bytes of all the stack-parms scanned so far. */ + struct args_size args_size; + /* Size of arguments before any adjustments (such as rounding). */ + struct args_size original_args_size; + register int argnum; + rtx fun; + int inc; + int count; + rtx argblock = 0; + CUMULATIVE_ARGS args_so_far; + struct arg { rtx value; enum machine_mode mode; rtx reg; int partial; + struct args_size offset; struct args_size size; rtx save_area; }; + struct arg *argvec; + int old_inhibit_defer_pop = inhibit_defer_pop; + rtx call_fusage = 0; + rtx mem_value = 0; + int pcc_struct_value = 0; + int struct_value_size = 0; + int is_const; + int reg_parm_stack_space = 0; +#ifdef ACCUMULATE_OUTGOING_ARGS + int needed; +#endif + +#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE) + /* Define the boundary of the register parm stack space that needs to be + save, if any. */ + int low_to_save = -1, high_to_save; + rtx save_area = 0; /* Place that it is saved */ +#endif + +#ifdef ACCUMULATE_OUTGOING_ARGS + /* Size of the stack reserved for parameter registers. */ + int initial_highest_arg_in_use = highest_outgoing_arg_in_use; + char *initial_stack_usage_map = stack_usage_map; +#endif + +#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 + + VA_START (p, nargs); + +#ifndef ANSI_PROTOTYPES + orgfun = va_arg (p, rtx); + value = va_arg (p, rtx); + no_queue = va_arg (p, int); + outmode = va_arg (p, enum machine_mode); + nargs = va_arg (p, int); +#endif + + is_const = no_queue; + fun = orgfun; + + /* If this kind of value comes back in memory, + decide where in memory it should come back. */ + if (aggregate_value_p (type_for_mode (outmode, 0))) + { +#ifdef PCC_STATIC_STRUCT_RETURN + rtx pointer_reg + = hard_function_value (build_pointer_type (type_for_mode (outmode, 0)), + 0); + mem_value = gen_rtx_MEM (outmode, pointer_reg); + pcc_struct_value = 1; + if (value == 0) + value = gen_reg_rtx (outmode); +#else /* not PCC_STATIC_STRUCT_RETURN */ + struct_value_size = GET_MODE_SIZE (outmode); + if (value != 0 && GET_CODE (value) == MEM) + mem_value = value; + else + mem_value = assign_stack_temp (outmode, GET_MODE_SIZE (outmode), 0); +#endif + + /* This call returns a big structure. */ + is_const = 0; + } + + /* ??? Unfinished: must pass the memory address as an argument. */ + + /* Copy all the libcall-arguments out of the varargs data + and into a vector ARGVEC. + + Compute how to pass each argument. We only support a very small subset + of the full argument passing conventions to limit complexity here since + library functions shouldn't have many args. */ + + argvec = (struct arg *) alloca ((nargs + 1) * sizeof (struct arg)); + bzero ((char *) argvec, (nargs + 1) * sizeof (struct arg)); + + INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun, 0); + + args_size.constant = 0; + args_size.var = 0; + + count = 0; + + push_temp_slots (); + + /* If there's a structure value address to be passed, + either pass it in the special place, or pass it as an extra argument. */ + if (mem_value && struct_value_rtx == 0 && ! pcc_struct_value) + { + rtx addr = XEXP (mem_value, 0); + nargs++; + + /* Make sure it is a reasonable operand for a move or push insn. */ + if (GET_CODE (addr) != REG && GET_CODE (addr) != MEM + && ! (CONSTANT_P (addr) && LEGITIMATE_CONSTANT_P (addr))) + addr = force_operand (addr, NULL_RTX); + + argvec[count].value = addr; + argvec[count].mode = Pmode; + argvec[count].partial = 0; + + argvec[count].reg = FUNCTION_ARG (args_so_far, Pmode, NULL_TREE, 1); +#ifdef FUNCTION_ARG_PARTIAL_NREGS + if (FUNCTION_ARG_PARTIAL_NREGS (args_so_far, Pmode, NULL_TREE, 1)) + abort (); +#endif + + locate_and_pad_parm (Pmode, NULL_TREE, + argvec[count].reg && argvec[count].partial == 0, + NULL_TREE, &args_size, &argvec[count].offset, + &argvec[count].size); + + + if (argvec[count].reg == 0 || argvec[count].partial != 0 + || reg_parm_stack_space > 0) + args_size.constant += argvec[count].size.constant; + + FUNCTION_ARG_ADVANCE (args_so_far, Pmode, (tree) 0, 1); + + count++; + } + + for (; count < nargs; count++) + { + rtx val = va_arg (p, rtx); + enum machine_mode mode = va_arg (p, enum machine_mode); + + /* We cannot convert the arg value to the mode the library wants here; + must do it earlier where we know the signedness of the arg. */ + if (mode == BLKmode + || (GET_MODE (val) != mode && GET_MODE (val) != VOIDmode)) + abort (); + + /* On some machines, there's no way to pass a float to a library fcn. + Pass it as a double instead. */ +#ifdef LIBGCC_NEEDS_DOUBLE + if (LIBGCC_NEEDS_DOUBLE && mode == SFmode) + val = convert_modes (DFmode, SFmode, val, 0), mode = DFmode; +#endif + + /* There's no need to call protect_from_queue, because + either emit_move_insn or emit_push_insn will do that. */ + + /* Make sure it is a reasonable operand for a move or push insn. */ + if (GET_CODE (val) != REG && GET_CODE (val) != MEM + && ! (CONSTANT_P (val) && LEGITIMATE_CONSTANT_P (val))) + val = force_operand (val, NULL_RTX); + +#ifdef FUNCTION_ARG_PASS_BY_REFERENCE + if (FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, mode, NULL_TREE, 1)) + { + /* We do not support FUNCTION_ARG_CALLEE_COPIES here since it can + be viewed as just an efficiency improvement. */ + rtx slot = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0); + emit_move_insn (slot, val); + val = XEXP (slot, 0); + mode = Pmode; + } +#endif + + argvec[count].value = val; + argvec[count].mode = mode; + + argvec[count].reg = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1); + if (argvec[count].reg && GET_CODE (argvec[count].reg) == PARALLEL) + abort (); +#ifdef FUNCTION_ARG_PARTIAL_NREGS + argvec[count].partial + = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, NULL_TREE, 1); +#else + argvec[count].partial = 0; +#endif + + locate_and_pad_parm (mode, NULL_TREE, + argvec[count].reg && argvec[count].partial == 0, + NULL_TREE, &args_size, &argvec[count].offset, + &argvec[count].size); + + if (argvec[count].size.var) + abort (); + + if (reg_parm_stack_space == 0 && argvec[count].partial) + argvec[count].size.constant -= argvec[count].partial * UNITS_PER_WORD; + + if (argvec[count].reg == 0 || argvec[count].partial != 0 + || reg_parm_stack_space > 0) + args_size.constant += argvec[count].size.constant; + + FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree) 0, 1); + } + va_end (p); + +#ifdef FINAL_REG_PARM_STACK_SPACE + reg_parm_stack_space = FINAL_REG_PARM_STACK_SPACE (args_size.constant, + args_size.var); +#endif + /* If this machine requires an external definition for library + functions, write one out. */ + assemble_external_libcall (fun); + + original_args_size = args_size; +#ifdef PREFERRED_STACK_BOUNDARY + args_size.constant = (((args_size.constant + (STACK_BYTES - 1)) + / STACK_BYTES) * STACK_BYTES); +#endif + + args_size.constant = MAX (args_size.constant, + reg_parm_stack_space); + +#ifndef OUTGOING_REG_PARM_STACK_SPACE + args_size.constant -= reg_parm_stack_space; +#endif + + if (args_size.constant > current_function_outgoing_args_size) + current_function_outgoing_args_size = args_size.constant; + +#ifdef ACCUMULATE_OUTGOING_ARGS + /* Since the stack pointer will never be pushed, it is possible for + the evaluation of a parm to clobber something we have already + written to the stack. Since most function calls on RISC machines + do not use the stack, this is uncommon, but must work correctly. + + Therefore, we save any area of the stack that was already written + and that we are using. Here we set up to do this by making a new + stack usage map from the old one. + + Another approach might be to try to reorder the argument + evaluations to avoid this conflicting stack usage. */ + + needed = args_size.constant; + +#ifndef OUTGOING_REG_PARM_STACK_SPACE + /* Since we will be writing into the entire argument area, the + map must be allocated for its entire size, not just the part that + is the responsibility of the caller. */ + needed += reg_parm_stack_space; +#endif + +#ifdef ARGS_GROW_DOWNWARD + highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use, + needed + 1); +#else + highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use, + needed); +#endif + stack_usage_map = (char *) alloca (highest_outgoing_arg_in_use); + + if (initial_highest_arg_in_use) + bcopy (initial_stack_usage_map, stack_usage_map, + initial_highest_arg_in_use); + + if (initial_highest_arg_in_use != highest_outgoing_arg_in_use) + bzero (&stack_usage_map[initial_highest_arg_in_use], + highest_outgoing_arg_in_use - initial_highest_arg_in_use); + needed = 0; + + /* The address of the outgoing argument list must not be copied to a + register here, because argblock would be left pointing to the + wrong place after the call to allocate_dynamic_stack_space below. + */ + + argblock = virtual_outgoing_args_rtx; +#else /* not ACCUMULATE_OUTGOING_ARGS */ +#ifndef PUSH_ROUNDING + argblock = push_block (GEN_INT (args_size.constant), 0, 0); +#endif +#endif + +#ifdef PUSH_ARGS_REVERSED +#ifdef PREFERRED_STACK_BOUNDARY + /* If we push args individually in reverse order, perform stack alignment + before the first push (the last arg). */ + if (argblock == 0) + anti_adjust_stack (GEN_INT (args_size.constant + - original_args_size.constant)); +#endif +#endif + +#ifdef PUSH_ARGS_REVERSED + inc = -1; + argnum = nargs - 1; +#else + inc = 1; + argnum = 0; +#endif + +#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE) + /* The argument list is the property of the called routine and it + may clobber it. If the fixed area has been used for previous + parameters, we must save and restore it. + + Here we compute the boundary of the that needs to be saved, if any. */ + +#ifdef ARGS_GROW_DOWNWARD + for (count = 0; count < reg_parm_stack_space + 1; count++) +#else + for (count = 0; count < reg_parm_stack_space; count++) +#endif + { + if (count >= highest_outgoing_arg_in_use + || stack_usage_map[count] == 0) + continue; + + if (low_to_save == -1) + low_to_save = count; + + high_to_save = count; + } + + if (low_to_save >= 0) + { + int num_to_save = high_to_save - low_to_save + 1; + enum machine_mode save_mode + = mode_for_size (num_to_save * BITS_PER_UNIT, MODE_INT, 1); + rtx stack_area; + + /* If we don't have the required alignment, must do this in BLKmode. */ + if ((low_to_save & (MIN (GET_MODE_SIZE (save_mode), + BIGGEST_ALIGNMENT / UNITS_PER_WORD) - 1))) + save_mode = BLKmode; + +#ifdef ARGS_GROW_DOWNWARD + stack_area = gen_rtx_MEM (save_mode, + memory_address (save_mode, + plus_constant (argblock, + - high_to_save))); +#else + stack_area = gen_rtx_MEM (save_mode, + memory_address (save_mode, + plus_constant (argblock, + low_to_save))); +#endif + if (save_mode == BLKmode) + { + save_area = assign_stack_temp (BLKmode, num_to_save, 0); + emit_block_move (validize_mem (save_area), stack_area, + GEN_INT (num_to_save), + PARM_BOUNDARY / BITS_PER_UNIT); + } + else + { + save_area = gen_reg_rtx (save_mode); + emit_move_insn (save_area, stack_area); + } + } +#endif + + /* Push the args that need to be pushed. */ + + /* ARGNUM indexes the ARGVEC array in the order in which the arguments + are to be pushed. */ + for (count = 0; count < nargs; count++, argnum += inc) + { + register enum machine_mode mode = argvec[argnum].mode; + register rtx val = argvec[argnum].value; + rtx reg = argvec[argnum].reg; + int partial = argvec[argnum].partial; +#ifdef ACCUMULATE_OUTGOING_ARGS + int lower_bound, upper_bound, i; +#endif + + if (! (reg != 0 && partial == 0)) + { +#ifdef ACCUMULATE_OUTGOING_ARGS + /* If this is being stored into a pre-allocated, fixed-size, stack + area, save any previous data at that location. */ + +#ifdef ARGS_GROW_DOWNWARD + /* stack_slot is negative, but we want to index stack_usage_map + with positive values. */ + upper_bound = -argvec[argnum].offset.constant + 1; + lower_bound = upper_bound - argvec[argnum].size.constant; +#else + lower_bound = argvec[argnum].offset.constant; + upper_bound = lower_bound + argvec[argnum].size.constant; +#endif + + for (i = lower_bound; i < upper_bound; i++) + if (stack_usage_map[i] + /* Don't store things in the fixed argument area at this point; + it has already been saved. */ + && i > reg_parm_stack_space) + break; + + if (i != upper_bound) + { + /* We need to make a save area. See what mode we can make it. */ + enum machine_mode save_mode + = mode_for_size (argvec[argnum].size.constant * BITS_PER_UNIT, + MODE_INT, 1); + rtx stack_area + = gen_rtx_MEM (save_mode, + memory_address (save_mode, + plus_constant (argblock, + argvec[argnum].offset.constant))); + argvec[argnum].save_area = gen_reg_rtx (save_mode); + emit_move_insn (argvec[argnum].save_area, stack_area); + } +#endif + emit_push_insn (val, mode, NULL_TREE, NULL_RTX, 0, partial, reg, 0, + argblock, GEN_INT (argvec[argnum].offset.constant), + reg_parm_stack_space); + +#ifdef ACCUMULATE_OUTGOING_ARGS + /* Now mark the segment we just used. */ + for (i = lower_bound; i < upper_bound; i++) + stack_usage_map[i] = 1; +#endif + + NO_DEFER_POP; + } + } + +#ifndef PUSH_ARGS_REVERSED +#ifdef PREFERRED_STACK_BOUNDARY + /* If we pushed args in forward order, perform stack alignment + after pushing the last arg. */ + if (argblock == 0) + anti_adjust_stack (GEN_INT (args_size.constant + - original_args_size.constant)); +#endif +#endif + +#ifdef PUSH_ARGS_REVERSED + argnum = nargs - 1; +#else + argnum = 0; +#endif + + fun = prepare_call_address (fun, NULL_TREE, &call_fusage, 0); + + /* Now load any reg parms into their regs. */ + + /* ARGNUM indexes the ARGVEC array in the order in which the arguments + are to be pushed. */ + for (count = 0; count < nargs; count++, argnum += inc) + { + register rtx val = argvec[argnum].value; + rtx reg = argvec[argnum].reg; + int partial = argvec[argnum].partial; + + if (reg != 0 && partial == 0) + emit_move_insn (reg, val); + NO_DEFER_POP; + } + +#if 0 + /* For version 1.37, try deleting this entirely. */ + if (! no_queue) + emit_queue (); +#endif + + /* Any regs containing parms remain in use through the call. */ + for (count = 0; count < nargs; count++) + if (argvec[count].reg != 0) + use_reg (&call_fusage, argvec[count].reg); + + /* Pass the function the address in which to return a structure value. */ + if (mem_value != 0 && struct_value_rtx != 0 && ! pcc_struct_value) + { + emit_move_insn (struct_value_rtx, + force_reg (Pmode, + force_operand (XEXP (mem_value, 0), + NULL_RTX))); + if (GET_CODE (struct_value_rtx) == REG) + use_reg (&call_fusage, struct_value_rtx); + } + + /* Don't allow popping to be deferred, since then + cse'ing of library calls could delete a call and leave the pop. */ + NO_DEFER_POP; + + /* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which + will set inhibit_defer_pop to that value. */ + /* See the comment in emit_library_call about the function type we build + and pass here. */ + + emit_call_1 (fun, + get_identifier (XSTR (orgfun, 0)), + build_function_type (type_for_mode (outmode, 0), NULL_TREE), + args_size.constant, struct_value_size, + FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1), + mem_value == 0 ? hard_libcall_value (outmode) : NULL_RTX, + old_inhibit_defer_pop + 1, call_fusage, is_const); + + /* Now restore inhibit_defer_pop to its actual original value. */ + OK_DEFER_POP; + + pop_temp_slots (); + + /* Copy the value to the right place. */ + if (outmode != VOIDmode) + { + if (mem_value) + { + if (value == 0) + value = mem_value; + if (value != mem_value) + emit_move_insn (value, mem_value); + } + else if (value != 0) + emit_move_insn (value, hard_libcall_value (outmode)); + else + value = hard_libcall_value (outmode); + } + +#ifdef ACCUMULATE_OUTGOING_ARGS +#ifdef REG_PARM_STACK_SPACE + if (save_area) + { + enum machine_mode save_mode = GET_MODE (save_area); +#ifdef ARGS_GROW_DOWNWARD + rtx stack_area + = gen_rtx_MEM (save_mode, + memory_address (save_mode, + plus_constant (argblock, + - high_to_save))); +#else + rtx stack_area + = gen_rtx_MEM (save_mode, + memory_address (save_mode, + plus_constant (argblock, low_to_save))); +#endif + if (save_mode != BLKmode) + emit_move_insn (stack_area, save_area); + else + emit_block_move (stack_area, validize_mem (save_area), + GEN_INT (high_to_save - low_to_save + 1), + PARM_BOUNDARY / BITS_PER_UNIT); + } +#endif + + /* If we saved any argument areas, restore them. */ + for (count = 0; count < nargs; count++) + if (argvec[count].save_area) + { + enum machine_mode save_mode = GET_MODE (argvec[count].save_area); + rtx stack_area + = gen_rtx_MEM (save_mode, + memory_address (save_mode, plus_constant (argblock, + argvec[count].offset.constant))); + + emit_move_insn (stack_area, argvec[count].save_area); + } + + highest_outgoing_arg_in_use = initial_highest_arg_in_use; + stack_usage_map = initial_stack_usage_map; +#endif + + return value; +} + +#if 0 +/* Return an rtx which represents a suitable home on the stack + given TYPE, the type of the argument looking for a home. + This is called only for BLKmode arguments. + + SIZE is the size needed for this target. + ARGS_ADDR is the address of the bottom of the argument block for this call. + OFFSET describes this parameter's offset into ARGS_ADDR. It is meaningless + if this machine uses push insns. */ + +static rtx +target_for_arg (type, size, args_addr, offset) + tree type; + rtx size; + rtx args_addr; + struct args_size offset; +{ + rtx target; + rtx offset_rtx = ARGS_SIZE_RTX (offset); + + /* We do not call memory_address if possible, + because we want to address as close to the stack + as possible. For non-variable sized arguments, + this will be stack-pointer relative addressing. */ + if (GET_CODE (offset_rtx) == CONST_INT) + target = plus_constant (args_addr, INTVAL (offset_rtx)); + else + { + /* I have no idea how to guarantee that this + will work in the presence of register parameters. */ + target = gen_rtx_PLUS (Pmode, args_addr, offset_rtx); + target = memory_address (QImode, target); + } + + return gen_rtx_MEM (BLKmode, target); +} +#endif + +/* Store a single argument for a function call + into the register or memory area where it must be passed. + *ARG describes the argument value and where to pass it. + + ARGBLOCK is the address of the stack-block for all the arguments, + or 0 on a machine where arguments are pushed individually. + + MAY_BE_ALLOCA nonzero says this could be a call to `alloca' + so must be careful about how the stack is used. + + VARIABLE_SIZE nonzero says that this was a variable-sized outgoing + argument stack. This is used if ACCUMULATE_OUTGOING_ARGS to indicate + that we need not worry about saving and restoring the stack. + + FNDECL is the declaration of the function we are calling. */ + +static void +store_one_arg (arg, argblock, may_be_alloca, variable_size, + reg_parm_stack_space) + struct arg_data *arg; + rtx argblock; + int may_be_alloca; + int variable_size; + int reg_parm_stack_space; +{ + register tree pval = arg->tree_value; + rtx reg = 0; + int partial = 0; + int used = 0; +#ifdef ACCUMULATE_OUTGOING_ARGS + int i, lower_bound, upper_bound; +#endif + + if (TREE_CODE (pval) == ERROR_MARK) + return; + + /* Push a new temporary level for any temporaries we make for + this argument. */ + push_temp_slots (); + +#ifdef ACCUMULATE_OUTGOING_ARGS + /* If this is being stored into a pre-allocated, fixed-size, stack area, + save any previous data at that location. */ + if (argblock && ! variable_size && arg->stack) + { +#ifdef ARGS_GROW_DOWNWARD + /* stack_slot is negative, but we want to index stack_usage_map + with positive values. */ + if (GET_CODE (XEXP (arg->stack_slot, 0)) == PLUS) + upper_bound = -INTVAL (XEXP (XEXP (arg->stack_slot, 0), 1)) + 1; + else + upper_bound = 0; + + lower_bound = upper_bound - arg->size.constant; +#else + if (GET_CODE (XEXP (arg->stack_slot, 0)) == PLUS) + lower_bound = INTVAL (XEXP (XEXP (arg->stack_slot, 0), 1)); + else + lower_bound = 0; + + upper_bound = lower_bound + arg->size.constant; +#endif + + for (i = lower_bound; i < upper_bound; i++) + if (stack_usage_map[i] + /* Don't store things in the fixed argument area at this point; + it has already been saved. */ + && i > reg_parm_stack_space) + break; + + if (i != upper_bound) + { + /* We need to make a save area. See what mode we can make it. */ + enum machine_mode save_mode + = mode_for_size (arg->size.constant * BITS_PER_UNIT, MODE_INT, 1); + rtx stack_area + = gen_rtx_MEM (save_mode, + memory_address (save_mode, + XEXP (arg->stack_slot, 0))); + + if (save_mode == BLKmode) + { + arg->save_area = assign_stack_temp (BLKmode, + arg->size.constant, 0); + MEM_SET_IN_STRUCT_P (arg->save_area, + AGGREGATE_TYPE_P (TREE_TYPE + (arg->tree_value))); + preserve_temp_slots (arg->save_area); + emit_block_move (validize_mem (arg->save_area), stack_area, + GEN_INT (arg->size.constant), + PARM_BOUNDARY / BITS_PER_UNIT); + } + else + { + arg->save_area = gen_reg_rtx (save_mode); + emit_move_insn (arg->save_area, stack_area); + } + } + } + + /* Now that we have saved any slots that will be overwritten by this + store, mark all slots this store will use. We must do this before + we actually expand the argument since the expansion itself may + trigger library calls which might need to use the same stack slot. */ + if (argblock && ! variable_size && arg->stack) + for (i = lower_bound; i < upper_bound; i++) + stack_usage_map[i] = 1; +#endif + + /* If this isn't going to be placed on both the stack and in registers, + set up the register and number of words. */ + if (! arg->pass_on_stack) + reg = arg->reg, partial = arg->partial; + + if (reg != 0 && partial == 0) + /* Being passed entirely in a register. We shouldn't be called in + this case. */ + abort (); + + /* If this arg needs special alignment, don't load the registers + here. */ + if (arg->n_aligned_regs != 0) + reg = 0; + + /* If this is being passed partially in a register, we can't evaluate + it directly into its stack slot. Otherwise, we can. */ + if (arg->value == 0) + { +#ifdef ACCUMULATE_OUTGOING_ARGS + /* stack_arg_under_construction is nonzero if a function argument is + being evaluated directly into the outgoing argument list and + expand_call must take special action to preserve the argument list + if it is called recursively. + + For scalar function arguments stack_usage_map is sufficient to + determine which stack slots must be saved and restored. Scalar + arguments in general have pass_on_stack == 0. + + If this argument is initialized by a function which takes the + address of the argument (a C++ constructor or a C function + returning a BLKmode structure), then stack_usage_map is + insufficient and expand_call must push the stack around the + function call. Such arguments have pass_on_stack == 1. + + Note that it is always safe to set stack_arg_under_construction, + but this generates suboptimal code if set when not needed. */ + + if (arg->pass_on_stack) + stack_arg_under_construction++; +#endif + arg->value = expand_expr (pval, + (partial + || TYPE_MODE (TREE_TYPE (pval)) != arg->mode) + ? NULL_RTX : arg->stack, + VOIDmode, 0); + + /* If we are promoting object (or for any other reason) the mode + doesn't agree, convert the mode. */ + + if (arg->mode != TYPE_MODE (TREE_TYPE (pval))) + arg->value = convert_modes (arg->mode, TYPE_MODE (TREE_TYPE (pval)), + arg->value, arg->unsignedp); + +#ifdef ACCUMULATE_OUTGOING_ARGS + if (arg->pass_on_stack) + stack_arg_under_construction--; +#endif + } + + /* Don't allow anything left on stack from computation + of argument to alloca. */ + if (may_be_alloca) + do_pending_stack_adjust (); + + if (arg->value == arg->stack) + { + /* If the value is already in the stack slot, we are done moving + data. */ + if (current_function_check_memory_usage && GET_CODE (arg->stack) == MEM) + { + emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3, + XEXP (arg->stack, 0), ptr_mode, + ARGS_SIZE_RTX (arg->size), + TYPE_MODE (sizetype), + GEN_INT (MEMORY_USE_RW), + TYPE_MODE (integer_type_node)); + } + } + else if (arg->mode != BLKmode) + { + register int size; + + /* Argument is a scalar, not entirely passed in registers. + (If part is passed in registers, arg->partial says how much + and emit_push_insn will take care of putting it there.) + + Push it, and if its size is less than the + amount of space allocated to it, + also bump stack pointer by the additional space. + Note that in C the default argument promotions + will prevent such mismatches. */ + + size = GET_MODE_SIZE (arg->mode); + /* Compute how much space the push instruction will push. + On many machines, pushing a byte will advance the stack + pointer by a halfword. */ +#ifdef PUSH_ROUNDING + size = PUSH_ROUNDING (size); +#endif + used = size; + + /* Compute how much space the argument should get: + round up to a multiple of the alignment for arguments. */ + if (none != FUNCTION_ARG_PADDING (arg->mode, TREE_TYPE (pval))) + used = (((size + PARM_BOUNDARY / BITS_PER_UNIT - 1) + / (PARM_BOUNDARY / BITS_PER_UNIT)) + * (PARM_BOUNDARY / BITS_PER_UNIT)); + + /* This isn't already where we want it on the stack, so put it there. + This can either be done with push or copy insns. */ + emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX, 0, + partial, reg, used - size, argblock, + ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space); + } + else + { + /* BLKmode, at least partly to be pushed. */ + + register int excess; + rtx size_rtx; + + /* Pushing a nonscalar. + If part is passed in registers, PARTIAL says how much + and emit_push_insn will take care of putting it there. */ + + /* Round its size up to a multiple + of the allocation unit for arguments. */ + + if (arg->size.var != 0) + { + excess = 0; + size_rtx = ARGS_SIZE_RTX (arg->size); + } + else + { + /* PUSH_ROUNDING has no effect on us, because + emit_push_insn for BLKmode is careful to avoid it. */ + excess = (arg->size.constant - int_size_in_bytes (TREE_TYPE (pval)) + + partial * UNITS_PER_WORD); + size_rtx = expr_size (pval); + } + + emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx, + TYPE_ALIGN (TREE_TYPE (pval)) / BITS_PER_UNIT, partial, + reg, excess, argblock, ARGS_SIZE_RTX (arg->offset), + reg_parm_stack_space); + } + + + /* Unless this is a partially-in-register argument, the argument is now + in the stack. + + ??? Note that this can change arg->value from arg->stack to + arg->stack_slot and it matters when they are not the same. + It isn't totally clear that this is correct in all cases. */ + if (partial == 0) + arg->value = arg->stack_slot; + + /* Once we have pushed something, pops can't safely + be deferred during the rest of the arguments. */ + NO_DEFER_POP; + + /* ANSI doesn't require a sequence point here, + but PCC has one, so this will avoid some problems. */ + emit_queue (); + + /* Free any temporary slots made in processing this argument. Show + that we might have taken the address of something and pushed that + as an operand. */ + preserve_temp_slots (NULL_RTX); + free_temp_slots (); + pop_temp_slots (); +} diff --git a/gcc_arm/cccp.1 b/gcc_arm/cccp.1 new file mode 100755 index 0000000..84eb19e --- /dev/null +++ b/gcc_arm/cccp.1 @@ -0,0 +1,674 @@ +.\" Copyright (c) 1991, 1992, 1993 Free Software Foundation \-*-Text-*- +.\" See section COPYING for conditions for redistribution +.TH cpp 1 "30apr1993" "GNU Tools" "GNU Tools" +.SH NAME +cccp, cpp \- The GNU C-Compatible Compiler Preprocessor. +.SH SYNOPSIS +.hy 0 +.na +.TP +.B cccp +.RB "[\|" \-$ "\|]" +.RB "[\|" \-A \c +.I predicate\c +.RB [ (\c +.I value\c +.BR ) ]\|] +.RB "[\|" \-C "\|]" +.RB "[\|" \-D \c +.I name\c +.RB [ =\c +.I definition\c +\&]\|] +.RB "[\|" \-dD "\|]" +.RB "[\|" \-dM "\|]" +.RB "[\|" "\-I\ "\c +.I directory\c +\&\|] +.RB "[\|" \-H "\|]" +.RB "[\|" \-I\- "\|]" +.RB "[\|" "\-imacros\ "\c +.I file\c +\&\|] +.RB "[\|" "\-include\ "\c +.I file\c +\&\|] +.RB "[\|" "\-idirafter\ "\c +.I dir\c +\&\|] +.RB "[\|" "\-iprefix\ "\c +.I prefix\c +\&\|] +.RB "[\|" "\-iwithprefix\ "\c +.I dir\c +\&\|] +.RB "[\|" \-lang\-c "\|]" +.RB "[\|" \-lang\-c++ "\|]" +.RB "[\|" \-lang\-objc "\|]" +.RB "[\|" \-lang\-objc++ "\|]" +.RB "[\|" \-lint "\|]" +.RB "[\|" \-M\ [ \-MG "\|]]" +.RB "[\|" \-MM\ [ \-MG "\|]]" +.RB "[\|" \-MD\ \c +.I file\ \c +\&\|] +.RB "[\|" \-MMD\ \c +.I file\ \c +\&\|] +.RB "[\|" \-nostdinc "\|]" +.RB "[\|" \-nostdinc++ "\|]" +.RB "[\|" \-P "\|]" +.RB "[\|" \-pedantic "\|]" +.RB "[\|" \-pedantic\-errors "\|]" +.RB "[\|" \-traditional "\|]" +.RB "[\|" \-trigraphs "\|]" +.RB "[\|" \-U \c +.I name\c +\&\|] +.RB "[\|" \-undef "\|]" +.RB "[\|" \-Wtrigraphs "\|]" +.RB "[\|" \-Wcomment "\|]" +.RB "[\|" \-Wall "\|]" +.RB "[\|" \-Wtraditional "\|]" +.br +.RB "[\|" \c +.I infile\c +.RB | \- "\|]" +.RB "[\|" \c +.I outfile\c +.RB | \- "\|]" +.ad b +.hy 1 +.SH DESCRIPTION +The C preprocessor is a \c +.I macro processor\c +\& that is used automatically by +the C compiler to transform your program before actual compilation. It is +called a macro processor because it allows you to define \c +.I macros\c +\&, +which are brief abbreviations for longer constructs. + +The C preprocessor provides four separate facilities that you can use as +you see fit: +.TP +\(bu +Inclusion of header files. These are files of declarations that can be +substituted into your program. +.TP +\(bu +Macro expansion. You can define \c +.I macros\c +\&, which are abbreviations +for arbitrary fragments of C code, and then the C preprocessor will +replace the macros with their definitions throughout the program. +.TP +\(bu +Conditional compilation. Using special preprocessing directives, you +can include or exclude parts of the program according to various +conditions. +.TP +\(bu +Line control. If you use a program to combine or rearrange source files into +an intermediate file which is then compiled, you can use line control +to inform the compiler of where each source line originally came from. +.PP +C preprocessors vary in some details. For a full explanation of the +GNU C preprocessor, see the +.B info +file `\|\c +.B cpp.info\c +\&\|', or the manual +.I The C Preprocessor\c +\&. Both of these are built from the same documentation source file, `\|\c +.B cpp.texinfo\c +\&\|'. The GNU C +preprocessor provides a superset of the features of ANSI Standard C. + +ANSI Standard C requires the rejection of many harmless constructs commonly +used by today's C programs. Such incompatibility would be inconvenient for +users, so the GNU C preprocessor is configured to accept these constructs +by default. Strictly speaking, to get ANSI Standard C, you must use the +options `\|\c +.B \-trigraphs\c +\&\|', `\|\c +.B \-undef\c +\&\|' and `\|\c +.B \-pedantic\c +\&\|', but in +practice the consequences of having strict ANSI Standard C make it +undesirable to do this. + +Most often when you use the C preprocessor you will not have to invoke it +explicitly: the C compiler will do so automatically. However, the +preprocessor is sometimes useful individually. + +When you call the preprocessor individually, either name +(\c +.B cpp\c +\& or \c +.B cccp\c +\&) will do\(em\&they are completely synonymous. + +The C preprocessor expects two file names as arguments, \c +.I infile\c +\& and +\c +.I outfile\c +\&. The preprocessor reads \c +.I infile\c +\& together with any other +files it specifies with `\|\c +.B #include\c +\&\|'. All the output generated by the +combined input files is written in \c +.I outfile\c +\&. + +Either \c +.I infile\c +\& or \c +.I outfile\c +\& may be `\|\c +.B \-\c +\&\|', which as \c +.I infile\c +\& +means to read from standard input and as \c +.I outfile\c +\& means to write to +standard output. Also, if \c +.I outfile\c +\& or both file names are omitted, +the standard output and standard input are used for the omitted file names. +.SH OPTIONS +Here is a table of command options accepted by the C preprocessor. +These options can also be given when compiling a C program; they are +passed along automatically to the preprocessor when it is invoked by +the compiler. +.TP +.B \-P +Inhibit generation of `\|\c +.B #\c +\&\|'-lines with line-number information in +the output from the preprocessor. This might be +useful when running the preprocessor on something that is not C code +and will be sent to a program which might be confused by the +`\|\c +.B #\c +\&\|'-lines. +.TP +.B \-C +Do not discard comments: pass them through to the output file. +Comments appearing in arguments of a macro call will be copied to the +output before the expansion of the macro call. +.TP +.B \-traditional +Try to imitate the behavior of old-fashioned C, as opposed to ANSI C. +.TP +.B \-trigraphs +Process ANSI standard trigraph sequences. These are three-character +sequences, all starting with `\|\c +.B ??\c +\&\|', that are defined by ANSI C to +stand for single characters. For example, `\|\c +.B ??/\c +\&\|' stands for +`\|\c +.BR "\e" "\|'," +so `\|\c +.B '??/n'\c +\&\|' is a character constant for a newline. +Strictly speaking, the GNU C preprocessor does not support all +programs in ANSI Standard C unless `\|\c +.B \-trigraphs\c +\&\|' is used, but if +you ever notice the difference it will be with relief. + +You don't want to know any more about trigraphs. +.TP +.B \-pedantic +Issue warnings required by the ANSI C standard in certain cases such +as when text other than a comment follows `\|\c +.B #else\c +\&\|' or `\|\c +.B #endif\c +\&\|'. +.TP +.B \-pedantic\-errors +Like `\|\c +.B \-pedantic\c +\&\|', except that errors are produced rather than +warnings. +.TP +.B \-Wtrigraphs +Warn if any trigraphs are encountered (assuming they are enabled). +.TP +.B \-Wcomment +.TP +.B \-Wcomments +Warn whenever a comment-start sequence `\|\c +.B /*\c +\&\|' appears in a comment. +(Both forms have the same effect). +.TP +.B \-Wall +Requests both `\|\c +.B \-Wtrigraphs\c +\&\|' and `\|\c +.B \-Wcomment\c +\&\|' (but not +`\|\c +.B \-Wtraditional\c +\&\|'). +.TP +.B \-Wtraditional +Warn about certain constructs that behave differently in traditional and +ANSI C. +.TP +.BI "\-I " directory\c +\& +Add the directory \c +.I directory\c +\& to the end of the list of +directories to be searched for header files. +This can be used to override a system header file, substituting your +own version, since these directories are searched before the system +header file directories. If you use more than one `\|\c +.B \-I\c +\&\|' option, +the directories are scanned in left-to-right order; the standard +system directories come after. +.TP +.B \-I\- +Any directories specified with `\|\c +.B \-I\c +\&\|' options before the `\|\c +.B \-I\-\c +\&\|' +option are searched only for the case of `\|\c +.B #include "\c +.I file\c +\&"\c +\&\|'; +they are not searched for `\|\c +.B #include <\c +.I file\c +\&>\c +\&\|'. + +If additional directories are specified with `\|\c +.B \-I\c +\&\|' options after +the `\|\c +.B \-I\-\c +\&\|', these directories are searched for all `\|\c +.B #include\c +\&\|' +directives. + +In addition, the `\|\c +.B \-I\-\c +\&\|' option inhibits the use of the current +directory as the first search directory for `\|\c +.B #include "\c +.I file\c +\&"\c +\&\|'. +Therefore, the current directory is searched only if it is requested +explicitly with `\|\c +.B \-I.\c +\&\|'. Specifying both `\|\c +.B \-I\-\c +\&\|' and `\|\c +.B \-I.\c +\&\|' +allows you to control precisely which directories are searched before +the current one and which are searched after. +.TP +.B \-nostdinc +Do not search the standard system directories for header files. +Only the directories you have specified with `\|\c +.B \-I\c +\&\|' options +(and the current directory, if appropriate) are searched. +.TP +.B \-nostdinc++ +Do not search for header files in the C++ specific standard +directories, but do still search the other standard directories. +(This option is used when building libg++.) +.TP +.BI "\-D " "name"\c +\& +Predefine \c +.I name\c +\& as a macro, with definition `\|\c +.B 1\c +\&\|'. +.TP +.BI "\-D " "name" = definition +\& +Predefine \c +.I name\c +\& as a macro, with definition \c +.I definition\c +\&. +There are no restrictions on the contents of \c +.I definition\c +\&, but if +you are invoking the preprocessor from a shell or shell-like program +you may need to use the shell's quoting syntax to protect characters +such as spaces that have a meaning in the shell syntax. If you use more than +one `\|\c +.B \-D\c +\&\|' for the same +.I name\c +\&, the rightmost definition takes effect. +.TP +.BI "\-U " "name"\c +\& +Do not predefine \c +.I name\c +\&. If both `\|\c +.B \-U\c +\&\|' and `\|\c +.B \-D\c +\&\|' are +specified for one name, the `\|\c +.B \-U\c +\&\|' beats the `\|\c +.B \-D\c +\&\|' and the name +is not predefined. +.TP +.B \-undef +Do not predefine any nonstandard macros. +.TP +.BI "\-A " "name(" value ) +Assert (in the same way as the \c +.B #assert\c +\& directive) +the predicate \c +.I name\c +\& with tokenlist \c +.I value\c +\&. Remember to escape or quote the parentheses on +shell command lines. + +You can use `\|\c +.B \-A-\c +\&\|' to disable all predefined assertions; it also +undefines all predefined macros. +.TP +.B \-dM +Instead of outputting the result of preprocessing, output a list of +`\|\c +.B #define\c +\&\|' directives for all the macros defined during the +execution of the preprocessor, including predefined macros. This gives +you a way of finding out what is predefined in your version of the +preprocessor; assuming you have no file `\|\c +.B foo.h\c +\&\|', the command +.sp +.br +touch\ foo.h;\ cpp\ \-dM\ foo.h +.br +.sp +will show the values of any predefined macros. +.TP +.B \-dD +Like `\|\c +.B \-dM\c +\&\|' except in two respects: it does \c +.I not\c +\& include the +predefined macros, and it outputs \c +.I both\c +\& the `\|\c +.B #define\c +\&\|' +directives and the result of preprocessing. Both kinds of output go to +the standard output file. +.PP +.TP +.BR \-M\ [ \-MG ] +Instead of outputting the result of preprocessing, output a rule +suitable for \c +.B make\c +\& describing the dependencies of the main +source file. The preprocessor outputs one \c +.B make\c +\& rule containing +the object file name for that source file, a colon, and the names of +all the included files. If there are many included files then the +rule is split into several lines using `\|\c +.B \\\\\c +\&\|'-newline. + +`\|\c +.B \-MG\c +\&\|' says to treat missing header files as generated files and assume \c +they live in the same directory as the source file. It must be specified \c +in addition to `\|\c +.B \-M\c +\&\|'. + +This feature is used in automatic updating of makefiles. +.TP +.BR \-MM\ [ \-MG ] +Like `\|\c +.B \-M\c +\&\|' but mention only the files included with `\|\c +.B #include +"\c +.I file\c +\&"\c +\&\|'. System header files included with `\|\c +.B #include +<\c +.I file\c +\&>\c +\&\|' are omitted. +.TP +.BI \-MD\ file +Like `\|\c +.B \-M\c +\&\|' but the dependency information is written to `\|\c +.I file\c +\&\|'. This is in addition to compiling the file as +specified\(em\&`\|\c +.B \-MD\c +\&\|' does not inhibit ordinary compilation the way +`\|\c +.B \-M\c +\&\|' does. + +When invoking gcc, do not specify the `\|\c +.I file\c +\&\|' argument. Gcc will create file names made by replacing `\|\c +.B .c\c +\&\|' with `\|\c +.B .d\c +\&\|' at the end of the input file names. + +In Mach, you can use the utility \c +.B md\c +\& to merge multiple files +into a single dependency file suitable for using with the `\|\c +.B make\c +\&\|' +command. +.TP +.BI \-MMD\ file +Like `\|\c +.B \-MD\c +\&\|' except mention only user header files, not system +header files. +.TP +.B \-H +Print the name of each header file used, in addition to other normal +activities. +.TP +.BI "\-imacros " "file"\c +\& +Process \c +.I file\c +\& as input, discarding the resulting output, before +processing the regular input file. Because the output generated from +\c +.I file\c +\& is discarded, the only effect of `\|\c +.B \-imacros \c +.I file\c +\&\c +\&\|' is to +make the macros defined in \c +.I file\c +\& available for use in the main +input. The preprocessor evaluates any `\|\c +.B \-D\c +\&\|' and `\|\c +.B \-U\c +\&\|' options +on the command line before processing `\|\c +.B \-imacros \c +.I file\c +\&\|' \c +\&. +.TP +.BI "\-include " "file" +Process +.I file +as input, and include all the resulting output, +before processing the regular input file. +.TP +.BI "-idirafter " "dir"\c +\& +Add the directory \c +.I dir\c +\& to the second include path. The directories +on the second include path are searched when a header file is not found +in any of the directories in the main include path (the one that +`\|\c +.B \-I\c +\&\|' adds to). +.TP +.BI "-iprefix " "prefix"\c +\& +Specify \c +.I prefix\c +\& as the prefix for subsequent `\|\c +.B \-iwithprefix\c +\&\|' +options. +.TP +.BI "-iwithprefix " "dir"\c +\& +Add a directory to the second include path. The directory's name is +made by concatenating \c +.I prefix\c +\& and \c +.I dir\c +\&, where \c +.I prefix\c +\& +was specified previously with `\|\c +.B \-iprefix\c +\&\|'. +.TP +.B \-lang-c +.TP +.B \-lang-c++ +.TP +.B \-lang-objc +.TP +.B \-lang-objc++ +Specify the source language. `\|\c +.B \-lang-c++\c +\&\|' makes the preprocessor +handle C++ comment syntax, and includes extra default include +directories for C++, and `\|\c +.B \-lang-objc\c +\&\|' enables the Objective C +`\|\c +.B #import\c +\&\|' directive. `\|\c +.B \-lang-c\c +\&\|' explicitly turns off both of +these extensions, and `\|\c +.B \-lang-objc++\c +\&\|' enables both. + +These options are generated by the compiler driver \c +.B gcc\c +\&, but not +passed from the `\|\c +.B gcc\c +\&\|' command line. +.TP +.B \-lint +Look for commands to the program checker \c +.B lint\c +\& embedded in +comments, and emit them preceded by `\|\c +.B #pragma lint\c +\&\|'. For example, +the comment `\|\c +.B /* NOTREACHED */\c +\&\|' becomes `\|\c +.B #pragma lint +NOTREACHED\c +\&\|'. + +This option is available only when you call \c +.B cpp\c +\& directly; +\c +.B gcc\c +\& will not pass it from its command line. +.TP +.B \-$ +Forbid the use of `\|\c +.B $\c +\&\|' in identifiers. This was formerly required for strict conformance +to the C Standard before the standard was corrected. \c + +This option is available only when you call \c +.B cpp\c +\& directly; +.B gcc\c +\& will not pass it from its command line. +.SH "SEE ALSO" +.RB "`\|" Cpp "\|'" +entry in +.B info\c +\&; +.I The C Preprocessor\c +, Richard M. Stallman. +.br +.BR gcc "(" 1 ");" +.RB "`\|" Gcc "\|'" +entry in +.B info\c +\&; +.I +Using and Porting GNU CC (for version 2.0)\c +, Richard M. Stallman. +.SH COPYING +Copyright (c) 1991, 1992, 1993 Free Software Foundation, Inc. +.PP +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. +.PP +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. +.PP +Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions, except that this permission notice may be included in +translations approved by the Free Software Foundation instead of in +the original English. diff --git a/gcc_arm/cccp.c b/gcc_arm/cccp.c new file mode 100755 index 0000000..76ae613 --- /dev/null +++ b/gcc_arm/cccp.c @@ -0,0 +1,11450 @@ +/* C Compatible Compiler Preprocessor (CCCP) + Copyright (C) 1986, 87, 89, 92-98, 1999 Free Software Foundation, Inc. + Written by Paul Rubin, June 1986 + Adapted to ANSI C, Richard Stallman, Jan 1987 + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" + +#define PRINTF_PROTO(ARGS, m, n) PVPROTO (ARGS) ATTRIBUTE_PRINTF(m, n) + +#define PRINTF_PROTO_1(ARGS) PRINTF_PROTO(ARGS, 1, 2) +#define PRINTF_PROTO_2(ARGS) PRINTF_PROTO(ARGS, 2, 3) +#define PRINTF_PROTO_3(ARGS) PRINTF_PROTO(ARGS, 3, 4) +#define PRINTF_PROTO_4(ARGS) PRINTF_PROTO(ARGS, 4, 5) + +#include "system.h" +#include + +#ifdef HAVE_SYS_RESOURCE_H +# include +#endif + +typedef unsigned char U_CHAR; + +#include "pcp.h" +#include "prefix.h" + +#ifdef MULTIBYTE_CHARS +#include "mbchar.h" +#include +#endif /* MULTIBYTE_CHARS */ + +#ifndef GET_ENV_PATH_LIST +#define GET_ENV_PATH_LIST(VAR,NAME) do { (VAR) = getenv (NAME); } while (0) +#endif + +#ifndef STANDARD_INCLUDE_DIR +# define STANDARD_INCLUDE_DIR "/usr/include" +#endif + +/* By default, colon separates directories in a path. */ +#ifndef PATH_SEPARATOR +# define PATH_SEPARATOR ':' +#endif + +/* By default, the suffix for object files is ".o". */ +#ifdef OBJECT_SUFFIX +# define HAVE_OBJECT_SUFFIX +#else +# define OBJECT_SUFFIX ".o" +#endif + +/* VMS-specific definitions */ +#ifdef VMS +#include +#include +#include +#define open(fname,mode,prot) VMS_open (fname,mode,prot) +#define fopen(fname,mode) VMS_fopen (fname,mode) +#define freopen(fname,mode,ofile) VMS_freopen (fname,mode,ofile) +#define fstat(fd,stbuf) VMS_fstat (fd,stbuf) +static int VMS_fstat (), VMS_stat (); +static int VMS_open (); +static FILE *VMS_fopen (); +static FILE *VMS_freopen (); +static int hack_vms_include_specification (); +#define INO_T_EQ(a, b) (!bcmp((char *) &(a), (char *) &(b), sizeof (a))) +#define INO_T_HASH(a) 0 +#define INCLUDE_LEN_FUDGE 12 /* leave room for VMS syntax conversion */ +#endif /* VMS */ + +/* Windows does not natively support inodes, and neither does MSDOS. */ +#if (defined (_WIN32) && ! defined (__CYGWIN__)) || defined (__MSDOS__) +#define INO_T_EQ(a, b) 0 +#endif + +/* Find the largest host integer type and set its size and type. + Watch out: on some crazy hosts `long' is shorter than `int'. */ + +#ifndef HOST_WIDE_INT +# if HAVE_INTTYPES_H +# include +# define HOST_WIDE_INT intmax_t +# else +# if (HOST_BITS_PER_LONG <= HOST_BITS_PER_INT && HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_INT) +# define HOST_WIDE_INT int +# else +# if (HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_LONG || ! (defined LONG_LONG_MAX || defined LLONG_MAX)) +# define HOST_WIDE_INT long +# else +# define HOST_WIDE_INT long long +# endif +# endif +# endif +#endif + +#ifndef INO_T_EQ +#define INO_T_EQ(a, b) ((a) == (b)) +#endif + +#ifndef INO_T_HASH +#define INO_T_HASH(a) (a) +#endif + +#ifndef INCLUDE_LEN_FUDGE +#define INCLUDE_LEN_FUDGE 0 +#endif + +/* External declarations. */ + +extern char *version_string; +HOST_WIDE_INT parse_escape PROTO((char **, HOST_WIDE_INT)); +HOST_WIDE_INT parse_c_expression PROTO((char *, int)); + +/* Name under which this program was invoked. */ + +static char *progname = "cpp"; /* CYGNUS LOCAL: initialisation added nickc */ + +/* Nonzero means use extra default include directories for C++. */ + +static int cplusplus; + +/* Nonzero means handle cplusplus style comments */ + +static int cplusplus_comments; + +/* Nonzero means handle #import, for objective C. */ + +static int objc; + +/* Nonzero means this is an assembly file, and allow + unknown directives, which could be comments. */ + +static int lang_asm; + +/* CYGNUS LOCAL chill */ +/* Nonzero means handle CHILL comment syntax + and output CHILL string delimeter for __DATE___ etc. */ + +static int chill; +/* END CYGNUS LOCAL chill */ + +/* Current maximum length of directory names in the search path + for include files. (Altered as we get more of them.) */ + +static int max_include_len; + +/* Nonzero means turn NOTREACHED into #pragma NOTREACHED etc */ + +static int for_lint = 0; + +/* Nonzero means copy comments into the output file. */ + +static int put_out_comments = 0; + +/* Nonzero means don't process the ANSI trigraph sequences. */ + +static int no_trigraphs = 0; + +/* Nonzero means print the names of included files rather than + the preprocessed output. 1 means just the #include "...", + 2 means #include <...> as well. */ + +static int print_deps = 0; + +/* Nonzero if missing .h files in -M output are assumed to be generated + files and not errors. */ + +static int print_deps_missing_files = 0; + +/* Nonzero means print names of header files (-H). */ + +static int print_include_names = 0; + +/* Nonzero means don't output line number information. */ + +static int no_line_directives; + +/* Nonzero means output the text in failing conditionals, + inside #failed ... #endfailed. */ + +static int output_conditionals; + +/* dump_only means inhibit output of the preprocessed text + and instead output the definitions of all user-defined + macros in a form suitable for use as input to cccp. + dump_names means pass #define and the macro name through to output. + dump_definitions means pass the whole definition (plus #define) through +*/ + +static enum {dump_none, dump_only, dump_names, dump_definitions} + dump_macros = dump_none; + +/* Nonzero means pass all #define and #undef directives which we actually + process through to the output stream. This feature is used primarily + to allow cc1 to record the #defines and #undefs for the sake of + debuggers which understand about preprocessor macros, but it may + also be useful with -E to figure out how symbols are defined, and + where they are defined. */ +static int debug_output = 0; + +/* Nonzero means pass #include lines through to the output, + even if they are ifdefed out. */ +static int dump_includes; + +/* Nonzero indicates special processing used by the pcp program. The + special effects of this mode are: + + Inhibit all macro expansion, except those inside #if directives. + + Process #define directives normally, and output their contents + to the output file. + + Output preconditions to pcp_outfile indicating all the relevant + preconditions for use of this file in a later cpp run. +*/ +static FILE *pcp_outfile; + +/* Nonzero means we are inside an IF during a -pcp run. In this mode + macro expansion is done, and preconditions are output for all macro + uses requiring them. */ +static int pcp_inside_if; + +/* Nonzero means never to include precompiled files. + This is 1 since there's no way now to make precompiled files, + so it's not worth testing for them. */ +static int no_precomp = 1; + +/* Nonzero means give all the error messages the ANSI standard requires. */ + +int pedantic; + +/* Nonzero means try to make failure to fit ANSI C an error. */ + +static int pedantic_errors; + +/* Nonzero means don't print warning messages. -w. */ + +static int inhibit_warnings = 0; + +/* Nonzero means warn if slash-star appears in a slash-star comment, + or if newline-backslash appears in a slash-slash comment. */ + +static int warn_comments; + +/* Nonzero means warn if a macro argument is (or would be) + stringified with -traditional. */ + +static int warn_stringify; + +/* Nonzero means warn if there are any trigraphs. */ + +static int warn_trigraphs; + +/* Nonzero means warn if undefined identifiers are evaluated in an #if. */ + +static int warn_undef; + +/* Nonzero means warn if #import is used. */ + +static int warn_import = 1; + +/* Nonzero means turn warnings into errors. */ + +static int warnings_are_errors; + +/* Nonzero means try to imitate old fashioned non-ANSI preprocessor. */ + +int traditional; + +/* Nonzero for the 1989 C Standard, including corrigenda and amendments. */ + +int c89; + +/* Nonzero for the 199x C Standard. */ + +int c9x; + +/* Nonzero causes output not to be done, + but directives such as #define that have side effects + are still obeyed. */ + +static int no_output; + +/* Nonzero means we should look for header.gcc files that remap file names. */ +static int remap; + +/* Nonzero means this file was included with a -imacros or -include + command line and should not be recorded as an include file. */ + +static int no_record_file; + +/* Nonzero means that we have finished processing the command line options. + This flag is used to decide whether or not to issue certain errors + and/or warnings. */ + +static int done_initializing = 0; + +/* Line where a newline was first seen in a string constant. */ + +static int multiline_string_line = 0; + +/* I/O buffer structure. + The `fname' field is nonzero for source files and #include files + and for the dummy text used for -D and -U. + It is zero for rescanning results of macro expansion + and for expanding macro arguments. */ +#define INPUT_STACK_MAX 400 +static struct file_buf { + char *fname; + /* Filename specified with #line directive. */ + char *nominal_fname; + /* The length of nominal_fname, which may contain embedded NULs. */ + size_t nominal_fname_len; + /* Include file description. */ + struct include_file *inc; + /* Record where in the search path this file was found. + For #include_next. */ + struct file_name_list *dir; + int lineno; + int length; + U_CHAR *buf; + U_CHAR *bufp; + /* Macro that this level is the expansion of. + Included so that we can reenable the macro + at the end of this level. */ + struct hashnode *macro; + /* Value of if_stack at start of this file. + Used to prohibit unmatched #endif (etc) in an include file. */ + struct if_stack *if_stack; + /* Object to be freed at end of input at this level. */ + U_CHAR *free_ptr; + /* True if this is a system header file; see is_system_include. */ + char system_header_p; +} instack[INPUT_STACK_MAX]; + +static int last_error_tick; /* Incremented each time we print it. */ +static int input_file_stack_tick; /* Incremented when the status changes. */ + +/* Current nesting level of input sources. + `instack[indepth]' is the level currently being read. */ +static int indepth = -1; +#define CHECK_DEPTH(code) \ + if (indepth >= (INPUT_STACK_MAX - 1)) \ + { \ + error_with_line (line_for_error (instack[indepth].lineno), \ + "macro or `#include' recursion too deep"); \ + code; \ + } + +/* Current depth in #include directives that use <...>. */ +static int system_include_depth = 0; + +typedef struct file_buf FILE_BUF; + +/* The output buffer. Its LENGTH field is the amount of room allocated + for the buffer, not the number of chars actually present. To get + that, subtract outbuf.buf from outbuf.bufp. */ + +#define OUTBUF_SIZE 10 /* initial size of output buffer */ +static FILE_BUF outbuf; + +/* Grow output buffer OBUF points at + so it can hold at least NEEDED more chars. */ + +#define check_expand(OBUF, NEEDED) \ + (((OBUF)->length - ((OBUF)->bufp - (OBUF)->buf) <= (NEEDED)) \ + ? grow_outbuf ((OBUF), (NEEDED)) : 0) + +struct file_name_list + { + struct file_name_list *next; + /* If the following is 1, it is a C-language system include + directory. */ + int c_system_include_path; + /* Mapping of file names for this directory. */ + struct file_name_map *name_map; + /* Non-zero if name_map is valid. */ + int got_name_map; + /* The include directory status. */ + struct stat st; + /* The include prefix: "" denotes the working directory, + otherwise fname must end in '/'. + The actual size is dynamically allocated. */ + char fname[1]; + }; + +/* #include "file" looks in source file dir, then stack. */ +/* #include just looks in the stack. */ +/* -I directories are added to the end, then the defaults are added. */ +/* The */ +static struct default_include { + char *fname; /* The name of the directory. */ + char *component; /* The component containing the directory */ + int cplusplus; /* Only look here if we're compiling C++. */ + int cxx_aware; /* Includes in this directory don't need to + be wrapped in extern "C" when compiling + C++. */ +} include_defaults_array[] +#ifdef INCLUDE_DEFAULTS + = INCLUDE_DEFAULTS; +#else + = { + /* Pick up GNU C++ specific include files. */ + { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1 }, +#ifdef CROSS_COMPILE + /* This is the dir for fixincludes. Put it just before + the files that we fix. */ + { GCC_INCLUDE_DIR, "GCC", 0, 0 }, + /* For cross-compilation, this dir name is generated + automatically in Makefile.in. */ + { CROSS_INCLUDE_DIR, "GCC", 0, 0 }, +#ifdef TOOL_INCLUDE_DIR + /* This is another place that the target system's headers might be. */ + { TOOL_INCLUDE_DIR, "BINUTILS", 0, 0 }, +#endif +#else /* not CROSS_COMPILE */ +#ifdef LOCAL_INCLUDE_DIR + /* This should be /usr/local/include and should come before + the fixincludes-fixed header files. */ + { LOCAL_INCLUDE_DIR, 0, 0, 1 }, +#endif +#ifdef TOOL_INCLUDE_DIR + /* This is here ahead of GCC_INCLUDE_DIR because assert.h goes here. + Likewise, behind LOCAL_INCLUDE_DIR, where glibc puts its assert.h. */ + { TOOL_INCLUDE_DIR, "BINUTILS", 0, 0 }, +#endif + /* This is the dir for fixincludes. Put it just before + the files that we fix. */ + { GCC_INCLUDE_DIR, "GCC", 0, 0 }, + /* Some systems have an extra dir of include files. */ +#ifdef SYSTEM_INCLUDE_DIR + { SYSTEM_INCLUDE_DIR, 0, 0, 0 }, +#endif +#ifndef STANDARD_INCLUDE_COMPONENT +#define STANDARD_INCLUDE_COMPONENT 0 +#endif + { STANDARD_INCLUDE_DIR, STANDARD_INCLUDE_COMPONENT, 0, 0 }, +#endif /* not CROSS_COMPILE */ + { 0, 0, 0, 0 } + }; +#endif /* no INCLUDE_DEFAULTS */ + +/* The code looks at the defaults through this pointer, rather than through + the constant structure above. This pointer gets changed if an environment + variable specifies other defaults. */ +static struct default_include *include_defaults = include_defaults_array; + +static struct file_name_list *include = 0; /* First dir to search */ + /* First dir to search for */ +/* This is the first element to use for #include <...>. + If it is 0, use the entire chain for such includes. */ +static struct file_name_list *first_bracket_include = 0; +/* This is the first element in the chain that corresponds to + a directory of system header files. */ +static struct file_name_list *first_system_include = 0; +static struct file_name_list *last_include = 0; /* Last in chain */ + +/* Chain of include directories to put at the end of the other chain. */ +static struct file_name_list *after_include = 0; +static struct file_name_list *last_after_include = 0; /* Last in chain */ + +/* Chain to put at the start of the system include files. */ +static struct file_name_list *before_system = 0; +static struct file_name_list *last_before_system = 0; /* Last in chain */ + +/* Directory prefix that should replace `/usr' in the standard + include file directories. */ +static char *include_prefix; + +/* Maintain and search list of included files. */ + +struct include_file { + struct include_file *next; /* for include_hashtab */ + struct include_file *next_ino; /* for include_ino_hashtab */ + char *fname; + /* If the following is the empty string, it means #pragma once + was seen in this include file, or #import was applied to the file. + Otherwise, if it is nonzero, it is a macro name. + Don't include the file again if that macro is defined. */ + U_CHAR *control_macro; + /* Nonzero if the dependency on this include file has been output. */ + int deps_output; + struct stat st; +}; + +/* Hash tables of files already included with #include or #import. + include_hashtab is by full name; include_ino_hashtab is by inode number. */ + +#define INCLUDE_HASHSIZE 61 +static struct include_file *include_hashtab[INCLUDE_HASHSIZE]; +static struct include_file *include_ino_hashtab[INCLUDE_HASHSIZE]; + +/* Global list of strings read in from precompiled files. This list + is kept in the order the strings are read in, with new strings being + added at the end through stringlist_tailp. We use this list to output + the strings at the end of the run. +*/ +static STRINGDEF *stringlist; +static STRINGDEF **stringlist_tailp = &stringlist; + + +/* Structure returned by create_definition */ +typedef struct macrodef MACRODEF; +struct macrodef +{ + struct definition *defn; + U_CHAR *symnam; + int symlen; +}; + +enum sharp_token_type { + NO_SHARP_TOKEN = 0, /* token not present */ + + SHARP_TOKEN = '#', /* token spelled with # only */ + WHITE_SHARP_TOKEN, /* token spelled with # and white space */ + + PERCENT_COLON_TOKEN = '%', /* token spelled with %: only */ + WHITE_PERCENT_COLON_TOKEN /* token spelled with %: and white space */ +}; + +/* Structure allocated for every #define. For a simple replacement + such as + #define foo bar , + nargs = -1, the `pattern' list is null, and the expansion is just + the replacement text. Nargs = 0 means a functionlike macro with no args, + e.g., + #define getchar() getc (stdin) . + When there are args, the expansion is the replacement text with the + args squashed out, and the reflist is a list describing how to + build the output from the input: e.g., "3 chars, then the 1st arg, + then 9 chars, then the 3rd arg, then 0 chars, then the 2nd arg". + The chars here come from the expansion. Whatever is left of the + expansion after the last arg-occurrence is copied after that arg. + Note that the reflist can be arbitrarily long--- + its length depends on the number of times the arguments appear in + the replacement text, not how many args there are. Example: + #define f(x) x+x+x+x+x+x+x would have replacement text "++++++" and + pattern list + { (0, 1), (1, 1), (1, 1), ..., (1, 1), NULL } + where (x, y) means (nchars, argno). */ + +typedef struct definition DEFINITION; +struct definition { + int nargs; + int length; /* length of expansion string */ + int predefined; /* True if the macro was builtin or */ + /* came from the command line */ + U_CHAR *expansion; + int line; /* Line number of definition */ + char *file; /* File of definition */ + size_t file_len; /* Length of file (which can contain NULs) */ + char rest_args; /* Nonzero if last arg. absorbs the rest */ + struct reflist { + struct reflist *next; + + enum sharp_token_type stringify; /* set if a # operator before arg */ + enum sharp_token_type raw_before; /* set if a ## operator before arg */ + enum sharp_token_type raw_after; /* set if a ## operator after arg */ + + char rest_args; /* Nonzero if this arg. absorbs the rest */ + int nchars; /* Number of literal chars to copy before + this arg occurrence. */ + int argno; /* Number of arg to substitute (origin-0) */ + } *pattern; + union { + /* Names of macro args, concatenated in reverse order + with comma-space between them. + The only use of this is that we warn on redefinition + if this differs between the old and new definitions. */ + U_CHAR *argnames; + } args; +}; + +/* different kinds of things that can appear in the value field + of a hash node. Actually, this may be useless now. */ +union hashval { + char *cpval; + DEFINITION *defn; + KEYDEF *keydef; +}; + +/* + * special extension string that can be added to the last macro argument to + * allow it to absorb the "rest" of the arguments when expanded. Ex: + * #define wow(a, b...) process (b, a, b) + * { wow (1, 2, 3); } -> { process (2, 3, 1, 2, 3); } + * { wow (one, two); } -> { process (two, one, two); } + * if this "rest_arg" is used with the concat token '##' and if it is not + * supplied then the token attached to with ## will not be outputted. Ex: + * #define wow (a, b...) process (b ## , a, ## b) + * { wow (1, 2); } -> { process (2, 1, 2); } + * { wow (one); } -> { process (one); { + */ +static char rest_extension[] = "..."; +#define REST_EXTENSION_LENGTH (sizeof (rest_extension) - 1) + +/* This is the implicit parameter name when using variable number of + parameters for macros using the ISO C 9x extension. */ +static char va_args_name[] = "__VA_ARGS__"; +#define VA_ARGS_NAME_LENGTH (sizeof (va_args_name) - 1) + +/* The structure of a node in the hash table. The hash table + has entries for all tokens defined by #define directives (type T_MACRO), + plus some special tokens like __LINE__ (these each have their own + type, and the appropriate code is run when that type of node is seen. + It does not contain control words like "#define", which are recognized + by a separate piece of code. */ + +/* different flavors of hash nodes --- also used in keyword table */ +enum node_type { + T_DEFINE = 1, /* the `#define' keyword */ + T_INCLUDE, /* the `#include' keyword */ + T_INCLUDE_NEXT, /* the `#include_next' keyword */ + T_IMPORT, /* the `#import' keyword */ + T_IFDEF, /* the `#ifdef' keyword */ + T_IFNDEF, /* the `#ifndef' keyword */ + T_IF, /* the `#if' keyword */ + T_ELSE, /* `#else' */ + T_PRAGMA, /* `#pragma' */ + T_ELIF, /* `#elif' */ + T_UNDEF, /* `#undef' */ + T_LINE, /* `#line' */ + T_ERROR, /* `#error' */ + T_WARNING, /* `#warning' */ + T_ENDIF, /* `#endif' */ + T_SCCS, /* `#sccs', used on system V. */ + T_IDENT, /* `#ident', used on system V. */ + T_ASSERT, /* `#assert', taken from system V. */ + T_UNASSERT, /* `#unassert', taken from system V. */ + T_SPECLINE, /* special symbol `__LINE__' */ + T_DATE, /* `__DATE__' */ + T_FILE, /* `__FILE__' */ + T_BASE_FILE, /* `__BASE_FILE__' */ + T_INCLUDE_LEVEL, /* `__INCLUDE_LEVEL__' */ + T_VERSION, /* `__VERSION__' */ + T_SIZE_TYPE, /* `__SIZE_TYPE__' */ + T_PTRDIFF_TYPE, /* `__PTRDIFF_TYPE__' */ + T_WCHAR_TYPE, /* `__WCHAR_TYPE__' */ + T_USER_LABEL_PREFIX_TYPE, /* `__USER_LABEL_PREFIX__' */ + T_REGISTER_PREFIX_TYPE, /* `__REGISTER_PREFIX__' */ + T_IMMEDIATE_PREFIX_TYPE, /* `__IMMEDIATE_PREFIX__' */ + T_TIME, /* `__TIME__' */ + T_CONST, /* Constant value, used by `__STDC__' */ + T_MACRO, /* macro defined by `#define' */ + T_DISABLED, /* macro temporarily turned off for rescan */ + T_SPEC_DEFINED, /* special `defined' macro for use in #if statements */ + T_PCSTRING, /* precompiled string (hashval is KEYDEF *) */ + T_UNUSED /* Used for something not defined. */ + }; + +struct hashnode { + struct hashnode *next; /* double links for easy deletion */ + struct hashnode *prev; + struct hashnode **bucket_hdr; /* also, a back pointer to this node's hash + chain is kept, in case the node is the head + of the chain and gets deleted. */ + enum node_type type; /* type of special token */ + int length; /* length of token, for quick comparison */ + U_CHAR *name; /* the actual name */ + union hashval value; /* pointer to expansion, or whatever */ +}; + +typedef struct hashnode HASHNODE; + +/* Some definitions for the hash table. The hash function MUST be + computed as shown in hashf () below. That is because the rescan + loop computes the hash value `on the fly' for most tokens, + in order to avoid the overhead of a lot of procedure calls to + the hashf () function. Hashf () only exists for the sake of + politeness, for use when speed isn't so important. */ + +#define HASHSIZE 1403 +static HASHNODE *hashtab[HASHSIZE]; +#define HASHSTEP(old, c) ((old << 2) + c) +#define MAKE_POS(v) (v & 0x7fffffff) /* make number positive */ + +/* Symbols to predefine. */ + +#ifdef CPP_PREDEFINES +static char *predefs = CPP_PREDEFINES; +#else +static char *predefs = ""; +#endif + +/* We let tm.h override the types used here, to handle trivial differences + such as the choice of unsigned int or long unsigned int for size_t. + When machines start needing nontrivial differences in the size type, + it would be best to do something here to figure out automatically + from other information what type to use. */ + +/* The string value for __SIZE_TYPE__. */ + +#ifndef SIZE_TYPE +#define SIZE_TYPE "long unsigned int" +#endif + +/* The string value for __PTRDIFF_TYPE__. */ + +#ifndef PTRDIFF_TYPE +#define PTRDIFF_TYPE "long int" +#endif + +/* The string value for __WCHAR_TYPE__. */ + +/* CYGNUS LOCAL vmakarov */ +#ifndef NO_BUILTIN_WCHAR_TYPE +/* END CYGNUS LOCAL */ +#ifndef WCHAR_TYPE +#define WCHAR_TYPE "int" +#endif +char * wchar_type = WCHAR_TYPE; +#undef WCHAR_TYPE +/* CYGNUS LOCAL vmakarov */ +#endif +/* END CYGNUS LOCAL */ + +/* The string value for __USER_LABEL_PREFIX__ */ + +#ifndef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "" +#endif +char * user_label_prefix = USER_LABEL_PREFIX; +#undef USER_LABEL_PREFIX + +/* The string value for __REGISTER_PREFIX__ */ + +#ifndef REGISTER_PREFIX +#define REGISTER_PREFIX "" +#endif + +/* The string value for __IMMEDIATE_PREFIX__ */ + +#ifndef IMMEDIATE_PREFIX +#define IMMEDIATE_PREFIX "" +#endif + +/* In the definition of a #assert name, this structure forms + a list of the individual values asserted. + Each value is itself a list of "tokens". + These are strings that are compared by name. */ + +struct tokenlist_list { + struct tokenlist_list *next; + struct arglist *tokens; +}; + +struct assertion_hashnode { + struct assertion_hashnode *next; /* double links for easy deletion */ + struct assertion_hashnode *prev; + /* also, a back pointer to this node's hash + chain is kept, in case the node is the head + of the chain and gets deleted. */ + struct assertion_hashnode **bucket_hdr; + int length; /* length of token, for quick comparison */ + U_CHAR *name; /* the actual name */ + /* List of token-sequences. */ + struct tokenlist_list *value; +}; + +typedef struct assertion_hashnode ASSERTION_HASHNODE; + +/* Some definitions for the hash table. The hash function MUST be + computed as shown in hashf below. That is because the rescan + loop computes the hash value `on the fly' for most tokens, + in order to avoid the overhead of a lot of procedure calls to + the hashf function. hashf only exists for the sake of + politeness, for use when speed isn't so important. */ + +#define ASSERTION_HASHSIZE 37 +static ASSERTION_HASHNODE *assertion_hashtab[ASSERTION_HASHSIZE]; + +/* Nonzero means inhibit macroexpansion of what seem to be + assertion tests, in rescan. For #if. */ +static int assertions_flag; + +/* `struct directive' defines one #-directive, including how to handle it. */ + +#define DO_PROTO PROTO((U_CHAR *, U_CHAR *, FILE_BUF *, struct directive *)) + +struct directive { + int length; /* Length of name */ + int (*func) DO_PROTO; /* Function to handle directive */ + char *name; /* Name of directive */ + enum node_type type; /* Code which describes which directive. */ +}; + +#define IS_INCLUDE_DIRECTIVE_TYPE(t) \ +((int) T_INCLUDE <= (int) (t) && (int) (t) <= (int) T_IMPORT) + +/* These functions are declared to return int instead of void since they + are going to be placed in the table and some old compilers have trouble with + pointers to functions returning void. */ + +static int do_assert DO_PROTO; +static int do_define DO_PROTO; +static int do_elif DO_PROTO; +static int do_else DO_PROTO; +static int do_endif DO_PROTO; +static int do_error DO_PROTO; +static int do_ident DO_PROTO; +static int do_if DO_PROTO; +static int do_include DO_PROTO; +static int do_line DO_PROTO; +static int do_pragma DO_PROTO; +#ifdef SCCS_DIRECTIVE +static int do_sccs DO_PROTO; +#endif +static int do_unassert DO_PROTO; +static int do_undef DO_PROTO; +static int do_warning DO_PROTO; +static int do_xifdef DO_PROTO; + +/* Here is the actual list of #-directives, most-often-used first. */ + +static struct directive directive_table[] = { + { 6, do_define, "define", T_DEFINE}, + { 2, do_if, "if", T_IF}, + { 5, do_xifdef, "ifdef", T_IFDEF}, + { 6, do_xifdef, "ifndef", T_IFNDEF}, + { 5, do_endif, "endif", T_ENDIF}, + { 4, do_else, "else", T_ELSE}, + { 4, do_elif, "elif", T_ELIF}, + { 4, do_line, "line", T_LINE}, + { 7, do_include, "include", T_INCLUDE}, + { 12, do_include, "include_next", T_INCLUDE_NEXT}, + { 6, do_include, "import", T_IMPORT}, + { 5, do_undef, "undef", T_UNDEF}, + { 5, do_error, "error", T_ERROR}, + { 7, do_warning, "warning", T_WARNING}, +#ifdef SCCS_DIRECTIVE + { 4, do_sccs, "sccs", T_SCCS}, +#endif + { 6, do_pragma, "pragma", T_PRAGMA}, + { 5, do_ident, "ident", T_IDENT}, + { 6, do_assert, "assert", T_ASSERT}, + { 8, do_unassert, "unassert", T_UNASSERT}, + { -1, 0, "", T_UNUSED}, +}; + +/* When a directive handler is called, + this points to the # (or the : of the %:) that started the directive. */ +U_CHAR *directive_start; + +/* table to tell if char can be part of a C identifier. */ +U_CHAR is_idchar[256]; +/* table to tell if char can be first char of a c identifier. */ +U_CHAR is_idstart[256]; +/* table to tell if c is horizontal space. */ +static U_CHAR is_hor_space[256]; +/* table to tell if c is horizontal or vertical space. */ +U_CHAR is_space[256]; +/* names of some characters */ +static char *char_name[256]; + +#define SKIP_WHITE_SPACE(p) do { while (is_hor_space[*p]) p++; } while (0) +#define SKIP_ALL_WHITE_SPACE(p) do { while (is_space[*p]) p++; } while (0) + +static int errors = 0; /* Error counter for exit code */ + +/* Name of output file, for error messages. */ +static char *out_fname; + +/* Nonzero to ignore \ in string constants. Use to treat #line 1 "A:\file.h + as a non-form feed. If you want it to be a form feed, you must use + # 1 "\f". */ +static int ignore_escape_flag = 1; + +/* Stack of conditionals currently in progress + (including both successful and failing conditionals). */ + +struct if_stack { + struct if_stack *next; /* for chaining to the next stack frame */ + char *fname; /* copied from input when frame is made */ + size_t fname_len; /* similarly */ + int lineno; /* similarly */ + int if_succeeded; /* true if a leg of this if-group + has been passed through rescan */ + U_CHAR *control_macro; /* For #ifndef at start of file, + this is the macro name tested. */ + enum node_type type; /* type of last directive seen in this group */ +}; +typedef struct if_stack IF_STACK_FRAME; +static IF_STACK_FRAME *if_stack = NULL; + +/* Buffer of -M output. */ +static char *deps_buffer; + +/* Number of bytes allocated in above. */ +static int deps_allocated_size; + +/* Number of bytes used. */ +static int deps_size; + +/* Number of bytes since the last newline. */ +static int deps_column; + +/* Nonzero means -I- has been seen, + so don't look for #include "foo" the source-file directory. */ +static int ignore_srcdir; + +static int safe_read PROTO((int, char *, int)); +static void safe_write PROTO((int, char *, int)); +static void eprint_string PROTO((char *, size_t)); + +int main PROTO((int, char **)); + +static void path_include PROTO((char *)); + +static U_CHAR *index0 PROTO((U_CHAR *, int, size_t)); + +static void trigraph_pcp PROTO((FILE_BUF *)); + +static void newline_fix PROTO((U_CHAR *)); +static void name_newline_fix PROTO((U_CHAR *)); + +static char *get_lintcmd PROTO((U_CHAR *, U_CHAR *, U_CHAR **, int *, int *)); + +static void rescan PROTO((FILE_BUF *, int)); + +static FILE_BUF expand_to_temp_buffer PROTO((U_CHAR *, U_CHAR *, int, int)); + +static int handle_directive PROTO((FILE_BUF *, FILE_BUF *)); + +static struct tm *timestamp PROTO((void)); +static void special_symbol PROTO((HASHNODE *, FILE_BUF *)); + +static int is_system_include PROTO((char *)); +static char *base_name PROTO((char *)); +static int absolute_filename PROTO((char *)); +static size_t simplify_filename PROTO((char *)); + +static char *read_filename_string PROTO((int, FILE *)); +static struct file_name_map *read_name_map PROTO((char *)); +static int open_include_file PROTO((char *, struct file_name_list *, U_CHAR *, struct include_file **)); +static char *remap_include_file PROTO((char *, struct file_name_list *)); +static int lookup_ino_include PROTO((struct include_file *)); + +static void finclude PROTO((int, struct include_file *, FILE_BUF *, int, struct file_name_list *)); +static void record_control_macro PROTO((struct include_file *, U_CHAR *)); + +static char *check_precompiled PROTO((int, struct stat *, char *, char **)); +static int check_preconditions PROTO((char *)); +static void pcfinclude PROTO((U_CHAR *, U_CHAR *, FILE_BUF *)); +static void pcstring_used PROTO((HASHNODE *)); +static void write_output PROTO((void)); +static void pass_thru_directive PROTO((U_CHAR *, U_CHAR *, FILE_BUF *, struct directive *)); + +static MACRODEF create_definition PROTO((U_CHAR *, U_CHAR *, FILE_BUF *)); + +static int check_macro_name PROTO((U_CHAR *, char *)); +static int compare_defs PROTO((DEFINITION *, DEFINITION *)); +static int comp_def_part PROTO((int, U_CHAR *, int, U_CHAR *, int, int)); + +static DEFINITION *collect_expansion PROTO((U_CHAR *, U_CHAR *, int, struct arglist *)); + +int check_assertion PROTO((U_CHAR *, int, int, struct arglist *)); +static int compare_token_lists PROTO((struct arglist *, struct arglist *)); + +static struct arglist *read_token_list PROTO((U_CHAR **, U_CHAR *, int *)); +static void free_token_list PROTO((struct arglist *)); + +static ASSERTION_HASHNODE *assertion_install PROTO((U_CHAR *, int, int)); +static ASSERTION_HASHNODE *assertion_lookup PROTO((U_CHAR *, int, int)); +static void delete_assertion PROTO((ASSERTION_HASHNODE *)); + +static void do_once PROTO((void)); + +static HOST_WIDE_INT eval_if_expression PROTO((U_CHAR *, int)); +static void conditional_skip PROTO((FILE_BUF *, int, enum node_type, U_CHAR *, FILE_BUF *)); +static void skip_if_group PROTO((FILE_BUF *, int, FILE_BUF *)); +static void validate_else PROTO((U_CHAR *, U_CHAR *)); + +static U_CHAR *skip_to_end_of_comment PROTO((FILE_BUF *, int *, int)); +static U_CHAR *skip_quoted_string PROTO((U_CHAR *, U_CHAR *, int, int *, int *, int *)); +static char *quote_string PROTO((char *, char *, size_t)); +static U_CHAR *skip_paren_group PROTO((FILE_BUF *)); + +/* Last arg to output_line_directive. */ +enum file_change_code {same_file, enter_file, leave_file}; +static void output_line_directive PROTO((FILE_BUF *, FILE_BUF *, int, enum file_change_code)); + +static void macroexpand PROTO((HASHNODE *, FILE_BUF *)); + +struct argdata; +static char *macarg PROTO((struct argdata *, int)); + +static U_CHAR *macarg1 PROTO((U_CHAR *, U_CHAR *, struct hashnode *, int *, int *, int *, int)); + +static int discard_comments PROTO((U_CHAR *, int, int)); + +static int change_newlines PROTO((U_CHAR *, int)); + +static char *my_strerror PROTO((int)); +void error PRINTF_PROTO_1((char *, ...)); +static void verror PROTO((char *, va_list)); +static void error_from_errno PROTO((char *)); +void warning PRINTF_PROTO_1((char *, ...)); +static void vwarning PROTO((char *, va_list)); +static void error_with_line PRINTF_PROTO_2((int, char *, ...)); +static void verror_with_line PROTO((int, char *, va_list)); +static void vwarning_with_line PROTO((int, char *, va_list)); +static void warning_with_line PRINTF_PROTO_2((int, char *, ...)); +void pedwarn PRINTF_PROTO_1((char *, ...)); +void pedwarn_with_line PRINTF_PROTO_2((int, char *, ...)); +static void pedwarn_with_file_and_line PRINTF_PROTO_4((char *, size_t, int, char *, ...)); + +static void print_containing_files PROTO((void)); + +static int line_for_error PROTO((int)); +static int grow_outbuf PROTO((FILE_BUF *, int)); + +static HASHNODE *install PROTO((U_CHAR *, int, enum node_type, char *, int)); +HASHNODE *lookup PROTO((U_CHAR *, int, int)); +static void delete_macro PROTO((HASHNODE *)); +static int hashf PROTO((U_CHAR *, int, int)); + +static void dump_single_macro PROTO((HASHNODE *, FILE *)); +static void dump_all_macros PROTO((void)); +static void dump_defn_1 PROTO((U_CHAR *, int, int, FILE *)); +static void dump_arg_n PROTO((DEFINITION *, int, FILE *)); + +static void initialize_char_syntax PROTO((void)); +static void initialize_builtins PROTO((FILE_BUF *, FILE_BUF *)); + +static void make_definition PROTO((char *)); +static void make_undef PROTO((char *, FILE_BUF *)); + +static void make_assertion PROTO((char *, char *)); + +static struct file_name_list *new_include_prefix PROTO((struct file_name_list *, const char *, const char *, const char *)); +static void append_include_chain PROTO((struct file_name_list *, struct file_name_list *)); + +static int quote_string_for_make PROTO((char *, char *)); +static void deps_output PROTO((char *, int)); + +static void fatal PRINTF_PROTO_1((char *, ...)) __attribute__ ((noreturn)); +void fancy_abort PROTO((void)) __attribute__ ((noreturn)); +static void perror_with_name PROTO((char *)); +static void pfatal_with_name PROTO((char *)) __attribute__ ((noreturn)); +static void pipe_closed PROTO((int)) __attribute__ ((noreturn)); + +static void memory_full PROTO((void)) __attribute__ ((noreturn)); +static char *savestring PROTO((char *)); +static void print_help PROTO((void)); + +/* Read LEN bytes at PTR from descriptor DESC, for file FILENAME, + retrying if necessary. If MAX_READ_LEN is defined, read at most + that bytes at a time. Return a negative value if an error occurs, + otherwise return the actual number of bytes read, + which must be LEN unless end-of-file was reached. */ + +static int +safe_read (desc, ptr, len) + int desc; + char *ptr; + int len; +{ + int left, rcount, nchars; + + left = len; + while (left > 0) { + rcount = left; +#ifdef MAX_READ_LEN + if (rcount > MAX_READ_LEN) + rcount = MAX_READ_LEN; +#endif + nchars = read (desc, ptr, rcount); + if (nchars < 0) + { +#ifdef EINTR + if (errno == EINTR) + continue; +#endif + return nchars; + } + if (nchars == 0) + break; + ptr += nchars; + left -= nchars; + } + return len - left; +} + +/* Write LEN bytes at PTR to descriptor DESC, + retrying if necessary, and treating any real error as fatal. + If MAX_WRITE_LEN is defined, write at most that many bytes at a time. */ + +static void +safe_write (desc, ptr, len) + int desc; + char *ptr; + int len; +{ + int wcount, written; + + while (len > 0) { + wcount = len; +#ifdef MAX_WRITE_LEN + if (wcount > MAX_WRITE_LEN) + wcount = MAX_WRITE_LEN; +#endif + written = write (desc, ptr, wcount); + if (written < 0) + { +#ifdef EINTR + if (errno == EINTR) + continue; +#endif + pfatal_with_name (out_fname); + } + ptr += written; + len -= written; + } +} + +/* Print a string to stderr, with extra handling in case it contains + embedded NUL characters. Any present are written as is. + + Using fwrite for this purpose produces undesireable results on VMS + when stderr happens to be a record oriented file, such as a batch log + file, rather than a stream oriented one. */ + +static void +eprint_string (string, length) + char *string; + size_t length; +{ + size_t segment_length; + + do { + fprintf(stderr, "%s", string); + length -= (segment_length = strlen(string)); + if (length > 0) + { + fputc('\0', stderr); + length -= 1; + /* Advance past the portion which has already been printed. */ + string += segment_length + 1; + } + } while (length > 0); +} + + +static void +print_help () +{ + printf ("Usage: %s [switches] input output\n", progname); + printf ("Switches:\n"); + printf (" -include Include the contents of before other files\n"); + printf (" -imacros Accept definition of marcos in \n"); + printf (" -iprefix Specify as a prefix for next two options\n"); + printf (" -iwithprefix Add to the end of the system include paths\n"); + printf (" -iwithprefixbefore Add to the end of the main include paths\n"); + printf (" -isystem Add to the start of the system include paths\n"); + printf (" -idirafter Add to the end of the system include paths\n"); + printf (" -I Add to the end of the main include paths\n"); + printf (" -nostdinc Do not search the system include directories\n"); + printf (" -nostdinc++ Do not search the system include directories for C++\n"); + printf (" -o Put output into \n"); + printf (" -pedantic Issue all warnings demanded by strict ANSI C\n"); + printf (" -traditional Follow K&R pre-processor behaviour\n"); + printf (" -trigraphs Support ANSI C trigraphs\n"); + printf (" -lang-c Assume that the input sources are in C\n"); + printf (" -lang-c89 Assume that the input is C89; depricated\n"); + printf (" -lang-c++ Assume that the input sources are in C++\n"); + printf (" -lang-objc Assume that the input sources are in ObjectiveC\n"); + printf (" -lang-objc++ Assume that the input sources are in ObjectiveC++\n"); + printf (" -lang-asm Assume that the input sources are in assembler\n"); + printf (" -lang-chill Assume that the input sources are in Chill\n"); + printf (" -std= Specify the conformance standard; one of:\n"); + printf (" gnu89, gnu9x, c89, c9x, iso9899:1990,\n"); + printf (" iso9899:199409, iso9899:199x\n"); + printf (" -+ Allow parsing of C++ style features\n"); + printf (" -w Inhibit warning messages\n"); + printf (" -Wtrigraphs Warn if trigraphs are encountered\n"); + printf (" -Wno-trigraphs Do not warn about trigraphs\n"); + printf (" -Wcomment{s} Warn if one comment starts inside another\n"); + printf (" -Wno-comment{s} Do not warn about comments\n"); + printf (" -Wtraditional Warn if a macro argument is/would be turned into\n"); + printf (" a string if -tradtional is specified\n"); + printf (" -Wno-traditional Do not warn about stringification\n"); + printf (" -Wundef Warn if an undefined macro is used by #if\n"); + printf (" -Wno-undef Do not warn about testing udefined macros\n"); + printf (" -Wimport Warn about the use of the #import directive\n"); + printf (" -Wno-import Do not warn about the use of #import\n"); + printf (" -Werror Treat all warnings as errors\n"); + printf (" -Wno-error Do not treat warnings as errors\n"); + printf (" -Wall Enable all preprocessor warnings\n"); + printf (" -M Generate make dependencies\n"); + printf (" -MM As -M, but ignore system header files\n"); + printf (" -MD As -M, but put output in a .d file\n"); + printf (" -MMD As -MD, but ignore system header files\n"); + printf (" -MG Treat missing header file as generated files\n"); + printf (" -g Include #define and #undef directives in the output\n"); + printf (" -D Define a with string '1' as its value\n"); + printf (" -D= Define a with as its value\n"); + printf (" -A () Assert the to \n"); + printf (" -U Undefine \n"); + printf (" -u or -undef Do not predefine any macros\n"); + printf (" -v Display the version number\n"); + printf (" -H Print the name of header files as they are used\n"); + printf (" -C Do not discard comments\n"); + printf (" -dM Display a list of macro definitions active at end\n"); + printf (" -dD Preserve macro definitions in output\n"); + printf (" -dN As -dD except that only the names are preserved\n"); + printf (" -dI Include #include directives in the output\n"); + printf (" -ifoutput Describe skipped code blocks in output \n"); + printf (" -P Do not generate #line directives\n"); + printf (" -$ Do not include '$' in identifiers\n"); + printf (" -remap Remap file names when including files.\n"); + printf (" -h or --help Display this information\n"); +} + +int +main (argc, argv) + int argc; + char **argv; +{ + struct stat st; + char *in_fname; + char *cp; + int f, i; + FILE_BUF *fp; + char **pend_files = (char **) xmalloc (argc * sizeof (char *)); + char **pend_defs = (char **) xmalloc (argc * sizeof (char *)); + char **pend_undefs = (char **) xmalloc (argc * sizeof (char *)); + char **pend_assertions = (char **) xmalloc (argc * sizeof (char *)); + char **pend_includes = (char **) xmalloc (argc * sizeof (char *)); + + /* Record the option used with each element of pend_assertions. + This is preparation for supporting more than one option for making + an assertion. */ + char **pend_assertion_options = (char **) xmalloc (argc * sizeof (char *)); + int inhibit_predefs = 0; + int no_standard_includes = 0; + int no_standard_cplusplus_includes = 0; + int missing_newline = 0; + + /* Non-0 means don't output the preprocessed program. */ + int inhibit_output = 0; + /* Non-0 means -v, so print the full set of include dirs. */ + int verbose = 0; + + /* File name which deps are being written to. + This is 0 if deps are being written to stdout. */ + char *deps_file = 0; + /* Fopen file mode to open deps_file with. */ + char *deps_mode = "a"; + /* Stream on which to print the dependency information. */ + FILE *deps_stream = 0; + /* Target-name to write with the dependency information. */ + char *deps_target = 0; + +#if defined (RLIMIT_STACK) && defined (HAVE_GETRLIMIT) && defined (HAVE_SETRLIMIT) + /* Get rid of any avoidable limit on stack size. */ + { + struct rlimit rlim; + + /* Set the stack limit huge so that alloca (particularly stringtab + in dbxread.c) does not fail. */ + getrlimit (RLIMIT_STACK, &rlim); + rlim.rlim_cur = rlim.rlim_max; + setrlimit (RLIMIT_STACK, &rlim); + } +#endif + +#ifdef SIGPIPE + signal (SIGPIPE, pipe_closed); +#endif + + progname = base_name (argv[0]); + +#ifdef VMS + { + /* Remove extension from PROGNAME. */ + char *p; + char *s = progname = savestring (progname); + + if ((p = rindex (s, ';')) != 0) *p = '\0'; /* strip version number */ + if ((p = rindex (s, '.')) != 0 /* strip type iff ".exe" */ + && (p[1] == 'e' || p[1] == 'E') + && (p[2] == 'x' || p[2] == 'X') + && (p[3] == 'e' || p[3] == 'E') + && !p[4]) + *p = '\0'; + } +#endif + + in_fname = NULL; + out_fname = NULL; + + /* Initialize is_idchar. */ + initialize_char_syntax (); + + no_line_directives = 0; + no_trigraphs = 1; + dump_macros = dump_none; + no_output = 0; + cplusplus = 0; + cplusplus_comments = 1; + + bzero ((char *) pend_files, argc * sizeof (char *)); + bzero ((char *) pend_defs, argc * sizeof (char *)); + bzero ((char *) pend_undefs, argc * sizeof (char *)); + bzero ((char *) pend_assertions, argc * sizeof (char *)); + bzero ((char *) pend_includes, argc * sizeof (char *)); + +#ifdef MULTIBYTE_CHARS + /* Change to the native locale for multibyte conversions. */ + setlocale (LC_CTYPE, ""); + literal_codeset = getenv ("LANG"); +#endif + + /* Process switches and find input file name. */ + + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') { + if (out_fname != NULL) + { + print_help (); + fatal ("Too many arguments"); + } + else if (in_fname != NULL) + out_fname = argv[i]; + else + in_fname = argv[i]; + } else { + switch (argv[i][1]) { + + case 'i': + if (!strcmp (argv[i], "-include")) { + int temp = i; + + if (i + 1 == argc) + fatal ("Filename missing after `-include' option"); + else + simplify_filename (pend_includes[temp] = argv[++i]); + } + if (!strcmp (argv[i], "-imacros")) { + int temp = i; + + if (i + 1 == argc) + fatal ("Filename missing after `-imacros' option"); + else + simplify_filename (pend_files[temp] = argv[++i]); + } + if (!strcmp (argv[i], "-iprefix")) { + if (i + 1 == argc) + fatal ("Filename missing after `-iprefix' option"); + else + include_prefix = argv[++i]; + } + if (!strcmp (argv[i], "-ifoutput")) { + output_conditionals = 1; + } + if (!strcmp (argv[i], "-isystem")) { + struct file_name_list *dirtmp; + + if (! (dirtmp = new_include_prefix (NULL_PTR, NULL_PTR, + "", argv[++i]))) + break; + dirtmp->c_system_include_path = 1; + + if (before_system == 0) + before_system = dirtmp; + else + last_before_system->next = dirtmp; + last_before_system = dirtmp; /* Tail follows the last one */ + } + /* Add directory to end of path for includes, + with the default prefix at the front of its name. */ + if (!strcmp (argv[i], "-iwithprefix")) { + struct file_name_list *dirtmp; + char *prefix; + + if (include_prefix != 0) + prefix = include_prefix; + else { + prefix = savestring (GCC_INCLUDE_DIR); + /* Remove the `include' from /usr/local/lib/gcc.../include. */ + if (!strcmp (prefix + strlen (prefix) - 8, "/include")) + prefix[strlen (prefix) - 7] = 0; + } + + if (! (dirtmp = new_include_prefix (NULL_PTR, NULL_PTR, + prefix, argv[++i]))) + break; + + if (after_include == 0) + after_include = dirtmp; + else + last_after_include->next = dirtmp; + last_after_include = dirtmp; /* Tail follows the last one */ + } + /* Add directory to main path for includes, + with the default prefix at the front of its name. */ + if (!strcmp (argv[i], "-iwithprefixbefore")) { + struct file_name_list *dirtmp; + char *prefix; + + if (include_prefix != 0) + prefix = include_prefix; + else { + prefix = savestring (GCC_INCLUDE_DIR); + /* Remove the `include' from /usr/local/lib/gcc.../include. */ + if (!strcmp (prefix + strlen (prefix) - 8, "/include")) + prefix[strlen (prefix) - 7] = 0; + } + + dirtmp = new_include_prefix (NULL_PTR, NULL_PTR, prefix, argv[++i]); + append_include_chain (dirtmp, dirtmp); + } + /* Add directory to end of path for includes. */ + if (!strcmp (argv[i], "-idirafter")) { + struct file_name_list *dirtmp; + + if (! (dirtmp = new_include_prefix (NULL_PTR, NULL_PTR, + "", argv[++i]))) + break; + + if (after_include == 0) + after_include = dirtmp; + else + last_after_include->next = dirtmp; + last_after_include = dirtmp; /* Tail follows the last one */ + } + break; + + case 'o': + if (out_fname != NULL) + fatal ("Output filename specified twice"); + if (i + 1 == argc) + fatal ("Filename missing after -o option"); + out_fname = argv[++i]; + if (!strcmp (out_fname, "-")) + out_fname = ""; + break; + + case 'p': + if (!strcmp (argv[i], "-pedantic")) + pedantic = 1; + else if (!strcmp (argv[i], "-pedantic-errors")) { + pedantic = 1; + pedantic_errors = 1; + } else if (!strcmp (argv[i], "-pcp")) { + char *pcp_fname; + if (i + 1 == argc) + fatal ("Filename missing after -pcp option"); + pcp_fname = argv[++i]; + pcp_outfile + = ((pcp_fname[0] != '-' || pcp_fname[1] != '\0') + ? fopen (pcp_fname, "w") + : stdout); + if (pcp_outfile == 0) + pfatal_with_name (pcp_fname); + no_precomp = 1; + } + break; + + case 't': + if (!strcmp (argv[i], "-traditional")) { + traditional = 1; + cplusplus_comments = 0; + } else if (!strcmp (argv[i], "-trigraphs")) { +/* CYGNUS LOCAL chill */ + if (!chill) +/* END CYGNUS LOCAL chill */ + no_trigraphs = 0; + } + break; + + case 'l': + if (! strcmp (argv[i], "-lang-c")) + cplusplus = 0, cplusplus_comments = 1, c89 = 0, c9x = 1, objc = 0; + else if (! strcmp (argv[i], "-lang-c89")) + cplusplus = 0, cplusplus_comments = 0, c89 = 1, c9x = 0, objc = 0; + else if (! strcmp (argv[i], "-lang-c++")) + cplusplus = 1, cplusplus_comments = 1, c89 = 0, c9x = 0, objc = 0; + else if (! strcmp (argv[i], "-lang-objc")) + cplusplus = 0, cplusplus_comments = 1, c89 = 0, c9x = 0, objc = 1; + else if (! strcmp (argv[i], "-lang-objc++")) + cplusplus = 1, cplusplus_comments = 1, c89 = 0, c9x = 0, objc = 1; + else if (! strcmp (argv[i], "-lang-asm")) + lang_asm = 1; + else if (! strcmp (argv[i], "-lint")) + for_lint = 1; +/* CYGNUS LOCAL chill */ + if (! strcmp (argv[i], "-lang-chill")) + objc = 0, cplusplus = 0, chill = 1, /* traditional = 1, */ + no_trigraphs = 1, cplusplus_comments = 0;; +/* END CYGNUS LOCAL chill */ + break; + + case '+': + cplusplus = 1, cplusplus_comments = 1; + break; + + case 's': + if (!strcmp (argv[i], "-std=iso9899:1990") + || !strcmp (argv[i], "-std=iso9899:199409") + || !strcmp (argv[i], "-std=c89") + || !strcmp (argv[i], "-std=gnu89")) + cplusplus = 0, cplusplus_comments = 0, c89 = 1, c9x = 0, objc = 0; + else if (!strcmp (argv[i], "-std=iso9899:199x") + || !strcmp (argv[i], "-std=c9x") + || !strcmp (argv[i], "-std=gnu9x")) + cplusplus = 0, cplusplus_comments = 1, c89 = 0, c9x = 1, objc = 0; + break; + + case 'w': + inhibit_warnings = 1; + break; + + case 'W': + if (!strcmp (argv[i], "-Wtrigraphs")) + warn_trigraphs = 1; + else if (!strcmp (argv[i], "-Wno-trigraphs")) + warn_trigraphs = 0; + else if (!strcmp (argv[i], "-Wcomment")) + warn_comments = 1; + else if (!strcmp (argv[i], "-Wno-comment")) + warn_comments = 0; + else if (!strcmp (argv[i], "-Wcomments")) + warn_comments = 1; + else if (!strcmp (argv[i], "-Wno-comments")) + warn_comments = 0; + else if (!strcmp (argv[i], "-Wtraditional")) + warn_stringify = 1; + else if (!strcmp (argv[i], "-Wno-traditional")) + warn_stringify = 0; + else if (!strcmp (argv[i], "-Wundef")) + warn_undef = 1; + else if (!strcmp (argv[i], "-Wno-undef")) + warn_undef = 0; + else if (!strcmp (argv[i], "-Wimport")) + warn_import = 1; + else if (!strcmp (argv[i], "-Wno-import")) + warn_import = 0; + else if (!strcmp (argv[i], "-Werror")) + warnings_are_errors = 1; + else if (!strcmp (argv[i], "-Wno-error")) + warnings_are_errors = 0; + else if (!strcmp (argv[i], "-Wall")) + { + warn_trigraphs = 1; + warn_comments = 1; + } + break; + + case 'f': + if (!strcmp (argv[i], "-fleading-underscore")) + user_label_prefix = "_"; + else if (!strcmp (argv[i], "-fno-leading-underscore")) + user_label_prefix = ""; + break; + + case 'M': + /* The style of the choices here is a bit mixed. + The chosen scheme is a hybrid of keeping all options in one string + and specifying each option in a separate argument: + -M|-MM|-MD file|-MMD file [-MG]. An alternative is: + -M|-MM|-MD file|-MMD file|-MG|-MMG; or more concisely: + -M[M][G][D file]. This is awkward to handle in specs, and is not + as extensible. */ + /* ??? -MG must be specified in addition to one of -M or -MM. + This can be relaxed in the future without breaking anything. + The converse isn't true. */ + + /* -MG isn't valid with -MD or -MMD. This is checked for later. */ + if (!strcmp (argv[i], "-MG")) + { + print_deps_missing_files = 1; + break; + } + if (!strcmp (argv[i], "-M")) + print_deps = 2; + else if (!strcmp (argv[i], "-MM")) + print_deps = 1; + else if (!strcmp (argv[i], "-MD")) + print_deps = 2; + else if (!strcmp (argv[i], "-MMD")) + print_deps = 1; + /* For -MD and -MMD options, write deps on file named by next arg. */ + if (!strcmp (argv[i], "-MD") + || !strcmp (argv[i], "-MMD")) { + if (i + 1 == argc) + fatal ("Filename missing after %s option", argv[i]); + i++; + deps_file = argv[i]; + deps_mode = "w"; + } else { + /* For -M and -MM, write deps on standard output + and suppress the usual output. */ + deps_stream = stdout; + inhibit_output = 1; + } + break; + + case 'd': + { + char *p = argv[i] + 2; + char c; + while ((c = *p++)) { + /* Arg to -d specifies what parts of macros to dump */ + switch (c) { + case 'M': + dump_macros = dump_only; + no_output = 1; + break; + case 'N': + dump_macros = dump_names; + break; + case 'D': + dump_macros = dump_definitions; + break; + case 'I': + dump_includes = 1; + break; + } + } + } + break; + + case 'g': + if (argv[i][2] == '3') + debug_output = 1; + break; + + case '-': + if (strcmp (argv[i], "--help") != 0) + return i; + print_help (); + exit (0); + break; + + case 'v': + fprintf (stderr, "GNU CPP version %s", version_string); +#ifdef TARGET_VERSION + TARGET_VERSION; +#endif + fprintf (stderr, "\n"); + verbose = 1; + break; + + case 'H': + print_include_names = 1; + break; + + case 'D': + if (argv[i][2] != 0) + pend_defs[i] = argv[i] + 2; + else if (i + 1 == argc) + fatal ("Macro name missing after -D option"); + else + i++, pend_defs[i] = argv[i]; + break; + + case 'A': + { + char *p; + + if (argv[i][2] != 0) + p = argv[i] + 2; + else if (i + 1 == argc) + fatal ("Assertion missing after -A option"); + else + p = argv[++i]; + + if (!strcmp (p, "-")) { + /* -A- eliminates all predefined macros and assertions. + Let's include also any that were specified earlier + on the command line. That way we can get rid of any + that were passed automatically in from GCC. */ + int j; + inhibit_predefs = 1; + for (j = 0; j < i; j++) + pend_defs[j] = pend_assertions[j] = 0; + } else { + pend_assertions[i] = p; + pend_assertion_options[i] = "-A"; + } + } + break; + + case 'U': /* JF #undef something */ + if (argv[i][2] != 0) + pend_undefs[i] = argv[i] + 2; + else if (i + 1 == argc) + fatal ("Macro name missing after -U option"); + else + pend_undefs[i] = argv[i+1], i++; + break; + + case 'C': + put_out_comments = 1; + break; + + case 'E': /* -E comes from cc -E; ignore it. */ + break; + + case 'P': + no_line_directives = 1; + break; + + case '$': /* Don't include $ in identifiers. */ + is_idchar['$'] = is_idstart['$'] = 0; + break; + + case 'I': /* Add directory to path for includes. */ + { + struct file_name_list *dirtmp; + + if (! ignore_srcdir && !strcmp (argv[i] + 2, "-")) { + ignore_srcdir = 1; + /* Don't use any preceding -I directories for #include <...>. */ + first_bracket_include = 0; + } + else { + dirtmp = new_include_prefix (last_include, NULL_PTR, "", + argv[i][2] ? argv[i] + 2 : argv[++i]); + append_include_chain (dirtmp, dirtmp); + } + } + break; + + case 'n': + if (!strcmp (argv[i], "-nostdinc")) + /* -nostdinc causes no default include directories. + You must specify all include-file directories with -I. */ + no_standard_includes = 1; + else if (!strcmp (argv[i], "-nostdinc++")) + /* -nostdinc++ causes no default C++-specific include directories. */ + no_standard_cplusplus_includes = 1; + else if (!strcmp (argv[i], "-noprecomp")) + no_precomp = 1; + break; + + case 'r': + if (!strcmp (argv[i], "-remap")) + remap = 1; + break; + + case 'u': + /* Sun compiler passes undocumented switch "-undef". + Let's assume it means to inhibit the predefined symbols. */ + inhibit_predefs = 1; + break; + + case '\0': /* JF handle '-' as file name meaning stdin or stdout */ + if (in_fname == NULL) { + in_fname = ""; + break; + } else if (out_fname == NULL) { + out_fname = ""; + break; + } /* else fall through into error */ + + default: + fatal ("Invalid option `%s'", argv[i]); + } + } + } + + /* Add dirs from CPATH after dirs from -I. */ + /* There seems to be confusion about what CPATH should do, + so for the moment it is not documented. */ + /* Some people say that CPATH should replace the standard include dirs, + but that seems pointless: it comes before them, so it overrides them + anyway. */ + GET_ENV_PATH_LIST (cp, "CPATH"); + if (cp && ! no_standard_includes) + path_include (cp); + + /* Initialize output buffer */ + + outbuf.buf = (U_CHAR *) xmalloc (OUTBUF_SIZE); + outbuf.bufp = outbuf.buf; + outbuf.length = OUTBUF_SIZE; + + /* Do partial setup of input buffer for the sake of generating + early #line directives (when -g is in effect). */ + + fp = &instack[++indepth]; + if (in_fname == NULL) + in_fname = ""; + fp->nominal_fname = fp->fname = in_fname; + fp->nominal_fname_len = strlen (in_fname); + fp->lineno = 0; + +/* CYGNUS LOCAL vmakarov */ +#ifndef NO_BUILTIN_WCHAR_TYPE +/* END CYGNUS LOCAL */ + /* In C++, wchar_t is a distinct basic type, and we can expect + __wchar_t to be defined by cc1plus. */ + if (cplusplus) + wchar_type = "__wchar_t"; +/* CYGNUS LOCAL vmakarov */ +#endif +/* END CYGNUS LOCAL */ + + /* Install __LINE__, etc. Must follow initialize_char_syntax + and option processing. */ + initialize_builtins (fp, &outbuf); + + /* Do standard #defines and assertions + that identify system and machine type. */ + + if (!inhibit_predefs) { + char *p = (char *) alloca (strlen (predefs) + 1); + +#ifdef VMS + struct dsc$descriptor_s lcl_name; + struct item_list { + unsigned short length; /* input length */ + unsigned short code; /* item code */ + unsigned long dptr; /* data ptr */ + unsigned long lptr; /* output length ptr */ + }; + + unsigned long syi_length; + char syi_data[16]; + + struct item_list items[] = { + { 16, SYI$_VERSION, 0, 0 }, + { 0, 0, 0, 0 } + }; + + items[0].dptr = (unsigned long)syi_data; + items[0].lptr = (unsigned long)(&syi_length); + + if (SYS$GETSYIW (0, 0, 0, items, NULL, NULL, NULL, NULL) == SS$_NORMAL) + { + unsigned long vms_version_value; + char *vers; + + vers = syi_data; + vms_version_value = 0; + + if (*vers == 'V') + vers++; + if (ISDIGIT (*vers)) + { + vms_version_value = (*vers - '0') * 10000000; + } + vers++; + if (*vers == '.') + { + vers++; + if (ISDIGIT (*vers)) + { + vms_version_value += (*vers - '0') * 100000; + } + } + + if (vms_version_value > 0) + { + char versbuf[32]; + + sprintf (versbuf, "__VMS_VER=%08ld", vms_version_value); + if (debug_output) + output_line_directive (fp, &outbuf, 0, same_file); + make_definition (versbuf); + } + } +#endif + + strcpy (p, predefs); + while (*p) { + char *q; + while (*p == ' ' || *p == '\t') + p++; + /* Handle -D options. */ + if (p[0] == '-' && p[1] == 'D') { + q = &p[2]; + while (*p && *p != ' ' && *p != '\t') + p++; + if (*p != 0) + *p++= 0; + if (debug_output) + output_line_directive (fp, &outbuf, 0, same_file); + make_definition (q); + while (*p == ' ' || *p == '\t') + p++; + } else if (p[0] == '-' && p[1] == 'A') { + /* Handle -A options (assertions). */ + char *assertion; + char *past_name; + char *value; + char *past_value; + char *termination; + int save_char; + + assertion = &p[2]; + past_name = assertion; + /* Locate end of name. */ + while (*past_name && *past_name != ' ' + && *past_name != '\t' && *past_name != '(') + past_name++; + /* Locate `(' at start of value. */ + value = past_name; + while (*value && (*value == ' ' || *value == '\t')) + value++; + if (*value++ != '(') + abort (); + while (*value && (*value == ' ' || *value == '\t')) + value++; + past_value = value; + /* Locate end of value. */ + while (*past_value && *past_value != ' ' + && *past_value != '\t' && *past_value != ')') + past_value++; + termination = past_value; + while (*termination && (*termination == ' ' || *termination == '\t')) + termination++; + if (*termination++ != ')') + abort (); + if (*termination && *termination != ' ' && *termination != '\t') + abort (); + /* Temporarily null-terminate the value. */ + save_char = *termination; + *termination = '\0'; + /* Install the assertion. */ + make_assertion ("-A", assertion); + *termination = (char) save_char; + p = termination; + while (*p == ' ' || *p == '\t') + p++; + } else { + abort (); + } + } + } + + /* Now handle the command line options. */ + + /* Do -U's, -D's and -A's in the order they were seen. */ + for (i = 1; i < argc; i++) { + if (pend_undefs[i]) { + if (debug_output) + output_line_directive (fp, &outbuf, 0, same_file); + make_undef (pend_undefs[i], &outbuf); + } + if (pend_defs[i]) { + if (debug_output) + output_line_directive (fp, &outbuf, 0, same_file); + make_definition (pend_defs[i]); + } + if (pend_assertions[i]) + make_assertion (pend_assertion_options[i], pend_assertions[i]); + } + + done_initializing = 1; + + { /* Read the appropriate environment variable and if it exists + replace include_defaults with the listed path. */ + char *epath = 0; + switch ((objc << 1) + cplusplus) + { + case 0: + GET_ENV_PATH_LIST (epath, "C_INCLUDE_PATH"); + break; + case 1: + GET_ENV_PATH_LIST (epath, "CPLUS_INCLUDE_PATH"); + break; + case 2: + GET_ENV_PATH_LIST (epath, "OBJC_INCLUDE_PATH"); + break; + case 3: + GET_ENV_PATH_LIST (epath, "OBJCPLUS_INCLUDE_PATH"); + break; + } + /* If the environment var for this language is set, + add to the default list of include directories. */ + if (epath) { + int num_dirs; + char *startp, *endp; + + for (num_dirs = 1, startp = epath; *startp; startp++) + if (*startp == PATH_SEPARATOR) + num_dirs++; + include_defaults + = (struct default_include *) xmalloc ((num_dirs + * sizeof (struct default_include)) + + sizeof (include_defaults_array)); + startp = endp = epath; + num_dirs = 0; + while (1) { + char c = *endp++; + if (c == PATH_SEPARATOR || !c) { + endp[-1] = 0; + include_defaults[num_dirs].fname + = startp == endp ? "." : savestring (startp); + endp[-1] = c; + include_defaults[num_dirs].component = 0; + include_defaults[num_dirs].cplusplus = cplusplus; + include_defaults[num_dirs].cxx_aware = 1; + num_dirs++; + if (!c) + break; + startp = endp; + } + } + /* Put the usual defaults back in at the end. */ + bcopy ((char *) include_defaults_array, + (char *) &include_defaults[num_dirs], + sizeof (include_defaults_array)); + } + } + + append_include_chain (before_system, last_before_system); + first_system_include = before_system; + + /* Unless -fnostdinc, + tack on the standard include file dirs to the specified list */ + if (!no_standard_includes) { + struct default_include *p = include_defaults; + char *specd_prefix = include_prefix; + char *default_prefix = savestring (GCC_INCLUDE_DIR); + int default_len = 0; + /* Remove the `include' from /usr/local/lib/gcc.../include. */ + if (!strcmp (default_prefix + strlen (default_prefix) - 8, "/include")) { + default_len = strlen (default_prefix) - 7; + default_prefix[default_len] = 0; + } + /* Search "translated" versions of GNU directories. + These have /usr/local/lib/gcc... replaced by specd_prefix. */ + if (specd_prefix != 0 && default_len != 0) + for (p = include_defaults; p->fname; p++) { + /* Some standard dirs are only for C++. */ + if (!p->cplusplus || (cplusplus && !no_standard_cplusplus_includes)) { + /* Does this dir start with the prefix? */ + if (!strncmp (p->fname, default_prefix, default_len)) { + /* Yes; change prefix and add to search list. */ + struct file_name_list *new + = new_include_prefix (NULL_PTR, NULL_PTR, specd_prefix, + p->fname + default_len); + if (new) { + new->c_system_include_path = !p->cxx_aware; + append_include_chain (new, new); + if (first_system_include == 0) + first_system_include = new; + } + } + } + } + /* Search ordinary names for GNU include directories. */ + for (p = include_defaults; p->fname; p++) { + /* Some standard dirs are only for C++. */ + if (!p->cplusplus || (cplusplus && !no_standard_cplusplus_includes)) { + struct file_name_list *new + = new_include_prefix (NULL_PTR, p->component, "", p->fname); + if (new) { + new->c_system_include_path = !p->cxx_aware; + append_include_chain (new, new); + if (first_system_include == 0) + first_system_include = new; + } + } + } + } + + /* Tack the after_include chain at the end of the include chain. */ + append_include_chain (after_include, last_after_include); + if (first_system_include == 0) + first_system_include = after_include; + + /* With -v, print the list of dirs to search. */ + if (verbose) { + struct file_name_list *p; + fprintf (stderr, "#include \"...\" search starts here:\n"); + for (p = include; p; p = p->next) { + if (p == first_bracket_include) + fprintf (stderr, "#include <...> search starts here:\n"); + if (!p->fname[0]) + fprintf (stderr, " .\n"); + else if (!strcmp (p->fname, "/") || !strcmp (p->fname, "//")) + fprintf (stderr, " %s\n", p->fname); + else + /* Omit trailing '/'. */ + fprintf (stderr, " %.*s\n", (int) strlen (p->fname) - 1, p->fname); + } + fprintf (stderr, "End of search list.\n"); + } + + /* -MG doesn't select the form of output and must be specified with one of + -M or -MM. -MG doesn't make sense with -MD or -MMD since they don't + inhibit compilation. */ + if (print_deps_missing_files && (print_deps == 0 || !inhibit_output)) + fatal ("-MG must be specified with one of -M or -MM"); + + /* Either of two environment variables can specify output of deps. + Its value is either "OUTPUT_FILE" or "OUTPUT_FILE DEPS_TARGET", + where OUTPUT_FILE is the file to write deps info to + and DEPS_TARGET is the target to mention in the deps. */ + + if (print_deps == 0 + && (getenv ("SUNPRO_DEPENDENCIES") != 0 + || getenv ("DEPENDENCIES_OUTPUT") != 0)) { + char *spec = getenv ("DEPENDENCIES_OUTPUT"); + char *s; + char *output_file; + + if (spec == 0) { + spec = getenv ("SUNPRO_DEPENDENCIES"); + print_deps = 2; + } + else + print_deps = 1; + + s = spec; + /* Find the space before the DEPS_TARGET, if there is one. */ + /* This should use index. (mrs) */ + while (*s != 0 && *s != ' ') s++; + if (*s != 0) { + deps_target = s + 1; + output_file = xmalloc (s - spec + 1); + bcopy (spec, output_file, s - spec); + output_file[s - spec] = 0; + } + else { + deps_target = 0; + output_file = spec; + } + + deps_file = output_file; + deps_mode = "a"; + } + + /* For -M, print the expected object file name + as the target of this Make-rule. */ + if (print_deps) { + deps_allocated_size = 200; + deps_buffer = xmalloc (deps_allocated_size); + deps_buffer[0] = 0; + deps_size = 0; + deps_column = 0; + + if (deps_target) { + deps_output (deps_target, ':'); + } else if (*in_fname == 0) { + deps_output ("-", ':'); + } else { + char *p, *q; + int len; + + q = base_name (in_fname); + + /* Copy remainder to mungable area. */ + p = (char *) alloca (strlen(q) + 8); + strcpy (p, q); + + /* Output P, but remove known suffixes. */ + len = strlen (p); + q = p + len; + if (len >= 2 + && p[len - 2] == '.' + && index("cCsSm", p[len - 1])) + q = p + (len - 2); + else if (len >= 3 + && p[len - 3] == '.' + && p[len - 2] == 'c' + && p[len - 1] == 'c') + q = p + (len - 3); + else if (len >= 4 + && p[len - 4] == '.' + && p[len - 3] == 'c' + && p[len - 2] == 'x' + && p[len - 1] == 'x') + q = p + (len - 4); + else if (len >= 4 + && p[len - 4] == '.' + && p[len - 3] == 'c' + && p[len - 2] == 'p' + && p[len - 1] == 'p') + q = p + (len - 4); + + /* Supply our own suffix. */ + strcpy (q, OBJECT_SUFFIX); + + deps_output (p, ':'); + deps_output (in_fname, ' '); + } + } + + /* Scan the -imacros files before the main input. + Much like #including them, but with no_output set + so that only their macro definitions matter. */ + + no_output++; no_record_file++; + for (i = 1; i < argc; i++) + if (pend_files[i]) { + struct include_file *inc; + int fd = open_include_file (pend_files[i], NULL_PTR, NULL_PTR, &inc); + if (fd < 0) { + perror_with_name (pend_files[i]); + return FATAL_EXIT_CODE; + } + finclude (fd, inc, &outbuf, 0, NULL_PTR); + } + no_output--; no_record_file--; + + /* Copy the entire contents of the main input file into + the stacked input buffer previously allocated for it. */ + + /* JF check for stdin */ + if (in_fname == NULL || *in_fname == 0) { + in_fname = ""; + f = 0; + } else if ((f = open (in_fname, O_RDONLY, 0666)) < 0) + goto perror; + + if (fstat (f, &st) != 0) + pfatal_with_name (in_fname); + fp->nominal_fname = fp->fname = in_fname; + fp->nominal_fname_len = strlen (in_fname); + fp->lineno = 1; + fp->system_header_p = 0; + /* JF all this is mine about reading pipes and ttys */ + if (! S_ISREG (st.st_mode)) { + /* Read input from a file that is not a normal disk file. + We cannot preallocate a buffer with the correct size, + so we must read in the file a piece at the time and make it bigger. */ + int size; + int bsize; + int cnt; + + if (S_ISDIR (st.st_mode)) + fatal ("Input file `%s' is a directory", in_fname); + + bsize = 2000; + size = 0; + fp->buf = (U_CHAR *) xmalloc (bsize + 2); + for (;;) { + cnt = safe_read (f, (char *) fp->buf + size, bsize - size); + if (cnt < 0) goto perror; /* error! */ + size += cnt; + if (size != bsize) break; /* End of file */ + bsize *= 2; + fp->buf = (U_CHAR *) xrealloc (fp->buf, bsize + 2); + } + fp->length = size; + } else { + /* Read a file whose size we can determine in advance. + For the sake of VMS, st.st_size is just an upper bound. */ + size_t s = (size_t) st.st_size; + if (s != st.st_size || s + 2 < s) + memory_full (); + fp->buf = (U_CHAR *) xmalloc (s + 2); + fp->length = safe_read (f, (char *) fp->buf, s); + if (fp->length < 0) goto perror; + } + fp->bufp = fp->buf; + fp->if_stack = if_stack; + + /* Make sure data ends with a newline. And put a null after it. */ + + if ((fp->length > 0 && fp->buf[fp->length - 1] != '\n') + /* Backslash-newline at end is not good enough. */ + || (fp->length > 1 && fp->buf[fp->length - 2] == '\\')) { + fp->buf[fp->length++] = '\n'; + missing_newline = 1; + } + fp->buf[fp->length] = '\0'; + + /* Unless inhibited, convert trigraphs in the input. */ + + if (!no_trigraphs) + trigraph_pcp (fp); + + /* Now that we know the input file is valid, open the output. */ + + if (!out_fname || !strcmp (out_fname, "")) + out_fname = "stdout"; + else if (! freopen (out_fname, "w", stdout)) + pfatal_with_name (out_fname); + + output_line_directive (fp, &outbuf, 0, same_file); + + /* Scan the -include files before the main input. */ + + no_record_file++; + for (i = 1; i < argc; i++) + if (pend_includes[i]) { + struct include_file *inc; + int fd = open_include_file (pend_includes[i], NULL_PTR, NULL_PTR, &inc); + if (fd < 0) { + perror_with_name (pend_includes[i]); + return FATAL_EXIT_CODE; + } + finclude (fd, inc, &outbuf, 0, NULL_PTR); + } + no_record_file--; + + /* Scan the input, processing macros and directives. */ + + rescan (&outbuf, 0); + + if (missing_newline) + fp->lineno--; + + if (pedantic && missing_newline) + pedwarn ("file does not end in newline"); + + /* Now we have processed the entire input + Write whichever kind of output has been requested. */ + + if (dump_macros == dump_only) + dump_all_macros (); + else if (! inhibit_output) { + write_output (); + } + + if (print_deps) { + /* Don't actually write the deps file if compilation has failed. */ + if (errors == 0) { + if (deps_file && ! (deps_stream = fopen (deps_file, deps_mode))) + pfatal_with_name (deps_file); + fputs (deps_buffer, deps_stream); + putc ('\n', deps_stream); + if (deps_file) { + if (ferror (deps_stream) || fclose (deps_stream) != 0) + fatal ("I/O error on output"); + } + } + } + + if (pcp_outfile && pcp_outfile != stdout + && (ferror (pcp_outfile) || fclose (pcp_outfile) != 0)) + fatal ("I/O error on `-pcp' output"); + + if (ferror (stdout) || fclose (stdout) != 0) + fatal ("I/O error on output"); + + if (errors) + exit (FATAL_EXIT_CODE); + exit (SUCCESS_EXIT_CODE); + + perror: + pfatal_with_name (in_fname); + return 0; +} + +/* Given a colon-separated list of file names PATH, + add all the names to the search path for include files. */ + +static void +path_include (path) + char *path; +{ + char *p; + + p = path; + + if (*p) + while (1) { + char *q = p; + char c; + struct file_name_list *dirtmp; + + /* Find the end of this name. */ + while ((c = *q++) != PATH_SEPARATOR && c) + continue; + + q[-1] = 0; + dirtmp = new_include_prefix (last_include, NULL_PTR, + "", p == q ? "." : p); + q[-1] = c; + append_include_chain (dirtmp, dirtmp); + + /* Advance past this name. */ + p = q; + if (! c) + break; + } +} + +/* Return the address of the first character in S that equals C. + S is an array of length N, possibly containing '\0's, and followed by '\0'. + Return 0 if there is no such character. Assume that C itself is not '\0'. + If we knew we could use memchr, we could just invoke memchr (S, C, N), + but unfortunately memchr isn't autoconfigured yet. */ + +static U_CHAR * +index0 (s, c, n) + U_CHAR *s; + int c; + size_t n; +{ + char *p = (char *) s; + for (;;) { + char *q = index (p, c); + if (q) + return (U_CHAR *) q; + else { + size_t l = strlen (p); + if (l == n) + return 0; + l++; + p += l; + n -= l; + } + } +} + +/* Pre-C-Preprocessor to translate ANSI trigraph idiocy in BUF + before main CCCP processing. Name `pcp' is also in honor of the + drugs the trigraph designers must have been on. + + Using an extra pass through the buffer takes a little extra time, + but is infinitely less hairy than trying to handle trigraphs inside + strings, etc. everywhere, and also makes sure that trigraphs are + only translated in the top level of processing. */ + +static void +trigraph_pcp (buf) + FILE_BUF *buf; +{ + register U_CHAR c, *fptr, *bptr, *sptr, *lptr; + int len; + + fptr = bptr = sptr = buf->buf; + lptr = fptr + buf->length; + while ((sptr = index0 (sptr, '?', (size_t) (lptr - sptr))) != NULL) { + if (*++sptr != '?') + continue; + switch (*++sptr) { + case '=': + c = '#'; + break; + case '(': + c = '['; + break; + case '/': + c = '\\'; + break; + case ')': + c = ']'; + break; + case '\'': + c = '^'; + break; + case '<': + c = '{'; + break; + case '!': + c = '|'; + break; + case '>': + c = '}'; + break; + case '-': + c = '~'; + break; + case '?': + sptr--; + continue; + default: + continue; + } + len = sptr - fptr - 2; + + /* BSD doc says bcopy () works right for overlapping strings. In ANSI + C, this will be memmove (). */ + if (bptr != fptr && len > 0) + bcopy ((char *) fptr, (char *) bptr, len); + + bptr += len; + *bptr++ = c; + fptr = ++sptr; + } + len = buf->length - (fptr - buf->buf); + if (bptr != fptr && len > 0) + bcopy ((char *) fptr, (char *) bptr, len); + buf->length -= fptr - bptr; + buf->buf[buf->length] = '\0'; + if (warn_trigraphs && fptr != bptr) + warning_with_line (0, "%lu trigraph(s) encountered", + (unsigned long) (fptr - bptr) / 2); +} + +/* Move all backslash-newline pairs out of embarrassing places. + Exchange all such pairs following BP + with any potentially-embarrassing characters that follow them. + Potentially-embarrassing characters are / and * + (because a backslash-newline inside a comment delimiter + would cause it not to be recognized). */ + +static void +newline_fix (bp) + U_CHAR *bp; +{ + register U_CHAR *p = bp; + + /* First count the backslash-newline pairs here. */ + + while (p[0] == '\\' && p[1] == '\n') + p += 2; + + /* What follows the backslash-newlines is not embarrassing. */ + + if (*p != '/' && *p != '*') + return; + + /* Copy all potentially embarrassing characters + that follow the backslash-newline pairs + down to where the pairs originally started. */ + + while (*p == '*' || *p == '/') + *bp++ = *p++; + + /* Now write the same number of pairs after the embarrassing chars. */ + while (bp < p) { + *bp++ = '\\'; + *bp++ = '\n'; + } +} + +/* Like newline_fix but for use within a directive-name. + Move any backslash-newlines up past any following symbol constituents. */ + +static void +name_newline_fix (bp) + U_CHAR *bp; +{ + register U_CHAR *p = bp; + + /* First count the backslash-newline pairs here. */ + while (p[0] == '\\' && p[1] == '\n') + p += 2; + + /* What follows the backslash-newlines is not embarrassing. */ + + if (!is_idchar[*p]) + return; + + /* Copy all potentially embarrassing characters + that follow the backslash-newline pairs + down to where the pairs originally started. */ + + while (is_idchar[*p]) + *bp++ = *p++; + + /* Now write the same number of pairs after the embarrassing chars. */ + while (bp < p) { + *bp++ = '\\'; + *bp++ = '\n'; + } +} + +/* Look for lint commands in comments. + + When we come in here, ibp points into a comment. Limit is as one expects. + scan within the comment -- it should start, after lwsp, with a lint command. + If so that command is returned as a (constant) string. + + Upon return, any arg will be pointed to with argstart and will be + arglen long. Note that we don't parse that arg since it will just + be printed out again. */ + +static char * +get_lintcmd (ibp, limit, argstart, arglen, cmdlen) + register U_CHAR *ibp; + register U_CHAR *limit; + U_CHAR **argstart; /* point to command arg */ + int *arglen, *cmdlen; /* how long they are */ +{ + HOST_WIDE_INT linsize; + register U_CHAR *numptr; /* temp for arg parsing */ + + *arglen = 0; + + SKIP_WHITE_SPACE (ibp); + + if (ibp >= limit) return NULL; + + linsize = limit - ibp; + + /* Oh, I wish C had lexical functions... hell, I'll just open-code the set */ + if ((linsize >= 10) && !bcmp (ibp, "NOTREACHED", 10)) { + *cmdlen = 10; + return "NOTREACHED"; + } + if ((linsize >= 8) && !bcmp (ibp, "ARGSUSED", 8)) { + *cmdlen = 8; + return "ARGSUSED"; + } + if ((linsize >= 11) && !bcmp (ibp, "LINTLIBRARY", 11)) { + *cmdlen = 11; + return "LINTLIBRARY"; + } + if ((linsize >= 7) && !bcmp (ibp, "VARARGS", 7)) { + *cmdlen = 7; + ibp += 7; linsize -= 7; + if ((linsize == 0) || ! ISDIGIT (*ibp)) return "VARARGS"; + + /* OK, read a number */ + for (numptr = *argstart = ibp; (numptr < limit) && ISDIGIT (*numptr); + numptr++); + *arglen = numptr - *argstart; + return "VARARGS"; + } + return NULL; +} + +/* + * The main loop of the program. + * + * Read characters from the input stack, transferring them to the + * output buffer OP. + * + * Macros are expanded and push levels on the input stack. + * At the end of such a level it is popped off and we keep reading. + * At the end of any other kind of level, we return. + * #-directives are handled, except within macros. + * + * If OUTPUT_MARKS is nonzero, keep Newline markers found in the input + * and insert them when appropriate. This is set while scanning macro + * arguments before substitution. It is zero when scanning for final output. + * There are three types of Newline markers: + * * Newline - follows a macro name that was not expanded + * because it appeared inside an expansion of the same macro. + * This marker prevents future expansion of that identifier. + * When the input is rescanned into the final output, these are deleted. + * These are also deleted by ## concatenation. + * * Newline Space (or Newline and any other whitespace character) + * stands for a place that tokens must be separated or whitespace + * is otherwise desirable, but where the ANSI standard specifies there + * is no whitespace. This marker turns into a Space (or whichever other + * whitespace char appears in the marker) in the final output, + * but it turns into nothing in an argument that is stringified with #. + * Such stringified arguments are the only place where the ANSI standard + * specifies with precision that whitespace may not appear. + * + * During this function, IP->bufp is kept cached in IBP for speed of access. + * Likewise, OP->bufp is kept in OBP. Before calling a subroutine + * IBP, IP and OBP must be copied back to memory. IP and IBP are + * copied back with the RECACHE macro. OBP must be copied back from OP->bufp + * explicitly, and before RECACHE, since RECACHE uses OBP. + */ + +static void +rescan (op, output_marks) + FILE_BUF *op; + int output_marks; +{ + /* Character being scanned in main loop. */ + register U_CHAR c; + + /* Length of pending accumulated identifier. */ + register int ident_length = 0; + + /* Hash code of pending accumulated identifier. */ + register int hash = 0; + + /* Current input level (&instack[indepth]). */ + FILE_BUF *ip; + + /* Pointer for scanning input. */ + register U_CHAR *ibp; + + /* Pointer to end of input. End of scan is controlled by LIMIT. */ + register U_CHAR *limit; + + /* Pointer for storing output. */ + register U_CHAR *obp; + + /* REDO_CHAR is nonzero if we are processing an identifier + after backing up over the terminating character. + Sometimes we process an identifier without backing up over + the terminating character, if the terminating character + is not special. Backing up is done so that the terminating character + will be dispatched on again once the identifier is dealt with. */ + int redo_char = 0; + + /* 1 if within an identifier inside of which a concatenation + marker (Newline -) has been seen. */ + int concatenated = 0; + + /* While scanning a comment or a string constant, + this records the line it started on, for error messages. */ + int start_line; + + /* Record position of last `real' newline. */ + U_CHAR *beg_of_line; + +/* Pop the innermost input stack level, assuming it is a macro expansion. */ + +#define POPMACRO \ +do { ip->macro->type = T_MACRO; \ + if (ip->free_ptr) free (ip->free_ptr); \ + --indepth; } while (0) + +/* Reload `rescan's local variables that describe the current + level of the input stack. */ + +#define RECACHE \ +do { ip = &instack[indepth]; \ + ibp = ip->bufp; \ + limit = ip->buf + ip->length; \ + op->bufp = obp; \ + check_expand (op, limit - ibp); \ + beg_of_line = 0; \ + obp = op->bufp; } while (0) + + if (no_output && instack[indepth].fname != 0) + skip_if_group (&instack[indepth], 1, NULL); + + obp = op->bufp; + RECACHE; + + beg_of_line = ibp; + + /* Our caller must always put a null after the end of + the input at each input stack level. */ + if (*limit != 0) + abort (); + + while (1) { + c = *ibp++; + *obp++ = c; + + switch (c) { + case '\\': + if (*ibp == '\n' && !ip->macro) { + /* At the top level, always merge lines ending with backslash-newline, + even in middle of identifier. But do not merge lines in a macro, + since backslash might be followed by a newline-space marker. */ + ++ibp; + ++ip->lineno; + --obp; /* remove backslash from obuf */ + break; + } + /* If ANSI, backslash is just another character outside a string. */ + if (!traditional) + goto randomchar; + /* Otherwise, backslash suppresses specialness of following char, + so copy it here to prevent the switch from seeing it. + But first get any pending identifier processed. */ + if (ident_length > 0) + goto specialchar; + if (ibp < limit) + *obp++ = *ibp++; + break; + + case '%': + if (ident_length || ip->macro || traditional) + goto randomchar; + while (*ibp == '\\' && ibp[1] == '\n') { + ibp += 2; + ++ip->lineno; + } + if (*ibp != ':') + break; + /* Treat this %: digraph as if it were #. */ + /* Fall through. */ + + case '#': + if (assertions_flag) { + if (ident_length) + goto specialchar; + /* Copy #foo (bar lose) without macro expansion. */ + obp[-1] = '#'; /* In case it was '%'. */ + SKIP_WHITE_SPACE (ibp); + while (is_idchar[*ibp]) + *obp++ = *ibp++; + SKIP_WHITE_SPACE (ibp); + if (*ibp == '(') { + ip->bufp = ibp; + skip_paren_group (ip); + bcopy ((char *) ibp, (char *) obp, ip->bufp - ibp); + obp += ip->bufp - ibp; + ibp = ip->bufp; + } + break; + } + + /* If this is expanding a macro definition, don't recognize + preprocessing directives. */ + if (ip->macro != 0) + goto randomchar; + /* If this is expand_into_temp_buffer, + don't recognize them either. Warn about them + only after an actual newline at this level, + not at the beginning of the input level. */ + if (! ip->fname) { + if (ip->buf != beg_of_line) + warning ("preprocessing directive not recognized within macro arg"); + goto randomchar; + } + if (ident_length) + goto specialchar; + + + /* # keyword: a # must be first nonblank char on the line */ + if (beg_of_line == 0) + goto randomchar; + { + U_CHAR *bp; + + /* Scan from start of line, skipping whitespace, comments + and backslash-newlines, and see if we reach this #. + If not, this # is not special. */ + bp = beg_of_line; + /* If -traditional, require # to be at beginning of line. */ + if (!traditional) { + while (1) { + if (is_hor_space[*bp]) + bp++; + else if (*bp == '\\' && bp[1] == '\n') + bp += 2; + else if (*bp == '/' && bp[1] == '*') { + bp += 2; + while (1) + { + if (*bp == '*') + { + if (bp[1] == '/') + { + bp += 2; + break; + } + } + else + { +#ifdef MULTIBYTE_CHARS + /* CYGNUS LOCAL chill */ + if (! chill) + /* END CYGNUS LOCAL chill */ + { + int length; + length = local_mblen (bp, limit - bp); + if (length > 1) + bp += (length - 1); + } +#endif + } + bp++; + } + } + /* There is no point in trying to deal with C++ // comments here, + because if there is one, then this # must be part of the + comment and we would never reach here. */ + else break; + } + if (c == '%') { + if (bp[0] != '%') + break; + while (bp[1] == '\\' && bp[2] == '\n') + bp += 2; + if (bp + 1 != ibp) + break; + /* %: appears at start of line; skip past the ':' too. */ + bp++; + ibp++; + } + } + if (bp + 1 != ibp) + goto randomchar; + } + + /* This # can start a directive. */ + + --obp; /* Don't copy the '#' */ + + ip->bufp = ibp; + op->bufp = obp; + if (! handle_directive (ip, op)) { +#ifdef USE_C_ALLOCA + alloca (0); +#endif + /* Not a known directive: treat it as ordinary text. + IP, OP, IBP, etc. have not been changed. */ + if (no_output && instack[indepth].fname) { + /* If not generating expanded output, + what we do with ordinary text is skip it. + Discard everything until next # directive. */ + skip_if_group (&instack[indepth], 1, 0); + RECACHE; + beg_of_line = ibp; + break; + } + *obp++ = '#'; /* Copy # (even if it was originally %:). */ + /* Don't expand an identifier that could be a macro directive. + (Section 3.8.3 of the ANSI C standard) */ + SKIP_WHITE_SPACE (ibp); + if (is_idstart[*ibp]) + { + *obp++ = *ibp++; + while (is_idchar[*ibp]) + *obp++ = *ibp++; + } + goto randomchar; + } +#ifdef USE_C_ALLOCA + alloca (0); +#endif + /* A # directive has been successfully processed. */ + /* If not generating expanded output, ignore everything until + next # directive. */ + if (no_output && instack[indepth].fname) + skip_if_group (&instack[indepth], 1, 0); + obp = op->bufp; + RECACHE; + beg_of_line = ibp; + break; + + case '\"': /* skip quoted string */ + case '\'': + /* A single quoted string is treated like a double -- some + programs (e.g., troff) are perverse this way */ + + /* Handle any pending identifier; + but the L in L'...' or L"..." is not an identifier. */ + if (ident_length) { + if (! (ident_length == 1 && hash == HASHSTEP (0, 'L'))) + goto specialchar; + ident_length = hash = 0; + } + + start_line = ip->lineno; + + /* Skip ahead to a matching quote. */ + + while (1) { + if (ibp >= limit) { + if (ip->macro != 0) { + /* try harder: this string crosses a macro expansion boundary. + This can happen naturally if -traditional. + Otherwise, only -D can make a macro with an unmatched quote. */ + POPMACRO; + RECACHE; + continue; + } + if (!traditional) { + error_with_line (line_for_error (start_line), + "unterminated string or character constant"); + if (multiline_string_line) { + error_with_line (multiline_string_line, + "possible real start of unterminated constant"); + multiline_string_line = 0; + } + } + break; + } + *obp++ = *ibp; + switch (*ibp++) { + case '\n': + ++ip->lineno; + ++op->lineno; + /* Traditionally, end of line ends a string constant with no error. + So exit the loop and record the new line. */ + if (traditional) { + beg_of_line = ibp; + goto while2end; + } + if (c == '\'') { + error_with_line (line_for_error (start_line), + "unterminated character constant"); + goto while2end; + } + if (multiline_string_line == 0) { + if (pedantic) + pedwarn_with_line (line_for_error (start_line), + "string constant runs past end of line"); + multiline_string_line = ip->lineno - 1; + } + break; + + case '\\': +/* CYGNUS LOCAL chill */ + if (chill) + break; +/* END CYGNUS LOCAL chill */ + if (*ibp == '\n') { + /* Backslash newline is replaced by nothing at all, but + keep the line counts correct. But if we are reading + from a macro, keep the backslash newline, since backslash + newlines have already been processed. */ + if (ip->macro) + *obp++ = '\n'; + else + --obp; + ++ibp; + ++ip->lineno; + } else { + /* ANSI stupidly requires that in \\ the second \ + is *not* prevented from combining with a newline. */ + if (!ip->macro) { + while (*ibp == '\\' && ibp[1] == '\n') { + ibp += 2; + ++ip->lineno; + } + } + *obp++ = *ibp++; + } + break; + + case '\"': + case '\'': + if (ibp[-1] == c) + goto while2end; + break; +/* CYGNUS LOCAL chill */ + case '^': + if (chill) + { + /* skip a control sequence in chill. This looks like + ^([b | B | d | D | h | H | o | O']digits) | ^^ */ + if (*ibp == '^') + { + *obp++=*ibp++; + break; + } + if (*ibp == '(') + { + /* skip till closing paran or eol */ + while (*ibp) + { + *obp++ = *ibp++; + if (*ibp == ')') + break; + if (*ibp == '\n' || *ibp == 0) + goto while2end; + } + } + } + break; +/* END CYGNUS LOCAL chill */ +#ifdef MULTIBYTE_CHARS + default: +/* CYGNUS LOCAL chill */ + if (! chill) +/* END CYGNUS LOCAL chill */ + { + int length; + --ibp; + length = local_mblen (ibp, limit - ibp); + if (length > 0) + { + --obp; + bcopy (ibp, obp, length); + obp += length; + ibp += length; + } + else + ++ibp; + } + break; +#endif + } + } + while2end: + break; + +/* CYGNUS LOCAL chill */ + case '-': + if (*ibp == '\\' && ibp[1] == '\n') + newline_fix (ibp); + + if (!(chill && *ibp == '-')) + goto randomchar; + if (ip->macro != 0) + goto randomchar; + if (ident_length) + goto specialchar; + + if (*ibp == '-') { + /* CHILL style comment... */ + start_line = ip->lineno; + + --ibp; /* Back over the dash */ + --obp; + + /* Comments are equivalent to spaces. */ + if (! put_out_comments) + *obp++ = ' '; + else { + /* must fake up a comment here */ + *obp++ = '-'; + *obp++ = '-'; + } + { + U_CHAR *before_bp = ibp+2; + + while (ibp < limit) { + if (*ibp++ == '\n') { + ibp--; + if (put_out_comments) { + bcopy (before_bp, obp, ibp - before_bp); + obp += ibp - before_bp; + } + break; + } + } + break; + } + } + break; +/* END CYGNUS LOCAL chill */ + + case '/': + if (ip->macro != 0) + goto randomchar; + if (*ibp == '\\' && ibp[1] == '\n') + newline_fix (ibp); + if (*ibp != '*' + && !(cplusplus_comments && *ibp == '/')) + goto randomchar; + if (ident_length) + goto specialchar; + + if (*ibp == '/') { + /* C++ style comment... */ + start_line = ip->lineno; + + /* Comments are equivalent to spaces. */ + if (! put_out_comments) + obp[-1] = ' '; + + { + U_CHAR *before_bp = ibp; + + while (++ibp < limit) { + if (*ibp == '\n') + { + if (put_out_comments) { + bcopy ((char *) before_bp, (char *) obp, ibp - before_bp); + obp += ibp - before_bp; + } + break; + } + if (*ibp == '\\') + { + if (ibp + 1 < limit && ibp[1] == '\n') + { + if (warn_comments) + warning ("multiline `//' comment"); + ++ip->lineno; + /* Copy the newline into the output buffer, in order to + avoid the pain of a #line every time a multiline comment + is seen. */ + if (!put_out_comments) + *obp++ = '\n'; + ++op->lineno; + ++ibp; + } + } + else + { +#ifdef MULTIBYTE_CHARS + /* CYGNUS LOCAL chill */ + if (! chill) + /* END CYGNUS LOCAL chill */ + { + int length; + length = local_mblen (ibp, limit - ibp); + if (length > 1) + ibp += (length - 1); + } +#endif + } + } + break; + } + } + + /* Ordinary C comment. Skip it, optionally copying it to output. */ + + start_line = ip->lineno; + + ++ibp; /* Skip the star. */ + + /* If this cpp is for lint, we peek inside the comments: */ + if (for_lint) { + U_CHAR *argbp; + int cmdlen, arglen; + char *lintcmd = get_lintcmd (ibp, limit, &argbp, &arglen, &cmdlen); + + if (lintcmd != NULL) { + op->bufp = obp; + check_expand (op, cmdlen + arglen + 14); + obp = op->bufp; + /* I believe it is always safe to emit this newline: */ + obp[-1] = '\n'; + bcopy ("#pragma lint ", (char *) obp, 13); + obp += 13; + bcopy (lintcmd, (char *) obp, cmdlen); + obp += cmdlen; + + if (arglen != 0) { + *(obp++) = ' '; + bcopy (argbp, (char *) obp, arglen); + obp += arglen; + } + + /* OK, now bring us back to the state we were in before we entered + this branch. We need #line because the #pragma's newline always + messes up the line count. */ + op->bufp = obp; + output_line_directive (ip, op, 0, same_file); + check_expand (op, limit - ibp + 2); + obp = op->bufp; + *(obp++) = '/'; + } + } + + /* Comments are equivalent to spaces. + Note that we already output the slash; we might not want it. + For -traditional, a comment is equivalent to nothing. */ + if (! put_out_comments) { + if (traditional) + obp--; + else + obp[-1] = ' '; + } + else + *obp++ = '*'; + + { + U_CHAR *before_bp = ibp; + + for (;;) { + switch (*ibp++) { + case '*': + if (ibp[-2] == '/' && warn_comments) + warning ("`/*' within comment"); + if (*ibp == '\\' && ibp[1] == '\n') + newline_fix (ibp); + if (*ibp == '/') + goto comment_end; + break; + + case '\n': + ++ip->lineno; + /* Copy the newline into the output buffer, in order to + avoid the pain of a #line every time a multiline comment + is seen. */ + if (!put_out_comments) + *obp++ = '\n'; + ++op->lineno; + break; + + case 0: + if (limit < ibp) { + error_with_line (line_for_error (start_line), + "unterminated comment"); + goto limit_reached; + } + break; +#ifdef MULTIBYTE_CHARS + default: + /* CYGNUS LOCAL chill */ + if (! chill) + /* END CYGNUS LOCAL chill */ + { + int length; + length = local_mblen (ibp, limit - ibp); + if (length > 1) + ibp += (length - 1); + } + break; +#endif + } + } + comment_end: + + ibp++; + if (put_out_comments) { + bcopy ((char *) before_bp, (char *) obp, ibp - before_bp); + obp += ibp - before_bp; + } + } + break; + + case '$': + if (! is_idchar['$']) + goto randomchar; + if (pedantic) + pedwarn ("`$' in identifier"); + goto letter; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + /* If digit is not part of identifier, it starts a number, + which means that following letters are not an identifier. + "0x5" does not refer to an identifier "x5". + So copy all alphanumerics that follow without accumulating + as an identifier. Periods also, for sake of "3.e7". */ + + if (ident_length == 0) { + for (;;) { + if (!ip->macro) { + while (ibp[0] == '\\' && ibp[1] == '\n') { + ++ip->lineno; + ibp += 2; + } + } + c = *ibp++; + if (!is_idchar[c] && c != '.') { + --ibp; + break; + } + *obp++ = c; + /* A sign can be part of a preprocessing number + if it follows an `e' or `p'. */ + if (c == 'e' || c == 'E' || c == 'p' || c == 'P') { + if (!ip->macro) { + while (ibp[0] == '\\' && ibp[1] == '\n') { + ++ip->lineno; + ibp += 2; + } + } + if (*ibp == '+' || *ibp == '-') { + *obp++ = *ibp++; + /* But traditional C does not let the token go past the sign, + and C89 does not allow `p'. */ + if (traditional || (c89 && (c == 'p' || c == 'P'))) + break; + } + } + } + break; + } + /* fall through */ + + case '_': + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': + case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': + case 's': case 't': case 'u': case 'v': case 'w': case 'x': + case 'y': case 'z': + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': + case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': + case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': + case 'Y': case 'Z': +/* CYGNUS LOCAL chill */ + if (chill && *ibp == '\'' && + (c == 'd' || c == 'D' || c == 'o' || c == 'O' || + c == 'h' || c == 'H' || c == 'b' || c == 'B')) + { + /* here we skip till end of literal. The reason is, that this + literal may not be terminated by another "'", and therefor + no macro evaluation is done till end of line */ + /* put the "'" */ + *obp++ = *ibp++; + while (*ibp == '_' || (*ibp >= '0' && *ibp <= '9') || + (*ibp >= 'A' && *ibp <= 'F') || (*ibp >= 'a' && *ibp <= 'f')) + *obp++ = *ibp++; + + /* if we have another "'" at the end, put this to obp and + continue */ + if (*ibp == '\'') + *obp++ = *ibp++; + break; + } + /* fall through */ +/* END CYGNUS LOCAL chill */ + letter: + ident_length++; + /* Compute step of hash function, to avoid a proc call on every token */ + hash = HASHSTEP (hash, c); + break; + + case '\n': + if (ip->fname == 0 && *ibp == '-') { + /* Newline - inhibits expansion of preceding token. + If expanding a macro arg, we keep the newline -. + In final output, it is deleted. + We recognize Newline - in macro bodies and macro args. */ + if (! concatenated) { + ident_length = 0; + hash = 0; + } + ibp++; + if (!output_marks) { + obp--; + } else { + /* If expanding a macro arg, keep the newline -. */ + *obp++ = '-'; + } + break; + } + + /* If reprocessing a macro expansion, newline is a special marker. */ + else if (ip->macro != 0) { + /* Newline White is a "funny space" to separate tokens that are + supposed to be separate but without space between. + Here White means any whitespace character. + Newline - marks a recursive macro use that is not + supposed to be expandable. */ + + if (is_space[*ibp]) { + /* Newline Space does not prevent expansion of preceding token + so expand the preceding token and then come back. */ + if (ident_length > 0) + goto specialchar; + + /* If generating final output, newline space makes a space. */ + if (!output_marks) { + obp[-1] = *ibp++; + /* And Newline Newline makes a newline, so count it. */ + if (obp[-1] == '\n') + op->lineno++; + } else { + /* If expanding a macro arg, keep the newline space. + If the arg gets stringified, newline space makes nothing. */ + *obp++ = *ibp++; + } + } else abort (); /* Newline followed by something random? */ + break; + } + + /* If there is a pending identifier, handle it and come back here. */ + if (ident_length > 0) + goto specialchar; + + beg_of_line = ibp; + + /* Update the line counts and output a #line if necessary. */ + ++ip->lineno; + ++op->lineno; + if (ip->lineno != op->lineno) { + op->bufp = obp; + output_line_directive (ip, op, 1, same_file); + check_expand (op, limit - ibp); + obp = op->bufp; + } + break; + + /* Come here either after (1) a null character that is part of the input + or (2) at the end of the input, because there is a null there. */ + case 0: + if (ibp <= limit) + /* Our input really contains a null character. */ + goto randomchar; + + limit_reached: + /* At end of a macro-expansion level, pop it and read next level. */ + if (ip->macro != 0) { + obp--; + ibp--; + /* If traditional, and we have an identifier that ends here, + process it now, so we get the right error for recursion. */ + if (traditional && ident_length + && ! is_idchar[*instack[indepth - 1].bufp]) { + redo_char = 1; + goto randomchar; + } + POPMACRO; + RECACHE; + break; + } + + /* If we don't have a pending identifier, + return at end of input. */ + if (ident_length == 0) { + obp--; + ibp--; + op->bufp = obp; + ip->bufp = ibp; + goto ending; + } + + /* If we do have a pending identifier, just consider this null + a special character and arrange to dispatch on it again. + The second time, IDENT_LENGTH will be zero so we will return. */ + + /* Fall through */ + +specialchar: + + /* Handle the case of a character such as /, ', " or null + seen following an identifier. Back over it so that + after the identifier is processed the special char + will be dispatched on again. */ + + ibp--; + obp--; + redo_char = 1; + + default: + +randomchar: + + if (ident_length > 0) { + register HASHNODE *hp; + + /* We have just seen an identifier end. If it's a macro, expand it. + + IDENT_LENGTH is the length of the identifier + and HASH is its hash code. + + The identifier has already been copied to the output, + so if it is a macro we must remove it. + + If REDO_CHAR is 0, the char that terminated the identifier + has been skipped in the output and the input. + OBP-IDENT_LENGTH-1 points to the identifier. + If the identifier is a macro, we must back over the terminator. + + If REDO_CHAR is 1, the terminating char has already been + backed over. OBP-IDENT_LENGTH points to the identifier. */ + + if (!pcp_outfile || pcp_inside_if) { + for (hp = hashtab[MAKE_POS (hash) % HASHSIZE]; hp != NULL; + hp = hp->next) { + + if (hp->length == ident_length) { + int obufp_before_macroname; + int op_lineno_before_macroname; + register int i = ident_length; + register U_CHAR *p = hp->name; + register U_CHAR *q = obp - i; + int disabled; + + if (! redo_char) + q--; + + do { /* All this to avoid a strncmp () */ + if (*p++ != *q++) + goto hashcollision; + } while (--i); + + /* We found a use of a macro name. + see if the context shows it is a macro call. */ + + /* Back up over terminating character if not already done. */ + if (! redo_char) { + ibp--; + obp--; + } + + /* Save this as a displacement from the beginning of the output + buffer. We can not save this as a position in the output + buffer, because it may get realloc'ed by RECACHE. */ + obufp_before_macroname = (obp - op->buf) - ident_length; + op_lineno_before_macroname = op->lineno; + + if (hp->type == T_PCSTRING) { + pcstring_used (hp); /* Mark the definition of this key + as needed, ensuring that it + will be output. */ + break; /* Exit loop, since the key cannot have a + definition any longer. */ + } + + /* Record whether the macro is disabled. */ + disabled = hp->type == T_DISABLED; + + /* This looks like a macro ref, but if the macro was disabled, + just copy its name and put in a marker if requested. */ + + if (disabled) { +#if 0 + /* This error check caught useful cases such as + #define foo(x,y) bar (x (y,0), y) + foo (foo, baz) */ + if (traditional) + error ("recursive use of macro `%s'", hp->name); +#endif + + if (output_marks) { + check_expand (op, limit - ibp + 2); + *obp++ = '\n'; + *obp++ = '-'; + } + break; + } + + /* If macro wants an arglist, verify that a '(' follows. + first skip all whitespace, copying it to the output + after the macro name. Then, if there is no '(', + decide this is not a macro call and leave things that way. */ + if ((hp->type == T_MACRO || hp->type == T_DISABLED) + && hp->value.defn->nargs >= 0) + { + U_CHAR *old_ibp = ibp; + U_CHAR *old_obp = obp; + int old_iln = ip->lineno; + int old_oln = op->lineno; + + while (1) { + /* Scan forward over whitespace, copying it to the output. */ + if (ibp == limit && ip->macro != 0) { + POPMACRO; + RECACHE; + old_ibp = ibp; + old_obp = obp; + old_iln = ip->lineno; + old_oln = op->lineno; + } + else if (is_space[*ibp]) { + *obp++ = *ibp++; + if (ibp[-1] == '\n') { + if (ip->macro == 0) { + /* Newline in a file. Count it. */ + ++ip->lineno; + ++op->lineno; + } else if (!output_marks) { + /* A newline mark, and we don't want marks + in the output. If it is newline-hyphen, + discard it entirely. Otherwise, it is + newline-whitechar, so keep the whitechar. */ + obp--; + if (*ibp == '-') + ibp++; + else { + if (*ibp == '\n') + ++op->lineno; + *obp++ = *ibp++; + } + } else { + /* A newline mark; copy both chars to the output. */ + *obp++ = *ibp++; + } + } + } + else if (ip->macro) + break; + else if (*ibp == '/') { + /* If a comment, copy it unchanged or discard it. */ + if (ibp[1] == '\\' && ibp[2] == '\n') + newline_fix (ibp + 1); + if (ibp[1] == '*') { + if (put_out_comments) { + *obp++ = '/'; + *obp++ = '*'; + } else if (! traditional) { + *obp++ = ' '; + } + for (ibp += 2; ibp < limit; ibp++) { + /* We need not worry about newline-marks, + since they are never found in comments. */ + if (ibp[0] == '*') { + if (ibp[1] == '\\' && ibp[2] == '\n') + newline_fix (ibp + 1); + if (ibp[1] == '/') { + ibp += 2; + if (put_out_comments) { + *obp++ = '*'; + *obp++ = '/'; + } + break; + } + } + else if (*ibp == '\n') { + /* Newline in a file. Count it. */ + ++ip->lineno; + ++op->lineno; + } + else + { +#ifdef MULTIBYTE_CHARS + /* CYGNUS LOCAL chill */ + if (! chill) + /* END CYGNUS LOCAL chill */ + { + int length; + length = local_mblen (ibp, limit - ibp); + if (length > 1) + { + if (put_out_comments) + { + bcopy (ibp, obp, length - 1); + obp += length - 1; + } + ibp += (length - 1); + } + } +#endif + } + if (put_out_comments) + *obp++ = *ibp; + } + } else if (ibp[1] == '/' && cplusplus_comments) { + if (put_out_comments) { + *obp++ = '/'; + *obp++ = '/'; + } else if (! traditional) { + *obp++ = ' '; + } + for (ibp += 2; ; ibp++) + { + if (*ibp == '\n') + break; + if (*ibp == '\\' && ibp[1] == '\n') + { + if (put_out_comments) + *obp++ = *ibp++; + } + else + { +#ifdef MULTIBYTE_CHARS + /* CYGNUS LOCAL chill */ + if (! chill) + /* END CYGNUS LOCAL chill */ + { + int length; + length = local_mblen (ibp, limit - ibp); + if (length > 1) + { + if (put_out_comments) + { + bcopy (ibp, obp, length - 1); + obp += length - 1; + } + ibp += (length - 1); + } + } +#endif + } + if (put_out_comments) + *obp++ = *ibp; + } + } else + break; + } + else if (ibp[0] == '\\' && ibp[1] == '\n') { + ibp += 2; + ++ip->lineno; + } + else break; + } + if (*ibp != '(') { + /* It isn't a macro call. + Put back the space that we just skipped. */ + ibp = old_ibp; + obp = old_obp; + ip->lineno = old_iln; + op->lineno = old_oln; + /* Exit the for loop. */ + break; + } + } + + /* This is now known to be a macro call. + Discard the macro name from the output, + along with any following whitespace just copied, + but preserve newlines if not outputting marks since this + is more likely to do the right thing with line numbers. */ + obp = op->buf + obufp_before_macroname; + if (output_marks) + op->lineno = op_lineno_before_macroname; + else { + int newlines = op->lineno - op_lineno_before_macroname; + while (0 < newlines--) + *obp++ = '\n'; + } + + /* Prevent accidental token-pasting with a character + before the macro call. */ + if (!traditional && obp != op->buf) { + switch (obp[-1]) { + case '!': case '%': case '&': case '*': + case '+': case '-': case '.': case '/': + case ':': case '<': case '=': case '>': + case '^': case '|': + /* If we are expanding a macro arg, make a newline marker + to separate the tokens. If we are making real output, + a plain space will do. */ + if (output_marks) + *obp++ = '\n'; + *obp++ = ' '; + } + } + + /* Expand the macro, reading arguments as needed, + and push the expansion on the input stack. */ + ip->bufp = ibp; + op->bufp = obp; + macroexpand (hp, op); + + /* Reexamine input stack, since macroexpand has pushed + a new level on it. */ + obp = op->bufp; + RECACHE; + break; + } +hashcollision: + ; + } /* End hash-table-search loop */ + } + ident_length = hash = 0; /* Stop collecting identifier */ + redo_char = 0; + concatenated = 0; + } /* End if (ident_length > 0) */ + } /* End switch */ + } /* End per-char loop */ + + /* Come here to return -- but first give an error message + if there was an unterminated successful conditional. */ + ending: + if (if_stack != ip->if_stack) + { + char *str; + + switch (if_stack->type) + { + case T_IF: + str = "if"; + break; + case T_IFDEF: + str = "ifdef"; + break; + case T_IFNDEF: + str = "ifndef"; + break; + case T_ELSE: + str = "else"; + break; + case T_ELIF: + str = "elif"; + break; + default: + abort (); + } + + error_with_line (line_for_error (if_stack->lineno), + "unterminated `#%s' conditional", str); + } + if_stack = ip->if_stack; +} + +/* + * Rescan a string into a temporary buffer and return the result + * as a FILE_BUF. Note this function returns a struct, not a pointer. + * + * OUTPUT_MARKS nonzero means keep Newline markers found in the input + * and insert such markers when appropriate. See `rescan' for details. + * OUTPUT_MARKS is 1 for macroexpanding a macro argument separately + * before substitution; it is 0 for other uses. + */ +static FILE_BUF +expand_to_temp_buffer (buf, limit, output_marks, assertions) + U_CHAR *buf, *limit; + int output_marks, assertions; +{ + register FILE_BUF *ip; + FILE_BUF obuf; + int length = limit - buf; + U_CHAR *buf1; + int odepth = indepth; + int save_assertions_flag = assertions_flag; + + assertions_flag = assertions; + + if (length < 0) + abort (); + + /* Set up the input on the input stack. */ + + buf1 = (U_CHAR *) alloca (length + 1); + { + register U_CHAR *p1 = buf; + register U_CHAR *p2 = buf1; + + while (p1 != limit) + *p2++ = *p1++; + } + buf1[length] = 0; + + /* Set up to receive the output. */ + + obuf.length = length * 2 + 100; /* Usually enough. Why be stingy? */ + obuf.bufp = obuf.buf = (U_CHAR *) xmalloc (obuf.length); + obuf.nominal_fname = 0; + obuf.inc = 0; + obuf.dir = 0; + obuf.fname = 0; + obuf.macro = 0; + obuf.if_stack = 0; + obuf.free_ptr = 0; + obuf.system_header_p = 0; + + CHECK_DEPTH ({return obuf;}); + + ++indepth; + + ip = &instack[indepth]; + ip->fname = 0; + ip->nominal_fname = 0; + ip->nominal_fname_len = 0; + ip->inc = 0; + ip->system_header_p = 0; + ip->macro = 0; + ip->free_ptr = 0; + ip->length = length; + ip->buf = ip->bufp = buf1; + ip->if_stack = if_stack; + + ip->lineno = obuf.lineno = 1; + + /* Scan the input, create the output. */ + rescan (&obuf, output_marks); + + /* Pop input stack to original state. */ + --indepth; + + if (indepth != odepth) + abort (); + + /* Record the output. */ + obuf.length = obuf.bufp - obuf.buf; + + assertions_flag = save_assertions_flag; + return obuf; +} + +/* + * Process a # directive. Expects IP->bufp to point after the '#', as in + * `#define foo bar'. Passes to the directive handler + * (do_define, do_include, etc.): the addresses of the 1st and + * last chars of the directive (starting immediately after the # + * keyword), plus op and the keyword table pointer. If the directive + * contains comments it is copied into a temporary buffer sans comments + * and the temporary buffer is passed to the directive handler instead. + * Likewise for backslash-newlines. + * + * Returns nonzero if this was a known # directive. + * Otherwise, returns zero, without advancing the input pointer. + */ + +static int +handle_directive (ip, op) + FILE_BUF *ip, *op; +{ + register U_CHAR *bp, *cp; + register struct directive *kt; + register int ident_length; + U_CHAR *resume_p; + + /* Nonzero means we must copy the entire directive + to get rid of comments or backslash-newlines. */ + int copy_directive = 0; + + U_CHAR *ident, *after_ident; + + bp = ip->bufp; + + /* Record where the directive started. do_xifdef needs this. */ + directive_start = bp - 1; + + ignore_escape_flag = 1; + + /* Skip whitespace and \-newline. */ + while (1) { + if (is_hor_space[*bp]) { + if (*bp != ' ' && *bp != '\t' && pedantic) + pedwarn ("%s in preprocessing directive", char_name[*bp]); + bp++; + } else if (*bp == '/') { + if (bp[1] == '\\' && bp[2] == '\n') + newline_fix (bp + 1); + if (! (bp[1] == '*' || (cplusplus_comments && bp[1] == '/'))) + break; + ip->bufp = bp + 2; + skip_to_end_of_comment (ip, &ip->lineno, 0); + bp = ip->bufp; + } else if (*bp == '\\' && bp[1] == '\n') { + bp += 2; ip->lineno++; + } else break; + } + + /* Now find end of directive name. + If we encounter a backslash-newline, exchange it with any following + symbol-constituents so that we end up with a contiguous name. */ + + cp = bp; + while (1) { + if (is_idchar[*cp]) + cp++; + else { + if (*cp == '\\' && cp[1] == '\n') + name_newline_fix (cp); + if (is_idchar[*cp]) + cp++; + else break; + } + } + ident_length = cp - bp; + ident = bp; + after_ident = cp; + + /* A line of just `#' becomes blank. */ + + if (ident_length == 0 && *after_ident == '\n') { + ip->bufp = after_ident; + return 1; + } + + if (ident_length == 0 || !is_idstart[*ident]) { + U_CHAR *p = ident; + while (is_idchar[*p]) { + if (*p < '0' || *p > '9') + break; + p++; + } + /* Handle # followed by a line number. */ + if (p != ident && !is_idchar[*p]) { + static struct directive line_directive_table[] = { + { 4, do_line, "line", T_LINE}, + }; + if (pedantic) + pedwarn ("`#' followed by integer"); + after_ident = ident; + kt = line_directive_table; + ignore_escape_flag = 0; + goto old_linenum; + } + + /* Avoid error for `###' and similar cases unless -pedantic. */ + if (p == ident) { + while (*p == '#' || is_hor_space[*p]) p++; + if (*p == '\n') { + if (pedantic && !lang_asm) + warning ("invalid preprocessing directive"); + return 0; + } + } + + if (!lang_asm) + error ("invalid preprocessing directive name"); + + return 0; + } + + /* + * Decode the keyword and call the appropriate expansion + * routine, after moving the input pointer up to the next line. + */ + for (kt = directive_table; kt->length > 0; kt++) { + if (kt->length == ident_length && !bcmp (kt->name, ident, ident_length)) { + register U_CHAR *buf; + register U_CHAR *limit; + int unterminated; + int junk; + int *already_output; + + /* Nonzero means do not delete comments within the directive. + #define needs this when -traditional. */ + int keep_comments; + + old_linenum: + + limit = ip->buf + ip->length; + unterminated = 0; + already_output = 0; + keep_comments = traditional && kt->type == T_DEFINE; + /* #import is defined only in Objective C, or when on the NeXT. */ + if (kt->type == T_IMPORT + && !(objc || lookup ((U_CHAR *) "__NeXT__", -1, -1))) + break; + + /* Find the end of this directive (first newline not backslashed + and not in a string or comment). + Set COPY_DIRECTIVE if the directive must be copied + (it contains a backslash-newline or a comment). */ + + buf = bp = after_ident; + while (bp < limit) { + register U_CHAR c = *bp++; + switch (c) { + case '\\': + if (bp < limit) { + if (*bp == '\n') { + ip->lineno++; + copy_directive = 1; + bp++; + } else if (traditional) + bp++; + } + break; + + case '"': + /* "..." is special for #include. */ + if (IS_INCLUDE_DIRECTIVE_TYPE (kt->type)) { + while (bp < limit && *bp != '\n') { + if (*bp == '"') { + bp++; + break; + } + if (*bp == '\\' && bp[1] == '\n') { + ip->lineno++; + copy_directive = 1; + bp++; + } + bp++; + } + break; + } + /* Fall through. */ + case '\'': + bp = skip_quoted_string (bp - 1, limit, ip->lineno, &ip->lineno, ©_directive, &unterminated); + /* Don't bother calling the directive if we already got an error + message due to unterminated string. Skip everything and pretend + we called the directive. */ + if (unterminated) { + if (traditional) { + /* Traditional preprocessing permits unterminated strings. */ + ip->bufp = bp; + goto endloop1; + } + ip->bufp = bp; + return 1; + } + break; + + /* <...> is special for #include. */ + case '<': + if (! IS_INCLUDE_DIRECTIVE_TYPE (kt->type)) + break; + while (bp < limit && *bp != '>' && *bp != '\n') { + if (*bp == '\\' && bp[1] == '\n') { + ip->lineno++; + copy_directive = 1; + bp++; + } + bp++; + } + break; + + case '/': + if (*bp == '\\' && bp[1] == '\n') + newline_fix (bp); + if (*bp == '*' + || (cplusplus_comments && *bp == '/')) { + U_CHAR *obp = bp - 1; + ip->bufp = bp + 1; + skip_to_end_of_comment (ip, &ip->lineno, 0); + bp = ip->bufp; + /* No need to copy the directive because of a comment at the end; + just don't include the comment in the directive. */ + if (!put_out_comments) { + U_CHAR *p; + for (p = bp; *p == ' ' || *p == '\t'; p++) + continue; + if (*p == '\n') { + bp = obp; + goto endloop1; + } + } + /* Don't remove the comments if -traditional. */ + if (! keep_comments) + copy_directive++; + } + break; + + case '\f': + case '\r': + case '\v': + if (pedantic) + pedwarn ("%s in preprocessing directive", char_name[c]); + break; + + case '\n': + --bp; /* Point to the newline */ + ip->bufp = bp; + goto endloop1; + } + } + ip->bufp = bp; + + endloop1: + resume_p = ip->bufp; + /* BP is the end of the directive. + RESUME_P is the next interesting data after the directive. + A comment may come between. */ + + /* If a directive should be copied through, and -C was given, + pass it through before removing comments. */ + if (!no_output && put_out_comments + && (kt->type == T_DEFINE ? dump_macros == dump_definitions + : IS_INCLUDE_DIRECTIVE_TYPE (kt->type) ? dump_includes + : kt->type == T_PRAGMA)) { + int len; + + /* Output directive name. */ + check_expand (op, kt->length + 2); + /* Make sure # is at the start of a line */ + if (op->bufp > op->buf && op->bufp[-1] != '\n') { + op->lineno++; + *op->bufp++ = '\n'; + } + *op->bufp++ = '#'; + bcopy (kt->name, op->bufp, kt->length); + op->bufp += kt->length; + + /* Output arguments. */ + len = (bp - buf); + check_expand (op, len); + bcopy (buf, (char *) op->bufp, len); + op->bufp += len; + /* Take account of any (escaped) newlines just output. */ + while (--len >= 0) + if (buf[len] == '\n') + op->lineno++; + + already_output = &junk; + } /* Don't we need a newline or #line? */ + + if (copy_directive) { + register U_CHAR *xp = buf; + /* Need to copy entire directive into temp buffer before dispatching */ + + cp = (U_CHAR *) alloca (bp - buf + 5); /* room for directive plus + some slop */ + buf = cp; + + /* Copy to the new buffer, deleting comments + and backslash-newlines (and whitespace surrounding the latter). */ + + while (xp < bp) { + register U_CHAR c = *xp++; + *cp++ = c; + + switch (c) { + case '\n': + abort (); /* A bare newline should never part of the line. */ + break; + + /* <...> is special for #include. */ + case '<': + if (! IS_INCLUDE_DIRECTIVE_TYPE (kt->type)) + break; + while (xp < bp && c != '>') { + c = *xp++; + if (c == '\\' && xp < bp && *xp == '\n') + xp++; + else + *cp++ = c; + } + break; + + case '\\': + if (*xp == '\n') { + xp++; + cp--; + if (cp != buf && is_hor_space[cp[-1]]) { + while (cp - 1 != buf && is_hor_space[cp[-2]]) + cp--; + SKIP_WHITE_SPACE (xp); + } else if (is_hor_space[*xp]) { + *cp++ = *xp++; + SKIP_WHITE_SPACE (xp); + } + } else if (traditional && xp < bp) { + *cp++ = *xp++; + } + break; + + case '\'': + case '\"': + { + register U_CHAR *bp1 + = skip_quoted_string (xp - 1, bp, ip->lineno, + NULL_PTR, NULL_PTR, NULL_PTR); + while (xp != bp1) + *cp++ = *xp++; + } + break; + + case '/': + if (*xp == '*' + || (cplusplus_comments && *xp == '/')) { + ip->bufp = xp + 1; + /* If we already copied the directive through, + already_output != 0 prevents outputting comment now. */ + skip_to_end_of_comment (ip, already_output, 0); + if (keep_comments) + while (xp != ip->bufp) + *cp++ = *xp++; + /* Delete or replace the slash. */ + else if (traditional) + cp--; + else + cp[-1] = ' '; + xp = ip->bufp; + } + } + } + + /* Null-terminate the copy. */ + + *cp = 0; + } else + cp = bp; + + ip->bufp = resume_p; + + /* Some directives should be written out for cc1 to process, + just as if they were not defined. And sometimes we're copying + directives through. */ + + if (!no_output && already_output == 0 + && (kt->type == T_DEFINE ? (int) dump_names <= (int) dump_macros + : IS_INCLUDE_DIRECTIVE_TYPE (kt->type) ? dump_includes + : kt->type == T_PRAGMA)) { + int len; + + /* Output directive name. */ + check_expand (op, kt->length + 1); + *op->bufp++ = '#'; + bcopy (kt->name, (char *) op->bufp, kt->length); + op->bufp += kt->length; + + if (kt->type == T_DEFINE && dump_macros == dump_names) { + /* Output `#define name' only. */ + U_CHAR *xp = buf; + U_CHAR *yp; + SKIP_WHITE_SPACE (xp); + yp = xp; + while (is_idchar[*xp]) xp++; + len = (xp - yp); + check_expand (op, len + 1); + *op->bufp++ = ' '; + bcopy (yp, (char *) op->bufp, len); + } else { + /* Output entire directive. */ + len = (cp - buf); + check_expand (op, len); + bcopy (buf, (char *) op->bufp, len); + } + op->bufp += len; + } /* Don't we need a newline or #line? */ + + /* Call the appropriate directive handler. buf now points to + either the appropriate place in the input buffer, or to + the temp buffer if it was necessary to make one. cp + points to the first char after the contents of the (possibly + copied) directive, in either case. */ + (*kt->func) (buf, cp, op, kt); + check_expand (op, ip->length - (ip->bufp - ip->buf)); + + return 1; + } + } + + /* It is deliberate that we don't warn about undefined directives. + That is the responsibility of cc1. */ + return 0; +} + +static struct tm * +timestamp () +{ + static struct tm *timebuf; + if (!timebuf) { + time_t t = time ((time_t *) 0); + timebuf = localtime (&t); + } + return timebuf; +} + +static char *monthnames[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + }; + +/* + * expand things like __FILE__. Place the expansion into the output + * buffer *without* rescanning. + */ + +static void +special_symbol (hp, op) + HASHNODE *hp; + FILE_BUF *op; +{ + char *buf; + int i, len; + int true_indepth; + FILE_BUF *ip = NULL; + struct tm *timebuf; + + int paren = 0; /* For special `defined' keyword */ + + if (pcp_outfile && pcp_inside_if + && hp->type != T_SPEC_DEFINED && hp->type != T_CONST) + error ("Predefined macro `%s' used inside `#if' during precompilation", + hp->name); + + for (i = indepth; i >= 0; i--) + if (instack[i].fname != NULL) { + ip = &instack[i]; + break; + } + if (ip == NULL) { + error ("cccp error: not in any file?!"); + return; /* the show must go on */ + } + + switch (hp->type) { + case T_FILE: + case T_BASE_FILE: + { + FILE_BUF *p = hp->type == T_FILE ? ip : &instack[0]; + char *string = p->nominal_fname; + + if (string) + { + size_t string_len = p->nominal_fname_len; + buf = (char *) alloca (3 + 4 * string_len); + quote_string (buf, string, string_len); + } + else + buf = "\"\""; + + break; + } + + case T_INCLUDE_LEVEL: + true_indepth = 0; + for (i = indepth; i >= 0; i--) + if (instack[i].fname != NULL) + true_indepth++; + + buf = (char *) alloca (8); /* Eight bytes ought to be more than enough */ + sprintf (buf, "%d", true_indepth - 1); + break; + + case T_VERSION: + buf = (char *) alloca (3 + strlen (version_string)); + sprintf (buf, "\"%s\"", version_string); + break; + +#ifndef NO_BUILTIN_SIZE_TYPE + case T_SIZE_TYPE: + buf = SIZE_TYPE; + break; +#endif + +#ifndef NO_BUILTIN_PTRDIFF_TYPE + case T_PTRDIFF_TYPE: + buf = PTRDIFF_TYPE; + break; +#endif + +/* CYGNUS LOCAL vmakarov */ +#ifndef NO_BUILTIN_WCHAR_TYPE +/* END CYGNUS LOCAL */ + case T_WCHAR_TYPE: + buf = wchar_type; + break; +/* CYGNUS LOCAL vmakarov */ +#endif +/* END CYGNUS LOCAL */ + + case T_USER_LABEL_PREFIX_TYPE: + buf = user_label_prefix; + break; + + case T_REGISTER_PREFIX_TYPE: + buf = REGISTER_PREFIX; + break; + + case T_IMMEDIATE_PREFIX_TYPE: + buf = IMMEDIATE_PREFIX; + break; + + case T_CONST: + buf = hp->value.cpval; +#ifdef STDC_0_IN_SYSTEM_HEADERS + if (ip->system_header_p + && hp->length == 8 && bcmp (hp->name, "__STDC__", 8) == 0 + && !lookup ((U_CHAR *) "__STRICT_ANSI__", -1, -1)) + buf = "0"; +#endif + if (pcp_inside_if && pcp_outfile) + /* Output a precondition for this macro use */ + fprintf (pcp_outfile, "#define %s %s\n", hp->name, buf); + break; + + case T_SPECLINE: + buf = (char *) alloca (10); + sprintf (buf, "%d", ip->lineno); + break; + + case T_DATE: + case T_TIME: + buf = (char *) alloca (20); + timebuf = timestamp (); + if (hp->type == T_DATE) + sprintf (buf, "\"%s %2d %4d\"", monthnames[timebuf->tm_mon], + timebuf->tm_mday, timebuf->tm_year + 1900); + else + sprintf (buf, "\"%02d:%02d:%02d\"", timebuf->tm_hour, timebuf->tm_min, + timebuf->tm_sec); + break; + + case T_SPEC_DEFINED: + buf = " 0 "; /* Assume symbol is not defined */ + ip = &instack[indepth]; + SKIP_WHITE_SPACE (ip->bufp); + if (*ip->bufp == '(') { + paren++; + ip->bufp++; /* Skip over the paren */ + SKIP_WHITE_SPACE (ip->bufp); + } + + if (!is_idstart[*ip->bufp]) + goto oops; + if (ip->bufp[0] == 'L' && (ip->bufp[1] == '\'' || ip->bufp[1] == '"')) + goto oops; + if ((hp = lookup (ip->bufp, -1, -1))) { + if (pcp_outfile && pcp_inside_if + && (hp->type == T_CONST + || (hp->type == T_MACRO && hp->value.defn->predefined))) + /* Output a precondition for this macro use. */ + fprintf (pcp_outfile, "#define %s\n", hp->name); + buf = " 1 "; + } + else + if (pcp_outfile && pcp_inside_if) { + /* Output a precondition for this macro use */ + U_CHAR *cp = ip->bufp; + fprintf (pcp_outfile, "#undef "); + while (is_idchar[*cp]) /* Ick! */ + fputc (*cp++, pcp_outfile); + putc ('\n', pcp_outfile); + } + while (is_idchar[*ip->bufp]) + ++ip->bufp; + SKIP_WHITE_SPACE (ip->bufp); + if (paren) { + if (*ip->bufp != ')') + goto oops; + ++ip->bufp; + } + break; + +oops: + + error ("`defined' without an identifier"); + break; + + default: + error ("cccp error: invalid special hash type"); /* time for gdb */ + abort (); + } + len = strlen (buf); + check_expand (op, len); + bcopy (buf, (char *) op->bufp, len); + op->bufp += len; + + return; +} + + +/* Routines to handle #directives */ + +/* Handle #include and #import. + This function expects to see "fname" or on the input. */ + +static int +do_include (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword; +{ + U_CHAR *importing = keyword->type == T_IMPORT ? (U_CHAR *) "" : (U_CHAR *) 0; + int skip_dirs = (keyword->type == T_INCLUDE_NEXT); + static int import_warning = 0; + char *fname; /* Dynamically allocated fname buffer */ + char *pcftry; + char *pcfname; + char *fbeg, *fend; /* Beginning and end of fname */ + U_CHAR *fin; + + struct file_name_list *search_start = include; /* Chain of dirs to search */ + struct file_name_list *dsp; /* First in chain, if #include "..." */ + struct file_name_list *searchptr = 0; + size_t flen; + + int f = -3; /* file number */ + struct include_file *inc = 0; + + int retried = 0; /* Have already tried macro + expanding the include line*/ + int angle_brackets = 0; /* 0 for "...", 1 for <...> */ +#ifdef VMS + int vaxc_include = 0; /* 1 for token without punctuation */ +#endif + int pcf = -1; + char *pcfbuf; + char *pcfbuflimit; + int pcfnum; + + if (pedantic && !instack[indepth].system_header_p) + { + if (importing) + pedwarn ("ANSI C does not allow `#import'"); + if (skip_dirs) + pedwarn ("ANSI C does not allow `#include_next'"); + } + + if (importing && warn_import && !inhibit_warnings + && !instack[indepth].system_header_p && !import_warning) { + import_warning = 1; + warning ("using `#import' is not recommended"); + fprintf (stderr, "The fact that a certain header file need not be processed more than once\n"); + fprintf (stderr, "should be indicated in the header file, not where it is used.\n"); + fprintf (stderr, "The best way to do this is with a conditional of this form:\n\n"); + fprintf (stderr, " #ifndef _FOO_H_INCLUDED\n"); + fprintf (stderr, " #define _FOO_H_INCLUDED\n"); + fprintf (stderr, " ... ...\n"); + fprintf (stderr, " #endif /* Not _FOO_H_INCLUDED */\n\n"); + fprintf (stderr, "Then users can use `#include' any number of times.\n"); + fprintf (stderr, "GNU C automatically avoids processing the file more than once\n"); + fprintf (stderr, "when it is equipped with such a conditional.\n"); + } + +get_filename: + + fin = buf; + SKIP_WHITE_SPACE (fin); + /* Discard trailing whitespace so we can easily see + if we have parsed all the significant chars we were given. */ + while (limit != fin && is_hor_space[limit[-1]]) limit--; + fbeg = fend = (char *) alloca (limit - fin); + + switch (*fin++) { + case '\"': + { + FILE_BUF *fp; + /* Copy the operand text, concatenating the strings. */ + { + for (;;) { + for (;;) { + if (fin == limit) + goto invalid_include_file_name; + *fend = *fin++; + if (*fend == '"') + break; + fend++; + } + if (fin == limit) + break; + /* If not at the end, there had better be another string. */ + /* Skip just horiz space, and don't go past limit. */ + while (fin != limit && is_hor_space[*fin]) fin++; + if (fin != limit && *fin == '\"') + fin++; + else + goto fail; + } + } + + /* We have "filename". Figure out directory this source + file is coming from and put it on the front of the list. */ + + /* If -I- was specified, don't search current dir, only spec'd ones. */ + if (ignore_srcdir) break; + + for (fp = &instack[indepth]; fp >= instack; fp--) + { + int n; + char *nam; + + if ((nam = fp->nominal_fname) != NULL) { + /* Found a named file. Figure out dir of the file, + and put it in front of the search list. */ + dsp = ((struct file_name_list *) + alloca (sizeof (struct file_name_list) + + fp->nominal_fname_len)); + strcpy (dsp->fname, nam); + simplify_filename (dsp->fname); + nam = base_name (dsp->fname); + *nam = 0; +#ifdef VMS + /* for hack_vms_include_specification(), a local + dir specification must start with "./" on VMS. */ + if (nam == dsp->fname) + { + *nam++ = '.'; + *nam++ = '/'; + *nam = 0; + } +#endif + /* But for efficiency's sake, do not insert the dir + if it matches the search list's first dir. */ + dsp->next = search_start; + if (!search_start || strcmp (dsp->fname, search_start->fname)) { + search_start = dsp; + n = nam - dsp->fname; + if (n + INCLUDE_LEN_FUDGE > max_include_len) + max_include_len = n + INCLUDE_LEN_FUDGE; + } + dsp[0].got_name_map = 0; + break; + } + } + break; + } + + case '<': + while (fin != limit && *fin != '>') + *fend++ = *fin++; + if (*fin == '>' && fin + 1 == limit) { + angle_brackets = 1; + /* If -I-, start with the first -I dir after the -I-. */ + search_start = first_bracket_include; + break; + } + goto fail; + + default: +#ifdef VMS + /* + * Support '#include xyz' like VAX-C to allow for easy use of all the + * decwindow include files. It defaults to '#include ' (so the + * code from case '<' is repeated here) and generates a warning. + * (Note: macro expansion of `xyz' takes precedence.) + */ + /* Note: The argument of ISALPHA() can be evaluated twice, so do + the pre-decrement outside of the macro. */ + if (retried && (--fin, ISALPHA(*(U_CHAR *) (fin)))) { + while (fin != limit && (!ISSPACE(*fin))) + *fend++ = *fin++; + warning ("VAX-C-style include specification found, use '#include ' !"); + vaxc_include = 1; + if (fin == limit) { + angle_brackets = 1; + /* If -I-, start with the first -I dir after the -I-. */ + search_start = first_bracket_include; + break; + } + } +#endif + + fail: + if (! retried) { + /* Expand buffer and then remove any newline markers. + We can't just tell expand_to_temp_buffer to omit the markers, + since it would put extra spaces in include file names. */ + FILE_BUF trybuf; + U_CHAR *src; + int errors_before_expansion = errors; + trybuf = expand_to_temp_buffer (buf, limit, 1, 0); + if (errors != errors_before_expansion) { + free (trybuf.buf); + goto invalid_include_file_name; + } + src = trybuf.buf; + buf = (U_CHAR *) alloca (trybuf.bufp - trybuf.buf + 1); + limit = buf; + while (src != trybuf.bufp) { + switch ((*limit++ = *src++)) { + case '\n': + limit--; + src++; + break; + + case '\'': + case '\"': + { + U_CHAR *src1 = skip_quoted_string (src - 1, trybuf.bufp, 0, + NULL_PTR, NULL_PTR, NULL_PTR); + while (src != src1) + *limit++ = *src++; + } + break; + } + } + *limit = 0; + free (trybuf.buf); + retried = 1; + goto get_filename; + } + + invalid_include_file_name: + error ("`#%s' expects \"FILENAME\" or ", keyword->name); + return 0; + } + + /* For #include_next, skip in the search path + past the dir in which the containing file was found. */ + if (skip_dirs) { + FILE_BUF *fp; + for (fp = &instack[indepth]; fp >= instack; fp--) + if (fp->fname != NULL) { + /* fp->dir is null if the containing file was specified + with an absolute file name. In that case, don't skip anything. */ + if (fp->dir) + search_start = fp->dir->next; + break; + } + } + + *fend = 0; + flen = simplify_filename (fbeg); + + if (flen == 0) + { + error ("empty file name in `#%s'", keyword->name); + return 0; + } + + /* Allocate this permanently, because it gets stored in the definitions + of macros. */ + fname = xmalloc (max_include_len + flen + 1); + /* + 1 above for terminating null. */ + + system_include_depth += angle_brackets; + + /* If specified file name is absolute, just open it. */ + + if (absolute_filename (fbeg)) { + strcpy (fname, fbeg); + f = open_include_file (fname, NULL_PTR, importing, &inc); + } else { + + struct bypass_dir { + struct bypass_dir *next; + char *fname; + struct file_name_list *searchptr; + } **bypass_slot = 0; + + /* Search directory path, trying to open the file. + Copy each filename tried into FNAME. */ + + for (searchptr = search_start; searchptr; searchptr = searchptr->next) { + + if (searchptr == first_bracket_include) { + /* Go to bypass directory if we know we've seen this file before. */ + static struct bypass_dir *bypass_hashtab[INCLUDE_HASHSIZE]; + struct bypass_dir *p; + bypass_slot = &bypass_hashtab[hashf ((U_CHAR *) fbeg, flen, + INCLUDE_HASHSIZE)]; + for (p = *bypass_slot; p; p = p->next) + if (!strcmp (fbeg, p->fname)) { + searchptr = p->searchptr; + bypass_slot = 0; + break; + } + } + +#ifdef VMS + /* Change this 1/2 Unix 1/2 VMS file specification into a + full VMS file specification */ + if (searchptr->fname[0]) + { + strcpy (fname, searchptr->fname); + if (fname[strlen (fname) - 1] == ':') + { + char *slashp; + slashp = strchr (fbeg, '/'); + + /* start at root-dir of logical device if no path given. */ + if (slashp == 0) + strcat (fname, "[000000]"); + } + strcat (fname, fbeg); + + /* Fix up the filename */ + hack_vms_include_specification (fname, vaxc_include); + } + else + { + /* This is a normal VMS filespec, so use it unchanged. */ + strcpy (fname, fbeg); + /* if it's '#include filename', add the missing .h */ + if (vaxc_include && index(fname,'.')==NULL) + strcat (fname, ".h"); + } +#else + strcpy (fname, searchptr->fname); + strcat (fname, fbeg); +#endif /* VMS */ + f = open_include_file (fname, searchptr, importing, &inc); + if (f != -1) { + if (bypass_slot && searchptr != first_bracket_include) { + /* This is the first time we found this include file, + and we found it after first_bracket_include. + Record its location so that we can bypass to here next time. */ + struct bypass_dir *p + = (struct bypass_dir *) xmalloc (sizeof (struct bypass_dir)); + p->next = *bypass_slot; + p->fname = fname + strlen (searchptr->fname); + p->searchptr = searchptr; + *bypass_slot = p; + } + break; + } +#ifdef VMS + /* Our VMS hacks can produce invalid filespecs, so don't worry + about errors other than EACCES. */ + if (errno == EACCES) + break; +#else + if (errno != ENOENT && errno != ENOTDIR) + break; +#endif + } + } + + + if (f < 0) { + + if (f == -2) { + /* The file was already included. */ + + /* If generating dependencies and -MG was specified, we assume missing + files are leaf files, living in the same directory as the source file + or other similar place; these missing files may be generated from + other files and may not exist yet (eg: y.tab.h). */ + } else if (print_deps_missing_files + && (system_include_depth != 0) < print_deps) + { + /* If it was requested as a system header file, + then assume it belongs in the first place to look for such. */ + if (angle_brackets) + { + if (search_start) { + char *p = (char *) alloca (strlen (search_start->fname) + + strlen (fbeg) + 1); + strcpy (p, search_start->fname); + strcat (p, fbeg); + deps_output (p, ' '); + } + } + else + { + /* Otherwise, omit the directory, as if the file existed + in the directory with the source. */ + deps_output (fbeg, ' '); + } + } + /* If -M was specified, and this header file won't be added to the + dependency list, then don't count this as an error, because we can + still produce correct output. Otherwise, we can't produce correct + output, because there may be dependencies we need inside the missing + file, and we don't know what directory this missing file exists in. */ + else if (0 < print_deps && print_deps <= (system_include_depth != 0)) + warning ("No include path in which to find %s", fbeg); + else if (f != -3) + error_from_errno (fbeg); + else + error ("No include path in which to find %s", fbeg); + + } else { + + /* Actually process the file. */ + + pcftry = (char *) alloca (strlen (fname) + 30); + pcfbuf = 0; + pcfnum = 0; + + if (!no_precomp) + { + do { + sprintf (pcftry, "%s%d", fname, pcfnum++); + + pcf = open (pcftry, O_RDONLY, 0666); + if (pcf != -1) + { + struct stat s; + + if (fstat (pcf, &s) != 0) + pfatal_with_name (pcftry); + if (! INO_T_EQ (inc->st.st_ino, s.st_ino) + || inc->st.st_dev != s.st_dev) + { + pcfbuf = check_precompiled (pcf, &s, fname, &pcfbuflimit); + /* Don't need it any more. */ + close (pcf); + } + else + { + /* Don't need it at all. */ + close (pcf); + break; + } + } + } while (pcf != -1 && !pcfbuf); + } + + /* Actually process the file */ + if (pcfbuf) { + pcfname = xmalloc (strlen (pcftry) + 1); + strcpy (pcfname, pcftry); + pcfinclude ((U_CHAR *) pcfbuf, (U_CHAR *) fname, op); + } + else + finclude (f, inc, op, is_system_include (fname), searchptr); + } + + system_include_depth -= angle_brackets; + + return 0; +} + +/* Return nonzero if the given FILENAME is an absolute pathname which + designates a file within one of the known "system" include file + directories. We assume here that if the given FILENAME looks like + it is the name of a file which resides either directly in a "system" + include file directory, or within any subdirectory thereof, then the + given file must be a "system" include file. This function tells us + if we should suppress pedantic errors/warnings for the given FILENAME. + + The value is 2 if the file is a C-language system header file + for which C++ should (on most systems) assume `extern "C"'. */ + +static int +is_system_include (filename) + register char *filename; +{ + struct file_name_list *searchptr; + + for (searchptr = first_system_include; searchptr; + searchptr = searchptr->next) + if (! strncmp (searchptr->fname, filename, strlen (searchptr->fname))) + return searchptr->c_system_include_path + 1; + return 0; +} + +/* Yield the non-directory suffix of a file name. */ + +static char * +base_name (fname) + char *fname; +{ + char *s = fname; + char *p; +#if defined (__MSDOS__) || defined (_WIN32) + if (ISALPHA (s[0]) && s[1] == ':') s += 2; +#endif +#ifdef VMS + if ((p = rindex (s, ':'))) s = p + 1; /* Skip device. */ + if ((p = rindex (s, ']'))) s = p + 1; /* Skip directory. */ + if ((p = rindex (s, '>'))) s = p + 1; /* Skip alternate (int'n'l) dir. */ + if (s != fname) + return s; +#endif + if ((p = rindex (s, '/'))) s = p + 1; +#ifdef DIR_SEPARATOR + if ((p = rindex (s, DIR_SEPARATOR))) s = p + 1; +#endif + return s; +} + +/* Yield nonzero if FILENAME is absolute (i.e. not relative). */ + +static int +absolute_filename (filename) + char *filename; +{ +#if defined (__MSDOS__) || (defined (_WIN32) && !defined (__CYGWIN__)) + if (ISALPHA (filename[0]) && filename[1] == ':') filename += 2; +#endif +#if defined (__CYGWIN__) + /* At present, any path that begins with a drive spec is absolute. */ + if (ISALPHA (filename[0]) && filename[1] == ':') return 1; +#endif +#ifdef VMS + if (index (filename, ':') != 0) return 1; +#endif + if (filename[0] == '/') return 1; +#ifdef DIR_SEPARATOR + if (filename[0] == DIR_SEPARATOR) return 1; +#endif + return 0; +} + +/* Remove unnecessary characters from FILENAME in place, + to avoid unnecessary filename aliasing. + Return the length of the resulting string. + + Do only the simplifications allowed by Posix. + It is OK to miss simplifications on non-Posix hosts, + since this merely leads to suboptimal results. */ + +static size_t +simplify_filename (filename) + char *filename; +{ + register char *from = filename; + register char *to = filename; + char *to0; + + /* Remove redundant initial /s. */ + if (*from == '/') { + *to++ = '/'; + if (*++from == '/') { + if (*++from == '/') { + /* 3 or more initial /s are equivalent to 1 /. */ + while (*++from == '/') + continue; + } else { + /* On some hosts // differs from /; Posix allows this. */ + static int slashslash_vs_slash; + if (slashslash_vs_slash == 0) { + struct stat s1, s2; + slashslash_vs_slash = ((stat ("/", &s1) == 0 && stat ("//", &s2) == 0 + && INO_T_EQ (s1.st_ino, s2.st_ino) + && s1.st_dev == s2.st_dev) + ? 1 : -1); + } + if (slashslash_vs_slash < 0) + *to++ = '/'; + } + } + } + to0 = to; + + for (;;) { +#ifndef VMS + if (from[0] == '.' && from[1] == '/') + from += 2; + else +#endif + { + /* Copy this component and trailing /, if any. */ + while ((*to++ = *from++) != '/') { + if (!to[-1]) { + /* Trim . component at end of nonempty name. */ + to -= filename <= to - 3 && to[-3] == '/' && to[-2] == '.'; + + /* Trim unnecessary trailing /s. */ + while (to0 < --to && to[-1] == '/') + continue; + + *to = 0; + return to - filename; + } + } + } + + /* Skip /s after a /. */ + while (*from == '/') + from++; + } +} + +/* The file_name_map structure holds a mapping of file names for a + particular directory. This mapping is read from the file named + FILE_NAME_MAP_FILE in that directory. Such a file can be used to + map filenames on a file system with severe filename restrictions, + such as DOS. The format of the file name map file is just a series + of lines with two tokens on each line. The first token is the name + to map, and the second token is the actual name to use. */ + +struct file_name_map +{ + struct file_name_map *map_next; + char *map_from; + char *map_to; +}; + +#define FILE_NAME_MAP_FILE "header.gcc" + +/* Read a space delimited string of unlimited length from a stdio + file. */ + +static char * +read_filename_string (ch, f) + int ch; + FILE *f; +{ + char *alloc, *set; + int len; + + len = 20; + set = alloc = xmalloc (len + 1); + if (! is_space[ch]) + { + *set++ = ch; + while ((ch = getc (f)) != EOF && ! is_space[ch]) + { + if (set - alloc == len) + { + len *= 2; + alloc = xrealloc (alloc, len + 1); + set = alloc + len / 2; + } + *set++ = ch; + } + } + *set = '\0'; + ungetc (ch, f); + return alloc; +} + +/* Read the file name map file for DIRNAME. + If DIRNAME is empty, read the map file for the working directory; + otherwise DIRNAME must end in '/'. */ + +static struct file_name_map * +read_name_map (dirname) + char *dirname; +{ + /* This structure holds a linked list of file name maps, one per + directory. */ + struct file_name_map_list + { + struct file_name_map_list *map_list_next; + char *map_list_name; + struct file_name_map *map_list_map; + }; + static struct file_name_map_list *map_list; + register struct file_name_map_list *map_list_ptr; + char *name; + FILE *f; + size_t dirlen; + + for (map_list_ptr = map_list; map_list_ptr; + map_list_ptr = map_list_ptr->map_list_next) + if (! strcmp (map_list_ptr->map_list_name, dirname)) + return map_list_ptr->map_list_map; + + map_list_ptr = ((struct file_name_map_list *) + xmalloc (sizeof (struct file_name_map_list))); + map_list_ptr->map_list_name = savestring (dirname); + map_list_ptr->map_list_map = NULL; + + dirlen = strlen (dirname); + name = (char *) alloca (dirlen + strlen (FILE_NAME_MAP_FILE) + 1); + strcpy (name, dirname); + strcat (name, FILE_NAME_MAP_FILE); + f = fopen (name, "r"); + if (!f) + map_list_ptr->map_list_map = NULL; + else + { + int ch; + + while ((ch = getc (f)) != EOF) + { + char *from, *to; + struct file_name_map *ptr; + size_t tolen; + + if (is_space[ch]) + continue; + from = read_filename_string (ch, f); + while ((ch = getc (f)) != EOF && is_hor_space[ch]) + ; + to = read_filename_string (ch, f); + + simplify_filename (from); + tolen = simplify_filename (to); + + ptr = ((struct file_name_map *) + xmalloc (sizeof (struct file_name_map))); + ptr->map_from = from; + + /* Make the real filename absolute. */ + if (absolute_filename (to)) + ptr->map_to = to; + else + { + ptr->map_to = xmalloc (dirlen + tolen + 1); + strcpy (ptr->map_to, dirname); + strcat (ptr->map_to, to); + free (to); + } + + ptr->map_next = map_list_ptr->map_list_map; + map_list_ptr->map_list_map = ptr; + + while ((ch = getc (f)) != '\n') + if (ch == EOF) + break; + } + fclose (f); + } + + map_list_ptr->map_list_next = map_list; + map_list = map_list_ptr; + + return map_list_ptr->map_list_map; +} + +/* Try to open include file FILENAME. SEARCHPTR is the directory + being tried from the include file search path. + IMPORTING is "" if we are importing, null otherwise. + Return -2 if found, either a matching name or a matching inode. + Otherwise, open the file and return a file descriptor if successful + or -1 if unsuccessful. + Unless unsuccessful, put a descriptor of the included file into *PINC. + This function maps filenames on file systems based on information read by + read_name_map. */ + +static int +open_include_file (filename, searchptr, importing, pinc) + char *filename; + struct file_name_list *searchptr; + U_CHAR *importing; + struct include_file **pinc; +{ + char *fname = remap ? remap_include_file (filename, searchptr) : filename; + int fd = -2; + + /* Look up FNAME in include_hashtab. */ + struct include_file **phead = &include_hashtab[hashf ((U_CHAR *) fname, + strlen (fname), + INCLUDE_HASHSIZE)]; + struct include_file *inc, *head = *phead; + for (inc = head; inc; inc = inc->next) + if (!strcmp (fname, inc->fname)) + break; + + if (!inc + || ! inc->control_macro + || (inc->control_macro[0] && ! lookup (inc->control_macro, -1, -1))) { + + fd = open (fname, O_RDONLY, 0); + + if (fd < 0) + { +#ifdef VMS + /* if #include fails, try again with hacked spec. */ + if (!hack_vms_include_specification (fname, 0)) + return fd; + fd = open (fname, O_RDONLY, 0); + if (fd < 0) +#endif + return fd; + } + + if (!inc) { + /* FNAME was not in include_hashtab; insert a new entry. */ + inc = (struct include_file *) xmalloc (sizeof (struct include_file)); + inc->next = head; + inc->fname = fname; + inc->control_macro = 0; + inc->deps_output = 0; + if (fstat (fd, &inc->st) != 0) + pfatal_with_name (fname); + *phead = inc; + + /* Look for another file with the same inode and device. */ + if (lookup_ino_include (inc) + && inc->control_macro + && (!inc->control_macro[0] || lookup (inc->control_macro, -1, -1))) { + close (fd); + fd = -2; + } + } + + /* For -M, add this file to the dependencies. */ + if (! inc->deps_output && (system_include_depth != 0) < print_deps) { + inc->deps_output = 1; + deps_output (fname, ' '); + } + + /* Handle -H option. */ + if (print_include_names) + fprintf (stderr, "%*s%s\n", indepth, "", fname); + } + + if (importing) + inc->control_macro = importing; + + *pinc = inc; + return fd; +} + +/* Return the remapped name of the include file FILENAME. + SEARCHPTR is the directory being tried from the include file path. */ + +static char * +remap_include_file (filename, searchptr) + char *filename; + struct file_name_list *searchptr; +{ + register struct file_name_map *map; + register char *from; + + if (searchptr) + { + if (! searchptr->got_name_map) + { + searchptr->name_map = read_name_map (searchptr->fname); + searchptr->got_name_map = 1; + } + + /* Check the mapping for the directory we are using. */ + from = filename + strlen (searchptr->fname); + for (map = searchptr->name_map; map; map = map->map_next) + if (! strcmp (map->map_from, from)) + return map->map_to; + } + + from = base_name (filename); + + if (from != filename || !searchptr) + { + /* Try to find a mapping file for the particular directory we are + looking in. Thus #include will look up sys/types.h + in /usr/include/header.gcc and look up types.h in + /usr/include/sys/header.gcc. */ + + char *dir = (char *) alloca (from - filename + 1); + bcopy (filename, dir, from - filename); + dir[from - filename] = '\0'; + + for (map = read_name_map (dir); map; map = map->map_next) + if (! strcmp (map->map_from, from)) + return map->map_to; + } + + return filename; +} + +/* Insert INC into the include file table, hashed by device and inode number. + If a file with different name but same dev+ino was already in the table, + return 1 and set INC's control macro to the already-known macro. */ + +static int +lookup_ino_include (inc) + struct include_file *inc; +{ + int hash = ((unsigned) (inc->st.st_dev + INO_T_HASH (inc->st.st_ino)) + % INCLUDE_HASHSIZE); + struct include_file *i = include_ino_hashtab[hash]; + inc->next_ino = i; + include_ino_hashtab[hash] = inc; + + for (; i; i = i->next_ino) + if (INO_T_EQ (inc->st.st_ino, i->st.st_ino) + && inc->st.st_dev == i->st.st_dev) { + inc->control_macro = i->control_macro; + return 1; + } + + return 0; +} + +/* Process file descriptor F, which corresponds to include file INC, + with output to OP. + SYSTEM_HEADER_P is 1 if this file resides in any one of the known + "system" include directories (as decided by the `is_system_include' + function above). + DIRPTR is the link in the dir path through which this file was found, + or 0 if the file name was absolute. */ + +static void +finclude (f, inc, op, system_header_p, dirptr) + int f; + struct include_file *inc; + FILE_BUF *op; + int system_header_p; + struct file_name_list *dirptr; +{ + char *fname = inc->fname; + int i; + FILE_BUF *fp; /* For input stack frame */ + int missing_newline = 0; + + CHECK_DEPTH (return;); + + fp = &instack[indepth + 1]; + bzero ((char *) fp, sizeof (FILE_BUF)); + fp->nominal_fname = fp->fname = fname; + fp->nominal_fname_len = strlen (fname); + fp->inc = inc; + fp->length = 0; + fp->lineno = 1; + fp->if_stack = if_stack; + fp->system_header_p = system_header_p; + fp->dir = dirptr; + + if (S_ISREG (inc->st.st_mode)) { + size_t s = (size_t) inc->st.st_size; + if (s != inc->st.st_size || s + 2 < s) + memory_full (); + fp->buf = (U_CHAR *) xmalloc (s + 2); + fp->bufp = fp->buf; + + /* Read the file contents, knowing that s is an upper bound + on the number of bytes we can read. */ + fp->length = safe_read (f, (char *) fp->buf, s); + if (fp->length < 0) goto nope; + } + else if (S_ISDIR (inc->st.st_mode)) { + error ("directory `%s' specified in #include", fname); + close (f); + return; + } else { + /* Cannot count its file size before reading. + First read the entire file into heap and + copy them into buffer on stack. */ + + int bsize = 2000; + int st_size = 0; + + fp->buf = (U_CHAR *) xmalloc (bsize + 2); + + for (;;) { + i = safe_read (f, (char *) fp->buf + st_size, bsize - st_size); + if (i < 0) + goto nope; /* error! */ + st_size += i; + if (st_size != bsize) + break; /* End of file */ + bsize *= 2; + fp->buf = (U_CHAR *) xrealloc (fp->buf, bsize + 2); + } + fp->bufp = fp->buf; + fp->length = st_size; + } + + if ((fp->length > 0 && fp->buf[fp->length - 1] != '\n') + /* Backslash-newline at end is not good enough. */ + || (fp->length > 1 && fp->buf[fp->length - 2] == '\\')) { + fp->buf[fp->length++] = '\n'; + missing_newline = 1; + } + fp->buf[fp->length] = '\0'; + + /* Close descriptor now, so nesting does not use lots of descriptors. */ + close (f); + + /* Must do this before calling trigraph_pcp, so that the correct file name + will be printed in warning messages. */ + + indepth++; + input_file_stack_tick++; + + if (!no_trigraphs) + trigraph_pcp (fp); + + output_line_directive (fp, op, 0, enter_file); + rescan (op, 0); + + if (missing_newline) + fp->lineno--; + + if (pedantic && missing_newline) + pedwarn ("file does not end in newline"); + + indepth--; + input_file_stack_tick++; + output_line_directive (&instack[indepth], op, 0, leave_file); + free (fp->buf); + return; + + nope: + + perror_with_name (fname); + close (f); + free (fp->buf); +} + +/* Record that inclusion of the include file INC + should be controlled by the macro named MACRO_NAME. + This means that trying to include the file again + will do something if that macro is defined. */ + +static void +record_control_macro (inc, macro_name) + struct include_file *inc; + U_CHAR *macro_name; +{ + if (!inc->control_macro || inc->control_macro[0]) + inc->control_macro = macro_name; +} + +/* Load the specified precompiled header into core, and verify its + preconditions. PCF indicates the file descriptor to read, which must + be a regular file. *ST is its file status. + FNAME indicates the file name of the original header. + *LIMIT will be set to an address one past the end of the file. + If the preconditions of the file are not satisfied, the buffer is + freed and we return 0. If the preconditions are satisfied, return + the address of the buffer following the preconditions. The buffer, in + this case, should never be freed because various pieces of it will + be referred to until all precompiled strings are output at the end of + the run. */ + +static char * +check_precompiled (pcf, st, fname, limit) + int pcf; + struct stat *st; + char *fname ATTRIBUTE_UNUSED; + char **limit; +{ + int length = 0; + char *buf; + char *cp; + + if (pcp_outfile) + return 0; + + if (S_ISREG (st->st_mode)) + { + size_t s = (size_t) st->st_size; + if (s != st->st_size || s + 2 < s) + memory_full (); + buf = xmalloc (s + 2); + length = safe_read (pcf, buf, s); + if (length < 0) + goto nope; + } + else + abort (); + + if (length > 0 && buf[length-1] != '\n') + buf[length++] = '\n'; + buf[length] = '\0'; + + *limit = buf + length; + + /* File is in core. Check the preconditions. */ + if (!check_preconditions (buf)) + goto nope; + for (cp = buf; *cp; cp++) + ; +#ifdef DEBUG_PCP + fprintf (stderr, "Using preinclude %s\n", fname); +#endif + return cp + 1; + + nope: +#ifdef DEBUG_PCP + fprintf (stderr, "Cannot use preinclude %s\n", fname); +#endif + free (buf); + return 0; +} + +/* PREC (null terminated) points to the preconditions of a + precompiled header. These are a series of #define and #undef + lines which must match the current contents of the hash + table. */ + +static int +check_preconditions (prec) + char *prec; +{ + MACRODEF mdef; + char *lineend; + + while (*prec) { + lineend = index (prec, '\n'); + + if (*prec++ != '#') { + error ("Bad format encountered while reading precompiled file"); + return 0; + } + if (!strncmp (prec, "define", 6)) { + HASHNODE *hp; + + prec += 6; + mdef = create_definition ((U_CHAR *) prec, (U_CHAR *) lineend, NULL_PTR); + + if (mdef.defn == 0) + abort (); + + if ((hp = lookup (mdef.symnam, mdef.symlen, -1)) == NULL + || (hp->type != T_MACRO && hp->type != T_CONST) + || (hp->type == T_MACRO + && !compare_defs (mdef.defn, hp->value.defn) + && (mdef.defn->length != 2 + || mdef.defn->expansion[0] != '\n' + || mdef.defn->expansion[1] != ' '))) + return 0; + } else if (!strncmp (prec, "undef", 5)) { + char *name; + int len; + + prec += 5; + while (is_hor_space[(U_CHAR) *prec]) + prec++; + name = prec; + while (is_idchar[(U_CHAR) *prec]) + prec++; + len = prec - name; + + if (lookup ((U_CHAR *) name, len, -1)) + return 0; + } else { + error ("Bad format encountered while reading precompiled file"); + return 0; + } + prec = lineend + 1; + } + /* They all passed successfully */ + return 1; +} + +/* Process the main body of a precompiled file. BUF points to the + string section of the file, following the preconditions. LIMIT is one + character past the end. NAME is the name of the file being read + in. OP is the main output buffer. */ + +static void +pcfinclude (buf, name, op) + U_CHAR *buf, *name; + FILE_BUF *op; +{ + FILE_BUF tmpbuf; + int nstrings; + U_CHAR *cp = buf; + + /* First in the file comes 4 bytes indicating the number of strings, */ + /* in network byte order. (MSB first). */ + nstrings = *cp++; + nstrings = (nstrings << 8) | *cp++; + nstrings = (nstrings << 8) | *cp++; + nstrings = (nstrings << 8) | *cp++; + + /* Looping over each string... */ + while (nstrings--) { + U_CHAR *string_start; + U_CHAR *endofthiskey; + STRINGDEF *str; + int nkeys; + + /* Each string starts with a STRINGDEF structure (str), followed */ + /* by the text of the string (string_start) */ + + /* First skip to a longword boundary */ + /* ??? Why a 4-byte boundary? On all machines? */ + /* NOTE: This works correctly even if size_t + is narrower than a pointer. + Do not try risky measures here to get another type to use! + Do not include stddef.h--it will fail! */ + if ((size_t) cp & 3) + cp += 4 - ((size_t) cp & 3); + + /* Now get the string. */ + str = (STRINGDEF *) (GENERIC_PTR) cp; + string_start = cp += sizeof (STRINGDEF); + + for (; *cp; cp++) /* skip the string */ + ; + + /* We need to macro expand the string here to ensure that the + proper definition environment is in place. If it were only + expanded when we find out it is needed, macros necessary for + its proper expansion might have had their definitions changed. */ + tmpbuf = expand_to_temp_buffer (string_start, cp++, 0, 0); + /* Lineno is already set in the precompiled file */ + str->contents = tmpbuf.buf; + str->len = tmpbuf.length; + str->writeflag = 0; + str->filename = name; + str->output_mark = outbuf.bufp - outbuf.buf; + + str->chain = 0; + *stringlist_tailp = str; + stringlist_tailp = &str->chain; + + /* Next comes a fourbyte number indicating the number of keys + for this string. */ + nkeys = *cp++; + nkeys = (nkeys << 8) | *cp++; + nkeys = (nkeys << 8) | *cp++; + nkeys = (nkeys << 8) | *cp++; + + /* If this number is -1, then the string is mandatory. */ + if (nkeys == -1) + str->writeflag = 1; + else + /* Otherwise, for each key, */ + for (; nkeys--; free (tmpbuf.buf), cp = endofthiskey + 1) { + KEYDEF *kp = (KEYDEF *) (GENERIC_PTR) cp; + HASHNODE *hp; + + /* It starts with a KEYDEF structure */ + cp += sizeof (KEYDEF); + + /* Find the end of the key. At the end of this for loop we + advance CP to the start of the next key using this variable. */ + endofthiskey = cp + strlen ((char *) cp); + kp->str = str; + + /* Expand the key, and enter it into the hash table. */ + tmpbuf = expand_to_temp_buffer (cp, endofthiskey, 0, 0); + tmpbuf.bufp = tmpbuf.buf; + + while (is_hor_space[*tmpbuf.bufp]) + tmpbuf.bufp++; + if (!is_idstart[*tmpbuf.bufp] + || tmpbuf.bufp == tmpbuf.buf + tmpbuf.length) { + str->writeflag = 1; + continue; + } + + hp = lookup (tmpbuf.bufp, -1, -1); + if (hp == NULL) { + kp->chain = 0; + install (tmpbuf.bufp, -1, T_PCSTRING, (char *) kp, -1); + } + else if (hp->type == T_PCSTRING) { + kp->chain = hp->value.keydef; + hp->value.keydef = kp; + } + else + str->writeflag = 1; + } + } + /* This output_line_directive serves to switch us back to the current + input file in case some of these strings get output (which will + result in line directives for the header file being output). */ + output_line_directive (&instack[indepth], op, 0, enter_file); +} + +/* Called from rescan when it hits a key for strings. Mark them all + used and clean up. */ + +static void +pcstring_used (hp) + HASHNODE *hp; +{ + KEYDEF *kp; + + for (kp = hp->value.keydef; kp; kp = kp->chain) + kp->str->writeflag = 1; + delete_macro (hp); +} + +/* Write the output, interspersing precompiled strings in their + appropriate places. */ + +static void +write_output () +{ + STRINGDEF *next_string; + U_CHAR *cur_buf_loc; + int line_directive_len = 80; + char *line_directive = xmalloc (line_directive_len); + int len; + + /* In each run through the loop, either cur_buf_loc == + next_string_loc, in which case we print a series of strings, or + it is less than next_string_loc, in which case we write some of + the buffer. */ + cur_buf_loc = outbuf.buf; + next_string = stringlist; + + while (cur_buf_loc < outbuf.bufp || next_string) { + if (next_string + && cur_buf_loc - outbuf.buf == next_string->output_mark) { + if (next_string->writeflag) { + len = 4 * strlen ((char *) next_string->filename) + 32; + while (len > line_directive_len) + line_directive = xrealloc (line_directive, + line_directive_len *= 2); + sprintf (line_directive, "\n# %d ", next_string->lineno); + strcpy (quote_string (line_directive + strlen (line_directive), + (char *) next_string->filename, + strlen ((char *) next_string->filename)), + "\n"); + safe_write (fileno (stdout), line_directive, strlen (line_directive)); + safe_write (fileno (stdout), + (char *) next_string->contents, next_string->len); + } + next_string = next_string->chain; + } + else { + len = (next_string + ? (next_string->output_mark + - (cur_buf_loc - outbuf.buf)) + : outbuf.bufp - cur_buf_loc); + + safe_write (fileno (stdout), (char *) cur_buf_loc, len); + cur_buf_loc += len; + } + } + free (line_directive); +} + +/* Pass a directive through to the output file. + BUF points to the contents of the directive, as a contiguous string. + LIMIT points to the first character past the end of the directive. + KEYWORD is the keyword-table entry for the directive. */ + +static void +pass_thru_directive (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword; +{ + register unsigned keyword_length = keyword->length; + + check_expand (op, 1 + keyword_length + (limit - buf)); + *op->bufp++ = '#'; + bcopy (keyword->name, (char *) op->bufp, keyword_length); + op->bufp += keyword_length; + if (limit != buf && buf[0] != ' ') + *op->bufp++ = ' '; + bcopy ((char *) buf, (char *) op->bufp, limit - buf); + op->bufp += (limit - buf); +#if 0 + *op->bufp++ = '\n'; + /* Count the line we have just made in the output, + to get in sync properly. */ + op->lineno++; +#endif +} + +/* The arglist structure is built by do_define to tell + collect_definition where the argument names begin. That + is, for a define like "#define f(x,y,z) foo+x-bar*y", the arglist + would contain pointers to the strings x, y, and z. + Collect_definition would then build a DEFINITION node, + with reflist nodes pointing to the places x, y, and z had + appeared. So the arglist is just convenience data passed + between these two routines. It is not kept around after + the current #define has been processed and entered into the + hash table. */ + +struct arglist { + struct arglist *next; + U_CHAR *name; + int length; + int argno; + char rest_args; +}; + +/* Create a DEFINITION node from a #define directive. Arguments are + as for do_define. */ + +static MACRODEF +create_definition (buf, limit, op) + U_CHAR *buf, *limit; + FILE_BUF *op; +{ + U_CHAR *bp; /* temp ptr into input buffer */ + U_CHAR *symname; /* remember where symbol name starts */ + int sym_length; /* and how long it is */ + int line = instack[indepth].lineno; + char *file = instack[indepth].nominal_fname; + size_t file_len = instack[indepth].nominal_fname_len; + int rest_args = 0; + + DEFINITION *defn; + int arglengths = 0; /* Accumulate lengths of arg names + plus number of args. */ + MACRODEF mdef; + + bp = buf; + + while (is_hor_space[*bp]) + bp++; + + symname = bp; /* remember where it starts */ + sym_length = check_macro_name (bp, "macro"); + bp += sym_length; + + /* Lossage will occur if identifiers or control keywords are broken + across lines using backslash. This is not the right place to take + care of that. */ + + if (*bp == '(') { + struct arglist *arg_ptrs = NULL; + int argno = 0; + + bp++; /* skip '(' */ + SKIP_WHITE_SPACE (bp); + + /* Loop over macro argument names. */ + while (*bp != ')') { + struct arglist *temp; + + temp = (struct arglist *) alloca (sizeof (struct arglist)); + temp->name = bp; + temp->next = arg_ptrs; + temp->argno = argno++; + temp->rest_args = 0; + arg_ptrs = temp; + + if (rest_args) + pedwarn ("another parameter follows `%s'", + rest_extension); + + if (!is_idstart[*bp]) + { + if (c9x && limit - bp > (long) REST_EXTENSION_LENGTH + && bcmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0) + { + /* This is the ISO C 9x way to write macros with variable + number of arguments. */ + rest_args = 1; + temp->rest_args = 1; + } + else + pedwarn ("invalid character in macro parameter name"); + } + + /* Find the end of the arg name. */ + while (is_idchar[*bp]) { + bp++; + /* do we have a "special" rest-args extension here? */ + if (limit - bp > (long) REST_EXTENSION_LENGTH + && bcmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0) { + if (pedantic && !instack[indepth].system_header_p) + pedwarn ("ANSI C does not allow macro with variable arguments"); + rest_args = 1; + temp->rest_args = 1; + break; + } + } + if (bp == temp->name && rest_args == 1) + { + /* This is the ISO C 9x style. */ + temp->name = va_args_name; + temp->length = VA_ARGS_NAME_LENGTH; + } + else + temp->length = bp - temp->name; + if (rest_args == 1) + bp += REST_EXTENSION_LENGTH; + arglengths += temp->length + 2; + SKIP_WHITE_SPACE (bp); + if (temp->length == 0 || (*bp != ',' && *bp != ')')) { + error ("badly punctuated parameter list in `#define'"); + goto nope; + } + if (*bp == ',') { + bp++; + SKIP_WHITE_SPACE (bp); + /* A comma at this point can only be followed by an identifier. */ + if (!is_idstart[*bp] + && !(c9x && limit - bp > (long) REST_EXTENSION_LENGTH + && bcmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0)) { + error ("badly punctuated parameter list in `#define'"); + goto nope; + } + } + if (bp >= limit) { + error ("unterminated parameter list in `#define'"); + goto nope; + } + { + struct arglist *otemp; + + for (otemp = temp->next; otemp != NULL; otemp = otemp->next) + if (temp->length == otemp->length + && bcmp (temp->name, otemp->name, temp->length) == 0) + { + error ("duplicate argument name `%.*s' in `#define'", + temp->length, temp->name); + goto nope; + } + if (rest_args == 0 && temp->length == VA_ARGS_NAME_LENGTH + && bcmp (temp->name, va_args_name, VA_ARGS_NAME_LENGTH) == 0) + { + error ("\ +reserved name `%s' used as argument name in `#define'", va_args_name); + goto nope; + } + } + } + + ++bp; /* skip paren */ + SKIP_WHITE_SPACE (bp); + /* now everything from bp before limit is the definition. */ + defn = collect_expansion (bp, limit, argno, arg_ptrs); + defn->rest_args = rest_args; + + /* Now set defn->args.argnames to the result of concatenating + the argument names in reverse order + with comma-space between them. */ + defn->args.argnames = (U_CHAR *) xmalloc (arglengths + 1); + { + struct arglist *temp; + int i = 0; + for (temp = arg_ptrs; temp; temp = temp->next) { + bcopy (temp->name, &defn->args.argnames[i], temp->length); + i += temp->length; + if (temp->next != 0) { + defn->args.argnames[i++] = ','; + defn->args.argnames[i++] = ' '; + } + } + defn->args.argnames[i] = 0; + } + } else { + /* Simple expansion or empty definition. */ + + if (bp < limit) + { + if (is_hor_space[*bp]) { + bp++; + SKIP_WHITE_SPACE (bp); + } else if (sym_length) { + switch (*bp) { + case '!': case '"': case '#': case '%': case '&': case '\'': + case ')': case '*': case '+': case ',': case '-': case '.': + case '/': case ':': case ';': case '<': case '=': case '>': + case '?': case '[': case '\\': case ']': case '^': case '{': + case '|': case '}': case '~': + warning ("missing white space after `#define %.*s'", + sym_length, symname); + break; + + default: + pedwarn ("missing white space after `#define %.*s'", + sym_length, symname); + break; + } + } + } + /* Now everything from bp before limit is the definition. */ + defn = collect_expansion (bp, limit, -1, NULL_PTR); + defn->args.argnames = (U_CHAR *) ""; + } + + defn->line = line; + defn->file = file; + defn->file_len = file_len; + + /* OP is null if this is a predefinition */ + defn->predefined = !op; + mdef.defn = defn; + mdef.symnam = symname; + mdef.symlen = sym_length; + + return mdef; + + nope: + mdef.defn = 0; + return mdef; +} + +/* Process a #define directive. +BUF points to the contents of the #define directive, as a contiguous string. +LIMIT points to the first character past the end of the definition. +KEYWORD is the keyword-table entry for #define. */ + +static int +do_define (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword; +{ + int hashcode; + MACRODEF mdef; + + /* If this is a precompiler run (with -pcp) pass thru #define directives. */ + if (pcp_outfile && op) + pass_thru_directive (buf, limit, op, keyword); + + mdef = create_definition (buf, limit, op); + if (mdef.defn == 0) + goto nope; + + hashcode = hashf (mdef.symnam, mdef.symlen, HASHSIZE); + + { + HASHNODE *hp; + if ((hp = lookup (mdef.symnam, mdef.symlen, hashcode)) != NULL) { + int ok = 0; + /* Redefining a precompiled key is ok. */ + if (hp->type == T_PCSTRING) + ok = 1; + /* Redefining a macro is ok if the definitions are the same. */ + else if (hp->type == T_MACRO) + ok = ! compare_defs (mdef.defn, hp->value.defn); + /* Redefining a constant is ok with -D. */ + else if (hp->type == T_CONST) + ok = ! done_initializing; + /* Print the warning if it's not ok. */ + if (!ok) { + /* If we are passing through #define and #undef directives, do + that for this re-definition now. */ + if (debug_output && op) + pass_thru_directive (buf, limit, op, keyword); + +/* CYGNUS LOCAL chill */ + if (!chill || strcmp (mdef.defn->file, "*Initialization*")) +/* END CYGNUS LOCAL chill */ + pedwarn ("`%.*s' redefined", mdef.symlen, mdef.symnam); + if (hp->type == T_MACRO) + pedwarn_with_file_and_line (hp->value.defn->file, + hp->value.defn->file_len, + hp->value.defn->line, + "this is the location of the previous definition"); + } + /* Replace the old definition. */ + hp->type = T_MACRO; + hp->value.defn = mdef.defn; + } else { + /* If we are passing through #define and #undef directives, do + that for this new definition now. */ + if (debug_output && op) + pass_thru_directive (buf, limit, op, keyword); + install (mdef.symnam, mdef.symlen, T_MACRO, + (char *) mdef.defn, hashcode); + } + } + + return 0; + +nope: + + return 1; +} + +/* Check a purported macro name SYMNAME, and yield its length. + USAGE is the kind of name this is intended for. */ + +static int +check_macro_name (symname, usage) + U_CHAR *symname; + char *usage; +{ + U_CHAR *p; + int sym_length; + + for (p = symname; is_idchar[*p]; p++) + ; + sym_length = p - symname; + if (sym_length == 0 + || (sym_length == 1 && *symname == 'L' && (*p == '\'' || *p == '"'))) + error ("invalid %s name", usage); + else if (!is_idstart[*symname] + || (sym_length == 7 && ! bcmp (symname, "defined", 7))) + error ("invalid %s name `%.*s'", usage, sym_length, symname); + return sym_length; +} + +/* Return zero if two DEFINITIONs are isomorphic. */ + +static int +compare_defs (d1, d2) + DEFINITION *d1, *d2; +{ + register struct reflist *a1, *a2; + register U_CHAR *p1 = d1->expansion; + register U_CHAR *p2 = d2->expansion; + int first = 1; + + if (d1->nargs != d2->nargs) + return 1; + if (pedantic + && strcmp ((char *)d1->args.argnames, (char *)d2->args.argnames)) + return 1; + for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2; + a1 = a1->next, a2 = a2->next) { + if (!((a1->nchars == a2->nchars && ! bcmp (p1, p2, a1->nchars)) + || ! comp_def_part (first, p1, a1->nchars, p2, a2->nchars, 0)) + || a1->argno != a2->argno + || a1->stringify != a2->stringify + || a1->raw_before != a2->raw_before + || a1->raw_after != a2->raw_after) + return 1; + first = 0; + p1 += a1->nchars; + p2 += a2->nchars; + } + if (a1 != a2) + return 1; + if (comp_def_part (first, p1, d1->length - (p1 - d1->expansion), + p2, d2->length - (p2 - d2->expansion), 1)) + return 1; + return 0; +} + +/* Return 1 if two parts of two macro definitions are effectively different. + One of the parts starts at BEG1 and has LEN1 chars; + the other has LEN2 chars at BEG2. + Any sequence of whitespace matches any other sequence of whitespace. + FIRST means these parts are the first of a macro definition; + so ignore leading whitespace entirely. + LAST means these parts are the last of a macro definition; + so ignore trailing whitespace entirely. */ + +static int +comp_def_part (first, beg1, len1, beg2, len2, last) + int first; + U_CHAR *beg1, *beg2; + int len1, len2; + int last; +{ + register U_CHAR *end1 = beg1 + len1; + register U_CHAR *end2 = beg2 + len2; + if (first) { + while (beg1 != end1 && is_space[*beg1]) beg1++; + while (beg2 != end2 && is_space[*beg2]) beg2++; + } + if (last) { + while (beg1 != end1 && is_space[end1[-1]]) end1--; + while (beg2 != end2 && is_space[end2[-1]]) end2--; + } + while (beg1 != end1 && beg2 != end2) { + if (is_space[*beg1] && is_space[*beg2]) { + while (beg1 != end1 && is_space[*beg1]) beg1++; + while (beg2 != end2 && is_space[*beg2]) beg2++; + } else if (*beg1 == *beg2) { + beg1++; beg2++; + } else break; + } + return (beg1 != end1) || (beg2 != end2); +} + +/* Read a replacement list for a macro with parameters. + Build the DEFINITION structure. + Reads characters of text starting at BUF until END. + ARGLIST specifies the formal parameters to look for + in the text of the definition; NARGS is the number of args + in that list, or -1 for a macro name that wants no argument list. + MACRONAME is the macro name itself (so we can avoid recursive expansion) + and NAMELEN is its length in characters. + +Note that comments, backslash-newlines, and leading white space +have already been deleted from the argument. */ + +/* If there is no trailing whitespace, a Newline Space is added at the end + to prevent concatenation that would be contrary to the standard. */ + +static DEFINITION * +collect_expansion (buf, end, nargs, arglist) + U_CHAR *buf, *end; + int nargs; + struct arglist *arglist; +{ + DEFINITION *defn; + register U_CHAR *p, *limit, *lastp, *exp_p; + struct reflist *endpat = NULL; + /* Pointer to first nonspace after last ## seen. */ + U_CHAR *concat = 0; + /* Pointer to first nonspace after last single-# seen. */ + U_CHAR *stringify = 0; + /* How those tokens were spelled. */ + enum sharp_token_type concat_sharp_token_type = NO_SHARP_TOKEN; + enum sharp_token_type stringify_sharp_token_type = NO_SHARP_TOKEN; + int maxsize; + int expected_delimiter = '\0'; + + /* Scan thru the replacement list, ignoring comments and quoted + strings, picking up on the macro calls. It does a linear search + thru the arg list on every potential symbol. Profiling might say + that something smarter should happen. */ + + if (end < buf) + abort (); + + /* Find the beginning of the trailing whitespace. */ + limit = end; + p = buf; + while (p < limit && is_space[limit[-1]]) limit--; + + /* Allocate space for the text in the macro definition. + Each input char may or may not need 1 byte, + so this is an upper bound. + The extra 3 are for invented trailing newline-marker and final null. */ + maxsize = (sizeof (DEFINITION) + + (limit - p) + 3); + defn = (DEFINITION *) xcalloc (1, maxsize); + + defn->nargs = nargs; + exp_p = defn->expansion = (U_CHAR *) defn + sizeof (DEFINITION); + lastp = exp_p; + + if (p[0] == '#' + ? p[1] == '#' + : p[0] == '%' && p[1] == ':' && p[2] == '%' && p[3] == ':') { + error ("`##' at start of macro definition"); + p += p[0] == '#' ? 2 : 4; + } + + /* Process the main body of the definition. */ + while (p < limit) { + int skipped_arg = 0; + register U_CHAR c = *p++; + + *exp_p++ = c; + + if (!traditional) { + switch (c) { + case '\'': + case '\"': + if (expected_delimiter != '\0') { + if (c == expected_delimiter) + expected_delimiter = '\0'; + } else + expected_delimiter = c; + break; + + case '\\': + if (p < limit && expected_delimiter) { + /* In a string, backslash goes through + and makes next char ordinary. */ + *exp_p++ = *p++; + } + break; + + case '%': + if (!expected_delimiter && *p == ':') { + /* %: is not a digraph if preceded by an odd number of '<'s. */ + U_CHAR *p0 = p - 1; + while (buf < p0 && p0[-1] == '<') + p0--; + if ((p - p0) & 1) { + /* Treat %:%: as ## and %: as #. */ + if (p[1] == '%' && p[2] == ':') { + p += 2; + goto sharp_sharp_token; + } + if (nargs >= 0) { + p++; + goto sharp_token; + } + } + } + break; + + case '#': + /* # is ordinary inside a string. */ + if (expected_delimiter) + break; + if (*p == '#') { + sharp_sharp_token: + /* ##: concatenate preceding and following tokens. */ + /* Take out the first #, discard preceding whitespace. */ + exp_p--; + while (exp_p > lastp && is_hor_space[exp_p[-1]]) + --exp_p; + /* Skip the second #. */ + p++; + concat_sharp_token_type = c; + if (is_hor_space[*p]) { + concat_sharp_token_type = c + 1; + p++; + SKIP_WHITE_SPACE (p); + } + concat = p; + if (p == limit) + error ("`##' at end of macro definition"); + } else if (nargs >= 0) { + /* Single #: stringify following argument ref. + Don't leave the # in the expansion. */ + sharp_token: + exp_p--; + stringify_sharp_token_type = c; + if (is_hor_space[*p]) { + stringify_sharp_token_type = c + 1; + p++; + SKIP_WHITE_SPACE (p); + } + if (! is_idstart[*p] || nargs == 0 + || (*p == 'L' && (p[1] == '\'' || p[1] == '"'))) + error ("`#' operator is not followed by a macro argument name"); + else + stringify = p; + } + break; + } + } else { + /* In -traditional mode, recognize arguments inside strings and + character constants, and ignore special properties of #. + Arguments inside strings are considered "stringified", but no + extra quote marks are supplied. */ + switch (c) { + case '\'': + case '\"': + if (expected_delimiter != '\0') { + if (c == expected_delimiter) + expected_delimiter = '\0'; + } else + expected_delimiter = c; + break; + + case '\\': + /* Backslash quotes delimiters and itself, but not macro args. */ + if (expected_delimiter != 0 && p < limit + && (*p == expected_delimiter || *p == '\\')) { + *exp_p++ = *p++; + continue; + } + break; + + case '/': + if (expected_delimiter != '\0') /* No comments inside strings. */ + break; + if (*p == '*') { + /* If we find a comment that wasn't removed by handle_directive, + this must be -traditional. So replace the comment with + nothing at all. */ + exp_p--; + while (++p < limit) { + if (p[0] == '*' && p[1] == '/') { + p += 2; + break; + } + } +#if 0 + /* Mark this as a concatenation-point, as if it had been ##. */ + concat = p; +#endif + } + break; + } + } + +#ifdef MULTIBYTE_CHARS +/* CYGNUS LOCAL chill */ + if (! chill) +/* END CYGNUS LOCAL chill */ + { + /* Handle multibyte characters inside string and character literals. */ + if (expected_delimiter != '\0') + { + int length; + --p; + length = local_mblen (p, limit - p); + if (length > 1) + { + --exp_p; + bcopy (p, exp_p, length); + p += length; + exp_p += length; + continue; + } + ++p; + } + } +#endif + + /* Handle the start of a symbol. */ + if (is_idchar[c] && nargs > 0) { + U_CHAR *id_beg = p - 1; + int id_len; + + --exp_p; + while (p != limit && is_idchar[*p]) p++; + id_len = p - id_beg; + + if (is_idstart[c] + && ! (id_len == 1 && c == 'L' && (*p == '\'' || *p == '"'))) { + register struct arglist *arg; + + for (arg = arglist; arg != NULL; arg = arg->next) { + struct reflist *tpat; + + if (arg->name[0] == c + && arg->length == id_len + && bcmp (arg->name, id_beg, id_len) == 0) { + enum sharp_token_type tpat_stringify; + if (expected_delimiter) { + if (warn_stringify) { + if (traditional) { + warning ("macro argument `%.*s' is stringified.", + id_len, arg->name); + } else { + warning ("macro arg `%.*s' would be stringified with -traditional.", + id_len, arg->name); + } + } + /* If ANSI, don't actually substitute inside a string. */ + if (!traditional) + break; + tpat_stringify = SHARP_TOKEN; + } else { + tpat_stringify + = (stringify == id_beg + ? stringify_sharp_token_type : NO_SHARP_TOKEN); + } + /* make a pat node for this arg and append it to the end of + the pat list */ + tpat = (struct reflist *) xmalloc (sizeof (struct reflist)); + tpat->next = NULL; + tpat->raw_before + = concat == id_beg ? concat_sharp_token_type : NO_SHARP_TOKEN; + tpat->raw_after = NO_SHARP_TOKEN; + tpat->rest_args = arg->rest_args; + tpat->stringify = tpat_stringify; + + if (endpat == NULL) + defn->pattern = tpat; + else + endpat->next = tpat; + endpat = tpat; + + tpat->argno = arg->argno; + tpat->nchars = exp_p - lastp; + { + register U_CHAR *p1 = p; + SKIP_WHITE_SPACE (p1); + if (p1[0]=='#' + ? p1[1]=='#' + : p1[0]=='%' && p1[1]==':' && p1[2]=='%' && p1[3]==':') + tpat->raw_after = p1[0] + (p != p1); + } + lastp = exp_p; /* place to start copying from next time */ + skipped_arg = 1; + break; + } + } + } + + /* If this was not a macro arg, copy it into the expansion. */ + if (! skipped_arg) { + register U_CHAR *lim1 = p; + p = id_beg; + while (p != lim1) + *exp_p++ = *p++; + if (stringify == id_beg) + error ("`#' operator should be followed by a macro argument name"); + } + } + } + + if (!traditional && expected_delimiter == 0) { + /* If ANSI, put in a newline-space marker to prevent token pasting. + But not if "inside a string" (which in ANSI mode happens only for + -D option). */ + *exp_p++ = '\n'; + *exp_p++ = ' '; + } + + *exp_p = '\0'; + + defn->length = exp_p - defn->expansion; + + /* Crash now if we overrun the allocated size. */ + if (defn->length + 1 > maxsize) + abort (); + +#if 0 +/* This isn't worth the time it takes. */ + /* give back excess storage */ + defn->expansion = (U_CHAR *) xrealloc (defn->expansion, defn->length + 1); +#endif + + return defn; +} + +static int +do_assert (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op ATTRIBUTE_UNUSED; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + U_CHAR *bp; /* temp ptr into input buffer */ + U_CHAR *symname; /* remember where symbol name starts */ + int sym_length; /* and how long it is */ + struct arglist *tokens = NULL; + + if (pedantic && done_initializing && !instack[indepth].system_header_p) + pedwarn ("ANSI C does not allow `#assert'"); + + bp = buf; + + while (is_hor_space[*bp]) + bp++; + + symname = bp; /* remember where it starts */ + sym_length = check_macro_name (bp, "assertion"); + bp += sym_length; + /* #define doesn't do this, but we should. */ + SKIP_WHITE_SPACE (bp); + + /* Lossage will occur if identifiers or control tokens are broken + across lines using backslash. This is not the right place to take + care of that. */ + + if (*bp != '(') { + error ("missing token-sequence in `#assert'"); + return 1; + } + + { + int error_flag = 0; + + bp++; /* skip '(' */ + SKIP_WHITE_SPACE (bp); + + tokens = read_token_list (&bp, limit, &error_flag); + if (error_flag) + return 1; + if (tokens == 0) { + error ("empty token-sequence in `#assert'"); + return 1; + } + + ++bp; /* skip paren */ + SKIP_WHITE_SPACE (bp); + } + + /* If this name isn't already an assertion name, make it one. + Error if it was already in use in some other way. */ + + { + ASSERTION_HASHNODE *hp; + int hashcode = hashf (symname, sym_length, ASSERTION_HASHSIZE); + struct tokenlist_list *value + = (struct tokenlist_list *) xmalloc (sizeof (struct tokenlist_list)); + + hp = assertion_lookup (symname, sym_length, hashcode); + if (hp == NULL) { + if (sym_length == 7 && ! bcmp (symname, "defined", 7)) + error ("`defined' redefined as assertion"); + hp = assertion_install (symname, sym_length, hashcode); + } + + /* Add the spec'd token-sequence to the list of such. */ + value->tokens = tokens; + value->next = hp->value; + hp->value = value; + } + + return 0; +} + +static int +do_unassert (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op ATTRIBUTE_UNUSED; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + U_CHAR *bp; /* temp ptr into input buffer */ + U_CHAR *symname; /* remember where symbol name starts */ + int sym_length; /* and how long it is */ + + struct arglist *tokens = NULL; + int tokens_specified = 0; + + if (pedantic && done_initializing && !instack[indepth].system_header_p) + pedwarn ("ANSI C does not allow `#unassert'"); + + bp = buf; + + while (is_hor_space[*bp]) + bp++; + + symname = bp; /* remember where it starts */ + sym_length = check_macro_name (bp, "assertion"); + bp += sym_length; + /* #define doesn't do this, but we should. */ + SKIP_WHITE_SPACE (bp); + + /* Lossage will occur if identifiers or control tokens are broken + across lines using backslash. This is not the right place to take + care of that. */ + + if (*bp == '(') { + int error_flag = 0; + + bp++; /* skip '(' */ + SKIP_WHITE_SPACE (bp); + + tokens = read_token_list (&bp, limit, &error_flag); + if (error_flag) + return 1; + if (tokens == 0) { + error ("empty token list in `#unassert'"); + return 1; + } + + tokens_specified = 1; + + ++bp; /* skip paren */ + SKIP_WHITE_SPACE (bp); + } + + { + ASSERTION_HASHNODE *hp; + int hashcode = hashf (symname, sym_length, ASSERTION_HASHSIZE); + struct tokenlist_list *tail, *prev; + + hp = assertion_lookup (symname, sym_length, hashcode); + if (hp == NULL) + return 1; + + /* If no token list was specified, then eliminate this assertion + entirely. */ + if (! tokens_specified) { + struct tokenlist_list *next; + for (tail = hp->value; tail; tail = next) { + next = tail->next; + free_token_list (tail->tokens); + free (tail); + } + delete_assertion (hp); + } else { + /* If a list of tokens was given, then delete any matching list. */ + + tail = hp->value; + prev = 0; + while (tail) { + struct tokenlist_list *next = tail->next; + if (compare_token_lists (tail->tokens, tokens)) { + if (prev) + prev->next = next; + else + hp->value = tail->next; + free_token_list (tail->tokens); + free (tail); + } else { + prev = tail; + } + tail = next; + } + } + } + + return 0; +} + +/* Test whether there is an assertion named NAME + and optionally whether it has an asserted token list TOKENS. + NAME is not null terminated; its length is SYM_LENGTH. + If TOKENS_SPECIFIED is 0, then don't check for any token list. */ + +int +check_assertion (name, sym_length, tokens_specified, tokens) + U_CHAR *name; + int sym_length; + int tokens_specified; + struct arglist *tokens; +{ + ASSERTION_HASHNODE *hp; + int hashcode = hashf (name, sym_length, ASSERTION_HASHSIZE); + + if (pedantic && !instack[indepth].system_header_p) + pedwarn ("ANSI C does not allow testing assertions"); + + hp = assertion_lookup (name, sym_length, hashcode); + if (hp == NULL) + /* It is not an assertion; just return false. */ + return 0; + + /* If no token list was specified, then value is 1. */ + if (! tokens_specified) + return 1; + + { + struct tokenlist_list *tail; + + tail = hp->value; + + /* If a list of tokens was given, + then succeed if the assertion records a matching list. */ + + while (tail) { + if (compare_token_lists (tail->tokens, tokens)) + return 1; + tail = tail->next; + } + + /* Fail if the assertion has no matching list. */ + return 0; + } +} + +/* Compare two lists of tokens for equality including order of tokens. */ + +static int +compare_token_lists (l1, l2) + struct arglist *l1, *l2; +{ + while (l1 && l2) { + if (l1->length != l2->length) + return 0; + if (bcmp (l1->name, l2->name, l1->length)) + return 0; + l1 = l1->next; + l2 = l2->next; + } + + /* Succeed if both lists end at the same time. */ + return l1 == l2; +} + +/* Read a space-separated list of tokens ending in a close parenthesis. + Return a list of strings, in the order they were written. + (In case of error, return 0 and store -1 in *ERROR_FLAG.) + Parse the text starting at *BPP, and update *BPP. + Don't parse beyond LIMIT. */ + +static struct arglist * +read_token_list (bpp, limit, error_flag) + U_CHAR **bpp; + U_CHAR *limit; + int *error_flag; +{ + struct arglist *token_ptrs = 0; + U_CHAR *bp = *bpp; + int depth = 1; + + *error_flag = 0; + + /* Loop over the assertion value tokens. */ + while (depth > 0) { + struct arglist *temp; + int eofp = 0; + U_CHAR *beg = bp; + + /* Find the end of the token. */ + if (*bp == '(') { + bp++; + depth++; + } else if (*bp == ')') { + depth--; + if (depth == 0) + break; + bp++; + } else if (*bp == '"' || *bp == '\'') + bp = skip_quoted_string (bp, limit, 0, NULL_PTR, NULL_PTR, &eofp); + else + while (! is_hor_space[*bp] && *bp != '(' && *bp != ')' + && *bp != '"' && *bp != '\'' && bp != limit) + bp++; + + temp = (struct arglist *) xmalloc (sizeof (struct arglist)); + temp->name = (U_CHAR *) xmalloc (bp - beg + 1); + bcopy ((char *) beg, (char *) temp->name, bp - beg); + temp->name[bp - beg] = 0; + temp->next = token_ptrs; + token_ptrs = temp; + temp->length = bp - beg; + + SKIP_WHITE_SPACE (bp); + + if (bp >= limit) { + error ("unterminated token sequence in `#assert' or `#unassert'"); + *error_flag = -1; + return 0; + } + } + *bpp = bp; + + /* We accumulated the names in reverse order. + Now reverse them to get the proper order. */ + { + register struct arglist *prev = 0, *this, *next; + for (this = token_ptrs; this; this = next) { + next = this->next; + this->next = prev; + prev = this; + } + return prev; + } +} + +static void +free_token_list (tokens) + struct arglist *tokens; +{ + while (tokens) { + struct arglist *next = tokens->next; + free (tokens->name); + free (tokens); + tokens = next; + } +} + +/* Install a name in the assertion hash table. + + If LEN is >= 0, it is the length of the name. + Otherwise, compute the length by scanning the entire name. + + If HASH is >= 0, it is the precomputed hash code. + Otherwise, compute the hash code. */ + +static ASSERTION_HASHNODE * +assertion_install (name, len, hash) + U_CHAR *name; + int len; + int hash; +{ + register ASSERTION_HASHNODE *hp; + register int i, bucket; + register U_CHAR *p, *q; + + i = sizeof (ASSERTION_HASHNODE) + len + 1; + hp = (ASSERTION_HASHNODE *) xmalloc (i); + bucket = hash; + hp->bucket_hdr = &assertion_hashtab[bucket]; + hp->next = assertion_hashtab[bucket]; + assertion_hashtab[bucket] = hp; + hp->prev = NULL; + if (hp->next != NULL) + hp->next->prev = hp; + hp->length = len; + hp->value = 0; + hp->name = ((U_CHAR *) hp) + sizeof (ASSERTION_HASHNODE); + p = hp->name; + q = name; + for (i = 0; i < len; i++) + *p++ = *q++; + hp->name[len] = 0; + return hp; +} + +/* Find the most recent hash node for name "name" (ending with first + non-identifier char) installed by install + + If LEN is >= 0, it is the length of the name. + Otherwise, compute the length by scanning the entire name. + + If HASH is >= 0, it is the precomputed hash code. + Otherwise, compute the hash code. */ + +static ASSERTION_HASHNODE * +assertion_lookup (name, len, hash) + U_CHAR *name; + int len; + int hash; +{ + register ASSERTION_HASHNODE *bucket; + + bucket = assertion_hashtab[hash]; + while (bucket) { + if (bucket->length == len && bcmp (bucket->name, name, len) == 0) + return bucket; + bucket = bucket->next; + } + return NULL; +} + +static void +delete_assertion (hp) + ASSERTION_HASHNODE *hp; +{ + + if (hp->prev != NULL) + hp->prev->next = hp->next; + if (hp->next != NULL) + hp->next->prev = hp->prev; + + /* Make sure that the bucket chain header that the deleted guy was + on points to the right thing afterwards. */ + if (hp == *hp->bucket_hdr) + *hp->bucket_hdr = hp->next; + + free (hp); +} + +/* + * interpret #line directive. Remembers previously seen fnames + * in its very own hash table. + */ +#define FNAME_HASHSIZE 37 + +static int +do_line (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + register U_CHAR *bp; + FILE_BUF *ip = &instack[indepth]; + FILE_BUF tem; + int new_lineno; + enum file_change_code file_change = same_file; + + /* Expand any macros. */ + tem = expand_to_temp_buffer (buf, limit, 0, 0); + + /* Point to macroexpanded line, which is null-terminated now. */ + bp = tem.buf; + SKIP_WHITE_SPACE (bp); + + if (!ISDIGIT (*bp)) { + error ("invalid format `#line' directive"); + return 0; + } + + /* The Newline at the end of this line remains to be processed. + To put the next line at the specified line number, + we must store a line number now that is one less. */ + new_lineno = atoi ((char *) bp) - 1; + + /* NEW_LINENO is one less than the actual line number here. */ + if (pedantic && new_lineno < 0) + pedwarn ("line number out of range in `#line' directive"); + + /* skip over the line number. */ + while (ISDIGIT (*bp)) + bp++; + +#if 0 /* #line 10"foo.c" is supposed to be allowed. */ + if (*bp && !is_space[*bp]) { + error ("invalid format `#line' directive"); + return; + } +#endif + + SKIP_WHITE_SPACE (bp); + + if (*bp == '\"') { + static HASHNODE *fname_table[FNAME_HASHSIZE]; + HASHNODE *hp, **hash_bucket; + U_CHAR *fname, *p; + int fname_length; + + fname = ++bp; + + /* Turn the file name, which is a character string literal, + into a null-terminated string. Do this in place. */ + p = bp; + for (;;) + switch ((*p++ = *bp++)) { + case '\0': + error ("invalid format `#line' directive"); + return 0; + + case '\\': + if (! ignore_escape_flag) + { + char *bpc = (char *) bp; + HOST_WIDE_INT c = parse_escape (&bpc, (HOST_WIDE_INT) (U_CHAR) (-1)); + bp = (U_CHAR *) bpc; + if (c < 0) + p--; + else + p[-1] = c; + } + break; + + case '\"': + *--p = 0; + goto fname_done; + } + fname_done: + fname_length = p - fname; + + SKIP_WHITE_SPACE (bp); + if (*bp) { + if (pedantic) + pedwarn ("garbage at end of `#line' directive"); + if (*bp == '1') + file_change = enter_file; + else if (*bp == '2') + file_change = leave_file; + else if (*bp == '3') + ip->system_header_p = 1; + else if (*bp == '4') + ip->system_header_p = 2; + else { + error ("invalid format `#line' directive"); + return 0; + } + + bp++; + SKIP_WHITE_SPACE (bp); + if (*bp == '3') { + ip->system_header_p = 1; + bp++; + SKIP_WHITE_SPACE (bp); + } + if (*bp == '4') { + ip->system_header_p = 2; + bp++; + SKIP_WHITE_SPACE (bp); + } + if (*bp) { + error ("invalid format `#line' directive"); + return 0; + } + } + + hash_bucket = &fname_table[hashf (fname, fname_length, FNAME_HASHSIZE)]; + for (hp = *hash_bucket; hp != NULL; hp = hp->next) + if (hp->length == fname_length && + bcmp (hp->value.cpval, fname, fname_length) == 0) { + ip->nominal_fname = hp->value.cpval; + ip->nominal_fname_len = fname_length; + break; + } + if (hp == 0) { + /* Didn't find it; cons up a new one. */ + hp = (HASHNODE *) xcalloc (1, sizeof (HASHNODE) + fname_length + 1); + hp->next = *hash_bucket; + *hash_bucket = hp; + + ip->nominal_fname = hp->value.cpval = ((char *) hp) + sizeof (HASHNODE); + ip->nominal_fname_len = hp->length = fname_length; + bcopy (fname, hp->value.cpval, fname_length + 1); + } + } else if (*bp) { + error ("invalid format `#line' directive"); + return 0; + } + + ip->lineno = new_lineno; + output_line_directive (ip, op, 0, file_change); + check_expand (op, ip->length - (ip->bufp - ip->buf)); + return 0; +} + +/* Remove the definition of a symbol from the symbol table. + according to un*x /lib/cpp, it is not an error to undef + something that has no definitions, so it isn't one here either. */ + +static int +do_undef (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword; +{ + int sym_length; + HASHNODE *hp; + U_CHAR *orig_buf = buf; + + /* If this is a precompiler run (with -pcp) pass thru #undef directives. */ + if (pcp_outfile && op) + pass_thru_directive (buf, limit, op, keyword); + + SKIP_WHITE_SPACE (buf); + sym_length = check_macro_name (buf, "macro"); + + while ((hp = lookup (buf, sym_length, -1)) != NULL) { + /* If we are generating additional info for debugging (with -g) we + need to pass through all effective #undef directives. */ + if (debug_output && op) + pass_thru_directive (orig_buf, limit, op, keyword); + if (hp->type != T_MACRO) + warning ("undefining `%s'", hp->name); + delete_macro (hp); + } + + if (pedantic) { + buf += sym_length; + SKIP_WHITE_SPACE (buf); + if (buf != limit) + pedwarn ("garbage after `#undef' directive"); + } + return 0; +} + +/* Report an error detected by the program we are processing. + Use the text of the line in the error message. + (We use error because it prints the filename & line#.) */ + +static int +do_error (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op ATTRIBUTE_UNUSED; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + int length = limit - buf; + U_CHAR *copy = (U_CHAR *) alloca (length + 1); + bcopy ((char *) buf, (char *) copy, length); + copy[length] = 0; + SKIP_WHITE_SPACE (copy); + error ("#error %s", copy); + return 0; +} + +/* Report a warning detected by the program we are processing. + Use the text of the line in the warning message, then continue. + (We use error because it prints the filename & line#.) */ + +static int +do_warning (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op ATTRIBUTE_UNUSED; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + int length = limit - buf; + U_CHAR *copy = (U_CHAR *) alloca (length + 1); + bcopy ((char *) buf, (char *) copy, length); + copy[length] = 0; + SKIP_WHITE_SPACE (copy); + + if (pedantic && !instack[indepth].system_header_p) + pedwarn ("ANSI C does not allow `#warning'"); + + /* Use `pedwarn' not `warning', because #warning isn't in the C Standard; + if -pedantic-errors is given, #warning should cause an error. */ + pedwarn ("#warning %s", copy); + return 0; +} + +/* Remember the name of the current file being read from so that we can + avoid ever including it again. */ + +static void +do_once () +{ + int i; + + for (i = indepth; i >= 0; i--) + if (instack[i].inc) { + record_control_macro (instack[i].inc, (U_CHAR *) ""); + break; + } +} + +/* Report program identification. */ + +static int +do_ident (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + FILE_BUF trybuf; + int len; + + /* Allow #ident in system headers, since that's not user's fault. */ + if (pedantic && !instack[indepth].system_header_p) + pedwarn ("ANSI C does not allow `#ident'"); + + trybuf = expand_to_temp_buffer (buf, limit, 0, 0); + buf = trybuf.buf; + len = trybuf.bufp - buf; + + /* Output expanded directive. */ + check_expand (op, 7 + len); + bcopy ("#ident ", (char *) op->bufp, 7); + op->bufp += 7; + bcopy ((char *) buf, (char *) op->bufp, len); + op->bufp += len; + + free (buf); + return 0; +} + +/* #pragma and its argument line have already been copied to the output file. + Just check for some recognized pragmas that need validation here. */ + +static int +do_pragma (buf, limit, op, keyword) + U_CHAR *buf, *limit ATTRIBUTE_UNUSED; + FILE_BUF *op ATTRIBUTE_UNUSED; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + SKIP_WHITE_SPACE (buf); + if (!strncmp ((char *) buf, "once", 4)) { + /* Allow #pragma once in system headers, since that's not the user's + fault. */ + if (!instack[indepth].system_header_p) + warning ("`#pragma once' is obsolete"); + do_once (); + } + + if (!strncmp ((char *) buf, "implementation", 14)) { + /* Be quiet about `#pragma implementation' for a file only if it hasn't + been included yet. */ + + int h; + U_CHAR *p = buf + 14, *fname; + SKIP_WHITE_SPACE (p); + if (*p != '\"') + return 0; + + fname = p + 1; + if ((p = (U_CHAR *) index ((char *) fname, '\"'))) + *p = '\0'; + + for (h = 0; h < INCLUDE_HASHSIZE; h++) { + struct include_file *inc; + for (inc = include_hashtab[h]; inc; inc = inc->next) { + if (!strcmp (base_name (inc->fname), (char *) fname)) { + warning ("`#pragma implementation' for \"%s\" appears after its #include",fname); + return 0; + } + } + } + } + return 0; +} + +#if 0 +/* This was a fun hack, but #pragma seems to start to be useful. + By failing to recognize it, we pass it through unchanged to cc1. */ + +/* The behavior of the #pragma directive is implementation defined. + this implementation defines it as follows. */ + +static int +do_pragma () +{ + close (0); + if (open ("/dev/tty", O_RDONLY, 0666) != 0) + goto nope; + close (1); + if (open ("/dev/tty", O_WRONLY, 0666) != 1) + goto nope; + execl ("/usr/games/hack", "#pragma", 0); + execl ("/usr/games/rogue", "#pragma", 0); + execl ("/usr/new/emacs", "-f", "hanoi", "9", "-kill", 0); + execl ("/usr/local/emacs", "-f", "hanoi", "9", "-kill", 0); +nope: + fatal ("You are in a maze of twisty compiler features, all different"); +} +#endif + +#ifdef SCCS_DIRECTIVE + +/* Just ignore #sccs, on systems where we define it at all. */ + +static int +do_sccs (buf, limit, op, keyword) + U_CHAR *buf ATTRIBUTE_UNUSED, *limit ATTRIBUTE_UNUSED; + FILE_BUF *op ATTRIBUTE_UNUSED; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + if (pedantic) + pedwarn ("ANSI C does not allow `#sccs'"); + return 0; +} + +#endif /* defined (SCCS_DIRECTIVE) */ + +/* Handle #if directive by + 1) inserting special `defined' keyword into the hash table + that gets turned into 0 or 1 by special_symbol (thus, + if the luser has a symbol called `defined' already, it won't + work inside the #if directive) + 2) rescan the input into a temporary output buffer + 3) pass the output buffer to the yacc parser and collect a value + 4) clean up the mess left from steps 1 and 2. + 5) call conditional_skip to skip til the next #endif (etc.), + or not, depending on the value from step 3. */ + +static int +do_if (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + HOST_WIDE_INT value; + FILE_BUF *ip = &instack[indepth]; + + value = eval_if_expression (buf, limit - buf); + conditional_skip (ip, value == 0, T_IF, NULL_PTR, op); + return 0; +} + +/* Handle a #elif directive by not changing if_stack either. + see the comment above do_else. */ + +static int +do_elif (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + HOST_WIDE_INT value; + FILE_BUF *ip = &instack[indepth]; + + if (if_stack == instack[indepth].if_stack) { + error ("`#elif' not within a conditional"); + return 0; + } else { + if (if_stack->type != T_IF && if_stack->type != T_ELIF) { + error ("`#elif' after `#else'"); + fprintf (stderr, " (matches line %d", if_stack->lineno); + if (! (if_stack->fname_len == ip->nominal_fname_len + && !bcmp (if_stack->fname, ip->nominal_fname, + if_stack->fname_len))) { + fprintf (stderr, ", file "); + eprint_string (if_stack->fname, if_stack->fname_len); + } + fprintf (stderr, ")\n"); + } + if_stack->type = T_ELIF; + } + + if (if_stack->if_succeeded) + skip_if_group (ip, 0, op); + else { + value = eval_if_expression (buf, limit - buf); + if (value == 0) + skip_if_group (ip, 0, op); + else { + ++if_stack->if_succeeded; /* continue processing input */ + output_line_directive (ip, op, 1, same_file); + } + } + return 0; +} + +/* Evaluate a #if expression in BUF, of length LENGTH, then parse the + result as a C expression and return the value as an int. */ + +static HOST_WIDE_INT +eval_if_expression (buf, length) + U_CHAR *buf; + int length; +{ + FILE_BUF temp_obuf; + HASHNODE *save_defined; + HOST_WIDE_INT value; + + save_defined = install ((U_CHAR *) "defined", -1, T_SPEC_DEFINED, + NULL_PTR, -1); + pcp_inside_if = 1; + temp_obuf = expand_to_temp_buffer (buf, buf + length, 0, 1); + pcp_inside_if = 0; + delete_macro (save_defined); /* clean up special symbol */ + + temp_obuf.buf[temp_obuf.length] = '\n'; + value = parse_c_expression ((char *) temp_obuf.buf, + warn_undef && !instack[indepth].system_header_p); + + free (temp_obuf.buf); + + return value; +} + +/* routine to handle ifdef/ifndef. Try to look up the symbol, then do + or don't skip to the #endif/#else/#elif depending on what directive + is actually being processed. */ + +static int +do_xifdef (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword; +{ + int skip; + FILE_BUF *ip = &instack[indepth]; + U_CHAR *end; + int start_of_file = 0; + U_CHAR *control_macro = 0; + + /* Detect a #ifndef at start of file (not counting comments). */ + if (ip->fname != 0 && keyword->type == T_IFNDEF) { + U_CHAR *p = ip->buf; + while (p != directive_start) { + U_CHAR c = *p++; + if (is_space[c]) + ; + /* Make no special provision for backslash-newline here; this is + slower if backslash-newlines are present, but it's correct, + and it's not worth it to tune for the rare backslash-newline. */ + else if (c == '/' + && (*p == '*' || (cplusplus_comments && *p == '/'))) { + /* Skip this comment. */ + int junk = 0; + U_CHAR *save_bufp = ip->bufp; + ip->bufp = p + 1; + p = skip_to_end_of_comment (ip, &junk, 1); + ip->bufp = save_bufp; + } else { + goto fail; + } + } + /* If we get here, this conditional is the beginning of the file. */ + start_of_file = 1; + fail: ; + } + + /* Discard leading and trailing whitespace. */ + SKIP_WHITE_SPACE (buf); + while (limit != buf && is_hor_space[limit[-1]]) limit--; + + /* Find the end of the identifier at the beginning. */ + for (end = buf; is_idchar[*end]; end++); + + if (end == buf) { + skip = (keyword->type == T_IFDEF); + if (! traditional) + pedwarn (end == limit ? "`#%s' with no argument" + : "`#%s' argument starts with punctuation", + keyword->name); + } else { + HASHNODE *hp; + + if (! traditional) { + if (ISDIGIT (buf[0])) + pedwarn ("`#%s' argument starts with a digit", keyword->name); + else if (end != limit) + pedwarn ("garbage at end of `#%s' argument", keyword->name); + } + + hp = lookup (buf, end-buf, -1); + + if (pcp_outfile) { + /* Output a precondition for this macro. */ + if (hp + && (hp->type == T_CONST + || (hp->type == T_MACRO && hp->value.defn->predefined))) + fprintf (pcp_outfile, "#define %s\n", hp->name); + else { + U_CHAR *cp = buf; + fprintf (pcp_outfile, "#undef "); + while (is_idchar[*cp]) /* Ick! */ + fputc (*cp++, pcp_outfile); + putc ('\n', pcp_outfile); + } + } + + skip = (hp == NULL) ^ (keyword->type == T_IFNDEF); + if (start_of_file && !skip) { + control_macro = (U_CHAR *) xmalloc (end - buf + 1); + bcopy ((char *) buf, (char *) control_macro, end - buf); + control_macro[end - buf] = 0; + } + } + + conditional_skip (ip, skip, T_IF, control_macro, op); + return 0; +} + +/* Push TYPE on stack; then, if SKIP is nonzero, skip ahead. + If this is a #ifndef starting at the beginning of a file, + CONTROL_MACRO is the macro name tested by the #ifndef. + Otherwise, CONTROL_MACRO is 0. */ + +static void +conditional_skip (ip, skip, type, control_macro, op) + FILE_BUF *ip; + int skip; + enum node_type type; + U_CHAR *control_macro; + FILE_BUF *op; +{ + IF_STACK_FRAME *temp; + + temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME)); + temp->fname = ip->nominal_fname; + temp->fname_len = ip->nominal_fname_len; + temp->lineno = ip->lineno; + temp->next = if_stack; + temp->control_macro = control_macro; + if_stack = temp; + + if_stack->type = type; + + if (skip != 0) { + skip_if_group (ip, 0, op); + return; + } else { + ++if_stack->if_succeeded; + output_line_directive (ip, &outbuf, 1, same_file); + } +} + +/* Skip to #endif, #else, or #elif. adjust line numbers, etc. + Leaves input ptr at the sharp sign found. + If ANY is nonzero, return at next directive of any sort. */ + +static void +skip_if_group (ip, any, op) + FILE_BUF *ip; + int any; + FILE_BUF *op; +{ + register U_CHAR *bp = ip->bufp, *cp; + register U_CHAR *endb = ip->buf + ip->length; + struct directive *kt; + IF_STACK_FRAME *save_if_stack = if_stack; /* don't pop past here */ + U_CHAR *beg_of_line = bp; + register int ident_length; + U_CHAR *ident, *after_ident; + /* Save info about where the group starts. */ + U_CHAR *beg_of_group = bp; + int beg_lineno = ip->lineno; + int skipping_include_directive = 0; + + if (output_conditionals && op != 0) { + char *ptr = "#failed\n"; + int len = strlen (ptr); + + if (op->bufp > op->buf && op->bufp[-1] != '\n') + { + *op->bufp++ = '\n'; + op->lineno++; + } + check_expand (op, len); + bcopy (ptr, (char *) op->bufp, len); + op->bufp += len; + op->lineno++; + output_line_directive (ip, op, 1, 0); + } + + while (bp < endb) { + switch (*bp++) { + case '/': /* possible comment */ + if (*bp == '\\' && bp[1] == '\n') + newline_fix (bp); + if (*bp == '*' + || (cplusplus_comments && *bp == '/')) { + ip->bufp = ++bp; + bp = skip_to_end_of_comment (ip, &ip->lineno, 0); + } + break; + case '<': + if (skipping_include_directive) { + while (bp < endb && *bp != '>' && *bp != '\n') { + if (*bp == '\\' && bp[1] == '\n') { + ip->lineno++; + bp++; + } + bp++; + } + } + break; + case '\"': + if (skipping_include_directive) { + while (bp < endb && *bp != '\n') { + if (*bp == '"') { + bp++; + break; + } + if (*bp == '\\' && bp[1] == '\n') { + ip->lineno++; + bp++; + } + bp++; + } + break; + } + /* Fall through. */ + case '\'': + bp = skip_quoted_string (bp - 1, endb, ip->lineno, &ip->lineno, + NULL_PTR, NULL_PTR); + break; + case '\\': + /* Char after backslash loses its special meaning in some cases. */ + if (*bp == '\n') { + ++ip->lineno; + bp++; + } else if (traditional && bp < endb) + bp++; + break; + case '\n': + ++ip->lineno; + beg_of_line = bp; + skipping_include_directive = 0; + break; + case '%': + if (beg_of_line == 0 || traditional) + break; + ip->bufp = bp - 1; + while (bp[0] == '\\' && bp[1] == '\n') + bp += 2; + if (*bp == ':') + goto sharp_token; + break; + case '#': + /* # keyword: a # must be first nonblank char on the line */ + if (beg_of_line == 0) + break; + ip->bufp = bp - 1; + sharp_token: + /* Scan from start of line, skipping whitespace, comments + and backslash-newlines, and see if we reach this #. + If not, this # is not special. */ + bp = beg_of_line; + /* If -traditional, require # to be at beginning of line. */ + if (!traditional) { + while (1) { + if (is_hor_space[*bp]) + bp++; + else if (*bp == '\\' && bp[1] == '\n') + bp += 2; + else if (*bp == '/' && bp[1] == '*') { + bp += 2; + while (1) + { + if (*bp == '*') + { + if (bp[1] == '/') + { + bp += 2; + break; + } + } + else + { +#ifdef MULTIBYTE_CHARS + /* CYGNUS LOCAL chill */ + if (! chill) + /* END CYGNUS LOCAL chill */ + { + int length; + length = local_mblen (bp, endb - bp); + if (length > 1) + bp += (length - 1); + } +#endif + } + bp++; + } + } + /* There is no point in trying to deal with C++ // comments here, + because if there is one, then this # must be part of the + comment and we would never reach here. */ + else break; + } + } + if (bp != ip->bufp) { + bp = ip->bufp + 1; /* Reset bp to after the #. */ + break; + } + + bp = ip->bufp + 1; /* Point after the '#' */ + if (ip->bufp[0] == '%') { + /* Skip past the ':' again. */ + while (*bp == '\\') { + ip->lineno++; + bp += 2; + } + bp++; + } + + /* Skip whitespace and \-newline. */ + while (1) { + if (is_hor_space[*bp]) + bp++; + else if (*bp == '\\' && bp[1] == '\n') + bp += 2; + else if (*bp == '/') { + if (bp[1] == '\\' && bp[2] == '\n') + newline_fix (bp + 1); + if (bp[1] == '*') { + for (bp += 2; ; bp++) { + if (*bp == '\n') + ip->lineno++; + else if (*bp == '*') { + if (bp[-1] == '/' && warn_comments) + warning ("`/*' within comment"); + if (bp[1] == '\\' && bp[2] == '\n') + newline_fix (bp + 1); + if (bp[1] == '/') + break; + } + else + { +#ifdef MULTIBYTE_CHARS + /* CYGNUS LOCAL chill */ + if (! chill) + /* END CYGNUS LOCAL chill */ + { + int length; + length = local_mblen (bp, endb - bp); + if (length > 1) + bp += (length - 1); + } +#endif + } + } + bp += 2; + } else if (bp[1] == '/' && cplusplus_comments) { + for (bp += 2; ; bp++) { + if (*bp == '\n') + break; + if (*bp == '\\' && bp[1] == '\n') + { + if (warn_comments) + warning ("multiline `//' comment"); + ip->lineno++; + bp++; + } + else + { +#ifdef MULTIBYTE_CHARS + /* CYGNUS LOCAL chill */ + if (! chill) + /* END CYGNUS LOCAL chill */ + { + int length; + length = local_mblen (bp, endb - bp); + if (length > 1) + bp += (length - 1); + } +#endif + } + } + } else + break; + } else + break; + } + + cp = bp; + + /* Now find end of directive name. + If we encounter a backslash-newline, exchange it with any following + symbol-constituents so that we end up with a contiguous name. */ + + while (1) { + if (is_idchar[*bp]) + bp++; + else { + if (*bp == '\\' && bp[1] == '\n') + name_newline_fix (bp); + if (is_idchar[*bp]) + bp++; + else break; + } + } + ident_length = bp - cp; + ident = cp; + after_ident = bp; + + /* A line of just `#' becomes blank. */ + + if (ident_length == 0 && *after_ident == '\n') { + continue; + } + + if (ident_length == 0 || !is_idstart[*ident]) { + U_CHAR *p = ident; + while (is_idchar[*p]) { + if (*p < '0' || *p > '9') + break; + p++; + } + /* Handle # followed by a line number. */ + if (p != ident && !is_idchar[*p]) { + if (pedantic) + pedwarn ("`#' followed by integer"); + continue; + } + + /* Avoid error for `###' and similar cases unless -pedantic. */ + if (p == ident) { + while (*p == '#' || is_hor_space[*p]) p++; + if (*p == '\n') { + if (pedantic && !lang_asm) + pedwarn ("invalid preprocessing directive"); + continue; + } + } + + if (!lang_asm && pedantic) + pedwarn ("invalid preprocessing directive name"); + continue; + } + + for (kt = directive_table; kt->length >= 0; kt++) { + IF_STACK_FRAME *temp; + if (ident_length == kt->length + && bcmp (cp, kt->name, kt->length) == 0) { + /* If we are asked to return on next directive, do so now. */ + if (any) + goto done; + + switch (kt->type) { + case T_IF: + case T_IFDEF: + case T_IFNDEF: + temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME)); + temp->next = if_stack; + if_stack = temp; + temp->lineno = ip->lineno; + temp->fname = ip->nominal_fname; + temp->fname_len = ip->nominal_fname_len; + temp->type = kt->type; + break; + case T_ELSE: + case T_ENDIF: + if (pedantic && if_stack != save_if_stack) + validate_else (bp, endb); + case T_ELIF: + if (if_stack == instack[indepth].if_stack) { + error ("`#%s' not within a conditional", kt->name); + break; + } + else if (if_stack == save_if_stack) + goto done; /* found what we came for */ + + if (kt->type != T_ENDIF) { + if (if_stack->type == T_ELSE) + error ("`#else' or `#elif' after `#else'"); + if_stack->type = kt->type; + break; + } + + temp = if_stack; + if_stack = if_stack->next; + free (temp); + break; + + case T_INCLUDE: + case T_INCLUDE_NEXT: + case T_IMPORT: + skipping_include_directive = 1; + break; + + default: + break; + } + break; + } + } + /* Don't let erroneous code go by. */ + if (kt->length < 0 && !lang_asm && pedantic) + pedwarn ("invalid preprocessing directive name"); + } + } + + ip->bufp = bp; + /* after this returns, rescan will exit because ip->bufp + now points to the end of the buffer. + rescan is responsible for the error message also. */ + + done: + if (output_conditionals && op != 0) { + char *ptr = "#endfailed\n"; + int len = strlen (ptr); + + if (op->bufp > op->buf && op->bufp[-1] != '\n') + { + *op->bufp++ = '\n'; + op->lineno++; + } + check_expand (op, beg_of_line - beg_of_group); + bcopy ((char *) beg_of_group, (char *) op->bufp, + beg_of_line - beg_of_group); + op->bufp += beg_of_line - beg_of_group; + op->lineno += ip->lineno - beg_lineno; + check_expand (op, len); + bcopy (ptr, (char *) op->bufp, len); + op->bufp += len; + op->lineno++; + } +} + +/* Handle a #else directive. Do this by just continuing processing + without changing if_stack ; this is so that the error message + for missing #endif's etc. will point to the original #if. It + is possible that something different would be better. */ + +static int +do_else (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + FILE_BUF *ip = &instack[indepth]; + + if (pedantic) { + SKIP_WHITE_SPACE (buf); + if (buf != limit) + pedwarn ("text following `#else' violates ANSI standard"); + } + + if (if_stack == instack[indepth].if_stack) { + error ("`#else' not within a conditional"); + return 0; + } else { + /* #ifndef can't have its special treatment for containing the whole file + if it has a #else clause. */ + if_stack->control_macro = 0; + + if (if_stack->type != T_IF && if_stack->type != T_ELIF) { + error ("`#else' after `#else'"); + fprintf (stderr, " (matches line %d", if_stack->lineno); + if (! (if_stack->fname_len == ip->nominal_fname_len + && !bcmp (if_stack->fname, ip->nominal_fname, + if_stack->fname_len))) { + fprintf (stderr, ", file "); + eprint_string (if_stack->fname, if_stack->fname_len); + } + fprintf (stderr, ")\n"); + } + if_stack->type = T_ELSE; + } + + if (if_stack->if_succeeded) + skip_if_group (ip, 0, op); + else { + ++if_stack->if_succeeded; /* continue processing input */ + output_line_directive (ip, op, 1, same_file); + } + return 0; +} + +/* Unstack after #endif directive. */ + +static int +do_endif (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + if (pedantic) { + SKIP_WHITE_SPACE (buf); + if (buf != limit) + pedwarn ("text following `#endif' violates ANSI standard"); + } + + if (if_stack == instack[indepth].if_stack) + error ("unbalanced `#endif'"); + else { + IF_STACK_FRAME *temp = if_stack; + if_stack = if_stack->next; + if (temp->control_macro != 0) { + /* This #endif matched a #ifndef at the start of the file. + See if it is at the end of the file. */ + FILE_BUF *ip = &instack[indepth]; + U_CHAR *p = ip->bufp; + U_CHAR *ep = ip->buf + ip->length; + + while (p != ep) { + U_CHAR c = *p++; + if (!is_space[c]) { + if (c == '/' + && (*p == '*' || (cplusplus_comments && *p == '/'))) { + /* Skip this comment. */ + int junk = 0; + U_CHAR *save_bufp = ip->bufp; + ip->bufp = p + 1; + p = skip_to_end_of_comment (ip, &junk, 1); + ip->bufp = save_bufp; + } else + goto fail; + } + } + /* If we get here, this #endif ends a #ifndef + that contains all of the file (aside from whitespace). + Arrange not to include the file again + if the macro that was tested is defined. + + Do not do this for the top-level file in a -include or any + file in a -imacros. */ + if (indepth != 0 + && ! (indepth == 1 && no_record_file) + && ! (no_record_file && no_output)) + record_control_macro (ip->inc, temp->control_macro); + fail: ; + } + free (temp); + output_line_directive (&instack[indepth], op, 1, same_file); + } + return 0; +} + +/* When an #else or #endif is found while skipping failed conditional, + if -pedantic was specified, this is called to warn about text after + the directive name. P points to the first char after the directive + name. */ + +static void +validate_else (p, limit) + register U_CHAR *p; + register U_CHAR *limit; +{ + /* Advance P over whitespace and comments. */ + while (1) { + while (*p == '\\' && p[1] == '\n') + p += 2; + if (is_hor_space[*p]) + p++; + else if (*p == '/') { + while (p[1] == '\\' && p[2] == '\n') + p += 2; + if (p[1] == '*') { + /* Don't bother warning about unterminated comments + since that will happen later. Just be sure to exit. */ + for (p += 2; ; p++) { + if (p == limit) + return; + if (*p == '*') { + while (p[1] == '\\' && p[2] == '\n') + p += 2; + if (p[1] == '/') { + p += 2; + break; + } + } + else + { +#ifdef MULTIBYTE_CHARS + /* CYGNUS LOCAL chill */ + if (! chill) + /* END CYGNUS LOCAL chill */ + { + int length; + length = local_mblen (p, limit - p); + if (length > 1) + p += (length - 1); + } +#endif + } + } + } + else if (cplusplus_comments && p[1] == '/') + return; + else break; + } else break; + } + if (*p != '\n') + pedwarn ("text following `#else' or `#endif' violates ANSI standard"); +} + +/* Skip a comment, assuming the input ptr immediately follows the + initial slash-star. Bump *LINE_COUNTER for each newline. + (The canonical line counter is &ip->lineno.) + Don't use this routine (or the next one) if bumping the line + counter is not sufficient to deal with newlines in the string. + + If NOWARN is nonzero, don't warn about slash-star inside a comment. + This feature is useful when processing a comment that is going to + be processed or was processed at another point in the preprocessor, + to avoid a duplicate warning. Likewise for unterminated comment + errors. */ + +static U_CHAR * +skip_to_end_of_comment (ip, line_counter, nowarn) + register FILE_BUF *ip; + int *line_counter; /* place to remember newlines, or NULL */ + int nowarn; +{ + register U_CHAR *limit = ip->buf + ip->length; + register U_CHAR *bp = ip->bufp; + FILE_BUF *op = put_out_comments && !line_counter ? &outbuf : (FILE_BUF *) 0; + int start_line = line_counter ? *line_counter : 0; + + /* JF this line_counter stuff is a crock to make sure the + comment is only put out once, no matter how many times + the comment is skipped. It almost works */ + if (op) { + *op->bufp++ = '/'; + *op->bufp++ = bp[-1]; + } + if (cplusplus_comments && bp[-1] == '/') { + for (; bp < limit; bp++) { + if (*bp == '\n') + break; + if (*bp == '\\' && bp + 1 < limit && bp[1] == '\n') + { + if (!nowarn && warn_comments) + warning ("multiline `//' comment"); + if (line_counter) + ++*line_counter; + if (op) + { + ++op->lineno; + *op->bufp++ = *bp; + } + ++bp; + } + else + { +#ifdef MULTIBYTE_CHARS + /* CYGNUS LOCAL chill */ + if (! chill) + /* END CYGNUS LOCAL chill */ + { + int length; + length = local_mblen (bp, limit - bp); + if (length > 1) + { + if (op) + { + bcopy (bp, op->bufp, length - 1); + op->bufp += (length - 1); + } + bp += (length - 1); + } + } +#endif + } + if (op) + *op->bufp++ = *bp; + } + ip->bufp = bp; + return bp; + } + while (bp < limit) { + if (op) + *op->bufp++ = *bp; + switch (*bp++) { + case '\n': + /* If this is the end of the file, we have an unterminated comment. + Don't swallow the newline. We are guaranteed that there will be a + trailing newline and various pieces assume it's there. */ + if (bp == limit) + { + --bp; + --limit; + break; + } + if (line_counter != NULL) + ++*line_counter; + if (op) + ++op->lineno; + break; + case '*': + if (bp[-2] == '/' && !nowarn && warn_comments) + warning ("`/*' within comment"); + if (*bp == '\\' && bp[1] == '\n') + newline_fix (bp); + if (*bp == '/') { + if (op) + *op->bufp++ = '/'; + ip->bufp = ++bp; + return bp; + } + break; +#ifdef MULTIBYTE_CHARS + default: + /* CYGNUS LOCAL chill */ + if (! chill) + /* END CYGNUS LOCAL chill */ + { + int length; + bp--; + length = local_mblen (bp, limit - bp); + if (length <= 0) + length = 1; + if (op) + { + op->bufp--; + bcopy (bp, op->bufp, length); + op->bufp += length; + } + bp += length; + } +#endif + } + } + + if (!nowarn) + error_with_line (line_for_error (start_line), "unterminated comment"); + ip->bufp = bp; + return bp; +} + +/* Skip over a quoted string. BP points to the opening quote. + Returns a pointer after the closing quote. Don't go past LIMIT. + START_LINE is the line number of the starting point (but it need + not be valid if the starting point is inside a macro expansion). + + The input stack state is not changed. + + If COUNT_NEWLINES is nonzero, it points to an int to increment + for each newline passed. + + If BACKSLASH_NEWLINES_P is nonzero, store 1 thru it + if we pass a backslash-newline. + + If EOFP is nonzero, set *EOFP to 1 if the string is unterminated. */ + +static U_CHAR * +skip_quoted_string (bp, limit, start_line, count_newlines, backslash_newlines_p, eofp) + register U_CHAR *bp; + register U_CHAR *limit; + int start_line; + int *count_newlines; + int *backslash_newlines_p; + int *eofp; +{ + register U_CHAR c, match; + + match = *bp++; + while (1) { + if (bp >= limit) { + error_with_line (line_for_error (start_line), + "unterminated string or character constant"); + error_with_line (multiline_string_line, + "possible real start of unterminated constant"); + multiline_string_line = 0; + if (eofp) + *eofp = 1; + break; + } + c = *bp++; + if (c == '\\') { + while (*bp == '\\' && bp[1] == '\n') { + if (backslash_newlines_p) + *backslash_newlines_p = 1; + if (count_newlines) + ++*count_newlines; + bp += 2; + } + if (*bp == '\n') { + if (backslash_newlines_p) + *backslash_newlines_p = 1; + if (count_newlines) + ++*count_newlines; + } + bp++; + } else if (c == '\n') { + if (traditional +/* CYGNUS LOCAL chill */ + || chill +/* END CYGNUS LOCAL chill */ + ) { + /* Unterminated strings and character constants are 'valid'. */ + bp--; /* Don't consume the newline. */ + if (eofp) + *eofp = 1; + break; + } + if (match == '\'') { + error_with_line (line_for_error (start_line), + "unterminated string or character constant"); + bp--; + if (eofp) + *eofp = 1; + break; + } + /* If not traditional, then allow newlines inside strings. */ + if (count_newlines) + ++*count_newlines; + if (multiline_string_line == 0) { + if (pedantic) + pedwarn_with_line (line_for_error (start_line), + "string constant runs past end of line"); + multiline_string_line = start_line; + } + } else if (c == match) + break; +#ifdef MULTIBYTE_CHARS +/* CYGNUS LOCAL chill */ + else if (! chill) +/* END CYGNUS LOCAL chill */ + { + int length; + --bp; + length = local_mblen (bp, limit - bp); + if (length <= 0) + length = 1; + bp += length; + } +#endif + } + return bp; +} + +/* Place into DST a quoted string representing the string SRC. + SRCLEN is the length of SRC; SRC may contain null bytes. + Return the address of DST's terminating null. */ + +static char * +quote_string (dst, src, srclen) + char *dst, *src; + size_t srclen; +{ + U_CHAR c; + char *srclim = src + srclen; + + *dst++ = '\"'; + while (src != srclim) + switch ((c = *src++)) + { + default: + if (ISPRINT (c)) + *dst++ = c; + else + { + sprintf (dst, "\\%03o", c); + dst += 4; + } + break; + + case '\"': + case '\\': + *dst++ = '\\'; + *dst++ = c; + break; + } + + *dst++ = '\"'; + *dst = '\0'; + return dst; +} + +/* Skip across a group of balanced parens, starting from IP->bufp. + IP->bufp is updated. Use this with IP->bufp pointing at an open-paren. + + This does not handle newlines, because it's used for the arg of #if, + where there aren't any newlines. Also, backslash-newline can't appear. */ + +static U_CHAR * +skip_paren_group (ip) + register FILE_BUF *ip; +{ + U_CHAR *limit = ip->buf + ip->length; + U_CHAR *p = ip->bufp; + int depth = 0; + int lines_dummy = 0; + + while (p != limit) { + int c = *p++; + switch (c) { + case '(': + depth++; + break; + + case ')': + depth--; + if (depth == 0) + return ip->bufp = p; + break; + + case '/': + if (*p == '*') { + ip->bufp = p; + p = skip_to_end_of_comment (ip, &lines_dummy, 0); + p = ip->bufp; + } + + case '"': + case '\'': + { + int eofp = 0; + p = skip_quoted_string (p - 1, limit, 0, NULL_PTR, NULL_PTR, &eofp); + if (eofp) + return ip->bufp = p; + } + break; + } + } + + ip->bufp = p; + return p; +} + +/* Write out a #line directive, for instance, after an #include file. + If CONDITIONAL is nonzero, we can omit the #line if it would + appear to be a no-op, and we can output a few newlines instead + if we want to increase the line number by a small amount. + FILE_CHANGE says whether we are entering a file, leaving, or neither. */ + +static void +output_line_directive (ip, op, conditional, file_change) + FILE_BUF *ip, *op; + int conditional; + enum file_change_code file_change; +{ + int len; + char *line_directive_buf, *line_end; + + if (no_line_directives + || ip->fname == NULL + || no_output) { + op->lineno = ip->lineno; + return; + } + + if (conditional) { + if (ip->lineno == op->lineno) + return; + + /* If the inherited line number is a little too small, + output some newlines instead of a #line directive. */ + if (ip->lineno > op->lineno && ip->lineno < op->lineno + 8) { + check_expand (op, 10); + while (ip->lineno > op->lineno) { + *op->bufp++ = '\n'; + op->lineno++; + } + return; + } + } + + /* Output a positive line number if possible. */ + while (ip->lineno <= 0 && ip->bufp - ip->buf < ip->length + && *ip->bufp == '\n') { + ip->lineno++; + ip->bufp++; + } + + line_directive_buf = (char *) alloca (4 * ip->nominal_fname_len + 100); + sprintf (line_directive_buf, "# %d ", ip->lineno); + line_end = quote_string (line_directive_buf + strlen (line_directive_buf), + ip->nominal_fname, ip->nominal_fname_len); + if (file_change != same_file) { + *line_end++ = ' '; + *line_end++ = file_change == enter_file ? '1' : '2'; + } + /* Tell cc1 if following text comes from a system header file. */ + if (ip->system_header_p) { + *line_end++ = ' '; + *line_end++ = '3'; + } +#ifndef NO_IMPLICIT_EXTERN_C + /* Tell cc1plus if following text should be treated as C. */ + if (ip->system_header_p == 2 && cplusplus) { + *line_end++ = ' '; + *line_end++ = '4'; + } +#endif + *line_end++ = '\n'; + len = line_end - line_directive_buf; + check_expand (op, len + 1); + if (op->bufp > op->buf && op->bufp[-1] != '\n') + *op->bufp++ = '\n'; + bcopy ((char *) line_directive_buf, (char *) op->bufp, len); + op->bufp += len; + op->lineno = ip->lineno; +} + +/* This structure represents one parsed argument in a macro call. + `raw' points to the argument text as written (`raw_length' is its length). + `expanded' points to the argument's macro-expansion + (its length is `expand_length'). + `stringified_length' is the length the argument would have + if stringified. + `use_count' is the number of times this macro arg is substituted + into the macro. If the actual use count exceeds 10, + the value stored is 10. + `free1' and `free2', if nonzero, point to blocks to be freed + when the macro argument data is no longer needed. */ + +struct argdata { + U_CHAR *raw, *expanded; + int raw_length, expand_length; + int stringified_length; + U_CHAR *free1, *free2; + char newlines; + char use_count; +}; + +/* Expand a macro call. + HP points to the symbol that is the macro being called. + Put the result of expansion onto the input stack + so that subsequent input by our caller will use it. + + If macro wants arguments, caller has already verified that + an argument list follows; arguments come from the input stack. */ + +static void +macroexpand (hp, op) + HASHNODE *hp; + FILE_BUF *op; +{ + int nargs; + DEFINITION *defn = hp->value.defn; + register U_CHAR *xbuf; + int xbuf_len; + int start_line = instack[indepth].lineno; + int rest_args, rest_zero; + + CHECK_DEPTH (return;); + + /* it might not actually be a macro. */ + if (hp->type != T_MACRO) { + special_symbol (hp, op); + return; + } + + /* This macro is being used inside a #if, which means it must be */ + /* recorded as a precondition. */ + if (pcp_inside_if && pcp_outfile && defn->predefined) + dump_single_macro (hp, pcp_outfile); + + nargs = defn->nargs; + + if (nargs >= 0) { + register int i; + struct argdata *args; + char *parse_error = 0; + + args = (struct argdata *) alloca ((nargs + 1) * sizeof (struct argdata)); + + for (i = 0; i < nargs; i++) { + args[i].raw = (U_CHAR *) ""; + args[i].expanded = 0; + args[i].raw_length = args[i].expand_length + = args[i].stringified_length = 0; + args[i].free1 = args[i].free2 = 0; + args[i].use_count = 0; + } + + /* Parse all the macro args that are supplied. I counts them. + The first NARGS args are stored in ARGS. + The rest are discarded. + If rest_args is set then we assume macarg absorbed the rest of the args. + */ + i = 0; + rest_args = 0; + do { + /* Discard the open-parenthesis or comma before the next arg. */ + ++instack[indepth].bufp; + if (rest_args) + continue; + if (i < nargs || (nargs == 0 && i == 0)) { + /* If we are working on last arg which absorbs rest of args... */ + if (i == nargs - 1 && defn->rest_args) + rest_args = 1; + parse_error = macarg (&args[i], rest_args); + } + else + parse_error = macarg (NULL_PTR, 0); + if (parse_error) { + error_with_line (line_for_error (start_line), parse_error); + break; + } + i++; + } while (*instack[indepth].bufp != ')'); + + /* If we got one arg but it was just whitespace, call that 0 args. */ + if (i == 1) { + register U_CHAR *bp = args[0].raw; + register U_CHAR *lim = bp + args[0].raw_length; + /* cpp.texi says for foo ( ) we provide one argument. + However, if foo wants just 0 arguments, treat this as 0. */ + if (nargs == 0) + while (bp != lim && is_space[*bp]) bp++; + if (bp == lim) + i = 0; + } + + /* Don't output an error message if we have already output one for + a parse error above. */ + rest_zero = 0; + if (nargs == 0 && i > 0) { + if (! parse_error) + error ("arguments given to macro `%s'", hp->name); + } else if (i < nargs) { + /* traditional C allows foo() if foo wants one argument. */ + if (nargs == 1 && i == 0 && traditional) + ; + /* the rest args token is allowed to absorb 0 tokens */ + else if (i == nargs - 1 && defn->rest_args) + rest_zero = 1; + else if (parse_error) + ; + else if (i == 0) + error ("macro `%s' used without args", hp->name); + else if (i == 1) + error ("macro `%s' used with just one arg", hp->name); + else + error ("macro `%s' used with only %d args", hp->name, i); + } else if (i > nargs) { + if (! parse_error) + error ("macro `%s' used with too many (%d) args", hp->name, i); + } + + /* Swallow the closeparen. */ + ++instack[indepth].bufp; + + /* If macro wants zero args, we parsed the arglist for checking only. + Read directly from the macro definition. */ + if (nargs == 0) { + xbuf = defn->expansion; + xbuf_len = defn->length; + } else { + register U_CHAR *exp = defn->expansion; + register int offset; /* offset in expansion, + copied a piece at a time */ + register int totlen; /* total amount of exp buffer filled so far */ + + register struct reflist *ap, *last_ap; + + /* Macro really takes args. Compute the expansion of this call. */ + + /* Compute length in characters of the macro's expansion. + Also count number of times each arg is used. */ + xbuf_len = defn->length; + for (ap = defn->pattern; ap != NULL; ap = ap->next) { + if (ap->stringify) + xbuf_len += args[ap->argno].stringified_length; + else if (ap->raw_before != 0 || ap->raw_after != 0 || traditional) + /* Add 4 for two newline-space markers to prevent + token concatenation. */ + xbuf_len += args[ap->argno].raw_length + 4; + else { + /* We have an ordinary (expanded) occurrence of the arg. + So compute its expansion, if we have not already. */ + if (args[ap->argno].expanded == 0) { + FILE_BUF obuf; + obuf = expand_to_temp_buffer (args[ap->argno].raw, + args[ap->argno].raw + args[ap->argno].raw_length, + 1, 0); + + args[ap->argno].expanded = obuf.buf; + args[ap->argno].expand_length = obuf.length; + args[ap->argno].free2 = obuf.buf; + } + + /* Add 4 for two newline-space markers to prevent + token concatenation. */ + xbuf_len += args[ap->argno].expand_length + 4; + } + if (args[ap->argno].use_count < 10) + args[ap->argno].use_count++; + } + + xbuf = (U_CHAR *) xmalloc (xbuf_len + 1); + + /* Generate in XBUF the complete expansion + with arguments substituted in. + TOTLEN is the total size generated so far. + OFFSET is the index in the definition + of where we are copying from. */ + offset = totlen = 0; + for (last_ap = NULL, ap = defn->pattern; ap != NULL; + last_ap = ap, ap = ap->next) { + register struct argdata *arg = &args[ap->argno]; + int count_before = totlen; + + /* Add chars to XBUF. */ + for (i = 0; i < ap->nchars; i++, offset++) + xbuf[totlen++] = exp[offset]; + + /* If followed by an empty rest arg with concatenation, + delete the last run of nonwhite chars. */ + if (rest_zero && totlen > count_before + && ((ap->rest_args && ap->raw_before != 0) + || (last_ap != NULL && last_ap->rest_args + && last_ap->raw_after != 0))) { + /* Delete final whitespace. */ + while (totlen > count_before && is_space[xbuf[totlen - 1]]) { + totlen--; + } + + /* Delete the nonwhites before them. */ + while (totlen > count_before && ! is_space[xbuf[totlen - 1]]) { + totlen--; + } + } + + if (ap->stringify != 0) { + int arglen = arg->raw_length; + int escaped = 0; + int in_string = 0; + int c; + i = 0; + while (i < arglen + && (c = arg->raw[i], is_space[c])) + i++; + while (i < arglen + && (c = arg->raw[arglen - 1], is_space[c])) + arglen--; + if (!traditional) + xbuf[totlen++] = '\"'; /* insert beginning quote */ + for (; i < arglen; i++) { + c = arg->raw[i]; + + if (! in_string) { + /* Special markers Newline Space + generate nothing for a stringified argument. */ + if (c == '\n' && arg->raw[i+1] != '\n') { + i++; + continue; + } + + /* Internal sequences of whitespace are replaced by one space + except within an string or char token. */ + if (c == '\n' ? arg->raw[i+1] == '\n' : is_space[c]) { + while (1) { + /* Note that Newline Space does occur within whitespace + sequences; consider it part of the sequence. */ + if (c == '\n' && is_space[arg->raw[i+1]]) + i += 2; + else if (c != '\n' && is_space[c]) + i++; + else break; + c = arg->raw[i]; + } + i--; + c = ' '; + } + } + + if (escaped) + escaped = 0; + else { + if (c == '\\') + escaped = 1; + else if (in_string) { + if (c == in_string) + in_string = 0; + else + { +#ifdef MULTIBYTE_CHARS + /* CYGNUS LOCAL chill */ + if (! chill) + /* END CYGNUS LOCAL chill */ + { + int length; + length = local_mblen (arg->raw + i, arglen - i); + if (length > 1) + { + bcopy (arg->raw + i, xbuf + totlen, length); + i += length - 1; + totlen += length; + continue; + } + } +#endif + } + } else if (c == '\"' || c == '\'') + in_string = c; + } + + /* Escape these chars */ + if (c == '\"' || (in_string && c == '\\')) + xbuf[totlen++] = '\\'; + /* We used to output e.g. \008 for control characters here, + but this doesn't conform to the C Standard. + Just output the characters as-is. */ + xbuf[totlen++] = c; + } + if (!traditional) + xbuf[totlen++] = '\"'; /* insert ending quote */ + } else if (ap->raw_before != 0 || ap->raw_after != 0 || traditional) { + U_CHAR *p1 = arg->raw; + U_CHAR *l1 = p1 + arg->raw_length; + if (ap->raw_before != 0) { + while (p1 != l1 && is_space[*p1]) p1++; + while (p1 != l1 && is_idchar[*p1]) + xbuf[totlen++] = *p1++; + /* Delete any no-reexpansion marker that follows + an identifier at the beginning of the argument + if the argument is concatenated with what precedes it. */ + if (p1[0] == '\n' && p1[1] == '-') + p1 += 2; + } else if (!traditional) { + /* Ordinary expanded use of the argument. + Put in newline-space markers to prevent token pasting. */ + xbuf[totlen++] = '\n'; + xbuf[totlen++] = ' '; + } + if (ap->raw_after != 0) { + /* Arg is concatenated after: delete trailing whitespace, + whitespace markers, and no-reexpansion markers. */ + while (p1 != l1) { + if (is_space[l1[-1]]) l1--; + else if (l1[-1] == '-') { + U_CHAR *p2 = l1 - 1; + /* If a `-' is preceded by an odd number of newlines then it + and the last newline are a no-reexpansion marker. */ + while (p2 != p1 && p2[-1] == '\n') p2--; + if ((l1 - 1 - p2) & 1) { + l1 -= 2; + } + else break; + } + else break; + } + } + + bcopy ((char *) p1, (char *) (xbuf + totlen), l1 - p1); + totlen += l1 - p1; + if (!traditional && ap->raw_after == 0) { + /* Ordinary expanded use of the argument. + Put in newline-space markers to prevent token pasting. */ + xbuf[totlen++] = '\n'; + xbuf[totlen++] = ' '; + } + } else { + /* Ordinary expanded use of the argument. + Put in newline-space markers to prevent token pasting. */ + if (!traditional) { + xbuf[totlen++] = '\n'; + xbuf[totlen++] = ' '; + } + bcopy ((char *) arg->expanded, (char *) (xbuf + totlen), + arg->expand_length); + totlen += arg->expand_length; + if (!traditional) { + xbuf[totlen++] = '\n'; + xbuf[totlen++] = ' '; + } + /* If a macro argument with newlines is used multiple times, + then only expand the newlines once. This avoids creating output + lines which don't correspond to any input line, which confuses + gdb and gcov. */ + if (arg->use_count > 1 && arg->newlines > 0) { + /* Don't bother doing change_newlines for subsequent + uses of arg. */ + arg->use_count = 1; + arg->expand_length + = change_newlines (arg->expanded, arg->expand_length); + } + } + + if (totlen > xbuf_len) + abort (); + } + + /* If there is anything left of the definition after handling + the arg list, copy that in too. */ + + for (i = offset; i < defn->length; i++) { + /* if we've reached the end of the macro */ + if (exp[i] == ')') + rest_zero = 0; + if (! (rest_zero && last_ap != NULL && last_ap->rest_args + && last_ap->raw_after != 0)) + xbuf[totlen++] = exp[i]; + } + + xbuf[totlen] = 0; + xbuf_len = totlen; + + for (i = 0; i < nargs; i++) { + if (args[i].free1 != 0) + free (args[i].free1); + if (args[i].free2 != 0) + free (args[i].free2); + } + } + } else { + xbuf = defn->expansion; + xbuf_len = defn->length; + } + + /* Now put the expansion on the input stack + so our caller will commence reading from it. */ + { + register FILE_BUF *ip2; + + ip2 = &instack[++indepth]; + + ip2->fname = 0; + ip2->nominal_fname = 0; + ip2->nominal_fname_len = 0; + ip2->inc = 0; + /* This may not be exactly correct, but will give much better error + messages for nested macro calls than using a line number of zero. */ + ip2->lineno = start_line; + ip2->buf = xbuf; + ip2->length = xbuf_len; + ip2->bufp = xbuf; + ip2->free_ptr = (nargs > 0) ? xbuf : 0; + ip2->macro = hp; + ip2->if_stack = if_stack; + ip2->system_header_p = 0; + + /* Recursive macro use sometimes works traditionally. + #define foo(x,y) bar (x (y,0), y) + foo (foo, baz) */ + + if (!traditional) + hp->type = T_DISABLED; + } +} + +/* Parse a macro argument and store the info on it into *ARGPTR. + REST_ARGS is passed to macarg1 to make it absorb the rest of the args. + Return nonzero to indicate a syntax error. */ + +static char * +macarg (argptr, rest_args) + register struct argdata *argptr; + int rest_args; +{ + FILE_BUF *ip = &instack[indepth]; + int paren = 0; + int newlines = 0; + int comments = 0; + char *result = 0; + + /* Try to parse as much of the argument as exists at this + input stack level. */ + U_CHAR *bp = macarg1 (ip->bufp, ip->buf + ip->length, ip->macro, + &paren, &newlines, &comments, rest_args); + + /* If we find the end of the argument at this level, + set up *ARGPTR to point at it in the input stack. */ + if (!(ip->fname != 0 && (newlines != 0 || comments != 0)) + && bp != ip->buf + ip->length) { + if (argptr != 0) { + argptr->raw = ip->bufp; + argptr->raw_length = bp - ip->bufp; + argptr->newlines = newlines; + } + ip->bufp = bp; + } else { + /* This input stack level ends before the macro argument does. + We must pop levels and keep parsing. + Therefore, we must allocate a temporary buffer and copy + the macro argument into it. */ + int bufsize = bp - ip->bufp; + int extra = newlines; + U_CHAR *buffer = (U_CHAR *) xmalloc (bufsize + extra + 1); + int final_start = 0; + + bcopy ((char *) ip->bufp, (char *) buffer, bufsize); + ip->bufp = bp; + ip->lineno += newlines; + + while (bp == ip->buf + ip->length) { + if (instack[indepth].macro == 0) { + result = "unterminated macro call"; + break; + } + ip->macro->type = T_MACRO; + if (ip->free_ptr) + free (ip->free_ptr); + ip = &instack[--indepth]; + newlines = 0; + comments = 0; + bp = macarg1 (ip->bufp, ip->buf + ip->length, ip->macro, &paren, + &newlines, &comments, rest_args); + final_start = bufsize; + bufsize += bp - ip->bufp; + extra += newlines; + buffer = (U_CHAR *) xrealloc (buffer, bufsize + extra + 1); + bcopy ((char *) ip->bufp, (char *) (buffer + bufsize - (bp - ip->bufp)), + bp - ip->bufp); + ip->bufp = bp; + ip->lineno += newlines; + } + + /* Now, if arg is actually wanted, record its raw form, + discarding comments and duplicating newlines in whatever + part of it did not come from a macro expansion. + EXTRA space has been preallocated for duplicating the newlines. + FINAL_START is the index of the start of that part. */ + if (argptr != 0) { + argptr->raw = buffer; + argptr->raw_length = bufsize; + argptr->free1 = buffer; + argptr->newlines = newlines; + if ((newlines || comments) && ip->fname != 0) + argptr->raw_length + = final_start + + discard_comments (argptr->raw + final_start, + argptr->raw_length - final_start, + newlines); + argptr->raw[argptr->raw_length] = 0; + if (argptr->raw_length > bufsize + extra) + abort (); + } + } + + /* If we are not discarding this argument, + macroexpand it and compute its length as stringified. + All this info goes into *ARGPTR. */ + + if (argptr != 0) { + register U_CHAR *buf, *lim; + register int totlen; + + buf = argptr->raw; + lim = buf + argptr->raw_length; + + while (buf != lim && is_space[*buf]) + buf++; + while (buf != lim && is_space[lim[-1]]) + lim--; + totlen = traditional ? 0 : 2; /* Count opening and closing quote. */ + while (buf != lim) { + register U_CHAR c = *buf++; + totlen++; + /* Internal sequences of whitespace are replaced by one space + in most cases, but not always. So count all the whitespace + in case we need to keep it all. */ +#if 0 + if (is_space[c]) + SKIP_ALL_WHITE_SPACE (buf); + else +#endif + if (c == '\"' || c == '\\') /* escape these chars */ + totlen++; + } + argptr->stringified_length = totlen; + } + return result; +} + +/* Scan text from START (inclusive) up to LIMIT (exclusive), + taken from the expansion of MACRO, + counting parens in *DEPTHPTR, + and return if reach LIMIT + or before a `)' that would make *DEPTHPTR negative + or before a comma when *DEPTHPTR is zero. + Single and double quotes are matched and termination + is inhibited within them. Comments also inhibit it. + Value returned is pointer to stopping place. + + Increment *NEWLINES each time a newline is passed. + REST_ARGS notifies macarg1 that it should absorb the rest of the args. + Set *COMMENTS to 1 if a comment is seen. */ + +static U_CHAR * +macarg1 (start, limit, macro, depthptr, newlines, comments, rest_args) + U_CHAR *start; + register U_CHAR *limit; + struct hashnode *macro; + int *depthptr, *newlines, *comments; + int rest_args; +{ + register U_CHAR *bp = start; + + while (bp < limit) { + switch (*bp) { + case '(': + (*depthptr)++; + break; + case ')': + if (--(*depthptr) < 0) + return bp; + break; + case '\\': + /* Traditionally, backslash makes following char not special. */ + if (traditional && bp + 1 < limit && bp[1] != '\n') + bp++; + break; + case '\n': + ++*newlines; + break; + case '/': + if (macro) + break; + if (bp[1] == '\\' && bp[2] == '\n') + newline_fix (bp + 1); + if (bp[1] == '*') { + *comments = 1; + for (bp += 2; bp < limit; bp++) { + if (*bp == '\n') + ++*newlines; + else if (*bp == '*') { + if (bp[-1] == '/' && warn_comments) + warning ("`/*' within comment"); + if (bp[1] == '\\' && bp[2] == '\n') + newline_fix (bp + 1); + if (bp[1] == '/') { + bp++; + break; + } + } + else + { +#ifdef MULTIBYTE_CHARS + /* CYGNUS LOCAL chill */ + if (! chill) + /* END CYGNUS LOCAL chill */ + { + int length; + length = local_mblen (bp, limit - bp); + if (length > 1) + bp += (length - 1); + } +#endif + } + } + } else if (bp[1] == '/' && cplusplus_comments) { + *comments = 1; + for (bp += 2; bp < limit; bp++) { + if (*bp == '\n') { + ++*newlines; + break; + } + if (*bp == '\\' && bp + 1 < limit && bp[1] == '\n') + { + ++*newlines; + if (warn_comments) + warning ("multiline `//' comment"); + ++bp; + } + else + { +#ifdef MULTIBYTE_CHARS + /* CYGNUS LOCAL chill */ + if (! chill) + /* END CYGNUS LOCAL chill */ + { + int length; + length = local_mblen (bp, limit - bp); + if (length > 1) + bp += (length - 1); + } +#endif + } + } + } + break; + case '\'': + case '\"': + { + int quotec; + for (quotec = *bp++; bp + 1 < limit && *bp != quotec; bp++) { + if (*bp == '\\') { + bp++; + if (*bp == '\n') + ++*newlines; + if (!macro) { + while (*bp == '\\' && bp[1] == '\n') { + bp += 2; + ++*newlines; + } + } + } else if (*bp == '\n') { + ++*newlines; + if (quotec == '\'') + break; + } + else + { +#ifdef MULTIBYTE_CHARS + /* CYGNUS LOCAL chill */ + if (! chill) + /* END CYGNUS LOCAL chill */ + { + int length; + length = local_mblen (bp, limit - bp); + if (length > 1) + bp += (length - 1); + } +#endif + } + } + } + break; + case ',': + /* if we've returned to lowest level and we aren't absorbing all args */ + if ((*depthptr) == 0 && rest_args == 0) + return bp; + break; + } + bp++; + } + + return bp; +} + +/* Discard comments and duplicate newlines + in the string of length LENGTH at START, + except inside of string constants. + The string is copied into itself with its beginning staying fixed. + + NEWLINES is the number of newlines that must be duplicated. + We assume that that much extra space is available past the end + of the string. */ + +static int +discard_comments (start, length, newlines) + U_CHAR *start; + int length; + int newlines; +{ + register U_CHAR *ibp; + register U_CHAR *obp; + register U_CHAR *limit; + register int c; + + /* If we have newlines to duplicate, copy everything + that many characters up. Then, in the second part, + we will have room to insert the newlines + while copying down. + NEWLINES may actually be too large, because it counts + newlines in string constants, and we don't duplicate those. + But that does no harm. */ + if (newlines > 0) { + ibp = start + length; + obp = ibp + newlines; + limit = start; + while (limit != ibp) + *--obp = *--ibp; + } + + ibp = start + newlines; + limit = start + length + newlines; + obp = start; + + while (ibp < limit) { + *obp++ = c = *ibp++; + switch (c) { + case '\n': + /* Duplicate the newline. */ + *obp++ = '\n'; + break; + + case '\\': + if (*ibp == '\n') { + obp--; + ibp++; + } + break; + + case '/': + if (*ibp == '\\' && ibp[1] == '\n') + newline_fix (ibp); + /* Delete any comment. */ + if (cplusplus_comments && ibp[0] == '/') { + /* Comments are equivalent to spaces. */ + obp[-1] = ' '; + ibp++; + while (ibp < limit) + { + if (*ibp == '\n') + break; + if (*ibp == '\\' && ibp + 1 < limit && ibp[1] == '\n') + ibp++; + else + { +#ifdef MULTIBYTE_CHARS + /* CYGNUS LOCAL chill */ + if (! chill) + /* END CYGNUS LOCAL chill */ + { + int length = local_mblen (ibp, limit - ibp); + if (length > 1) + ibp += (length - 1); + } +#endif + } + ibp++; + } + break; + } + if (ibp[0] != '*' || ibp + 1 >= limit) + break; + /* Comments are equivalent to spaces. + For -traditional, a comment is equivalent to nothing. */ + if (traditional) + obp--; + else + obp[-1] = ' '; + while (++ibp < limit) { + if (ibp[0] == '*') { + if (ibp[1] == '\\' && ibp[2] == '\n') + newline_fix (ibp + 1); + if (ibp[1] == '/') { + ibp += 2; + break; + } + } + else + { +#ifdef MULTIBYTE_CHARS + /* CYGNUS LOCAL chill */ + if (! chill) + /* END CYGNUS LOCAL chill */ + { + int length = local_mblen (ibp, limit - ibp); + if (length > 1) + ibp += (length - 1); + } +#endif + } + } + break; + + case '\'': + case '\"': + /* Notice and skip strings, so that we don't + think that comments start inside them, + and so we don't duplicate newlines in them. */ + { + int quotec = c; + while (ibp < limit) { + *obp++ = c = *ibp++; + if (c == quotec) + break; + if (c == '\n') + { + if (quotec == '\'') + break; + } + else if (c == '\\') { + if (ibp < limit && *ibp == '\n') { + ibp++; + obp--; + } else { + while (*ibp == '\\' && ibp[1] == '\n') + ibp += 2; + if (ibp < limit) + *obp++ = *ibp++; + } + } + else + { +#ifdef MULTIBYTE_CHARS + /* CYGNUS LOCAL chill */ + if (! chill) + /* END CYGNUS LOCAL chill */ + { + int length; + ibp--; + length = local_mblen (ibp, limit - ibp); + if (length > 1) + { + obp--; + bcopy (ibp, obp, length); + ibp += length; + obp += length; + } + else + ibp++; + } +#endif + } + } + } + break; + } + } + + return obp - start; +} + +/* Turn newlines to spaces in the string of length LENGTH at START, + except inside of string constants. + The string is copied into itself with its beginning staying fixed. */ + +static int +change_newlines (start, length) + U_CHAR *start; + int length; +{ + register U_CHAR *ibp; + register U_CHAR *obp; + register U_CHAR *limit; + register int c; + + ibp = start; + limit = start + length; + obp = start; + + while (ibp < limit) { + *obp++ = c = *ibp++; + switch (c) { + case '\n': + /* If this is a NEWLINE NEWLINE, then this is a real newline in the + string. Skip past the newline and its duplicate. + Put a space in the output. */ + if (*ibp == '\n') + { + ibp++; + obp--; + *obp++ = ' '; + } + break; + + case '\'': + case '\"': + /* Notice and skip strings, so that we don't delete newlines in them. */ + { + int quotec = c; + while (ibp < limit) { + *obp++ = c = *ibp++; + if (c == quotec) + break; + else if (c == '\\' && ibp < limit && *ibp == '\n') + *obp++ = *ibp++; + else if (c == '\n') + { + if (quotec == '\'') + break; + } + else + { +#ifdef MULTIBYTE_CHARS + /* CYGNUS LOCAL chill */ + if (! chill) + /* END CYGNUS LOCAL chill */ + { + int length; + ibp--; + length = local_mblen (ibp, limit - ibp); + if (length > 1) + { + obp--; + bcopy (ibp, obp, length); + ibp += length; + obp += length; + } + else + ibp++; + } +#endif + } + } + } + break; + } + } + + return obp - start; +} + +/* my_strerror - return the descriptive text associated with an + `errno' code. */ + +static char * +my_strerror (errnum) + int errnum; +{ + char *result; + +#ifndef VMS +#ifndef HAVE_STRERROR + result = (char *) ((errnum < sys_nerr) ? sys_errlist[errnum] : 0); +#else + result = strerror (errnum); +#endif +#else /* VMS */ + /* VAXCRTL's strerror() takes an optional second argument, which only + matters when the first argument is EVMSERR. However, it's simplest + just to pass it unconditionally. `vaxc$errno' is declared in + , and maintained by the library in parallel with `errno'. + We assume that caller's `errnum' either matches the last setting of + `errno' by the library or else does not have the value `EVMSERR'. */ + + result = strerror (errnum, vaxc$errno); +#endif + + if (!result) + result = "undocumented I/O error"; + + return result; +} + +/* error - print error message and increment count of errors. */ + +void +error VPROTO ((char * msg, ...)) +{ +#ifndef ANSI_PROTOTYPES + char * msg; +#endif + va_list args; + + VA_START (args, msg); + +#ifndef ANSI_PROTOTYPES + msg = va_arg (args, char *); +#endif + + verror (msg, args); + va_end (args); +} + +static void +verror (msg, args) + char *msg; + va_list args; +{ + int i; + FILE_BUF *ip = NULL; + + print_containing_files (); + + for (i = indepth; i >= 0; i--) + if (instack[i].fname != NULL) { + ip = &instack[i]; + break; + } + + if (ip != NULL) { + eprint_string (ip->nominal_fname, ip->nominal_fname_len); + fprintf (stderr, ":%d: ", ip->lineno); + } + vfprintf (stderr, msg, args); + fprintf (stderr, "\n"); + errors++; +} + +/* Error including a message from `errno'. */ + +static void +error_from_errno (name) + char *name; +{ + int e = errno; + int i; + FILE_BUF *ip = NULL; + + print_containing_files (); + + for (i = indepth; i >= 0; i--) + if (instack[i].fname != NULL) { + ip = &instack[i]; + break; + } + + if (ip != NULL) { + eprint_string (ip->nominal_fname, ip->nominal_fname_len); + fprintf (stderr, ":%d: ", ip->lineno); + } + + fprintf (stderr, "%s: %s\n", name, my_strerror (e)); + + errors++; +} + +/* Print error message but don't count it. */ + +void +warning VPROTO ((char * msg, ...)) +{ +#ifndef ANSI_PROTOTYPES + char * msg; +#endif + va_list args; + + VA_START (args, msg); + +#ifndef ANSI_PROTOTYPES + msg = va_arg (args, char *); +#endif + + vwarning (msg, args); + va_end (args); +} + +static void +vwarning (msg, args) + char *msg; + va_list args; +{ + int i; + FILE_BUF *ip = NULL; + + if (inhibit_warnings) + return; + + if (warnings_are_errors) + errors++; + + print_containing_files (); + + for (i = indepth; i >= 0; i--) + if (instack[i].fname != NULL) { + ip = &instack[i]; + break; + } + + if (ip != NULL) { + eprint_string (ip->nominal_fname, ip->nominal_fname_len); + fprintf (stderr, ":%d: ", ip->lineno); + } + fprintf (stderr, "warning: "); + vfprintf (stderr, msg, args); + fprintf (stderr, "\n"); +} + +static void +error_with_line VPROTO ((int line, char * msg, ...)) +{ +#ifndef ANSI_PROTOTYPES + int line; + char * msg; +#endif + va_list args; + + VA_START (args, msg); + +#ifndef ANSI_PROTOTYPES + line = va_arg (args, int); + msg = va_arg (args, char *); +#endif + + verror_with_line (line, msg, args); + va_end (args); +} + +static void +verror_with_line (line, msg, args) + int line; + char *msg; + va_list args; +{ + int i; + FILE_BUF *ip = NULL; + + print_containing_files (); + + for (i = indepth; i >= 0; i--) + if (instack[i].fname != NULL) { + ip = &instack[i]; + break; + } + + if (ip != NULL) { + eprint_string (ip->nominal_fname, ip->nominal_fname_len); + fprintf (stderr, ":%d: ", line); + } + vfprintf (stderr, msg, args); + fprintf (stderr, "\n"); + errors++; +} + +static void +warning_with_line VPROTO ((int line, char * msg, ...)) +{ +#ifndef ANSI_PROTOTYPES + int line; + char * msg; +#endif + va_list args; + + VA_START (args, msg); + +#ifndef ANSI_PROTOTYPES + line = va_arg (args, int); + msg = va_arg (args, char *); +#endif + + vwarning_with_line (line, msg, args); + va_end (args); +} + +static void +vwarning_with_line (line, msg, args) + int line; + char *msg; + va_list args; +{ + int i; + FILE_BUF *ip = NULL; + + if (inhibit_warnings) + return; + + if (warnings_are_errors) + errors++; + + print_containing_files (); + + for (i = indepth; i >= 0; i--) + if (instack[i].fname != NULL) { + ip = &instack[i]; + break; + } + + if (ip != NULL) { + eprint_string (ip->nominal_fname, ip->nominal_fname_len); + fprintf (stderr, line ? ":%d: " : ": ", line); + } + fprintf (stderr, "warning: "); + vfprintf (stderr, msg, args); + fprintf (stderr, "\n"); +} + +/* Print an error message and maybe count it. */ + +void +pedwarn VPROTO ((char * msg, ...)) +{ +#ifndef ANSI_PROTOTYPES + char * msg; +#endif + va_list args; + + VA_START (args, msg); + +#ifndef ANSI_PROTOTYPES + msg = va_arg (args, char *); +#endif + + if (pedantic_errors) + verror (msg, args); + else + vwarning (msg, args); + va_end (args); +} + +void +pedwarn_with_line VPROTO ((int line, char * msg, ...)) +{ +#ifndef ANSI_PROTOTYPES + int line; + char * msg; +#endif + va_list args; + + VA_START (args, msg); + +#ifndef ANSI_PROTOTYPES + line = va_arg (args, int); + msg = va_arg (args, char *); +#endif + + if (pedantic_errors) + verror_with_line (line, msg, args); + else + vwarning_with_line (line, msg, args); + va_end (args); +} + +/* Report a warning (or an error if pedantic_errors) + giving specified file name and line number, not current. */ + +static void +pedwarn_with_file_and_line VPROTO ((char *file, size_t file_len, int line, + char * msg, ...)) +{ +#ifndef ANSI_PROTOTYPES + char *file; + size_t file_len; + int line; + char * msg; +#endif + va_list args; + + if (!pedantic_errors && inhibit_warnings) + return; + + VA_START (args, msg); + +#ifndef ANSI_PROTOTYPES + file = va_arg (args, char *); + file_len = va_arg (args, size_t); + line = va_arg (args, int); + msg = va_arg (args, char *); +#endif + + if (file) { + eprint_string (file, file_len); + fprintf (stderr, ":%d: ", line); + } + if (pedantic_errors) + errors++; + if (!pedantic_errors) + fprintf (stderr, "warning: "); + + vfprintf (stderr, msg, args); + va_end (args); + fprintf (stderr, "\n"); +} + +/* Print the file names and line numbers of the #include + directives which led to the current file. */ + +static void +print_containing_files () +{ + FILE_BUF *ip = NULL; + int i; + int first = 1; + + /* If stack of files hasn't changed since we last printed + this info, don't repeat it. */ + if (last_error_tick == input_file_stack_tick) + return; + + for (i = indepth; i >= 0; i--) + if (instack[i].fname != NULL) { + ip = &instack[i]; + break; + } + + /* Give up if we don't find a source file. */ + if (ip == NULL) + return; + + /* Find the other, outer source files. */ + for (i--; i >= 0; i--) + if (instack[i].fname != NULL) { + ip = &instack[i]; + if (first) { + first = 0; + fprintf (stderr, "In file included"); + } else { + fprintf (stderr, ",\n "); + } + + fprintf (stderr, " from "); + eprint_string (ip->nominal_fname, ip->nominal_fname_len); + fprintf (stderr, ":%d", ip->lineno); + } + if (! first) + fprintf (stderr, ":\n"); + + /* Record we have printed the status as of this time. */ + last_error_tick = input_file_stack_tick; +} + +/* Return the line at which an error occurred. + The error is not necessarily associated with the current spot + in the input stack, so LINE says where. LINE will have been + copied from ip->lineno for the current input level. + If the current level is for a file, we return LINE. + But if the current level is not for a file, LINE is meaningless. + In that case, we return the lineno of the innermost file. */ + +static int +line_for_error (line) + int line; +{ + int i; + int line1 = line; + + for (i = indepth; i >= 0; ) { + if (instack[i].fname != 0) + return line1; + i--; + if (i < 0) + return 0; + line1 = instack[i].lineno; + } + abort (); + /*NOTREACHED*/ + return 0; +} + +/* + * If OBUF doesn't have NEEDED bytes after OPTR, make it bigger. + * + * As things stand, nothing is ever placed in the output buffer to be + * removed again except when it's KNOWN to be part of an identifier, + * so flushing and moving down everything left, instead of expanding, + * should work ok. + */ + +/* You might think void was cleaner for the return type, + but that would get type mismatch in check_expand in strict ANSI. */ + +static int +grow_outbuf (obuf, needed) + register FILE_BUF *obuf; + register int needed; +{ + register U_CHAR *p; + int minsize; + + if (obuf->length - (obuf->bufp - obuf->buf) > needed) + return 0; + + /* Make it at least twice as big as it is now. */ + obuf->length *= 2; + /* Make it have at least 150% of the free space we will need. */ + minsize = (3 * needed) / 2 + (obuf->bufp - obuf->buf); + if (minsize > obuf->length) + obuf->length = minsize; + + if ((p = (U_CHAR *) xrealloc (obuf->buf, obuf->length)) == NULL) + memory_full (); + + obuf->bufp = p + (obuf->bufp - obuf->buf); + obuf->buf = p; + + return 0; +} + +/* Symbol table for macro names and special symbols */ + +/* + * install a name in the main hash table, even if it is already there. + * name stops with first non alphanumeric, except leading '#'. + * caller must check against redefinition if that is desired. + * delete_macro () removes things installed by install () in fifo order. + * this is important because of the `defined' special symbol used + * in #if, and also if pushdef/popdef directives are ever implemented. + * + * If LEN is >= 0, it is the length of the name. + * Otherwise, compute the length by scanning the entire name. + * + * If HASH is >= 0, it is the precomputed hash code. + * Otherwise, compute the hash code. + */ + +static HASHNODE * +install (name, len, type, value, hash) + U_CHAR *name; + int len; + enum node_type type; + char *value; + int hash; +{ + register HASHNODE *hp; + register int i, bucket; + register U_CHAR *p, *q; + + if (len < 0) { + p = name; + while (is_idchar[*p]) + p++; + len = p - name; + } + + if (hash < 0) + hash = hashf (name, len, HASHSIZE); + + i = sizeof (HASHNODE) + len + 1; + hp = (HASHNODE *) xmalloc (i); + bucket = hash; + hp->bucket_hdr = &hashtab[bucket]; + hp->next = hashtab[bucket]; + hashtab[bucket] = hp; + hp->prev = NULL; + if (hp->next != NULL) + hp->next->prev = hp; + hp->type = type; + hp->length = len; + hp->value.cpval = value; + hp->name = ((U_CHAR *) hp) + sizeof (HASHNODE); + p = hp->name; + q = name; + for (i = 0; i < len; i++) + *p++ = *q++; + hp->name[len] = 0; + return hp; +} + +/* + * find the most recent hash node for name "name" (ending with first + * non-identifier char) installed by install + * + * If LEN is >= 0, it is the length of the name. + * Otherwise, compute the length by scanning the entire name. + * + * If HASH is >= 0, it is the precomputed hash code. + * Otherwise, compute the hash code. + */ + +HASHNODE * +lookup (name, len, hash) + U_CHAR *name; + int len; + int hash; +{ + register U_CHAR *bp; + register HASHNODE *bucket; + + if (len < 0) { + for (bp = name; is_idchar[*bp]; bp++) ; + len = bp - name; + } + + if (hash < 0) + hash = hashf (name, len, HASHSIZE); + + bucket = hashtab[hash]; + while (bucket) { + if (bucket->length == len && bcmp (bucket->name, name, len) == 0) + return bucket; + bucket = bucket->next; + } + return NULL; +} + +/* + * Delete a hash node. Some weirdness to free junk from macros. + * More such weirdness will have to be added if you define more hash + * types that need it. + */ + +/* Note that the DEFINITION of a macro is removed from the hash table + but its storage is not freed. This would be a storage leak + except that it is not reasonable to keep undefining and redefining + large numbers of macros many times. + In any case, this is necessary, because a macro can be #undef'd + in the middle of reading the arguments to a call to it. + If #undef freed the DEFINITION, that would crash. */ + +static void +delete_macro (hp) + HASHNODE *hp; +{ + + if (hp->prev != NULL) + hp->prev->next = hp->next; + if (hp->next != NULL) + hp->next->prev = hp->prev; + + /* Make sure that the bucket chain header that the deleted guy was + on points to the right thing afterwards. */ + if (hp == *hp->bucket_hdr) + *hp->bucket_hdr = hp->next; + +#if 0 + if (hp->type == T_MACRO) { + DEFINITION *d = hp->value.defn; + struct reflist *ap, *nextap; + + for (ap = d->pattern; ap != NULL; ap = nextap) { + nextap = ap->next; + free (ap); + } + free (d); + } +#endif + free (hp); +} + +/* + * return hash function on name. must be compatible with the one + * computed a step at a time, elsewhere + */ + +static int +hashf (name, len, hashsize) + register U_CHAR *name; + register int len; + int hashsize; +{ + register int r = 0; + + while (len--) + r = HASHSTEP (r, *name++); + + return MAKE_POS (r) % hashsize; +} + + +/* Dump the definition of a single macro HP to OF. */ + +static void +dump_single_macro (hp, of) + register HASHNODE *hp; + FILE *of; +{ + register DEFINITION *defn = hp->value.defn; + struct reflist *ap; + int offset; + int concat; + + + /* Print the definition of the macro HP. */ + + fprintf (of, "#define %s", hp->name); + + if (defn->nargs >= 0) { + int i; + + fprintf (of, "("); + for (i = 0; i < defn->nargs; i++) { + dump_arg_n (defn, i, of); + if (i + 1 < defn->nargs) + fprintf (of, ", "); + } + fprintf (of, ")"); + } + + fprintf (of, " "); + + offset = 0; + concat = 0; + for (ap = defn->pattern; ap != NULL; ap = ap->next) { + dump_defn_1 (defn->expansion, offset, ap->nchars, of); + offset += ap->nchars; + if (!traditional) { + if (ap->nchars != 0) + concat = 0; + if (ap->stringify) { + switch (ap->stringify) { + case SHARP_TOKEN: fprintf (of, "#"); break; + case WHITE_SHARP_TOKEN: fprintf (of, "# "); break; + case PERCENT_COLON_TOKEN: fprintf (of, "%%:"); break; + case WHITE_PERCENT_COLON_TOKEN: fprintf (of, "%%: "); break; + default: abort (); + } + } + if (ap->raw_before != 0) { + if (concat) { + switch (ap->raw_before) { + case WHITE_SHARP_TOKEN: + case WHITE_PERCENT_COLON_TOKEN: + fprintf (of, " "); + break; + default: + break; + } + } else { + switch (ap->raw_before) { + case SHARP_TOKEN: fprintf (of, "##"); break; + case WHITE_SHARP_TOKEN: fprintf (of, "## "); break; + case PERCENT_COLON_TOKEN: fprintf (of, "%%:%%:"); break; + case WHITE_PERCENT_COLON_TOKEN: fprintf (of, "%%:%%: "); break; + default: abort (); + } + } + } + concat = 0; + } + dump_arg_n (defn, ap->argno, of); + if (!traditional && ap->raw_after != 0) { + switch (ap->raw_after) { + case SHARP_TOKEN: fprintf (of, "##"); break; + case WHITE_SHARP_TOKEN: fprintf (of, " ##"); break; + case PERCENT_COLON_TOKEN: fprintf (of, "%%:%%:"); break; + case WHITE_PERCENT_COLON_TOKEN: fprintf (of, " %%:%%:"); break; + default: abort (); + } + concat = 1; + } + } + dump_defn_1 (defn->expansion, offset, defn->length - offset, of); + fprintf (of, "\n"); +} + +/* Dump all macro definitions as #defines to stdout. */ + +static void +dump_all_macros () +{ + int bucket; + + for (bucket = 0; bucket < HASHSIZE; bucket++) { + register HASHNODE *hp; + + for (hp = hashtab[bucket]; hp; hp= hp->next) { + if (hp->type == T_MACRO) + dump_single_macro (hp, stdout); + } + } +} + +/* Output to OF a substring of a macro definition. + BASE is the beginning of the definition. + Output characters START thru LENGTH. + Unless traditional, discard newlines outside of strings, thus + converting funny-space markers to ordinary spaces. */ + +static void +dump_defn_1 (base, start, length, of) + U_CHAR *base; + int start; + int length; + FILE *of; +{ + U_CHAR *p = base + start; + U_CHAR *limit = base + start + length; + + if (traditional) + fwrite (p, sizeof (*p), length, of); + else { + while (p < limit) { + if (*p == '\"' || *p =='\'') { + U_CHAR *p1 = skip_quoted_string (p, limit, 0, NULL_PTR, + NULL_PTR, NULL_PTR); + fwrite (p, sizeof (*p), p1 - p, of); + p = p1; + } else { + if (*p != '\n') + putc (*p, of); + p++; + } + } + } +} + +/* Print the name of argument number ARGNUM of macro definition DEFN + to OF. + Recall that DEFN->args.argnames contains all the arg names + concatenated in reverse order with comma-space in between. */ + +static void +dump_arg_n (defn, argnum, of) + DEFINITION *defn; + int argnum; + FILE *of; +{ + register U_CHAR *p = defn->args.argnames; + while (argnum + 1 < defn->nargs) { + p = (U_CHAR *) index ((char *) p, ' ') + 1; + argnum++; + } + + while (*p && *p != ',') { + putc (*p, of); + p++; + } +} + +/* Initialize syntactic classifications of characters. */ + +static void +initialize_char_syntax () +{ + register int i; + + /* + * Set up is_idchar and is_idstart tables. These should be + * faster than saying (is_alpha (c) || c == '_'), etc. + * Set up these things before calling any routines tthat + * refer to them. + */ + for (i = 'a'; i <= 'z'; i++) { + is_idchar[i - 'a' + 'A'] = 1; + is_idchar[i] = 1; + is_idstart[i - 'a' + 'A'] = 1; + is_idstart[i] = 1; + } + for (i = '0'; i <= '9'; i++) + is_idchar[i] = 1; + is_idchar['_'] = 1; + is_idstart['_'] = 1; + is_idchar['$'] = 1; + is_idstart['$'] = 1; + + /* horizontal space table */ + is_hor_space[' '] = 1; + is_hor_space['\t'] = 1; + is_hor_space['\v'] = 1; + is_hor_space['\f'] = 1; + is_hor_space['\r'] = 1; + + is_space[' '] = 1; + is_space['\t'] = 1; + is_space['\v'] = 1; + is_space['\f'] = 1; + is_space['\n'] = 1; + is_space['\r'] = 1; + + char_name['\v'] = "vertical tab"; + char_name['\f'] = "formfeed"; + char_name['\r'] = "carriage return"; +} + +/* Initialize the built-in macros. */ + +static void +initialize_builtins (inp, outp) + FILE_BUF *inp; + FILE_BUF *outp; +{ + install ((U_CHAR *) "__LINE__", -1, T_SPECLINE, NULL_PTR, -1); + install ((U_CHAR *) "__DATE__", -1, T_DATE, NULL_PTR, -1); + install ((U_CHAR *) "__FILE__", -1, T_FILE, NULL_PTR, -1); + install ((U_CHAR *) "__BASE_FILE__", -1, T_BASE_FILE, NULL_PTR, -1); + install ((U_CHAR *) "__INCLUDE_LEVEL__", -1, T_INCLUDE_LEVEL, NULL_PTR, -1); + install ((U_CHAR *) "__VERSION__", -1, T_VERSION, NULL_PTR, -1); +#ifndef NO_BUILTIN_SIZE_TYPE + install ((U_CHAR *) "__SIZE_TYPE__", -1, T_SIZE_TYPE, NULL_PTR, -1); +#endif +#ifndef NO_BUILTIN_PTRDIFF_TYPE + install ((U_CHAR *) "__PTRDIFF_TYPE__ ", -1, T_PTRDIFF_TYPE, NULL_PTR, -1); +#endif +/* CYGNUS LOCAL vmakarov */ +#ifndef NO_BUILTIN_WCHAR_TYPE +/* END CYGNUS LOCAL */ + install ((U_CHAR *) "__WCHAR_TYPE__", -1, T_WCHAR_TYPE, NULL_PTR, -1); +/* CYGNUS LOCAL vmakarov */ +#endif +/* END CYGNUS LOCAL */ + install ((U_CHAR *) "__USER_LABEL_PREFIX__", -1, T_USER_LABEL_PREFIX_TYPE, + NULL_PTR, -1); + install ((U_CHAR *) "__REGISTER_PREFIX__", -1, T_REGISTER_PREFIX_TYPE, + NULL_PTR, -1); + install ((U_CHAR *) "__IMMEDIATE_PREFIX__", -1, T_IMMEDIATE_PREFIX_TYPE, + NULL_PTR, -1); + install ((U_CHAR *) "__TIME__", -1, T_TIME, NULL_PTR, -1); + if (!traditional) { + install ((U_CHAR *) "__STDC__", -1, T_CONST, "1", -1); + install ((U_CHAR *) "__STDC_VERSION__", -1, T_CONST, "199409L", -1); + } + if (objc) + install ((U_CHAR *) "__OBJC__", -1, T_CONST, "1", -1); +/* This is supplied using a -D by the compiler driver + so that it is present only when truly compiling with GNU C. */ +/* install ((U_CHAR *) "__GNUC__", -1, T_CONST, "2", -1); */ + install ((U_CHAR *) "__HAVE_BUILTIN_SETJMP__", -1, T_CONST, "1", -1); + + if (debug_output) + { + char directive[2048]; + U_CHAR *udirective = (U_CHAR *) directive; + register struct directive *dp = &directive_table[0]; + struct tm *timebuf = timestamp (); + + sprintf (directive, " __BASE_FILE__ \"%s\"\n", + instack[0].nominal_fname); + output_line_directive (inp, outp, 0, same_file); + pass_thru_directive (udirective, &udirective[strlen (directive)], + outp, dp); + + sprintf (directive, " __VERSION__ \"%s\"\n", version_string); + output_line_directive (inp, outp, 0, same_file); + pass_thru_directive (udirective, &udirective[strlen (directive)], + outp, dp); + +#ifndef NO_BUILTIN_SIZE_TYPE + sprintf (directive, " __SIZE_TYPE__ %s\n", SIZE_TYPE); + output_line_directive (inp, outp, 0, same_file); + pass_thru_directive (udirective, &udirective[strlen (directive)], + outp, dp); +#endif + +#ifndef NO_BUILTIN_PTRDIFF_TYPE + sprintf (directive, " __PTRDIFF_TYPE__ %s\n", PTRDIFF_TYPE); + output_line_directive (inp, outp, 0, same_file); + pass_thru_directive (udirective, &udirective[strlen (directive)], + outp, dp); +#endif + +/* CYGNUS LOCAL vmakarov */ +#ifndef NO_BUILTIN_WCHAR_TYPE +/* END CYGNUS LOCAL */ + sprintf (directive, " __WCHAR_TYPE__ %s\n", wchar_type); + output_line_directive (inp, outp, 0, same_file); + pass_thru_directive (udirective, &udirective[strlen (directive)], + outp, dp); +/* CYGNUS LOCAL vmakarov */ +#endif +/* END CYGNUS LOCAL */ + + sprintf (directive, " __DATE__ \"%s %2d %4d\"\n", + monthnames[timebuf->tm_mon], + timebuf->tm_mday, timebuf->tm_year + 1900); + output_line_directive (inp, outp, 0, same_file); + pass_thru_directive (udirective, &udirective[strlen (directive)], + outp, dp); + + sprintf (directive, " __TIME__ \"%02d:%02d:%02d\"\n", + timebuf->tm_hour, timebuf->tm_min, timebuf->tm_sec); + output_line_directive (inp, outp, 0, same_file); + pass_thru_directive (udirective, &udirective[strlen (directive)], + outp, dp); + + if (!traditional) + { + sprintf (directive, " __STDC__ 1"); + output_line_directive (inp, outp, 0, same_file); + pass_thru_directive (udirective, &udirective[strlen (directive)], + outp, dp); + } + if (objc) + { + sprintf (directive, " __OBJC__ 1"); + output_line_directive (inp, outp, 0, same_file); + pass_thru_directive (udirective, &udirective[strlen (directive)], + outp, dp); + } + } +} + +/* + * process a given definition string, for initialization + * If STR is just an identifier, define it with value 1. + * If STR has anything after the identifier, then it should + * be identifier=definition. + */ + +static void +make_definition (str) + char *str; +{ + FILE_BUF *ip; + struct directive *kt; + U_CHAR *buf, *p; + + p = buf = (U_CHAR *) str; + if (!is_idstart[*p]) { + error ("malformed option `-D %s'", str); + return; + } + while (is_idchar[*++p]) + ; + if (*p == '(') { + while (is_idchar[*++p] || *p == ',' || is_hor_space[*p]) + ; + if (*p++ != ')') + p = (U_CHAR *) str; /* Error */ + } + if (*p == 0) { + buf = (U_CHAR *) alloca (p - buf + 4); + strcpy ((char *)buf, str); + strcat ((char *)buf, " 1"); + } else if (*p != '=') { + error ("malformed option `-D %s'", str); + return; + } else { + U_CHAR *q; + /* Copy the entire option so we can modify it. */ + buf = (U_CHAR *) alloca (2 * strlen (str) + 1); + strncpy ((char *) buf, str, p - (U_CHAR *) str); + /* Change the = to a space. */ + buf[p - (U_CHAR *) str] = ' '; + /* Scan for any backslash-newline and remove it. */ + p++; + q = &buf[p - (U_CHAR *) str]; + while (*p) { + if (*p == '\"' || *p == '\'') { + int unterminated = 0; + U_CHAR *p1 = skip_quoted_string (p, p + strlen ((char *) p), 0, + NULL_PTR, NULL_PTR, &unterminated); + if (unterminated) + return; + while (p != p1) + *q++ = *p++; + } else if (*p == '\\' && p[1] == '\n') + p += 2; + /* Change newline chars into newline-markers. */ + else if (*p == '\n') + { + *q++ = '\n'; + *q++ = '\n'; + p++; + } + else + *q++ = *p++; + } + *q = 0; + } + + ip = &instack[++indepth]; + ip->nominal_fname = ip->fname = "*Initialization*"; + ip->nominal_fname_len = strlen (ip->nominal_fname); + + ip->buf = ip->bufp = buf; + ip->length = strlen ((char *) buf); + ip->lineno = 1; + ip->macro = 0; + ip->free_ptr = 0; + ip->if_stack = if_stack; + ip->system_header_p = 0; + + for (kt = directive_table; kt->type != T_DEFINE; kt++) + ; + + /* Pass NULL instead of OP, since this is a "predefined" macro. */ + do_define (buf, buf + strlen ((char *) buf), NULL_PTR, kt); + --indepth; +} + +/* JF, this does the work for the -U option */ + +static void +make_undef (str, op) + char *str; + FILE_BUF *op; +{ + FILE_BUF *ip; + struct directive *kt; + + ip = &instack[++indepth]; + ip->nominal_fname = ip->fname = "*undef*"; + ip->nominal_fname_len = strlen (ip->nominal_fname); + + ip->buf = ip->bufp = (U_CHAR *) str; + ip->length = strlen (str); + ip->lineno = 1; + ip->macro = 0; + ip->free_ptr = 0; + ip->if_stack = if_stack; + ip->system_header_p = 0; + + for (kt = directive_table; kt->type != T_UNDEF; kt++) + ; + + do_undef ((U_CHAR *) str, (U_CHAR *) str + strlen (str), op, kt); + --indepth; +} + +/* Process the string STR as if it appeared as the body of a #assert. + OPTION is the option name for which STR was the argument. */ + +static void +make_assertion (option, str) + char *option; + char *str; +{ + FILE_BUF *ip; + struct directive *kt; + U_CHAR *buf, *p, *q; + + /* Copy the entire option so we can modify it. */ + buf = (U_CHAR *) alloca (strlen (str) + 1); + strcpy ((char *) buf, str); + /* Scan for any backslash-newline and remove it. */ + p = q = buf; + while (*p) { + if (*p == '\\' && p[1] == '\n') + p += 2; + else + *q++ = *p++; + } + *q = 0; + + p = buf; + if (!is_idstart[*p]) { + error ("malformed option `%s %s'", option, str); + return; + } + while (is_idchar[*++p]) + ; + SKIP_WHITE_SPACE (p); + if (! (*p == 0 || *p == '(')) { + error ("malformed option `%s %s'", option, str); + return; + } + + ip = &instack[++indepth]; + ip->nominal_fname = ip->fname = "*Initialization*"; + ip->nominal_fname_len = strlen (ip->nominal_fname); + + ip->buf = ip->bufp = buf; + ip->length = strlen ((char *) buf); + ip->lineno = 1; + ip->macro = 0; + ip->free_ptr = 0; + ip->if_stack = if_stack; + ip->system_header_p = 0; + + for (kt = directive_table; kt->type != T_ASSERT; kt++) + ; + + /* Pass NULL as output ptr to do_define since we KNOW it never does + any output.... */ + do_assert (buf, buf + strlen ((char *) buf) , NULL_PTR, kt); + --indepth; +} + +#ifndef DIR_SEPARATOR +#define DIR_SEPARATOR '/' +#endif + +/* The previous include prefix, if any, is PREV_FILE_NAME. + Translate any pathnames with COMPONENT. + Allocate a new include prefix whose name is the + simplified concatenation of PREFIX and NAME, + with a trailing / added if needed. + But return 0 if the include prefix should be ignored, + e.g. because it is a duplicate of PREV_FILE_NAME. */ + +static struct file_name_list * +new_include_prefix (prev_file_name, component, prefix, name) + struct file_name_list *prev_file_name; + const char *component; + const char *prefix; + const char *name; +{ + if (name == 0) + fatal ("Directory name missing after command line option"); + + if (*name == 0) + /* Ignore the empty string. */ + return 0; + + prefix = update_path (prefix, component); + name = update_path (name, component); + + { + struct file_name_list *dir + = ((struct file_name_list *) + xmalloc (sizeof (struct file_name_list) + + strlen (prefix) + strlen (name) + 2)); + size_t len; + strcpy (dir->fname, prefix); + strcat (dir->fname, name); + len = simplify_filename (dir->fname); + + /* Convert directory name to a prefix. */ + if (len && dir->fname[len - 1] != DIR_SEPARATOR) { + if (len == 1 && dir->fname[len - 1] == '.') + len = 0; + else +#ifdef VMS + /* must be '/', hack_vms_include_specification triggers on it. */ + dir->fname[len++] = '/'; +#else + dir->fname[len++] = DIR_SEPARATOR; +#endif + dir->fname[len] = 0; + } + + /* Ignore a directory whose name matches the previous one. */ + if (prev_file_name && !strcmp (prev_file_name->fname, dir->fname)) { + /* But treat `-Idir -I- -Idir' as `-I- -Idir'. */ + if (!first_bracket_include) + first_bracket_include = prev_file_name; + free (dir); + return 0; + } + +#ifndef VMS + /* VMS can't stat dir prefixes, so skip these optimizations in VMS. */ + + /* Add a trailing "." if there is a filename. This increases the number + of systems that can stat directories. We remove it below. */ + if (len != 0) + { + dir->fname[len] = '.'; + dir->fname[len + 1] = 0; + } + + /* Ignore a nonexistent directory. */ + if (stat (len ? dir->fname : ".", &dir->st) != 0) { + if (errno != ENOENT && errno != ENOTDIR) + error_from_errno (dir->fname); + free (dir); + return 0; + } + + if (len != 0) + dir->fname[len] = 0; + + /* Ignore a directory whose identity matches the previous one. */ + if (prev_file_name + && INO_T_EQ (prev_file_name->st.st_ino, dir->st.st_ino) + && prev_file_name->st.st_dev == dir->st.st_dev) { + /* But treat `-Idir -I- -Idir' as `-I- -Idir'. */ + if (!first_bracket_include) + first_bracket_include = prev_file_name; + free (dir); + return 0; + } +#endif /* ! VMS */ + + dir->next = 0; + dir->c_system_include_path = 0; + dir->got_name_map = 0; + + return dir; + } +} + +/* Append a chain of `struct file_name_list's + to the end of the main include chain. + FIRST is the beginning of the chain to append, and LAST is the end. */ + +static void +append_include_chain (first, last) + struct file_name_list *first, *last; +{ + struct file_name_list *dir; + + if (!first || !last) + return; + + if (include == 0) + include = first; + else + last_include->next = first; + + if (first_bracket_include == 0) + first_bracket_include = first; + + for (dir = first; ; dir = dir->next) { + int len = strlen (dir->fname) + INCLUDE_LEN_FUDGE; + if (len > max_include_len) + max_include_len = len; + if (dir == last) + break; + } + + last->next = NULL; + last_include = last; +} + +/* Place into DST a representation of the file named SRC that is suitable + for `make'. Do not null-terminate DST. Return its length. */ +static int +quote_string_for_make (dst, src) + char *dst; + char *src; +{ + char *p = src; + int i = 0; + for (;;) + { + char c = *p++; + switch (c) + { + case '\0': + case ' ': + case '\t': + { + /* GNU make uses a weird quoting scheme for white space. + A space or tab preceded by 2N+1 backslashes represents + N backslashes followed by space; a space or tab + preceded by 2N backslashes represents N backslashes at + the end of a file name; and backslashes in other + contexts should not be doubled. */ + char *q; + for (q = p - 1; src < q && q[-1] == '\\'; q--) + { + if (dst) + dst[i] = '\\'; + i++; + } + } + if (!c) + return i; + if (dst) + dst[i] = '\\'; + i++; + goto ordinary_char; + + case '$': + if (dst) + dst[i] = c; + i++; + /* Fall through. This can mishandle things like "$(" but + there's no easy fix. */ + default: + ordinary_char: + /* This can mishandle characters in the string "\0\n%*?[\\~"; + exactly which chars are mishandled depends on the `make' version. + We know of no portable solution for this; + even GNU make 3.76.1 doesn't solve the problem entirely. + (Also, '\0' is mishandled due to our calling conventions.) */ + if (dst) + dst[i] = c; + i++; + break; + } + } +} + + +/* Add output to `deps_buffer' for the -M switch. + STRING points to the text to be output. + SPACER is ':' for targets, ' ' for dependencies. */ + +static void +deps_output (string, spacer) + char *string; + int spacer; +{ + int size = quote_string_for_make ((char *) 0, string); +/* CYGNUS LOCAL vmakarov */ + int spacer_size = spacer == ':' ? 2 : 1; +/* END CYGNUS LOCAL */ + + if (size == 0) + return; + +#ifndef MAX_OUTPUT_COLUMNS +#define MAX_OUTPUT_COLUMNS 72 +#endif + if (MAX_OUTPUT_COLUMNS - spacer_size /* CYGNUS LOCAL vmakarov: spacer_size */ - 2 /*` \'*/ < deps_column + size + && 1 < deps_column) { + bcopy (" \\\n ", &deps_buffer[deps_size], 4); + deps_size += 4; + deps_column = 1; + if (spacer == ' ') + spacer = 0; + } + + if (deps_size + 2 * size + 8 > deps_allocated_size) { + deps_allocated_size = (deps_size + 2 * size + 50) * 2; + deps_buffer = xrealloc (deps_buffer, deps_allocated_size); + } + if (spacer == ' ') { + deps_buffer[deps_size++] = ' '; + deps_column++; + } + quote_string_for_make (&deps_buffer[deps_size], string); + deps_size += size; + deps_column += size; + if (spacer == ':') { +/* CYGNUS LOCAL vmakarov */ + deps_buffer[deps_size++] = ' '; +/* END CYGNUS LOCAL */ + deps_buffer[deps_size++] = ':'; + deps_column++; + } + deps_buffer[deps_size] = 0; +} + +static void +fatal VPROTO ((char * msg, ...)) +{ +#ifndef ANSI_PROTOTYPES + char * msg; +#endif + va_list args; + + fprintf (stderr, "%s: ", progname); + VA_START (args, msg); + +#ifndef ANSI_PROTOTYPES + msg = va_arg (args, char *); +#endif + + vfprintf (stderr, msg, args); + va_end (args); + fprintf (stderr, "\n"); + exit (FATAL_EXIT_CODE); +} + +/* More 'friendly' abort that prints the line and file. + config.h can #define abort fancy_abort if you like that sort of thing. */ + +void +fancy_abort () +{ + fatal ("Internal gcc abort."); +} + +static void +perror_with_name (name) + char *name; +{ + fprintf (stderr, "%s: %s: %s\n", progname, name, my_strerror (errno)); + errors++; +} + +static void +pfatal_with_name (name) + char *name; +{ + perror_with_name (name); +#ifdef VMS + exit (vaxc$errno); +#else + exit (FATAL_EXIT_CODE); +#endif +} + +/* Handler for SIGPIPE. */ + +static void +pipe_closed (signo) + /* If this is missing, some compilers complain. */ + int signo ATTRIBUTE_UNUSED; +{ + fatal ("output pipe has been closed"); +} + +static void +memory_full () +{ + fatal ("Memory exhausted."); +} + +PTR +xmalloc (size) + size_t size; +{ + register PTR ptr = (PTR) malloc (size); + if (!ptr) + memory_full (); + return ptr; +} + +PTR +xrealloc (old, size) + PTR old; + size_t size; +{ + register PTR ptr; + if (old) + ptr = (PTR) realloc (old, size); + else + ptr = (PTR) malloc (size); + if (!ptr) + memory_full (); + return ptr; +} + +PTR +xcalloc (number, size) + size_t number, size; +{ + register size_t total = number * size; + register PTR ptr = (PTR) malloc (total); + if (!ptr) + memory_full (); + bzero (ptr, total); + return ptr; +} + +static char * +savestring (input) + char *input; +{ + size_t size = strlen (input); + char *output = xmalloc (size + 1); + strcpy (output, input); + return output; +} + +#ifdef VMS + +/* Under VMS we need to fix up the "include" specification filename. + + Rules for possible conversions + + fullname tried paths + + name name + ./dir/name [.dir]name + /dir/name dir:name + /name [000000]name, name + dir/name dir:[000000]name, dir:name, dir/name + dir1/dir2/name dir1:[dir2]name, dir1:[000000.dir2]name + path:/name path:[000000]name, path:name + path:/dir/name path:[000000.dir]name, path:[dir]name + path:dir/name path:[dir]name + [path]:[dir]name [path.dir]name + path/[dir]name [path.dir]name + + The path:/name input is constructed when expanding <> includes. + + return 1 if name was changed, 0 else. */ + +static int +hack_vms_include_specification (fullname, vaxc_include) + char *fullname; + int vaxc_include; +{ + register char *basename, *unixname, *local_ptr, *first_slash; + int f, check_filename_before_returning, must_revert; + char Local[512]; + + check_filename_before_returning = 0; + must_revert = 0; + /* See if we can find a 1st slash. If not, there's no path information. */ + first_slash = index (fullname, '/'); + if (first_slash == 0) + return 0; /* Nothing to do!!! */ + + /* construct device spec if none given. */ + + if (index (fullname, ':') == 0) + { + + /* If fullname has a slash, take it as device spec. */ + + if (first_slash == fullname) + { + first_slash = index (fullname+1, '/'); /* 2nd slash ? */ + if (first_slash) + *first_slash = ':'; /* make device spec */ + for (basename = fullname; *basename != 0; basename++) + *basename = *(basename+1); /* remove leading slash */ + } + else if ((first_slash[-1] != '.') /* keep ':/', './' */ + && (first_slash[-1] != ':') + && (first_slash[-1] != ']')) /* or a vms path */ + { + *first_slash = ':'; + } + else if ((first_slash[1] == '[') /* skip './' in './[dir' */ + && (first_slash[-1] == '.')) + fullname += 2; + } + + /* Get part after first ':' (basename[-1] == ':') + or last '/' (basename[-1] == '/'). */ + + basename = base_name (fullname); + + /* + * Check if we have a vax-c style '#include filename' + * and add the missing .h + */ + + if (vaxc_include && !index (basename,'.')) + strcat (basename, ".h"); + + local_ptr = Local; /* initialize */ + + /* We are trying to do a number of things here. First of all, we are + trying to hammer the filenames into a standard format, such that later + processing can handle them. + + If the file name contains something like [dir.], then it recognizes this + as a root, and strips the ".]". Later processing will add whatever is + needed to get things working properly. + + If no device is specified, then the first directory name is taken to be + a device name (or a rooted logical). */ + + /* Point to the UNIX filename part (which needs to be fixed!) + but skip vms path information. + [basename != fullname since first_slash != 0]. */ + + if ((basename[-1] == ':') /* vms path spec. */ + || (basename[-1] == ']') + || (basename[-1] == '>')) + unixname = basename; + else + unixname = fullname; + + if (*unixname == '/') + unixname++; + + /* If the directory spec is not rooted, we can just copy + the UNIX filename part and we are done. */ + + if (((basename - fullname) > 1) + && ( (basename[-1] == ']') + || (basename[-1] == '>'))) + { + if (basename[-2] != '.') + { + + /* The VMS part ends in a `]', and the preceding character is not a `.'. + -> PATH]:/name (basename = '/name', unixname = 'name') + We strip the `]', and then splice the two parts of the name in the + usual way. Given the default locations for include files in cccp.c, + we will only use this code if the user specifies alternate locations + with the /include (-I) switch on the command line. */ + + basename -= 1; /* Strip "]" */ + unixname--; /* backspace */ + } + else + { + + /* The VMS part has a ".]" at the end, and this will not do. Later + processing will add a second directory spec, and this would be a syntax + error. Thus we strip the ".]", and thus merge the directory specs. + We also backspace unixname, so that it points to a '/'. This inhibits the + generation of the 000000 root directory spec (which does not belong here + in this case). */ + + basename -= 2; /* Strip ".]" */ + unixname--; /* backspace */ + } + } + + else + + { + + /* We drop in here if there is no VMS style directory specification yet. + If there is no device specification either, we make the first dir a + device and try that. If we do not do this, then we will be essentially + searching the users default directory (as if they did a #include "asdf.h"). + + Then all we need to do is to push a '[' into the output string. Later + processing will fill this in, and close the bracket. */ + + if ((unixname != fullname) /* vms path spec found. */ + && (basename[-1] != ':')) + *local_ptr++ = ':'; /* dev not in spec. take first dir */ + + *local_ptr++ = '['; /* Open the directory specification */ + } + + if (unixname == fullname) /* no vms dir spec. */ + { + must_revert = 1; + if ((first_slash != 0) /* unix dir spec. */ + && (*unixname != '/') /* not beginning with '/' */ + && (*unixname != '.')) /* or './' or '../' */ + *local_ptr++ = '.'; /* dir is local ! */ + } + + /* at this point we assume that we have the device spec, and (at least + the opening "[" for a directory specification. We may have directories + specified already. + + If there are no other slashes then the filename will be + in the "root" directory. Otherwise, we need to add + directory specifications. */ + + if (index (unixname, '/') == 0) + { + /* if no directories specified yet and none are following. */ + if (local_ptr[-1] == '[') + { + /* Just add "000000]" as the directory string */ + strcpy (local_ptr, "000000]"); + local_ptr += strlen (local_ptr); + check_filename_before_returning = 1; /* we might need to fool with this later */ + } + } + else + { + + /* As long as there are still subdirectories to add, do them. */ + while (index (unixname, '/') != 0) + { + /* If this token is "." we can ignore it + if it's not at the beginning of a path. */ + if ((unixname[0] == '.') && (unixname[1] == '/')) + { + /* remove it at beginning of path. */ + if ( ((unixname == fullname) /* no device spec */ + && (fullname+2 != basename)) /* starts with ./ */ + /* or */ + || ((basename[-1] == ':') /* device spec */ + && (unixname-1 == basename))) /* and ./ afterwards */ + *local_ptr++ = '.'; /* make '[.' start of path. */ + unixname += 2; + continue; + } + + /* Add a subdirectory spec. Do not duplicate "." */ + if ( local_ptr[-1] != '.' + && local_ptr[-1] != '[' + && local_ptr[-1] != '<') + *local_ptr++ = '.'; + + /* If this is ".." then the spec becomes "-" */ + if ( (unixname[0] == '.') + && (unixname[1] == '.') + && (unixname[2] == '/')) + { + /* Add "-" and skip the ".." */ + if ((local_ptr[-1] == '.') + && (local_ptr[-2] == '[')) + local_ptr--; /* prevent [.- */ + *local_ptr++ = '-'; + unixname += 3; + continue; + } + + /* Copy the subdirectory */ + while (*unixname != '/') + *local_ptr++= *unixname++; + + unixname++; /* Skip the "/" */ + } + + /* Close the directory specification */ + if (local_ptr[-1] == '.') /* no trailing periods */ + local_ptr--; + + if (local_ptr[-1] == '[') /* no dir needed */ + local_ptr--; + else + *local_ptr++ = ']'; + } + + /* Now add the filename. */ + + while (*unixname) + *local_ptr++ = *unixname++; + *local_ptr = 0; + + /* Now append it to the original VMS spec. */ + + strcpy ((must_revert==1)?fullname:basename, Local); + + /* If we put a [000000] in the filename, try to open it first. If this fails, + remove the [000000], and return that name. This provides flexibility + to the user in that they can use both rooted and non-rooted logical names + to point to the location of the file. */ + + if (check_filename_before_returning) + { + f = open (fullname, O_RDONLY, 0666); + if (f >= 0) + { + /* The file name is OK as it is, so return it as is. */ + close (f); + return 1; + } + + /* The filename did not work. Try to remove the [000000] from the name, + and return it. */ + + basename = index (fullname, '['); + local_ptr = index (fullname, ']') + 1; + strcpy (basename, local_ptr); /* this gets rid of it */ + + } + + return 1; +} +#endif /* VMS */ + +#ifdef VMS + +/* The following wrapper functions supply additional arguments to the VMS + I/O routines to optimize performance with file handling. The arguments + are: + "mbc=16" - Set multi-block count to 16 (use a 8192 byte buffer). + "deq=64" - When extending the file, extend it in chunks of 32Kbytes. + "fop=tef"- Truncate unused portions of file when closing file. + "shr=nil"- Disallow file sharing while file is open. */ + +static FILE * +VMS_freopen (fname, type, oldfile) + char *fname; + char *type; + FILE *oldfile; +{ +#undef freopen /* Get back the real freopen routine. */ + if (strcmp (type, "w") == 0) + return freopen (fname, type, oldfile, + "mbc=16", "deq=64", "fop=tef", "shr=nil"); + return freopen (fname, type, oldfile, "mbc=16"); +} + +static FILE * +VMS_fopen (fname, type) + char *fname; + char *type; +{ +#undef fopen /* Get back the real fopen routine. */ + /* The gcc-vms-1.42 distribution's header files prototype fopen with two + fixed arguments, which matches ANSI's specification but not VAXCRTL's + pre-ANSI implementation. This hack circumvents the mismatch problem. */ + FILE *(*vmslib_fopen)() = (FILE *(*)()) fopen; + + if (*type == 'w') + return (*vmslib_fopen) (fname, type, "mbc=32", + "deq=64", "fop=tef", "shr=nil"); + else + return (*vmslib_fopen) (fname, type, "mbc=32"); +} + +static int +VMS_open (fname, flags, prot) + char *fname; + int flags; + int prot; +{ +#undef open /* Get back the real open routine. */ + return open (fname, flags, prot, "mbc=16", "deq=64", "fop=tef"); +} + +/* more VMS hackery */ +#include +#include + +extern unsigned long SYS$PARSE(), SYS$SEARCH(); + +/* Work around another library bug. If a file is located via a searchlist, + and if the device it's on is not the same device as the one specified + in the first element of that searchlist, then both stat() and fstat() + will fail to return info about it. `errno' will be set to EVMSERR, and + `vaxc$errno' will be set to SS$_NORMAL due yet another bug in stat()! + We can get around this by fully parsing the filename and then passing + that absolute name to stat(). + + Without this fix, we can end up failing to find header files, which is + bad enough, but then compounding the problem by reporting the reason for + failure as "normal successful completion." */ + +#undef fstat /* Get back to the library version. */ + +static int +VMS_fstat (fd, statbuf) + int fd; + struct stat *statbuf; +{ + int result = fstat (fd, statbuf); + + if (result < 0) + { + FILE *fp; + char nambuf[NAM$C_MAXRSS+1]; + + if ((fp = fdopen (fd, "r")) != 0 && fgetname (fp, nambuf) != 0) + result = VMS_stat (nambuf, statbuf); + /* No fclose(fp) here; that would close(fd) as well. */ + } + + return result; +} + +static int +VMS_stat (name, statbuf) + const char *name; + struct stat *statbuf; +{ + int result = stat (name, statbuf); + + if (result < 0) + { + struct FAB fab; + struct NAM nam; + char exp_nam[NAM$C_MAXRSS+1], /* expanded name buffer for SYS$PARSE */ + res_nam[NAM$C_MAXRSS+1]; /* resultant name buffer for SYS$SEARCH */ + + fab = cc$rms_fab; + fab.fab$l_fna = (char *) name; + fab.fab$b_fns = (unsigned char) strlen (name); + fab.fab$l_nam = (void *) &nam; + nam = cc$rms_nam; + nam.nam$l_esa = exp_nam, nam.nam$b_ess = sizeof exp_nam - 1; + nam.nam$l_rsa = res_nam, nam.nam$b_rss = sizeof res_nam - 1; + nam.nam$b_nop = NAM$M_PWD | NAM$M_NOCONCEAL; + if (SYS$PARSE (&fab) & 1) + { + if (SYS$SEARCH (&fab) & 1) + { + res_nam[nam.nam$b_rsl] = '\0'; + result = stat (res_nam, statbuf); + } + /* Clean up searchlist context cached by the system. */ + nam.nam$b_nop = NAM$M_SYNCHK; + fab.fab$l_fna = 0, fab.fab$b_fns = 0; + (void) SYS$PARSE (&fab); + } + } + + return result; +} +#endif /* VMS */ diff --git a/gcc_arm/cexp.y b/gcc_arm/cexp.y new file mode 100755 index 0000000..d63c4d1 --- /dev/null +++ b/gcc_arm/cexp.y @@ -0,0 +1,1248 @@ +/* Parse C expressions for CCCP. + Copyright (C) 1987, 1992, 94 - 97, 1998 Free Software Foundation. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! + + Adapted from expread.y of GDB by Paul Rubin, July 1986. */ + +/* Parse a C expression from text in a string */ + +%{ +#include "config.h" + +#define PRINTF_PROTO(ARGS, m, n) PVPROTO (ARGS) ATTRIBUTE_PRINTF(m, n) + +#define PRINTF_PROTO_1(ARGS) PRINTF_PROTO(ARGS, 1, 2) + +#include "system.h" +#include +/* #define YYDEBUG 1 */ + +#ifdef MULTIBYTE_CHARS +#include "mbchar.h" +#include +#endif /* MULTIBYTE_CHARS */ + +typedef unsigned char U_CHAR; + +/* This is used for communicating lists of keywords with cccp.c. */ +struct arglist { + struct arglist *next; + U_CHAR *name; + int length; + int argno; +}; + +/* Find the largest host integer type and set its size and type. + Watch out: on some crazy hosts `long' is shorter than `int'. */ + +#ifndef HOST_WIDE_INT +# if HAVE_INTTYPES_H +# include +# define HOST_WIDE_INT intmax_t +# define unsigned_HOST_WIDE_INT uintmax_t +# else +# if (HOST_BITS_PER_LONG <= HOST_BITS_PER_INT && HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_INT) +# define HOST_WIDE_INT int +# else +# if (HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_LONG || ! (defined LONG_LONG_MAX || defined LLONG_MAX)) +# define HOST_WIDE_INT long +# else +# define HOST_WIDE_INT long long +# endif +# endif +# endif +#endif + +#ifndef unsigned_HOST_WIDE_INT +#define unsigned_HOST_WIDE_INT unsigned HOST_WIDE_INT +#endif + +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif + +#ifndef HOST_BITS_PER_WIDE_INT +#define HOST_BITS_PER_WIDE_INT (CHAR_BIT * sizeof (HOST_WIDE_INT)) +#endif + +HOST_WIDE_INT parse_c_expression PROTO((char *, int)); + +static int yylex PROTO((void)); +static void yyerror PROTO((char *)) __attribute__ ((noreturn)); +static HOST_WIDE_INT expression_value; +#ifdef TEST_EXP_READER +static int expression_signedp; +#endif + +static jmp_buf parse_return_error; + +/* Nonzero means count most punctuation as part of a name. */ +static int keyword_parsing = 0; + +/* Nonzero means do not evaluate this expression. + This is a count, since unevaluated expressions can nest. */ +static int skip_evaluation; + +/* Nonzero means warn if undefined identifiers are evaluated. */ +static int warn_undef; + +/* some external tables of character types */ +extern unsigned char is_idstart[], is_idchar[], is_space[]; + +/* Flag for -pedantic. */ +extern int pedantic; + +/* Flag for -traditional. */ +extern int traditional; + +/* Flag for -lang-c89. */ +extern int c89; + +#ifndef CHAR_TYPE_SIZE +#define CHAR_TYPE_SIZE BITS_PER_UNIT +#endif + +#ifndef INT_TYPE_SIZE +#define INT_TYPE_SIZE BITS_PER_WORD +#endif + +#ifndef LONG_TYPE_SIZE +#define LONG_TYPE_SIZE BITS_PER_WORD +#endif + +#ifndef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE INT_TYPE_SIZE +#endif + +#ifndef MAX_CHAR_TYPE_SIZE +#define MAX_CHAR_TYPE_SIZE CHAR_TYPE_SIZE +#endif + +#ifndef MAX_INT_TYPE_SIZE +#define MAX_INT_TYPE_SIZE INT_TYPE_SIZE +#endif + +#ifndef MAX_LONG_TYPE_SIZE +#define MAX_LONG_TYPE_SIZE LONG_TYPE_SIZE +#endif + +#ifndef MAX_WCHAR_TYPE_SIZE +#define MAX_WCHAR_TYPE_SIZE WCHAR_TYPE_SIZE +#endif + +#define MAX_CHAR_TYPE_MASK (MAX_CHAR_TYPE_SIZE < HOST_BITS_PER_WIDE_INT \ + ? (~ (~ (HOST_WIDE_INT) 0 << MAX_CHAR_TYPE_SIZE)) \ + : ~ (HOST_WIDE_INT) 0) + +#define MAX_WCHAR_TYPE_MASK (MAX_WCHAR_TYPE_SIZE < HOST_BITS_PER_WIDE_INT \ + ? ~ (~ (HOST_WIDE_INT) 0 << MAX_WCHAR_TYPE_SIZE) \ + : ~ (HOST_WIDE_INT) 0) + +/* Suppose A1 + B1 = SUM1, using 2's complement arithmetic ignoring overflow. + Suppose A, B and SUM have the same respective signs as A1, B1, and SUM1. + Suppose SIGNEDP is negative if the result is signed, zero if unsigned. + Then this yields nonzero if overflow occurred during the addition. + Overflow occurs if A and B have the same sign, but A and SUM differ in sign, + and SIGNEDP is negative. + Use `^' to test whether signs differ, and `< 0' to isolate the sign. */ +#define overflow_sum_sign(a, b, sum, signedp) \ + ((~((a) ^ (b)) & ((a) ^ (sum)) & (signedp)) < 0) + +struct constant; + +HOST_WIDE_INT parse_escape PROTO((char **, HOST_WIDE_INT)); +int check_assertion PROTO((U_CHAR *, int, int, struct arglist *)); +struct hashnode *lookup PROTO((U_CHAR *, int, int)); +void error PRINTF_PROTO_1((char *, ...)); +void pedwarn PRINTF_PROTO_1((char *, ...)); +void warning PRINTF_PROTO_1((char *, ...)); + +static int parse_number PROTO((int)); +static HOST_WIDE_INT left_shift PROTO((struct constant *, unsigned_HOST_WIDE_INT)); +static HOST_WIDE_INT right_shift PROTO((struct constant *, unsigned_HOST_WIDE_INT)); +static void integer_overflow PROTO((void)); + +/* `signedp' values */ +#define SIGNED (~0) +#define UNSIGNED 0 +%} + +%union { + struct constant {HOST_WIDE_INT value; int signedp;} integer; + struct name {U_CHAR *address; int length;} name; + struct arglist *keywords; +} + +%type exp exp1 start +%type keywords +%token INT CHAR +%token NAME +%token ERROR + +%right '?' ':' +%left ',' +%left OR +%left AND +%left '|' +%left '^' +%left '&' +%left EQUAL NOTEQUAL +%left '<' '>' LEQ GEQ +%left LSH RSH +%left '+' '-' +%left '*' '/' '%' +%right UNARY + +/* %expect 40 */ + +%% + +start : exp1 + { + expression_value = $1.value; +#ifdef TEST_EXP_READER + expression_signedp = $1.signedp; +#endif + } + ; + +/* Expressions, including the comma operator. */ +exp1 : exp + | exp1 ',' exp + { if (pedantic) + pedwarn ("comma operator in operand of `#if'"); + $$ = $3; } + ; + +/* Expressions, not including the comma operator. */ +exp : '-' exp %prec UNARY + { $$.value = - $2.value; + $$.signedp = $2.signedp; + if (($$.value & $2.value & $$.signedp) < 0) + integer_overflow (); } + | '!' exp %prec UNARY + { $$.value = ! $2.value; + $$.signedp = SIGNED; } + | '+' exp %prec UNARY + { $$ = $2; } + | '~' exp %prec UNARY + { $$.value = ~ $2.value; + $$.signedp = $2.signedp; } + | '#' NAME + { $$.value = check_assertion ($2.address, $2.length, + 0, NULL_PTR); + $$.signedp = SIGNED; } + | '#' NAME + { keyword_parsing = 1; } + '(' keywords ')' + { $$.value = check_assertion ($2.address, $2.length, + 1, $5); + keyword_parsing = 0; + $$.signedp = SIGNED; } + | '(' exp1 ')' + { $$ = $2; } + ; + +/* Binary operators in order of decreasing precedence. */ +exp : exp '*' exp + { $$.signedp = $1.signedp & $3.signedp; + if ($$.signedp) + { + $$.value = $1.value * $3.value; + if ($1.value + && ($$.value / $1.value != $3.value + || ($$.value & $1.value & $3.value) < 0)) + integer_overflow (); + } + else + $$.value = ((unsigned_HOST_WIDE_INT) $1.value + * $3.value); } + | exp '/' exp + { if ($3.value == 0) + { + if (!skip_evaluation) + error ("division by zero in #if"); + $3.value = 1; + } + $$.signedp = $1.signedp & $3.signedp; + if ($$.signedp) + { + $$.value = $1.value / $3.value; + if (($$.value & $1.value & $3.value) < 0) + integer_overflow (); + } + else + $$.value = ((unsigned_HOST_WIDE_INT) $1.value + / $3.value); } + | exp '%' exp + { if ($3.value == 0) + { + if (!skip_evaluation) + error ("division by zero in #if"); + $3.value = 1; + } + $$.signedp = $1.signedp & $3.signedp; + if ($$.signedp) + $$.value = $1.value % $3.value; + else + $$.value = ((unsigned_HOST_WIDE_INT) $1.value + % $3.value); } + | exp '+' exp + { $$.value = $1.value + $3.value; + $$.signedp = $1.signedp & $3.signedp; + if (overflow_sum_sign ($1.value, $3.value, + $$.value, $$.signedp)) + integer_overflow (); } + | exp '-' exp + { $$.value = $1.value - $3.value; + $$.signedp = $1.signedp & $3.signedp; + if (overflow_sum_sign ($$.value, $3.value, + $1.value, $$.signedp)) + integer_overflow (); } + | exp LSH exp + { $$.signedp = $1.signedp; + if (($3.value & $3.signedp) < 0) + $$.value = right_shift (&$1, -$3.value); + else + $$.value = left_shift (&$1, $3.value); } + | exp RSH exp + { $$.signedp = $1.signedp; + if (($3.value & $3.signedp) < 0) + $$.value = left_shift (&$1, -$3.value); + else + $$.value = right_shift (&$1, $3.value); } + | exp EQUAL exp + { $$.value = ($1.value == $3.value); + $$.signedp = SIGNED; } + | exp NOTEQUAL exp + { $$.value = ($1.value != $3.value); + $$.signedp = SIGNED; } + | exp LEQ exp + { $$.signedp = SIGNED; + if ($1.signedp & $3.signedp) + $$.value = $1.value <= $3.value; + else + $$.value = ((unsigned_HOST_WIDE_INT) $1.value + <= $3.value); } + | exp GEQ exp + { $$.signedp = SIGNED; + if ($1.signedp & $3.signedp) + $$.value = $1.value >= $3.value; + else + $$.value = ((unsigned_HOST_WIDE_INT) $1.value + >= $3.value); } + | exp '<' exp + { $$.signedp = SIGNED; + if ($1.signedp & $3.signedp) + $$.value = $1.value < $3.value; + else + $$.value = ((unsigned_HOST_WIDE_INT) $1.value + < $3.value); } + | exp '>' exp + { $$.signedp = SIGNED; + if ($1.signedp & $3.signedp) + $$.value = $1.value > $3.value; + else + $$.value = ((unsigned_HOST_WIDE_INT) $1.value + > $3.value); } + | exp '&' exp + { $$.value = $1.value & $3.value; + $$.signedp = $1.signedp & $3.signedp; } + | exp '^' exp + { $$.value = $1.value ^ $3.value; + $$.signedp = $1.signedp & $3.signedp; } + | exp '|' exp + { $$.value = $1.value | $3.value; + $$.signedp = $1.signedp & $3.signedp; } + | exp AND + { skip_evaluation += !$1.value; } + exp + { skip_evaluation -= !$1.value; + $$.value = ($1.value && $4.value); + $$.signedp = SIGNED; } + | exp OR + { skip_evaluation += !!$1.value; } + exp + { skip_evaluation -= !!$1.value; + $$.value = ($1.value || $4.value); + $$.signedp = SIGNED; } + | exp '?' + { skip_evaluation += !$1.value; } + exp ':' + { skip_evaluation += !!$1.value - !$1.value; } + exp + { skip_evaluation -= !!$1.value; + $$.value = $1.value ? $4.value : $7.value; + $$.signedp = $4.signedp & $7.signedp; } + | INT + { $$ = yylval.integer; } + | CHAR + { $$ = yylval.integer; } + | NAME + { if (warn_undef && !skip_evaluation) + warning ("`%.*s' is not defined", + $1.length, $1.address); + $$.value = 0; + $$.signedp = SIGNED; } + ; + +keywords : + { $$ = 0; } + | '(' keywords ')' keywords + { struct arglist *temp; + $$ = (struct arglist *) xmalloc (sizeof (struct arglist)); + $$->next = $2; + $$->name = (U_CHAR *) "("; + $$->length = 1; + temp = $$; + while (temp != 0 && temp->next != 0) + temp = temp->next; + temp->next = (struct arglist *) xmalloc (sizeof (struct arglist)); + temp->next->next = $4; + temp->next->name = (U_CHAR *) ")"; + temp->next->length = 1; } + | NAME keywords + { $$ = (struct arglist *) xmalloc (sizeof (struct arglist)); + $$->name = $1.address; + $$->length = $1.length; + $$->next = $2; } + ; +%% + +/* During parsing of a C expression, the pointer to the next character + is in this variable. */ + +static char *lexptr; + +/* Take care of parsing a number (anything that starts with a digit). + Set yylval and return the token type; update lexptr. + LEN is the number of characters in it. */ + +/* maybe needs to actually deal with floating point numbers */ + +static int +parse_number (olen) + int olen; +{ + register char *p = lexptr; + register int c; + register unsigned_HOST_WIDE_INT n = 0, nd, max_over_base; + register int base = 10; + register int len = olen; + register int overflow = 0; + register int digit, largest_digit = 0; + int spec_long = 0; + + yylval.integer.signedp = SIGNED; + + if (*p == '0') { + base = 8; + if (len >= 3 && (p[1] == 'x' || p[1] == 'X')) { + p += 2; + base = 16; + len -= 2; + } + } + + max_over_base = (unsigned_HOST_WIDE_INT) -1 / base; + + for (; len > 0; len--) { + c = *p++; + + if (c >= '0' && c <= '9') + digit = c - '0'; + else if (base == 16 && c >= 'a' && c <= 'f') + digit = c - 'a' + 10; + else if (base == 16 && c >= 'A' && c <= 'F') + digit = c - 'A' + 10; + else { + /* `l' means long, and `u' means unsigned. */ + while (1) { + if (c == 'l' || c == 'L') + { + if (!pedantic < spec_long) + yyerror ("too many `l's in integer constant"); + spec_long++; + } + else if (c == 'u' || c == 'U') + { + if (! yylval.integer.signedp) + yyerror ("two `u's in integer constant"); + yylval.integer.signedp = UNSIGNED; + } + else { + if (c == '.' || c == 'e' || c == 'E' || c == 'p' || c == 'P') + yyerror ("Floating point numbers not allowed in #if expressions"); + else { + char *buf = (char *) alloca (p - lexptr + 40); + sprintf (buf, "missing white space after number `%.*s'", + (int) (p - lexptr - 1), lexptr); + yyerror (buf); + } + } + + if (--len == 0) + break; + c = *p++; + } + /* Don't look for any more digits after the suffixes. */ + break; + } + if (largest_digit < digit) + largest_digit = digit; + nd = n * base + digit; + overflow |= (max_over_base < n) | (nd < n); + n = nd; + } + + if (base <= largest_digit) + pedwarn ("integer constant contains digits beyond the radix"); + + if (overflow) + pedwarn ("integer constant out of range"); + + /* If too big to be signed, consider it unsigned. */ + if (((HOST_WIDE_INT) n & yylval.integer.signedp) < 0) + { + if (base == 10) + warning ("integer constant is so large that it is unsigned"); + yylval.integer.signedp = UNSIGNED; + } + + lexptr = p; + yylval.integer.value = n; + return INT; +} + +struct token { + char *operator; + int token; +}; + +static struct token tokentab2[] = { + {"&&", AND}, + {"||", OR}, + {"<<", LSH}, + {">>", RSH}, + {"==", EQUAL}, + {"!=", NOTEQUAL}, + {"<=", LEQ}, + {">=", GEQ}, + {"++", ERROR}, + {"--", ERROR}, + {NULL, ERROR} +}; + +/* Read one token, getting characters through lexptr. */ + +static int +yylex () +{ + register int c; + register int namelen; + register unsigned char *tokstart; + register struct token *toktab; + int wide_flag; + HOST_WIDE_INT mask; + + retry: + + tokstart = (unsigned char *) lexptr; + c = *tokstart; + /* See if it is a special token of length 2. */ + if (! keyword_parsing) + for (toktab = tokentab2; toktab->operator != NULL; toktab++) + if (c == *toktab->operator && tokstart[1] == toktab->operator[1]) { + lexptr += 2; + if (toktab->token == ERROR) + { + char *buf = (char *) alloca (40); + sprintf (buf, "`%s' not allowed in operand of `#if'", toktab->operator); + yyerror (buf); + } + return toktab->token; + } + + switch (c) { + case '\n': + return 0; + + case ' ': + case '\t': + case '\r': + lexptr++; + goto retry; + + case 'L': + /* Capital L may start a wide-string or wide-character constant. */ + if (lexptr[1] == '\'') + { + lexptr++; + wide_flag = 1; + mask = MAX_WCHAR_TYPE_MASK; + goto char_constant; + } + if (lexptr[1] == '"') + { + lexptr++; + wide_flag = 1; + mask = MAX_WCHAR_TYPE_MASK; + goto string_constant; + } + break; + + case '\'': + wide_flag = 0; + mask = MAX_CHAR_TYPE_MASK; + char_constant: + lexptr++; + if (keyword_parsing) { + char *start_ptr = lexptr - 1; + while (1) { + c = *lexptr++; + if (c == '\\') + c = parse_escape (&lexptr, mask); + else if (c == '\'') + break; + } + yylval.name.address = tokstart; + yylval.name.length = lexptr - start_ptr; + return NAME; + } + + /* This code for reading a character constant + handles multicharacter constants and wide characters. + It is mostly copied from c-lex.c. */ + { + register HOST_WIDE_INT result = 0; + register int num_chars = 0; + int chars_seen = 0; + unsigned width = MAX_CHAR_TYPE_SIZE; + int max_chars; +#ifdef MULTIBYTE_CHARS + int longest_char = local_mb_cur_max (); + char *token_buffer = (char *) alloca (longest_char); + (void) local_mbtowc (NULL_PTR, NULL_PTR, 0); +#endif + + max_chars = MAX_LONG_TYPE_SIZE / width; + if (wide_flag) + width = MAX_WCHAR_TYPE_SIZE; + + while (1) + { + c = *lexptr++; + + if (c == '\'' || c == EOF) + break; + + ++chars_seen; + if (c == '\\') + { + c = parse_escape (&lexptr, mask); + } + else + { +#ifdef MULTIBYTE_CHARS + wchar_t wc; + int i; + int char_len = -1; + for (i = 1; i <= longest_char; ++i) + { + token_buffer[i - 1] = c; + char_len = local_mbtowc (& wc, token_buffer, i); + if (char_len != -1) + break; + c = *lexptr++; + } + if (char_len > 1) + { + /* mbtowc sometimes needs an extra char before accepting */ + if (char_len < i) + lexptr--; + if (! wide_flag) + { + /* Merge character into result; ignore excess chars. */ + for (i = 1; i <= char_len; ++i) + { + if (i > max_chars) + break; + if (width < HOST_BITS_PER_INT) + result = (result << width) + | (token_buffer[i - 1] + & ((1 << width) - 1)); + else + result = token_buffer[i - 1]; + } + num_chars += char_len; + continue; + } + } + else + { + if (char_len == -1) + warning ("Ignoring invalid multibyte character"); + } + if (wide_flag) + c = wc; +#endif /* ! MULTIBYTE_CHARS */ + } + + if (wide_flag) + { + if (chars_seen == 1) /* only keep the first one */ + result = c; + continue; + } + + /* Merge character into result; ignore excess chars. */ + num_chars++; + if (num_chars <= max_chars) + { + if (width < HOST_BITS_PER_INT) + result = (result << width) | (c & ((1 << width) - 1)); + else + result = c; + } + } + + if (c != '\'') + error ("malformatted character constant"); + else if (chars_seen == 0) + error ("empty character constant"); + else if (num_chars > max_chars) + { + num_chars = max_chars; + error ("character constant too long"); + } + else if (chars_seen != 1 && ! traditional) + warning ("multi-character character constant"); + + /* If char type is signed, sign-extend the constant. */ + if (! wide_flag) + { + int num_bits = num_chars * width; + if (num_bits == 0) + /* We already got an error; avoid invalid shift. */ + yylval.integer.value = 0; + else if (lookup ((U_CHAR *) "__CHAR_UNSIGNED__", + sizeof ("__CHAR_UNSIGNED__") - 1, -1) + || ((result >> (num_bits - 1)) & 1) == 0) + yylval.integer.value + = result & (~ (unsigned_HOST_WIDE_INT) 0 + >> (HOST_BITS_PER_WIDE_INT - num_bits)); + else + yylval.integer.value + = result | ~(~ (unsigned_HOST_WIDE_INT) 0 + >> (HOST_BITS_PER_WIDE_INT - num_bits)); + } + else + { + yylval.integer.value = result; + } + } + + /* This is always a signed type. */ + yylval.integer.signedp = SIGNED; + + return CHAR; + + /* some of these chars are invalid in constant expressions; + maybe do something about them later */ + case '/': + case '+': + case '-': + case '*': + case '%': + case '|': + case '&': + case '^': + case '~': + case '!': + case '@': + case '<': + case '>': + case '[': + case ']': + case '.': + case '?': + case ':': + case '=': + case '{': + case '}': + case ',': + case '#': + if (keyword_parsing) + break; + case '(': + case ')': + lexptr++; + return c; + + case '"': + mask = MAX_CHAR_TYPE_MASK; + string_constant: + if (keyword_parsing) { + char *start_ptr = lexptr; + lexptr++; + while (1) { + c = *lexptr++; + if (c == '\\') + c = parse_escape (&lexptr, mask); + else if (c == '"') + break; + } + yylval.name.address = tokstart; + yylval.name.length = lexptr - start_ptr; + return NAME; + } + yyerror ("string constants not allowed in #if expressions"); + return ERROR; + } + + if (c >= '0' && c <= '9' && !keyword_parsing) { + /* It's a number */ + for (namelen = 1; ; namelen++) { + int d = tokstart[namelen]; + if (! ((is_idchar[d] || d == '.') + || ((d == '-' || d == '+') + && (c == 'e' || c == 'E' + || ((c == 'p' || c == 'P') && ! c89)) + && ! traditional))) + break; + c = d; + } + return parse_number (namelen); + } + + /* It is a name. See how long it is. */ + + if (keyword_parsing) { + for (namelen = 0;; namelen++) { + if (is_space[tokstart[namelen]]) + break; + if (tokstart[namelen] == '(' || tokstart[namelen] == ')') + break; + if (tokstart[namelen] == '"' || tokstart[namelen] == '\'') + break; + } + } else { + if (!is_idstart[c]) { + yyerror ("Invalid token in expression"); + return ERROR; + } + + for (namelen = 0; is_idchar[tokstart[namelen]]; namelen++) + ; + } + + lexptr += namelen; + yylval.name.address = tokstart; + yylval.name.length = namelen; + return NAME; +} + + +/* Parse a C escape sequence. STRING_PTR points to a variable + containing a pointer to the string to parse. That pointer + is updated past the characters we use. The value of the + escape sequence is returned. + + RESULT_MASK is used to mask out the result; + an error is reported if bits are lost thereby. + + A negative value means the sequence \ newline was seen, + which is supposed to be equivalent to nothing at all. + + If \ is followed by a null character, we return a negative + value and leave the string pointer pointing at the null character. + + If \ is followed by 000, we return 0 and leave the string pointer + after the zeros. A value of 0 does not mean end of string. */ + +HOST_WIDE_INT +parse_escape (string_ptr, result_mask) + char **string_ptr; + HOST_WIDE_INT result_mask; +{ + register int c = *(*string_ptr)++; + switch (c) + { + case 'a': + return TARGET_BELL; + case 'b': + return TARGET_BS; + case 'e': + case 'E': + if (pedantic) + pedwarn ("non-ANSI-standard escape sequence, `\\%c'", c); + return 033; + case 'f': + return TARGET_FF; + case 'n': + return TARGET_NEWLINE; + case 'r': + return TARGET_CR; + case 't': + return TARGET_TAB; + case 'v': + return TARGET_VT; + case '\n': + return -2; + case 0: + (*string_ptr)--; + return 0; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + register HOST_WIDE_INT i = c - '0'; + register int count = 0; + while (++count < 3) + { + c = *(*string_ptr)++; + if (c >= '0' && c <= '7') + i = (i << 3) + c - '0'; + else + { + (*string_ptr)--; + break; + } + } + if (i != (i & result_mask)) + { + i &= result_mask; + pedwarn ("octal escape sequence out of range"); + } + return i; + } + case 'x': + { + register unsigned_HOST_WIDE_INT i = 0, overflow = 0; + register int digits_found = 0, digit; + for (;;) + { + c = *(*string_ptr)++; + if (c >= '0' && c <= '9') + digit = c - '0'; + else if (c >= 'a' && c <= 'f') + digit = c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + digit = c - 'A' + 10; + else + { + (*string_ptr)--; + break; + } + overflow |= i ^ (i << 4 >> 4); + i = (i << 4) + digit; + digits_found = 1; + } + if (!digits_found) + yyerror ("\\x used with no following hex digits"); + if (overflow | (i != (i & result_mask))) + { + i &= result_mask; + pedwarn ("hex escape sequence out of range"); + } + return i; + } + default: + return c; + } +} + +static void +yyerror (s) + char *s; +{ + error ("%s", s); + skip_evaluation = 0; + longjmp (parse_return_error, 1); +} + +static void +integer_overflow () +{ + if (!skip_evaluation && pedantic) + pedwarn ("integer overflow in preprocessor expression"); +} + +static HOST_WIDE_INT +left_shift (a, b) + struct constant *a; + unsigned_HOST_WIDE_INT b; +{ + /* It's unclear from the C standard whether shifts can overflow. + The following code ignores overflow; perhaps a C standard + interpretation ruling is needed. */ + if (b >= HOST_BITS_PER_WIDE_INT) + return 0; + else + return (unsigned_HOST_WIDE_INT) a->value << b; +} + +static HOST_WIDE_INT +right_shift (a, b) + struct constant *a; + unsigned_HOST_WIDE_INT b; +{ + if (b >= HOST_BITS_PER_WIDE_INT) + return a->signedp ? a->value >> (HOST_BITS_PER_WIDE_INT - 1) : 0; + else if (a->signedp) + return a->value >> b; + else + return (unsigned_HOST_WIDE_INT) a->value >> b; +} + +/* This page contains the entry point to this file. */ + +/* Parse STRING as an expression, and complain if this fails + to use up all of the contents of STRING. + STRING may contain '\0' bytes; it is terminated by the first '\n' + outside a string constant, so that we can diagnose '\0' properly. + If WARN_UNDEFINED is nonzero, warn if undefined identifiers are evaluated. + We do not support C comments. They should be removed before + this function is called. */ + +HOST_WIDE_INT +parse_c_expression (string, warn_undefined) + char *string; + int warn_undefined; +{ + lexptr = string; + warn_undef = warn_undefined; + + /* if there is some sort of scanning error, just return 0 and assume + the parsing routine has printed an error message somewhere. + there is surely a better thing to do than this. */ + if (setjmp (parse_return_error)) + return 0; + + if (yyparse () != 0) + abort (); + + if (*lexptr != '\n') + error ("Junk after end of expression."); + + return expression_value; /* set by yyparse () */ +} + +#ifdef TEST_EXP_READER + +#if YYDEBUG +extern int yydebug; +#endif + +int pedantic; +int traditional; + +int main PROTO((int, char **)); +static void initialize_random_junk PROTO((void)); +static void print_unsigned_host_wide_int PROTO((unsigned_HOST_WIDE_INT)); + +/* Main program for testing purposes. */ +int +main (argc, argv) + int argc; + char **argv; +{ + int n, c; + char buf[1024]; + unsigned_HOST_WIDE_INT u; + + pedantic = 1 < argc; + traditional = 2 < argc; +#if YYDEBUG + yydebug = 3 < argc; +#endif + initialize_random_junk (); + + for (;;) { + printf ("enter expression: "); + n = 0; + while ((buf[n] = c = getchar ()) != '\n' && c != EOF) + n++; + if (c == EOF) + break; + parse_c_expression (buf, 1); + printf ("parser returned "); + u = (unsigned_HOST_WIDE_INT) expression_value; + if (expression_value < 0 && expression_signedp) { + u = -u; + printf ("-"); + } + if (u == 0) + printf ("0"); + else + print_unsigned_host_wide_int (u); + if (! expression_signedp) + printf("u"); + printf ("\n"); + } + + return 0; +} + +static void +print_unsigned_host_wide_int (u) + unsigned_HOST_WIDE_INT u; +{ + if (u) { + print_unsigned_host_wide_int (u / 10); + putchar ('0' + (int) (u % 10)); + } +} + +/* table to tell if char can be part of a C identifier. */ +unsigned char is_idchar[256]; +/* table to tell if char can be first char of a c identifier. */ +unsigned char is_idstart[256]; +/* table to tell if c is horizontal or vertical space. */ +unsigned char is_space[256]; + +/* + * initialize random junk in the hash table and maybe other places + */ +static void +initialize_random_junk () +{ + register int i; + + /* + * Set up is_idchar and is_idstart tables. These should be + * faster than saying (is_alpha (c) || c == '_'), etc. + * Must do set up these things before calling any routines tthat + * refer to them. + */ + for (i = 'a'; i <= 'z'; i++) { + ++is_idchar[i - 'a' + 'A']; + ++is_idchar[i]; + ++is_idstart[i - 'a' + 'A']; + ++is_idstart[i]; + } + for (i = '0'; i <= '9'; i++) + ++is_idchar[i]; + ++is_idchar['_']; + ++is_idstart['_']; + ++is_idchar['$']; + ++is_idstart['$']; + + ++is_space[' ']; + ++is_space['\t']; + ++is_space['\v']; + ++is_space['\f']; + ++is_space['\n']; + ++is_space['\r']; +} + +void +error VPROTO ((char * msg, ...)) +{ +#ifndef ANSI_PROTOTYPES + char * msg; +#endif + va_list args; + + VA_START (args, msg); + +#ifndef ANSI_PROTOTYPES + msg = va_arg (args, char *); +#endif + + fprintf (stderr, "error: "); + vfprintf (stderr, msg, args); + fprintf (stderr, "\n"); + va_end (args); +} + +void +pedwarn VPROTO ((char * msg, ...)) +{ +#ifndef ANSI_PROTOTYPES + char * msg; +#endif + va_list args; + + VA_START (args, msg); + +#ifndef ANSI_PROTOTYPES + msg = va_arg (args, char *); +#endif + + fprintf (stderr, "pedwarn: "); + vfprintf (stderr, msg, args); + fprintf (stderr, "\n"); + va_end (args); +} + +void +warning VPROTO ((char * msg, ...)) +{ +#ifndef ANSI_PROTOTYPES + char * msg; +#endif + va_list args; + + VA_START (args, msg); + +#ifndef ANSI_PROTOTYPES + msg = va_arg (args, char *); +#endif + + fprintf (stderr, "warning: "); + vfprintf (stderr, msg, args); + fprintf (stderr, "\n"); + va_end (args); +} + +int +check_assertion (name, sym_length, tokens_specified, tokens) + U_CHAR *name; + int sym_length; + int tokens_specified; + struct arglist *tokens; +{ + return 0; +} + +struct hashnode * +lookup (name, len, hash) + U_CHAR *name; + int len; + int hash; +{ + return (DEFAULT_SIGNED_CHAR) ? 0 : ((struct hashnode *) -1); +} + +PTR +xmalloc (size) + size_t size; +{ + return (PTR) malloc (size); +} +#endif diff --git a/gcc_arm/combine.c b/gcc_arm/combine.c new file mode 100755 index 0000000..3fd6fe9 --- /dev/null +++ b/gcc_arm/combine.c @@ -0,0 +1,12112 @@ +/* Optimize by combining instructions for GNU compiler. + Copyright (C) 1987, 88, 92-98, 1999 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* This module is essentially the "combiner" phase of the U. of Arizona + Portable Optimizer, but redone to work on our list-structured + representation for RTL instead of their string representation. + + The LOG_LINKS of each insn identify the most recent assignment + to each REG used in the insn. It is a list of previous insns, + each of which contains a SET for a REG that is used in this insn + and not used or set in between. LOG_LINKs never cross basic blocks. + They were set up by the preceding pass (lifetime analysis). + + We try to combine each pair of insns joined by a logical link. + We also try to combine triples of insns A, B and C when + C has a link back to B and B has a link back to A. + + LOG_LINKS does not have links for use of the CC0. They don't + need to, because the insn that sets the CC0 is always immediately + before the insn that tests it. So we always regard a branch + insn as having a logical link to the preceding insn. The same is true + for an insn explicitly using CC0. + + We check (with use_crosses_set_p) to avoid combining in such a way + as to move a computation to a place where its value would be different. + + Combination is done by mathematically substituting the previous + insn(s) values for the regs they set into the expressions in + the later insns that refer to these regs. If the result is a valid insn + for our target machine, according to the machine description, + we install it, delete the earlier insns, and update the data flow + information (LOG_LINKS and REG_NOTES) for what we did. + + There are a few exceptions where the dataflow information created by + flow.c aren't completely updated: + + - reg_live_length is not updated + - reg_n_refs is not adjusted in the rare case when a register is + no longer required in a computation + - there are extremely rare cases (see distribute_regnotes) when a + REG_DEAD note is lost + - a LOG_LINKS entry that refers to an insn with multiple SETs may be + removed because there is no way to know which register it was + linking + + To simplify substitution, we combine only when the earlier insn(s) + consist of only a single assignment. To simplify updating afterward, + we never combine when a subroutine call appears in the middle. + + Since we do not represent assignments to CC0 explicitly except when that + is all an insn does, there is no LOG_LINKS entry in an insn that uses + the condition code for the insn that set the condition code. + Fortunately, these two insns must be consecutive. + Therefore, every JUMP_INSN is taken to have an implicit logical link + to the preceding insn. This is not quite right, since non-jumps can + also use the condition code; but in practice such insns would not + combine anyway. */ + +#include "config.h" +#include "system.h" +#include "rtl.h" /* stdio.h must precede rtl.h for FFS. */ +#include "flags.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "basic-block.h" +#include "insn-config.h" +/* Include expr.h after insn-config.h so we get HAVE_conditional_move. */ +#include "expr.h" +#include "insn-flags.h" +#include "insn-codes.h" +#include "insn-attr.h" +#include "recog.h" +#include "real.h" +#include "toplev.h" + +/* It is not safe to use ordinary gen_lowpart in combine. + Use gen_lowpart_for_combine instead. See comments there. */ +#define gen_lowpart dont_use_gen_lowpart_you_dummy + +/* Number of attempts to combine instructions in this function. */ + +static int combine_attempts; + +/* Number of attempts that got as far as substitution in this function. */ + +static int combine_merges; + +/* Number of instructions combined with added SETs in this function. */ + +static int combine_extras; + +/* Number of instructions combined in this function. */ + +static int combine_successes; + +/* Totals over entire compilation. */ + +static int total_attempts, total_merges, total_extras, total_successes; + +/* Define a default value for REVERSIBLE_CC_MODE. + We can never assume that a condition code mode is safe to reverse unless + the md tells us so. */ +#ifndef REVERSIBLE_CC_MODE +#define REVERSIBLE_CC_MODE(MODE) 0 +#endif + +/* Vector mapping INSN_UIDs to cuids. + The cuids are like uids but increase monotonically always. + Combine always uses cuids so that it can compare them. + But actually renumbering the uids, which we used to do, + proves to be a bad idea because it makes it hard to compare + the dumps produced by earlier passes with those from later passes. */ + +static int *uid_cuid; +static int max_uid_cuid; + +/* Get the cuid of an insn. */ + +#define INSN_CUID(INSN) \ +(INSN_UID (INSN) > max_uid_cuid ? insn_cuid (INSN) : uid_cuid[INSN_UID (INSN)]) + +/* Maximum register number, which is the size of the tables below. */ + +static int combine_max_regno; + +/* Record last point of death of (hard or pseudo) register n. */ + +static rtx *reg_last_death; + +/* Record last point of modification of (hard or pseudo) register n. */ + +static rtx *reg_last_set; + +/* Record the cuid of the last insn that invalidated memory + (anything that writes memory, and subroutine calls, but not pushes). */ + +static int mem_last_set; + +/* Record the cuid of the last CALL_INSN + so we can tell whether a potential combination crosses any calls. */ + +static int last_call_cuid; + +/* When `subst' is called, this is the insn that is being modified + (by combining in a previous insn). The PATTERN of this insn + is still the old pattern partially modified and it should not be + looked at, but this may be used to examine the successors of the insn + to judge whether a simplification is valid. */ + +static rtx subst_insn; + +/* This is an insn that belongs before subst_insn, but is not currently + on the insn chain. */ + +static rtx subst_prev_insn; + +/* This is the lowest CUID that `subst' is currently dealing with. + get_last_value will not return a value if the register was set at or + after this CUID. If not for this mechanism, we could get confused if + I2 or I1 in try_combine were an insn that used the old value of a register + to obtain a new value. In that case, we might erroneously get the + new value of the register when we wanted the old one. */ + +static int subst_low_cuid; + +/* This contains any hard registers that are used in newpat; reg_dead_at_p + must consider all these registers to be always live. */ + +static HARD_REG_SET newpat_used_regs; + +/* This is an insn to which a LOG_LINKS entry has been added. If this + insn is the earlier than I2 or I3, combine should rescan starting at + that location. */ + +static rtx added_links_insn; + +/* Basic block number of the block in which we are performing combines. */ +static int this_basic_block; + +/* The next group of arrays allows the recording of the last value assigned + to (hard or pseudo) register n. We use this information to see if a + operation being processed is redundant given a prior operation performed + on the register. For example, an `and' with a constant is redundant if + all the zero bits are already known to be turned off. + + We use an approach similar to that used by cse, but change it in the + following ways: + + (1) We do not want to reinitialize at each label. + (2) It is useful, but not critical, to know the actual value assigned + to a register. Often just its form is helpful. + + Therefore, we maintain the following arrays: + + reg_last_set_value the last value assigned + reg_last_set_label records the value of label_tick when the + register was assigned + reg_last_set_table_tick records the value of label_tick when a + value using the register is assigned + reg_last_set_invalid set to non-zero when it is not valid + to use the value of this register in some + register's value + + To understand the usage of these tables, it is important to understand + the distinction between the value in reg_last_set_value being valid + and the register being validly contained in some other expression in the + table. + + Entry I in reg_last_set_value is valid if it is non-zero, and either + reg_n_sets[i] is 1 or reg_last_set_label[i] == label_tick. + + Register I may validly appear in any expression returned for the value + of another register if reg_n_sets[i] is 1. It may also appear in the + value for register J if reg_last_set_label[i] < reg_last_set_label[j] or + reg_last_set_invalid[j] is zero. + + If an expression is found in the table containing a register which may + not validly appear in an expression, the register is replaced by + something that won't match, (clobber (const_int 0)). + + reg_last_set_invalid[i] is set non-zero when register I is being assigned + to and reg_last_set_table_tick[i] == label_tick. */ + +/* Record last value assigned to (hard or pseudo) register n. */ + +static rtx *reg_last_set_value; + +/* Record the value of label_tick when the value for register n is placed in + reg_last_set_value[n]. */ + +static int *reg_last_set_label; + +/* Record the value of label_tick when an expression involving register n + is placed in reg_last_set_value. */ + +static int *reg_last_set_table_tick; + +/* Set non-zero if references to register n in expressions should not be + used. */ + +static char *reg_last_set_invalid; + +/* Incremented for each label. */ + +static int label_tick; + +/* Some registers that are set more than once and used in more than one + basic block are nevertheless always set in similar ways. For example, + a QImode register may be loaded from memory in two places on a machine + where byte loads zero extend. + + We record in the following array what we know about the nonzero + bits of a register, specifically which bits are known to be zero. + + If an entry is zero, it means that we don't know anything special. */ + +static unsigned HOST_WIDE_INT *reg_nonzero_bits; + +/* Mode used to compute significance in reg_nonzero_bits. It is the largest + integer mode that can fit in HOST_BITS_PER_WIDE_INT. */ + +static enum machine_mode nonzero_bits_mode; + +/* Nonzero if we know that a register has some leading bits that are always + equal to the sign bit. */ + +static char *reg_sign_bit_copies; + +/* Nonzero when reg_nonzero_bits and reg_sign_bit_copies can be safely used. + It is zero while computing them and after combine has completed. This + former test prevents propagating values based on previously set values, + which can be incorrect if a variable is modified in a loop. */ + +static int nonzero_sign_valid; + +/* These arrays are maintained in parallel with reg_last_set_value + and are used to store the mode in which the register was last set, + the bits that were known to be zero when it was last set, and the + number of sign bits copies it was known to have when it was last set. */ + +static enum machine_mode *reg_last_set_mode; +static unsigned HOST_WIDE_INT *reg_last_set_nonzero_bits; +static char *reg_last_set_sign_bit_copies; + +/* Record one modification to rtl structure + to be undone by storing old_contents into *where. + is_int is 1 if the contents are an int. */ + +struct undo +{ + struct undo *next; + int is_int; + union {rtx r; int i;} old_contents; + union {rtx *r; int *i;} where; +}; + +/* Record a bunch of changes to be undone, up to MAX_UNDO of them. + num_undo says how many are currently recorded. + + storage is nonzero if we must undo the allocation of new storage. + The value of storage is what to pass to obfree. + + other_insn is nonzero if we have modified some other insn in the process + of working on subst_insn. It must be verified too. + + previous_undos is the value of undobuf.undos when we started processing + this substitution. This will prevent gen_rtx_combine from re-used a piece + from the previous expression. Doing so can produce circular rtl + structures. */ + +struct undobuf +{ + char *storage; + struct undo *undos; + struct undo *frees; + struct undo *previous_undos; + rtx other_insn; +}; + +static struct undobuf undobuf; + +/* Substitute NEWVAL, an rtx expression, into INTO, a place in some + insn. The substitution can be undone by undo_all. If INTO is already + set to NEWVAL, do not record this change. Because computing NEWVAL might + also call SUBST, we have to compute it before we put anything into + the undo table. */ + +#define SUBST(INTO, NEWVAL) \ + do { rtx _new = (NEWVAL); \ + struct undo *_buf; \ + \ + if (undobuf.frees) \ + _buf = undobuf.frees, undobuf.frees = _buf->next; \ + else \ + _buf = (struct undo *) xmalloc (sizeof (struct undo)); \ + \ + _buf->is_int = 0; \ + _buf->where.r = &INTO; \ + _buf->old_contents.r = INTO; \ + INTO = _new; \ + if (_buf->old_contents.r == INTO) \ + _buf->next = undobuf.frees, undobuf.frees = _buf; \ + else \ + _buf->next = undobuf.undos, undobuf.undos = _buf; \ + } while (0) + +/* Similar to SUBST, but NEWVAL is an int expression. Note that substitution + for the value of a HOST_WIDE_INT value (including CONST_INT) is + not safe. */ + +#define SUBST_INT(INTO, NEWVAL) \ + do { struct undo *_buf; \ + \ + if (undobuf.frees) \ + _buf = undobuf.frees, undobuf.frees = _buf->next; \ + else \ + _buf = (struct undo *) xmalloc (sizeof (struct undo)); \ + \ + _buf->is_int = 1; \ + _buf->where.i = (int *) &INTO; \ + _buf->old_contents.i = INTO; \ + INTO = NEWVAL; \ + if (_buf->old_contents.i == INTO) \ + _buf->next = undobuf.frees, undobuf.frees = _buf; \ + else \ + _buf->next = undobuf.undos, undobuf.undos = _buf; \ + } while (0) + +/* Number of times the pseudo being substituted for + was found and replaced. */ + +static int n_occurrences; + +static void init_reg_last_arrays PROTO((void)); +static void setup_incoming_promotions PROTO((void)); +static void set_nonzero_bits_and_sign_copies PROTO((rtx, rtx)); +static int can_combine_p PROTO((rtx, rtx, rtx, rtx, rtx *, rtx *)); +static int sets_function_arg_p PROTO((rtx)); +static int combinable_i3pat PROTO((rtx, rtx *, rtx, rtx, int, rtx *)); +static rtx try_combine PROTO((rtx, rtx, rtx)); +static void undo_all PROTO((void)); +static rtx *find_split_point PROTO((rtx *, rtx)); +static rtx subst PROTO((rtx, rtx, rtx, int, int)); +static rtx simplify_rtx PROTO((rtx, enum machine_mode, int, int)); +static rtx simplify_if_then_else PROTO((rtx)); +static rtx simplify_set PROTO((rtx)); +static rtx simplify_logical PROTO((rtx, int)); +static rtx expand_compound_operation PROTO((rtx)); +static rtx expand_field_assignment PROTO((rtx)); +static rtx make_extraction PROTO((enum machine_mode, rtx, int, rtx, int, + int, int, int)); +static rtx extract_left_shift PROTO((rtx, int)); +static rtx make_compound_operation PROTO((rtx, enum rtx_code)); +static int get_pos_from_mask PROTO((unsigned HOST_WIDE_INT, int *)); +static rtx force_to_mode PROTO((rtx, enum machine_mode, + unsigned HOST_WIDE_INT, rtx, int)); +static rtx if_then_else_cond PROTO((rtx, rtx *, rtx *)); +static rtx known_cond PROTO((rtx, enum rtx_code, rtx, rtx)); +static int rtx_equal_for_field_assignment_p PROTO((rtx, rtx)); +static rtx make_field_assignment PROTO((rtx)); +static rtx apply_distributive_law PROTO((rtx)); +static rtx simplify_and_const_int PROTO((rtx, enum machine_mode, rtx, + unsigned HOST_WIDE_INT)); +static unsigned HOST_WIDE_INT nonzero_bits PROTO((rtx, enum machine_mode)); +static int num_sign_bit_copies PROTO((rtx, enum machine_mode)); +static int merge_outer_ops PROTO((enum rtx_code *, HOST_WIDE_INT *, + enum rtx_code, HOST_WIDE_INT, + enum machine_mode, int *)); +static rtx simplify_shift_const PROTO((rtx, enum rtx_code, enum machine_mode, + rtx, int)); +static int recog_for_combine PROTO((rtx *, rtx, rtx *)); +static rtx gen_lowpart_for_combine PROTO((enum machine_mode, rtx)); +static rtx gen_rtx_combine PVPROTO((enum rtx_code code, enum machine_mode mode, + ...)); +static rtx gen_binary PROTO((enum rtx_code, enum machine_mode, + rtx, rtx)); +static rtx gen_unary PROTO((enum rtx_code, enum machine_mode, + enum machine_mode, rtx)); +static enum rtx_code simplify_comparison PROTO((enum rtx_code, rtx *, rtx *)); +static int reversible_comparison_p PROTO((rtx)); +static void update_table_tick PROTO((rtx)); +static void record_value_for_reg PROTO((rtx, rtx, rtx)); +static void record_dead_and_set_regs_1 PROTO((rtx, rtx)); +static void record_dead_and_set_regs PROTO((rtx)); +static int get_last_value_validate PROTO((rtx *, rtx, int, int)); +static rtx get_last_value PROTO((rtx)); +static int use_crosses_set_p PROTO((rtx, int)); +static void reg_dead_at_p_1 PROTO((rtx, rtx)); +static int reg_dead_at_p PROTO((rtx, rtx)); +static void move_deaths PROTO((rtx, rtx, int, rtx, rtx *)); +static int reg_bitfield_target_p PROTO((rtx, rtx)); +static void distribute_notes PROTO((rtx, rtx, rtx, rtx, rtx, rtx)); +static void distribute_links PROTO((rtx)); +static void mark_used_regs_combine PROTO((rtx)); +static int insn_cuid PROTO((rtx)); + +/* Main entry point for combiner. F is the first insn of the function. + NREGS is the first unused pseudo-reg number. */ + +void +combine_instructions (f, nregs) + rtx f; + int nregs; +{ + register rtx insn, next; +#ifdef HAVE_cc0 + register rtx prev; +#endif + register int i; + register rtx links, nextlinks; + + combine_attempts = 0; + combine_merges = 0; + combine_extras = 0; + combine_successes = 0; + undobuf.undos = undobuf.previous_undos = 0; + + combine_max_regno = nregs; + + reg_nonzero_bits + = (unsigned HOST_WIDE_INT *) alloca (nregs * sizeof (HOST_WIDE_INT)); + reg_sign_bit_copies = (char *) alloca (nregs * sizeof (char)); + + bzero ((char *) reg_nonzero_bits, nregs * sizeof (HOST_WIDE_INT)); + bzero (reg_sign_bit_copies, nregs * sizeof (char)); + + reg_last_death = (rtx *) alloca (nregs * sizeof (rtx)); + reg_last_set = (rtx *) alloca (nregs * sizeof (rtx)); + reg_last_set_value = (rtx *) alloca (nregs * sizeof (rtx)); + reg_last_set_table_tick = (int *) alloca (nregs * sizeof (int)); + reg_last_set_label = (int *) alloca (nregs * sizeof (int)); + reg_last_set_invalid = (char *) alloca (nregs * sizeof (char)); + reg_last_set_mode + = (enum machine_mode *) alloca (nregs * sizeof (enum machine_mode)); + reg_last_set_nonzero_bits + = (unsigned HOST_WIDE_INT *) alloca (nregs * sizeof (HOST_WIDE_INT)); + reg_last_set_sign_bit_copies + = (char *) alloca (nregs * sizeof (char)); + + init_reg_last_arrays (); + + init_recog_no_volatile (); + + /* Compute maximum uid value so uid_cuid can be allocated. */ + + for (insn = f, i = 0; insn; insn = NEXT_INSN (insn)) + if (INSN_UID (insn) > i) + i = INSN_UID (insn); + + uid_cuid = (int *) alloca ((i + 1) * sizeof (int)); + max_uid_cuid = i; + + nonzero_bits_mode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0); + + /* Don't use reg_nonzero_bits when computing it. This can cause problems + when, for example, we have j <<= 1 in a loop. */ + + nonzero_sign_valid = 0; + + /* Compute the mapping from uids to cuids. + Cuids are numbers assigned to insns, like uids, + except that cuids increase monotonically through the code. + + Scan all SETs and see if we can deduce anything about what + bits are known to be zero for some registers and how many copies + of the sign bit are known to exist for those registers. + + Also set any known values so that we can use it while searching + for what bits are known to be set. */ + + label_tick = 1; + + /* We need to initialize it here, because record_dead_and_set_regs may call + get_last_value. */ + subst_prev_insn = NULL_RTX; + + setup_incoming_promotions (); + + for (insn = f, i = 0; insn; insn = NEXT_INSN (insn)) + { + uid_cuid[INSN_UID (insn)] = ++i; + subst_low_cuid = i; + subst_insn = insn; + + if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') + { + note_stores (PATTERN (insn), set_nonzero_bits_and_sign_copies); + record_dead_and_set_regs (insn); + +#ifdef AUTO_INC_DEC + for (links = REG_NOTES (insn); links; links = XEXP (links, 1)) + if (REG_NOTE_KIND (links) == REG_INC) + set_nonzero_bits_and_sign_copies (XEXP (links, 0), NULL_RTX); +#endif + } + + if (GET_CODE (insn) == CODE_LABEL) + label_tick++; + } + + nonzero_sign_valid = 1; + + /* Now scan all the insns in forward order. */ + + this_basic_block = -1; + label_tick = 1; + last_call_cuid = 0; + mem_last_set = 0; + init_reg_last_arrays (); + setup_incoming_promotions (); + + for (insn = f; insn; insn = next ? next : NEXT_INSN (insn)) + { + next = 0; + + /* If INSN starts a new basic block, update our basic block number. */ + if (this_basic_block + 1 < n_basic_blocks + && BLOCK_HEAD (this_basic_block + 1) == insn) + this_basic_block++; + + if (GET_CODE (insn) == CODE_LABEL) + label_tick++; + + else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') + { + /* Try this insn with each insn it links back to. */ + + for (links = LOG_LINKS (insn); links; links = XEXP (links, 1)) + if ((next = try_combine (insn, XEXP (links, 0), NULL_RTX)) != 0) + goto retry; + + /* Try each sequence of three linked insns ending with this one. */ + + for (links = LOG_LINKS (insn); links; links = XEXP (links, 1)) + for (nextlinks = LOG_LINKS (XEXP (links, 0)); nextlinks; + nextlinks = XEXP (nextlinks, 1)) + if ((next = try_combine (insn, XEXP (links, 0), + XEXP (nextlinks, 0))) != 0) + goto retry; + +#ifdef HAVE_cc0 + /* Try to combine a jump insn that uses CC0 + with a preceding insn that sets CC0, and maybe with its + logical predecessor as well. + This is how we make decrement-and-branch insns. + We need this special code because data flow connections + via CC0 do not get entered in LOG_LINKS. */ + + if (GET_CODE (insn) == JUMP_INSN + && (prev = prev_nonnote_insn (insn)) != 0 + && GET_CODE (prev) == INSN + && sets_cc0_p (PATTERN (prev))) + { + if ((next = try_combine (insn, prev, NULL_RTX)) != 0) + goto retry; + + for (nextlinks = LOG_LINKS (prev); nextlinks; + nextlinks = XEXP (nextlinks, 1)) + if ((next = try_combine (insn, prev, + XEXP (nextlinks, 0))) != 0) + goto retry; + } + + /* Do the same for an insn that explicitly references CC0. */ + if (GET_CODE (insn) == INSN + && (prev = prev_nonnote_insn (insn)) != 0 + && GET_CODE (prev) == INSN + && sets_cc0_p (PATTERN (prev)) + && GET_CODE (PATTERN (insn)) == SET + && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (insn)))) + { + if ((next = try_combine (insn, prev, NULL_RTX)) != 0) + goto retry; + + for (nextlinks = LOG_LINKS (prev); nextlinks; + nextlinks = XEXP (nextlinks, 1)) + if ((next = try_combine (insn, prev, + XEXP (nextlinks, 0))) != 0) + goto retry; + } + + /* Finally, see if any of the insns that this insn links to + explicitly references CC0. If so, try this insn, that insn, + and its predecessor if it sets CC0. */ + for (links = LOG_LINKS (insn); links; links = XEXP (links, 1)) + if (GET_CODE (XEXP (links, 0)) == INSN + && GET_CODE (PATTERN (XEXP (links, 0))) == SET + && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (XEXP (links, 0)))) + && (prev = prev_nonnote_insn (XEXP (links, 0))) != 0 + && GET_CODE (prev) == INSN + && sets_cc0_p (PATTERN (prev)) + && (next = try_combine (insn, XEXP (links, 0), prev)) != 0) + goto retry; +#endif + + /* Try combining an insn with two different insns whose results it + uses. */ + for (links = LOG_LINKS (insn); links; links = XEXP (links, 1)) + for (nextlinks = XEXP (links, 1); nextlinks; + nextlinks = XEXP (nextlinks, 1)) + if ((next = try_combine (insn, XEXP (links, 0), + XEXP (nextlinks, 0))) != 0) + goto retry; + + if (GET_CODE (insn) != NOTE) + record_dead_and_set_regs (insn); + + retry: + ; + } + } + + total_attempts += combine_attempts; + total_merges += combine_merges; + total_extras += combine_extras; + total_successes += combine_successes; + + nonzero_sign_valid = 0; + + /* Make recognizer allow volatile MEMs again. */ + init_recog (); +} + +/* Wipe the reg_last_xxx arrays in preparation for another pass. */ + +static void +init_reg_last_arrays () +{ + int nregs = combine_max_regno; + + bzero ((char *) reg_last_death, nregs * sizeof (rtx)); + bzero ((char *) reg_last_set, nregs * sizeof (rtx)); + bzero ((char *) reg_last_set_value, nregs * sizeof (rtx)); + bzero ((char *) reg_last_set_table_tick, nregs * sizeof (int)); + bzero ((char *) reg_last_set_label, nregs * sizeof (int)); + bzero (reg_last_set_invalid, nregs * sizeof (char)); + bzero ((char *) reg_last_set_mode, nregs * sizeof (enum machine_mode)); + bzero ((char *) reg_last_set_nonzero_bits, nregs * sizeof (HOST_WIDE_INT)); + bzero (reg_last_set_sign_bit_copies, nregs * sizeof (char)); +} + +/* Set up any promoted values for incoming argument registers. */ + +static void +setup_incoming_promotions () +{ +#ifdef PROMOTE_FUNCTION_ARGS + int regno; + rtx reg; + enum machine_mode mode; + int unsignedp; + rtx first = get_insns (); + + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if (FUNCTION_ARG_REGNO_P (regno) + && (reg = promoted_input_arg (regno, &mode, &unsignedp)) != 0) + { + record_value_for_reg + (reg, first, gen_rtx_fmt_e ((unsignedp ? ZERO_EXTEND + : SIGN_EXTEND), + GET_MODE (reg), + gen_rtx_CLOBBER (mode, const0_rtx))); + } +#endif +} + +/* Called via note_stores. If X is a pseudo that is narrower than + HOST_BITS_PER_WIDE_INT and is being set, record what bits are known zero. + + If we are setting only a portion of X and we can't figure out what + portion, assume all bits will be used since we don't know what will + be happening. + + Similarly, set how many bits of X are known to be copies of the sign bit + at all locations in the function. This is the smallest number implied + by any set of X. */ + +static void +set_nonzero_bits_and_sign_copies (x, set) + rtx x; + rtx set; +{ + int num; + + if (GET_CODE (x) == REG + && REGNO (x) >= FIRST_PSEUDO_REGISTER + /* If this register is undefined at the start of the file, we can't + say what its contents were. */ + && ! REGNO_REG_SET_P (basic_block_live_at_start[0], REGNO (x)) + && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT) + { + if (set == 0 || GET_CODE (set) == CLOBBER) + { + reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x)); + reg_sign_bit_copies[REGNO (x)] = 1; + return; + } + + /* If this is a complex assignment, see if we can convert it into a + simple assignment. */ + set = expand_field_assignment (set); + + /* If this is a simple assignment, or we have a paradoxical SUBREG, + set what we know about X. */ + + if (SET_DEST (set) == x + || (GET_CODE (SET_DEST (set)) == SUBREG + && (GET_MODE_SIZE (GET_MODE (SET_DEST (set))) + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (set))))) + && SUBREG_REG (SET_DEST (set)) == x)) + { + rtx src = SET_SRC (set); + +#ifdef SHORT_IMMEDIATES_SIGN_EXTEND + /* If X is narrower than a word and SRC is a non-negative + constant that would appear negative in the mode of X, + sign-extend it for use in reg_nonzero_bits because some + machines (maybe most) will actually do the sign-extension + and this is the conservative approach. + + ??? For 2.5, try to tighten up the MD files in this regard + instead of this kludge. */ + + if (GET_MODE_BITSIZE (GET_MODE (x)) < BITS_PER_WORD + && GET_CODE (src) == CONST_INT + && INTVAL (src) > 0 + && 0 != (INTVAL (src) + & ((HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (GET_MODE (x)) - 1)))) + src = GEN_INT (INTVAL (src) + | ((HOST_WIDE_INT) (-1) + << GET_MODE_BITSIZE (GET_MODE (x)))); +#endif + + reg_nonzero_bits[REGNO (x)] + |= nonzero_bits (src, nonzero_bits_mode); + num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x)); + if (reg_sign_bit_copies[REGNO (x)] == 0 + || reg_sign_bit_copies[REGNO (x)] > num) + reg_sign_bit_copies[REGNO (x)] = num; + } + else + { + reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x)); + reg_sign_bit_copies[REGNO (x)] = 1; + } + } +} + +/* See if INSN can be combined into I3. PRED and SUCC are optionally + insns that were previously combined into I3 or that will be combined + into the merger of INSN and I3. + + Return 0 if the combination is not allowed for any reason. + + If the combination is allowed, *PDEST will be set to the single + destination of INSN and *PSRC to the single source, and this function + will return 1. */ + +static int +can_combine_p (insn, i3, pred, succ, pdest, psrc) + rtx insn; + rtx i3; + rtx pred ATTRIBUTE_UNUSED; + rtx succ; + rtx *pdest, *psrc; +{ + int i; + rtx set = 0, src, dest; + rtx p; +#ifdef AUTO_INC_DEC + rtx link; +#endif + int all_adjacent = (succ ? (next_active_insn (insn) == succ + && next_active_insn (succ) == i3) + : next_active_insn (insn) == i3); + + /* Can combine only if previous insn is a SET of a REG, a SUBREG or CC0. + or a PARALLEL consisting of such a SET and CLOBBERs. + + If INSN has CLOBBER parallel parts, ignore them for our processing. + By definition, these happen during the execution of the insn. When it + is merged with another insn, all bets are off. If they are, in fact, + needed and aren't also supplied in I3, they may be added by + recog_for_combine. Otherwise, it won't match. + + We can also ignore a SET whose SET_DEST is mentioned in a REG_UNUSED + note. + + Get the source and destination of INSN. If more than one, can't + combine. */ + + if (GET_CODE (PATTERN (insn)) == SET) + set = PATTERN (insn); + else if (GET_CODE (PATTERN (insn)) == PARALLEL + && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET) + { + for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++) + { + rtx elt = XVECEXP (PATTERN (insn), 0, i); + + switch (GET_CODE (elt)) + { + /* This is important to combine floating point insns + for the SH4 port. */ + case USE: + /* Combining an isolated USE doesn't make sense. + We depend here on combinable_i3_pat to reject them. */ + /* The code below this loop only verifies that the inputs of + the SET in INSN do not change. We call reg_set_between_p + to verify that the REG in the USE does not change betweeen + I3 and INSN. + If the USE in INSN was for a pseudo register, the matching + insn pattern will likely match any register; combining this + with any other USE would only be safe if we knew that the + used registers have identical values, or if there was + something to tell them apart, e.g. different modes. For + now, we forgo such compilcated tests and simply disallow + combining of USES of pseudo registers with any other USE. */ + if (GET_CODE (XEXP (elt, 0)) == REG + && GET_CODE (PATTERN (i3)) == PARALLEL) + { + rtx i3pat = PATTERN (i3); + int i = XVECLEN (i3pat, 0) - 1; + int regno = REGNO (XEXP (elt, 0)); + do + { + rtx i3elt = XVECEXP (i3pat, 0, i); + if (GET_CODE (i3elt) == USE + && GET_CODE (XEXP (i3elt, 0)) == REG + && (REGNO (XEXP (i3elt, 0)) == regno + ? reg_set_between_p (XEXP (elt, 0), + PREV_INSN (insn), i3) + : regno >= FIRST_PSEUDO_REGISTER)) + return 0; + } + while (--i >= 0); + } + break; + + /* We can ignore CLOBBERs. */ + case CLOBBER: + break; + + case SET: + /* Ignore SETs whose result isn't used but not those that + have side-effects. */ + if (find_reg_note (insn, REG_UNUSED, SET_DEST (elt)) + && ! side_effects_p (elt)) + break; + + /* If we have already found a SET, this is a second one and + so we cannot combine with this insn. */ + if (set) + return 0; + + set = elt; + break; + + default: + /* Anything else means we can't combine. */ + return 0; + } + } + + if (set == 0 + /* If SET_SRC is an ASM_OPERANDS we can't throw away these CLOBBERs, + so don't do anything with it. */ + || GET_CODE (SET_SRC (set)) == ASM_OPERANDS) + return 0; + } + else + return 0; + + if (set == 0) + return 0; + + set = expand_field_assignment (set); + src = SET_SRC (set), dest = SET_DEST (set); + + /* Don't eliminate a store in the stack pointer. */ + if (dest == stack_pointer_rtx + /* If we couldn't eliminate a field assignment, we can't combine. */ + || GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == STRICT_LOW_PART + /* Don't combine with an insn that sets a register to itself if it has + a REG_EQUAL note. This may be part of a REG_NO_CONFLICT sequence. */ + || (rtx_equal_p (src, dest) && find_reg_note (insn, REG_EQUAL, NULL_RTX)) + /* Can't merge a function call. */ + || GET_CODE (src) == CALL + /* Don't eliminate a function call argument. */ + || (GET_CODE (i3) == CALL_INSN + && (find_reg_fusage (i3, USE, dest) + || (GET_CODE (dest) == REG + && REGNO (dest) < FIRST_PSEUDO_REGISTER + && global_regs[REGNO (dest)]))) + /* Don't substitute into an incremented register. */ + || FIND_REG_INC_NOTE (i3, dest) + || (succ && FIND_REG_INC_NOTE (succ, dest)) +#if 0 + /* Don't combine the end of a libcall into anything. */ + /* ??? This gives worse code, and appears to be unnecessary, since no + pass after flow uses REG_LIBCALL/REG_RETVAL notes. Local-alloc does + use REG_RETVAL notes for noconflict blocks, but other code here + makes sure that those insns don't disappear. */ + || find_reg_note (insn, REG_RETVAL, NULL_RTX) +#endif + /* Make sure that DEST is not used after SUCC but before I3. */ + || (succ && ! all_adjacent + && reg_used_between_p (dest, succ, i3)) + /* Make sure that the value that is to be substituted for the register + does not use any registers whose values alter in between. However, + If the insns are adjacent, a use can't cross a set even though we + think it might (this can happen for a sequence of insns each setting + the same destination; reg_last_set of that register might point to + a NOTE). If INSN has a REG_EQUIV note, the register is always + equivalent to the memory so the substitution is valid even if there + are intervening stores. Also, don't move a volatile asm or + UNSPEC_VOLATILE across any other insns. */ + || (! all_adjacent + && (((GET_CODE (src) != MEM + || ! find_reg_note (insn, REG_EQUIV, src)) + && use_crosses_set_p (src, INSN_CUID (insn))) + || (GET_CODE (src) == ASM_OPERANDS && MEM_VOLATILE_P (src)) + || GET_CODE (src) == UNSPEC_VOLATILE)) + /* If there is a REG_NO_CONFLICT note for DEST in I3 or SUCC, we get + better register allocation by not doing the combine. */ + || find_reg_note (i3, REG_NO_CONFLICT, dest) + || (succ && find_reg_note (succ, REG_NO_CONFLICT, dest)) + /* Don't combine across a CALL_INSN, because that would possibly + change whether the life span of some REGs crosses calls or not, + and it is a pain to update that information. + Exception: if source is a constant, moving it later can't hurt. + Accept that special case, because it helps -fforce-addr a lot. */ + || (INSN_CUID (insn) < last_call_cuid && ! CONSTANT_P (src))) + return 0; + + /* DEST must either be a REG or CC0. */ + if (GET_CODE (dest) == REG) + { + /* If register alignment is being enforced for multi-word items in all + cases except for parameters, it is possible to have a register copy + insn referencing a hard register that is not allowed to contain the + mode being copied and which would not be valid as an operand of most + insns. Eliminate this problem by not combining with such an insn. + + Also, on some machines we don't want to extend the life of a hard + register. + + This is the same test done in can_combine except that we don't test + if SRC is a CALL operation to permit a hard register with + SMALL_REGISTER_CLASSES, and that we have to take all_adjacent + into account. */ + + if (GET_CODE (src) == REG + && ((REGNO (dest) < FIRST_PSEUDO_REGISTER + && ! HARD_REGNO_MODE_OK (REGNO (dest), GET_MODE (dest))) + /* Don't extend the life of a hard register unless it is + user variable (if we have few registers) or it can't + fit into the desired register (meaning something special + is going on). + Also avoid substituting a return register into I3, because + reload can't handle a conflict with constraints of other + inputs. */ + || (REGNO (src) < FIRST_PSEUDO_REGISTER + && (! HARD_REGNO_MODE_OK (REGNO (src), GET_MODE (src)) + || (SMALL_REGISTER_CLASSES + && ((! all_adjacent && ! REG_USERVAR_P (src)) + || (FUNCTION_VALUE_REGNO_P (REGNO (src)) + && ! REG_USERVAR_P (src)))))))) + return 0; + } + else if (GET_CODE (dest) != CC0) + return 0; + + /* Don't substitute for a register intended as a clobberable operand. + Similarly, don't substitute an expression containing a register that + will be clobbered in I3. */ + if (GET_CODE (PATTERN (i3)) == PARALLEL) + for (i = XVECLEN (PATTERN (i3), 0) - 1; i >= 0; i--) + if (GET_CODE (XVECEXP (PATTERN (i3), 0, i)) == CLOBBER + && (reg_overlap_mentioned_p (XEXP (XVECEXP (PATTERN (i3), 0, i), 0), + src) + || rtx_equal_p (XEXP (XVECEXP (PATTERN (i3), 0, i), 0), dest))) + return 0; + + /* If INSN contains anything volatile, or is an `asm' (whether volatile + or not), reject, unless nothing volatile comes between it and I3 */ + + if (GET_CODE (src) == ASM_OPERANDS || volatile_refs_p (src)) + { + /* Make sure succ doesn't contain a volatile reference. */ + if (succ != 0 && volatile_refs_p (PATTERN (succ))) + return 0; + + for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p)) + if (GET_RTX_CLASS (GET_CODE (p)) == 'i' + && p != succ && volatile_refs_p (PATTERN (p))) + return 0; + } + + /* If INSN is an asm, and DEST is a hard register, reject, since it has + to be an explicit register variable, and was chosen for a reason. */ + + if (GET_CODE (src) == ASM_OPERANDS + && GET_CODE (dest) == REG && REGNO (dest) < FIRST_PSEUDO_REGISTER) + return 0; + + /* If there are any volatile insns between INSN and I3, reject, because + they might affect machine state. */ + + for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p)) + if (GET_RTX_CLASS (GET_CODE (p)) == 'i' + && p != succ && volatile_insn_p (PATTERN (p))) + return 0; + + /* If INSN or I2 contains an autoincrement or autodecrement, + make sure that register is not used between there and I3, + and not already used in I3 either. + Also insist that I3 not be a jump; if it were one + and the incremented register were spilled, we would lose. */ + +#ifdef AUTO_INC_DEC + for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) + if (REG_NOTE_KIND (link) == REG_INC + && (GET_CODE (i3) == JUMP_INSN + || reg_used_between_p (XEXP (link, 0), insn, i3) + || reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i3)))) + return 0; +#endif + +#ifdef HAVE_cc0 + /* Don't combine an insn that follows a CC0-setting insn. + An insn that uses CC0 must not be separated from the one that sets it. + We do, however, allow I2 to follow a CC0-setting insn if that insn + is passed as I1; in that case it will be deleted also. + We also allow combining in this case if all the insns are adjacent + because that would leave the two CC0 insns adjacent as well. + It would be more logical to test whether CC0 occurs inside I1 or I2, + but that would be much slower, and this ought to be equivalent. */ + + p = prev_nonnote_insn (insn); + if (p && p != pred && GET_CODE (p) == INSN && sets_cc0_p (PATTERN (p)) + && ! all_adjacent) + return 0; +#endif + + /* If we get here, we have passed all the tests and the combination is + to be allowed. */ + + *pdest = dest; + *psrc = src; + + return 1; +} + +/* Check if PAT is an insn - or a part of it - used to set up an + argument for a function in a hard register. */ + +static int +sets_function_arg_p (pat) + rtx pat; +{ + int i; + rtx inner_dest; + + switch (GET_CODE (pat)) + { + case INSN: + return sets_function_arg_p (PATTERN (pat)); + + case PARALLEL: + for (i = XVECLEN (pat, 0); --i >= 0;) + if (sets_function_arg_p (XVECEXP (pat, 0, i))) + return 1; + + break; + + case SET: + inner_dest = SET_DEST (pat); + while (GET_CODE (inner_dest) == STRICT_LOW_PART + || GET_CODE (inner_dest) == SUBREG + || GET_CODE (inner_dest) == ZERO_EXTRACT) + inner_dest = XEXP (inner_dest, 0); + + return (GET_CODE (inner_dest) == REG + && REGNO (inner_dest) < FIRST_PSEUDO_REGISTER + && FUNCTION_ARG_REGNO_P (REGNO (inner_dest))); + + default: + break; + } + + return 0; +} + +/* LOC is the location within I3 that contains its pattern or the component + of a PARALLEL of the pattern. We validate that it is valid for combining. + + One problem is if I3 modifies its output, as opposed to replacing it + entirely, we can't allow the output to contain I2DEST or I1DEST as doing + so would produce an insn that is not equivalent to the original insns. + + Consider: + + (set (reg:DI 101) (reg:DI 100)) + (set (subreg:SI (reg:DI 101) 0) ) + + This is NOT equivalent to: + + (parallel [(set (subreg:SI (reg:DI 100) 0) ) + (set (reg:DI 101) (reg:DI 100))]) + + Not only does this modify 100 (in which case it might still be valid + if 100 were dead in I2), it sets 101 to the ORIGINAL value of 100. + + We can also run into a problem if I2 sets a register that I1 + uses and I1 gets directly substituted into I3 (not via I2). In that + case, we would be getting the wrong value of I2DEST into I3, so we + must reject the combination. This case occurs when I2 and I1 both + feed into I3, rather than when I1 feeds into I2, which feeds into I3. + If I1_NOT_IN_SRC is non-zero, it means that finding I1 in the source + of a SET must prevent combination from occurring. + + On machines where SMALL_REGISTER_CLASSES is non-zero, we don't combine + if the destination of a SET is a hard register that isn't a user + variable. + + Before doing the above check, we first try to expand a field assignment + into a set of logical operations. + + If PI3_DEST_KILLED is non-zero, it is a pointer to a location in which + we place a register that is both set and used within I3. If more than one + such register is detected, we fail. + + Return 1 if the combination is valid, zero otherwise. */ + +static int +combinable_i3pat (i3, loc, i2dest, i1dest, i1_not_in_src, pi3dest_killed) + rtx i3; + rtx *loc; + rtx i2dest; + rtx i1dest; + int i1_not_in_src; + rtx *pi3dest_killed; +{ + rtx x = *loc; + + if (GET_CODE (x) == SET) + { + rtx set = expand_field_assignment (x); + rtx dest = SET_DEST (set); + rtx src = SET_SRC (set); + rtx inner_dest = dest; + +#if 0 + rtx inner_src = src; +#endif + + SUBST (*loc, set); + + while (GET_CODE (inner_dest) == STRICT_LOW_PART + || GET_CODE (inner_dest) == SUBREG + || GET_CODE (inner_dest) == ZERO_EXTRACT) + inner_dest = XEXP (inner_dest, 0); + + /* We probably don't need this any more now that LIMIT_RELOAD_CLASS + was added. */ +#if 0 + while (GET_CODE (inner_src) == STRICT_LOW_PART + || GET_CODE (inner_src) == SUBREG + || GET_CODE (inner_src) == ZERO_EXTRACT) + inner_src = XEXP (inner_src, 0); + + /* If it is better that two different modes keep two different pseudos, + avoid combining them. This avoids producing the following pattern + on a 386: + (set (subreg:SI (reg/v:QI 21) 0) + (lshiftrt:SI (reg/v:SI 20) + (const_int 24))) + If that were made, reload could not handle the pair of + reg 20/21, since it would try to get any GENERAL_REGS + but some of them don't handle QImode. */ + + if (rtx_equal_p (inner_src, i2dest) + && GET_CODE (inner_dest) == REG + && ! MODES_TIEABLE_P (GET_MODE (i2dest), GET_MODE (inner_dest))) + return 0; +#endif + + /* Check for the case where I3 modifies its output, as + discussed above. */ + if ((inner_dest != dest + && (reg_overlap_mentioned_p (i2dest, inner_dest) + || (i1dest && reg_overlap_mentioned_p (i1dest, inner_dest)))) + + /* This is the same test done in can_combine_p except that we + allow a hard register with SMALL_REGISTER_CLASSES if SRC is a + CALL operation. Moreover, we can't test all_adjacent; we don't + have to, since this instruction will stay in place, thus we are + not considering increasing the lifetime of INNER_DEST. + + Also, if this insn sets a function argument, combining it with + something that might need a spill could clobber a previous + function argument; the all_adjacent test in can_combine_p also + checks this; here, we do a more specific test for this case. */ + + || (GET_CODE (inner_dest) == REG + && REGNO (inner_dest) < FIRST_PSEUDO_REGISTER + && (! HARD_REGNO_MODE_OK (REGNO (inner_dest), + GET_MODE (inner_dest)) + || (SMALL_REGISTER_CLASSES && GET_CODE (src) != CALL + && ! REG_USERVAR_P (inner_dest) + && (FUNCTION_VALUE_REGNO_P (REGNO (inner_dest)) + || (FUNCTION_ARG_REGNO_P (REGNO (inner_dest)) + && i3 != 0 + && sets_function_arg_p (prev_nonnote_insn (i3))))))) + || (i1_not_in_src && reg_overlap_mentioned_p (i1dest, src))) + return 0; + + /* If DEST is used in I3, it is being killed in this insn, + so record that for later. + Never add REG_DEAD notes for the FRAME_POINTER_REGNUM or the + STACK_POINTER_REGNUM, since these are always considered to be + live. Similarly for ARG_POINTER_REGNUM if it is fixed. */ + if (pi3dest_killed && GET_CODE (dest) == REG + && reg_referenced_p (dest, PATTERN (i3)) + && REGNO (dest) != FRAME_POINTER_REGNUM +#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM + && REGNO (dest) != HARD_FRAME_POINTER_REGNUM +#endif +#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM + && (REGNO (dest) != ARG_POINTER_REGNUM + || ! fixed_regs [REGNO (dest)]) +#endif + && REGNO (dest) != STACK_POINTER_REGNUM) + { + if (*pi3dest_killed) + return 0; + + *pi3dest_killed = dest; + } + } + + else if (GET_CODE (x) == PARALLEL) + { + int i; + + for (i = 0; i < XVECLEN (x, 0); i++) + if (! combinable_i3pat (i3, &XVECEXP (x, 0, i), i2dest, i1dest, + i1_not_in_src, pi3dest_killed)) + return 0; + } + + return 1; +} + +/* Try to combine the insns I1 and I2 into I3. + Here I1 and I2 appear earlier than I3. + I1 can be zero; then we combine just I2 into I3. + + It we are combining three insns and the resulting insn is not recognized, + try splitting it into two insns. If that happens, I2 and I3 are retained + and I1 is pseudo-deleted by turning it into a NOTE. Otherwise, I1 and I2 + are pseudo-deleted. + + Return 0 if the combination does not work. Then nothing is changed. + If we did the combination, return the insn at which combine should + resume scanning. */ + +static rtx +try_combine (i3, i2, i1) + register rtx i3, i2, i1; +{ + /* New patterns for I3 and I3, respectively. */ + rtx newpat, newi2pat = 0; + /* Indicates need to preserve SET in I1 or I2 in I3 if it is not dead. */ + int added_sets_1, added_sets_2; + /* Total number of SETs to put into I3. */ + int total_sets; + /* Nonzero is I2's body now appears in I3. */ + int i2_is_used; + /* INSN_CODEs for new I3, new I2, and user of condition code. */ + int insn_code_number, i2_code_number, other_code_number; + /* Contains I3 if the destination of I3 is used in its source, which means + that the old life of I3 is being killed. If that usage is placed into + I2 and not in I3, a REG_DEAD note must be made. */ + rtx i3dest_killed = 0; + /* SET_DEST and SET_SRC of I2 and I1. */ + rtx i2dest, i2src, i1dest = 0, i1src = 0; + /* PATTERN (I2), or a copy of it in certain cases. */ + rtx i2pat; + /* Indicates if I2DEST or I1DEST is in I2SRC or I1_SRC. */ + int i2dest_in_i2src = 0, i1dest_in_i1src = 0, i2dest_in_i1src = 0; + int i1_feeds_i3 = 0; + /* Notes that must be added to REG_NOTES in I3 and I2. */ + rtx new_i3_notes, new_i2_notes; + /* Notes that we substituted I3 into I2 instead of the normal case. */ + int i3_subst_into_i2 = 0; + /* Notes that I1, I2 or I3 is a MULT operation. */ + int have_mult = 0; + + int maxreg; + rtx temp; + register rtx link; + int i; + + /* If any of I1, I2, and I3 isn't really an insn, we can't do anything. + This can occur when flow deletes an insn that it has merged into an + auto-increment address. We also can't do anything if I3 has a + REG_LIBCALL note since we don't want to disrupt the contiguity of a + libcall. */ + + if (GET_RTX_CLASS (GET_CODE (i3)) != 'i' + || GET_RTX_CLASS (GET_CODE (i2)) != 'i' + || (i1 && GET_RTX_CLASS (GET_CODE (i1)) != 'i') +#if 0 + /* ??? This gives worse code, and appears to be unnecessary, since no + pass after flow uses REG_LIBCALL/REG_RETVAL notes. */ + || find_reg_note (i3, REG_LIBCALL, NULL_RTX) +#endif +) + return 0; + + combine_attempts++; + + undobuf.undos = undobuf.previous_undos = 0; + undobuf.other_insn = 0; + + /* Save the current high-water-mark so we can free storage if we didn't + accept this combination. */ + undobuf.storage = (char *) oballoc (0); + + /* Reset the hard register usage information. */ + CLEAR_HARD_REG_SET (newpat_used_regs); + + /* If I1 and I2 both feed I3, they can be in any order. To simplify the + code below, set I1 to be the earlier of the two insns. */ + if (i1 && INSN_CUID (i1) > INSN_CUID (i2)) + temp = i1, i1 = i2, i2 = temp; + + added_links_insn = 0; + + /* First check for one important special-case that the code below will + not handle. Namely, the case where I1 is zero, I2 has multiple sets, + and I3 is a SET whose SET_SRC is a SET_DEST in I2. In that case, + we may be able to replace that destination with the destination of I3. + This occurs in the common code where we compute both a quotient and + remainder into a structure, in which case we want to do the computation + directly into the structure to avoid register-register copies. + + We make very conservative checks below and only try to handle the + most common cases of this. For example, we only handle the case + where I2 and I3 are adjacent to avoid making difficult register + usage tests. */ + + if (i1 == 0 && GET_CODE (i3) == INSN && GET_CODE (PATTERN (i3)) == SET + && GET_CODE (SET_SRC (PATTERN (i3))) == REG + && REGNO (SET_SRC (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER + && (! SMALL_REGISTER_CLASSES + || (GET_CODE (SET_DEST (PATTERN (i3))) != REG + || REGNO (SET_DEST (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER + || REG_USERVAR_P (SET_DEST (PATTERN (i3))))) + && find_reg_note (i3, REG_DEAD, SET_SRC (PATTERN (i3))) + && GET_CODE (PATTERN (i2)) == PARALLEL + && ! side_effects_p (SET_DEST (PATTERN (i3))) + /* If the dest of I3 is a ZERO_EXTRACT or STRICT_LOW_PART, the code + below would need to check what is inside (and reg_overlap_mentioned_p + doesn't support those codes anyway). Don't allow those destinations; + the resulting insn isn't likely to be recognized anyway. */ + && GET_CODE (SET_DEST (PATTERN (i3))) != ZERO_EXTRACT + && GET_CODE (SET_DEST (PATTERN (i3))) != STRICT_LOW_PART + && ! reg_overlap_mentioned_p (SET_SRC (PATTERN (i3)), + SET_DEST (PATTERN (i3))) + && next_real_insn (i2) == i3) + { + rtx p2 = PATTERN (i2); + + /* Make sure that the destination of I3, + which we are going to substitute into one output of I2, + is not used within another output of I2. We must avoid making this: + (parallel [(set (mem (reg 69)) ...) + (set (reg 69) ...)]) + which is not well-defined as to order of actions. + (Besides, reload can't handle output reloads for this.) + + The problem can also happen if the dest of I3 is a memory ref, + if another dest in I2 is an indirect memory ref. */ + for (i = 0; i < XVECLEN (p2, 0); i++) + if ((GET_CODE (XVECEXP (p2, 0, i)) == SET + || GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER) + && reg_overlap_mentioned_p (SET_DEST (PATTERN (i3)), + SET_DEST (XVECEXP (p2, 0, i)))) + break; + + if (i == XVECLEN (p2, 0)) + for (i = 0; i < XVECLEN (p2, 0); i++) + if (SET_DEST (XVECEXP (p2, 0, i)) == SET_SRC (PATTERN (i3))) + { + combine_merges++; + + subst_insn = i3; + subst_low_cuid = INSN_CUID (i2); + + added_sets_2 = added_sets_1 = 0; + i2dest = SET_SRC (PATTERN (i3)); + + /* Replace the dest in I2 with our dest and make the resulting + insn the new pattern for I3. Then skip to where we + validate the pattern. Everything was set up above. */ + SUBST (SET_DEST (XVECEXP (p2, 0, i)), + SET_DEST (PATTERN (i3))); + + newpat = p2; + i3_subst_into_i2 = 1; + goto validate_replacement; + } + } + +#ifndef HAVE_cc0 + /* If we have no I1 and I2 looks like: + (parallel [(set (reg:CC X) (compare:CC OP (const_int 0))) + (set Y OP)]) + make up a dummy I1 that is + (set Y OP) + and change I2 to be + (set (reg:CC X) (compare:CC Y (const_int 0))) + + (We can ignore any trailing CLOBBERs.) + + This undoes a previous combination and allows us to match a branch-and- + decrement insn. */ + + if (i1 == 0 && GET_CODE (PATTERN (i2)) == PARALLEL + && XVECLEN (PATTERN (i2), 0) >= 2 + && GET_CODE (XVECEXP (PATTERN (i2), 0, 0)) == SET + && (GET_MODE_CLASS (GET_MODE (SET_DEST (XVECEXP (PATTERN (i2), 0, 0)))) + == MODE_CC) + && GET_CODE (SET_SRC (XVECEXP (PATTERN (i2), 0, 0))) == COMPARE + && XEXP (SET_SRC (XVECEXP (PATTERN (i2), 0, 0)), 1) == const0_rtx + && GET_CODE (XVECEXP (PATTERN (i2), 0, 1)) == SET + && GET_CODE (SET_DEST (XVECEXP (PATTERN (i2), 0, 1))) == REG + && rtx_equal_p (XEXP (SET_SRC (XVECEXP (PATTERN (i2), 0, 0)), 0), + SET_SRC (XVECEXP (PATTERN (i2), 0, 1)))) + { + for (i = XVECLEN (PATTERN (i2), 0) - 1; i >= 2; i--) + if (GET_CODE (XVECEXP (PATTERN (i2), 0, i)) != CLOBBER) + break; + + if (i == 1) + { + /* We make I1 with the same INSN_UID as I2. This gives it + the same INSN_CUID for value tracking. Our fake I1 will + never appear in the insn stream so giving it the same INSN_UID + as I2 will not cause a problem. */ + + subst_prev_insn = i1 + = gen_rtx_INSN (VOIDmode, INSN_UID (i2), NULL_RTX, i2, + XVECEXP (PATTERN (i2), 0, 1), -1, NULL_RTX, + NULL_RTX); + + SUBST (PATTERN (i2), XVECEXP (PATTERN (i2), 0, 0)); + SUBST (XEXP (SET_SRC (PATTERN (i2)), 0), + SET_DEST (PATTERN (i1))); + } + } +#endif + + /* Verify that I2 and I1 are valid for combining. */ + if (! can_combine_p (i2, i3, i1, NULL_RTX, &i2dest, &i2src) + || (i1 && ! can_combine_p (i1, i3, NULL_RTX, i2, &i1dest, &i1src))) + { + undo_all (); + return 0; + } + + /* Record whether I2DEST is used in I2SRC and similarly for the other + cases. Knowing this will help in register status updating below. */ + i2dest_in_i2src = reg_overlap_mentioned_p (i2dest, i2src); + i1dest_in_i1src = i1 && reg_overlap_mentioned_p (i1dest, i1src); + i2dest_in_i1src = i1 && reg_overlap_mentioned_p (i2dest, i1src); + + /* See if I1 directly feeds into I3. It does if I1DEST is not used + in I2SRC. */ + i1_feeds_i3 = i1 && ! reg_overlap_mentioned_p (i1dest, i2src); + + /* Ensure that I3's pattern can be the destination of combines. */ + if (! combinable_i3pat (i3, &PATTERN (i3), i2dest, i1dest, + i1 && i2dest_in_i1src && i1_feeds_i3, + &i3dest_killed)) + { + undo_all (); + return 0; + } + + /* See if any of the insns is a MULT operation. Unless one is, we will + reject a combination that is, since it must be slower. Be conservative + here. */ + if (GET_CODE (i2src) == MULT + || (i1 != 0 && GET_CODE (i1src) == MULT) + || (GET_CODE (PATTERN (i3)) == SET + && GET_CODE (SET_SRC (PATTERN (i3))) == MULT)) + have_mult = 1; + + /* If I3 has an inc, then give up if I1 or I2 uses the reg that is inc'd. + We used to do this EXCEPT in one case: I3 has a post-inc in an + output operand. However, that exception can give rise to insns like + mov r3,(r3)+ + which is a famous insn on the PDP-11 where the value of r3 used as the + source was model-dependent. Avoid this sort of thing. */ + +#if 0 + if (!(GET_CODE (PATTERN (i3)) == SET + && GET_CODE (SET_SRC (PATTERN (i3))) == REG + && GET_CODE (SET_DEST (PATTERN (i3))) == MEM + && (GET_CODE (XEXP (SET_DEST (PATTERN (i3)), 0)) == POST_INC + || GET_CODE (XEXP (SET_DEST (PATTERN (i3)), 0)) == POST_DEC))) + /* It's not the exception. */ +#endif +#ifdef AUTO_INC_DEC + for (link = REG_NOTES (i3); link; link = XEXP (link, 1)) + if (REG_NOTE_KIND (link) == REG_INC + && (reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i2)) + || (i1 != 0 + && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i1))))) + { + undo_all (); + return 0; + } +#endif + + /* See if the SETs in I1 or I2 need to be kept around in the merged + instruction: whenever the value set there is still needed past I3. + For the SETs in I2, this is easy: we see if I2DEST dies or is set in I3. + + For the SET in I1, we have two cases: If I1 and I2 independently + feed into I3, the set in I1 needs to be kept around if I1DEST dies + or is set in I3. Otherwise (if I1 feeds I2 which feeds I3), the set + in I1 needs to be kept around unless I1DEST dies or is set in either + I2 or I3. We can distinguish these cases by seeing if I2SRC mentions + I1DEST. If so, we know I1 feeds into I2. */ + + added_sets_2 = ! dead_or_set_p (i3, i2dest); + + added_sets_1 + = i1 && ! (i1_feeds_i3 ? dead_or_set_p (i3, i1dest) + : (dead_or_set_p (i3, i1dest) || dead_or_set_p (i2, i1dest))); + + /* If the set in I2 needs to be kept around, we must make a copy of + PATTERN (I2), so that when we substitute I1SRC for I1DEST in + PATTERN (I2), we are only substituting for the original I1DEST, not into + an already-substituted copy. This also prevents making self-referential + rtx. If I2 is a PARALLEL, we just need the piece that assigns I2SRC to + I2DEST. */ + + i2pat = (GET_CODE (PATTERN (i2)) == PARALLEL + ? gen_rtx_SET (VOIDmode, i2dest, i2src) + : PATTERN (i2)); + + if (added_sets_2) + i2pat = copy_rtx (i2pat); + + combine_merges++; + + /* Substitute in the latest insn for the regs set by the earlier ones. */ + + maxreg = max_reg_num (); + + subst_insn = i3; + + /* CYGNUS LOCAL -- meissner/branch prediction */ + /* Convert EXPECT expressions into canonical form */ +#if defined(HAVE_expectsi3) && !defined(HAVE_cc0) + if (current_function_uses_expect) + { + rtx set2, set3, expect, expreg, expint, compare, test; + /* Convert: + (set (register) + (compare (expect (register) (const_int) + (const_int)))) + (set (pc) + (if_then_else ( (register) (const_int 0)) + (label_ref ...) + (pc))) + into: + (set (register) (compare (register) (const_int)))) + (set (pc) + (if_then_else ( (expect (register) (const_int)) + (const_int 0)) + (const_int)) + (label_ref ...) + (pc))) */ + if (i2 && i3 + && (set2 = single_set (i2)) != NULL_RTX + && GET_CODE (SET_DEST (set2)) == REG + && GET_CODE ((compare = SET_SRC (set2))) == COMPARE + && GET_CODE ((expect = XEXP (compare, 0))) == EXPECT + && GET_CODE ((expint = XEXP (compare, 1))) == CONST_INT + && GET_CODE (i3) == JUMP_INSN + && (set3 = single_set (i3)) != NULL_RTX + && SET_DEST (set3) == pc_rtx + && GET_CODE (SET_SRC (set3)) == IF_THEN_ELSE + && GET_RTX_CLASS (GET_CODE ((test = XEXP (SET_SRC (set3), 0)))) == '<' + && rtx_equal_p (SET_DEST (set2), + (expreg = XEXP (XEXP (SET_SRC (set3), 0), 0)))) + { + HOST_WIDE_INT cmp_value = INTVAL (XEXP (expect, 1)); + HOST_WIDE_INT exp_value = INTVAL (expint); + unsigned HOST_WIDE_INT ucmp_value = cmp_value; + unsigned HOST_WIDE_INT uexp_value = exp_value; + HOST_WIDE_INT value; + + if (cmp_value == exp_value) + value = 0; + + else + switch (GET_CODE (test)) + { + default: + abort (); + + case EQ: + case NE: + case LT: + case LE: + case GT: + case GE: + value = (cmp_value > exp_value) ? -1 : 1; + break; + + case LTU: + case LEU: + case GTU: + case GEU: + value = (ucmp_value > uexp_value) ? -1 : 1; + break; + } + + newi2pat = gen_rtx (SET, VOIDmode, + SET_DEST (set2), + gen_rtx (COMPARE, GET_MODE (SET_SRC (set2)), + XEXP (expect, 0), expint)); + + newpat + = gen_rtx (SET, VOIDmode, + pc_rtx, + gen_rtx (IF_THEN_ELSE, VOIDmode, + gen_rtx (GET_CODE (test), + GET_MODE (test), + gen_rtx (EXPECT, + GET_MODE (SET_DEST (set2)), + SET_DEST (set2), + GEN_INT (value)), + const0_rtx), + XEXP (SET_SRC (set3), 1), + XEXP (SET_SRC (set3), 2))); + + i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes); + insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes); + + if (i2_code_number >= 0 && insn_code_number >= 0) + { + PATTERN (i2) = newi2pat; + PATTERN (i3) = newpat; + INSN_CODE (i2) = i2_code_number; + INSN_CODE (i3) = insn_code_number; + return i2; + } + else + { + newi2pat = newpat = NULL_RTX; + i2_code_number = insn_code_number = -1; + } + } + } +#endif + /* END CYGNUS LOCAL -- meissner/branch prediction */ + + /* It is possible that the source of I2 or I1 may be performing an + unneeded operation, such as a ZERO_EXTEND of something that is known + to have the high part zero. Handle that case by letting subst look at + the innermost one of them. + + Another way to do this would be to have a function that tries to + simplify a single insn instead of merging two or more insns. We don't + do this because of the potential of infinite loops and because + of the potential extra memory required. However, doing it the way + we are is a bit of a kludge and doesn't catch all cases. + + But only do this if -fexpensive-optimizations since it slows things down + and doesn't usually win. */ + + if (flag_expensive_optimizations) + { + /* Pass pc_rtx so no substitutions are done, just simplifications. + The cases that we are interested in here do not involve the few + cases were is_replaced is checked. */ + if (i1) + { + subst_low_cuid = INSN_CUID (i1); + i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0); + } + else + { + subst_low_cuid = INSN_CUID (i2); + i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0); + } + + undobuf.previous_undos = undobuf.undos; + } + +#ifndef HAVE_cc0 + /* Many machines that don't use CC0 have insns that can both perform an + arithmetic operation and set the condition code. These operations will + be represented as a PARALLEL with the first element of the vector + being a COMPARE of an arithmetic operation with the constant zero. + The second element of the vector will set some pseudo to the result + of the same arithmetic operation. If we simplify the COMPARE, we won't + match such a pattern and so will generate an extra insn. Here we test + for this case, where both the comparison and the operation result are + needed, and make the PARALLEL by just replacing I2DEST in I3SRC with + I2SRC. Later we will make the PARALLEL that contains I2. */ + + if (i1 == 0 && added_sets_2 && GET_CODE (PATTERN (i3)) == SET + && GET_CODE (SET_SRC (PATTERN (i3))) == COMPARE + && XEXP (SET_SRC (PATTERN (i3)), 1) == const0_rtx + && rtx_equal_p (XEXP (SET_SRC (PATTERN (i3)), 0), i2dest)) + { +#ifdef EXTRA_CC_MODES + rtx *cc_use; + enum machine_mode compare_mode; +#endif + + newpat = PATTERN (i3); + SUBST (XEXP (SET_SRC (newpat), 0), i2src); + + i2_is_used = 1; + +#ifdef EXTRA_CC_MODES + /* See if a COMPARE with the operand we substituted in should be done + with the mode that is currently being used. If not, do the same + processing we do in `subst' for a SET; namely, if the destination + is used only once, try to replace it with a register of the proper + mode and also replace the COMPARE. */ + if (undobuf.other_insn == 0 + && (cc_use = find_single_use (SET_DEST (newpat), i3, + &undobuf.other_insn)) + && ((compare_mode = SELECT_CC_MODE (GET_CODE (*cc_use), + i2src, const0_rtx)) + != GET_MODE (SET_DEST (newpat)))) + { + int regno = REGNO (SET_DEST (newpat)); + rtx new_dest = gen_rtx_REG (compare_mode, regno); + + if (regno < FIRST_PSEUDO_REGISTER + || (REG_N_SETS (regno) == 1 && ! added_sets_2 + && ! REG_USERVAR_P (SET_DEST (newpat)))) + { + if (regno >= FIRST_PSEUDO_REGISTER) + SUBST (regno_reg_rtx[regno], new_dest); + + SUBST (SET_DEST (newpat), new_dest); + SUBST (XEXP (*cc_use, 0), new_dest); + SUBST (SET_SRC (newpat), + gen_rtx_combine (COMPARE, compare_mode, + i2src, const0_rtx)); + } + else + undobuf.other_insn = 0; + } +#endif + } + else +#endif + { + n_occurrences = 0; /* `subst' counts here */ + + /* If I1 feeds into I2 (not into I3) and I1DEST is in I1SRC, we + need to make a unique copy of I2SRC each time we substitute it + to avoid self-referential rtl. */ + + subst_low_cuid = INSN_CUID (i2); + newpat = subst (PATTERN (i3), i2dest, i2src, 0, + ! i1_feeds_i3 && i1dest_in_i1src); + undobuf.previous_undos = undobuf.undos; + + /* Record whether i2's body now appears within i3's body. */ + i2_is_used = n_occurrences; + } + + /* If we already got a failure, don't try to do more. Otherwise, + try to substitute in I1 if we have it. */ + + if (i1 && GET_CODE (newpat) != CLOBBER) + { + /* Before we can do this substitution, we must redo the test done + above (see detailed comments there) that ensures that I1DEST + isn't mentioned in any SETs in NEWPAT that are field assignments. */ + + if (! combinable_i3pat (NULL_RTX, &newpat, i1dest, NULL_RTX, + 0, NULL_PTR)) + { + undo_all (); + return 0; + } + + n_occurrences = 0; + subst_low_cuid = INSN_CUID (i1); + newpat = subst (newpat, i1dest, i1src, 0, 0); + undobuf.previous_undos = undobuf.undos; + } + + /* Fail if an autoincrement side-effect has been duplicated. Be careful + to count all the ways that I2SRC and I1SRC can be used. */ + if ((FIND_REG_INC_NOTE (i2, NULL_RTX) != 0 + && i2_is_used + added_sets_2 > 1) + || (i1 != 0 && FIND_REG_INC_NOTE (i1, NULL_RTX) != 0 + && (n_occurrences + added_sets_1 + (added_sets_2 && ! i1_feeds_i3) + > 1)) + /* Fail if we tried to make a new register (we used to abort, but there's + really no reason to). */ + || max_reg_num () != maxreg + /* Fail if we couldn't do something and have a CLOBBER. */ + || GET_CODE (newpat) == CLOBBER + /* Fail if this new pattern is a MULT and we didn't have one before + at the outer level. */ + || (GET_CODE (newpat) == SET && GET_CODE (SET_SRC (newpat)) == MULT + && ! have_mult)) + { + undo_all (); + return 0; + } + + /* If the actions of the earlier insns must be kept + in addition to substituting them into the latest one, + we must make a new PARALLEL for the latest insn + to hold additional the SETs. */ + + if (added_sets_1 || added_sets_2) + { + combine_extras++; + + if (GET_CODE (newpat) == PARALLEL) + { + rtvec old = XVEC (newpat, 0); + total_sets = XVECLEN (newpat, 0) + added_sets_1 + added_sets_2; + newpat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_sets)); + bcopy ((char *) &old->elem[0], (char *) XVEC (newpat, 0)->elem, + sizeof (old->elem[0]) * old->num_elem); + } + else + { + rtx old = newpat; + total_sets = 1 + added_sets_1 + added_sets_2; + newpat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_sets)); + XVECEXP (newpat, 0, 0) = old; + } + + if (added_sets_1) + XVECEXP (newpat, 0, --total_sets) + = (GET_CODE (PATTERN (i1)) == PARALLEL + ? gen_rtx_SET (VOIDmode, i1dest, i1src) : PATTERN (i1)); + + if (added_sets_2) + { + /* If there is no I1, use I2's body as is. We used to also not do + the subst call below if I2 was substituted into I3, + but that could lose a simplification. */ + if (i1 == 0) + XVECEXP (newpat, 0, --total_sets) = i2pat; + else + /* See comment where i2pat is assigned. */ + XVECEXP (newpat, 0, --total_sets) + = subst (i2pat, i1dest, i1src, 0, 0); + } + } + + /* We come here when we are replacing a destination in I2 with the + destination of I3. */ + validate_replacement: + + /* Note which hard regs this insn has as inputs. */ + mark_used_regs_combine (newpat); + + /* Is the result of combination a valid instruction? */ + insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes); + + /* If the result isn't valid, see if it is a PARALLEL of two SETs where + the second SET's destination is a register that is unused. In that case, + we just need the first SET. This can occur when simplifying a divmod + insn. We *must* test for this case here because the code below that + splits two independent SETs doesn't handle this case correctly when it + updates the register status. Also check the case where the first + SET's destination is unused. That would not cause incorrect code, but + does cause an unneeded insn to remain. */ + + if (insn_code_number < 0 && GET_CODE (newpat) == PARALLEL + && XVECLEN (newpat, 0) == 2 + && GET_CODE (XVECEXP (newpat, 0, 0)) == SET + && GET_CODE (XVECEXP (newpat, 0, 1)) == SET + && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == REG + && find_reg_note (i3, REG_UNUSED, SET_DEST (XVECEXP (newpat, 0, 1))) + && ! side_effects_p (SET_SRC (XVECEXP (newpat, 0, 1))) + && asm_noperands (newpat) < 0) + { + newpat = XVECEXP (newpat, 0, 0); + insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes); + } + + else if (insn_code_number < 0 && GET_CODE (newpat) == PARALLEL + && XVECLEN (newpat, 0) == 2 + && GET_CODE (XVECEXP (newpat, 0, 0)) == SET + && GET_CODE (XVECEXP (newpat, 0, 1)) == SET + && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) == REG + && find_reg_note (i3, REG_UNUSED, SET_DEST (XVECEXP (newpat, 0, 0))) + && ! side_effects_p (SET_SRC (XVECEXP (newpat, 0, 0))) + && asm_noperands (newpat) < 0) + { + newpat = XVECEXP (newpat, 0, 1); + insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes); + } + + /* If we were combining three insns and the result is a simple SET + with no ASM_OPERANDS that wasn't recognized, try to split it into two + insns. There are two ways to do this. It can be split using a + machine-specific method (like when you have an addition of a large + constant) or by combine in the function find_split_point. */ + + if (i1 && insn_code_number < 0 && GET_CODE (newpat) == SET + && asm_noperands (newpat) < 0) + { + rtx m_split, *split; + rtx ni2dest = i2dest; + + /* See if the MD file can split NEWPAT. If it can't, see if letting it + use I2DEST as a scratch register will help. In the latter case, + convert I2DEST to the mode of the source of NEWPAT if we can. */ + + m_split = split_insns (newpat, i3); + + /* We can only use I2DEST as a scratch reg if it doesn't overlap any + inputs of NEWPAT. */ + + /* ??? If I2DEST is not safe, and I1DEST exists, then it would be + possible to try that as a scratch reg. This would require adding + more code to make it work though. */ + + if (m_split == 0 && ! reg_overlap_mentioned_p (ni2dest, newpat)) + { + /* If I2DEST is a hard register or the only use of a pseudo, + we can change its mode. */ + if (GET_MODE (SET_DEST (newpat)) != GET_MODE (i2dest) + && GET_MODE (SET_DEST (newpat)) != VOIDmode + && GET_CODE (i2dest) == REG + && (REGNO (i2dest) < FIRST_PSEUDO_REGISTER + || (REG_N_SETS (REGNO (i2dest)) == 1 && ! added_sets_2 + && ! REG_USERVAR_P (i2dest)))) + ni2dest = gen_rtx_REG (GET_MODE (SET_DEST (newpat)), + REGNO (i2dest)); + + m_split = split_insns + (gen_rtx_PARALLEL (VOIDmode, + gen_rtvec (2, newpat, + gen_rtx_CLOBBER (VOIDmode, + ni2dest))), + i3); + } + + if (m_split && GET_CODE (m_split) == SEQUENCE + && XVECLEN (m_split, 0) == 2 + && (next_real_insn (i2) == i3 + || ! use_crosses_set_p (PATTERN (XVECEXP (m_split, 0, 0)), + INSN_CUID (i2)))) + { + rtx i2set, i3set; + rtx newi3pat = PATTERN (XVECEXP (m_split, 0, 1)); + newi2pat = PATTERN (XVECEXP (m_split, 0, 0)); + + i3set = single_set (XVECEXP (m_split, 0, 1)); + i2set = single_set (XVECEXP (m_split, 0, 0)); + + /* In case we changed the mode of I2DEST, replace it in the + pseudo-register table here. We can't do it above in case this + code doesn't get executed and we do a split the other way. */ + + if (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER) + SUBST (regno_reg_rtx[REGNO (i2dest)], ni2dest); + + i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes); + + /* If I2 or I3 has multiple SETs, we won't know how to track + register status, so don't use these insns. If I2's destination + is used between I2 and I3, we also can't use these insns. */ + + if (i2_code_number >= 0 && i2set && i3set + && (next_real_insn (i2) == i3 + || ! reg_used_between_p (SET_DEST (i2set), i2, i3))) + insn_code_number = recog_for_combine (&newi3pat, i3, + &new_i3_notes); + if (insn_code_number >= 0) + newpat = newi3pat; + + /* It is possible that both insns now set the destination of I3. + If so, we must show an extra use of it. */ + + if (insn_code_number >= 0) + { + rtx new_i3_dest = SET_DEST (i3set); + rtx new_i2_dest = SET_DEST (i2set); + + while (GET_CODE (new_i3_dest) == ZERO_EXTRACT + || GET_CODE (new_i3_dest) == STRICT_LOW_PART + || GET_CODE (new_i3_dest) == SUBREG) + new_i3_dest = XEXP (new_i3_dest, 0); + + while (GET_CODE (new_i2_dest) == ZERO_EXTRACT + || GET_CODE (new_i2_dest) == STRICT_LOW_PART + || GET_CODE (new_i2_dest) == SUBREG) + new_i2_dest = XEXP (new_i2_dest, 0); + + if (GET_CODE (new_i3_dest) == REG + && GET_CODE (new_i2_dest) == REG + && REGNO (new_i3_dest) == REGNO (new_i2_dest)) + REG_N_SETS (REGNO (new_i2_dest))++; + } + } + + /* If we can split it and use I2DEST, go ahead and see if that + helps things be recognized. Verify that none of the registers + are set between I2 and I3. */ + if (insn_code_number < 0 && (split = find_split_point (&newpat, i3)) != 0 +#ifdef HAVE_cc0 + && GET_CODE (i2dest) == REG +#endif + /* We need I2DEST in the proper mode. If it is a hard register + or the only use of a pseudo, we can change its mode. */ + && (GET_MODE (*split) == GET_MODE (i2dest) + || GET_MODE (*split) == VOIDmode + || REGNO (i2dest) < FIRST_PSEUDO_REGISTER + || (REG_N_SETS (REGNO (i2dest)) == 1 && ! added_sets_2 + && ! REG_USERVAR_P (i2dest))) + && (next_real_insn (i2) == i3 + || ! use_crosses_set_p (*split, INSN_CUID (i2))) + /* We can't overwrite I2DEST if its value is still used by + NEWPAT. */ + && ! reg_referenced_p (i2dest, newpat)) + { + rtx newdest = i2dest; + enum rtx_code split_code = GET_CODE (*split); + enum machine_mode split_mode = GET_MODE (*split); + + /* Get NEWDEST as a register in the proper mode. We have already + validated that we can do this. */ + if (GET_MODE (i2dest) != split_mode && split_mode != VOIDmode) + { + newdest = gen_rtx_REG (split_mode, REGNO (i2dest)); + + if (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER) + SUBST (regno_reg_rtx[REGNO (i2dest)], newdest); + } + + /* If *SPLIT is a (mult FOO (const_int pow2)), convert it to + an ASHIFT. This can occur if it was inside a PLUS and hence + appeared to be a memory address. This is a kludge. */ + if (split_code == MULT + && GET_CODE (XEXP (*split, 1)) == CONST_INT + && (i = exact_log2 (INTVAL (XEXP (*split, 1)))) >= 0) + { + SUBST (*split, gen_rtx_combine (ASHIFT, split_mode, + XEXP (*split, 0), GEN_INT (i))); + /* Update split_code because we may not have a multiply + anymore. */ + split_code = GET_CODE (*split); + } + +#ifdef INSN_SCHEDULING + /* If *SPLIT is a paradoxical SUBREG, when we split it, it should + be written as a ZERO_EXTEND. */ + if (split_code == SUBREG && GET_CODE (SUBREG_REG (*split)) == MEM) + SUBST (*split, gen_rtx_combine (ZERO_EXTEND, split_mode, + XEXP (*split, 0))); +#endif + + newi2pat = gen_rtx_combine (SET, VOIDmode, newdest, *split); + SUBST (*split, newdest); + i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes); + + /* If the split point was a MULT and we didn't have one before, + don't use one now. */ + if (i2_code_number >= 0 && ! (split_code == MULT && ! have_mult)) + insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes); + } + } + + /* Check for a case where we loaded from memory in a narrow mode and + then sign extended it, but we need both registers. In that case, + we have a PARALLEL with both loads from the same memory location. + We can split this into a load from memory followed by a register-register + copy. This saves at least one insn, more if register allocation can + eliminate the copy. + + We cannot do this if the destination of the second assignment is + a register that we have already assumed is zero-extended. Similarly + for a SUBREG of such a register. */ + + else if (i1 && insn_code_number < 0 && asm_noperands (newpat) < 0 + && GET_CODE (newpat) == PARALLEL + && XVECLEN (newpat, 0) == 2 + && GET_CODE (XVECEXP (newpat, 0, 0)) == SET + && GET_CODE (SET_SRC (XVECEXP (newpat, 0, 0))) == SIGN_EXTEND + && GET_CODE (XVECEXP (newpat, 0, 1)) == SET + && rtx_equal_p (SET_SRC (XVECEXP (newpat, 0, 1)), + XEXP (SET_SRC (XVECEXP (newpat, 0, 0)), 0)) + && ! use_crosses_set_p (SET_SRC (XVECEXP (newpat, 0, 1)), + INSN_CUID (i2)) + && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != ZERO_EXTRACT + && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != STRICT_LOW_PART + && ! (temp = SET_DEST (XVECEXP (newpat, 0, 1)), + (GET_CODE (temp) == REG + && reg_nonzero_bits[REGNO (temp)] != 0 + && GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD + && GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT + && (reg_nonzero_bits[REGNO (temp)] + != GET_MODE_MASK (word_mode)))) + && ! (GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == SUBREG + && (temp = SUBREG_REG (SET_DEST (XVECEXP (newpat, 0, 1))), + (GET_CODE (temp) == REG + && reg_nonzero_bits[REGNO (temp)] != 0 + && GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD + && GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT + && (reg_nonzero_bits[REGNO (temp)] + != GET_MODE_MASK (word_mode))))) + && ! reg_overlap_mentioned_p (SET_DEST (XVECEXP (newpat, 0, 1)), + SET_SRC (XVECEXP (newpat, 0, 1))) + && ! find_reg_note (i3, REG_UNUSED, + SET_DEST (XVECEXP (newpat, 0, 0)))) + { + rtx ni2dest; + + newi2pat = XVECEXP (newpat, 0, 0); + ni2dest = SET_DEST (XVECEXP (newpat, 0, 0)); + newpat = XVECEXP (newpat, 0, 1); + SUBST (SET_SRC (newpat), + gen_lowpart_for_combine (GET_MODE (SET_SRC (newpat)), ni2dest)); + i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes); + + if (i2_code_number >= 0) + insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes); + + if (insn_code_number >= 0) + { + rtx insn; + rtx link; + + /* If we will be able to accept this, we have made a change to the + destination of I3. This can invalidate a LOG_LINKS pointing + to I3. No other part of combine.c makes such a transformation. + + The new I3 will have a destination that was previously the + destination of I1 or I2 and which was used in i2 or I3. Call + distribute_links to make a LOG_LINK from the next use of + that destination. */ + + PATTERN (i3) = newpat; + distribute_links (gen_rtx_INSN_LIST (VOIDmode, i3, NULL_RTX)); + + /* I3 now uses what used to be its destination and which is + now I2's destination. That means we need a LOG_LINK from + I3 to I2. But we used to have one, so we still will. + + However, some later insn might be using I2's dest and have + a LOG_LINK pointing at I3. We must remove this link. + The simplest way to remove the link is to point it at I1, + which we know will be a NOTE. */ + + for (insn = NEXT_INSN (i3); + insn && (this_basic_block == n_basic_blocks - 1 + || insn != BLOCK_HEAD (this_basic_block + 1)); + insn = NEXT_INSN (insn)) + { + if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' + && reg_referenced_p (ni2dest, PATTERN (insn))) + { + for (link = LOG_LINKS (insn); link; + link = XEXP (link, 1)) + if (XEXP (link, 0) == i3) + XEXP (link, 0) = i1; + + break; + } + } + } + } + + /* Similarly, check for a case where we have a PARALLEL of two independent + SETs but we started with three insns. In this case, we can do the sets + as two separate insns. This case occurs when some SET allows two + other insns to combine, but the destination of that SET is still live. */ + + else if (i1 && insn_code_number < 0 && asm_noperands (newpat) < 0 + && GET_CODE (newpat) == PARALLEL + && XVECLEN (newpat, 0) == 2 + && GET_CODE (XVECEXP (newpat, 0, 0)) == SET + && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) != ZERO_EXTRACT + && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) != STRICT_LOW_PART + && GET_CODE (XVECEXP (newpat, 0, 1)) == SET + && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != ZERO_EXTRACT + && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != STRICT_LOW_PART + && ! use_crosses_set_p (SET_SRC (XVECEXP (newpat, 0, 1)), + INSN_CUID (i2)) + /* Don't pass sets with (USE (MEM ...)) dests to the following. */ + && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != USE + && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) != USE + && ! reg_referenced_p (SET_DEST (XVECEXP (newpat, 0, 1)), + XVECEXP (newpat, 0, 0)) + && ! reg_referenced_p (SET_DEST (XVECEXP (newpat, 0, 0)), + XVECEXP (newpat, 0, 1))) + { + /* Normally, it doesn't matter which of the two is done first, + but it does if one references cc0. In that case, it has to + be first. */ +#ifdef HAVE_cc0 + if (reg_referenced_p (cc0_rtx, XVECEXP (newpat, 0, 0))) + { + newi2pat = XVECEXP (newpat, 0, 0); + newpat = XVECEXP (newpat, 0, 1); + } + else +#endif + { + newi2pat = XVECEXP (newpat, 0, 1); + newpat = XVECEXP (newpat, 0, 0); + } + + i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes); + + if (i2_code_number >= 0) + insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes); + } + + /* If it still isn't recognized, fail and change things back the way they + were. */ + if ((insn_code_number < 0 + /* Is the result a reasonable ASM_OPERANDS? */ + && (! check_asm_operands (newpat) || added_sets_1 || added_sets_2))) + { + undo_all (); + return 0; + } + + /* If we had to change another insn, make sure it is valid also. */ + if (undobuf.other_insn) + { + rtx other_pat = PATTERN (undobuf.other_insn); + rtx new_other_notes; + rtx note, next; + + CLEAR_HARD_REG_SET (newpat_used_regs); + + other_code_number = recog_for_combine (&other_pat, undobuf.other_insn, + &new_other_notes); + + if (other_code_number < 0 && ! check_asm_operands (other_pat)) + { + undo_all (); + return 0; + } + + PATTERN (undobuf.other_insn) = other_pat; + + /* If any of the notes in OTHER_INSN were REG_UNUSED, ensure that they + are still valid. Then add any non-duplicate notes added by + recog_for_combine. */ + for (note = REG_NOTES (undobuf.other_insn); note; note = next) + { + next = XEXP (note, 1); + + if (REG_NOTE_KIND (note) == REG_UNUSED + && ! reg_set_p (XEXP (note, 0), PATTERN (undobuf.other_insn))) + { + if (GET_CODE (XEXP (note, 0)) == REG) + REG_N_DEATHS (REGNO (XEXP (note, 0)))--; + + remove_note (undobuf.other_insn, note); + } + } + + for (note = new_other_notes; note; note = XEXP (note, 1)) + if (GET_CODE (XEXP (note, 0)) == REG) + REG_N_DEATHS (REGNO (XEXP (note, 0)))++; + + distribute_notes (new_other_notes, undobuf.other_insn, + undobuf.other_insn, NULL_RTX, NULL_RTX, NULL_RTX); + } + + /* We now know that we can do this combination. Merge the insns and + update the status of registers and LOG_LINKS. */ + + { + rtx i3notes, i2notes, i1notes = 0; + rtx i3links, i2links, i1links = 0; + rtx midnotes = 0; + register int regno; + /* Compute which registers we expect to eliminate. newi2pat may be setting + either i3dest or i2dest, so we must check it. Also, i1dest may be the + same as i3dest, in which case newi2pat may be setting i1dest. */ + rtx elim_i2 = ((newi2pat && reg_set_p (i2dest, newi2pat)) + || i2dest_in_i2src || i2dest_in_i1src + ? 0 : i2dest); + rtx elim_i1 = (i1 == 0 || i1dest_in_i1src + || (newi2pat && reg_set_p (i1dest, newi2pat)) + ? 0 : i1dest); + + /* Get the old REG_NOTES and LOG_LINKS from all our insns and + clear them. */ + i3notes = REG_NOTES (i3), i3links = LOG_LINKS (i3); + i2notes = REG_NOTES (i2), i2links = LOG_LINKS (i2); + if (i1) + i1notes = REG_NOTES (i1), i1links = LOG_LINKS (i1); + + /* Ensure that we do not have something that should not be shared but + occurs multiple times in the new insns. Check this by first + resetting all the `used' flags and then copying anything is shared. */ + + reset_used_flags (i3notes); + reset_used_flags (i2notes); + reset_used_flags (i1notes); + reset_used_flags (newpat); + reset_used_flags (newi2pat); + if (undobuf.other_insn) + reset_used_flags (PATTERN (undobuf.other_insn)); + + i3notes = copy_rtx_if_shared (i3notes); + i2notes = copy_rtx_if_shared (i2notes); + i1notes = copy_rtx_if_shared (i1notes); + newpat = copy_rtx_if_shared (newpat); + newi2pat = copy_rtx_if_shared (newi2pat); + if (undobuf.other_insn) + reset_used_flags (PATTERN (undobuf.other_insn)); + + INSN_CODE (i3) = insn_code_number; + PATTERN (i3) = newpat; + if (undobuf.other_insn) + INSN_CODE (undobuf.other_insn) = other_code_number; + + /* We had one special case above where I2 had more than one set and + we replaced a destination of one of those sets with the destination + of I3. In that case, we have to update LOG_LINKS of insns later + in this basic block. Note that this (expensive) case is rare. + + Also, in this case, we must pretend that all REG_NOTEs for I2 + actually came from I3, so that REG_UNUSED notes from I2 will be + properly handled. */ + + if (i3_subst_into_i2) + { + for (i = 0; i < XVECLEN (PATTERN (i2), 0); i++) + if (GET_CODE (SET_DEST (XVECEXP (PATTERN (i2), 0, i))) == REG + && SET_DEST (XVECEXP (PATTERN (i2), 0, i)) != i2dest + && ! find_reg_note (i2, REG_UNUSED, + SET_DEST (XVECEXP (PATTERN (i2), 0, i)))) + for (temp = NEXT_INSN (i2); + temp && (this_basic_block == n_basic_blocks - 1 + || BLOCK_HEAD (this_basic_block) != temp); + temp = NEXT_INSN (temp)) + if (temp != i3 && GET_RTX_CLASS (GET_CODE (temp)) == 'i') + for (link = LOG_LINKS (temp); link; link = XEXP (link, 1)) + if (XEXP (link, 0) == i2) + XEXP (link, 0) = i3; + + if (i3notes) + { + rtx link = i3notes; + while (XEXP (link, 1)) + link = XEXP (link, 1); + XEXP (link, 1) = i2notes; + } + else + i3notes = i2notes; + i2notes = 0; + } + + LOG_LINKS (i3) = 0; + REG_NOTES (i3) = 0; + LOG_LINKS (i2) = 0; + REG_NOTES (i2) = 0; + + if (newi2pat) + { + INSN_CODE (i2) = i2_code_number; + PATTERN (i2) = newi2pat; + } + else + { + PUT_CODE (i2, NOTE); + NOTE_LINE_NUMBER (i2) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (i2) = 0; + } + + if (i1) + { + LOG_LINKS (i1) = 0; + REG_NOTES (i1) = 0; + PUT_CODE (i1, NOTE); + NOTE_LINE_NUMBER (i1) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (i1) = 0; + } + + /* Get death notes for everything that is now used in either I3 or + I2 and used to die in a previous insn. If we built two new + patterns, move from I1 to I2 then I2 to I3 so that we get the + proper movement on registers that I2 modifies. */ + + if (newi2pat) + { + move_deaths (newi2pat, NULL_RTX, INSN_CUID (i1), i2, &midnotes); + move_deaths (newpat, newi2pat, INSN_CUID (i1), i3, &midnotes); + } + else + move_deaths (newpat, NULL_RTX, i1 ? INSN_CUID (i1) : INSN_CUID (i2), + i3, &midnotes); + + /* Distribute all the LOG_LINKS and REG_NOTES from I1, I2, and I3. */ + if (i3notes) + distribute_notes (i3notes, i3, i3, newi2pat ? i2 : NULL_RTX, + elim_i2, elim_i1); + if (i2notes) + distribute_notes (i2notes, i2, i3, newi2pat ? i2 : NULL_RTX, + elim_i2, elim_i1); + if (i1notes) + distribute_notes (i1notes, i1, i3, newi2pat ? i2 : NULL_RTX, + elim_i2, elim_i1); + if (midnotes) + distribute_notes (midnotes, NULL_RTX, i3, newi2pat ? i2 : NULL_RTX, + elim_i2, elim_i1); + + /* Distribute any notes added to I2 or I3 by recog_for_combine. We + know these are REG_UNUSED and want them to go to the desired insn, + so we always pass it as i3. We have not counted the notes in + reg_n_deaths yet, so we need to do so now. */ + + if (newi2pat && new_i2_notes) + { + for (temp = new_i2_notes; temp; temp = XEXP (temp, 1)) + if (GET_CODE (XEXP (temp, 0)) == REG) + REG_N_DEATHS (REGNO (XEXP (temp, 0)))++; + + distribute_notes (new_i2_notes, i2, i2, NULL_RTX, NULL_RTX, NULL_RTX); + } + + if (new_i3_notes) + { + for (temp = new_i3_notes; temp; temp = XEXP (temp, 1)) + if (GET_CODE (XEXP (temp, 0)) == REG) + REG_N_DEATHS (REGNO (XEXP (temp, 0)))++; + + distribute_notes (new_i3_notes, i3, i3, NULL_RTX, NULL_RTX, NULL_RTX); + } + + /* If I3DEST was used in I3SRC, it really died in I3. We may need to + put a REG_DEAD note for it somewhere. If NEWI2PAT exists and sets + I3DEST, the death must be somewhere before I2, not I3. If we passed I3 + in that case, it might delete I2. Similarly for I2 and I1. + Show an additional death due to the REG_DEAD note we make here. If + we discard it in distribute_notes, we will decrement it again. */ + + if (i3dest_killed) + { + if (GET_CODE (i3dest_killed) == REG) + REG_N_DEATHS (REGNO (i3dest_killed))++; + + if (newi2pat && reg_set_p (i3dest_killed, newi2pat)) + distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed, + NULL_RTX), + NULL_RTX, i2, NULL_RTX, elim_i2, elim_i1); + else + distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed, + NULL_RTX), + NULL_RTX, i3, newi2pat ? i2 : NULL_RTX, + elim_i2, elim_i1); + } + + if (i2dest_in_i2src) + { + if (GET_CODE (i2dest) == REG) + REG_N_DEATHS (REGNO (i2dest))++; + + if (newi2pat && reg_set_p (i2dest, newi2pat)) + distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX), + NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX); + else + distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX), + NULL_RTX, i3, newi2pat ? i2 : NULL_RTX, + NULL_RTX, NULL_RTX); + } + + if (i1dest_in_i1src) + { + if (GET_CODE (i1dest) == REG) + REG_N_DEATHS (REGNO (i1dest))++; + + if (newi2pat && reg_set_p (i1dest, newi2pat)) + distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX), + NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX); + else + distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX), + NULL_RTX, i3, newi2pat ? i2 : NULL_RTX, + NULL_RTX, NULL_RTX); + } + + distribute_links (i3links); + distribute_links (i2links); + distribute_links (i1links); + + if (GET_CODE (i2dest) == REG) + { + rtx link; + rtx i2_insn = 0, i2_val = 0, set; + + /* The insn that used to set this register doesn't exist, and + this life of the register may not exist either. See if one of + I3's links points to an insn that sets I2DEST. If it does, + that is now the last known value for I2DEST. If we don't update + this and I2 set the register to a value that depended on its old + contents, we will get confused. If this insn is used, thing + will be set correctly in combine_instructions. */ + + for (link = LOG_LINKS (i3); link; link = XEXP (link, 1)) + if ((set = single_set (XEXP (link, 0))) != 0 + && rtx_equal_p (i2dest, SET_DEST (set))) + i2_insn = XEXP (link, 0), i2_val = SET_SRC (set); + + record_value_for_reg (i2dest, i2_insn, i2_val); + + /* If the reg formerly set in I2 died only once and that was in I3, + zero its use count so it won't make `reload' do any work. */ + if (! added_sets_2 + && (newi2pat == 0 || ! reg_mentioned_p (i2dest, newi2pat)) + && ! i2dest_in_i2src) + { + regno = REGNO (i2dest); + REG_N_SETS (regno)--; + if (REG_N_SETS (regno) == 0 + && ! REGNO_REG_SET_P (basic_block_live_at_start[0], regno)) + REG_N_REFS (regno) = 0; + } + } + + if (i1 && GET_CODE (i1dest) == REG) + { + rtx link; + rtx i1_insn = 0, i1_val = 0, set; + + for (link = LOG_LINKS (i3); link; link = XEXP (link, 1)) + if ((set = single_set (XEXP (link, 0))) != 0 + && rtx_equal_p (i1dest, SET_DEST (set))) + i1_insn = XEXP (link, 0), i1_val = SET_SRC (set); + + record_value_for_reg (i1dest, i1_insn, i1_val); + + regno = REGNO (i1dest); + if (! added_sets_1 && ! i1dest_in_i1src) + { + REG_N_SETS (regno)--; + if (REG_N_SETS (regno) == 0 + && ! REGNO_REG_SET_P (basic_block_live_at_start[0], regno)) + REG_N_REFS (regno) = 0; + } + } + + /* Update reg_nonzero_bits et al for any changes that may have been made + to this insn. */ + + note_stores (newpat, set_nonzero_bits_and_sign_copies); + if (newi2pat) + note_stores (newi2pat, set_nonzero_bits_and_sign_copies); + + /* If I3 is now an unconditional jump, ensure that it has a + BARRIER following it since it may have initially been a + conditional jump. It may also be the last nonnote insn. */ + + if ((GET_CODE (newpat) == RETURN || simplejump_p (i3)) + && ((temp = next_nonnote_insn (i3)) == NULL_RTX + || GET_CODE (temp) != BARRIER)) + emit_barrier_after (i3); + } + + combine_successes++; + + /* Clear this here, so that subsequent get_last_value calls are not + affected. */ + subst_prev_insn = NULL_RTX; + + if (added_links_insn + && (newi2pat == 0 || INSN_CUID (added_links_insn) < INSN_CUID (i2)) + && INSN_CUID (added_links_insn) < INSN_CUID (i3)) + return added_links_insn; + else + return newi2pat ? i2 : i3; +} + +/* Undo all the modifications recorded in undobuf. */ + +static void +undo_all () +{ + struct undo *undo, *next; + + for (undo = undobuf.undos; undo; undo = next) + { + next = undo->next; + if (undo->is_int) + *undo->where.i = undo->old_contents.i; + else + *undo->where.r = undo->old_contents.r; + + undo->next = undobuf.frees; + undobuf.frees = undo; + } + + obfree (undobuf.storage); + undobuf.undos = undobuf.previous_undos = 0; + + /* Clear this here, so that subsequent get_last_value calls are not + affected. */ + subst_prev_insn = NULL_RTX; +} + +/* Find the innermost point within the rtx at LOC, possibly LOC itself, + where we have an arithmetic expression and return that point. LOC will + be inside INSN. + + try_combine will call this function to see if an insn can be split into + two insns. */ + +static rtx * +find_split_point (loc, insn) + rtx *loc; + rtx insn; +{ + rtx x = *loc; + enum rtx_code code = GET_CODE (x); + rtx *split; + int len = 0, pos, unsignedp; + rtx inner; + + /* First special-case some codes. */ + switch (code) + { + case SUBREG: +#ifdef INSN_SCHEDULING + /* If we are making a paradoxical SUBREG invalid, it becomes a split + point. */ + if (GET_CODE (SUBREG_REG (x)) == MEM) + return loc; +#endif + return find_split_point (&SUBREG_REG (x), insn); + + case MEM: +#ifdef HAVE_lo_sum + /* If we have (mem (const ..)) or (mem (symbol_ref ...)), split it + using LO_SUM and HIGH. */ + if (GET_CODE (XEXP (x, 0)) == CONST + || GET_CODE (XEXP (x, 0)) == SYMBOL_REF) + { + SUBST (XEXP (x, 0), + gen_rtx_combine (LO_SUM, Pmode, + gen_rtx_combine (HIGH, Pmode, XEXP (x, 0)), + XEXP (x, 0))); + return &XEXP (XEXP (x, 0), 0); + } +#endif + + /* If we have a PLUS whose second operand is a constant and the + address is not valid, perhaps will can split it up using + the machine-specific way to split large constants. We use + the first pseudo-reg (one of the virtual regs) as a placeholder; + it will not remain in the result. */ + if (GET_CODE (XEXP (x, 0)) == PLUS + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && ! memory_address_p (GET_MODE (x), XEXP (x, 0))) + { + rtx reg = regno_reg_rtx[FIRST_PSEUDO_REGISTER]; + rtx seq = split_insns (gen_rtx_SET (VOIDmode, reg, XEXP (x, 0)), + subst_insn); + + /* This should have produced two insns, each of which sets our + placeholder. If the source of the second is a valid address, + we can make put both sources together and make a split point + in the middle. */ + + if (seq && XVECLEN (seq, 0) == 2 + && GET_CODE (XVECEXP (seq, 0, 0)) == INSN + && GET_CODE (PATTERN (XVECEXP (seq, 0, 0))) == SET + && SET_DEST (PATTERN (XVECEXP (seq, 0, 0))) == reg + && ! reg_mentioned_p (reg, + SET_SRC (PATTERN (XVECEXP (seq, 0, 0)))) + && GET_CODE (XVECEXP (seq, 0, 1)) == INSN + && GET_CODE (PATTERN (XVECEXP (seq, 0, 1))) == SET + && SET_DEST (PATTERN (XVECEXP (seq, 0, 1))) == reg + && memory_address_p (GET_MODE (x), + SET_SRC (PATTERN (XVECEXP (seq, 0, 1))))) + { + rtx src1 = SET_SRC (PATTERN (XVECEXP (seq, 0, 0))); + rtx src2 = SET_SRC (PATTERN (XVECEXP (seq, 0, 1))); + + /* Replace the placeholder in SRC2 with SRC1. If we can + find where in SRC2 it was placed, that can become our + split point and we can replace this address with SRC2. + Just try two obvious places. */ + + src2 = replace_rtx (src2, reg, src1); + split = 0; + if (XEXP (src2, 0) == src1) + split = &XEXP (src2, 0); + else if (GET_RTX_FORMAT (GET_CODE (XEXP (src2, 0)))[0] == 'e' + && XEXP (XEXP (src2, 0), 0) == src1) + split = &XEXP (XEXP (src2, 0), 0); + + if (split) + { + SUBST (XEXP (x, 0), src2); + return split; + } + } + + /* If that didn't work, perhaps the first operand is complex and + needs to be computed separately, so make a split point there. + This will occur on machines that just support REG + CONST + and have a constant moved through some previous computation. */ + + else if (GET_RTX_CLASS (GET_CODE (XEXP (XEXP (x, 0), 0))) != 'o' + && ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG + && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (XEXP (x, 0), 0)))) + == 'o'))) + return &XEXP (XEXP (x, 0), 0); + } + break; + + case SET: +#ifdef HAVE_cc0 + /* If SET_DEST is CC0 and SET_SRC is not an operand, a COMPARE, or a + ZERO_EXTRACT, the most likely reason why this doesn't match is that + we need to put the operand into a register. So split at that + point. */ + + if (SET_DEST (x) == cc0_rtx + && GET_CODE (SET_SRC (x)) != COMPARE + && GET_CODE (SET_SRC (x)) != ZERO_EXTRACT + && GET_RTX_CLASS (GET_CODE (SET_SRC (x))) != 'o' + && ! (GET_CODE (SET_SRC (x)) == SUBREG + && GET_RTX_CLASS (GET_CODE (SUBREG_REG (SET_SRC (x)))) == 'o')) + return &SET_SRC (x); +#endif + + /* See if we can split SET_SRC as it stands. */ + split = find_split_point (&SET_SRC (x), insn); + if (split && split != &SET_SRC (x)) + return split; + + /* See if we can split SET_DEST as it stands. */ + split = find_split_point (&SET_DEST (x), insn); + if (split && split != &SET_DEST (x)) + return split; + + /* See if this is a bitfield assignment with everything constant. If + so, this is an IOR of an AND, so split it into that. */ + if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT + && (GET_MODE_BITSIZE (GET_MODE (XEXP (SET_DEST (x), 0))) + <= HOST_BITS_PER_WIDE_INT) + && GET_CODE (XEXP (SET_DEST (x), 1)) == CONST_INT + && GET_CODE (XEXP (SET_DEST (x), 2)) == CONST_INT + && GET_CODE (SET_SRC (x)) == CONST_INT + && ((INTVAL (XEXP (SET_DEST (x), 1)) + + INTVAL (XEXP (SET_DEST (x), 2))) + <= GET_MODE_BITSIZE (GET_MODE (XEXP (SET_DEST (x), 0)))) + && ! side_effects_p (XEXP (SET_DEST (x), 0))) + { + int pos = INTVAL (XEXP (SET_DEST (x), 2)); + int len = INTVAL (XEXP (SET_DEST (x), 1)); + int src = INTVAL (SET_SRC (x)); + rtx dest = XEXP (SET_DEST (x), 0); + enum machine_mode mode = GET_MODE (dest); + unsigned HOST_WIDE_INT mask = ((HOST_WIDE_INT) 1 << len) - 1; + + if (BITS_BIG_ENDIAN) + pos = GET_MODE_BITSIZE (mode) - len - pos; + + if ((unsigned HOST_WIDE_INT) src == mask) + SUBST (SET_SRC (x), + gen_binary (IOR, mode, dest, GEN_INT (src << pos))); + else + SUBST (SET_SRC (x), + gen_binary (IOR, mode, + gen_binary (AND, mode, dest, + GEN_INT (~ (mask << pos) + & GET_MODE_MASK (mode))), + GEN_INT (src << pos))); + + SUBST (SET_DEST (x), dest); + + split = find_split_point (&SET_SRC (x), insn); + if (split && split != &SET_SRC (x)) + return split; + } + + /* Otherwise, see if this is an operation that we can split into two. + If so, try to split that. */ + code = GET_CODE (SET_SRC (x)); + + switch (code) + { + case AND: + /* If we are AND'ing with a large constant that is only a single + bit and the result is only being used in a context where we + need to know if it is zero or non-zero, replace it with a bit + extraction. This will avoid the large constant, which might + have taken more than one insn to make. If the constant were + not a valid argument to the AND but took only one insn to make, + this is no worse, but if it took more than one insn, it will + be better. */ + + if (GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT + && GET_CODE (XEXP (SET_SRC (x), 0)) == REG + && (pos = exact_log2 (INTVAL (XEXP (SET_SRC (x), 1)))) >= 7 + && GET_CODE (SET_DEST (x)) == REG + && (split = find_single_use (SET_DEST (x), insn, NULL_PTR)) != 0 + && (GET_CODE (*split) == EQ || GET_CODE (*split) == NE) + && XEXP (*split, 0) == SET_DEST (x) + && XEXP (*split, 1) == const0_rtx) + { + rtx extraction = make_extraction (GET_MODE (SET_DEST (x)), + XEXP (SET_SRC (x), 0), + pos, NULL_RTX, 1, 1, 0, 0); + if (extraction != 0) + { + SUBST (SET_SRC (x), extraction); + return find_split_point (loc, insn); + } + } + break; + + case NE: + /* if STORE_FLAG_VALUE is -1, this is (NE X 0) and only one bit of X + is known to be on, this can be converted into a NEG of a shift. */ + if (STORE_FLAG_VALUE == -1 && XEXP (SET_SRC (x), 1) == const0_rtx + && GET_MODE (SET_SRC (x)) == GET_MODE (XEXP (SET_SRC (x), 0)) + && 1 <= (pos = exact_log2 + (nonzero_bits (XEXP (SET_SRC (x), 0), + GET_MODE (XEXP (SET_SRC (x), 0)))))) + { + enum machine_mode mode = GET_MODE (XEXP (SET_SRC (x), 0)); + + SUBST (SET_SRC (x), + gen_rtx_combine (NEG, mode, + gen_rtx_combine (LSHIFTRT, mode, + XEXP (SET_SRC (x), 0), + GEN_INT (pos)))); + + split = find_split_point (&SET_SRC (x), insn); + if (split && split != &SET_SRC (x)) + return split; + } + break; + + case SIGN_EXTEND: + inner = XEXP (SET_SRC (x), 0); + + /* We can't optimize if either mode is a partial integer + mode as we don't know how many bits are significant + in those modes. */ + if (GET_MODE_CLASS (GET_MODE (inner)) == MODE_PARTIAL_INT + || GET_MODE_CLASS (GET_MODE (SET_SRC (x))) == MODE_PARTIAL_INT) + break; + + pos = 0; + len = GET_MODE_BITSIZE (GET_MODE (inner)); + unsignedp = 0; + break; + + case SIGN_EXTRACT: + case ZERO_EXTRACT: + if (GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT + && GET_CODE (XEXP (SET_SRC (x), 2)) == CONST_INT) + { + inner = XEXP (SET_SRC (x), 0); + len = INTVAL (XEXP (SET_SRC (x), 1)); + pos = INTVAL (XEXP (SET_SRC (x), 2)); + + if (BITS_BIG_ENDIAN) + pos = GET_MODE_BITSIZE (GET_MODE (inner)) - len - pos; + unsignedp = (code == ZERO_EXTRACT); + } + break; + + default: + break; + } + + if (len && pos >= 0 && pos + len <= GET_MODE_BITSIZE (GET_MODE (inner))) + { + enum machine_mode mode = GET_MODE (SET_SRC (x)); + + /* For unsigned, we have a choice of a shift followed by an + AND or two shifts. Use two shifts for field sizes where the + constant might be too large. We assume here that we can + always at least get 8-bit constants in an AND insn, which is + true for every current RISC. */ + + if (unsignedp && len <= 8) + { + SUBST (SET_SRC (x), + gen_rtx_combine + (AND, mode, + gen_rtx_combine (LSHIFTRT, mode, + gen_lowpart_for_combine (mode, inner), + GEN_INT (pos)), + GEN_INT (((HOST_WIDE_INT) 1 << len) - 1))); + + split = find_split_point (&SET_SRC (x), insn); + if (split && split != &SET_SRC (x)) + return split; + } + else + { + SUBST (SET_SRC (x), + gen_rtx_combine + (unsignedp ? LSHIFTRT : ASHIFTRT, mode, + gen_rtx_combine (ASHIFT, mode, + gen_lowpart_for_combine (mode, inner), + GEN_INT (GET_MODE_BITSIZE (mode) + - len - pos)), + GEN_INT (GET_MODE_BITSIZE (mode) - len))); + + split = find_split_point (&SET_SRC (x), insn); + if (split && split != &SET_SRC (x)) + return split; + } + } + + /* See if this is a simple operation with a constant as the second + operand. It might be that this constant is out of range and hence + could be used as a split point. */ + if ((GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '2' + || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == 'c' + || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '<') + && CONSTANT_P (XEXP (SET_SRC (x), 1)) + && (GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (x), 0))) == 'o' + || (GET_CODE (XEXP (SET_SRC (x), 0)) == SUBREG + && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (SET_SRC (x), 0)))) + == 'o')))) + return &XEXP (SET_SRC (x), 1); + + /* Finally, see if this is a simple operation with its first operand + not in a register. The operation might require this operand in a + register, so return it as a split point. We can always do this + because if the first operand were another operation, we would have + already found it as a split point. */ + if ((GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '2' + || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == 'c' + || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '<' + || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '1') + && ! register_operand (XEXP (SET_SRC (x), 0), VOIDmode)) + return &XEXP (SET_SRC (x), 0); + + return 0; + + case AND: + case IOR: + /* We write NOR as (and (not A) (not B)), but if we don't have a NOR, + it is better to write this as (not (ior A B)) so we can split it. + Similarly for IOR. */ + if (GET_CODE (XEXP (x, 0)) == NOT && GET_CODE (XEXP (x, 1)) == NOT) + { + SUBST (*loc, + gen_rtx_combine (NOT, GET_MODE (x), + gen_rtx_combine (code == IOR ? AND : IOR, + GET_MODE (x), + XEXP (XEXP (x, 0), 0), + XEXP (XEXP (x, 1), 0)))); + return find_split_point (loc, insn); + } + + /* Many RISC machines have a large set of logical insns. If the + second operand is a NOT, put it first so we will try to split the + other operand first. */ + if (GET_CODE (XEXP (x, 1)) == NOT) + { + rtx tem = XEXP (x, 0); + SUBST (XEXP (x, 0), XEXP (x, 1)); + SUBST (XEXP (x, 1), tem); + } + break; + + default: + break; + } + + /* Otherwise, select our actions depending on our rtx class. */ + switch (GET_RTX_CLASS (code)) + { + case 'b': /* This is ZERO_EXTRACT and SIGN_EXTRACT. */ + case '3': + split = find_split_point (&XEXP (x, 2), insn); + if (split) + return split; + /* ... fall through ... */ + case '2': + case 'c': + case '<': + split = find_split_point (&XEXP (x, 1), insn); + if (split) + return split; + /* ... fall through ... */ + case '1': + /* Some machines have (and (shift ...) ...) insns. If X is not + an AND, but XEXP (X, 0) is, use it as our split point. */ + if (GET_CODE (x) != AND && GET_CODE (XEXP (x, 0)) == AND) + return &XEXP (x, 0); + + split = find_split_point (&XEXP (x, 0), insn); + if (split) + return split; + return loc; + } + + /* Otherwise, we don't have a split point. */ + return 0; +} + +/* Throughout X, replace FROM with TO, and return the result. + The result is TO if X is FROM; + otherwise the result is X, but its contents may have been modified. + If they were modified, a record was made in undobuf so that + undo_all will (among other things) return X to its original state. + + If the number of changes necessary is too much to record to undo, + the excess changes are not made, so the result is invalid. + The changes already made can still be undone. + undobuf.num_undo is incremented for such changes, so by testing that + the caller can tell whether the result is valid. + + `n_occurrences' is incremented each time FROM is replaced. + + IN_DEST is non-zero if we are processing the SET_DEST of a SET. + + UNIQUE_COPY is non-zero if each substitution must be unique. We do this + by copying if `n_occurrences' is non-zero. */ + +static rtx +subst (x, from, to, in_dest, unique_copy) + register rtx x, from, to; + int in_dest; + int unique_copy; +{ + register enum rtx_code code = GET_CODE (x); + enum machine_mode op0_mode = VOIDmode; + register char *fmt; + register int len, i; + rtx new; + +/* Two expressions are equal if they are identical copies of a shared + RTX or if they are both registers with the same register number + and mode. */ + +#define COMBINE_RTX_EQUAL_P(X,Y) \ + ((X) == (Y) \ + || (GET_CODE (X) == REG && GET_CODE (Y) == REG \ + && REGNO (X) == REGNO (Y) && GET_MODE (X) == GET_MODE (Y))) + + if (! in_dest && COMBINE_RTX_EQUAL_P (x, from)) + { + n_occurrences++; + return (unique_copy && n_occurrences > 1 ? copy_rtx (to) : to); + } + + /* If X and FROM are the same register but different modes, they will + not have been seen as equal above. However, flow.c will make a + LOG_LINKS entry for that case. If we do nothing, we will try to + rerecognize our original insn and, when it succeeds, we will + delete the feeding insn, which is incorrect. + + So force this insn not to match in this (rare) case. */ + if (! in_dest && code == REG && GET_CODE (from) == REG + && REGNO (x) == REGNO (from)) + return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx); + + /* If this is an object, we are done unless it is a MEM or LO_SUM, both + of which may contain things that can be combined. */ + if (code != MEM && code != LO_SUM && GET_RTX_CLASS (code) == 'o') + return x; + + /* It is possible to have a subexpression appear twice in the insn. + Suppose that FROM is a register that appears within TO. + Then, after that subexpression has been scanned once by `subst', + the second time it is scanned, TO may be found. If we were + to scan TO here, we would find FROM within it and create a + self-referent rtl structure which is completely wrong. */ + if (COMBINE_RTX_EQUAL_P (x, to)) + return to; + + /* Parallel asm_operands need special attention because all of the + inputs are shared across the arms. Furthermore, unsharing the + rtl results in recognition failures. Failure to handle this case + specially can result in circular rtl. + + Solve this by doing a normal pass across the first entry of the + parallel, and only processing the SET_DESTs of the subsequent + entries. Ug. */ + + if (code == PARALLEL + && GET_CODE (XVECEXP (x, 0, 0)) == SET + && GET_CODE (SET_SRC (XVECEXP (x, 0, 0))) == ASM_OPERANDS) + { + new = subst (XVECEXP (x, 0, 0), from, to, 0, unique_copy); + + /* If this substitution failed, this whole thing fails. */ + if (GET_CODE (new) == CLOBBER + && XEXP (new, 0) == const0_rtx) + return new; + + SUBST (XVECEXP (x, 0, 0), new); + + for (i = XVECLEN (x, 0) - 1; i >= 1; i--) + { + rtx dest = SET_DEST (XVECEXP (x, 0, i)); + + if (GET_CODE (dest) != REG + && GET_CODE (dest) != CC0 + && GET_CODE (dest) != PC) + { + new = subst (dest, from, to, 0, unique_copy); + + /* If this substitution failed, this whole thing fails. */ + if (GET_CODE (new) == CLOBBER + && XEXP (new, 0) == const0_rtx) + return new; + + SUBST (SET_DEST (XVECEXP (x, 0, i)), new); + } + } + } + else + { + len = GET_RTX_LENGTH (code); + fmt = GET_RTX_FORMAT (code); + + /* We don't need to process a SET_DEST that is a register, CC0, + or PC, so set up to skip this common case. All other cases + where we want to suppress replacing something inside a + SET_SRC are handled via the IN_DEST operand. */ + if (code == SET + && (GET_CODE (SET_DEST (x)) == REG + || GET_CODE (SET_DEST (x)) == CC0 + || GET_CODE (SET_DEST (x)) == PC)) + fmt = "ie"; + + /* Get the mode of operand 0 in case X is now a SIGN_EXTEND of a + constant. */ + if (fmt[0] == 'e') + op0_mode = GET_MODE (XEXP (x, 0)); + + for (i = 0; i < len; i++) + { + if (fmt[i] == 'E') + { + register int j; + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + { + if (COMBINE_RTX_EQUAL_P (XVECEXP (x, i, j), from)) + { + new = (unique_copy && n_occurrences + ? copy_rtx (to) : to); + n_occurrences++; + } + else + { + new = subst (XVECEXP (x, i, j), from, to, 0, + unique_copy); + + /* If this substitution failed, this whole thing + fails. */ + if (GET_CODE (new) == CLOBBER + && XEXP (new, 0) == const0_rtx) + return new; + } + + SUBST (XVECEXP (x, i, j), new); + } + } + else if (fmt[i] == 'e') + { + if (COMBINE_RTX_EQUAL_P (XEXP (x, i), from)) + { + /* In general, don't install a subreg involving two + modes not tieable. It can worsen register + allocation, and can even make invalid reload + insns, since the reg inside may need to be copied + from in the outside mode, and that may be invalid + if it is an fp reg copied in integer mode. + + We allow two exceptions to this: It is valid if + it is inside another SUBREG and the mode of that + SUBREG and the mode of the inside of TO is + tieable and it is valid if X is a SET that copies + FROM to CC0. */ + + if (GET_CODE (to) == SUBREG + && ! MODES_TIEABLE_P (GET_MODE (to), + GET_MODE (SUBREG_REG (to))) + && ! (code == SUBREG + && MODES_TIEABLE_P (GET_MODE (x), + GET_MODE (SUBREG_REG (to)))) +#ifdef HAVE_cc0 + && ! (code == SET && i == 1 && XEXP (x, 0) == cc0_rtx) +#endif + ) + return gen_rtx_CLOBBER (VOIDmode, const0_rtx); + + new = (unique_copy && n_occurrences ? copy_rtx (to) : to); + n_occurrences++; + } + else + /* If we are in a SET_DEST, suppress most cases unless we + have gone inside a MEM, in which case we want to + simplify the address. We assume here that things that + are actually part of the destination have their inner + parts in the first expression. This is true for SUBREG, + STRICT_LOW_PART, and ZERO_EXTRACT, which are the only + things aside from REG and MEM that should appear in a + SET_DEST. */ + new = subst (XEXP (x, i), from, to, + (((in_dest + && (code == SUBREG || code == STRICT_LOW_PART + || code == ZERO_EXTRACT)) + || code == SET) + && i == 0), unique_copy); + + /* If we found that we will have to reject this combination, + indicate that by returning the CLOBBER ourselves, rather than + an expression containing it. This will speed things up as + well as prevent accidents where two CLOBBERs are considered + to be equal, thus producing an incorrect simplification. */ + + if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx) + return new; + + SUBST (XEXP (x, i), new); + } + } + } + + /* Try to simplify X. If the simplification changed the code, it is likely + that further simplification will help, so loop, but limit the number + of repetitions that will be performed. */ + + for (i = 0; i < 4; i++) + { + /* If X is sufficiently simple, don't bother trying to do anything + with it. */ + if (code != CONST_INT && code != REG && code != CLOBBER) + x = simplify_rtx (x, op0_mode, i == 3, in_dest); + + if (GET_CODE (x) == code) + break; + + code = GET_CODE (x); + + /* We no longer know the original mode of operand 0 since we + have changed the form of X) */ + op0_mode = VOIDmode; + } + + return x; +} + +/* Simplify X, a piece of RTL. We just operate on the expression at the + outer level; call `subst' to simplify recursively. Return the new + expression. + + OP0_MODE is the original mode of XEXP (x, 0); LAST is nonzero if this + will be the iteration even if an expression with a code different from + X is returned; IN_DEST is nonzero if we are inside a SET_DEST. */ + +static rtx +simplify_rtx (x, op0_mode, last, in_dest) + rtx x; + enum machine_mode op0_mode; + int last; + int in_dest; +{ + enum rtx_code code = GET_CODE (x); + enum machine_mode mode = GET_MODE (x); + rtx temp; + int i; + + /* If this is a commutative operation, put a constant last and a complex + expression first. We don't need to do this for comparisons here. */ + if (GET_RTX_CLASS (code) == 'c' + && ((CONSTANT_P (XEXP (x, 0)) && GET_CODE (XEXP (x, 1)) != CONST_INT) + || (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == 'o' + && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) != 'o') + || (GET_CODE (XEXP (x, 0)) == SUBREG + && GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0)))) == 'o' + && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) != 'o'))) + { + temp = XEXP (x, 0); + SUBST (XEXP (x, 0), XEXP (x, 1)); + SUBST (XEXP (x, 1), temp); + } + + /* If this is a PLUS, MINUS, or MULT, and the first operand is the + sign extension of a PLUS with a constant, reverse the order of the sign + extension and the addition. Note that this not the same as the original + code, but overflow is undefined for signed values. Also note that the + PLUS will have been partially moved "inside" the sign-extension, so that + the first operand of X will really look like: + (ashiftrt (plus (ashift A C4) C5) C4). + We convert this to + (plus (ashiftrt (ashift A C4) C2) C4) + and replace the first operand of X with that expression. Later parts + of this function may simplify the expression further. + + For example, if we start with (mult (sign_extend (plus A C1)) C2), + we swap the SIGN_EXTEND and PLUS. Later code will apply the + distributive law to produce (plus (mult (sign_extend X) C1) C3). + + We do this to simplify address expressions. */ + + if ((code == PLUS || code == MINUS || code == MULT) + && GET_CODE (XEXP (x, 0)) == ASHIFTRT + && GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS + && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == ASHIFT + && GET_CODE (XEXP (XEXP (XEXP (XEXP (x, 0), 0), 0), 1)) == CONST_INT + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && XEXP (XEXP (XEXP (XEXP (x, 0), 0), 0), 1) == XEXP (XEXP (x, 0), 1) + && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == CONST_INT + && (temp = simplify_binary_operation (ASHIFTRT, mode, + XEXP (XEXP (XEXP (x, 0), 0), 1), + XEXP (XEXP (x, 0), 1))) != 0) + { + rtx new + = simplify_shift_const (NULL_RTX, ASHIFT, mode, + XEXP (XEXP (XEXP (XEXP (x, 0), 0), 0), 0), + INTVAL (XEXP (XEXP (x, 0), 1))); + + new = simplify_shift_const (NULL_RTX, ASHIFTRT, mode, new, + INTVAL (XEXP (XEXP (x, 0), 1))); + + SUBST (XEXP (x, 0), gen_binary (PLUS, mode, new, temp)); + } + + /* If this is a simple operation applied to an IF_THEN_ELSE, try + applying it to the arms of the IF_THEN_ELSE. This often simplifies + things. Check for cases where both arms are testing the same + condition. + + Don't do anything if all operands are very simple. */ + + if (((GET_RTX_CLASS (code) == '2' || GET_RTX_CLASS (code) == 'c' + || GET_RTX_CLASS (code) == '<') + && ((GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) != 'o' + && ! (GET_CODE (XEXP (x, 0)) == SUBREG + && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0)))) + == 'o'))) + || (GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) != 'o' + && ! (GET_CODE (XEXP (x, 1)) == SUBREG + && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 1)))) + == 'o'))))) + || (GET_RTX_CLASS (code) == '1' + && ((GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) != 'o' + && ! (GET_CODE (XEXP (x, 0)) == SUBREG + && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0)))) + == 'o')))))) + { + rtx cond, true, false; + + cond = if_then_else_cond (x, &true, &false); + if (cond != 0 + /* If everything is a comparison, what we have is highly unlikely + to be simpler, so don't use it. */ + && ! (GET_RTX_CLASS (code) == '<' + && (GET_RTX_CLASS (GET_CODE (true)) == '<' + || GET_RTX_CLASS (GET_CODE (false)) == '<'))) + { + rtx cop1 = const0_rtx; + enum rtx_code cond_code = simplify_comparison (NE, &cond, &cop1); + + if (cond_code == NE && GET_RTX_CLASS (GET_CODE (cond)) == '<') + return x; + + /* Simplify the alternative arms; this may collapse the true and + false arms to store-flag values. */ + true = subst (true, pc_rtx, pc_rtx, 0, 0); + false = subst (false, pc_rtx, pc_rtx, 0, 0); + + /* Restarting if we generate a store-flag expression will cause + us to loop. Just drop through in this case. */ + + /* If the result values are STORE_FLAG_VALUE and zero, we can + just make the comparison operation. */ + if (true == const_true_rtx && false == const0_rtx) + x = gen_binary (cond_code, mode, cond, cop1); + else if (true == const0_rtx && false == const_true_rtx) + x = gen_binary (reverse_condition (cond_code), mode, cond, cop1); + + /* Likewise, we can make the negate of a comparison operation + if the result values are - STORE_FLAG_VALUE and zero. */ + else if (GET_CODE (true) == CONST_INT + && INTVAL (true) == - STORE_FLAG_VALUE + && false == const0_rtx) + x = gen_unary (NEG, mode, mode, + gen_binary (cond_code, mode, cond, cop1)); + else if (GET_CODE (false) == CONST_INT + && INTVAL (false) == - STORE_FLAG_VALUE + && true == const0_rtx) + x = gen_unary (NEG, mode, mode, + gen_binary (reverse_condition (cond_code), + mode, cond, cop1)); + else + return gen_rtx_IF_THEN_ELSE (mode, + gen_binary (cond_code, VOIDmode, + cond, cop1), + true, false); + + code = GET_CODE (x); + op0_mode = VOIDmode; + } + } + + /* Try to fold this expression in case we have constants that weren't + present before. */ + temp = 0; + switch (GET_RTX_CLASS (code)) + { + case '1': + temp = simplify_unary_operation (code, mode, XEXP (x, 0), op0_mode); + break; + case '<': + temp = simplify_relational_operation (code, op0_mode, + XEXP (x, 0), XEXP (x, 1)); +#ifdef FLOAT_STORE_FLAG_VALUE + if (temp != 0 && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) + temp = ((temp == const0_rtx) ? CONST0_RTX (GET_MODE (x)) + : immed_real_const_1 (FLOAT_STORE_FLAG_VALUE, GET_MODE (x))); +#endif + break; + case 'c': + case '2': + temp = simplify_binary_operation (code, mode, XEXP (x, 0), XEXP (x, 1)); + break; + case 'b': + case '3': + temp = simplify_ternary_operation (code, mode, op0_mode, XEXP (x, 0), + XEXP (x, 1), XEXP (x, 2)); + break; + } + + if (temp) + x = temp, code = GET_CODE (temp); + + /* First see if we can apply the inverse distributive law. */ + if (code == PLUS || code == MINUS + || code == AND || code == IOR || code == XOR) + { + x = apply_distributive_law (x); + code = GET_CODE (x); + } + + /* If CODE is an associative operation not otherwise handled, see if we + can associate some operands. This can win if they are constants or + if they are logically related (i.e. (a & b) & a. */ + if ((code == PLUS || code == MINUS + || code == MULT || code == AND || code == IOR || code == XOR + || code == DIV || code == UDIV + || code == SMAX || code == SMIN || code == UMAX || code == UMIN) + && INTEGRAL_MODE_P (mode)) + { + if (GET_CODE (XEXP (x, 0)) == code) + { + rtx other = XEXP (XEXP (x, 0), 0); + rtx inner_op0 = XEXP (XEXP (x, 0), 1); + rtx inner_op1 = XEXP (x, 1); + rtx inner; + + /* Make sure we pass the constant operand if any as the second + one if this is a commutative operation. */ + if (CONSTANT_P (inner_op0) && GET_RTX_CLASS (code) == 'c') + { + rtx tem = inner_op0; + inner_op0 = inner_op1; + inner_op1 = tem; + } + inner = simplify_binary_operation (code == MINUS ? PLUS + : code == DIV ? MULT + : code == UDIV ? MULT + : code, + mode, inner_op0, inner_op1); + + /* For commutative operations, try the other pair if that one + didn't simplify. */ + if (inner == 0 && GET_RTX_CLASS (code) == 'c') + { + other = XEXP (XEXP (x, 0), 1); + inner = simplify_binary_operation (code, mode, + XEXP (XEXP (x, 0), 0), + XEXP (x, 1)); + } + + if (inner) + return gen_binary (code, mode, other, inner); + } + } + + /* A little bit of algebraic simplification here. */ + switch (code) + { + case MEM: + /* Ensure that our address has any ASHIFTs converted to MULT in case + address-recognizing predicates are called later. */ + temp = make_compound_operation (XEXP (x, 0), MEM); + SUBST (XEXP (x, 0), temp); + break; + + case SUBREG: + /* (subreg:A (mem:B X) N) becomes a modified MEM unless the SUBREG + is paradoxical. If we can't do that safely, then it becomes + something nonsensical so that this combination won't take place. */ + + if (GET_CODE (SUBREG_REG (x)) == MEM + && (GET_MODE_SIZE (mode) + <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))) + { + rtx inner = SUBREG_REG (x); + int endian_offset = 0; + /* Don't change the mode of the MEM + if that would change the meaning of the address. */ + if (MEM_VOLATILE_P (SUBREG_REG (x)) + || mode_dependent_address_p (XEXP (inner, 0))) + return gen_rtx_CLOBBER (mode, const0_rtx); + + if (BYTES_BIG_ENDIAN) + { + if (GET_MODE_SIZE (mode) < UNITS_PER_WORD) + endian_offset += UNITS_PER_WORD - GET_MODE_SIZE (mode); + if (GET_MODE_SIZE (GET_MODE (inner)) < UNITS_PER_WORD) + endian_offset -= (UNITS_PER_WORD + - GET_MODE_SIZE (GET_MODE (inner))); + } + /* Note if the plus_constant doesn't make a valid address + then this combination won't be accepted. */ + x = gen_rtx_MEM (mode, + plus_constant (XEXP (inner, 0), + (SUBREG_WORD (x) * UNITS_PER_WORD + + endian_offset))); + RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (inner); + MEM_COPY_ATTRIBUTES (x, inner); + return x; + } + + /* If we are in a SET_DEST, these other cases can't apply. */ + if (in_dest) + return x; + + /* Changing mode twice with SUBREG => just change it once, + or not at all if changing back to starting mode. */ + if (GET_CODE (SUBREG_REG (x)) == SUBREG) + { + if (mode == GET_MODE (SUBREG_REG (SUBREG_REG (x))) + && SUBREG_WORD (x) == 0 && SUBREG_WORD (SUBREG_REG (x)) == 0) + return SUBREG_REG (SUBREG_REG (x)); + + SUBST_INT (SUBREG_WORD (x), + SUBREG_WORD (x) + SUBREG_WORD (SUBREG_REG (x))); + SUBST (SUBREG_REG (x), SUBREG_REG (SUBREG_REG (x))); + } + + /* SUBREG of a hard register => just change the register number + and/or mode. If the hard register is not valid in that mode, + suppress this combination. If the hard register is the stack, + frame, or argument pointer, leave this as a SUBREG. */ + + if (GET_CODE (SUBREG_REG (x)) == REG + && REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER + && REGNO (SUBREG_REG (x)) != FRAME_POINTER_REGNUM +#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM + && REGNO (SUBREG_REG (x)) != HARD_FRAME_POINTER_REGNUM +#endif +#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM + && REGNO (SUBREG_REG (x)) != ARG_POINTER_REGNUM +#endif + && REGNO (SUBREG_REG (x)) != STACK_POINTER_REGNUM) + { + if (HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (x)) + SUBREG_WORD (x), + mode)) + return gen_rtx_REG (mode, + REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)); + else + return gen_rtx_CLOBBER (mode, const0_rtx); + } + + /* For a constant, try to pick up the part we want. Handle a full + word and low-order part. Only do this if we are narrowing + the constant; if it is being widened, we have no idea what + the extra bits will have been set to. */ + + if (CONSTANT_P (SUBREG_REG (x)) && op0_mode != VOIDmode + && GET_MODE_SIZE (mode) == UNITS_PER_WORD + && GET_MODE_SIZE (op0_mode) > UNITS_PER_WORD + && GET_MODE_CLASS (mode) == MODE_INT) + { + temp = operand_subword (SUBREG_REG (x), SUBREG_WORD (x), + 0, op0_mode); + if (temp) + return temp; + } + + /* If we want a subreg of a constant, at offset 0, + take the low bits. On a little-endian machine, that's + always valid. On a big-endian machine, it's valid + only if the constant's mode fits in one word. Note that we + cannot use subreg_lowpart_p since SUBREG_REG may be VOIDmode. */ + if (CONSTANT_P (SUBREG_REG (x)) + && ((GET_MODE_SIZE (op0_mode) <= UNITS_PER_WORD + || ! WORDS_BIG_ENDIAN) + ? SUBREG_WORD (x) == 0 + : (SUBREG_WORD (x) + == ((GET_MODE_SIZE (op0_mode) + - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)) + / UNITS_PER_WORD))) + && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (op0_mode) + && (! WORDS_BIG_ENDIAN + || GET_MODE_BITSIZE (op0_mode) <= BITS_PER_WORD)) + return gen_lowpart_for_combine (mode, SUBREG_REG (x)); + + /* A paradoxical SUBREG of a VOIDmode constant is the same constant, + since we are saying that the high bits don't matter. */ + if (CONSTANT_P (SUBREG_REG (x)) && GET_MODE (SUBREG_REG (x)) == VOIDmode + && GET_MODE_SIZE (mode) > GET_MODE_SIZE (op0_mode)) + return SUBREG_REG (x); + + /* Note that we cannot do any narrowing for non-constants since + we might have been counting on using the fact that some bits were + zero. We now do this in the SET. */ + + break; + + case NOT: + /* (not (plus X -1)) can become (neg X). */ + if (GET_CODE (XEXP (x, 0)) == PLUS + && XEXP (XEXP (x, 0), 1) == constm1_rtx) + return gen_rtx_combine (NEG, mode, XEXP (XEXP (x, 0), 0)); + + /* Similarly, (not (neg X)) is (plus X -1). */ + if (GET_CODE (XEXP (x, 0)) == NEG) + return gen_rtx_combine (PLUS, mode, XEXP (XEXP (x, 0), 0), + constm1_rtx); + + /* (not (xor X C)) for C constant is (xor X D) with D = ~ C. */ + if (GET_CODE (XEXP (x, 0)) == XOR + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && (temp = simplify_unary_operation (NOT, mode, + XEXP (XEXP (x, 0), 1), + mode)) != 0) + return gen_binary (XOR, mode, XEXP (XEXP (x, 0), 0), temp); + + /* (not (ashift 1 X)) is (rotate ~1 X). We used to do this for operands + other than 1, but that is not valid. We could do a similar + simplification for (not (lshiftrt C X)) where C is just the sign bit, + but this doesn't seem common enough to bother with. */ + if (GET_CODE (XEXP (x, 0)) == ASHIFT + && XEXP (XEXP (x, 0), 0) == const1_rtx) + return gen_rtx_ROTATE (mode, gen_unary (NOT, mode, mode, const1_rtx), + XEXP (XEXP (x, 0), 1)); + + if (GET_CODE (XEXP (x, 0)) == SUBREG + && subreg_lowpart_p (XEXP (x, 0)) + && (GET_MODE_SIZE (GET_MODE (XEXP (x, 0))) + < GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (x, 0))))) + && GET_CODE (SUBREG_REG (XEXP (x, 0))) == ASHIFT + && XEXP (SUBREG_REG (XEXP (x, 0)), 0) == const1_rtx) + { + enum machine_mode inner_mode = GET_MODE (SUBREG_REG (XEXP (x, 0))); + + x = gen_rtx_ROTATE (inner_mode, + gen_unary (NOT, inner_mode, inner_mode, + const1_rtx), + XEXP (SUBREG_REG (XEXP (x, 0)), 1)); + return gen_lowpart_for_combine (mode, x); + } + + /* If STORE_FLAG_VALUE is -1, (not (comparison foo bar)) can be done by + reversing the comparison code if valid. */ + if (STORE_FLAG_VALUE == -1 + && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<' + && reversible_comparison_p (XEXP (x, 0))) + return gen_rtx_combine (reverse_condition (GET_CODE (XEXP (x, 0))), + mode, XEXP (XEXP (x, 0), 0), + XEXP (XEXP (x, 0), 1)); + + /* (ashiftrt foo C) where C is the number of bits in FOO minus 1 + is (lt foo (const_int 0)) if STORE_FLAG_VALUE is -1, so we can + perform the above simplification. */ + + if (STORE_FLAG_VALUE == -1 + && XEXP (x, 1) == const1_rtx + && GET_CODE (XEXP (x, 0)) == ASHIFTRT + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && INTVAL (XEXP (XEXP (x, 0), 1)) == GET_MODE_BITSIZE (mode) - 1) + return gen_rtx_combine (GE, mode, XEXP (XEXP (x, 0), 0), const0_rtx); + + /* Apply De Morgan's laws to reduce number of patterns for machines + with negating logical insns (and-not, nand, etc.). If result has + only one NOT, put it first, since that is how the patterns are + coded. */ + + if (GET_CODE (XEXP (x, 0)) == IOR || GET_CODE (XEXP (x, 0)) == AND) + { + rtx in1 = XEXP (XEXP (x, 0), 0), in2 = XEXP (XEXP (x, 0), 1); + + if (GET_CODE (in1) == NOT) + in1 = XEXP (in1, 0); + else + in1 = gen_rtx_combine (NOT, GET_MODE (in1), in1); + + if (GET_CODE (in2) == NOT) + in2 = XEXP (in2, 0); + else if (GET_CODE (in2) == CONST_INT + && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT) + in2 = GEN_INT (GET_MODE_MASK (mode) & ~ INTVAL (in2)); + else + in2 = gen_rtx_combine (NOT, GET_MODE (in2), in2); + + if (GET_CODE (in2) == NOT) + { + rtx tem = in2; + in2 = in1; in1 = tem; + } + + return gen_rtx_combine (GET_CODE (XEXP (x, 0)) == IOR ? AND : IOR, + mode, in1, in2); + } + break; + + case NEG: + /* (neg (plus X 1)) can become (not X). */ + if (GET_CODE (XEXP (x, 0)) == PLUS + && XEXP (XEXP (x, 0), 1) == const1_rtx) + return gen_rtx_combine (NOT, mode, XEXP (XEXP (x, 0), 0)); + + /* Similarly, (neg (not X)) is (plus X 1). */ + if (GET_CODE (XEXP (x, 0)) == NOT) + return plus_constant (XEXP (XEXP (x, 0), 0), 1); + + /* (neg (minus X Y)) can become (minus Y X). */ + if (GET_CODE (XEXP (x, 0)) == MINUS + && (! FLOAT_MODE_P (mode) + /* x-y != -(y-x) with IEEE floating point. */ + || TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT + || flag_fast_math)) + return gen_binary (MINUS, mode, XEXP (XEXP (x, 0), 1), + XEXP (XEXP (x, 0), 0)); + + /* (neg (xor A 1)) is (plus A -1) if A is known to be either 0 or 1. */ + if (GET_CODE (XEXP (x, 0)) == XOR && XEXP (XEXP (x, 0), 1) == const1_rtx + && nonzero_bits (XEXP (XEXP (x, 0), 0), mode) == 1) + return gen_binary (PLUS, mode, XEXP (XEXP (x, 0), 0), constm1_rtx); + + /* NEG commutes with ASHIFT since it is multiplication. Only do this + if we can then eliminate the NEG (e.g., + if the operand is a constant). */ + + if (GET_CODE (XEXP (x, 0)) == ASHIFT) + { + temp = simplify_unary_operation (NEG, mode, + XEXP (XEXP (x, 0), 0), mode); + if (temp) + { + SUBST (XEXP (XEXP (x, 0), 0), temp); + return XEXP (x, 0); + } + } + + temp = expand_compound_operation (XEXP (x, 0)); + + /* For C equal to the width of MODE minus 1, (neg (ashiftrt X C)) can be + replaced by (lshiftrt X C). This will convert + (neg (sign_extract X 1 Y)) to (zero_extract X 1 Y). */ + + if (GET_CODE (temp) == ASHIFTRT + && GET_CODE (XEXP (temp, 1)) == CONST_INT + && INTVAL (XEXP (temp, 1)) == GET_MODE_BITSIZE (mode) - 1) + return simplify_shift_const (temp, LSHIFTRT, mode, XEXP (temp, 0), + INTVAL (XEXP (temp, 1))); + + /* If X has only a single bit that might be nonzero, say, bit I, convert + (neg X) to (ashiftrt (ashift X C-I) C-I) where C is the bitsize of + MODE minus 1. This will convert (neg (zero_extract X 1 Y)) to + (sign_extract X 1 Y). But only do this if TEMP isn't a register + or a SUBREG of one since we'd be making the expression more + complex if it was just a register. */ + + if (GET_CODE (temp) != REG + && ! (GET_CODE (temp) == SUBREG + && GET_CODE (SUBREG_REG (temp)) == REG) + && (i = exact_log2 (nonzero_bits (temp, mode))) >= 0) + { + rtx temp1 = simplify_shift_const + (NULL_RTX, ASHIFTRT, mode, + simplify_shift_const (NULL_RTX, ASHIFT, mode, temp, + GET_MODE_BITSIZE (mode) - 1 - i), + GET_MODE_BITSIZE (mode) - 1 - i); + + /* If all we did was surround TEMP with the two shifts, we + haven't improved anything, so don't use it. Otherwise, + we are better off with TEMP1. */ + if (GET_CODE (temp1) != ASHIFTRT + || GET_CODE (XEXP (temp1, 0)) != ASHIFT + || XEXP (XEXP (temp1, 0), 0) != temp) + return temp1; + } + break; + + case TRUNCATE: + /* We can't handle truncation to a partial integer mode here + because we don't know the real bitsize of the partial + integer mode. */ + if (GET_MODE_CLASS (mode) == MODE_PARTIAL_INT) + break; + + if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT + && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode), + GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))))) + SUBST (XEXP (x, 0), + force_to_mode (XEXP (x, 0), GET_MODE (XEXP (x, 0)), + GET_MODE_MASK (mode), NULL_RTX, 0)); + + /* (truncate:SI ({sign,zero}_extend:DI foo:SI)) == foo:SI. */ + if ((GET_CODE (XEXP (x, 0)) == SIGN_EXTEND + || GET_CODE (XEXP (x, 0)) == ZERO_EXTEND) + && GET_MODE (XEXP (XEXP (x, 0), 0)) == mode) + return XEXP (XEXP (x, 0), 0); + + /* (truncate:SI (OP:DI ({sign,zero}_extend:DI foo:SI))) is + (OP:SI foo:SI) if OP is NEG or ABS. */ + if ((GET_CODE (XEXP (x, 0)) == ABS + || GET_CODE (XEXP (x, 0)) == NEG) + && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SIGN_EXTEND + || GET_CODE (XEXP (XEXP (x, 0), 0)) == ZERO_EXTEND) + && GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == mode) + return gen_unary (GET_CODE (XEXP (x, 0)), mode, mode, + XEXP (XEXP (XEXP (x, 0), 0), 0)); + + /* (truncate:SI (subreg:DI (truncate:SI X) 0)) is + (truncate:SI x). */ + if (GET_CODE (XEXP (x, 0)) == SUBREG + && GET_CODE (SUBREG_REG (XEXP (x, 0))) == TRUNCATE + && subreg_lowpart_p (XEXP (x, 0))) + return SUBREG_REG (XEXP (x, 0)); + + /* If we know that the value is already truncated, we can + replace the TRUNCATE with a SUBREG if TRULY_NOOP_TRUNCATION is + nonzero for the corresponding modes. */ + if (TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode), + GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))) + && num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0))) + >= GET_MODE_BITSIZE (mode) + 1) + return gen_lowpart_for_combine (mode, XEXP (x, 0)); + + /* A truncate of a comparison can be replaced with a subreg if + STORE_FLAG_VALUE permits. This is like the previous test, + but it works even if the comparison is done in a mode larger + than HOST_BITS_PER_WIDE_INT. */ + if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT + && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<' + && ((HOST_WIDE_INT) STORE_FLAG_VALUE &~ GET_MODE_MASK (mode)) == 0) + return gen_lowpart_for_combine (mode, XEXP (x, 0)); + + /* Similarly, a truncate of a register whose value is a + comparison can be replaced with a subreg if STORE_FLAG_VALUE + permits. */ + if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT + && ((HOST_WIDE_INT) STORE_FLAG_VALUE &~ GET_MODE_MASK (mode)) == 0 + && (temp = get_last_value (XEXP (x, 0))) + && GET_RTX_CLASS (GET_CODE (temp)) == '<') + return gen_lowpart_for_combine (mode, XEXP (x, 0)); + + break; + + case FLOAT_TRUNCATE: + /* (float_truncate:SF (float_extend:DF foo:SF)) = foo:SF. */ + if (GET_CODE (XEXP (x, 0)) == FLOAT_EXTEND + && GET_MODE (XEXP (XEXP (x, 0), 0)) == mode) + return XEXP (XEXP (x, 0), 0); + + /* (float_truncate:SF (OP:DF (float_extend:DF foo:sf))) is + (OP:SF foo:SF) if OP is NEG or ABS. */ + if ((GET_CODE (XEXP (x, 0)) == ABS + || GET_CODE (XEXP (x, 0)) == NEG) + && GET_CODE (XEXP (XEXP (x, 0), 0)) == FLOAT_EXTEND + && GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == mode) + return gen_unary (GET_CODE (XEXP (x, 0)), mode, mode, + XEXP (XEXP (XEXP (x, 0), 0), 0)); + + /* (float_truncate:SF (subreg:DF (float_truncate:SF X) 0)) + is (float_truncate:SF x). */ + if (GET_CODE (XEXP (x, 0)) == SUBREG + && subreg_lowpart_p (XEXP (x, 0)) + && GET_CODE (SUBREG_REG (XEXP (x, 0))) == FLOAT_TRUNCATE) + return SUBREG_REG (XEXP (x, 0)); + break; + +#ifdef HAVE_cc0 + case COMPARE: + /* Convert (compare FOO (const_int 0)) to FOO unless we aren't + using cc0, in which case we want to leave it as a COMPARE + so we can distinguish it from a register-register-copy. */ + if (XEXP (x, 1) == const0_rtx) + return XEXP (x, 0); + + /* In IEEE floating point, x-0 is not the same as x. */ + if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT + || ! FLOAT_MODE_P (GET_MODE (XEXP (x, 0))) + || flag_fast_math) + && XEXP (x, 1) == CONST0_RTX (GET_MODE (XEXP (x, 0)))) + return XEXP (x, 0); + break; +#endif + + case CONST: + /* (const (const X)) can become (const X). Do it this way rather than + returning the inner CONST since CONST can be shared with a + REG_EQUAL note. */ + if (GET_CODE (XEXP (x, 0)) == CONST) + SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0)); + break; + +#ifdef HAVE_lo_sum + case LO_SUM: + /* Convert (lo_sum (high FOO) FOO) to FOO. This is necessary so we + can add in an offset. find_split_point will split this address up + again if it doesn't match. */ + if (GET_CODE (XEXP (x, 0)) == HIGH + && rtx_equal_p (XEXP (XEXP (x, 0), 0), XEXP (x, 1))) + return XEXP (x, 1); + break; +#endif + + case PLUS: + /* If we have (plus (plus (A const) B)), associate it so that CONST is + outermost. That's because that's the way indexed addresses are + supposed to appear. This code used to check many more cases, but + they are now checked elsewhere. */ + if (GET_CODE (XEXP (x, 0)) == PLUS + && CONSTANT_ADDRESS_P (XEXP (XEXP (x, 0), 1))) + return gen_binary (PLUS, mode, + gen_binary (PLUS, mode, XEXP (XEXP (x, 0), 0), + XEXP (x, 1)), + XEXP (XEXP (x, 0), 1)); + + /* (plus (xor (and (const_int pow2 - 1)) ) <-c>) + when c is (const_int (pow2 + 1) / 2) is a sign extension of a + bit-field and can be replaced by either a sign_extend or a + sign_extract. The `and' may be a zero_extend. */ + if (GET_CODE (XEXP (x, 0)) == XOR + && GET_CODE (XEXP (x, 1)) == CONST_INT + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) == - INTVAL (XEXP (XEXP (x, 0), 1)) + && (i = exact_log2 (INTVAL (XEXP (XEXP (x, 0), 1)))) >= 0 + && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT + && ((GET_CODE (XEXP (XEXP (x, 0), 0)) == AND + && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == CONST_INT + && (INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1)) + == ((HOST_WIDE_INT) 1 << (i + 1)) - 1)) + || (GET_CODE (XEXP (XEXP (x, 0), 0)) == ZERO_EXTEND + && (GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0))) + == i + 1)))) + return simplify_shift_const + (NULL_RTX, ASHIFTRT, mode, + simplify_shift_const (NULL_RTX, ASHIFT, mode, + XEXP (XEXP (XEXP (x, 0), 0), 0), + GET_MODE_BITSIZE (mode) - (i + 1)), + GET_MODE_BITSIZE (mode) - (i + 1)); + + /* (plus (comparison A B) C) can become (neg (rev-comp A B)) if + C is 1 and STORE_FLAG_VALUE is -1 or if C is -1 and STORE_FLAG_VALUE + is 1. This produces better code than the alternative immediately + below. */ + if (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<' + && reversible_comparison_p (XEXP (x, 0)) + && ((STORE_FLAG_VALUE == -1 && XEXP (x, 1) == const1_rtx) + || (STORE_FLAG_VALUE == 1 && XEXP (x, 1) == constm1_rtx))) + return + gen_unary (NEG, mode, mode, + gen_binary (reverse_condition (GET_CODE (XEXP (x, 0))), + mode, XEXP (XEXP (x, 0), 0), + XEXP (XEXP (x, 0), 1))); + + /* If only the low-order bit of X is possibly nonzero, (plus x -1) + can become (ashiftrt (ashift (xor x 1) C) C) where C is + the bitsize of the mode - 1. This allows simplification of + "a = (b & 8) == 0;" */ + if (XEXP (x, 1) == constm1_rtx + && GET_CODE (XEXP (x, 0)) != REG + && ! (GET_CODE (XEXP (x,0)) == SUBREG + && GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG) + && nonzero_bits (XEXP (x, 0), mode) == 1) + return simplify_shift_const (NULL_RTX, ASHIFTRT, mode, + simplify_shift_const (NULL_RTX, ASHIFT, mode, + gen_rtx_combine (XOR, mode, + XEXP (x, 0), const1_rtx), + GET_MODE_BITSIZE (mode) - 1), + GET_MODE_BITSIZE (mode) - 1); + + /* If we are adding two things that have no bits in common, convert + the addition into an IOR. This will often be further simplified, + for example in cases like ((a & 1) + (a & 2)), which can + become a & 3. */ + + if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT + && (nonzero_bits (XEXP (x, 0), mode) + & nonzero_bits (XEXP (x, 1), mode)) == 0) + return gen_binary (IOR, mode, XEXP (x, 0), XEXP (x, 1)); + break; + + case MINUS: + /* If STORE_FLAG_VALUE is 1, (minus 1 (comparison foo bar)) can be done + by reversing the comparison code if valid. */ + if (STORE_FLAG_VALUE == 1 + && XEXP (x, 0) == const1_rtx + && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<' + && reversible_comparison_p (XEXP (x, 1))) + return gen_binary (reverse_condition (GET_CODE (XEXP (x, 1))), + mode, XEXP (XEXP (x, 1), 0), + XEXP (XEXP (x, 1), 1)); + + /* (minus (and (const_int -pow2))) becomes + (and (const_int pow2-1)) */ + if (GET_CODE (XEXP (x, 1)) == AND + && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT + && exact_log2 (- INTVAL (XEXP (XEXP (x, 1), 1))) >= 0 + && rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0))) + return simplify_and_const_int (NULL_RTX, mode, XEXP (x, 0), + - INTVAL (XEXP (XEXP (x, 1), 1)) - 1); + + /* Canonicalize (minus A (plus B C)) to (minus (minus A B) C) for + integers. */ + if (GET_CODE (XEXP (x, 1)) == PLUS && INTEGRAL_MODE_P (mode)) + return gen_binary (MINUS, mode, + gen_binary (MINUS, mode, XEXP (x, 0), + XEXP (XEXP (x, 1), 0)), + XEXP (XEXP (x, 1), 1)); + break; + + case MULT: + /* If we have (mult (plus A B) C), apply the distributive law and then + the inverse distributive law to see if things simplify. This + occurs mostly in addresses, often when unrolling loops. */ + + if (GET_CODE (XEXP (x, 0)) == PLUS) + { + x = apply_distributive_law + (gen_binary (PLUS, mode, + gen_binary (MULT, mode, + XEXP (XEXP (x, 0), 0), XEXP (x, 1)), + gen_binary (MULT, mode, + XEXP (XEXP (x, 0), 1), XEXP (x, 1)))); + + if (GET_CODE (x) != MULT) + return x; + } + break; + + case UDIV: + /* If this is a divide by a power of two, treat it as a shift if + its first operand is a shift. */ + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && (i = exact_log2 (INTVAL (XEXP (x, 1)))) >= 0 + && (GET_CODE (XEXP (x, 0)) == ASHIFT + || GET_CODE (XEXP (x, 0)) == LSHIFTRT + || GET_CODE (XEXP (x, 0)) == ASHIFTRT + || GET_CODE (XEXP (x, 0)) == ROTATE + || GET_CODE (XEXP (x, 0)) == ROTATERT)) + return simplify_shift_const (NULL_RTX, LSHIFTRT, mode, XEXP (x, 0), i); + break; + + case EQ: case NE: + case GT: case GTU: case GE: case GEU: + case LT: case LTU: case LE: case LEU: + /* If the first operand is a condition code, we can't do anything + with it. */ + if (GET_CODE (XEXP (x, 0)) == COMPARE + || (GET_MODE_CLASS (GET_MODE (XEXP (x, 0))) != MODE_CC +#ifdef HAVE_cc0 + && XEXP (x, 0) != cc0_rtx +#endif + )) + { + rtx op0 = XEXP (x, 0); + rtx op1 = XEXP (x, 1); + enum rtx_code new_code; + + if (GET_CODE (op0) == COMPARE) + op1 = XEXP (op0, 1), op0 = XEXP (op0, 0); + + /* Simplify our comparison, if possible. */ + new_code = simplify_comparison (code, &op0, &op1); + + /* If STORE_FLAG_VALUE is 1, we can convert (ne x 0) to simply X + if only the low-order bit is possibly nonzero in X (such as when + X is a ZERO_EXTRACT of one bit). Similarly, we can convert EQ to + (xor X 1) or (minus 1 X); we use the former. Finally, if X is + known to be either 0 or -1, NE becomes a NEG and EQ becomes + (plus X 1). + + Remove any ZERO_EXTRACT we made when thinking this was a + comparison. It may now be simpler to use, e.g., an AND. If a + ZERO_EXTRACT is indeed appropriate, it will be placed back by + the call to make_compound_operation in the SET case. */ + + if (STORE_FLAG_VALUE == 1 + && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT + && op1 == const0_rtx && nonzero_bits (op0, mode) == 1) + return gen_lowpart_for_combine (mode, + expand_compound_operation (op0)); + + else if (STORE_FLAG_VALUE == 1 + && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT + && op1 == const0_rtx + && (num_sign_bit_copies (op0, mode) + == GET_MODE_BITSIZE (mode))) + { + op0 = expand_compound_operation (op0); + return gen_unary (NEG, mode, mode, + gen_lowpart_for_combine (mode, op0)); + } + + else if (STORE_FLAG_VALUE == 1 + && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT + && op1 == const0_rtx + && nonzero_bits (op0, mode) == 1) + { + op0 = expand_compound_operation (op0); + return gen_binary (XOR, mode, + gen_lowpart_for_combine (mode, op0), + const1_rtx); + } + + else if (STORE_FLAG_VALUE == 1 + && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT + && op1 == const0_rtx + && (num_sign_bit_copies (op0, mode) + == GET_MODE_BITSIZE (mode))) + { + op0 = expand_compound_operation (op0); + return plus_constant (gen_lowpart_for_combine (mode, op0), 1); + } + + /* If STORE_FLAG_VALUE is -1, we have cases similar to + those above. */ + if (STORE_FLAG_VALUE == -1 + && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT + && op1 == const0_rtx + && (num_sign_bit_copies (op0, mode) + == GET_MODE_BITSIZE (mode))) + return gen_lowpart_for_combine (mode, + expand_compound_operation (op0)); + + else if (STORE_FLAG_VALUE == -1 + && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT + && op1 == const0_rtx + && nonzero_bits (op0, mode) == 1) + { + op0 = expand_compound_operation (op0); + return gen_unary (NEG, mode, mode, + gen_lowpart_for_combine (mode, op0)); + } + + else if (STORE_FLAG_VALUE == -1 + && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT + && op1 == const0_rtx + && (num_sign_bit_copies (op0, mode) + == GET_MODE_BITSIZE (mode))) + { + op0 = expand_compound_operation (op0); + return gen_unary (NOT, mode, mode, + gen_lowpart_for_combine (mode, op0)); + } + + /* If X is 0/1, (eq X 0) is X-1. */ + else if (STORE_FLAG_VALUE == -1 + && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT + && op1 == const0_rtx + && nonzero_bits (op0, mode) == 1) + { + op0 = expand_compound_operation (op0); + return plus_constant (gen_lowpart_for_combine (mode, op0), -1); + } + + /* If STORE_FLAG_VALUE says to just test the sign bit and X has just + one bit that might be nonzero, we can convert (ne x 0) to + (ashift x c) where C puts the bit in the sign bit. Remove any + AND with STORE_FLAG_VALUE when we are done, since we are only + going to test the sign bit. */ + if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT + && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT + && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode)) + == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE(mode)-1)) + && op1 == const0_rtx + && mode == GET_MODE (op0) + && (i = exact_log2 (nonzero_bits (op0, mode))) >= 0) + { + x = simplify_shift_const (NULL_RTX, ASHIFT, mode, + expand_compound_operation (op0), + GET_MODE_BITSIZE (mode) - 1 - i); + if (GET_CODE (x) == AND && XEXP (x, 1) == const_true_rtx) + return XEXP (x, 0); + else + return x; + } + + /* If the code changed, return a whole new comparison. */ + if (new_code != code) + return gen_rtx_combine (new_code, mode, op0, op1); + + /* Otherwise, keep this operation, but maybe change its operands. + This also converts (ne (compare FOO BAR) 0) to (ne FOO BAR). */ + SUBST (XEXP (x, 0), op0); + SUBST (XEXP (x, 1), op1); + } + break; + + case IF_THEN_ELSE: + return simplify_if_then_else (x); + + case ZERO_EXTRACT: + case SIGN_EXTRACT: + case ZERO_EXTEND: + case SIGN_EXTEND: + /* If we are processing SET_DEST, we are done. */ + if (in_dest) + return x; + + return expand_compound_operation (x); + + case SET: + return simplify_set (x); + + case AND: + case IOR: + case XOR: + return simplify_logical (x, last); + + case ABS: + /* (abs (neg )) -> (abs ) */ + if (GET_CODE (XEXP (x, 0)) == NEG) + SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0)); + + /* If the mode of the operand is VOIDmode (i.e. if it is ASM_OPERANDS), + do nothing. */ + if (GET_MODE (XEXP (x, 0)) == VOIDmode) + break; + + /* If operand is something known to be positive, ignore the ABS. */ + if (GET_CODE (XEXP (x, 0)) == FFS || GET_CODE (XEXP (x, 0)) == ABS + || ((GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) + <= HOST_BITS_PER_WIDE_INT) + && ((nonzero_bits (XEXP (x, 0), GET_MODE (XEXP (x, 0))) + & ((HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - 1))) + == 0))) + return XEXP (x, 0); + + + /* If operand is known to be only -1 or 0, convert ABS to NEG. */ + if (num_sign_bit_copies (XEXP (x, 0), mode) == GET_MODE_BITSIZE (mode)) + return gen_rtx_combine (NEG, mode, XEXP (x, 0)); + + break; + + case FFS: + /* (ffs (*_extend )) = (ffs ) */ + if (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND + || GET_CODE (XEXP (x, 0)) == ZERO_EXTEND) + SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0)); + break; + + case FLOAT: + /* (float (sign_extend )) = (float ). */ + if (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND) + SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0)); + break; + + case ASHIFT: + case LSHIFTRT: + case ASHIFTRT: + case ROTATE: + case ROTATERT: + /* If this is a shift by a constant amount, simplify it. */ + if (GET_CODE (XEXP (x, 1)) == CONST_INT) + return simplify_shift_const (x, code, mode, XEXP (x, 0), + INTVAL (XEXP (x, 1))); + +#ifdef SHIFT_COUNT_TRUNCATED + else if (SHIFT_COUNT_TRUNCATED && GET_CODE (XEXP (x, 1)) != REG) + SUBST (XEXP (x, 1), + force_to_mode (XEXP (x, 1), GET_MODE (x), + ((HOST_WIDE_INT) 1 + << exact_log2 (GET_MODE_BITSIZE (GET_MODE (x)))) + - 1, + NULL_RTX, 0)); +#endif + + break; + + default: + break; + } + + return x; +} + +/* Simplify X, an IF_THEN_ELSE expression. Return the new expression. */ + +static rtx +simplify_if_then_else (x) + rtx x; +{ + enum machine_mode mode = GET_MODE (x); + rtx cond = XEXP (x, 0); + rtx true = XEXP (x, 1); + rtx false = XEXP (x, 2); + enum rtx_code true_code = GET_CODE (cond); + int comparison_p = GET_RTX_CLASS (true_code) == '<'; + rtx temp; + int i; + + /* Simplify storing of the truth value. */ + if (comparison_p && true == const_true_rtx && false == const0_rtx) + return gen_binary (true_code, mode, XEXP (cond, 0), XEXP (cond, 1)); + + /* Also when the truth value has to be reversed. */ + if (comparison_p && reversible_comparison_p (cond) + && true == const0_rtx && false == const_true_rtx) + return gen_binary (reverse_condition (true_code), + mode, XEXP (cond, 0), XEXP (cond, 1)); + + /* Sometimes we can simplify the arm of an IF_THEN_ELSE if a register used + in it is being compared against certain values. Get the true and false + comparisons and see if that says anything about the value of each arm. */ + + if (comparison_p && reversible_comparison_p (cond) + && GET_CODE (XEXP (cond, 0)) == REG) + { + HOST_WIDE_INT nzb; + rtx from = XEXP (cond, 0); + enum rtx_code false_code = reverse_condition (true_code); + rtx true_val = XEXP (cond, 1); + rtx false_val = true_val; + int swapped = 0; + + /* If FALSE_CODE is EQ, swap the codes and arms. */ + + if (false_code == EQ) + { + swapped = 1, true_code = EQ, false_code = NE; + temp = true, true = false, false = temp; + } + + /* If we are comparing against zero and the expression being tested has + only a single bit that might be nonzero, that is its value when it is + not equal to zero. Similarly if it is known to be -1 or 0. */ + + if (true_code == EQ && true_val == const0_rtx + && exact_log2 (nzb = nonzero_bits (from, GET_MODE (from))) >= 0) + false_code = EQ, false_val = GEN_INT (nzb); + else if (true_code == EQ && true_val == const0_rtx + && (num_sign_bit_copies (from, GET_MODE (from)) + == GET_MODE_BITSIZE (GET_MODE (from)))) + false_code = EQ, false_val = constm1_rtx; + + /* Now simplify an arm if we know the value of the register in the + branch and it is used in the arm. Be careful due to the potential + of locally-shared RTL. */ + + if (reg_mentioned_p (from, true)) + true = subst (known_cond (copy_rtx (true), true_code, from, true_val), + pc_rtx, pc_rtx, 0, 0); + if (reg_mentioned_p (from, false)) + false = subst (known_cond (copy_rtx (false), false_code, + from, false_val), + pc_rtx, pc_rtx, 0, 0); + + SUBST (XEXP (x, 1), swapped ? false : true); + SUBST (XEXP (x, 2), swapped ? true : false); + + true = XEXP (x, 1), false = XEXP (x, 2), true_code = GET_CODE (cond); + } + + /* If we have (if_then_else FOO (pc) (label_ref BAR)) and FOO can be + reversed, do so to avoid needing two sets of patterns for + subtract-and-branch insns. Similarly if we have a constant in the true + arm, the false arm is the same as the first operand of the comparison, or + the false arm is more complicated than the true arm. */ + + if (comparison_p && reversible_comparison_p (cond) + && (true == pc_rtx + || (CONSTANT_P (true) + && GET_CODE (false) != CONST_INT && false != pc_rtx) + || true == const0_rtx + || (GET_RTX_CLASS (GET_CODE (true)) == 'o' + && GET_RTX_CLASS (GET_CODE (false)) != 'o') + || (GET_CODE (true) == SUBREG + && GET_RTX_CLASS (GET_CODE (SUBREG_REG (true))) == 'o' + && GET_RTX_CLASS (GET_CODE (false)) != 'o') + || reg_mentioned_p (true, false) + || rtx_equal_p (false, XEXP (cond, 0)))) + { + true_code = reverse_condition (true_code); + SUBST (XEXP (x, 0), + gen_binary (true_code, GET_MODE (cond), XEXP (cond, 0), + XEXP (cond, 1))); + + SUBST (XEXP (x, 1), false); + SUBST (XEXP (x, 2), true); + + temp = true, true = false, false = temp, cond = XEXP (x, 0); + + /* It is possible that the conditional has been simplified out. */ + true_code = GET_CODE (cond); + comparison_p = GET_RTX_CLASS (true_code) == '<'; + } + + /* If the two arms are identical, we don't need the comparison. */ + + if (rtx_equal_p (true, false) && ! side_effects_p (cond)) + return true; + + /* Convert a == b ? b : a to "a". */ + if (true_code == EQ && ! side_effects_p (cond) + && rtx_equal_p (XEXP (cond, 0), false) + && rtx_equal_p (XEXP (cond, 1), true)) + return false; + else if (true_code == NE && ! side_effects_p (cond) + && rtx_equal_p (XEXP (cond, 0), true) + && rtx_equal_p (XEXP (cond, 1), false)) + return true; + + /* Look for cases where we have (abs x) or (neg (abs X)). */ + + if (GET_MODE_CLASS (mode) == MODE_INT + && GET_CODE (false) == NEG + && rtx_equal_p (true, XEXP (false, 0)) + && comparison_p + && rtx_equal_p (true, XEXP (cond, 0)) + && ! side_effects_p (true)) + switch (true_code) + { + case GT: + case GE: + return gen_unary (ABS, mode, mode, true); + case LT: + case LE: + return gen_unary (NEG, mode, mode, gen_unary (ABS, mode, mode, true)); + default: + break; + } + + /* Look for MIN or MAX. */ + + if ((! FLOAT_MODE_P (mode) || flag_fast_math) + && comparison_p + && rtx_equal_p (XEXP (cond, 0), true) + && rtx_equal_p (XEXP (cond, 1), false) + && ! side_effects_p (cond)) + switch (true_code) + { + case GE: + case GT: + return gen_binary (SMAX, mode, true, false); + case LE: + case LT: + return gen_binary (SMIN, mode, true, false); + case GEU: + case GTU: + return gen_binary (UMAX, mode, true, false); + case LEU: + case LTU: + return gen_binary (UMIN, mode, true, false); + default: + break; + } + + /* If we have (if_then_else COND (OP Z C1) Z) and OP is an identity when its + second operand is zero, this can be done as (OP Z (mult COND C2)) where + C2 = C1 * STORE_FLAG_VALUE. Similarly if OP has an outer ZERO_EXTEND or + SIGN_EXTEND as long as Z is already extended (so we don't destroy it). + We can do this kind of thing in some cases when STORE_FLAG_VALUE is + neither 1 or -1, but it isn't worth checking for. */ + + if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1) + && comparison_p && mode != VOIDmode && ! side_effects_p (x)) + { + rtx t = make_compound_operation (true, SET); + rtx f = make_compound_operation (false, SET); + rtx cond_op0 = XEXP (cond, 0); + rtx cond_op1 = XEXP (cond, 1); + enum rtx_code op, extend_op = NIL; + enum machine_mode m = mode; + rtx z = 0, c1; + + if ((GET_CODE (t) == PLUS || GET_CODE (t) == MINUS + || GET_CODE (t) == IOR || GET_CODE (t) == XOR + || GET_CODE (t) == ASHIFT + || GET_CODE (t) == LSHIFTRT || GET_CODE (t) == ASHIFTRT) + && rtx_equal_p (XEXP (t, 0), f)) + c1 = XEXP (t, 1), op = GET_CODE (t), z = f; + + /* If an identity-zero op is commutative, check whether there + would be a match if we swapped the operands. */ + else if ((GET_CODE (t) == PLUS || GET_CODE (t) == IOR + || GET_CODE (t) == XOR) + && rtx_equal_p (XEXP (t, 1), f)) + c1 = XEXP (t, 0), op = GET_CODE (t), z = f; + else if (GET_CODE (t) == SIGN_EXTEND + && (GET_CODE (XEXP (t, 0)) == PLUS + || GET_CODE (XEXP (t, 0)) == MINUS + || GET_CODE (XEXP (t, 0)) == IOR + || GET_CODE (XEXP (t, 0)) == XOR + || GET_CODE (XEXP (t, 0)) == ASHIFT + || GET_CODE (XEXP (t, 0)) == LSHIFTRT + || GET_CODE (XEXP (t, 0)) == ASHIFTRT) + && GET_CODE (XEXP (XEXP (t, 0), 0)) == SUBREG + && subreg_lowpart_p (XEXP (XEXP (t, 0), 0)) + && rtx_equal_p (SUBREG_REG (XEXP (XEXP (t, 0), 0)), f) + && (num_sign_bit_copies (f, GET_MODE (f)) + > (GET_MODE_BITSIZE (mode) + - GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (t, 0), 0)))))) + { + c1 = XEXP (XEXP (t, 0), 1); z = f; op = GET_CODE (XEXP (t, 0)); + extend_op = SIGN_EXTEND; + m = GET_MODE (XEXP (t, 0)); + } + else if (GET_CODE (t) == SIGN_EXTEND + && (GET_CODE (XEXP (t, 0)) == PLUS + || GET_CODE (XEXP (t, 0)) == IOR + || GET_CODE (XEXP (t, 0)) == XOR) + && GET_CODE (XEXP (XEXP (t, 0), 1)) == SUBREG + && subreg_lowpart_p (XEXP (XEXP (t, 0), 1)) + && rtx_equal_p (SUBREG_REG (XEXP (XEXP (t, 0), 1)), f) + && (num_sign_bit_copies (f, GET_MODE (f)) + > (GET_MODE_BITSIZE (mode) + - GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (t, 0), 1)))))) + { + c1 = XEXP (XEXP (t, 0), 0); z = f; op = GET_CODE (XEXP (t, 0)); + extend_op = SIGN_EXTEND; + m = GET_MODE (XEXP (t, 0)); + } + else if (GET_CODE (t) == ZERO_EXTEND + && (GET_CODE (XEXP (t, 0)) == PLUS + || GET_CODE (XEXP (t, 0)) == MINUS + || GET_CODE (XEXP (t, 0)) == IOR + || GET_CODE (XEXP (t, 0)) == XOR + || GET_CODE (XEXP (t, 0)) == ASHIFT + || GET_CODE (XEXP (t, 0)) == LSHIFTRT + || GET_CODE (XEXP (t, 0)) == ASHIFTRT) + && GET_CODE (XEXP (XEXP (t, 0), 0)) == SUBREG + && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT + && subreg_lowpart_p (XEXP (XEXP (t, 0), 0)) + && rtx_equal_p (SUBREG_REG (XEXP (XEXP (t, 0), 0)), f) + && ((nonzero_bits (f, GET_MODE (f)) + & ~ GET_MODE_MASK (GET_MODE (XEXP (XEXP (t, 0), 0)))) + == 0)) + { + c1 = XEXP (XEXP (t, 0), 1); z = f; op = GET_CODE (XEXP (t, 0)); + extend_op = ZERO_EXTEND; + m = GET_MODE (XEXP (t, 0)); + } + else if (GET_CODE (t) == ZERO_EXTEND + && (GET_CODE (XEXP (t, 0)) == PLUS + || GET_CODE (XEXP (t, 0)) == IOR + || GET_CODE (XEXP (t, 0)) == XOR) + && GET_CODE (XEXP (XEXP (t, 0), 1)) == SUBREG + && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT + && subreg_lowpart_p (XEXP (XEXP (t, 0), 1)) + && rtx_equal_p (SUBREG_REG (XEXP (XEXP (t, 0), 1)), f) + && ((nonzero_bits (f, GET_MODE (f)) + & ~ GET_MODE_MASK (GET_MODE (XEXP (XEXP (t, 0), 1)))) + == 0)) + { + c1 = XEXP (XEXP (t, 0), 0); z = f; op = GET_CODE (XEXP (t, 0)); + extend_op = ZERO_EXTEND; + m = GET_MODE (XEXP (t, 0)); + } + + if (z) + { + temp = subst (gen_binary (true_code, m, cond_op0, cond_op1), + pc_rtx, pc_rtx, 0, 0); + temp = gen_binary (MULT, m, temp, + gen_binary (MULT, m, c1, const_true_rtx)); + temp = subst (temp, pc_rtx, pc_rtx, 0, 0); + temp = gen_binary (op, m, gen_lowpart_for_combine (m, z), temp); + + if (extend_op != NIL) + temp = gen_unary (extend_op, mode, m, temp); + + return temp; + } + } + + /* If we have (if_then_else (ne A 0) C1 0) and either A is known to be 0 or + 1 and C1 is a single bit or A is known to be 0 or -1 and C1 is the + negation of a single bit, we can convert this operation to a shift. We + can actually do this more generally, but it doesn't seem worth it. */ + + if (true_code == NE && XEXP (cond, 1) == const0_rtx + && false == const0_rtx && GET_CODE (true) == CONST_INT + && ((1 == nonzero_bits (XEXP (cond, 0), mode) + && (i = exact_log2 (INTVAL (true))) >= 0) + || ((num_sign_bit_copies (XEXP (cond, 0), mode) + == GET_MODE_BITSIZE (mode)) + && (i = exact_log2 (- INTVAL (true))) >= 0))) + return + simplify_shift_const (NULL_RTX, ASHIFT, mode, + gen_lowpart_for_combine (mode, XEXP (cond, 0)), i); + + return x; +} + +/* Simplify X, a SET expression. Return the new expression. */ + +static rtx +simplify_set (x) + rtx x; +{ + rtx src = SET_SRC (x); + rtx dest = SET_DEST (x); + enum machine_mode mode + = GET_MODE (src) != VOIDmode ? GET_MODE (src) : GET_MODE (dest); + rtx other_insn; + rtx *cc_use; + + /* (set (pc) (return)) gets written as (return). */ + if (GET_CODE (dest) == PC && GET_CODE (src) == RETURN) + return src; + + /* Now that we know for sure which bits of SRC we are using, see if we can + simplify the expression for the object knowing that we only need the + low-order bits. */ + + if (GET_MODE_CLASS (mode) == MODE_INT) + src = force_to_mode (src, mode, GET_MODE_MASK (mode), NULL_RTX, 0); + + /* If we are setting CC0 or if the source is a COMPARE, look for the use of + the comparison result and try to simplify it unless we already have used + undobuf.other_insn. */ + if ((GET_CODE (src) == COMPARE +#ifdef HAVE_cc0 + || dest == cc0_rtx +#endif + ) + && (cc_use = find_single_use (dest, subst_insn, &other_insn)) != 0 + && (undobuf.other_insn == 0 || other_insn == undobuf.other_insn) + && GET_RTX_CLASS (GET_CODE (*cc_use)) == '<' + && rtx_equal_p (XEXP (*cc_use, 0), dest)) + { + enum rtx_code old_code = GET_CODE (*cc_use); + enum rtx_code new_code; + rtx op0, op1; + int other_changed = 0; + enum machine_mode compare_mode = GET_MODE (dest); + + if (GET_CODE (src) == COMPARE) + op0 = XEXP (src, 0), op1 = XEXP (src, 1); + else + op0 = src, op1 = const0_rtx; + + /* Simplify our comparison, if possible. */ + new_code = simplify_comparison (old_code, &op0, &op1); + +#ifdef EXTRA_CC_MODES + /* If this machine has CC modes other than CCmode, check to see if we + need to use a different CC mode here. */ + compare_mode = SELECT_CC_MODE (new_code, op0, op1); +#endif /* EXTRA_CC_MODES */ + +#if !defined (HAVE_cc0) && defined (EXTRA_CC_MODES) + /* If the mode changed, we have to change SET_DEST, the mode in the + compare, and the mode in the place SET_DEST is used. If SET_DEST is + a hard register, just build new versions with the proper mode. If it + is a pseudo, we lose unless it is only time we set the pseudo, in + which case we can safely change its mode. */ + if (compare_mode != GET_MODE (dest)) + { + int regno = REGNO (dest); + rtx new_dest = gen_rtx_REG (compare_mode, regno); + + if (regno < FIRST_PSEUDO_REGISTER + || (REG_N_SETS (regno) == 1 && ! REG_USERVAR_P (dest))) + { + if (regno >= FIRST_PSEUDO_REGISTER) + SUBST (regno_reg_rtx[regno], new_dest); + + SUBST (SET_DEST (x), new_dest); + SUBST (XEXP (*cc_use, 0), new_dest); + other_changed = 1; + + dest = new_dest; + } + } +#endif + + /* If the code changed, we have to build a new comparison in + undobuf.other_insn. */ + if (new_code != old_code) + { + unsigned HOST_WIDE_INT mask; + + SUBST (*cc_use, gen_rtx_combine (new_code, GET_MODE (*cc_use), + dest, const0_rtx)); + + /* If the only change we made was to change an EQ into an NE or + vice versa, OP0 has only one bit that might be nonzero, and OP1 + is zero, check if changing the user of the condition code will + produce a valid insn. If it won't, we can keep the original code + in that insn by surrounding our operation with an XOR. */ + + if (((old_code == NE && new_code == EQ) + || (old_code == EQ && new_code == NE)) + && ! other_changed && op1 == const0_rtx + && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT + && exact_log2 (mask = nonzero_bits (op0, GET_MODE (op0))) >= 0) + { + rtx pat = PATTERN (other_insn), note = 0; + + if ((recog_for_combine (&pat, other_insn, ¬e) < 0 + && ! check_asm_operands (pat))) + { + PUT_CODE (*cc_use, old_code); + other_insn = 0; + + op0 = gen_binary (XOR, GET_MODE (op0), op0, GEN_INT (mask)); + } + } + + other_changed = 1; + } + + if (other_changed) + undobuf.other_insn = other_insn; + +#ifdef HAVE_cc0 + /* If we are now comparing against zero, change our source if + needed. If we do not use cc0, we always have a COMPARE. */ + if (op1 == const0_rtx && dest == cc0_rtx) + { + SUBST (SET_SRC (x), op0); + src = op0; + } + else +#endif + + /* Otherwise, if we didn't previously have a COMPARE in the + correct mode, we need one. */ + if (GET_CODE (src) != COMPARE || GET_MODE (src) != compare_mode) + { + SUBST (SET_SRC (x), + gen_rtx_combine (COMPARE, compare_mode, op0, op1)); + src = SET_SRC (x); + } + else + { + /* Otherwise, update the COMPARE if needed. */ + SUBST (XEXP (src, 0), op0); + SUBST (XEXP (src, 1), op1); + } + } + else + { + /* Get SET_SRC in a form where we have placed back any + compound expressions. Then do the checks below. */ + src = make_compound_operation (src, SET); + SUBST (SET_SRC (x), src); + } + + /* If we have (set x (subreg:m1 (op:m2 ...) 0)) with OP being some operation, + and X being a REG or (subreg (reg)), we may be able to convert this to + (set (subreg:m2 x) (op)). + + We can always do this if M1 is narrower than M2 because that means that + we only care about the low bits of the result. + + However, on machines without WORD_REGISTER_OPERATIONS defined, we cannot + perform a narrower operation than requested since the high-order bits will + be undefined. On machine where it is defined, this transformation is safe + as long as M1 and M2 have the same number of words. */ + + if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src) + && GET_RTX_CLASS (GET_CODE (SUBREG_REG (src))) != 'o' + && (((GET_MODE_SIZE (GET_MODE (src)) + (UNITS_PER_WORD - 1)) + / UNITS_PER_WORD) + == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))) + + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)) +#ifndef WORD_REGISTER_OPERATIONS + && (GET_MODE_SIZE (GET_MODE (src)) + < GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))) +#endif +#ifdef CLASS_CANNOT_CHANGE_SIZE + && ! (GET_CODE (dest) == REG && REGNO (dest) < FIRST_PSEUDO_REGISTER + && (TEST_HARD_REG_BIT + (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE], + REGNO (dest))) + && (GET_MODE_SIZE (GET_MODE (src)) + != GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))) +#endif + && (GET_CODE (dest) == REG + || (GET_CODE (dest) == SUBREG + && GET_CODE (SUBREG_REG (dest)) == REG))) + { + SUBST (SET_DEST (x), + gen_lowpart_for_combine (GET_MODE (SUBREG_REG (src)), + dest)); + SUBST (SET_SRC (x), SUBREG_REG (src)); + + src = SET_SRC (x), dest = SET_DEST (x); + } + +#ifdef LOAD_EXTEND_OP + /* If we have (set FOO (subreg:M (mem:N BAR) 0)) with M wider than N, this + would require a paradoxical subreg. Replace the subreg with a + zero_extend to avoid the reload that would otherwise be required. */ + + if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src) + && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))) != NIL + && SUBREG_WORD (src) == 0 + && (GET_MODE_SIZE (GET_MODE (src)) + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))) + && GET_CODE (SUBREG_REG (src)) == MEM) + { + SUBST (SET_SRC (x), + gen_rtx_combine (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))), + GET_MODE (src), XEXP (src, 0))); + + src = SET_SRC (x); + } +#endif + + /* If we don't have a conditional move, SET_SRC is an IF_THEN_ELSE, and we + are comparing an item known to be 0 or -1 against 0, use a logical + operation instead. Check for one of the arms being an IOR of the other + arm with some value. We compute three terms to be IOR'ed together. In + practice, at most two will be nonzero. Then we do the IOR's. */ + + if (GET_CODE (dest) != PC + && GET_CODE (src) == IF_THEN_ELSE + && GET_MODE_CLASS (GET_MODE (src)) == MODE_INT + && (GET_CODE (XEXP (src, 0)) == EQ || GET_CODE (XEXP (src, 0)) == NE) + && XEXP (XEXP (src, 0), 1) == const0_rtx + && GET_MODE (src) == GET_MODE (XEXP (XEXP (src, 0), 0)) +#ifdef HAVE_conditional_move + && ! can_conditionally_move_p (GET_MODE (src)) +#endif + && (num_sign_bit_copies (XEXP (XEXP (src, 0), 0), + GET_MODE (XEXP (XEXP (src, 0), 0))) + == GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (src, 0), 0)))) + && ! side_effects_p (src)) + { + rtx true = (GET_CODE (XEXP (src, 0)) == NE + ? XEXP (src, 1) : XEXP (src, 2)); + rtx false = (GET_CODE (XEXP (src, 0)) == NE + ? XEXP (src, 2) : XEXP (src, 1)); + rtx term1 = const0_rtx, term2, term3; + + if (GET_CODE (true) == IOR && rtx_equal_p (XEXP (true, 0), false)) + term1 = false, true = XEXP (true, 1), false = const0_rtx; + else if (GET_CODE (true) == IOR + && rtx_equal_p (XEXP (true, 1), false)) + term1 = false, true = XEXP (true, 0), false = const0_rtx; + else if (GET_CODE (false) == IOR + && rtx_equal_p (XEXP (false, 0), true)) + term1 = true, false = XEXP (false, 1), true = const0_rtx; + else if (GET_CODE (false) == IOR + && rtx_equal_p (XEXP (false, 1), true)) + term1 = true, false = XEXP (false, 0), true = const0_rtx; + + term2 = gen_binary (AND, GET_MODE (src), XEXP (XEXP (src, 0), 0), true); + term3 = gen_binary (AND, GET_MODE (src), + gen_unary (NOT, GET_MODE (src), GET_MODE (src), + XEXP (XEXP (src, 0), 0)), + false); + + SUBST (SET_SRC (x), + gen_binary (IOR, GET_MODE (src), + gen_binary (IOR, GET_MODE (src), term1, term2), + term3)); + + src = SET_SRC (x); + } + + /* If either SRC or DEST is a CLOBBER of (const_int 0), make this + whole thing fail. */ + if (GET_CODE (src) == CLOBBER && XEXP (src, 0) == const0_rtx) + return src; + else if (GET_CODE (dest) == CLOBBER && XEXP (dest, 0) == const0_rtx) + return dest; + else + /* Convert this into a field assignment operation, if possible. */ + return make_field_assignment (x); +} + +/* Simplify, X, and AND, IOR, or XOR operation, and return the simplified + result. LAST is nonzero if this is the last retry. */ + +static rtx +simplify_logical (x, last) + rtx x; + int last; +{ + enum machine_mode mode = GET_MODE (x); + rtx op0 = XEXP (x, 0); + rtx op1 = XEXP (x, 1); + + switch (GET_CODE (x)) + { + case AND: + /* Convert (A ^ B) & A to A & (~ B) since the latter is often a single + insn (and may simplify more). */ + if (GET_CODE (op0) == XOR + && rtx_equal_p (XEXP (op0, 0), op1) + && ! side_effects_p (op1)) + x = gen_binary (AND, mode, + gen_unary (NOT, mode, mode, XEXP (op0, 1)), op1); + + if (GET_CODE (op0) == XOR + && rtx_equal_p (XEXP (op0, 1), op1) + && ! side_effects_p (op1)) + x = gen_binary (AND, mode, + gen_unary (NOT, mode, mode, XEXP (op0, 0)), op1); + + /* Similarly for (~ (A ^ B)) & A. */ + if (GET_CODE (op0) == NOT + && GET_CODE (XEXP (op0, 0)) == XOR + && rtx_equal_p (XEXP (XEXP (op0, 0), 0), op1) + && ! side_effects_p (op1)) + x = gen_binary (AND, mode, XEXP (XEXP (op0, 0), 1), op1); + + if (GET_CODE (op0) == NOT + && GET_CODE (XEXP (op0, 0)) == XOR + && rtx_equal_p (XEXP (XEXP (op0, 0), 1), op1) + && ! side_effects_p (op1)) + x = gen_binary (AND, mode, XEXP (XEXP (op0, 0), 0), op1); + + if (GET_CODE (op1) == CONST_INT) + { + x = simplify_and_const_int (x, mode, op0, INTVAL (op1)); + + /* If we have (ior (and (X C1) C2)) and the next restart would be + the last, simplify this by making C1 as small as possible + and then exit. */ + if (last + && GET_CODE (x) == IOR && GET_CODE (op0) == AND + && GET_CODE (XEXP (op0, 1)) == CONST_INT + && GET_CODE (op1) == CONST_INT) + return gen_binary (IOR, mode, + gen_binary (AND, mode, XEXP (op0, 0), + GEN_INT (INTVAL (XEXP (op0, 1)) + & ~ INTVAL (op1))), op1); + + if (GET_CODE (x) != AND) + return x; + + if (GET_RTX_CLASS (GET_CODE (x)) == 'c' + || GET_RTX_CLASS (GET_CODE (x)) == '2') + op0 = XEXP (x, 0), op1 = XEXP (x, 1); + } + + /* Convert (A | B) & A to A. */ + if (GET_CODE (op0) == IOR + && (rtx_equal_p (XEXP (op0, 0), op1) + || rtx_equal_p (XEXP (op0, 1), op1)) + && ! side_effects_p (XEXP (op0, 0)) + && ! side_effects_p (XEXP (op0, 1))) + return op1; + + /* In the following group of tests (and those in case IOR below), + we start with some combination of logical operations and apply + the distributive law followed by the inverse distributive law. + Most of the time, this results in no change. However, if some of + the operands are the same or inverses of each other, simplifications + will result. + + For example, (and (ior A B) (not B)) can occur as the result of + expanding a bit field assignment. When we apply the distributive + law to this, we get (ior (and (A (not B))) (and (B (not B)))), + which then simplifies to (and (A (not B))). + + If we have (and (ior A B) C), apply the distributive law and then + the inverse distributive law to see if things simplify. */ + + if (GET_CODE (op0) == IOR || GET_CODE (op0) == XOR) + { + x = apply_distributive_law + (gen_binary (GET_CODE (op0), mode, + gen_binary (AND, mode, XEXP (op0, 0), op1), + gen_binary (AND, mode, XEXP (op0, 1), op1))); + if (GET_CODE (x) != AND) + return x; + } + + if (GET_CODE (op1) == IOR || GET_CODE (op1) == XOR) + return apply_distributive_law + (gen_binary (GET_CODE (op1), mode, + gen_binary (AND, mode, XEXP (op1, 0), op0), + gen_binary (AND, mode, XEXP (op1, 1), op0))); + + /* Similarly, taking advantage of the fact that + (and (not A) (xor B C)) == (xor (ior A B) (ior A C)) */ + + if (GET_CODE (op0) == NOT && GET_CODE (op1) == XOR) + return apply_distributive_law + (gen_binary (XOR, mode, + gen_binary (IOR, mode, XEXP (op0, 0), XEXP (op1, 0)), + gen_binary (IOR, mode, XEXP (op0, 0), XEXP (op1, 1)))); + + else if (GET_CODE (op1) == NOT && GET_CODE (op0) == XOR) + return apply_distributive_law + (gen_binary (XOR, mode, + gen_binary (IOR, mode, XEXP (op1, 0), XEXP (op0, 0)), + gen_binary (IOR, mode, XEXP (op1, 0), XEXP (op0, 1)))); + break; + + case IOR: + /* (ior A C) is C if all bits of A that might be nonzero are on in C. */ + if (GET_CODE (op1) == CONST_INT + && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT + && (nonzero_bits (op0, mode) & ~ INTVAL (op1)) == 0) + return op1; + + /* Convert (A & B) | A to A. */ + if (GET_CODE (op0) == AND + && (rtx_equal_p (XEXP (op0, 0), op1) + || rtx_equal_p (XEXP (op0, 1), op1)) + && ! side_effects_p (XEXP (op0, 0)) + && ! side_effects_p (XEXP (op0, 1))) + return op1; + + /* If we have (ior (and A B) C), apply the distributive law and then + the inverse distributive law to see if things simplify. */ + + if (GET_CODE (op0) == AND) + { + x = apply_distributive_law + (gen_binary (AND, mode, + gen_binary (IOR, mode, XEXP (op0, 0), op1), + gen_binary (IOR, mode, XEXP (op0, 1), op1))); + + if (GET_CODE (x) != IOR) + return x; + } + + if (GET_CODE (op1) == AND) + { + x = apply_distributive_law + (gen_binary (AND, mode, + gen_binary (IOR, mode, XEXP (op1, 0), op0), + gen_binary (IOR, mode, XEXP (op1, 1), op0))); + + if (GET_CODE (x) != IOR) + return x; + } + + /* Convert (ior (ashift A CX) (lshiftrt A CY)) where CX+CY equals the + mode size to (rotate A CX). */ + + if (((GET_CODE (op0) == ASHIFT && GET_CODE (op1) == LSHIFTRT) + || (GET_CODE (op1) == ASHIFT && GET_CODE (op0) == LSHIFTRT)) + && rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0)) + && GET_CODE (XEXP (op0, 1)) == CONST_INT + && GET_CODE (XEXP (op1, 1)) == CONST_INT + && (INTVAL (XEXP (op0, 1)) + INTVAL (XEXP (op1, 1)) + == GET_MODE_BITSIZE (mode))) + return gen_rtx_ROTATE (mode, XEXP (op0, 0), + (GET_CODE (op0) == ASHIFT + ? XEXP (op0, 1) : XEXP (op1, 1))); + + /* If OP0 is (ashiftrt (plus ...) C), it might actually be + a (sign_extend (plus ...)). If so, OP1 is a CONST_INT, and the PLUS + does not affect any of the bits in OP1, it can really be done + as a PLUS and we can associate. We do this by seeing if OP1 + can be safely shifted left C bits. */ + if (GET_CODE (op1) == CONST_INT && GET_CODE (op0) == ASHIFTRT + && GET_CODE (XEXP (op0, 0)) == PLUS + && GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT + && GET_CODE (XEXP (op0, 1)) == CONST_INT + && INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT) + { + int count = INTVAL (XEXP (op0, 1)); + HOST_WIDE_INT mask = INTVAL (op1) << count; + + if (mask >> count == INTVAL (op1) + && (mask & nonzero_bits (XEXP (op0, 0), mode)) == 0) + { + SUBST (XEXP (XEXP (op0, 0), 1), + GEN_INT (INTVAL (XEXP (XEXP (op0, 0), 1)) | mask)); + return op0; + } + } + break; + + case XOR: + /* Convert (XOR (NOT x) (NOT y)) to (XOR x y). + Also convert (XOR (NOT x) y) to (NOT (XOR x y)), similarly for + (NOT y). */ + { + int num_negated = 0; + + if (GET_CODE (op0) == NOT) + num_negated++, op0 = XEXP (op0, 0); + if (GET_CODE (op1) == NOT) + num_negated++, op1 = XEXP (op1, 0); + + if (num_negated == 2) + { + SUBST (XEXP (x, 0), op0); + SUBST (XEXP (x, 1), op1); + } + else if (num_negated == 1) + return gen_unary (NOT, mode, mode, gen_binary (XOR, mode, op0, op1)); + } + + /* Convert (xor (and A B) B) to (and (not A) B). The latter may + correspond to a machine insn or result in further simplifications + if B is a constant. */ + + if (GET_CODE (op0) == AND + && rtx_equal_p (XEXP (op0, 1), op1) + && ! side_effects_p (op1)) + return gen_binary (AND, mode, + gen_unary (NOT, mode, mode, XEXP (op0, 0)), + op1); + + else if (GET_CODE (op0) == AND + && rtx_equal_p (XEXP (op0, 0), op1) + && ! side_effects_p (op1)) + return gen_binary (AND, mode, + gen_unary (NOT, mode, mode, XEXP (op0, 1)), + op1); + + /* (xor (comparison foo bar) (const_int 1)) can become the reversed + comparison if STORE_FLAG_VALUE is 1. */ + if (STORE_FLAG_VALUE == 1 + && op1 == const1_rtx + && GET_RTX_CLASS (GET_CODE (op0)) == '<' + && reversible_comparison_p (op0)) + return gen_rtx_combine (reverse_condition (GET_CODE (op0)), + mode, XEXP (op0, 0), XEXP (op0, 1)); + + /* (lshiftrt foo C) where C is the number of bits in FOO minus 1 + is (lt foo (const_int 0)), so we can perform the above + simplification if STORE_FLAG_VALUE is 1. */ + + if (STORE_FLAG_VALUE == 1 + && op1 == const1_rtx + && GET_CODE (op0) == LSHIFTRT + && GET_CODE (XEXP (op0, 1)) == CONST_INT + && INTVAL (XEXP (op0, 1)) == GET_MODE_BITSIZE (mode) - 1) + return gen_rtx_combine (GE, mode, XEXP (op0, 0), const0_rtx); + + /* (xor (comparison foo bar) (const_int sign-bit)) + when STORE_FLAG_VALUE is the sign bit. */ + if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT + && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode)) + == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1)) + && op1 == const_true_rtx + && GET_RTX_CLASS (GET_CODE (op0)) == '<' + && reversible_comparison_p (op0)) + return gen_rtx_combine (reverse_condition (GET_CODE (op0)), + mode, XEXP (op0, 0), XEXP (op0, 1)); + break; + + default: + abort (); + } + + return x; +} + +/* We consider ZERO_EXTRACT, SIGN_EXTRACT, and SIGN_EXTEND as "compound + operations" because they can be replaced with two more basic operations. + ZERO_EXTEND is also considered "compound" because it can be replaced with + an AND operation, which is simpler, though only one operation. + + The function expand_compound_operation is called with an rtx expression + and will convert it to the appropriate shifts and AND operations, + simplifying at each stage. + + The function make_compound_operation is called to convert an expression + consisting of shifts and ANDs into the equivalent compound expression. + It is the inverse of this function, loosely speaking. */ + +static rtx +expand_compound_operation (x) + rtx x; +{ + int pos = 0, len; + int unsignedp = 0; + int modewidth; + rtx tem; + + switch (GET_CODE (x)) + { + case ZERO_EXTEND: + unsignedp = 1; + case SIGN_EXTEND: + /* We can't necessarily use a const_int for a multiword mode; + it depends on implicitly extending the value. + Since we don't know the right way to extend it, + we can't tell whether the implicit way is right. + + Even for a mode that is no wider than a const_int, + we can't win, because we need to sign extend one of its bits through + the rest of it, and we don't know which bit. */ + if (GET_CODE (XEXP (x, 0)) == CONST_INT) + return x; + + /* Return if (subreg:MODE FROM 0) is not a safe replacement for + (zero_extend:MODE FROM) or (sign_extend:MODE FROM). It is for any MEM + because (SUBREG (MEM...)) is guaranteed to cause the MEM to be + reloaded. If not for that, MEM's would very rarely be safe. + + Reject MODEs bigger than a word, because we might not be able + to reference a two-register group starting with an arbitrary register + (and currently gen_lowpart might crash for a SUBREG). */ + + if (GET_MODE_SIZE (GET_MODE (XEXP (x, 0))) > UNITS_PER_WORD) + return x; + + len = GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))); + /* If the inner object has VOIDmode (the only way this can happen + is if it is a ASM_OPERANDS), we can't do anything since we don't + know how much masking to do. */ + if (len == 0) + return x; + + break; + + case ZERO_EXTRACT: + unsignedp = 1; + case SIGN_EXTRACT: + /* If the operand is a CLOBBER, just return it. */ + if (GET_CODE (XEXP (x, 0)) == CLOBBER) + return XEXP (x, 0); + + if (GET_CODE (XEXP (x, 1)) != CONST_INT + || GET_CODE (XEXP (x, 2)) != CONST_INT + || GET_MODE (XEXP (x, 0)) == VOIDmode) + return x; + + len = INTVAL (XEXP (x, 1)); + pos = INTVAL (XEXP (x, 2)); + + /* If this goes outside the object being extracted, replace the object + with a (use (mem ...)) construct that only combine understands + and is used only for this purpose. */ + if (len + pos > GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))) + SUBST (XEXP (x, 0), gen_rtx_USE (GET_MODE (x), XEXP (x, 0))); + + if (BITS_BIG_ENDIAN) + pos = GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - len - pos; + + break; + + default: + return x; + } + + /* We can optimize some special cases of ZERO_EXTEND. */ + if (GET_CODE (x) == ZERO_EXTEND) + { + /* (zero_extend:DI (truncate:SI foo:DI)) is just foo:DI if we + know that the last value didn't have any inappropriate bits + set. */ + if (GET_CODE (XEXP (x, 0)) == TRUNCATE + && GET_MODE (XEXP (XEXP (x, 0), 0)) == GET_MODE (x) + && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT + && (nonzero_bits (XEXP (XEXP (x, 0), 0), GET_MODE (x)) + & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0) + return XEXP (XEXP (x, 0), 0); + + /* Likewise for (zero_extend:DI (subreg:SI foo:DI 0)). */ + if (GET_CODE (XEXP (x, 0)) == SUBREG + && GET_MODE (SUBREG_REG (XEXP (x, 0))) == GET_MODE (x) + && subreg_lowpart_p (XEXP (x, 0)) + && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT + && (nonzero_bits (SUBREG_REG (XEXP (x, 0)), GET_MODE (x)) + & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0) + return SUBREG_REG (XEXP (x, 0)); + + /* (zero_extend:DI (truncate:SI foo:DI)) is just foo:DI when foo + is a comparison and STORE_FLAG_VALUE permits. This is like + the first case, but it works even when GET_MODE (x) is larger + than HOST_WIDE_INT. */ + if (GET_CODE (XEXP (x, 0)) == TRUNCATE + && GET_MODE (XEXP (XEXP (x, 0), 0)) == GET_MODE (x) + && GET_RTX_CLASS (GET_CODE (XEXP (XEXP (x, 0), 0))) == '<' + && (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) + <= HOST_BITS_PER_WIDE_INT) + && ((HOST_WIDE_INT) STORE_FLAG_VALUE + & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0) + return XEXP (XEXP (x, 0), 0); + + /* Likewise for (zero_extend:DI (subreg:SI foo:DI 0)). */ + if (GET_CODE (XEXP (x, 0)) == SUBREG + && GET_MODE (SUBREG_REG (XEXP (x, 0))) == GET_MODE (x) + && subreg_lowpart_p (XEXP (x, 0)) + && GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0)))) == '<' + && (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) + <= HOST_BITS_PER_WIDE_INT) + && ((HOST_WIDE_INT) STORE_FLAG_VALUE + & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0) + return SUBREG_REG (XEXP (x, 0)); + + /* If sign extension is cheaper than zero extension, then use it + if we know that no extraneous bits are set, and that the high + bit is not set. */ + if (flag_expensive_optimizations + && ((GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT + && ((nonzero_bits (XEXP (x, 0), GET_MODE (x)) + & ~ (((unsigned HOST_WIDE_INT) + GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) + >> 1)) + == 0)) + || (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<' + && (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) + <= HOST_BITS_PER_WIDE_INT) + && (((HOST_WIDE_INT) STORE_FLAG_VALUE + & ~ (((unsigned HOST_WIDE_INT) + GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) + >> 1)) + == 0)))) + { + rtx temp = gen_rtx_SIGN_EXTEND (GET_MODE (x), XEXP (x, 0)); + + if (rtx_cost (temp, SET) < rtx_cost (x, SET)) + return expand_compound_operation (temp); + } + } + + /* If we reach here, we want to return a pair of shifts. The inner + shift is a left shift of BITSIZE - POS - LEN bits. The outer + shift is a right shift of BITSIZE - LEN bits. It is arithmetic or + logical depending on the value of UNSIGNEDP. + + If this was a ZERO_EXTEND or ZERO_EXTRACT, this pair of shifts will be + converted into an AND of a shift. + + We must check for the case where the left shift would have a negative + count. This can happen in a case like (x >> 31) & 255 on machines + that can't shift by a constant. On those machines, we would first + combine the shift with the AND to produce a variable-position + extraction. Then the constant of 31 would be substituted in to produce + a such a position. */ + + modewidth = GET_MODE_BITSIZE (GET_MODE (x)); + if (modewidth >= pos - len) + tem = simplify_shift_const (NULL_RTX, unsignedp ? LSHIFTRT : ASHIFTRT, + GET_MODE (x), + simplify_shift_const (NULL_RTX, ASHIFT, + GET_MODE (x), + XEXP (x, 0), + modewidth - pos - len), + modewidth - len); + + else if (unsignedp && len < HOST_BITS_PER_WIDE_INT) + tem = simplify_and_const_int (NULL_RTX, GET_MODE (x), + simplify_shift_const (NULL_RTX, LSHIFTRT, + GET_MODE (x), + XEXP (x, 0), pos), + ((HOST_WIDE_INT) 1 << len) - 1); + else + /* Any other cases we can't handle. */ + return x; + + + /* If we couldn't do this for some reason, return the original + expression. */ + if (GET_CODE (tem) == CLOBBER) + return x; + + return tem; +} + +/* X is a SET which contains an assignment of one object into + a part of another (such as a bit-field assignment, STRICT_LOW_PART, + or certain SUBREGS). If possible, convert it into a series of + logical operations. + + We half-heartedly support variable positions, but do not at all + support variable lengths. */ + +static rtx +expand_field_assignment (x) + rtx x; +{ + rtx inner; + rtx pos; /* Always counts from low bit. */ + int len; + rtx mask; + enum machine_mode compute_mode; + + /* Loop until we find something we can't simplify. */ + while (1) + { + if (GET_CODE (SET_DEST (x)) == STRICT_LOW_PART + && GET_CODE (XEXP (SET_DEST (x), 0)) == SUBREG) + { + inner = SUBREG_REG (XEXP (SET_DEST (x), 0)); + len = GET_MODE_BITSIZE (GET_MODE (XEXP (SET_DEST (x), 0))); + pos = GEN_INT (BITS_PER_WORD * SUBREG_WORD (XEXP (SET_DEST (x), 0))); + } + else if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT + && GET_CODE (XEXP (SET_DEST (x), 1)) == CONST_INT) + { + inner = XEXP (SET_DEST (x), 0); + len = INTVAL (XEXP (SET_DEST (x), 1)); + pos = XEXP (SET_DEST (x), 2); + + /* If the position is constant and spans the width of INNER, + surround INNER with a USE to indicate this. */ + if (GET_CODE (pos) == CONST_INT + && INTVAL (pos) + len > GET_MODE_BITSIZE (GET_MODE (inner))) + inner = gen_rtx_USE (GET_MODE (SET_DEST (x)), inner); + + if (BITS_BIG_ENDIAN) + { + if (GET_CODE (pos) == CONST_INT) + pos = GEN_INT (GET_MODE_BITSIZE (GET_MODE (inner)) - len + - INTVAL (pos)); + else if (GET_CODE (pos) == MINUS + && GET_CODE (XEXP (pos, 1)) == CONST_INT + && (INTVAL (XEXP (pos, 1)) + == GET_MODE_BITSIZE (GET_MODE (inner)) - len)) + /* If position is ADJUST - X, new position is X. */ + pos = XEXP (pos, 0); + else + pos = gen_binary (MINUS, GET_MODE (pos), + GEN_INT (GET_MODE_BITSIZE (GET_MODE (inner)) + - len), + pos); + } + } + + /* A SUBREG between two modes that occupy the same numbers of words + can be done by moving the SUBREG to the source. */ + else if (GET_CODE (SET_DEST (x)) == SUBREG + && (((GET_MODE_SIZE (GET_MODE (SET_DEST (x))) + + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD) + == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (x)))) + + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))) + { + x = gen_rtx_SET (VOIDmode, SUBREG_REG (SET_DEST (x)), + gen_lowpart_for_combine (GET_MODE (SUBREG_REG (SET_DEST (x))), + SET_SRC (x))); + continue; + } + else + break; + + while (GET_CODE (inner) == SUBREG && subreg_lowpart_p (inner)) + inner = SUBREG_REG (inner); + + compute_mode = GET_MODE (inner); + + /* Don't attempt bitwise arithmetic on non-integral modes. */ + if (! INTEGRAL_MODE_P (compute_mode)) + { + enum machine_mode imode; + + /* Something is probably seriously wrong if this matches. */ + if (! FLOAT_MODE_P (compute_mode)) + break; + + /* Try to find an integral mode to pun with. */ + imode = mode_for_size (GET_MODE_BITSIZE (compute_mode), MODE_INT, 0); + if (imode == BLKmode) + break; + + compute_mode = imode; + inner = gen_lowpart_for_combine (imode, inner); + } + + /* Compute a mask of LEN bits, if we can do this on the host machine. */ + if (len < HOST_BITS_PER_WIDE_INT) + mask = GEN_INT (((HOST_WIDE_INT) 1 << len) - 1); + else + break; + + /* Now compute the equivalent expression. Make a copy of INNER + for the SET_DEST in case it is a MEM into which we will substitute; + we don't want shared RTL in that case. */ + x = gen_rtx_SET (VOIDmode, copy_rtx (inner), + gen_binary (IOR, compute_mode, + gen_binary (AND, compute_mode, + gen_unary (NOT, compute_mode, + compute_mode, + gen_binary (ASHIFT, + compute_mode, + mask, pos)), + inner), + gen_binary (ASHIFT, compute_mode, + gen_binary (AND, compute_mode, + gen_lowpart_for_combine + (compute_mode, + SET_SRC (x)), + mask), + pos))); + } + + return x; +} + +/* Return an RTX for a reference to LEN bits of INNER. If POS_RTX is nonzero, + it is an RTX that represents a variable starting position; otherwise, + POS is the (constant) starting bit position (counted from the LSB). + + INNER may be a USE. This will occur when we started with a bitfield + that went outside the boundary of the object in memory, which is + allowed on most machines. To isolate this case, we produce a USE + whose mode is wide enough and surround the MEM with it. The only + code that understands the USE is this routine. If it is not removed, + it will cause the resulting insn not to match. + + UNSIGNEDP is non-zero for an unsigned reference and zero for a + signed reference. + + IN_DEST is non-zero if this is a reference in the destination of a + SET. This is used when a ZERO_ or SIGN_EXTRACT isn't needed. If non-zero, + a STRICT_LOW_PART will be used, if zero, ZERO_EXTEND or SIGN_EXTEND will + be used. + + IN_COMPARE is non-zero if we are in a COMPARE. This means that a + ZERO_EXTRACT should be built even for bits starting at bit 0. + + MODE is the desired mode of the result (if IN_DEST == 0). + + The result is an RTX for the extraction or NULL_RTX if the target + can't handle it. */ + +static rtx +make_extraction (mode, inner, pos, pos_rtx, len, + unsignedp, in_dest, in_compare) + enum machine_mode mode; + rtx inner; + int pos; + rtx pos_rtx; + int len; + int unsignedp; + int in_dest, in_compare; +{ + /* This mode describes the size of the storage area + to fetch the overall value from. Within that, we + ignore the POS lowest bits, etc. */ + enum machine_mode is_mode = GET_MODE (inner); + enum machine_mode inner_mode; + enum machine_mode wanted_inner_mode = byte_mode; + enum machine_mode wanted_inner_reg_mode = word_mode; + enum machine_mode pos_mode = word_mode; + enum machine_mode extraction_mode = word_mode; + enum machine_mode tmode = mode_for_size (len, MODE_INT, 1); + int spans_byte = 0; + rtx new = 0; + rtx orig_pos_rtx = pos_rtx; + int orig_pos; + + /* Get some information about INNER and get the innermost object. */ + if (GET_CODE (inner) == USE) + /* (use:SI (mem:QI foo)) stands for (mem:SI foo). */ + /* We don't need to adjust the position because we set up the USE + to pretend that it was a full-word object. */ + spans_byte = 1, inner = XEXP (inner, 0); + else if (GET_CODE (inner) == SUBREG && subreg_lowpart_p (inner)) + { + /* If going from (subreg:SI (mem:QI ...)) to (mem:QI ...), + consider just the QI as the memory to extract from. + The subreg adds or removes high bits; its mode is + irrelevant to the meaning of this extraction, + since POS and LEN count from the lsb. */ + if (GET_CODE (SUBREG_REG (inner)) == MEM) + is_mode = GET_MODE (SUBREG_REG (inner)); + inner = SUBREG_REG (inner); + } + + inner_mode = GET_MODE (inner); + + if (pos_rtx && GET_CODE (pos_rtx) == CONST_INT) + pos = INTVAL (pos_rtx), pos_rtx = 0; + + /* See if this can be done without an extraction. We never can if the + width of the field is not the same as that of some integer mode. For + registers, we can only avoid the extraction if the position is at the + low-order bit and this is either not in the destination or we have the + appropriate STRICT_LOW_PART operation available. + + For MEM, we can avoid an extract if the field starts on an appropriate + boundary and we can change the mode of the memory reference. However, + we cannot directly access the MEM if we have a USE and the underlying + MEM is not TMODE. This combination means that MEM was being used in a + context where bits outside its mode were being referenced; that is only + valid in bit-field insns. */ + + if (tmode != BLKmode + && ! (spans_byte && inner_mode != tmode) + && ((pos_rtx == 0 && (pos % BITS_PER_WORD) == 0 + && GET_CODE (inner) != MEM + && (! in_dest + || (GET_CODE (inner) == REG + && (movstrict_optab->handlers[(int) tmode].insn_code + != CODE_FOR_nothing)))) + || (GET_CODE (inner) == MEM && pos_rtx == 0 + && (pos + % (STRICT_ALIGNMENT ? GET_MODE_ALIGNMENT (tmode) + : BITS_PER_UNIT)) == 0 + /* We can't do this if we are widening INNER_MODE (it + may not be aligned, for one thing). */ + && GET_MODE_BITSIZE (inner_mode) >= GET_MODE_BITSIZE (tmode) + && (inner_mode == tmode + || (! mode_dependent_address_p (XEXP (inner, 0)) + && ! MEM_VOLATILE_P (inner)))))) + { + /* If INNER is a MEM, make a new MEM that encompasses just the desired + field. If the original and current mode are the same, we need not + adjust the offset. Otherwise, we do if bytes big endian. + + If INNER is not a MEM, get a piece consisting of just the field + of interest (in this case POS % BITS_PER_WORD must be 0). */ + + if (GET_CODE (inner) == MEM) + { + int offset; + /* POS counts from lsb, but make OFFSET count in memory order. */ + if (BYTES_BIG_ENDIAN) + offset = (GET_MODE_BITSIZE (is_mode) - len - pos) / BITS_PER_UNIT; + else + offset = pos / BITS_PER_UNIT; + + new = gen_rtx_MEM (tmode, plus_constant (XEXP (inner, 0), offset)); + RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (inner); + MEM_COPY_ATTRIBUTES (new, inner); + } + else if (GET_CODE (inner) == REG) + { + /* We can't call gen_lowpart_for_combine here since we always want + a SUBREG and it would sometimes return a new hard register. */ + if (tmode != inner_mode) + new = gen_rtx_SUBREG (tmode, inner, + (WORDS_BIG_ENDIAN + && GET_MODE_SIZE (inner_mode) > UNITS_PER_WORD + ? (((GET_MODE_SIZE (inner_mode) + - GET_MODE_SIZE (tmode)) + / UNITS_PER_WORD) + - pos / BITS_PER_WORD) + : pos / BITS_PER_WORD)); + else + new = inner; + } + else + new = force_to_mode (inner, tmode, + len >= HOST_BITS_PER_WIDE_INT + ? GET_MODE_MASK (tmode) + : ((HOST_WIDE_INT) 1 << len) - 1, + NULL_RTX, 0); + + /* If this extraction is going into the destination of a SET, + make a STRICT_LOW_PART unless we made a MEM. */ + + if (in_dest) + return (GET_CODE (new) == MEM ? new + : (GET_CODE (new) != SUBREG + ? gen_rtx_CLOBBER (tmode, const0_rtx) + : gen_rtx_combine (STRICT_LOW_PART, VOIDmode, new))); + + /* Otherwise, sign- or zero-extend unless we already are in the + proper mode. */ + + return (mode == tmode ? new + : gen_rtx_combine (unsignedp ? ZERO_EXTEND : SIGN_EXTEND, + mode, new)); + } + + /* Unless this is a COMPARE or we have a funny memory reference, + don't do anything with zero-extending field extracts starting at + the low-order bit since they are simple AND operations. */ + if (pos_rtx == 0 && pos == 0 && ! in_dest + && ! in_compare && ! spans_byte && unsignedp) + return 0; + + /* Unless we are allowed to span bytes, reject this if we would be + spanning bytes or if the position is not a constant and the length + is not 1. In all other cases, we would only be going outside + out object in cases when an original shift would have been + undefined. */ + if (! spans_byte + && ((pos_rtx == 0 && pos + len > GET_MODE_BITSIZE (is_mode)) + || (pos_rtx != 0 && len != 1))) + return 0; + + /* Get the mode to use should INNER not be a MEM, the mode for the position, + and the mode for the result. */ +#ifdef HAVE_insv + if (in_dest) + { + wanted_inner_reg_mode + = (insn_operand_mode[(int) CODE_FOR_insv][0] == VOIDmode + ? word_mode + : insn_operand_mode[(int) CODE_FOR_insv][0]); + pos_mode = (insn_operand_mode[(int) CODE_FOR_insv][2] == VOIDmode + ? word_mode : insn_operand_mode[(int) CODE_FOR_insv][2]); + extraction_mode = (insn_operand_mode[(int) CODE_FOR_insv][3] == VOIDmode + ? word_mode + : insn_operand_mode[(int) CODE_FOR_insv][3]); + } +#endif + +#ifdef HAVE_extzv + if (! in_dest && unsignedp) + { + wanted_inner_reg_mode + = (insn_operand_mode[(int) CODE_FOR_extzv][1] == VOIDmode + ? word_mode + : insn_operand_mode[(int) CODE_FOR_extzv][1]); + pos_mode = (insn_operand_mode[(int) CODE_FOR_extzv][3] == VOIDmode + ? word_mode : insn_operand_mode[(int) CODE_FOR_extzv][3]); + extraction_mode = (insn_operand_mode[(int) CODE_FOR_extzv][0] == VOIDmode + ? word_mode + : insn_operand_mode[(int) CODE_FOR_extzv][0]); + } +#endif + +#ifdef HAVE_extv + if (! in_dest && ! unsignedp) + { + wanted_inner_reg_mode + = (insn_operand_mode[(int) CODE_FOR_extv][1] == VOIDmode + ? word_mode + : insn_operand_mode[(int) CODE_FOR_extv][1]); + pos_mode = (insn_operand_mode[(int) CODE_FOR_extv][3] == VOIDmode + ? word_mode : insn_operand_mode[(int) CODE_FOR_extv][3]); + extraction_mode = (insn_operand_mode[(int) CODE_FOR_extv][0] == VOIDmode + ? word_mode + : insn_operand_mode[(int) CODE_FOR_extv][0]); + } +#endif + + /* Never narrow an object, since that might not be safe. */ + + if (mode != VOIDmode + && GET_MODE_SIZE (extraction_mode) < GET_MODE_SIZE (mode)) + extraction_mode = mode; + + if (pos_rtx && GET_MODE (pos_rtx) != VOIDmode + && GET_MODE_SIZE (pos_mode) < GET_MODE_SIZE (GET_MODE (pos_rtx))) + pos_mode = GET_MODE (pos_rtx); + + /* If this is not from memory, the desired mode is wanted_inner_reg_mode; + if we have to change the mode of memory and cannot, the desired mode is + EXTRACTION_MODE. */ + if (GET_CODE (inner) != MEM) + wanted_inner_mode = wanted_inner_reg_mode; + else if (inner_mode != wanted_inner_mode + && (mode_dependent_address_p (XEXP (inner, 0)) + || MEM_VOLATILE_P (inner))) + wanted_inner_mode = extraction_mode; + + orig_pos = pos; + + if (BITS_BIG_ENDIAN) + { + /* POS is passed as if BITS_BIG_ENDIAN == 0, so we need to convert it to + BITS_BIG_ENDIAN style. If position is constant, compute new + position. Otherwise, build subtraction. + Note that POS is relative to the mode of the original argument. + If it's a MEM we need to recompute POS relative to that. + However, if we're extracting from (or inserting into) a register, + we want to recompute POS relative to wanted_inner_mode. */ + int width = (GET_CODE (inner) == MEM + ? GET_MODE_BITSIZE (is_mode) + : GET_MODE_BITSIZE (wanted_inner_mode)); + + if (pos_rtx == 0) + pos = width - len - pos; + else + pos_rtx + = gen_rtx_combine (MINUS, GET_MODE (pos_rtx), + GEN_INT (width - len), pos_rtx); + /* POS may be less than 0 now, but we check for that below. + Note that it can only be less than 0 if GET_CODE (inner) != MEM. */ + } + + /* If INNER has a wider mode, make it smaller. If this is a constant + extract, try to adjust the byte to point to the byte containing + the value. */ + if (wanted_inner_mode != VOIDmode + && GET_MODE_SIZE (wanted_inner_mode) < GET_MODE_SIZE (is_mode) + && ((GET_CODE (inner) == MEM + && (inner_mode == wanted_inner_mode + || (! mode_dependent_address_p (XEXP (inner, 0)) + && ! MEM_VOLATILE_P (inner)))))) + { + int offset = 0; + + /* The computations below will be correct if the machine is big + endian in both bits and bytes or little endian in bits and bytes. + If it is mixed, we must adjust. */ + + /* If bytes are big endian and we had a paradoxical SUBREG, we must + adjust OFFSET to compensate. */ + if (BYTES_BIG_ENDIAN + && ! spans_byte + && GET_MODE_SIZE (inner_mode) < GET_MODE_SIZE (is_mode)) + offset -= GET_MODE_SIZE (is_mode) - GET_MODE_SIZE (inner_mode); + + /* If this is a constant position, we can move to the desired byte. */ + if (pos_rtx == 0) + { + offset += pos / BITS_PER_UNIT; + pos %= GET_MODE_BITSIZE (wanted_inner_mode); + } + + if (BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN + && ! spans_byte + && is_mode != wanted_inner_mode) + offset = (GET_MODE_SIZE (is_mode) + - GET_MODE_SIZE (wanted_inner_mode) - offset); + + if (offset != 0 || inner_mode != wanted_inner_mode) + { + rtx newmem = gen_rtx_MEM (wanted_inner_mode, + plus_constant (XEXP (inner, 0), offset)); + RTX_UNCHANGING_P (newmem) = RTX_UNCHANGING_P (inner); + MEM_COPY_ATTRIBUTES (newmem, inner); + inner = newmem; + } + } + + /* If INNER is not memory, we can always get it into the proper mode. If we + are changing its mode, POS must be a constant and smaller than the size + of the new mode. */ + else if (GET_CODE (inner) != MEM) + { + if (GET_MODE (inner) != wanted_inner_mode + && (pos_rtx != 0 + || orig_pos + len > GET_MODE_BITSIZE (wanted_inner_mode))) + return 0; + + inner = force_to_mode (inner, wanted_inner_mode, + pos_rtx + || len + orig_pos >= HOST_BITS_PER_WIDE_INT + ? GET_MODE_MASK (wanted_inner_mode) + : (((HOST_WIDE_INT) 1 << len) - 1) << orig_pos, + NULL_RTX, 0); + } + + /* Adjust mode of POS_RTX, if needed. If we want a wider mode, we + have to zero extend. Otherwise, we can just use a SUBREG. */ + if (pos_rtx != 0 + && GET_MODE_SIZE (pos_mode) > GET_MODE_SIZE (GET_MODE (pos_rtx))) + pos_rtx = gen_rtx_combine (ZERO_EXTEND, pos_mode, pos_rtx); + else if (pos_rtx != 0 + && GET_MODE_SIZE (pos_mode) < GET_MODE_SIZE (GET_MODE (pos_rtx))) + pos_rtx = gen_lowpart_for_combine (pos_mode, pos_rtx); + + /* Make POS_RTX unless we already have it and it is correct. If we don't + have a POS_RTX but we do have an ORIG_POS_RTX, the latter must + be a CONST_INT. */ + if (pos_rtx == 0 && orig_pos_rtx != 0 && INTVAL (orig_pos_rtx) == pos) + pos_rtx = orig_pos_rtx; + + else if (pos_rtx == 0) + pos_rtx = GEN_INT (pos); + + /* Make the required operation. See if we can use existing rtx. */ + new = gen_rtx_combine (unsignedp ? ZERO_EXTRACT : SIGN_EXTRACT, + extraction_mode, inner, GEN_INT (len), pos_rtx); + if (! in_dest) + new = gen_lowpart_for_combine (mode, new); + + return new; +} + +/* See if X contains an ASHIFT of COUNT or more bits that can be commuted + with any other operations in X. Return X without that shift if so. */ + +static rtx +extract_left_shift (x, count) + rtx x; + int count; +{ + enum rtx_code code = GET_CODE (x); + enum machine_mode mode = GET_MODE (x); + rtx tem; + + switch (code) + { + case ASHIFT: + /* This is the shift itself. If it is wide enough, we will return + either the value being shifted if the shift count is equal to + COUNT or a shift for the difference. */ + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) >= count) + return simplify_shift_const (NULL_RTX, ASHIFT, mode, XEXP (x, 0), + INTVAL (XEXP (x, 1)) - count); + break; + + case NEG: case NOT: + if ((tem = extract_left_shift (XEXP (x, 0), count)) != 0) + return gen_unary (code, mode, mode, tem); + + break; + + case PLUS: case IOR: case XOR: case AND: + /* If we can safely shift this constant and we find the inner shift, + make a new operation. */ + if (GET_CODE (XEXP (x,1)) == CONST_INT + && (INTVAL (XEXP (x, 1)) & ((((HOST_WIDE_INT) 1 << count)) - 1)) == 0 + && (tem = extract_left_shift (XEXP (x, 0), count)) != 0) + return gen_binary (code, mode, tem, + GEN_INT (INTVAL (XEXP (x, 1)) >> count)); + + break; + + default: + break; + } + + return 0; +} + +/* Look at the expression rooted at X. Look for expressions + equivalent to ZERO_EXTRACT, SIGN_EXTRACT, ZERO_EXTEND, SIGN_EXTEND. + Form these expressions. + + Return the new rtx, usually just X. + + Also, for machines like the Vax that don't have logical shift insns, + try to convert logical to arithmetic shift operations in cases where + they are equivalent. This undoes the canonicalizations to logical + shifts done elsewhere. + + We try, as much as possible, to re-use rtl expressions to save memory. + + IN_CODE says what kind of expression we are processing. Normally, it is + SET. In a memory address (inside a MEM, PLUS or minus, the latter two + being kludges), it is MEM. When processing the arguments of a comparison + or a COMPARE against zero, it is COMPARE. */ + +static rtx +make_compound_operation (x, in_code) + rtx x; + enum rtx_code in_code; +{ + enum rtx_code code = GET_CODE (x); + enum machine_mode mode = GET_MODE (x); + int mode_width = GET_MODE_BITSIZE (mode); + rtx rhs, lhs; + enum rtx_code next_code; + int i; + rtx new = 0; + rtx tem; + char *fmt; + + /* Select the code to be used in recursive calls. Once we are inside an + address, we stay there. If we have a comparison, set to COMPARE, + but once inside, go back to our default of SET. */ + + next_code = (code == MEM || code == PLUS || code == MINUS ? MEM + : ((code == COMPARE || GET_RTX_CLASS (code) == '<') + && XEXP (x, 1) == const0_rtx) ? COMPARE + : in_code == COMPARE ? SET : in_code); + + /* Process depending on the code of this operation. If NEW is set + non-zero, it will be returned. */ + + switch (code) + { + case ASHIFT: + /* Convert shifts by constants into multiplications if inside + an address. */ + if (in_code == MEM && GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT + && INTVAL (XEXP (x, 1)) >= 0) + { + new = make_compound_operation (XEXP (x, 0), next_code); + new = gen_rtx_combine (MULT, mode, new, + GEN_INT ((HOST_WIDE_INT) 1 + << INTVAL (XEXP (x, 1)))); + } + break; + + case AND: + /* If the second operand is not a constant, we can't do anything + with it. */ + if (GET_CODE (XEXP (x, 1)) != CONST_INT) + break; + + /* If the constant is a power of two minus one and the first operand + is a logical right shift, make an extraction. */ + if (GET_CODE (XEXP (x, 0)) == LSHIFTRT + && (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0) + { + new = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code); + new = make_extraction (mode, new, 0, XEXP (XEXP (x, 0), 1), i, 1, + 0, in_code == COMPARE); + } + + /* Same as previous, but for (subreg (lshiftrt ...)) in first op. */ + else if (GET_CODE (XEXP (x, 0)) == SUBREG + && subreg_lowpart_p (XEXP (x, 0)) + && GET_CODE (SUBREG_REG (XEXP (x, 0))) == LSHIFTRT + && (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0) + { + new = make_compound_operation (XEXP (SUBREG_REG (XEXP (x, 0)), 0), + next_code); + new = make_extraction (GET_MODE (SUBREG_REG (XEXP (x, 0))), new, 0, + XEXP (SUBREG_REG (XEXP (x, 0)), 1), i, 1, + 0, in_code == COMPARE); + } + /* Same as previous, but for (xor/ior (lshiftrt...) (lshiftrt...)). */ + else if ((GET_CODE (XEXP (x, 0)) == XOR + || GET_CODE (XEXP (x, 0)) == IOR) + && GET_CODE (XEXP (XEXP (x, 0), 0)) == LSHIFTRT + && GET_CODE (XEXP (XEXP (x, 0), 1)) == LSHIFTRT + && (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0) + { + /* Apply the distributive law, and then try to make extractions. */ + new = gen_rtx_combine (GET_CODE (XEXP (x, 0)), mode, + gen_rtx_AND (mode, XEXP (XEXP (x, 0), 0), + XEXP (x, 1)), + gen_rtx_AND (mode, XEXP (XEXP (x, 0), 1), + XEXP (x, 1))); + new = make_compound_operation (new, in_code); + } + + /* If we are have (and (rotate X C) M) and C is larger than the number + of bits in M, this is an extraction. */ + + else if (GET_CODE (XEXP (x, 0)) == ROTATE + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0 + && i <= INTVAL (XEXP (XEXP (x, 0), 1))) + { + new = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code); + new = make_extraction (mode, new, + (GET_MODE_BITSIZE (mode) + - INTVAL (XEXP (XEXP (x, 0), 1))), + NULL_RTX, i, 1, 0, in_code == COMPARE); + } + + /* On machines without logical shifts, if the operand of the AND is + a logical shift and our mask turns off all the propagated sign + bits, we can replace the logical shift with an arithmetic shift. */ + else if (ashr_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing + && (lshr_optab->handlers[(int) mode].insn_code + == CODE_FOR_nothing) + && GET_CODE (XEXP (x, 0)) == LSHIFTRT + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && INTVAL (XEXP (XEXP (x, 0), 1)) >= 0 + && INTVAL (XEXP (XEXP (x, 0), 1)) < HOST_BITS_PER_WIDE_INT + && mode_width <= HOST_BITS_PER_WIDE_INT) + { + unsigned HOST_WIDE_INT mask = GET_MODE_MASK (mode); + + mask >>= INTVAL (XEXP (XEXP (x, 0), 1)); + if ((INTVAL (XEXP (x, 1)) & ~mask) == 0) + SUBST (XEXP (x, 0), + gen_rtx_combine (ASHIFTRT, mode, + make_compound_operation (XEXP (XEXP (x, 0), 0), + next_code), + XEXP (XEXP (x, 0), 1))); + } + + /* If the constant is one less than a power of two, this might be + representable by an extraction even if no shift is present. + If it doesn't end up being a ZERO_EXTEND, we will ignore it unless + we are in a COMPARE. */ + else if ((i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0) + new = make_extraction (mode, + make_compound_operation (XEXP (x, 0), + next_code), + 0, NULL_RTX, i, 1, 0, in_code == COMPARE); + + /* If we are in a comparison and this is an AND with a power of two, + convert this into the appropriate bit extract. */ + else if (in_code == COMPARE + && (i = exact_log2 (INTVAL (XEXP (x, 1)))) >= 0) + new = make_extraction (mode, + make_compound_operation (XEXP (x, 0), + next_code), + i, NULL_RTX, 1, 1, 0, 1); + + break; + + case LSHIFTRT: + /* If the sign bit is known to be zero, replace this with an + arithmetic shift. */ + if (ashr_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing + && lshr_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing + && mode_width <= HOST_BITS_PER_WIDE_INT + && (nonzero_bits (XEXP (x, 0), mode) & (1 << (mode_width - 1))) == 0) + { + new = gen_rtx_combine (ASHIFTRT, mode, + make_compound_operation (XEXP (x, 0), + next_code), + XEXP (x, 1)); + break; + } + + /* ... fall through ... */ + + case ASHIFTRT: + lhs = XEXP (x, 0); + rhs = XEXP (x, 1); + + /* If we have (ashiftrt (ashift foo C1) C2) with C2 >= C1, + this is a SIGN_EXTRACT. */ + if (GET_CODE (rhs) == CONST_INT + && GET_CODE (lhs) == ASHIFT + && GET_CODE (XEXP (lhs, 1)) == CONST_INT + && INTVAL (rhs) >= INTVAL (XEXP (lhs, 1))) + { + new = make_compound_operation (XEXP (lhs, 0), next_code); + new = make_extraction (mode, new, + INTVAL (rhs) - INTVAL (XEXP (lhs, 1)), + NULL_RTX, mode_width - INTVAL (rhs), + code == LSHIFTRT, 0, in_code == COMPARE); + } + + /* See if we have operations between an ASHIFTRT and an ASHIFT. + If so, try to merge the shifts into a SIGN_EXTEND. We could + also do this for some cases of SIGN_EXTRACT, but it doesn't + seem worth the effort; the case checked for occurs on Alpha. */ + + if (GET_RTX_CLASS (GET_CODE (lhs)) != 'o' + && ! (GET_CODE (lhs) == SUBREG + && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (lhs))) == 'o')) + && GET_CODE (rhs) == CONST_INT + && INTVAL (rhs) < HOST_BITS_PER_WIDE_INT + && (new = extract_left_shift (lhs, INTVAL (rhs))) != 0) + new = make_extraction (mode, make_compound_operation (new, next_code), + 0, NULL_RTX, mode_width - INTVAL (rhs), + code == LSHIFTRT, 0, in_code == COMPARE); + + break; + + case SUBREG: + /* Call ourselves recursively on the inner expression. If we are + narrowing the object and it has a different RTL code from + what it originally did, do this SUBREG as a force_to_mode. */ + + tem = make_compound_operation (SUBREG_REG (x), in_code); + if (GET_CODE (tem) != GET_CODE (SUBREG_REG (x)) + && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (tem)) + && subreg_lowpart_p (x)) + { + rtx newer = force_to_mode (tem, mode, + GET_MODE_MASK (mode), NULL_RTX, 0); + + /* If we have something other than a SUBREG, we might have + done an expansion, so rerun outselves. */ + if (GET_CODE (newer) != SUBREG) + newer = make_compound_operation (newer, in_code); + + return newer; + } + + /* If this is a paradoxical subreg, and the new code is a sign or + zero extension, omit the subreg and widen the extension. If it + is a regular subreg, we can still get rid of the subreg by not + widening so much, or in fact removing the extension entirely. */ + if ((GET_CODE (tem) == SIGN_EXTEND + || GET_CODE (tem) == ZERO_EXTEND) + && subreg_lowpart_p (x)) + { + if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (tem)) + || (GET_MODE_SIZE (mode) > + GET_MODE_SIZE (GET_MODE (XEXP (tem, 0))))) + tem = gen_rtx_combine (GET_CODE (tem), mode, XEXP (tem, 0)); + else + tem = gen_lowpart_for_combine (mode, XEXP (tem, 0)); + return tem; + } + break; + + default: + break; + } + + if (new) + { + x = gen_lowpart_for_combine (mode, new); + code = GET_CODE (x); + } + + /* Now recursively process each operand of this operation. */ + fmt = GET_RTX_FORMAT (code); + for (i = 0; i < GET_RTX_LENGTH (code); i++) + if (fmt[i] == 'e') + { + new = make_compound_operation (XEXP (x, i), next_code); + SUBST (XEXP (x, i), new); + } + + return x; +} + +/* Given M see if it is a value that would select a field of bits + within an item, but not the entire word. Return -1 if not. + Otherwise, return the starting position of the field, where 0 is the + low-order bit. + + *PLEN is set to the length of the field. */ + +static int +get_pos_from_mask (m, plen) + unsigned HOST_WIDE_INT m; + int *plen; +{ + /* Get the bit number of the first 1 bit from the right, -1 if none. */ + int pos = exact_log2 (m & - m); + + if (pos < 0) + return -1; + + /* Now shift off the low-order zero bits and see if we have a power of + two minus 1. */ + *plen = exact_log2 ((m >> pos) + 1); + + if (*plen <= 0) + return -1; + + return pos; +} + +/* See if X can be simplified knowing that we will only refer to it in + MODE and will only refer to those bits that are nonzero in MASK. + If other bits are being computed or if masking operations are done + that select a superset of the bits in MASK, they can sometimes be + ignored. + + Return a possibly simplified expression, but always convert X to + MODE. If X is a CONST_INT, AND the CONST_INT with MASK. + + Also, if REG is non-zero and X is a register equal in value to REG, + replace X with REG. + + If JUST_SELECT is nonzero, don't optimize by noticing that bits in MASK + are all off in X. This is used when X will be complemented, by either + NOT, NEG, or XOR. */ + +static rtx +force_to_mode (x, mode, mask, reg, just_select) + rtx x; + enum machine_mode mode; + unsigned HOST_WIDE_INT mask; + rtx reg; + int just_select; +{ + enum rtx_code code = GET_CODE (x); + int next_select = just_select || code == XOR || code == NOT || code == NEG; + enum machine_mode op_mode; + unsigned HOST_WIDE_INT fuller_mask, nonzero; + rtx op0, op1, temp; + + /* If this is a CALL or ASM_OPERANDS, don't do anything. Some of the + code below will do the wrong thing since the mode of such an + expression is VOIDmode. + + Also do nothing if X is a CLOBBER; this can happen if X was + the return value from a call to gen_lowpart_for_combine. */ + if (code == CALL || code == ASM_OPERANDS || code == CLOBBER) + return x; + + /* We want to perform the operation is its present mode unless we know + that the operation is valid in MODE, in which case we do the operation + in MODE. */ + op_mode = ((GET_MODE_CLASS (mode) == GET_MODE_CLASS (GET_MODE (x)) + && code_to_optab[(int) code] != 0 + && (code_to_optab[(int) code]->handlers[(int) mode].insn_code + != CODE_FOR_nothing)) + ? mode : GET_MODE (x)); + + /* It is not valid to do a right-shift in a narrower mode + than the one it came in with. */ + if ((code == LSHIFTRT || code == ASHIFTRT) + && GET_MODE_BITSIZE (mode) < GET_MODE_BITSIZE (GET_MODE (x))) + op_mode = GET_MODE (x); + + /* Truncate MASK to fit OP_MODE. */ + if (op_mode) + mask &= GET_MODE_MASK (op_mode); + + /* When we have an arithmetic operation, or a shift whose count we + do not know, we need to assume that all bit the up to the highest-order + bit in MASK will be needed. This is how we form such a mask. */ + if (op_mode) + fuller_mask = (GET_MODE_BITSIZE (op_mode) >= HOST_BITS_PER_WIDE_INT + ? GET_MODE_MASK (op_mode) + : ((HOST_WIDE_INT) 1 << (floor_log2 (mask) + 1)) - 1); + else + fuller_mask = ~ (HOST_WIDE_INT) 0; + + /* Determine what bits of X are guaranteed to be (non)zero. */ + nonzero = nonzero_bits (x, mode); + + /* If none of the bits in X are needed, return a zero. */ + if (! just_select && (nonzero & mask) == 0) + return const0_rtx; + + /* If X is a CONST_INT, return a new one. Do this here since the + test below will fail. */ + if (GET_CODE (x) == CONST_INT) + { + HOST_WIDE_INT cval = INTVAL (x) & mask; + int width = GET_MODE_BITSIZE (mode); + + /* If MODE is narrower that HOST_WIDE_INT and CVAL is a negative + number, sign extend it. */ + if (width > 0 && width < HOST_BITS_PER_WIDE_INT + && (cval & ((HOST_WIDE_INT) 1 << (width - 1))) != 0) + cval |= (HOST_WIDE_INT) -1 << width; + + return GEN_INT (cval); + } + + /* If X is narrower than MODE and we want all the bits in X's mode, just + get X in the proper mode. */ + if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode) + && (GET_MODE_MASK (GET_MODE (x)) & ~ mask) == 0) + return gen_lowpart_for_combine (mode, x); + + /* If we aren't changing the mode, X is not a SUBREG, and all zero bits in + MASK are already known to be zero in X, we need not do anything. */ + if (GET_MODE (x) == mode && code != SUBREG && (~ mask & nonzero) == 0) + return x; + + switch (code) + { + case CLOBBER: + /* If X is a (clobber (const_int)), return it since we know we are + generating something that won't match. */ + return x; + + case USE: + /* X is a (use (mem ..)) that was made from a bit-field extraction that + spanned the boundary of the MEM. If we are now masking so it is + within that boundary, we don't need the USE any more. */ + if (! BITS_BIG_ENDIAN + && (mask & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0) + return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select); + break; + + case SIGN_EXTEND: + case ZERO_EXTEND: + case ZERO_EXTRACT: + case SIGN_EXTRACT: + x = expand_compound_operation (x); + if (GET_CODE (x) != code) + return force_to_mode (x, mode, mask, reg, next_select); + break; + + case REG: + if (reg != 0 && (rtx_equal_p (get_last_value (reg), x) + || rtx_equal_p (reg, get_last_value (x)))) + x = reg; + break; + + case SUBREG: + if (subreg_lowpart_p (x) + /* We can ignore the effect of this SUBREG if it narrows the mode or + if the constant masks to zero all the bits the mode doesn't + have. */ + && ((GET_MODE_SIZE (GET_MODE (x)) + < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) + || (0 == (mask + & GET_MODE_MASK (GET_MODE (x)) + & ~ GET_MODE_MASK (GET_MODE (SUBREG_REG (x))))))) + return force_to_mode (SUBREG_REG (x), mode, mask, reg, next_select); + break; + + case AND: + /* If this is an AND with a constant, convert it into an AND + whose constant is the AND of that constant with MASK. If it + remains an AND of MASK, delete it since it is redundant. */ + + if (GET_CODE (XEXP (x, 1)) == CONST_INT) + { + x = simplify_and_const_int (x, op_mode, XEXP (x, 0), + mask & INTVAL (XEXP (x, 1))); + + /* If X is still an AND, see if it is an AND with a mask that + is just some low-order bits. If so, and it is MASK, we don't + need it. */ + + if (GET_CODE (x) == AND && GET_CODE (XEXP (x, 1)) == CONST_INT + && (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) == mask) + x = XEXP (x, 0); + + /* If it remains an AND, try making another AND with the bits + in the mode mask that aren't in MASK turned on. If the + constant in the AND is wide enough, this might make a + cheaper constant. */ + + if (GET_CODE (x) == AND && GET_CODE (XEXP (x, 1)) == CONST_INT + && GET_MODE_MASK (GET_MODE (x)) != mask + && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT) + { + HOST_WIDE_INT cval = (INTVAL (XEXP (x, 1)) + | (GET_MODE_MASK (GET_MODE (x)) & ~ mask)); + int width = GET_MODE_BITSIZE (GET_MODE (x)); + rtx y; + + /* If MODE is narrower that HOST_WIDE_INT and CVAL is a negative + number, sign extend it. */ + if (width > 0 && width < HOST_BITS_PER_WIDE_INT + && (cval & ((HOST_WIDE_INT) 1 << (width - 1))) != 0) + cval |= (HOST_WIDE_INT) -1 << width; + + y = gen_binary (AND, GET_MODE (x), XEXP (x, 0), GEN_INT (cval)); + if (rtx_cost (y, SET) < rtx_cost (x, SET)) + x = y; + } + + break; + } + + goto binop; + + case PLUS: + /* In (and (plus FOO C1) M), if M is a mask that just turns off + low-order bits (as in an alignment operation) and FOO is already + aligned to that boundary, mask C1 to that boundary as well. + This may eliminate that PLUS and, later, the AND. */ + + { + int width = GET_MODE_BITSIZE (mode); + unsigned HOST_WIDE_INT smask = mask; + + /* If MODE is narrower than HOST_WIDE_INT and mask is a negative + number, sign extend it. */ + + if (width < HOST_BITS_PER_WIDE_INT + && (smask & ((HOST_WIDE_INT) 1 << (width - 1))) != 0) + smask |= (HOST_WIDE_INT) -1 << width; + + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && exact_log2 (- smask) >= 0) + { +#ifdef STACK_BIAS + if (STACK_BIAS + && (XEXP (x, 0) == stack_pointer_rtx + || XEXP (x, 0) == frame_pointer_rtx)) + { + int sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT; + unsigned HOST_WIDE_INT sp_mask = GET_MODE_MASK (mode); + + sp_mask &= ~ (sp_alignment - 1); + if ((sp_mask & ~ mask) == 0 + && ((INTVAL (XEXP (x, 1)) - STACK_BIAS) & ~ mask) != 0) + return force_to_mode (plus_constant (XEXP (x, 0), + ((INTVAL (XEXP (x, 1)) - + STACK_BIAS) & mask) + + STACK_BIAS), + mode, mask, reg, next_select); + } +#endif + if ((nonzero_bits (XEXP (x, 0), mode) & ~ mask) == 0 + && (INTVAL (XEXP (x, 1)) & ~ mask) != 0) + return force_to_mode (plus_constant (XEXP (x, 0), + INTVAL (XEXP (x, 1)) & mask), + mode, mask, reg, next_select); + } + } + + /* ... fall through ... */ + + case MINUS: + case MULT: + /* For PLUS, MINUS and MULT, we need any bits less significant than the + most significant bit in MASK since carries from those bits will + affect the bits we are interested in. */ + mask = fuller_mask; + goto binop; + + case IOR: + case XOR: + /* If X is (ior (lshiftrt FOO C1) C2), try to commute the IOR and + LSHIFTRT so we end up with an (and (lshiftrt (ior ...) ...) ...) + operation which may be a bitfield extraction. Ensure that the + constant we form is not wider than the mode of X. */ + + if (GET_CODE (XEXP (x, 0)) == LSHIFTRT + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && INTVAL (XEXP (XEXP (x, 0), 1)) >= 0 + && INTVAL (XEXP (XEXP (x, 0), 1)) < HOST_BITS_PER_WIDE_INT + && GET_CODE (XEXP (x, 1)) == CONST_INT + && ((INTVAL (XEXP (XEXP (x, 0), 1)) + + floor_log2 (INTVAL (XEXP (x, 1)))) + < GET_MODE_BITSIZE (GET_MODE (x))) + && (INTVAL (XEXP (x, 1)) + & ~ nonzero_bits (XEXP (x, 0), GET_MODE (x))) == 0) + { + temp = GEN_INT ((INTVAL (XEXP (x, 1)) & mask) + << INTVAL (XEXP (XEXP (x, 0), 1))); + temp = gen_binary (GET_CODE (x), GET_MODE (x), + XEXP (XEXP (x, 0), 0), temp); + x = gen_binary (LSHIFTRT, GET_MODE (x), temp, + XEXP (XEXP (x, 0), 1)); + return force_to_mode (x, mode, mask, reg, next_select); + } + + binop: + /* For most binary operations, just propagate into the operation and + change the mode if we have an operation of that mode. */ + + op0 = gen_lowpart_for_combine (op_mode, + force_to_mode (XEXP (x, 0), mode, mask, + reg, next_select)); + op1 = gen_lowpart_for_combine (op_mode, + force_to_mode (XEXP (x, 1), mode, mask, + reg, next_select)); + + /* If OP1 is a CONST_INT and X is an IOR or XOR, clear bits outside + MASK since OP1 might have been sign-extended but we never want + to turn on extra bits, since combine might have previously relied + on them being off. */ + if (GET_CODE (op1) == CONST_INT && (code == IOR || code == XOR) + && (INTVAL (op1) & mask) != 0) + op1 = GEN_INT (INTVAL (op1) & mask); + + if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0) || op1 != XEXP (x, 1)) + x = gen_binary (code, op_mode, op0, op1); + break; + + case ASHIFT: + /* For left shifts, do the same, but just for the first operand. + However, we cannot do anything with shifts where we cannot + guarantee that the counts are smaller than the size of the mode + because such a count will have a different meaning in a + wider mode. */ + + if (! (GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) >= 0 + && INTVAL (XEXP (x, 1)) < GET_MODE_BITSIZE (mode)) + && ! (GET_MODE (XEXP (x, 1)) != VOIDmode + && (nonzero_bits (XEXP (x, 1), GET_MODE (XEXP (x, 1))) + < (unsigned HOST_WIDE_INT) GET_MODE_BITSIZE (mode)))) + break; + + /* If the shift count is a constant and we can do arithmetic in + the mode of the shift, refine which bits we need. Otherwise, use the + conservative form of the mask. */ + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) >= 0 + && INTVAL (XEXP (x, 1)) < GET_MODE_BITSIZE (op_mode) + && GET_MODE_BITSIZE (op_mode) <= HOST_BITS_PER_WIDE_INT) + mask >>= INTVAL (XEXP (x, 1)); + else + mask = fuller_mask; + + op0 = gen_lowpart_for_combine (op_mode, + force_to_mode (XEXP (x, 0), op_mode, + mask, reg, next_select)); + + if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0)) + x = gen_binary (code, op_mode, op0, XEXP (x, 1)); + break; + + case LSHIFTRT: + /* Here we can only do something if the shift count is a constant, + this shift constant is valid for the host, and we can do arithmetic + in OP_MODE. */ + + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT + && GET_MODE_BITSIZE (op_mode) <= HOST_BITS_PER_WIDE_INT) + { + rtx inner = XEXP (x, 0); + + /* Select the mask of the bits we need for the shift operand. */ + mask <<= INTVAL (XEXP (x, 1)); + + /* We can only change the mode of the shift if we can do arithmetic + in the mode of the shift and MASK is no wider than the width of + OP_MODE. */ + if (GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT + || (mask & ~ GET_MODE_MASK (op_mode)) != 0) + op_mode = GET_MODE (x); + + inner = force_to_mode (inner, op_mode, mask, reg, next_select); + + if (GET_MODE (x) != op_mode || inner != XEXP (x, 0)) + x = gen_binary (LSHIFTRT, op_mode, inner, XEXP (x, 1)); + } + + /* If we have (and (lshiftrt FOO C1) C2) where the combination of the + shift and AND produces only copies of the sign bit (C2 is one less + than a power of two), we can do this with just a shift. */ + + if (GET_CODE (x) == LSHIFTRT + && GET_CODE (XEXP (x, 1)) == CONST_INT + && ((INTVAL (XEXP (x, 1)) + + num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0)))) + >= GET_MODE_BITSIZE (GET_MODE (x))) + && exact_log2 (mask + 1) >= 0 + && (num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0))) + >= exact_log2 (mask + 1))) + x = gen_binary (LSHIFTRT, GET_MODE (x), XEXP (x, 0), + GEN_INT (GET_MODE_BITSIZE (GET_MODE (x)) + - exact_log2 (mask + 1))); + break; + + case ASHIFTRT: + /* If we are just looking for the sign bit, we don't need this shift at + all, even if it has a variable count. */ + if (GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT + && (mask == ((unsigned HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (GET_MODE (x)) - 1)))) + return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select); + + /* If this is a shift by a constant, get a mask that contains those bits + that are not copies of the sign bit. We then have two cases: If + MASK only includes those bits, this can be a logical shift, which may + allow simplifications. If MASK is a single-bit field not within + those bits, we are requesting a copy of the sign bit and hence can + shift the sign bit to the appropriate location. */ + + if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0 + && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT) + { + int i = -1; + + /* If the considered data is wider then HOST_WIDE_INT, we can't + represent a mask for all its bits in a single scalar. + But we only care about the lower bits, so calculate these. */ + + if (GET_MODE_BITSIZE (GET_MODE (x)) > HOST_BITS_PER_WIDE_INT) + { + nonzero = ~ (HOST_WIDE_INT) 0; + + /* GET_MODE_BITSIZE (GET_MODE (x)) - INTVAL (XEXP (x, 1)) + is the number of bits a full-width mask would have set. + We need only shift if these are fewer than nonzero can + hold. If not, we must keep all bits set in nonzero. */ + + if (GET_MODE_BITSIZE (GET_MODE (x)) - INTVAL (XEXP (x, 1)) + < HOST_BITS_PER_WIDE_INT) + nonzero >>= INTVAL (XEXP (x, 1)) + + HOST_BITS_PER_WIDE_INT + - GET_MODE_BITSIZE (GET_MODE (x)) ; + } + else + { + nonzero = GET_MODE_MASK (GET_MODE (x)); + nonzero >>= INTVAL (XEXP (x, 1)); + } + + if ((mask & ~ nonzero) == 0 + || (i = exact_log2 (mask)) >= 0) + { + x = simplify_shift_const + (x, LSHIFTRT, GET_MODE (x), XEXP (x, 0), + i < 0 ? INTVAL (XEXP (x, 1)) + : GET_MODE_BITSIZE (GET_MODE (x)) - 1 - i); + + if (GET_CODE (x) != ASHIFTRT) + return force_to_mode (x, mode, mask, reg, next_select); + } + } + + /* If MASK is 1, convert this to a LSHIFTRT. This can be done + even if the shift count isn't a constant. */ + if (mask == 1) + x = gen_binary (LSHIFTRT, GET_MODE (x), XEXP (x, 0), XEXP (x, 1)); + + /* If this is a sign-extension operation that just affects bits + we don't care about, remove it. Be sure the call above returned + something that is still a shift. */ + + if ((GET_CODE (x) == LSHIFTRT || GET_CODE (x) == ASHIFTRT) + && GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) >= 0 + && (INTVAL (XEXP (x, 1)) + <= GET_MODE_BITSIZE (GET_MODE (x)) - (floor_log2 (mask) + 1)) + && GET_CODE (XEXP (x, 0)) == ASHIFT + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && INTVAL (XEXP (XEXP (x, 0), 1)) == INTVAL (XEXP (x, 1))) + return force_to_mode (XEXP (XEXP (x, 0), 0), mode, mask, + reg, next_select); + + break; + + case ROTATE: + case ROTATERT: + /* If the shift count is constant and we can do computations + in the mode of X, compute where the bits we care about are. + Otherwise, we can't do anything. Don't change the mode of + the shift or propagate MODE into the shift, though. */ + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) >= 0) + { + temp = simplify_binary_operation (code == ROTATE ? ROTATERT : ROTATE, + GET_MODE (x), GEN_INT (mask), + XEXP (x, 1)); + if (temp && GET_CODE(temp) == CONST_INT) + SUBST (XEXP (x, 0), + force_to_mode (XEXP (x, 0), GET_MODE (x), + INTVAL (temp), reg, next_select)); + } + break; + + case NEG: + /* If we just want the low-order bit, the NEG isn't needed since it + won't change the low-order bit. */ + if (mask == 1) + return force_to_mode (XEXP (x, 0), mode, mask, reg, just_select); + + /* We need any bits less significant than the most significant bit in + MASK since carries from those bits will affect the bits we are + interested in. */ + mask = fuller_mask; + goto unop; + + case NOT: + /* (not FOO) is (xor FOO CONST), so if FOO is an LSHIFTRT, we can do the + same as the XOR case above. Ensure that the constant we form is not + wider than the mode of X. */ + + if (GET_CODE (XEXP (x, 0)) == LSHIFTRT + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && INTVAL (XEXP (XEXP (x, 0), 1)) >= 0 + && (INTVAL (XEXP (XEXP (x, 0), 1)) + floor_log2 (mask) + < GET_MODE_BITSIZE (GET_MODE (x))) + && INTVAL (XEXP (XEXP (x, 0), 1)) < HOST_BITS_PER_WIDE_INT) + { + temp = GEN_INT (mask << INTVAL (XEXP (XEXP (x, 0), 1))); + temp = gen_binary (XOR, GET_MODE (x), XEXP (XEXP (x, 0), 0), temp); + x = gen_binary (LSHIFTRT, GET_MODE (x), temp, XEXP (XEXP (x, 0), 1)); + + return force_to_mode (x, mode, mask, reg, next_select); + } + + /* (and (not FOO) CONST) is (not (or FOO (not CONST))), so we must + use the full mask inside the NOT. */ + mask = fuller_mask; + + unop: + op0 = gen_lowpart_for_combine (op_mode, + force_to_mode (XEXP (x, 0), mode, mask, + reg, next_select)); + if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0)) + x = gen_unary (code, op_mode, op_mode, op0); + break; + + case NE: + /* (and (ne FOO 0) CONST) can be (and FOO CONST) if CONST is included + in STORE_FLAG_VALUE and FOO has a single bit that might be nonzero, + which is equal to STORE_FLAG_VALUE. */ + if ((mask & ~ STORE_FLAG_VALUE) == 0 && XEXP (x, 1) == const0_rtx + && exact_log2 (nonzero_bits (XEXP (x, 0), mode)) >= 0 + && nonzero_bits (XEXP (x, 0), mode) == STORE_FLAG_VALUE) + return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select); + + break; + + case IF_THEN_ELSE: + /* We have no way of knowing if the IF_THEN_ELSE can itself be + written in a narrower mode. We play it safe and do not do so. */ + + SUBST (XEXP (x, 1), + gen_lowpart_for_combine (GET_MODE (x), + force_to_mode (XEXP (x, 1), mode, + mask, reg, next_select))); + SUBST (XEXP (x, 2), + gen_lowpart_for_combine (GET_MODE (x), + force_to_mode (XEXP (x, 2), mode, + mask, reg,next_select))); + break; + + default: + break; + } + + /* Ensure we return a value of the proper mode. */ + return gen_lowpart_for_combine (mode, x); +} + +/* Return nonzero if X is an expression that has one of two values depending on + whether some other value is zero or nonzero. In that case, we return the + value that is being tested, *PTRUE is set to the value if the rtx being + returned has a nonzero value, and *PFALSE is set to the other alternative. + + If we return zero, we set *PTRUE and *PFALSE to X. */ + +static rtx +if_then_else_cond (x, ptrue, pfalse) + rtx x; + rtx *ptrue, *pfalse; +{ + enum machine_mode mode = GET_MODE (x); + enum rtx_code code = GET_CODE (x); + int size = GET_MODE_BITSIZE (mode); + rtx cond0, cond1, true0, true1, false0, false1; + unsigned HOST_WIDE_INT nz; + + /* If this is a unary operation whose operand has one of two values, apply + our opcode to compute those values. */ + if (GET_RTX_CLASS (code) == '1' + && (cond0 = if_then_else_cond (XEXP (x, 0), &true0, &false0)) != 0) + { + *ptrue = gen_unary (code, mode, GET_MODE (XEXP (x, 0)), true0); + *pfalse = gen_unary (code, mode, GET_MODE (XEXP (x, 0)), false0); + return cond0; + } + + /* If this is a COMPARE, do nothing, since the IF_THEN_ELSE we would + make can't possibly match and would suppress other optimizations. */ + else if (code == COMPARE) + ; + + /* If this is a binary operation, see if either side has only one of two + values. If either one does or if both do and they are conditional on + the same value, compute the new true and false values. */ + else if (GET_RTX_CLASS (code) == 'c' || GET_RTX_CLASS (code) == '2' + || GET_RTX_CLASS (code) == '<') + { + cond0 = if_then_else_cond (XEXP (x, 0), &true0, &false0); + cond1 = if_then_else_cond (XEXP (x, 1), &true1, &false1); + + if ((cond0 != 0 || cond1 != 0) + && ! (cond0 != 0 && cond1 != 0 && ! rtx_equal_p (cond0, cond1))) + { + /* If if_then_else_cond returned zero, then true/false are the + same rtl. We must copy one of them to prevent invalid rtl + sharing. */ + if (cond0 == 0) + true0 = copy_rtx (true0); + else if (cond1 == 0) + true1 = copy_rtx (true1); + + *ptrue = gen_binary (code, mode, true0, true1); + *pfalse = gen_binary (code, mode, false0, false1); + return cond0 ? cond0 : cond1; + } + + /* See if we have PLUS, IOR, XOR, MINUS or UMAX, where one of the + operands is zero when the other is non-zero, and vice-versa, + and STORE_FLAG_VALUE is 1 or -1. */ + + if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1) + && (code == PLUS || code == IOR || code == XOR || code == MINUS + || code == UMAX) + && GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == MULT) + { + rtx op0 = XEXP (XEXP (x, 0), 1); + rtx op1 = XEXP (XEXP (x, 1), 1); + + cond0 = XEXP (XEXP (x, 0), 0); + cond1 = XEXP (XEXP (x, 1), 0); + + if (GET_RTX_CLASS (GET_CODE (cond0)) == '<' + && GET_RTX_CLASS (GET_CODE (cond1)) == '<' + && reversible_comparison_p (cond1) + && ((GET_CODE (cond0) == reverse_condition (GET_CODE (cond1)) + && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 0)) + && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 1))) + || ((swap_condition (GET_CODE (cond0)) + == reverse_condition (GET_CODE (cond1))) + && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 1)) + && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 0)))) + && ! side_effects_p (x)) + { + *ptrue = gen_binary (MULT, mode, op0, const_true_rtx); + *pfalse = gen_binary (MULT, mode, + (code == MINUS + ? gen_unary (NEG, mode, mode, op1) : op1), + const_true_rtx); + return cond0; + } + } + + /* Similarly for MULT, AND and UMIN, execpt that for these the result + is always zero. */ + if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1) + && (code == MULT || code == AND || code == UMIN) + && GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == MULT) + { + cond0 = XEXP (XEXP (x, 0), 0); + cond1 = XEXP (XEXP (x, 1), 0); + + if (GET_RTX_CLASS (GET_CODE (cond0)) == '<' + && GET_RTX_CLASS (GET_CODE (cond1)) == '<' + && reversible_comparison_p (cond1) + && ((GET_CODE (cond0) == reverse_condition (GET_CODE (cond1)) + && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 0)) + && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 1))) + || ((swap_condition (GET_CODE (cond0)) + == reverse_condition (GET_CODE (cond1))) + && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 1)) + && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 0)))) + && ! side_effects_p (x)) + { + *ptrue = *pfalse = const0_rtx; + return cond0; + } + } + } + + else if (code == IF_THEN_ELSE) + { + /* If we have IF_THEN_ELSE already, extract the condition and + canonicalize it if it is NE or EQ. */ + cond0 = XEXP (x, 0); + *ptrue = XEXP (x, 1), *pfalse = XEXP (x, 2); + if (GET_CODE (cond0) == NE && XEXP (cond0, 1) == const0_rtx) + return XEXP (cond0, 0); + else if (GET_CODE (cond0) == EQ && XEXP (cond0, 1) == const0_rtx) + { + *ptrue = XEXP (x, 2), *pfalse = XEXP (x, 1); + return XEXP (cond0, 0); + } + else + return cond0; + } + + /* If X is a normal SUBREG with both inner and outer modes integral, + we can narrow both the true and false values of the inner expression, + if there is a condition. */ + else if (code == SUBREG && GET_MODE_CLASS (mode) == MODE_INT + && GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_INT + && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) + && 0 != (cond0 = if_then_else_cond (SUBREG_REG (x), + &true0, &false0))) + { + *ptrue = force_to_mode (true0, mode, GET_MODE_MASK (mode), NULL_RTX, 0); + *pfalse + = force_to_mode (false0, mode, GET_MODE_MASK (mode), NULL_RTX, 0); + + return cond0; + } + + /* If X is a constant, this isn't special and will cause confusions + if we treat it as such. Likewise if it is equivalent to a constant. */ + else if (CONSTANT_P (x) + || ((cond0 = get_last_value (x)) != 0 && CONSTANT_P (cond0))) + ; + + /* If X is known to be either 0 or -1, those are the true and + false values when testing X. */ + else if (num_sign_bit_copies (x, mode) == size) + { + *ptrue = constm1_rtx, *pfalse = const0_rtx; + return x; + } + + /* Likewise for 0 or a single bit. */ + else if (exact_log2 (nz = nonzero_bits (x, mode)) >= 0) + { + *ptrue = GEN_INT (nz), *pfalse = const0_rtx; + return x; + } + + /* Otherwise fail; show no condition with true and false values the same. */ + *ptrue = *pfalse = x; + return 0; +} + +/* Return the value of expression X given the fact that condition COND + is known to be true when applied to REG as its first operand and VAL + as its second. X is known to not be shared and so can be modified in + place. + + We only handle the simplest cases, and specifically those cases that + arise with IF_THEN_ELSE expressions. */ + +static rtx +known_cond (x, cond, reg, val) + rtx x; + enum rtx_code cond; + rtx reg, val; +{ + enum rtx_code code = GET_CODE (x); + rtx temp; + char *fmt; + int i, j; + + if (side_effects_p (x)) + return x; + + if (cond == EQ && rtx_equal_p (x, reg)) + return val; + + /* If X is (abs REG) and we know something about REG's relationship + with zero, we may be able to simplify this. */ + + if (code == ABS && rtx_equal_p (XEXP (x, 0), reg) && val == const0_rtx) + switch (cond) + { + case GE: case GT: case EQ: + return XEXP (x, 0); + case LT: case LE: + return gen_unary (NEG, GET_MODE (XEXP (x, 0)), GET_MODE (XEXP (x, 0)), + XEXP (x, 0)); + default: + break; + } + + /* The only other cases we handle are MIN, MAX, and comparisons if the + operands are the same as REG and VAL. */ + + else if (GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == 'c') + { + if (rtx_equal_p (XEXP (x, 0), val)) + cond = swap_condition (cond), temp = val, val = reg, reg = temp; + + if (rtx_equal_p (XEXP (x, 0), reg) && rtx_equal_p (XEXP (x, 1), val)) + { + if (GET_RTX_CLASS (code) == '<') + return (comparison_dominates_p (cond, code) ? const_true_rtx + : (comparison_dominates_p (cond, + reverse_condition (code)) + ? const0_rtx : x)); + + else if (code == SMAX || code == SMIN + || code == UMIN || code == UMAX) + { + int unsignedp = (code == UMIN || code == UMAX); + + if (code == SMAX || code == UMAX) + cond = reverse_condition (cond); + + switch (cond) + { + case GE: case GT: + return unsignedp ? x : XEXP (x, 1); + case LE: case LT: + return unsignedp ? x : XEXP (x, 0); + case GEU: case GTU: + return unsignedp ? XEXP (x, 1) : x; + case LEU: case LTU: + return unsignedp ? XEXP (x, 0) : x; + default: + break; + } + } + } + } + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + SUBST (XEXP (x, i), known_cond (XEXP (x, i), cond, reg, val)); + else if (fmt[i] == 'E') + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + SUBST (XVECEXP (x, i, j), known_cond (XVECEXP (x, i, j), + cond, reg, val)); + } + + return x; +} + +/* See if X and Y are equal for the purposes of seeing if we can rewrite an + assignment as a field assignment. */ + +static int +rtx_equal_for_field_assignment_p (x, y) + rtx x; + rtx y; +{ + if (x == y || rtx_equal_p (x, y)) + return 1; + + if (x == 0 || y == 0 || GET_MODE (x) != GET_MODE (y)) + return 0; + + /* Check for a paradoxical SUBREG of a MEM compared with the MEM. + Note that all SUBREGs of MEM are paradoxical; otherwise they + would have been rewritten. */ + if (GET_CODE (x) == MEM && GET_CODE (y) == SUBREG + && GET_CODE (SUBREG_REG (y)) == MEM + && rtx_equal_p (SUBREG_REG (y), + gen_lowpart_for_combine (GET_MODE (SUBREG_REG (y)), x))) + return 1; + + if (GET_CODE (y) == MEM && GET_CODE (x) == SUBREG + && GET_CODE (SUBREG_REG (x)) == MEM + && rtx_equal_p (SUBREG_REG (x), + gen_lowpart_for_combine (GET_MODE (SUBREG_REG (x)), y))) + return 1; + + /* We used to see if get_last_value of X and Y were the same but that's + not correct. In one direction, we'll cause the assignment to have + the wrong destination and in the case, we'll import a register into this + insn that might have already have been dead. So fail if none of the + above cases are true. */ + return 0; +} + +/* See if X, a SET operation, can be rewritten as a bit-field assignment. + Return that assignment if so. + + We only handle the most common cases. */ + +static rtx +make_field_assignment (x) + rtx x; +{ + rtx dest = SET_DEST (x); + rtx src = SET_SRC (x); + rtx assign; + rtx rhs, lhs; + HOST_WIDE_INT c1; + int pos, len; + rtx other; + enum machine_mode mode; + + /* If SRC was (and (not (ashift (const_int 1) POS)) DEST), this is + a clear of a one-bit field. We will have changed it to + (and (rotate (const_int -2) POS) DEST), so check for that. Also check + for a SUBREG. */ + + if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == ROTATE + && GET_CODE (XEXP (XEXP (src, 0), 0)) == CONST_INT + && INTVAL (XEXP (XEXP (src, 0), 0)) == -2 + && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1))) + { + assign = make_extraction (VOIDmode, dest, 0, XEXP (XEXP (src, 0), 1), + 1, 1, 1, 0); + if (assign != 0) + return gen_rtx_SET (VOIDmode, assign, const0_rtx); + return x; + } + + else if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == SUBREG + && subreg_lowpart_p (XEXP (src, 0)) + && (GET_MODE_SIZE (GET_MODE (XEXP (src, 0))) + < GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (src, 0))))) + && GET_CODE (SUBREG_REG (XEXP (src, 0))) == ROTATE + && INTVAL (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == -2 + && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1))) + { + assign = make_extraction (VOIDmode, dest, 0, + XEXP (SUBREG_REG (XEXP (src, 0)), 1), + 1, 1, 1, 0); + if (assign != 0) + return gen_rtx_SET (VOIDmode, assign, const0_rtx); + return x; + } + + /* If SRC is (ior (ashift (const_int 1) POS) DEST), this is a set of a + one-bit field. */ + else if (GET_CODE (src) == IOR && GET_CODE (XEXP (src, 0)) == ASHIFT + && XEXP (XEXP (src, 0), 0) == const1_rtx + && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1))) + { + assign = make_extraction (VOIDmode, dest, 0, XEXP (XEXP (src, 0), 1), + 1, 1, 1, 0); + if (assign != 0) + return gen_rtx_SET (VOIDmode, assign, const1_rtx); + return x; + } + + /* The other case we handle is assignments into a constant-position + field. They look like (ior/xor (and DEST C1) OTHER). If C1 represents + a mask that has all one bits except for a group of zero bits and + OTHER is known to have zeros where C1 has ones, this is such an + assignment. Compute the position and length from C1. Shift OTHER + to the appropriate position, force it to the required mode, and + make the extraction. Check for the AND in both operands. */ + + if (GET_CODE (src) != IOR && GET_CODE (src) != XOR) + return x; + + rhs = expand_compound_operation (XEXP (src, 0)); + lhs = expand_compound_operation (XEXP (src, 1)); + + if (GET_CODE (rhs) == AND + && GET_CODE (XEXP (rhs, 1)) == CONST_INT + && rtx_equal_for_field_assignment_p (XEXP (rhs, 0), dest)) + c1 = INTVAL (XEXP (rhs, 1)), other = lhs; + else if (GET_CODE (lhs) == AND + && GET_CODE (XEXP (lhs, 1)) == CONST_INT + && rtx_equal_for_field_assignment_p (XEXP (lhs, 0), dest)) + c1 = INTVAL (XEXP (lhs, 1)), other = rhs; + else + return x; + + pos = get_pos_from_mask ((~ c1) & GET_MODE_MASK (GET_MODE (dest)), &len); + if (pos < 0 || pos + len > GET_MODE_BITSIZE (GET_MODE (dest)) + || GET_MODE_BITSIZE (GET_MODE (dest)) > HOST_BITS_PER_WIDE_INT + || (c1 & nonzero_bits (other, GET_MODE (dest))) != 0) + return x; + + assign = make_extraction (VOIDmode, dest, pos, NULL_RTX, len, 1, 1, 0); + if (assign == 0) + return x; + + /* The mode to use for the source is the mode of the assignment, or of + what is inside a possible STRICT_LOW_PART. */ + mode = (GET_CODE (assign) == STRICT_LOW_PART + ? GET_MODE (XEXP (assign, 0)) : GET_MODE (assign)); + + /* Shift OTHER right POS places and make it the source, restricting it + to the proper length and mode. */ + + src = force_to_mode (simplify_shift_const (NULL_RTX, LSHIFTRT, + GET_MODE (src), other, pos), + mode, + GET_MODE_BITSIZE (mode) >= HOST_BITS_PER_WIDE_INT + ? GET_MODE_MASK (mode) + : ((HOST_WIDE_INT) 1 << len) - 1, + dest, 0); + + return gen_rtx_combine (SET, VOIDmode, assign, src); +} + +/* See if X is of the form (+ (* a c) (* b c)) and convert to (* (+ a b) c) + if so. */ + +static rtx +apply_distributive_law (x) + rtx x; +{ + enum rtx_code code = GET_CODE (x); + rtx lhs, rhs, other; + rtx tem; + enum rtx_code inner_code; + + /* Distributivity is not true for floating point. + It can change the value. So don't do it. + -- rms and moshier@world.std.com. */ + if (FLOAT_MODE_P (GET_MODE (x))) + return x; + + /* The outer operation can only be one of the following: */ + if (code != IOR && code != AND && code != XOR + && code != PLUS && code != MINUS) + return x; + + lhs = XEXP (x, 0), rhs = XEXP (x, 1); + + /* If either operand is a primitive we can't do anything, so get out + fast. */ + if (GET_RTX_CLASS (GET_CODE (lhs)) == 'o' + || GET_RTX_CLASS (GET_CODE (rhs)) == 'o') + return x; + + lhs = expand_compound_operation (lhs); + rhs = expand_compound_operation (rhs); + inner_code = GET_CODE (lhs); + if (inner_code != GET_CODE (rhs)) + return x; + + /* See if the inner and outer operations distribute. */ + switch (inner_code) + { + case LSHIFTRT: + case ASHIFTRT: + case AND: + case IOR: + /* These all distribute except over PLUS. */ + if (code == PLUS || code == MINUS) + return x; + break; + + case MULT: + if (code != PLUS && code != MINUS) + return x; + break; + + case ASHIFT: + /* This is also a multiply, so it distributes over everything. */ + break; + + case SUBREG: + /* Non-paradoxical SUBREGs distributes over all operations, provided + the inner modes and word numbers are the same, this is an extraction + of a low-order part, we don't convert an fp operation to int or + vice versa, and we would not be converting a single-word + operation into a multi-word operation. The latter test is not + required, but it prevents generating unneeded multi-word operations. + Some of the previous tests are redundant given the latter test, but + are retained because they are required for correctness. + + We produce the result slightly differently in this case. */ + + if (GET_MODE (SUBREG_REG (lhs)) != GET_MODE (SUBREG_REG (rhs)) + || SUBREG_WORD (lhs) != SUBREG_WORD (rhs) + || ! subreg_lowpart_p (lhs) + || (GET_MODE_CLASS (GET_MODE (lhs)) + != GET_MODE_CLASS (GET_MODE (SUBREG_REG (lhs)))) + || (GET_MODE_SIZE (GET_MODE (lhs)) + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (lhs)))) + || GET_MODE_SIZE (GET_MODE (SUBREG_REG (lhs))) > UNITS_PER_WORD) + return x; + + tem = gen_binary (code, GET_MODE (SUBREG_REG (lhs)), + SUBREG_REG (lhs), SUBREG_REG (rhs)); + return gen_lowpart_for_combine (GET_MODE (x), tem); + + default: + return x; + } + + /* Set LHS and RHS to the inner operands (A and B in the example + above) and set OTHER to the common operand (C in the example). + These is only one way to do this unless the inner operation is + commutative. */ + if (GET_RTX_CLASS (inner_code) == 'c' + && rtx_equal_p (XEXP (lhs, 0), XEXP (rhs, 0))) + other = XEXP (lhs, 0), lhs = XEXP (lhs, 1), rhs = XEXP (rhs, 1); + else if (GET_RTX_CLASS (inner_code) == 'c' + && rtx_equal_p (XEXP (lhs, 0), XEXP (rhs, 1))) + other = XEXP (lhs, 0), lhs = XEXP (lhs, 1), rhs = XEXP (rhs, 0); + else if (GET_RTX_CLASS (inner_code) == 'c' + && rtx_equal_p (XEXP (lhs, 1), XEXP (rhs, 0))) + other = XEXP (lhs, 1), lhs = XEXP (lhs, 0), rhs = XEXP (rhs, 1); + else if (rtx_equal_p (XEXP (lhs, 1), XEXP (rhs, 1))) + other = XEXP (lhs, 1), lhs = XEXP (lhs, 0), rhs = XEXP (rhs, 0); + else + return x; + + /* Form the new inner operation, seeing if it simplifies first. */ + tem = gen_binary (code, GET_MODE (x), lhs, rhs); + + /* There is one exception to the general way of distributing: + (a ^ b) | (a ^ c) -> (~a) & (b ^ c) */ + if (code == XOR && inner_code == IOR) + { + inner_code = AND; + other = gen_unary (NOT, GET_MODE (x), GET_MODE (x), other); + } + + /* We may be able to continuing distributing the result, so call + ourselves recursively on the inner operation before forming the + outer operation, which we return. */ + return gen_binary (inner_code, GET_MODE (x), + apply_distributive_law (tem), other); +} + +/* We have X, a logical `and' of VAROP with the constant CONSTOP, to be done + in MODE. + + Return an equivalent form, if different from X. Otherwise, return X. If + X is zero, we are to always construct the equivalent form. */ + +static rtx +simplify_and_const_int (x, mode, varop, constop) + rtx x; + enum machine_mode mode; + rtx varop; + unsigned HOST_WIDE_INT constop; +{ + unsigned HOST_WIDE_INT nonzero; + int width = GET_MODE_BITSIZE (mode); + int i; + + /* Simplify VAROP knowing that we will be only looking at some of the + bits in it. */ + varop = force_to_mode (varop, mode, constop, NULL_RTX, 0); + + /* If VAROP is a CLOBBER, we will fail so return it; if it is a + CONST_INT, we are done. */ + if (GET_CODE (varop) == CLOBBER || GET_CODE (varop) == CONST_INT) + return varop; + + /* See what bits may be nonzero in VAROP. Unlike the general case of + a call to nonzero_bits, here we don't care about bits outside + MODE. */ + + nonzero = nonzero_bits (varop, mode) & GET_MODE_MASK (mode); + + /* 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 later confuses the sparc backend. */ + + if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width + && (nonzero & ((HOST_WIDE_INT) 1 << (width - 1)))) + nonzero |= ((HOST_WIDE_INT) (-1) << width); + + /* Turn off all bits in the constant that are known to already be zero. + Thus, if the AND isn't needed at all, we will have CONSTOP == NONZERO_BITS + which is tested below. */ + + constop &= nonzero; + + /* If we don't have any bits left, return zero. */ + if (constop == 0) + return const0_rtx; + + /* If VAROP is a NEG of something known to be zero or 1 and CONSTOP is + a power of two, we can replace this with a ASHIFT. */ + if (GET_CODE (varop) == NEG && nonzero_bits (XEXP (varop, 0), mode) == 1 + && (i = exact_log2 (constop)) >= 0) + return simplify_shift_const (NULL_RTX, ASHIFT, mode, XEXP (varop, 0), i); + + /* If VAROP is an IOR or XOR, apply the AND to both branches of the IOR + or XOR, then try to apply the distributive law. This may eliminate + operations if either branch can be simplified because of the AND. + It may also make some cases more complex, but those cases probably + won't match a pattern either with or without this. */ + + if (GET_CODE (varop) == IOR || GET_CODE (varop) == XOR) + return + gen_lowpart_for_combine + (mode, + apply_distributive_law + (gen_binary (GET_CODE (varop), GET_MODE (varop), + simplify_and_const_int (NULL_RTX, GET_MODE (varop), + XEXP (varop, 0), constop), + simplify_and_const_int (NULL_RTX, GET_MODE (varop), + XEXP (varop, 1), constop)))); + + /* Get VAROP in MODE. Try to get a SUBREG if not. Don't make a new SUBREG + if we already had one (just check for the simplest cases). */ + if (x && GET_CODE (XEXP (x, 0)) == SUBREG + && GET_MODE (XEXP (x, 0)) == mode + && SUBREG_REG (XEXP (x, 0)) == varop) + varop = XEXP (x, 0); + else + varop = gen_lowpart_for_combine (mode, varop); + + /* If we can't make the SUBREG, try to return what we were given. */ + if (GET_CODE (varop) == CLOBBER) + return x ? x : varop; + + /* If we are only masking insignificant bits, return VAROP. */ + if (constop == nonzero) + x = varop; + + /* Otherwise, return an AND. See how much, if any, of X we can use. */ + else if (x == 0 || GET_CODE (x) != AND || GET_MODE (x) != mode) + x = gen_binary (AND, mode, varop, GEN_INT (constop)); + + else + { + if (GET_CODE (XEXP (x, 1)) != CONST_INT + || (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) != constop) + SUBST (XEXP (x, 1), GEN_INT (constop)); + + SUBST (XEXP (x, 0), varop); + } + + return x; +} + +/* We let num_sign_bit_copies recur into nonzero_bits as that is useful. + We don't let nonzero_bits recur into num_sign_bit_copies, because that + is less useful. We can't allow both, because that results in exponential + run time recursion. There is a nullstone testcase that triggered + this. This macro avoids accidental uses of num_sign_bit_copies. */ +#define num_sign_bit_copies() + +/* Given an expression, X, compute which bits in X can be non-zero. + We don't care about bits outside of those defined in MODE. + + For most X this is simply GET_MODE_MASK (GET_MODE (MODE)), but if X is + a shift, AND, or zero_extract, we can do better. */ + +static unsigned HOST_WIDE_INT +nonzero_bits (x, mode) + rtx x; + enum machine_mode mode; +{ + unsigned HOST_WIDE_INT nonzero = GET_MODE_MASK (mode); + unsigned HOST_WIDE_INT inner_nz; + enum rtx_code code; + int mode_width = GET_MODE_BITSIZE (mode); + rtx tem; + + /* For floating-point values, assume all bits are needed. */ + if (FLOAT_MODE_P (GET_MODE (x)) || FLOAT_MODE_P (mode)) + return nonzero; + + /* If X is wider than MODE, use its mode instead. */ + if (GET_MODE_BITSIZE (GET_MODE (x)) > mode_width) + { + mode = GET_MODE (x); + nonzero = GET_MODE_MASK (mode); + mode_width = GET_MODE_BITSIZE (mode); + } + + if (mode_width > HOST_BITS_PER_WIDE_INT) + /* Our only callers in this case look for single bit values. So + just return the mode mask. Those tests will then be false. */ + return nonzero; + +#ifndef WORD_REGISTER_OPERATIONS + /* If MODE is wider than X, but both are a single word for both the host + and target machines, we can compute this from which bits of the + object might be nonzero in its own mode, taking into account the fact + that on many CISC machines, accessing an object in a wider mode + causes the high-order bits to become undefined. So they are + not known to be zero. */ + + if (GET_MODE (x) != VOIDmode && GET_MODE (x) != mode + && GET_MODE_BITSIZE (GET_MODE (x)) <= BITS_PER_WORD + && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT + && GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (GET_MODE (x))) + { + nonzero &= nonzero_bits (x, GET_MODE (x)); + nonzero |= GET_MODE_MASK (mode) & ~ GET_MODE_MASK (GET_MODE (x)); + return nonzero; + } +#endif + + code = GET_CODE (x); + switch (code) + { + case REG: +#ifdef POINTERS_EXTEND_UNSIGNED + /* If pointers extend unsigned and this is a pointer in Pmode, say that + all the bits above ptr_mode are known to be zero. */ + if (POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode + && REGNO_POINTER_FLAG (REGNO (x))) + nonzero &= GET_MODE_MASK (ptr_mode); +#endif + +#ifdef STACK_BOUNDARY + /* If this is the stack pointer, we may know something about its + alignment. If PUSH_ROUNDING is defined, it is possible for the + stack to be momentarily aligned only to that amount, so we pick + the least alignment. */ + + /* We can't check for arg_pointer_rtx here, because it is not + guaranteed to have as much alignment as the stack pointer. + In particular, in the Irix6 n64 ABI, the stack has 128 bit + alignment but the argument pointer has only 64 bit alignment. */ + + if ((x == frame_pointer_rtx + || x == stack_pointer_rtx + || x == hard_frame_pointer_rtx + || (REGNO (x) >= FIRST_VIRTUAL_REGISTER + && REGNO (x) <= LAST_VIRTUAL_REGISTER)) +#ifdef STACK_BIAS + && !STACK_BIAS +#endif + ) + { + int sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT; + +#ifdef PUSH_ROUNDING + if (REGNO (x) == STACK_POINTER_REGNUM) + sp_alignment = MIN (PUSH_ROUNDING (1), sp_alignment); +#endif + + /* We must return here, otherwise we may get a worse result from + one of the choices below. There is nothing useful below as + far as the stack pointer is concerned. */ + return nonzero &= ~ (sp_alignment - 1); + } +#endif + + /* If X is a register whose nonzero bits value is current, use it. + Otherwise, if X is a register whose value we can find, use that + value. Otherwise, use the previously-computed global nonzero bits + for this register. */ + + if (reg_last_set_value[REGNO (x)] != 0 + && reg_last_set_mode[REGNO (x)] == mode + && (REG_N_SETS (REGNO (x)) == 1 + || reg_last_set_label[REGNO (x)] == label_tick) + && INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid) + return reg_last_set_nonzero_bits[REGNO (x)]; + + tem = get_last_value (x); + + if (tem) + { +#ifdef SHORT_IMMEDIATES_SIGN_EXTEND + /* If X is narrower than MODE and TEM is a non-negative + constant that would appear negative in the mode of X, + sign-extend it for use in reg_nonzero_bits because some + machines (maybe most) will actually do the sign-extension + and this is the conservative approach. + + ??? For 2.5, try to tighten up the MD files in this regard + instead of this kludge. */ + + if (GET_MODE_BITSIZE (GET_MODE (x)) < mode_width + && GET_CODE (tem) == CONST_INT + && INTVAL (tem) > 0 + && 0 != (INTVAL (tem) + & ((HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (GET_MODE (x)) - 1)))) + tem = GEN_INT (INTVAL (tem) + | ((HOST_WIDE_INT) (-1) + << GET_MODE_BITSIZE (GET_MODE (x)))); +#endif + return nonzero_bits (tem, mode); + } + else if (nonzero_sign_valid && reg_nonzero_bits[REGNO (x)]) + return reg_nonzero_bits[REGNO (x)] & nonzero; + else + return nonzero; + + case CONST_INT: +#ifdef SHORT_IMMEDIATES_SIGN_EXTEND + /* If X is negative in MODE, sign-extend the value. */ + if (INTVAL (x) > 0 && mode_width < BITS_PER_WORD + && 0 != (INTVAL (x) & ((HOST_WIDE_INT) 1 << (mode_width - 1)))) + return (INTVAL (x) | ((HOST_WIDE_INT) (-1) << mode_width)); +#endif + + return INTVAL (x); + + case MEM: +#ifdef LOAD_EXTEND_OP + /* In many, if not most, RISC machines, reading a byte from memory + zeros the rest of the register. Noticing that fact saves a lot + of extra zero-extends. */ + if (LOAD_EXTEND_OP (GET_MODE (x)) == ZERO_EXTEND) + nonzero &= GET_MODE_MASK (GET_MODE (x)); +#endif + break; + + case EQ: case NE: + case GT: case GTU: + case LT: case LTU: + case GE: case GEU: + case LE: case LEU: + + /* If this produces an integer result, we know which bits are set. + Code here used to clear bits outside the mode of X, but that is + now done above. */ + + if (GET_MODE_CLASS (mode) == MODE_INT + && mode_width <= HOST_BITS_PER_WIDE_INT) + nonzero = STORE_FLAG_VALUE; + break; + + case NEG: +#if 0 + /* Disabled to avoid exponential mutual recursion between nonzero_bits + and num_sign_bit_copies. */ + if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x)) + == GET_MODE_BITSIZE (GET_MODE (x))) + nonzero = 1; +#endif + + if (GET_MODE_SIZE (GET_MODE (x)) < mode_width) + nonzero |= (GET_MODE_MASK (mode) & ~ GET_MODE_MASK (GET_MODE (x))); + break; + + case ABS: +#if 0 + /* Disabled to avoid exponential mutual recursion between nonzero_bits + and num_sign_bit_copies. */ + if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x)) + == GET_MODE_BITSIZE (GET_MODE (x))) + nonzero = 1; +#endif + break; + + case TRUNCATE: + nonzero &= (nonzero_bits (XEXP (x, 0), mode) & GET_MODE_MASK (mode)); + break; + + case ZERO_EXTEND: + nonzero &= nonzero_bits (XEXP (x, 0), mode); + if (GET_MODE (XEXP (x, 0)) != VOIDmode) + nonzero &= GET_MODE_MASK (GET_MODE (XEXP (x, 0))); + break; + + case SIGN_EXTEND: + /* If the sign bit is known clear, this is the same as ZERO_EXTEND. + Otherwise, show all the bits in the outer mode but not the inner + may be non-zero. */ + inner_nz = nonzero_bits (XEXP (x, 0), mode); + if (GET_MODE (XEXP (x, 0)) != VOIDmode) + { + inner_nz &= GET_MODE_MASK (GET_MODE (XEXP (x, 0))); + if (inner_nz + & (((HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - 1)))) + inner_nz |= (GET_MODE_MASK (mode) + & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))); + } + + nonzero &= inner_nz; + break; + + case AND: + nonzero &= (nonzero_bits (XEXP (x, 0), mode) + & nonzero_bits (XEXP (x, 1), mode)); + break; + + case XOR: case IOR: + case UMIN: case UMAX: case SMIN: case SMAX: + nonzero &= (nonzero_bits (XEXP (x, 0), mode) + | nonzero_bits (XEXP (x, 1), mode)); + break; + + case PLUS: case MINUS: + case MULT: + case DIV: case UDIV: + case MOD: case UMOD: + /* We can apply the rules of arithmetic to compute the number of + high- and low-order zero bits of these operations. We start by + computing the width (position of the highest-order non-zero bit) + and the number of low-order zero bits for each value. */ + { + unsigned HOST_WIDE_INT nz0 = nonzero_bits (XEXP (x, 0), mode); + unsigned HOST_WIDE_INT nz1 = nonzero_bits (XEXP (x, 1), mode); + int width0 = floor_log2 (nz0) + 1; + int width1 = floor_log2 (nz1) + 1; + int low0 = floor_log2 (nz0 & -nz0); + int low1 = floor_log2 (nz1 & -nz1); + HOST_WIDE_INT op0_maybe_minusp + = (nz0 & ((HOST_WIDE_INT) 1 << (mode_width - 1))); + HOST_WIDE_INT op1_maybe_minusp + = (nz1 & ((HOST_WIDE_INT) 1 << (mode_width - 1))); + int result_width = mode_width; + int result_low = 0; + + switch (code) + { + case PLUS: +#ifdef STACK_BIAS + if (STACK_BIAS + && (XEXP (x, 0) == stack_pointer_rtx + || XEXP (x, 0) == frame_pointer_rtx) + && GET_CODE (XEXP (x, 1)) == CONST_INT) + { + int sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT; + + nz0 = (GET_MODE_MASK (mode) & ~ (sp_alignment - 1)); + nz1 = INTVAL (XEXP (x, 1)) - STACK_BIAS; + width0 = floor_log2 (nz0) + 1; + width1 = floor_log2 (nz1) + 1; + low0 = floor_log2 (nz0 & -nz0); + low1 = floor_log2 (nz1 & -nz1); + } +#endif + result_width = MAX (width0, width1) + 1; + result_low = MIN (low0, low1); + break; + case MINUS: + result_low = MIN (low0, low1); + break; + case MULT: + result_width = width0 + width1; + result_low = low0 + low1; + break; + case DIV: + if (! op0_maybe_minusp && ! op1_maybe_minusp) + result_width = width0; + break; + case UDIV: + result_width = width0; + break; + case MOD: + if (! op0_maybe_minusp && ! op1_maybe_minusp) + result_width = MIN (width0, width1); + result_low = MIN (low0, low1); + break; + case UMOD: + result_width = MIN (width0, width1); + result_low = MIN (low0, low1); + break; + default: + abort (); + } + + if (result_width < mode_width) + nonzero &= ((HOST_WIDE_INT) 1 << result_width) - 1; + + if (result_low > 0) + nonzero &= ~ (((HOST_WIDE_INT) 1 << result_low) - 1); + } + break; + + case ZERO_EXTRACT: + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT) + nonzero &= ((HOST_WIDE_INT) 1 << INTVAL (XEXP (x, 1))) - 1; + break; + + case SUBREG: + /* If this is a SUBREG formed for a promoted variable that has + been zero-extended, we know that at least the high-order bits + are zero, though others might be too. */ + + if (SUBREG_PROMOTED_VAR_P (x) && SUBREG_PROMOTED_UNSIGNED_P (x)) + nonzero = (GET_MODE_MASK (GET_MODE (x)) + & nonzero_bits (SUBREG_REG (x), GET_MODE (x))); + + /* If the inner mode is a single word for both the host and target + machines, we can compute this from which bits of the inner + object might be nonzero. */ + if (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) <= BITS_PER_WORD + && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) + <= HOST_BITS_PER_WIDE_INT)) + { + nonzero &= nonzero_bits (SUBREG_REG (x), mode); + +#if defined (WORD_REGISTER_OPERATIONS) && defined (LOAD_EXTEND_OP) + /* If this is a typical RISC machine, we only have to worry + about the way loads are extended. */ + if (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) == SIGN_EXTEND + ? (nonzero + & (1L << (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) - 1))) + : LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) != ZERO_EXTEND) +#endif + { + /* On many CISC machines, accessing an object in a wider mode + causes the high-order bits to become undefined. So they are + not known to be zero. */ + if (GET_MODE_SIZE (GET_MODE (x)) + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) + nonzero |= (GET_MODE_MASK (GET_MODE (x)) + & ~ GET_MODE_MASK (GET_MODE (SUBREG_REG (x)))); + } + } + break; + + case ASHIFTRT: + case LSHIFTRT: + case ASHIFT: + case ROTATE: + /* The nonzero bits are in two classes: any bits within MODE + that aren't in GET_MODE (x) are always significant. The rest of the + nonzero bits are those that are significant in the operand of + the shift when shifted the appropriate number of bits. This + shows that high-order bits are cleared by the right shift and + low-order bits by left shifts. */ + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) >= 0 + && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT) + { + enum machine_mode inner_mode = GET_MODE (x); + int width = GET_MODE_BITSIZE (inner_mode); + int count = INTVAL (XEXP (x, 1)); + unsigned HOST_WIDE_INT mode_mask = GET_MODE_MASK (inner_mode); + unsigned HOST_WIDE_INT op_nonzero = nonzero_bits (XEXP (x, 0), mode); + unsigned HOST_WIDE_INT inner = op_nonzero & mode_mask; + unsigned HOST_WIDE_INT outer = 0; + + if (mode_width > width) + outer = (op_nonzero & nonzero & ~ mode_mask); + + if (code == LSHIFTRT) + inner >>= count; + else if (code == ASHIFTRT) + { + inner >>= count; + + /* If the sign bit may have been nonzero before the shift, we + need to mark all the places it could have been copied to + by the shift as possibly nonzero. */ + if (inner & ((HOST_WIDE_INT) 1 << (width - 1 - count))) + inner |= (((HOST_WIDE_INT) 1 << count) - 1) << (width - count); + } + else if (code == ASHIFT) + inner <<= count; + else + inner = ((inner << (count % width) + | (inner >> (width - (count % width)))) & mode_mask); + + nonzero &= (outer | inner); + } + break; + + case FFS: + /* This is at most the number of bits in the mode. */ + nonzero = ((HOST_WIDE_INT) 1 << (floor_log2 (mode_width) + 1)) - 1; + break; + + case IF_THEN_ELSE: + nonzero &= (nonzero_bits (XEXP (x, 1), mode) + | nonzero_bits (XEXP (x, 2), mode)); + break; + + default: + break; + } + + return nonzero; +} + +/* See the macro definition above. */ +#undef num_sign_bit_copies + +/* Return the number of bits at the high-order end of X that are known to + be equal to the sign bit. X will be used in mode MODE; if MODE is + VOIDmode, X will be used in its own mode. The returned value will always + be between 1 and the number of bits in MODE. */ + +static int +num_sign_bit_copies (x, mode) + rtx x; + enum machine_mode mode; +{ + enum rtx_code code = GET_CODE (x); + int bitwidth; + int num0, num1, result; + unsigned HOST_WIDE_INT nonzero; + rtx tem; + + /* If we weren't given a mode, use the mode of X. If the mode is still + VOIDmode, we don't know anything. Likewise if one of the modes is + floating-point. */ + + if (mode == VOIDmode) + mode = GET_MODE (x); + + if (mode == VOIDmode || FLOAT_MODE_P (mode) || FLOAT_MODE_P (GET_MODE (x))) + return 1; + + bitwidth = GET_MODE_BITSIZE (mode); + + /* For a smaller object, just ignore the high bits. */ + if (bitwidth < GET_MODE_BITSIZE (GET_MODE (x))) + return MAX (1, (num_sign_bit_copies (x, GET_MODE (x)) + - (GET_MODE_BITSIZE (GET_MODE (x)) - bitwidth))); + + if (GET_MODE (x) != VOIDmode && bitwidth > GET_MODE_BITSIZE (GET_MODE (x))) + { +#ifndef WORD_REGISTER_OPERATIONS + /* If this machine does not do all register operations on the entire + register and MODE is wider than the mode of X, we can say nothing + at all about the high-order bits. */ + return 1; +#else + /* Likewise on machines that do, if the mode of the object is smaller + than a word and loads of that size don't sign extend, we can say + nothing about the high order bits. */ + if (GET_MODE_BITSIZE (GET_MODE (x)) < BITS_PER_WORD +#ifdef LOAD_EXTEND_OP + && LOAD_EXTEND_OP (GET_MODE (x)) != SIGN_EXTEND +#endif + ) + return 1; +#endif + } + + switch (code) + { + case REG: + +#ifdef POINTERS_EXTEND_UNSIGNED + /* If pointers extend signed and this is a pointer in Pmode, say that + all the bits above ptr_mode are known to be sign bit copies. */ + if (! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode && mode == Pmode + && REGNO_POINTER_FLAG (REGNO (x))) + return GET_MODE_BITSIZE (Pmode) - GET_MODE_BITSIZE (ptr_mode) + 1; +#endif + + if (reg_last_set_value[REGNO (x)] != 0 + && reg_last_set_mode[REGNO (x)] == mode + && (REG_N_SETS (REGNO (x)) == 1 + || reg_last_set_label[REGNO (x)] == label_tick) + && INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid) + return reg_last_set_sign_bit_copies[REGNO (x)]; + + tem = get_last_value (x); + if (tem != 0) + return num_sign_bit_copies (tem, mode); + + if (nonzero_sign_valid && reg_sign_bit_copies[REGNO (x)] != 0) + return reg_sign_bit_copies[REGNO (x)]; + break; + + case MEM: +#ifdef LOAD_EXTEND_OP + /* Some RISC machines sign-extend all loads of smaller than a word. */ + if (LOAD_EXTEND_OP (GET_MODE (x)) == SIGN_EXTEND) + return MAX (1, bitwidth - GET_MODE_BITSIZE (GET_MODE (x)) + 1); +#endif + break; + + case CONST_INT: + /* If the constant is negative, take its 1's complement and remask. + Then see how many zero bits we have. */ + nonzero = INTVAL (x) & GET_MODE_MASK (mode); + if (bitwidth <= HOST_BITS_PER_WIDE_INT + && (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0) + nonzero = (~ nonzero) & GET_MODE_MASK (mode); + + return (nonzero == 0 ? bitwidth : bitwidth - floor_log2 (nonzero) - 1); + + case SUBREG: + /* If this is a SUBREG for a promoted object that is sign-extended + and we are looking at it in a wider mode, we know that at least the + high-order bits are known to be sign bit copies. */ + + if (SUBREG_PROMOTED_VAR_P (x) && ! SUBREG_PROMOTED_UNSIGNED_P (x)) + return MAX (bitwidth - GET_MODE_BITSIZE (GET_MODE (x)) + 1, + num_sign_bit_copies (SUBREG_REG (x), mode)); + + /* For a smaller object, just ignore the high bits. */ + if (bitwidth <= GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))) + { + num0 = num_sign_bit_copies (SUBREG_REG (x), VOIDmode); + return MAX (1, (num0 + - (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) + - bitwidth))); + } + +#ifdef WORD_REGISTER_OPERATIONS +#ifdef LOAD_EXTEND_OP + /* For paradoxical SUBREGs on machines where all register operations + affect the entire register, just look inside. Note that we are + passing MODE to the recursive call, so the number of sign bit copies + will remain relative to that mode, not the inner mode. */ + + /* This works only if loads sign extend. Otherwise, if we get a + reload for the inner part, it may be loaded from the stack, and + then we lose all sign bit copies that existed before the store + to the stack. */ + + if ((GET_MODE_SIZE (GET_MODE (x)) + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) + && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) == SIGN_EXTEND) + return num_sign_bit_copies (SUBREG_REG (x), mode); +#endif +#endif + break; + + case SIGN_EXTRACT: + if (GET_CODE (XEXP (x, 1)) == CONST_INT) + return MAX (1, bitwidth - INTVAL (XEXP (x, 1))); + break; + + case SIGN_EXTEND: + return (bitwidth - GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) + + num_sign_bit_copies (XEXP (x, 0), VOIDmode)); + + case TRUNCATE: + /* For a smaller object, just ignore the high bits. */ + num0 = num_sign_bit_copies (XEXP (x, 0), VOIDmode); + return MAX (1, (num0 - (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) + - bitwidth))); + + case NOT: + return num_sign_bit_copies (XEXP (x, 0), mode); + + case ROTATE: case ROTATERT: + /* If we are rotating left by a number of bits less than the number + of sign bit copies, we can just subtract that amount from the + number. */ + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) >= 0 && INTVAL (XEXP (x, 1)) < bitwidth) + { + num0 = num_sign_bit_copies (XEXP (x, 0), mode); + return MAX (1, num0 - (code == ROTATE ? INTVAL (XEXP (x, 1)) + : bitwidth - INTVAL (XEXP (x, 1)))); + } + break; + + case NEG: + /* In general, this subtracts one sign bit copy. But if the value + is known to be positive, the number of sign bit copies is the + same as that of the input. Finally, if the input has just one bit + that might be nonzero, all the bits are copies of the sign bit. */ + num0 = num_sign_bit_copies (XEXP (x, 0), mode); + if (bitwidth > HOST_BITS_PER_WIDE_INT) + return num0 > 1 ? num0 - 1 : 1; + + nonzero = nonzero_bits (XEXP (x, 0), mode); + if (nonzero == 1) + return bitwidth; + + if (num0 > 1 + && (((HOST_WIDE_INT) 1 << (bitwidth - 1)) & nonzero)) + num0--; + + return num0; + + case IOR: case AND: case XOR: + case SMIN: case SMAX: case UMIN: case UMAX: + /* Logical operations will preserve the number of sign-bit copies. + MIN and MAX operations always return one of the operands. */ + num0 = num_sign_bit_copies (XEXP (x, 0), mode); + num1 = num_sign_bit_copies (XEXP (x, 1), mode); + return MIN (num0, num1); + + case PLUS: case MINUS: + /* For addition and subtraction, we can have a 1-bit carry. However, + if we are subtracting 1 from a positive number, there will not + be such a carry. Furthermore, if the positive number is known to + be 0 or 1, we know the result is either -1 or 0. */ + + if (code == PLUS && XEXP (x, 1) == constm1_rtx + && bitwidth <= HOST_BITS_PER_WIDE_INT) + { + nonzero = nonzero_bits (XEXP (x, 0), mode); + if ((((HOST_WIDE_INT) 1 << (bitwidth - 1)) & nonzero) == 0) + return (nonzero == 1 || nonzero == 0 ? bitwidth + : bitwidth - floor_log2 (nonzero) - 1); + } + + num0 = num_sign_bit_copies (XEXP (x, 0), mode); + num1 = num_sign_bit_copies (XEXP (x, 1), mode); + return MAX (1, MIN (num0, num1) - 1); + + case MULT: + /* The number of bits of the product is the sum of the number of + bits of both terms. However, unless one of the terms if known + to be positive, we must allow for an additional bit since negating + a negative number can remove one sign bit copy. */ + + num0 = num_sign_bit_copies (XEXP (x, 0), mode); + num1 = num_sign_bit_copies (XEXP (x, 1), mode); + + result = bitwidth - (bitwidth - num0) - (bitwidth - num1); + if (result > 0 + && (bitwidth > HOST_BITS_PER_WIDE_INT + || (((nonzero_bits (XEXP (x, 0), mode) + & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0) + && ((nonzero_bits (XEXP (x, 1), mode) + & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)))) + result--; + + return MAX (1, result); + + case UDIV: + /* The result must be <= the first operand. If the first operand + has the high bit set, we know nothing about the number of sign + bit copies. */ + if (bitwidth > HOST_BITS_PER_WIDE_INT) + return 1; + else if ((nonzero_bits (XEXP (x, 0), mode) + & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0) + return 1; + else + return num_sign_bit_copies (XEXP (x, 0), mode); + + case UMOD: + /* The result must be <= the scond operand. */ + return num_sign_bit_copies (XEXP (x, 1), mode); + + case DIV: + /* Similar to unsigned division, except that we have to worry about + the case where the divisor is negative, in which case we have + to add 1. */ + result = num_sign_bit_copies (XEXP (x, 0), mode); + if (result > 1 + && (bitwidth > HOST_BITS_PER_WIDE_INT + || (nonzero_bits (XEXP (x, 1), mode) + & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)) + result--; + + return result; + + case MOD: + result = num_sign_bit_copies (XEXP (x, 1), mode); + if (result > 1 + && (bitwidth > HOST_BITS_PER_WIDE_INT + || (nonzero_bits (XEXP (x, 1), mode) + & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)) + result--; + + return result; + + case ASHIFTRT: + /* Shifts by a constant add to the number of bits equal to the + sign bit. */ + num0 = num_sign_bit_copies (XEXP (x, 0), mode); + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) > 0) + num0 = MIN (bitwidth, num0 + INTVAL (XEXP (x, 1))); + + return num0; + + case ASHIFT: + /* Left shifts destroy copies. */ + if (GET_CODE (XEXP (x, 1)) != CONST_INT + || INTVAL (XEXP (x, 1)) < 0 + || INTVAL (XEXP (x, 1)) >= bitwidth) + return 1; + + num0 = num_sign_bit_copies (XEXP (x, 0), mode); + return MAX (1, num0 - INTVAL (XEXP (x, 1))); + + case IF_THEN_ELSE: + num0 = num_sign_bit_copies (XEXP (x, 1), mode); + num1 = num_sign_bit_copies (XEXP (x, 2), mode); + return MIN (num0, num1); + + case EQ: case NE: case GE: case GT: case LE: case LT: + case GEU: case GTU: case LEU: case LTU: + if (STORE_FLAG_VALUE == -1) + return bitwidth; + break; + + default: + break; + } + + /* If we haven't been able to figure it out by one of the above rules, + see if some of the high-order bits are known to be zero. If so, + count those bits and return one less than that amount. If we can't + safely compute the mask for this mode, always return BITWIDTH. */ + + if (bitwidth > HOST_BITS_PER_WIDE_INT) + return 1; + + nonzero = nonzero_bits (x, mode); + return (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1)) + ? 1 : bitwidth - floor_log2 (nonzero) - 1); +} + +/* Return the number of "extended" bits there are in X, when interpreted + as a quantity in MODE whose signedness is indicated by UNSIGNEDP. For + unsigned quantities, this is the number of high-order zero bits. + For signed quantities, this is the number of copies of the sign bit + minus 1. In both case, this function returns the number of "spare" + bits. For example, if two quantities for which this function returns + at least 1 are added, the addition is known not to overflow. + + This function will always return 0 unless called during combine, which + implies that it must be called from a define_split. */ + +int +extended_count (x, mode, unsignedp) + rtx x; + enum machine_mode mode; + int unsignedp; +{ + if (nonzero_sign_valid == 0) + return 0; + + return (unsignedp + ? (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT + && (GET_MODE_BITSIZE (mode) - 1 + - floor_log2 (nonzero_bits (x, mode)))) + : num_sign_bit_copies (x, mode) - 1); +} + +/* This function is called from `simplify_shift_const' to merge two + outer operations. Specifically, we have already found that we need + to perform operation *POP0 with constant *PCONST0 at the outermost + position. We would now like to also perform OP1 with constant CONST1 + (with *POP0 being done last). + + Return 1 if we can do the operation and update *POP0 and *PCONST0 with + the resulting operation. *PCOMP_P is set to 1 if we would need to + complement the innermost operand, otherwise it is unchanged. + + MODE is the mode in which the operation will be done. No bits outside + the width of this mode matter. It is assumed that the width of this mode + is smaller than or equal to HOST_BITS_PER_WIDE_INT. + + If *POP0 or OP1 are NIL, it means no operation is required. Only NEG, PLUS, + IOR, XOR, and AND are supported. We may set *POP0 to SET if the proper + result is simply *PCONST0. + + If the resulting operation cannot be expressed as one operation, we + return 0 and do not change *POP0, *PCONST0, and *PCOMP_P. */ + +static int +merge_outer_ops (pop0, pconst0, op1, const1, mode, pcomp_p) + enum rtx_code *pop0; + HOST_WIDE_INT *pconst0; + enum rtx_code op1; + HOST_WIDE_INT const1; + enum machine_mode mode; + int *pcomp_p; +{ + enum rtx_code op0 = *pop0; + HOST_WIDE_INT const0 = *pconst0; + int width = GET_MODE_BITSIZE (mode); + + const0 &= GET_MODE_MASK (mode); + const1 &= GET_MODE_MASK (mode); + + /* If OP0 is an AND, clear unimportant bits in CONST1. */ + if (op0 == AND) + const1 &= const0; + + /* If OP0 or OP1 is NIL, this is easy. Similarly if they are the same or + if OP0 is SET. */ + + if (op1 == NIL || op0 == SET) + return 1; + + else if (op0 == NIL) + op0 = op1, const0 = const1; + + else if (op0 == op1) + { + switch (op0) + { + case AND: + const0 &= const1; + break; + case IOR: + const0 |= const1; + break; + case XOR: + const0 ^= const1; + break; + case PLUS: + const0 += const1; + break; + case NEG: + op0 = NIL; + break; + default: + break; + } + } + + /* Otherwise, if either is a PLUS or NEG, we can't do anything. */ + else if (op0 == PLUS || op1 == PLUS || op0 == NEG || op1 == NEG) + return 0; + + /* If the two constants aren't the same, we can't do anything. The + remaining six cases can all be done. */ + else if (const0 != const1) + return 0; + + else + switch (op0) + { + case IOR: + if (op1 == AND) + /* (a & b) | b == b */ + op0 = SET; + else /* op1 == XOR */ + /* (a ^ b) | b == a | b */ + {;} + break; + + case XOR: + if (op1 == AND) + /* (a & b) ^ b == (~a) & b */ + op0 = AND, *pcomp_p = 1; + else /* op1 == IOR */ + /* (a | b) ^ b == a & ~b */ + op0 = AND, *pconst0 = ~ const0; + break; + + case AND: + if (op1 == IOR) + /* (a | b) & b == b */ + op0 = SET; + else /* op1 == XOR */ + /* (a ^ b) & b) == (~a) & b */ + *pcomp_p = 1; + break; + default: + break; + } + + /* Check for NO-OP cases. */ + const0 &= GET_MODE_MASK (mode); + if (const0 == 0 + && (op0 == IOR || op0 == XOR || op0 == PLUS)) + op0 = NIL; + else if (const0 == 0 && op0 == AND) + op0 = SET; + else if ((unsigned HOST_WIDE_INT) const0 == GET_MODE_MASK (mode) + && op0 == AND) + op0 = NIL; + + /* 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 later confuses the sparc backend. */ + + if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width + && (const0 & ((HOST_WIDE_INT) 1 << (width - 1)))) + const0 |= ((HOST_WIDE_INT) (-1) << width); + + *pop0 = op0; + *pconst0 = const0; + + return 1; +} + +/* Simplify a shift of VAROP by COUNT bits. CODE says what kind of shift. + The result of the shift is RESULT_MODE. X, if non-zero, is an expression + that we started with. + + The shift is normally computed in the widest mode we find in VAROP, as + long as it isn't a different number of words than RESULT_MODE. Exceptions + are ASHIFTRT and ROTATE, which are always done in their original mode, */ + +static rtx +simplify_shift_const (x, code, result_mode, varop, count) + rtx x; + enum rtx_code code; + enum machine_mode result_mode; + rtx varop; + int count; +{ + enum rtx_code orig_code = code; + int orig_count = count; + enum machine_mode mode = result_mode; + enum machine_mode shift_mode, tmode; + int mode_words + = (GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD; + /* We form (outer_op (code varop count) (outer_const)). */ + enum rtx_code outer_op = NIL; + HOST_WIDE_INT outer_const = 0; + rtx const_rtx; + int complement_p = 0; + rtx new; + + /* If we were given an invalid count, don't do anything except exactly + what was requested. */ + + if (count < 0 || count > GET_MODE_BITSIZE (mode)) + { + if (x) + return x; + + return gen_rtx_fmt_ee (code, mode, varop, GEN_INT (count)); + } + + /* Unless one of the branches of the `if' in this loop does a `continue', + we will `break' the loop after the `if'. */ + + while (count != 0) + { + /* If we have an operand of (clobber (const_int 0)), just return that + value. */ + if (GET_CODE (varop) == CLOBBER) + return varop; + + /* If we discovered we had to complement VAROP, leave. Making a NOT + here would cause an infinite loop. */ + if (complement_p) + break; + + /* Convert ROTATERT to ROTATE. */ + if (code == ROTATERT) + code = ROTATE, count = GET_MODE_BITSIZE (result_mode) - count; + + /* We need to determine what mode we will do the shift in. If the + shift is a right shift or a ROTATE, we must always do it in the mode + it was originally done in. Otherwise, we can do it in MODE, the + widest mode encountered. */ + shift_mode + = (code == ASHIFTRT || code == LSHIFTRT || code == ROTATE + ? result_mode : mode); + + /* Handle cases where the count is greater than the size of the mode + minus 1. For ASHIFT, use the size minus one as the count (this can + occur when simplifying (lshiftrt (ashiftrt ..))). For rotates, + take the count modulo the size. For other shifts, the result is + zero. + + Since these shifts are being produced by the compiler by combining + multiple operations, each of which are defined, we know what the + result is supposed to be. */ + + if (count > GET_MODE_BITSIZE (shift_mode) - 1) + { + if (code == ASHIFTRT) + count = GET_MODE_BITSIZE (shift_mode) - 1; + else if (code == ROTATE || code == ROTATERT) + count %= GET_MODE_BITSIZE (shift_mode); + else + { + /* We can't simply return zero because there may be an + outer op. */ + varop = const0_rtx; + count = 0; + break; + } + } + + /* Negative counts are invalid and should not have been made (a + programmer-specified negative count should have been handled + above). */ + else if (count < 0) + abort (); + + /* An arithmetic right shift of a quantity known to be -1 or 0 + is a no-op. */ + if (code == ASHIFTRT + && (num_sign_bit_copies (varop, shift_mode) + == GET_MODE_BITSIZE (shift_mode))) + { + count = 0; + break; + } + + /* If we are doing an arithmetic right shift and discarding all but + the sign bit copies, this is equivalent to doing a shift by the + bitsize minus one. Convert it into that shift because it will often + allow other simplifications. */ + + if (code == ASHIFTRT + && (count + num_sign_bit_copies (varop, shift_mode) + >= GET_MODE_BITSIZE (shift_mode))) + count = GET_MODE_BITSIZE (shift_mode) - 1; + + /* We simplify the tests below and elsewhere by converting + ASHIFTRT to LSHIFTRT if we know the sign bit is clear. + `make_compound_operation' will convert it to a ASHIFTRT for + those machines (such as Vax) that don't have a LSHIFTRT. */ + if (GET_MODE_BITSIZE (shift_mode) <= HOST_BITS_PER_WIDE_INT + && code == ASHIFTRT + && ((nonzero_bits (varop, shift_mode) + & ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (shift_mode) - 1))) + == 0)) + code = LSHIFTRT; + + switch (GET_CODE (varop)) + { + case SIGN_EXTEND: + case ZERO_EXTEND: + case SIGN_EXTRACT: + case ZERO_EXTRACT: + new = expand_compound_operation (varop); + if (new != varop) + { + varop = new; + continue; + } + break; + + case MEM: + /* If we have (xshiftrt (mem ...) C) and C is MODE_WIDTH + minus the width of a smaller mode, we can do this with a + SIGN_EXTEND or ZERO_EXTEND from the narrower memory location. */ + if ((code == ASHIFTRT || code == LSHIFTRT) + && ! mode_dependent_address_p (XEXP (varop, 0)) + && ! MEM_VOLATILE_P (varop) + && (tmode = mode_for_size (GET_MODE_BITSIZE (mode) - count, + MODE_INT, 1)) != BLKmode) + { + if (BYTES_BIG_ENDIAN) + new = gen_rtx_MEM (tmode, XEXP (varop, 0)); + else + new = gen_rtx_MEM (tmode, + plus_constant (XEXP (varop, 0), + count / BITS_PER_UNIT)); + RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (varop); + MEM_COPY_ATTRIBUTES (new, varop); + varop = gen_rtx_combine (code == ASHIFTRT ? SIGN_EXTEND + : ZERO_EXTEND, mode, new); + count = 0; + continue; + } + break; + + case USE: + /* Similar to the case above, except that we can only do this if + the resulting mode is the same as that of the underlying + MEM and adjust the address depending on the *bits* endianness + because of the way that bit-field extract insns are defined. */ + if ((code == ASHIFTRT || code == LSHIFTRT) + && (tmode = mode_for_size (GET_MODE_BITSIZE (mode) - count, + MODE_INT, 1)) != BLKmode + && tmode == GET_MODE (XEXP (varop, 0))) + { + if (BITS_BIG_ENDIAN) + new = XEXP (varop, 0); + else + { + new = copy_rtx (XEXP (varop, 0)); + SUBST (XEXP (new, 0), + plus_constant (XEXP (new, 0), + count / BITS_PER_UNIT)); + } + + varop = gen_rtx_combine (code == ASHIFTRT ? SIGN_EXTEND + : ZERO_EXTEND, mode, new); + count = 0; + continue; + } + break; + + case SUBREG: + /* If VAROP is a SUBREG, strip it as long as the inner operand has + the same number of words as what we've seen so far. Then store + the widest mode in MODE. */ + if (subreg_lowpart_p (varop) + && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (varop))) + > GET_MODE_SIZE (GET_MODE (varop))) + && (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (varop))) + + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD) + == mode_words)) + { + varop = SUBREG_REG (varop); + if (GET_MODE_SIZE (GET_MODE (varop)) > GET_MODE_SIZE (mode)) + mode = GET_MODE (varop); + continue; + } + break; + + case MULT: + /* Some machines use MULT instead of ASHIFT because MULT + is cheaper. But it is still better on those machines to + merge two shifts into one. */ + if (GET_CODE (XEXP (varop, 1)) == CONST_INT + && exact_log2 (INTVAL (XEXP (varop, 1))) >= 0) + { + varop = gen_binary (ASHIFT, GET_MODE (varop), XEXP (varop, 0), + GEN_INT (exact_log2 (INTVAL (XEXP (varop, 1)))));; + continue; + } + break; + + case UDIV: + /* Similar, for when divides are cheaper. */ + if (GET_CODE (XEXP (varop, 1)) == CONST_INT + && exact_log2 (INTVAL (XEXP (varop, 1))) >= 0) + { + varop = gen_binary (LSHIFTRT, GET_MODE (varop), XEXP (varop, 0), + GEN_INT (exact_log2 (INTVAL (XEXP (varop, 1))))); + continue; + } + break; + + case ASHIFTRT: + /* If we are extracting just the sign bit of an arithmetic right + shift, that shift is not needed. */ + if (code == LSHIFTRT && count == GET_MODE_BITSIZE (result_mode) - 1) + { + varop = XEXP (varop, 0); + continue; + } + + /* ... fall through ... */ + + case LSHIFTRT: + case ASHIFT: + case ROTATE: + /* Here we have two nested shifts. The result is usually the + AND of a new shift with a mask. We compute the result below. */ + if (GET_CODE (XEXP (varop, 1)) == CONST_INT + && INTVAL (XEXP (varop, 1)) >= 0 + && INTVAL (XEXP (varop, 1)) < GET_MODE_BITSIZE (GET_MODE (varop)) + && GET_MODE_BITSIZE (result_mode) <= HOST_BITS_PER_WIDE_INT + && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT) + { + enum rtx_code first_code = GET_CODE (varop); + int first_count = INTVAL (XEXP (varop, 1)); + unsigned HOST_WIDE_INT mask; + rtx mask_rtx; + + /* We have one common special case. We can't do any merging if + the inner code is an ASHIFTRT of a smaller mode. However, if + we have (ashift:M1 (subreg:M1 (ashiftrt:M2 FOO C1) 0) C2) + with C2 == GET_MODE_BITSIZE (M1) - GET_MODE_BITSIZE (M2), + we can convert it to + (ashiftrt:M1 (ashift:M1 (and:M1 (subreg:M1 FOO 0 C2) C3) C1). + This simplifies certain SIGN_EXTEND operations. */ + if (code == ASHIFT && first_code == ASHIFTRT + && (GET_MODE_BITSIZE (result_mode) + - GET_MODE_BITSIZE (GET_MODE (varop))) == count) + { + /* C3 has the low-order C1 bits zero. */ + + mask = (GET_MODE_MASK (mode) + & ~ (((HOST_WIDE_INT) 1 << first_count) - 1)); + + varop = simplify_and_const_int (NULL_RTX, result_mode, + XEXP (varop, 0), mask); + varop = simplify_shift_const (NULL_RTX, ASHIFT, result_mode, + varop, count); + count = first_count; + code = ASHIFTRT; + continue; + } + + /* If this was (ashiftrt (ashift foo C1) C2) and FOO has more + than C1 high-order bits equal to the sign bit, we can convert + this to either an ASHIFT or a ASHIFTRT depending on the + two counts. + + We cannot do this if VAROP's mode is not SHIFT_MODE. */ + + if (code == ASHIFTRT && first_code == ASHIFT + && GET_MODE (varop) == shift_mode + && (num_sign_bit_copies (XEXP (varop, 0), shift_mode) + > first_count)) + { + count -= first_count; + if (count < 0) + count = - count, code = ASHIFT; + varop = XEXP (varop, 0); + continue; + } + + /* There are some cases we can't do. If CODE is ASHIFTRT, + we can only do this if FIRST_CODE is also ASHIFTRT. + + We can't do the case when CODE is ROTATE and FIRST_CODE is + ASHIFTRT. + + If the mode of this shift is not the mode of the outer shift, + we can't do this if either shift is a right shift or ROTATE. + + Finally, we can't do any of these if the mode is too wide + unless the codes are the same. + + Handle the case where the shift codes are the same + first. */ + + if (code == first_code) + { + if (GET_MODE (varop) != result_mode + && (code == ASHIFTRT || code == LSHIFTRT + || code == ROTATE)) + break; + + count += first_count; + varop = XEXP (varop, 0); + continue; + } + + if (code == ASHIFTRT + || (code == ROTATE && first_code == ASHIFTRT) + || GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT + || (GET_MODE (varop) != result_mode + && (first_code == ASHIFTRT || first_code == LSHIFTRT + || first_code == ROTATE + || code == ROTATE))) + break; + + /* To compute the mask to apply after the shift, shift the + nonzero bits of the inner shift the same way the + outer shift will. */ + + mask_rtx = GEN_INT (nonzero_bits (varop, GET_MODE (varop))); + + mask_rtx + = simplify_binary_operation (code, result_mode, mask_rtx, + GEN_INT (count)); + + /* Give up if we can't compute an outer operation to use. */ + if (mask_rtx == 0 + || GET_CODE (mask_rtx) != CONST_INT + || ! merge_outer_ops (&outer_op, &outer_const, AND, + INTVAL (mask_rtx), + result_mode, &complement_p)) + break; + + /* If the shifts are in the same direction, we add the + counts. Otherwise, we subtract them. */ + if ((code == ASHIFTRT || code == LSHIFTRT) + == (first_code == ASHIFTRT || first_code == LSHIFTRT)) + count += first_count; + else + count -= first_count; + + /* If COUNT is positive, the new shift is usually CODE, + except for the two exceptions below, in which case it is + FIRST_CODE. If the count is negative, FIRST_CODE should + always be used */ + if (count > 0 + && ((first_code == ROTATE && code == ASHIFT) + || (first_code == ASHIFTRT && code == LSHIFTRT))) + code = first_code; + else if (count < 0) + code = first_code, count = - count; + + varop = XEXP (varop, 0); + continue; + } + + /* If we have (A << B << C) for any shift, we can convert this to + (A << C << B). This wins if A is a constant. Only try this if + B is not a constant. */ + + else if (GET_CODE (varop) == code + && GET_CODE (XEXP (varop, 1)) != CONST_INT + && 0 != (new + = simplify_binary_operation (code, mode, + XEXP (varop, 0), + GEN_INT (count)))) + { + varop = gen_rtx_combine (code, mode, new, XEXP (varop, 1)); + count = 0; + continue; + } + break; + + case NOT: + /* Make this fit the case below. */ + varop = gen_rtx_combine (XOR, mode, XEXP (varop, 0), + GEN_INT (GET_MODE_MASK (mode))); + continue; + + case IOR: + case AND: + case XOR: + /* If we have (xshiftrt (ior (plus X (const_int -1)) X) C) + with C the size of VAROP - 1 and the shift is logical if + STORE_FLAG_VALUE is 1 and arithmetic if STORE_FLAG_VALUE is -1, + we have an (le X 0) operation. If we have an arithmetic shift + and STORE_FLAG_VALUE is 1 or we have a logical shift with + STORE_FLAG_VALUE of -1, we have a (neg (le X 0)) operation. */ + + if (GET_CODE (varop) == IOR && GET_CODE (XEXP (varop, 0)) == PLUS + && XEXP (XEXP (varop, 0), 1) == constm1_rtx + && (STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1) + && (code == LSHIFTRT || code == ASHIFTRT) + && count == GET_MODE_BITSIZE (GET_MODE (varop)) - 1 + && rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1))) + { + count = 0; + varop = gen_rtx_combine (LE, GET_MODE (varop), XEXP (varop, 1), + const0_rtx); + + if (STORE_FLAG_VALUE == 1 ? code == ASHIFTRT : code == LSHIFTRT) + varop = gen_rtx_combine (NEG, GET_MODE (varop), varop); + + continue; + } + + /* If we have (shift (logical)), move the logical to the outside + to allow it to possibly combine with another logical and the + shift to combine with another shift. This also canonicalizes to + what a ZERO_EXTRACT looks like. Also, some machines have + (and (shift)) insns. */ + + if (GET_CODE (XEXP (varop, 1)) == CONST_INT + && (new = simplify_binary_operation (code, result_mode, + XEXP (varop, 1), + GEN_INT (count))) != 0 + && GET_CODE(new) == CONST_INT + && merge_outer_ops (&outer_op, &outer_const, GET_CODE (varop), + INTVAL (new), result_mode, &complement_p)) + { + varop = XEXP (varop, 0); + continue; + } + + /* If we can't do that, try to simplify the shift in each arm of the + logical expression, make a new logical expression, and apply + the inverse distributive law. */ + { + rtx lhs = simplify_shift_const (NULL_RTX, code, shift_mode, + XEXP (varop, 0), count); + rtx rhs = simplify_shift_const (NULL_RTX, code, shift_mode, + XEXP (varop, 1), count); + + varop = gen_binary (GET_CODE (varop), shift_mode, lhs, rhs); + varop = apply_distributive_law (varop); + + count = 0; + } + break; + + case EQ: + /* convert (lshiftrt (eq FOO 0) C) to (xor FOO 1) if STORE_FLAG_VALUE + says that the sign bit can be tested, FOO has mode MODE, C is + GET_MODE_BITSIZE (MODE) - 1, and FOO has only its low-order bit + that may be nonzero. */ + if (code == LSHIFTRT + && XEXP (varop, 1) == const0_rtx + && GET_MODE (XEXP (varop, 0)) == result_mode + && count == GET_MODE_BITSIZE (result_mode) - 1 + && GET_MODE_BITSIZE (result_mode) <= HOST_BITS_PER_WIDE_INT + && ((STORE_FLAG_VALUE + & ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (result_mode) - 1)))) + && nonzero_bits (XEXP (varop, 0), result_mode) == 1 + && merge_outer_ops (&outer_op, &outer_const, XOR, + (HOST_WIDE_INT) 1, result_mode, + &complement_p)) + { + varop = XEXP (varop, 0); + count = 0; + continue; + } + break; + + case NEG: + /* (lshiftrt (neg A) C) where A is either 0 or 1 and C is one less + than the number of bits in the mode is equivalent to A. */ + if (code == LSHIFTRT && count == GET_MODE_BITSIZE (result_mode) - 1 + && nonzero_bits (XEXP (varop, 0), result_mode) == 1) + { + varop = XEXP (varop, 0); + count = 0; + continue; + } + + /* NEG commutes with ASHIFT since it is multiplication. Move the + NEG outside to allow shifts to combine. */ + if (code == ASHIFT + && merge_outer_ops (&outer_op, &outer_const, NEG, + (HOST_WIDE_INT) 0, result_mode, + &complement_p)) + { + varop = XEXP (varop, 0); + continue; + } + break; + + case PLUS: + /* (lshiftrt (plus A -1) C) where A is either 0 or 1 and C + is one less than the number of bits in the mode is + equivalent to (xor A 1). */ + if (code == LSHIFTRT && count == GET_MODE_BITSIZE (result_mode) - 1 + && XEXP (varop, 1) == constm1_rtx + && nonzero_bits (XEXP (varop, 0), result_mode) == 1 + && merge_outer_ops (&outer_op, &outer_const, XOR, + (HOST_WIDE_INT) 1, result_mode, + &complement_p)) + { + count = 0; + varop = XEXP (varop, 0); + continue; + } + + /* If we have (xshiftrt (plus FOO BAR) C), and the only bits + that might be nonzero in BAR are those being shifted out and those + bits are known zero in FOO, we can replace the PLUS with FOO. + Similarly in the other operand order. This code occurs when + we are computing the size of a variable-size array. */ + + if ((code == ASHIFTRT || code == LSHIFTRT) + && count < HOST_BITS_PER_WIDE_INT + && nonzero_bits (XEXP (varop, 1), result_mode) >> count == 0 + && (nonzero_bits (XEXP (varop, 1), result_mode) + & nonzero_bits (XEXP (varop, 0), result_mode)) == 0) + { + varop = XEXP (varop, 0); + continue; + } + else if ((code == ASHIFTRT || code == LSHIFTRT) + && count < HOST_BITS_PER_WIDE_INT + && GET_MODE_BITSIZE (result_mode) <= HOST_BITS_PER_WIDE_INT + && 0 == (nonzero_bits (XEXP (varop, 0), result_mode) + >> count) + && 0 == (nonzero_bits (XEXP (varop, 0), result_mode) + & nonzero_bits (XEXP (varop, 1), + result_mode))) + { + varop = XEXP (varop, 1); + continue; + } + + /* (ashift (plus foo C) N) is (plus (ashift foo N) C'). */ + if (code == ASHIFT + && GET_CODE (XEXP (varop, 1)) == CONST_INT + && (new = simplify_binary_operation (ASHIFT, result_mode, + XEXP (varop, 1), + GEN_INT (count))) != 0 + && GET_CODE(new) == CONST_INT + && merge_outer_ops (&outer_op, &outer_const, PLUS, + INTVAL (new), result_mode, &complement_p)) + { + varop = XEXP (varop, 0); + continue; + } + break; + + case MINUS: + /* If we have (xshiftrt (minus (ashiftrt X C)) X) C) + with C the size of VAROP - 1 and the shift is logical if + STORE_FLAG_VALUE is 1 and arithmetic if STORE_FLAG_VALUE is -1, + we have a (gt X 0) operation. If the shift is arithmetic with + STORE_FLAG_VALUE of 1 or logical with STORE_FLAG_VALUE == -1, + we have a (neg (gt X 0)) operation. */ + + if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1) + && GET_CODE (XEXP (varop, 0)) == ASHIFTRT + && count == GET_MODE_BITSIZE (GET_MODE (varop)) - 1 + && (code == LSHIFTRT || code == ASHIFTRT) + && GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT + && INTVAL (XEXP (XEXP (varop, 0), 1)) == count + && rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1))) + { + count = 0; + varop = gen_rtx_combine (GT, GET_MODE (varop), XEXP (varop, 1), + const0_rtx); + + if (STORE_FLAG_VALUE == 1 ? code == ASHIFTRT : code == LSHIFTRT) + varop = gen_rtx_combine (NEG, GET_MODE (varop), varop); + + continue; + } + break; + + case TRUNCATE: + /* Change (lshiftrt (truncate (lshiftrt))) to (truncate (lshiftrt)) + if the truncate does not affect the value. */ + if (code == LSHIFTRT + && GET_CODE (XEXP (varop, 0)) == LSHIFTRT + && GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT + && (INTVAL (XEXP (XEXP (varop, 0), 1)) + >= (GET_MODE_BITSIZE (GET_MODE (XEXP (varop, 0))) + - GET_MODE_BITSIZE (GET_MODE (varop))))) + { + rtx varop_inner = XEXP (varop, 0); + + varop_inner = gen_rtx_combine (LSHIFTRT, + GET_MODE (varop_inner), + XEXP (varop_inner, 0), + GEN_INT (count + INTVAL (XEXP (varop_inner, 1)))); + varop = gen_rtx_combine (TRUNCATE, GET_MODE (varop), + varop_inner); + count = 0; + continue; + } + break; + + default: + break; + } + + break; + } + + /* We need to determine what mode to do the shift in. If the shift is + a right shift or ROTATE, we must always do it in the mode it was + originally done in. Otherwise, we can do it in MODE, the widest mode + encountered. The code we care about is that of the shift that will + actually be done, not the shift that was originally requested. */ + shift_mode + = (code == ASHIFTRT || code == LSHIFTRT || code == ROTATE + ? result_mode : mode); + + /* We have now finished analyzing the shift. The result should be + a shift of type CODE with SHIFT_MODE shifting VAROP COUNT places. If + OUTER_OP is non-NIL, it is an operation that needs to be applied + to the result of the shift. OUTER_CONST is the relevant constant, + but we must turn off all bits turned off in the shift. + + If we were passed a value for X, see if we can use any pieces of + it. If not, make new rtx. */ + + if (x && GET_RTX_CLASS (GET_CODE (x)) == '2' + && GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) == count) + const_rtx = XEXP (x, 1); + else + const_rtx = GEN_INT (count); + + if (x && GET_CODE (XEXP (x, 0)) == SUBREG + && GET_MODE (XEXP (x, 0)) == shift_mode + && SUBREG_REG (XEXP (x, 0)) == varop) + varop = XEXP (x, 0); + else if (GET_MODE (varop) != shift_mode) + varop = gen_lowpart_for_combine (shift_mode, varop); + + /* If we can't make the SUBREG, try to return what we were given. */ + if (GET_CODE (varop) == CLOBBER) + return x ? x : varop; + + new = simplify_binary_operation (code, shift_mode, varop, const_rtx); + if (new != 0) + x = new; + else + { + if (x == 0 || GET_CODE (x) != code || GET_MODE (x) != shift_mode) + x = gen_rtx_combine (code, shift_mode, varop, const_rtx); + + SUBST (XEXP (x, 0), varop); + SUBST (XEXP (x, 1), const_rtx); + } + + /* If we have an outer operation and we just made a shift, it is + possible that we could have simplified the shift were it not + for the outer operation. So try to do the simplification + recursively. */ + + if (outer_op != NIL && GET_CODE (x) == code + && GET_CODE (XEXP (x, 1)) == CONST_INT) + x = simplify_shift_const (x, code, shift_mode, XEXP (x, 0), + INTVAL (XEXP (x, 1))); + + /* If we were doing a LSHIFTRT in a wider mode than it was originally, + turn off all the bits that the shift would have turned off. */ + if (orig_code == LSHIFTRT && result_mode != shift_mode) + x = simplify_and_const_int (NULL_RTX, shift_mode, x, + GET_MODE_MASK (result_mode) >> orig_count); + + /* Do the remainder of the processing in RESULT_MODE. */ + x = gen_lowpart_for_combine (result_mode, x); + + /* If COMPLEMENT_P is set, we have to complement X before doing the outer + operation. */ + if (complement_p) + x = gen_unary (NOT, result_mode, result_mode, x); + + if (outer_op != NIL) + { + if (GET_MODE_BITSIZE (result_mode) < HOST_BITS_PER_WIDE_INT) + { + int width = GET_MODE_BITSIZE (result_mode); + + outer_const &= GET_MODE_MASK (result_mode); + + /* 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 later confuses the sparc backend. */ + + if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width + && (outer_const & ((HOST_WIDE_INT) 1 << (width - 1)))) + outer_const |= ((HOST_WIDE_INT) (-1) << width); + } + + if (outer_op == AND) + x = simplify_and_const_int (NULL_RTX, result_mode, x, outer_const); + else if (outer_op == SET) + /* This means that we have determined that the result is + equivalent to a constant. This should be rare. */ + x = GEN_INT (outer_const); + else if (GET_RTX_CLASS (outer_op) == '1') + x = gen_unary (outer_op, result_mode, result_mode, x); + else + x = gen_binary (outer_op, result_mode, x, GEN_INT (outer_const)); + } + + return x; +} + +/* Like recog, but we receive the address of a pointer to a new pattern. + We try to match the rtx that the pointer points to. + If that fails, we may try to modify or replace the pattern, + storing the replacement into the same pointer object. + + Modifications include deletion or addition of CLOBBERs. + + PNOTES is a pointer to a location where any REG_UNUSED notes added for + the CLOBBERs are placed. + + The value is the final insn code from the pattern ultimately matched, + or -1. */ + +static int +recog_for_combine (pnewpat, insn, pnotes) + rtx *pnewpat; + rtx insn; + rtx *pnotes; +{ + register rtx pat = *pnewpat; + int insn_code_number; + int num_clobbers_to_add = 0; + int i; + rtx notes = 0; + + /* If PAT is a PARALLEL, check to see if it contains the CLOBBER + we use to indicate that something didn't match. If we find such a + thing, force rejection. */ + if (GET_CODE (pat) == PARALLEL) + for (i = XVECLEN (pat, 0) - 1; i >= 0; i--) + if (GET_CODE (XVECEXP (pat, 0, i)) == CLOBBER + && XEXP (XVECEXP (pat, 0, i), 0) == const0_rtx) + return -1; + + /* Is the result of combination a valid instruction? */ + insn_code_number = recog (pat, insn, &num_clobbers_to_add); + + /* If it isn't, there is the possibility that we previously had an insn + that clobbered some register as a side effect, but the combined + insn doesn't need to do that. So try once more without the clobbers + unless this represents an ASM insn. */ + + if (insn_code_number < 0 && ! check_asm_operands (pat) + && GET_CODE (pat) == PARALLEL) + { + int pos; + + for (pos = 0, i = 0; i < XVECLEN (pat, 0); i++) + if (GET_CODE (XVECEXP (pat, 0, i)) != CLOBBER) + { + if (i != pos) + SUBST (XVECEXP (pat, 0, pos), XVECEXP (pat, 0, i)); + pos++; + } + + SUBST_INT (XVECLEN (pat, 0), pos); + + if (pos == 1) + pat = XVECEXP (pat, 0, 0); + + insn_code_number = recog (pat, insn, &num_clobbers_to_add); + } + + /* If we had any clobbers to add, make a new pattern than contains + them. Then check to make sure that all of them are dead. */ + if (num_clobbers_to_add) + { + rtx newpat = gen_rtx_PARALLEL (VOIDmode, + gen_rtvec (GET_CODE (pat) == PARALLEL + ? XVECLEN (pat, 0) + num_clobbers_to_add + : num_clobbers_to_add + 1)); + + if (GET_CODE (pat) == PARALLEL) + for (i = 0; i < XVECLEN (pat, 0); i++) + XVECEXP (newpat, 0, i) = XVECEXP (pat, 0, i); + else + XVECEXP (newpat, 0, 0) = pat; + + add_clobbers (newpat, insn_code_number); + + for (i = XVECLEN (newpat, 0) - num_clobbers_to_add; + i < XVECLEN (newpat, 0); i++) + { + if (GET_CODE (XEXP (XVECEXP (newpat, 0, i), 0)) == REG + && ! reg_dead_at_p (XEXP (XVECEXP (newpat, 0, i), 0), insn)) + return -1; + notes = gen_rtx_EXPR_LIST (REG_UNUSED, + XEXP (XVECEXP (newpat, 0, i), 0), notes); + } + pat = newpat; + } + + *pnewpat = pat; + *pnotes = notes; + + return insn_code_number; +} + +/* Like gen_lowpart but for use by combine. In combine it is not possible + to create any new pseudoregs. However, it is safe to create + invalid memory addresses, because combine will try to recognize + them and all they will do is make the combine attempt fail. + + If for some reason this cannot do its job, an rtx + (clobber (const_int 0)) is returned. + An insn containing that will not be recognized. */ + +#undef gen_lowpart + +static rtx +gen_lowpart_for_combine (mode, x) + enum machine_mode mode; + register rtx x; +{ + rtx result; + + if (GET_MODE (x) == mode) + return x; + + /* We can only support MODE being wider than a word if X is a + constant integer or has a mode the same size. */ + + if (GET_MODE_SIZE (mode) > UNITS_PER_WORD + && ! ((GET_MODE (x) == VOIDmode + && (GET_CODE (x) == CONST_INT + || GET_CODE (x) == CONST_DOUBLE)) + || GET_MODE_SIZE (GET_MODE (x)) == GET_MODE_SIZE (mode))) + return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx); + + /* X might be a paradoxical (subreg (mem)). In that case, gen_lowpart + won't know what to do. So we will strip off the SUBREG here and + process normally. */ + if (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == MEM) + { + x = SUBREG_REG (x); + if (GET_MODE (x) == mode) + return x; + } + + result = gen_lowpart_common (mode, x); + if (result != 0 + && GET_CODE (result) == SUBREG + && GET_CODE (SUBREG_REG (result)) == REG + && REGNO (SUBREG_REG (result)) >= FIRST_PSEUDO_REGISTER + && (GET_MODE_SIZE (GET_MODE (result)) + != GET_MODE_SIZE (GET_MODE (SUBREG_REG (result))))) + REG_CHANGES_SIZE (REGNO (SUBREG_REG (result))) = 1; + + if (result) + return result; + + if (GET_CODE (x) == MEM) + { + register int offset = 0; + rtx new; + + /* Refuse to work on a volatile memory ref or one with a mode-dependent + address. */ + if (MEM_VOLATILE_P (x) || mode_dependent_address_p (XEXP (x, 0))) + return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx); + + /* If we want to refer to something bigger than the original memref, + generate a perverse subreg instead. That will force a reload + of the original memref X. */ + if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode)) + return gen_rtx_SUBREG (mode, x, 0); + + 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)))); + } + new = gen_rtx_MEM (mode, plus_constant (XEXP (x, 0), offset)); + RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (x); + MEM_COPY_ATTRIBUTES (new, x); + return new; + } + + /* If X is a comparison operator, rewrite it in a new mode. This + probably won't match, but may allow further simplifications. */ + else if (GET_RTX_CLASS (GET_CODE (x)) == '<') + return gen_rtx_combine (GET_CODE (x), mode, XEXP (x, 0), XEXP (x, 1)); + + /* If we couldn't simplify X any other way, just enclose it in a + SUBREG. Normally, this SUBREG won't match, but some patterns may + include an explicit SUBREG or we may simplify it further in combine. */ + else + { + int word = 0; + + if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) + word = ((GET_MODE_SIZE (GET_MODE (x)) + - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)) + / UNITS_PER_WORD); + return gen_rtx_SUBREG (mode, x, word); + } +} + +/* Make an rtx expression. This is a subset of gen_rtx and only supports + expressions of 1, 2, or 3 operands, each of which are rtx expressions. + + If the identical expression was previously in the insn (in the undobuf), + it will be returned. Only if it is not found will a new expression + be made. */ + +/*VARARGS2*/ +static rtx +gen_rtx_combine VPROTO((enum rtx_code code, enum machine_mode mode, ...)) +{ +#ifndef ANSI_PROTOTYPES + enum rtx_code code; + enum machine_mode mode; +#endif + va_list p; + int n_args; + rtx args[3]; + int j; + char *fmt; + rtx rt; + struct undo *undo; + + VA_START (p, mode); + +#ifndef ANSI_PROTOTYPES + code = va_arg (p, enum rtx_code); + mode = va_arg (p, enum machine_mode); +#endif + + n_args = GET_RTX_LENGTH (code); + fmt = GET_RTX_FORMAT (code); + + if (n_args == 0 || n_args > 3) + abort (); + + /* Get each arg and verify that it is supposed to be an expression. */ + for (j = 0; j < n_args; j++) + { + if (*fmt++ != 'e') + abort (); + + args[j] = va_arg (p, rtx); + } + + /* See if this is in undobuf. Be sure we don't use objects that came + from another insn; this could produce circular rtl structures. */ + + for (undo = undobuf.undos; undo != undobuf.previous_undos; undo = undo->next) + if (!undo->is_int + && GET_CODE (undo->old_contents.r) == code + && GET_MODE (undo->old_contents.r) == mode) + { + for (j = 0; j < n_args; j++) + if (XEXP (undo->old_contents.r, j) != args[j]) + break; + + if (j == n_args) + return undo->old_contents.r; + } + + /* Otherwise make a new rtx. We know we have 1, 2, or 3 args. + Use rtx_alloc instead of gen_rtx because it's faster on RISC. */ + rt = rtx_alloc (code); + PUT_MODE (rt, mode); + XEXP (rt, 0) = args[0]; + if (n_args > 1) + { + XEXP (rt, 1) = args[1]; + if (n_args > 2) + XEXP (rt, 2) = args[2]; + } + return rt; +} + +/* These routines make binary and unary operations by first seeing if they + fold; if not, a new expression is allocated. */ + +static rtx +gen_binary (code, mode, op0, op1) + enum rtx_code code; + enum machine_mode mode; + rtx op0, op1; +{ + rtx result; + rtx tem; + + if (GET_RTX_CLASS (code) == 'c' + && (GET_CODE (op0) == CONST_INT + || (CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT))) + tem = op0, op0 = op1, op1 = tem; + + if (GET_RTX_CLASS (code) == '<') + { + enum machine_mode op_mode = GET_MODE (op0); + + /* Strip the COMPARE from (REL_OP (compare X Y) 0) to get + just (REL_OP X Y). */ + if (GET_CODE (op0) == COMPARE && op1 == const0_rtx) + { + op1 = XEXP (op0, 1); + op0 = XEXP (op0, 0); + op_mode = GET_MODE (op0); + } + + if (op_mode == VOIDmode) + op_mode = GET_MODE (op1); + result = simplify_relational_operation (code, op_mode, op0, op1); + } + else + result = simplify_binary_operation (code, mode, op0, op1); + + if (result) + return result; + + /* Put complex operands first and constants second. */ + if (GET_RTX_CLASS (code) == 'c' + && ((CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT) + || (GET_RTX_CLASS (GET_CODE (op0)) == 'o' + && GET_RTX_CLASS (GET_CODE (op1)) != 'o') + || (GET_CODE (op0) == SUBREG + && GET_RTX_CLASS (GET_CODE (SUBREG_REG (op0))) == 'o' + && GET_RTX_CLASS (GET_CODE (op1)) != 'o'))) + return gen_rtx_combine (code, mode, op1, op0); + + /* If we are turning off bits already known off in OP0, we need not do + an AND. */ + else if (code == AND && GET_CODE (op1) == CONST_INT + && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT + && (nonzero_bits (op0, mode) & ~ INTVAL (op1)) == 0) + return op0; + + return gen_rtx_combine (code, mode, op0, op1); +} + +static rtx +gen_unary (code, mode, op0_mode, op0) + enum rtx_code code; + enum machine_mode mode, op0_mode; + rtx op0; +{ + rtx result = simplify_unary_operation (code, mode, op0, op0_mode); + + if (result) + return result; + + return gen_rtx_combine (code, mode, op0); +} + +/* Simplify a comparison between *POP0 and *POP1 where CODE is the + comparison code that will be tested. + + The result is a possibly different comparison code to use. *POP0 and + *POP1 may be updated. + + It is possible that we might detect that a comparison is either always + true or always false. However, we do not perform general constant + folding in combine, so this knowledge isn't useful. Such tautologies + should have been detected earlier. Hence we ignore all such cases. */ + +static enum rtx_code +simplify_comparison (code, pop0, pop1) + enum rtx_code code; + rtx *pop0; + rtx *pop1; +{ + rtx op0 = *pop0; + rtx op1 = *pop1; + rtx tem, tem1; + int i; + enum machine_mode mode, tmode; + + /* Try a few ways of applying the same transformation to both operands. */ + while (1) + { +#ifndef WORD_REGISTER_OPERATIONS + /* The test below this one won't handle SIGN_EXTENDs on these machines, + so check specially. */ + if (code != GTU && code != GEU && code != LTU && code != LEU + && GET_CODE (op0) == ASHIFTRT && GET_CODE (op1) == ASHIFTRT + && GET_CODE (XEXP (op0, 0)) == ASHIFT + && GET_CODE (XEXP (op1, 0)) == ASHIFT + && GET_CODE (XEXP (XEXP (op0, 0), 0)) == SUBREG + && GET_CODE (XEXP (XEXP (op1, 0), 0)) == SUBREG + && (GET_MODE (SUBREG_REG (XEXP (XEXP (op0, 0), 0))) + == GET_MODE (SUBREG_REG (XEXP (XEXP (op1, 0), 0)))) + && GET_CODE (XEXP (op0, 1)) == CONST_INT + && GET_CODE (XEXP (op1, 1)) == CONST_INT + && GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT + && GET_CODE (XEXP (XEXP (op1, 0), 1)) == CONST_INT + && INTVAL (XEXP (op0, 1)) == INTVAL (XEXP (op1, 1)) + && INTVAL (XEXP (op0, 1)) == INTVAL (XEXP (XEXP (op0, 0), 1)) + && INTVAL (XEXP (op0, 1)) == INTVAL (XEXP (XEXP (op1, 0), 1)) + && (INTVAL (XEXP (op0, 1)) + == (GET_MODE_BITSIZE (GET_MODE (op0)) + - (GET_MODE_BITSIZE + (GET_MODE (SUBREG_REG (XEXP (XEXP (op0, 0), 0)))))))) + { + op0 = SUBREG_REG (XEXP (XEXP (op0, 0), 0)); + op1 = SUBREG_REG (XEXP (XEXP (op1, 0), 0)); + } +#endif + + /* If both operands are the same constant shift, see if we can ignore the + shift. We can if the shift is a rotate or if the bits shifted out of + this shift are known to be zero for both inputs and if the type of + comparison is compatible with the shift. */ + if (GET_CODE (op0) == GET_CODE (op1) + && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT + && ((GET_CODE (op0) == ROTATE && (code == NE || code == EQ)) + || ((GET_CODE (op0) == LSHIFTRT || GET_CODE (op0) == ASHIFT) + && (code != GT && code != LT && code != GE && code != LE)) + || (GET_CODE (op0) == ASHIFTRT + && (code != GTU && code != LTU + && code != GEU && code != GEU))) + && GET_CODE (XEXP (op0, 1)) == CONST_INT + && INTVAL (XEXP (op0, 1)) >= 0 + && INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT + && XEXP (op0, 1) == XEXP (op1, 1)) + { + enum machine_mode mode = GET_MODE (op0); + unsigned HOST_WIDE_INT mask = GET_MODE_MASK (mode); + int shift_count = INTVAL (XEXP (op0, 1)); + + if (GET_CODE (op0) == LSHIFTRT || GET_CODE (op0) == ASHIFTRT) + mask &= (mask >> shift_count) << shift_count; + else if (GET_CODE (op0) == ASHIFT) + mask = (mask & (mask << shift_count)) >> shift_count; + + if ((nonzero_bits (XEXP (op0, 0), mode) & ~ mask) == 0 + && (nonzero_bits (XEXP (op1, 0), mode) & ~ mask) == 0) + op0 = XEXP (op0, 0), op1 = XEXP (op1, 0); + else + break; + } + + /* If both operands are AND's of a paradoxical SUBREG by constant, the + SUBREGs are of the same mode, and, in both cases, the AND would + be redundant if the comparison was done in the narrower mode, + do the comparison in the narrower mode (e.g., we are AND'ing with 1 + and the operand's possibly nonzero bits are 0xffffff01; in that case + if we only care about QImode, we don't need the AND). This case + occurs if the output mode of an scc insn is not SImode and + STORE_FLAG_VALUE == 1 (e.g., the 386). + + Similarly, check for a case where the AND's are ZERO_EXTEND + operations from some narrower mode even though a SUBREG is not + present. */ + + else if (GET_CODE (op0) == AND && GET_CODE (op1) == AND + && GET_CODE (XEXP (op0, 1)) == CONST_INT + && GET_CODE (XEXP (op1, 1)) == CONST_INT) + { + rtx inner_op0 = XEXP (op0, 0); + rtx inner_op1 = XEXP (op1, 0); + HOST_WIDE_INT c0 = INTVAL (XEXP (op0, 1)); + HOST_WIDE_INT c1 = INTVAL (XEXP (op1, 1)); + int changed = 0; + + if (GET_CODE (inner_op0) == SUBREG && GET_CODE (inner_op1) == SUBREG + && (GET_MODE_SIZE (GET_MODE (inner_op0)) + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (inner_op0)))) + && (GET_MODE (SUBREG_REG (inner_op0)) + == GET_MODE (SUBREG_REG (inner_op1))) + && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (inner_op0))) + <= HOST_BITS_PER_WIDE_INT) + && (0 == ((~c0) & nonzero_bits (SUBREG_REG (inner_op0), + GET_MODE (SUBREG_REG (inner_op0))))) + && (0 == ((~c1) & nonzero_bits (SUBREG_REG (inner_op1), + GET_MODE (SUBREG_REG (inner_op1)))))) + { + op0 = SUBREG_REG (inner_op0); + op1 = SUBREG_REG (inner_op1); + + /* The resulting comparison is always unsigned since we masked + off the original sign bit. */ + code = unsigned_condition (code); + + changed = 1; + } + + else if (c0 == c1) + for (tmode = GET_CLASS_NARROWEST_MODE + (GET_MODE_CLASS (GET_MODE (op0))); + tmode != GET_MODE (op0); tmode = GET_MODE_WIDER_MODE (tmode)) + if ((unsigned HOST_WIDE_INT) c0 == GET_MODE_MASK (tmode)) + { + op0 = gen_lowpart_for_combine (tmode, inner_op0); + op1 = gen_lowpart_for_combine (tmode, inner_op1); + code = unsigned_condition (code); + changed = 1; + break; + } + + if (! changed) + break; + } + + /* If both operands are NOT, we can strip off the outer operation + and adjust the comparison code for swapped operands; similarly for + NEG, except that this must be an equality comparison. */ + else if ((GET_CODE (op0) == NOT && GET_CODE (op1) == NOT) + || (GET_CODE (op0) == NEG && GET_CODE (op1) == NEG + && (code == EQ || code == NE))) + op0 = XEXP (op0, 0), op1 = XEXP (op1, 0), code = swap_condition (code); + + else + break; + } + + /* If the first operand is a constant, swap the operands and adjust the + comparison code appropriately, but don't do this if the second operand + is already a constant integer. */ + if (CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT) + { + tem = op0, op0 = op1, op1 = tem; + code = swap_condition (code); + } + + /* We now enter a loop during which we will try to simplify the comparison. + For the most part, we only are concerned with comparisons with zero, + but some things may really be comparisons with zero but not start + out looking that way. */ + + while (GET_CODE (op1) == CONST_INT) + { + enum machine_mode mode = GET_MODE (op0); + int mode_width = GET_MODE_BITSIZE (mode); + unsigned HOST_WIDE_INT mask = GET_MODE_MASK (mode); + int equality_comparison_p; + int sign_bit_comparison_p; + int unsigned_comparison_p; + HOST_WIDE_INT const_op; + + /* We only want to handle integral modes. This catches VOIDmode, + CCmode, and the floating-point modes. An exception is that we + can handle VOIDmode if OP0 is a COMPARE or a comparison + operation. */ + + if (GET_MODE_CLASS (mode) != MODE_INT + && ! (mode == VOIDmode + && (GET_CODE (op0) == COMPARE + || GET_RTX_CLASS (GET_CODE (op0)) == '<'))) + break; + + /* Get the constant we are comparing against and turn off all bits + not on in our mode. */ + const_op = INTVAL (op1); + if (mode_width <= HOST_BITS_PER_WIDE_INT) + const_op &= mask; + + /* If we are comparing against a constant power of two and the value + being compared can only have that single bit nonzero (e.g., it was + `and'ed with that bit), we can replace this with a comparison + with zero. */ + if (const_op + && (code == EQ || code == NE || code == GE || code == GEU + || code == LT || code == LTU) + && mode_width <= HOST_BITS_PER_WIDE_INT + && exact_log2 (const_op) >= 0 + && nonzero_bits (op0, mode) == (unsigned HOST_WIDE_INT) const_op) + { + code = (code == EQ || code == GE || code == GEU ? NE : EQ); + op1 = const0_rtx, const_op = 0; + } + + /* Similarly, if we are comparing a value known to be either -1 or + 0 with -1, change it to the opposite comparison against zero. */ + + if (const_op == -1 + && (code == EQ || code == NE || code == GT || code == LE + || code == GEU || code == LTU) + && num_sign_bit_copies (op0, mode) == mode_width) + { + code = (code == EQ || code == LE || code == GEU ? NE : EQ); + op1 = const0_rtx, const_op = 0; + } + + /* Do some canonicalizations based on the comparison code. We prefer + comparisons against zero and then prefer equality comparisons. + If we can reduce the size of a constant, we will do that too. */ + + switch (code) + { + case LT: + /* < C is equivalent to <= (C - 1) */ + if (const_op > 0) + { + const_op -= 1; + op1 = GEN_INT (const_op); + code = LE; + /* ... fall through to LE case below. */ + } + else + break; + + case LE: + /* <= C is equivalent to < (C + 1); we do this for C < 0 */ + if (const_op < 0) + { + const_op += 1; + op1 = GEN_INT (const_op); + code = LT; + } + + /* If we are doing a <= 0 comparison on a value known to have + a zero sign bit, we can replace this with == 0. */ + else if (const_op == 0 + && mode_width <= HOST_BITS_PER_WIDE_INT + && (nonzero_bits (op0, mode) + & ((HOST_WIDE_INT) 1 << (mode_width - 1))) == 0) + code = EQ; + break; + + case GE: + /* >= C is equivalent to > (C - 1). */ + if (const_op > 0) + { + const_op -= 1; + op1 = GEN_INT (const_op); + code = GT; + /* ... fall through to GT below. */ + } + else + break; + + case GT: + /* > C is equivalent to >= (C + 1); we do this for C < 0*/ + if (const_op < 0) + { + const_op += 1; + op1 = GEN_INT (const_op); + code = GE; + } + + /* If we are doing a > 0 comparison on a value known to have + a zero sign bit, we can replace this with != 0. */ + else if (const_op == 0 + && mode_width <= HOST_BITS_PER_WIDE_INT + && (nonzero_bits (op0, mode) + & ((HOST_WIDE_INT) 1 << (mode_width - 1))) == 0) + code = NE; + break; + + case LTU: + /* < C is equivalent to <= (C - 1). */ + if (const_op > 0) + { + const_op -= 1; + op1 = GEN_INT (const_op); + code = LEU; + /* ... fall through ... */ + } + + /* (unsigned) < 0x80000000 is equivalent to >= 0. */ + else if ((mode_width <= HOST_BITS_PER_WIDE_INT) + && (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1))) + { + const_op = 0, op1 = const0_rtx; + code = GE; + break; + } + else + break; + + case LEU: + /* unsigned <= 0 is equivalent to == 0 */ + if (const_op == 0) + code = EQ; + + /* (unsigned) <= 0x7fffffff is equivalent to >= 0. */ + else if ((mode_width <= HOST_BITS_PER_WIDE_INT) + && (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1)) + { + const_op = 0, op1 = const0_rtx; + code = GE; + } + break; + + case GEU: + /* >= C is equivalent to < (C - 1). */ + if (const_op > 1) + { + const_op -= 1; + op1 = GEN_INT (const_op); + code = GTU; + /* ... fall through ... */ + } + + /* (unsigned) >= 0x80000000 is equivalent to < 0. */ + else if ((mode_width <= HOST_BITS_PER_WIDE_INT) + && (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1))) + { + const_op = 0, op1 = const0_rtx; + code = LT; + break; + } + else + break; + + case GTU: + /* unsigned > 0 is equivalent to != 0 */ + if (const_op == 0) + code = NE; + + /* (unsigned) > 0x7fffffff is equivalent to < 0. */ + else if ((mode_width <= HOST_BITS_PER_WIDE_INT) + && (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1)) + { + const_op = 0, op1 = const0_rtx; + code = LT; + } + break; + + default: + break; + } + + /* Compute some predicates to simplify code below. */ + + equality_comparison_p = (code == EQ || code == NE); + sign_bit_comparison_p = ((code == LT || code == GE) && const_op == 0); + unsigned_comparison_p = (code == LTU || code == LEU || code == GTU + || code == LEU); + + /* If this is a sign bit comparison and we can do arithmetic in + MODE, say that we will only be needing the sign bit of OP0. */ + if (sign_bit_comparison_p + && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT) + op0 = force_to_mode (op0, mode, + ((HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (mode) - 1)), + NULL_RTX, 0); + + /* Now try cases based on the opcode of OP0. If none of the cases + does a "continue", we exit this loop immediately after the + switch. */ + + switch (GET_CODE (op0)) + { + case ZERO_EXTRACT: + /* If we are extracting a single bit from a variable position in + a constant that has only a single bit set and are comparing it + with zero, we can convert this into an equality comparison + between the position and the location of the single bit. */ + + if (GET_CODE (XEXP (op0, 0)) == CONST_INT + && XEXP (op0, 1) == const1_rtx + && equality_comparison_p && const_op == 0 + && (i = exact_log2 (INTVAL (XEXP (op0, 0)))) >= 0) + { + if (BITS_BIG_ENDIAN) + { +#ifdef HAVE_extzv + mode = insn_operand_mode[(int) CODE_FOR_extzv][1]; + if (mode == VOIDmode) + mode = word_mode; + i = (GET_MODE_BITSIZE (mode) - 1 - i); +#else + i = BITS_PER_WORD - 1 - i; +#endif + } + + op0 = XEXP (op0, 2); + op1 = GEN_INT (i); + const_op = i; + + /* Result is nonzero iff shift count is equal to I. */ + code = reverse_condition (code); + continue; + } + + /* ... fall through ... */ + + case SIGN_EXTRACT: + tem = expand_compound_operation (op0); + if (tem != op0) + { + op0 = tem; + continue; + } + break; + + case NOT: + /* If testing for equality, we can take the NOT of the constant. */ + if (equality_comparison_p + && (tem = simplify_unary_operation (NOT, mode, op1, mode)) != 0) + { + op0 = XEXP (op0, 0); + op1 = tem; + continue; + } + + /* If just looking at the sign bit, reverse the sense of the + comparison. */ + if (sign_bit_comparison_p) + { + op0 = XEXP (op0, 0); + code = (code == GE ? LT : GE); + continue; + } + break; + + case NEG: + /* If testing for equality, we can take the NEG of the constant. */ + if (equality_comparison_p + && (tem = simplify_unary_operation (NEG, mode, op1, mode)) != 0) + { + op0 = XEXP (op0, 0); + op1 = tem; + continue; + } + + /* The remaining cases only apply to comparisons with zero. */ + if (const_op != 0) + break; + + /* When X is ABS or is known positive, + (neg X) is < 0 if and only if X != 0. */ + + if (sign_bit_comparison_p + && (GET_CODE (XEXP (op0, 0)) == ABS + || (mode_width <= HOST_BITS_PER_WIDE_INT + && (nonzero_bits (XEXP (op0, 0), mode) + & ((HOST_WIDE_INT) 1 << (mode_width - 1))) == 0))) + { + op0 = XEXP (op0, 0); + code = (code == LT ? NE : EQ); + continue; + } + + /* If we have NEG of something whose two high-order bits are the + same, we know that "(-a) < 0" is equivalent to "a > 0". */ + if (num_sign_bit_copies (op0, mode) >= 2) + { + op0 = XEXP (op0, 0); + code = swap_condition (code); + continue; + } + break; + + case ROTATE: + /* If we are testing equality and our count is a constant, we + can perform the inverse operation on our RHS. */ + if (equality_comparison_p && GET_CODE (XEXP (op0, 1)) == CONST_INT + && (tem = simplify_binary_operation (ROTATERT, mode, + op1, XEXP (op0, 1))) != 0) + { + op0 = XEXP (op0, 0); + op1 = tem; + continue; + } + + /* If we are doing a < 0 or >= 0 comparison, it means we are testing + a particular bit. Convert it to an AND of a constant of that + bit. This will be converted into a ZERO_EXTRACT. */ + if (const_op == 0 && sign_bit_comparison_p + && GET_CODE (XEXP (op0, 1)) == CONST_INT + && mode_width <= HOST_BITS_PER_WIDE_INT) + { + op0 = simplify_and_const_int (NULL_RTX, mode, XEXP (op0, 0), + ((HOST_WIDE_INT) 1 + << (mode_width - 1 + - INTVAL (XEXP (op0, 1))))); + code = (code == LT ? NE : EQ); + continue; + } + + /* ... fall through ... */ + + case ABS: + /* ABS is ignorable inside an equality comparison with zero. */ + if (const_op == 0 && equality_comparison_p) + { + op0 = XEXP (op0, 0); + continue; + } + break; + + + case SIGN_EXTEND: + /* Can simplify (compare (zero/sign_extend FOO) CONST) + to (compare FOO CONST) if CONST fits in FOO's mode and we + are either testing inequality or have an unsigned comparison + with ZERO_EXTEND or a signed comparison with SIGN_EXTEND. */ + if (! unsigned_comparison_p + && (GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0))) + <= HOST_BITS_PER_WIDE_INT) + && ((unsigned HOST_WIDE_INT) const_op + < (((unsigned HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0))) - 1))))) + { + op0 = XEXP (op0, 0); + continue; + } + break; + + case SUBREG: + /* Check for the case where we are comparing A - C1 with C2, + both constants are smaller than 1/2 the maximum positive + value in MODE, and the comparison is equality or unsigned. + In that case, if A is either zero-extended to MODE or has + sufficient sign bits so that the high-order bit in MODE + is a copy of the sign in the inner mode, we can prove that it is + safe to do the operation in the wider mode. This simplifies + many range checks. */ + + if (mode_width <= HOST_BITS_PER_WIDE_INT + && subreg_lowpart_p (op0) + && GET_CODE (SUBREG_REG (op0)) == PLUS + && GET_CODE (XEXP (SUBREG_REG (op0), 1)) == CONST_INT + && INTVAL (XEXP (SUBREG_REG (op0), 1)) < 0 + && (- INTVAL (XEXP (SUBREG_REG (op0), 1)) + < (HOST_WIDE_INT)(GET_MODE_MASK (mode) / 2)) + && (unsigned HOST_WIDE_INT) const_op < GET_MODE_MASK (mode) / 2 + && (0 == (nonzero_bits (XEXP (SUBREG_REG (op0), 0), + GET_MODE (SUBREG_REG (op0))) + & ~ GET_MODE_MASK (mode)) + || (num_sign_bit_copies (XEXP (SUBREG_REG (op0), 0), + GET_MODE (SUBREG_REG (op0))) + > (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0))) + - GET_MODE_BITSIZE (mode))))) + { + op0 = SUBREG_REG (op0); + continue; + } + + /* If the inner mode is narrower and we are extracting the low part, + we can treat the SUBREG as if it were a ZERO_EXTEND. */ + if (subreg_lowpart_p (op0) + && GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0))) < mode_width) + /* Fall through */ ; + else + break; + + /* ... fall through ... */ + + case ZERO_EXTEND: + if ((unsigned_comparison_p || equality_comparison_p) + && (GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0))) + <= HOST_BITS_PER_WIDE_INT) + && ((unsigned HOST_WIDE_INT) const_op + < GET_MODE_MASK (GET_MODE (XEXP (op0, 0))))) + { + op0 = XEXP (op0, 0); + continue; + } + break; + + case PLUS: + /* (eq (plus X A) B) -> (eq X (minus B A)). We can only do + this for equality comparisons due to pathological cases involving + overflows. */ + if (equality_comparison_p + && 0 != (tem = simplify_binary_operation (MINUS, mode, + op1, XEXP (op0, 1)))) + { + op0 = XEXP (op0, 0); + op1 = tem; + continue; + } + + /* (plus (abs X) (const_int -1)) is < 0 if and only if X == 0. */ + if (const_op == 0 && XEXP (op0, 1) == constm1_rtx + && GET_CODE (XEXP (op0, 0)) == ABS && sign_bit_comparison_p) + { + op0 = XEXP (XEXP (op0, 0), 0); + code = (code == LT ? EQ : NE); + continue; + } + break; + + case MINUS: + /* (eq (minus A B) C) -> (eq A (plus B C)) or + (eq B (minus A C)), whichever simplifies. We can only do + this for equality comparisons due to pathological cases involving + overflows. */ + if (equality_comparison_p + && 0 != (tem = simplify_binary_operation (PLUS, mode, + XEXP (op0, 1), op1))) + { + op0 = XEXP (op0, 0); + op1 = tem; + continue; + } + + if (equality_comparison_p + && 0 != (tem = simplify_binary_operation (MINUS, mode, + XEXP (op0, 0), op1))) + { + op0 = XEXP (op0, 1); + op1 = tem; + continue; + } + + /* The sign bit of (minus (ashiftrt X C) X), where C is the number + of bits in X minus 1, is one iff X > 0. */ + if (sign_bit_comparison_p && GET_CODE (XEXP (op0, 0)) == ASHIFTRT + && GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT + && INTVAL (XEXP (XEXP (op0, 0), 1)) == mode_width - 1 + && rtx_equal_p (XEXP (XEXP (op0, 0), 0), XEXP (op0, 1))) + { + op0 = XEXP (op0, 1); + code = (code == GE ? LE : GT); + continue; + } + break; + + case XOR: + /* (eq (xor A B) C) -> (eq A (xor B C)). This is a simplification + if C is zero or B is a constant. */ + if (equality_comparison_p + && 0 != (tem = simplify_binary_operation (XOR, mode, + XEXP (op0, 1), op1))) + { + op0 = XEXP (op0, 0); + op1 = tem; + continue; + } + break; + + case EQ: case NE: + case LT: case LTU: case LE: case LEU: + case GT: case GTU: case GE: case GEU: + /* We can't do anything if OP0 is a condition code value, rather + than an actual data value. */ + if (const_op != 0 +#ifdef HAVE_cc0 + || XEXP (op0, 0) == cc0_rtx +#endif + || GET_MODE_CLASS (GET_MODE (XEXP (op0, 0))) == MODE_CC) + break; + + /* Get the two operands being compared. */ + if (GET_CODE (XEXP (op0, 0)) == COMPARE) + tem = XEXP (XEXP (op0, 0), 0), tem1 = XEXP (XEXP (op0, 0), 1); + else + tem = XEXP (op0, 0), tem1 = XEXP (op0, 1); + + /* Check for the cases where we simply want the result of the + earlier test or the opposite of that result. */ + if (code == NE + || (code == EQ && reversible_comparison_p (op0)) + || (GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT + && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT + && (STORE_FLAG_VALUE + & (((HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (GET_MODE (op0)) - 1)))) + && (code == LT + || (code == GE && reversible_comparison_p (op0))))) + { + code = (code == LT || code == NE + ? GET_CODE (op0) : reverse_condition (GET_CODE (op0))); + op0 = tem, op1 = tem1; + continue; + } + break; + + case IOR: + /* The sign bit of (ior (plus X (const_int -1)) X) is non-zero + iff X <= 0. */ + if (sign_bit_comparison_p && GET_CODE (XEXP (op0, 0)) == PLUS + && XEXP (XEXP (op0, 0), 1) == constm1_rtx + && rtx_equal_p (XEXP (XEXP (op0, 0), 0), XEXP (op0, 1))) + { + op0 = XEXP (op0, 1); + code = (code == GE ? GT : LE); + continue; + } + break; + + case AND: + /* Convert (and (xshift 1 X) Y) to (and (lshiftrt Y X) 1). This + will be converted to a ZERO_EXTRACT later. */ + if (const_op == 0 && equality_comparison_p + && GET_CODE (XEXP (op0, 0)) == ASHIFT + && XEXP (XEXP (op0, 0), 0) == const1_rtx) + { + op0 = simplify_and_const_int + (op0, mode, gen_rtx_combine (LSHIFTRT, mode, + XEXP (op0, 1), + XEXP (XEXP (op0, 0), 1)), + (HOST_WIDE_INT) 1); + continue; + } + + /* If we are comparing (and (lshiftrt X C1) C2) for equality with + zero and X is a comparison and C1 and C2 describe only bits set + in STORE_FLAG_VALUE, we can compare with X. */ + if (const_op == 0 && equality_comparison_p + && mode_width <= HOST_BITS_PER_WIDE_INT + && GET_CODE (XEXP (op0, 1)) == CONST_INT + && GET_CODE (XEXP (op0, 0)) == LSHIFTRT + && GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT + && INTVAL (XEXP (XEXP (op0, 0), 1)) >= 0 + && INTVAL (XEXP (XEXP (op0, 0), 1)) < HOST_BITS_PER_WIDE_INT) + { + mask = ((INTVAL (XEXP (op0, 1)) & GET_MODE_MASK (mode)) + << INTVAL (XEXP (XEXP (op0, 0), 1))); + if ((~ STORE_FLAG_VALUE & mask) == 0 + && (GET_RTX_CLASS (GET_CODE (XEXP (XEXP (op0, 0), 0))) == '<' + || ((tem = get_last_value (XEXP (XEXP (op0, 0), 0))) != 0 + && GET_RTX_CLASS (GET_CODE (tem)) == '<'))) + { + op0 = XEXP (XEXP (op0, 0), 0); + continue; + } + } + + /* If we are doing an equality comparison of an AND of a bit equal + to the sign bit, replace this with a LT or GE comparison of + the underlying value. */ + if (equality_comparison_p + && const_op == 0 + && GET_CODE (XEXP (op0, 1)) == CONST_INT + && mode_width <= HOST_BITS_PER_WIDE_INT + && ((INTVAL (XEXP (op0, 1)) & GET_MODE_MASK (mode)) + == (unsigned HOST_WIDE_INT) 1 << (mode_width - 1))) + { + op0 = XEXP (op0, 0); + code = (code == EQ ? GE : LT); + continue; + } + + /* If this AND operation is really a ZERO_EXTEND from a narrower + mode, the constant fits within that mode, and this is either an + equality or unsigned comparison, try to do this comparison in + the narrower mode. */ + if ((equality_comparison_p || unsigned_comparison_p) + && GET_CODE (XEXP (op0, 1)) == CONST_INT + && (i = exact_log2 ((INTVAL (XEXP (op0, 1)) + & GET_MODE_MASK (mode)) + + 1)) >= 0 + && const_op >> i == 0 + && (tmode = mode_for_size (i, MODE_INT, 1)) != BLKmode) + { + op0 = gen_lowpart_for_combine (tmode, XEXP (op0, 0)); + continue; + } + + /* If this is (and:M1 (subreg:M2 X 0) (const_int C1)) where C1 fits + in both M1 and M2 and the SUBREG is either paradoxical or + represents the low part, permute the SUBREG and the AND and + try again. */ + if (GET_CODE (XEXP (op0, 0)) == SUBREG + && ((mode_width + >= GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (XEXP (op0, 0))))) +#ifdef WORD_REGISTER_OPERATIONS + || subreg_lowpart_p (XEXP (op0, 0)) +#endif + ) +#ifndef WORD_REGISTER_OPERATIONS + /* It is unsafe to commute the AND into the SUBREG if the SUBREG + is paradoxical and WORD_REGISTER_OPERATIONS is not defined. + As originally written the upper bits have a defined value + due to the AND operation. However, if we commute the AND + inside the SUBREG then they no longer have defined values + and the meaning of the code has been changed. */ + && (GET_MODE_SIZE (GET_MODE (XEXP (op0, 0))) + <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (op0, 0))))) +#endif + && GET_CODE (XEXP (op0, 1)) == CONST_INT + && mode_width <= HOST_BITS_PER_WIDE_INT + && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (XEXP (op0, 0)))) + <= HOST_BITS_PER_WIDE_INT) + && (INTVAL (XEXP (op0, 1)) & ~ mask) == 0 + && 0 == (~ GET_MODE_MASK (GET_MODE (SUBREG_REG (XEXP (op0, 0)))) + & INTVAL (XEXP (op0, 1))) + && (unsigned HOST_WIDE_INT) INTVAL (XEXP (op0, 1)) != mask + && ((unsigned HOST_WIDE_INT) INTVAL (XEXP (op0, 1)) + != GET_MODE_MASK (GET_MODE (SUBREG_REG (XEXP (op0, 0)))))) + + { + op0 + = gen_lowpart_for_combine + (mode, + gen_binary (AND, GET_MODE (SUBREG_REG (XEXP (op0, 0))), + SUBREG_REG (XEXP (op0, 0)), XEXP (op0, 1))); + continue; + } + + break; + + case ASHIFT: + /* If we have (compare (ashift FOO N) (const_int C)) and + the high order N bits of FOO (N+1 if an inequality comparison) + are known to be zero, we can do this by comparing FOO with C + shifted right N bits so long as the low-order N bits of C are + zero. */ + if (GET_CODE (XEXP (op0, 1)) == CONST_INT + && INTVAL (XEXP (op0, 1)) >= 0 + && ((INTVAL (XEXP (op0, 1)) + ! equality_comparison_p) + < HOST_BITS_PER_WIDE_INT) + && ((const_op + & (((HOST_WIDE_INT) 1 << INTVAL (XEXP (op0, 1))) - 1)) == 0) + && mode_width <= HOST_BITS_PER_WIDE_INT + && (nonzero_bits (XEXP (op0, 0), mode) + & ~ (mask >> (INTVAL (XEXP (op0, 1)) + + ! equality_comparison_p))) == 0) + { + const_op >>= INTVAL (XEXP (op0, 1)); + op1 = GEN_INT (const_op); + op0 = XEXP (op0, 0); + continue; + } + + /* If we are doing a sign bit comparison, it means we are testing + a particular bit. Convert it to the appropriate AND. */ + if (sign_bit_comparison_p && GET_CODE (XEXP (op0, 1)) == CONST_INT + && mode_width <= HOST_BITS_PER_WIDE_INT) + { + op0 = simplify_and_const_int (NULL_RTX, mode, XEXP (op0, 0), + ((HOST_WIDE_INT) 1 + << (mode_width - 1 + - INTVAL (XEXP (op0, 1))))); + code = (code == LT ? NE : EQ); + continue; + } + + /* If this an equality comparison with zero and we are shifting + the low bit to the sign bit, we can convert this to an AND of the + low-order bit. */ + if (const_op == 0 && equality_comparison_p + && GET_CODE (XEXP (op0, 1)) == CONST_INT + && INTVAL (XEXP (op0, 1)) == mode_width - 1) + { + op0 = simplify_and_const_int (NULL_RTX, mode, XEXP (op0, 0), + (HOST_WIDE_INT) 1); + continue; + } + break; + + case ASHIFTRT: + /* If this is an equality comparison with zero, we can do this + as a logical shift, which might be much simpler. */ + if (equality_comparison_p && const_op == 0 + && GET_CODE (XEXP (op0, 1)) == CONST_INT) + { + op0 = simplify_shift_const (NULL_RTX, LSHIFTRT, mode, + XEXP (op0, 0), + INTVAL (XEXP (op0, 1))); + continue; + } + + /* If OP0 is a sign extension and CODE is not an unsigned comparison, + do the comparison in a narrower mode. */ + if (! unsigned_comparison_p + && GET_CODE (XEXP (op0, 1)) == CONST_INT + && GET_CODE (XEXP (op0, 0)) == ASHIFT + && XEXP (op0, 1) == XEXP (XEXP (op0, 0), 1) + && (tmode = mode_for_size (mode_width - INTVAL (XEXP (op0, 1)), + MODE_INT, 1)) != BLKmode + && ((unsigned HOST_WIDE_INT) const_op <= GET_MODE_MASK (tmode) + || ((unsigned HOST_WIDE_INT) - const_op + <= GET_MODE_MASK (tmode)))) + { + op0 = gen_lowpart_for_combine (tmode, XEXP (XEXP (op0, 0), 0)); + continue; + } + + /* ... fall through ... */ + case LSHIFTRT: + /* If we have (compare (xshiftrt FOO N) (const_int C)) and + the low order N bits of FOO are known to be zero, we can do this + by comparing FOO with C shifted left N bits so long as no + overflow occurs. */ + if (GET_CODE (XEXP (op0, 1)) == CONST_INT + && INTVAL (XEXP (op0, 1)) >= 0 + && INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT + && mode_width <= HOST_BITS_PER_WIDE_INT + && (nonzero_bits (XEXP (op0, 0), mode) + & (((HOST_WIDE_INT) 1 << INTVAL (XEXP (op0, 1))) - 1)) == 0 + && (const_op == 0 + || (floor_log2 (const_op) + INTVAL (XEXP (op0, 1)) + < mode_width))) + { + const_op <<= INTVAL (XEXP (op0, 1)); + op1 = GEN_INT (const_op); + op0 = XEXP (op0, 0); + continue; + } + + /* If we are using this shift to extract just the sign bit, we + can replace this with an LT or GE comparison. */ + if (const_op == 0 + && (equality_comparison_p || sign_bit_comparison_p) + && GET_CODE (XEXP (op0, 1)) == CONST_INT + && INTVAL (XEXP (op0, 1)) == mode_width - 1) + { + op0 = XEXP (op0, 0); + code = (code == NE || code == GT ? LT : GE); + continue; + } + break; + + default: + break; + } + + break; + } + + /* Now make any compound operations involved in this comparison. Then, + check for an outmost SUBREG on OP0 that is not doing anything or is + paradoxical. The latter case can only occur when it is known that the + "extra" bits will be zero. Therefore, it is safe to remove the SUBREG. + We can never remove a SUBREG for a non-equality comparison because the + sign bit is in a different place in the underlying object. */ + + op0 = make_compound_operation (op0, op1 == const0_rtx ? COMPARE : SET); + op1 = make_compound_operation (op1, SET); + + if (GET_CODE (op0) == SUBREG && subreg_lowpart_p (op0) + && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT + && (code == NE || code == EQ) + && ((GET_MODE_SIZE (GET_MODE (op0)) + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))) + { + op0 = SUBREG_REG (op0); + op1 = gen_lowpart_for_combine (GET_MODE (op0), op1); + } + + else if (GET_CODE (op0) == SUBREG && subreg_lowpart_p (op0) + && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT + && (code == NE || code == EQ) + && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0))) + <= HOST_BITS_PER_WIDE_INT) + && (nonzero_bits (SUBREG_REG (op0), GET_MODE (SUBREG_REG (op0))) + & ~ GET_MODE_MASK (GET_MODE (op0))) == 0 + && (tem = gen_lowpart_for_combine (GET_MODE (SUBREG_REG (op0)), + op1), + (nonzero_bits (tem, GET_MODE (SUBREG_REG (op0))) + & ~ GET_MODE_MASK (GET_MODE (op0))) == 0)) + op0 = SUBREG_REG (op0), op1 = tem; + + /* We now do the opposite procedure: Some machines don't have compare + insns in all modes. If OP0's mode is an integer mode smaller than a + word and we can't do a compare in that mode, see if there is a larger + mode for which we can do the compare. There are a number of cases in + which we can use the wider mode. */ + + mode = GET_MODE (op0); + if (mode != VOIDmode && GET_MODE_CLASS (mode) == MODE_INT + && GET_MODE_SIZE (mode) < UNITS_PER_WORD + && cmp_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing) + for (tmode = GET_MODE_WIDER_MODE (mode); + (tmode != VOIDmode + && GET_MODE_BITSIZE (tmode) <= HOST_BITS_PER_WIDE_INT); + tmode = GET_MODE_WIDER_MODE (tmode)) + if (cmp_optab->handlers[(int) tmode].insn_code != CODE_FOR_nothing) + { + /* If the only nonzero bits in OP0 and OP1 are those in the + narrower mode and this is an equality or unsigned comparison, + we can use the wider mode. Similarly for sign-extended + values, in which case it is true for all comparisons. */ + if (((code == EQ || code == NE + || code == GEU || code == GTU || code == LEU || code == LTU) + && (nonzero_bits (op0, tmode) & ~ GET_MODE_MASK (mode)) == 0 + && (nonzero_bits (op1, tmode) & ~ GET_MODE_MASK (mode)) == 0) + || ((num_sign_bit_copies (op0, tmode) + > GET_MODE_BITSIZE (tmode) - GET_MODE_BITSIZE (mode)) + && (num_sign_bit_copies (op1, tmode) + > GET_MODE_BITSIZE (tmode) - GET_MODE_BITSIZE (mode)))) + { + op0 = gen_lowpart_for_combine (tmode, op0); + op1 = gen_lowpart_for_combine (tmode, op1); + break; + } + + /* If this is a test for negative, we can make an explicit + test of the sign bit. */ + + if (op1 == const0_rtx && (code == LT || code == GE) + && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT) + { + op0 = gen_binary (AND, tmode, + gen_lowpart_for_combine (tmode, op0), + GEN_INT ((HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (mode) - 1))); + code = (code == LT) ? NE : EQ; + break; + } + } + +#ifdef CANONICALIZE_COMPARISON + /* If this machine only supports a subset of valid comparisons, see if we + can convert an unsupported one into a supported one. */ + CANONICALIZE_COMPARISON (code, op0, op1); +#endif + + *pop0 = op0; + *pop1 = op1; + + return code; +} + +/* Return 1 if we know that X, a comparison operation, is not operating + on a floating-point value or is EQ or NE, meaning that we can safely + reverse it. */ + +static int +reversible_comparison_p (x) + rtx x; +{ + if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT + || flag_fast_math + || GET_CODE (x) == NE || GET_CODE (x) == EQ) + return 1; + + switch (GET_MODE_CLASS (GET_MODE (XEXP (x, 0)))) + { + case MODE_INT: + case MODE_PARTIAL_INT: + case MODE_COMPLEX_INT: + return 1; + + case MODE_CC: + /* If the mode of the condition codes tells us that this is safe, + we need look no further. */ + if (REVERSIBLE_CC_MODE (GET_MODE (XEXP (x, 0)))) + return 1; + + /* Otherwise try and find where the condition codes were last set and + use that. */ + x = get_last_value (XEXP (x, 0)); + return (x && GET_CODE (x) == COMPARE + && ! FLOAT_MODE_P (GET_MODE (XEXP (x, 0)))); + + default: + return 0; + } +} + +/* Utility function for following routine. Called when X is part of a value + being stored into reg_last_set_value. Sets reg_last_set_table_tick + for each register mentioned. Similar to mention_regs in cse.c */ + +static void +update_table_tick (x) + rtx x; +{ + register enum rtx_code code = GET_CODE (x); + register char *fmt = GET_RTX_FORMAT (code); + register int i; + + if (code == REG) + { + int regno = REGNO (x); + int endregno = regno + (regno < FIRST_PSEUDO_REGISTER + ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1); + + for (i = regno; i < endregno; i++) + reg_last_set_table_tick[i] = label_tick; + + return; + } + + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + /* Note that we can't have an "E" in values stored; see + get_last_value_validate. */ + if (fmt[i] == 'e') + update_table_tick (XEXP (x, i)); +} + +/* Record that REG is set to VALUE in insn INSN. If VALUE is zero, we + are saying that the register is clobbered and we no longer know its + value. If INSN is zero, don't update reg_last_set; this is only permitted + with VALUE also zero and is used to invalidate the register. */ + +static void +record_value_for_reg (reg, insn, value) + rtx reg; + rtx insn; + rtx value; +{ + int regno = REGNO (reg); + int endregno = regno + (regno < FIRST_PSEUDO_REGISTER + ? HARD_REGNO_NREGS (regno, GET_MODE (reg)) : 1); + int i; + + /* If VALUE contains REG and we have a previous value for REG, substitute + the previous value. */ + if (value && insn && reg_overlap_mentioned_p (reg, value)) + { + rtx tem; + + /* Set things up so get_last_value is allowed to see anything set up to + our insn. */ + subst_low_cuid = INSN_CUID (insn); + tem = get_last_value (reg); + + if (tem) + value = replace_rtx (copy_rtx (value), reg, tem); + } + + /* For each register modified, show we don't know its value, that + we don't know about its bitwise content, that its value has been + updated, and that we don't know the location of the death of the + register. */ + for (i = regno; i < endregno; i ++) + { + if (insn) + reg_last_set[i] = insn; + reg_last_set_value[i] = 0; + reg_last_set_mode[i] = 0; + reg_last_set_nonzero_bits[i] = 0; + reg_last_set_sign_bit_copies[i] = 0; + reg_last_death[i] = 0; + } + + /* Mark registers that are being referenced in this value. */ + if (value) + update_table_tick (value); + + /* Now update the status of each register being set. + If someone is using this register in this block, set this register + to invalid since we will get confused between the two lives in this + basic block. This makes using this register always invalid. In cse, we + scan the table to invalidate all entries using this register, but this + is too much work for us. */ + + for (i = regno; i < endregno; i++) + { + reg_last_set_label[i] = label_tick; + if (value && reg_last_set_table_tick[i] == label_tick) + reg_last_set_invalid[i] = 1; + else + reg_last_set_invalid[i] = 0; + } + + /* The value being assigned might refer to X (like in "x++;"). In that + case, we must replace it with (clobber (const_int 0)) to prevent + infinite loops. */ + if (value && ! get_last_value_validate (&value, insn, + reg_last_set_label[regno], 0)) + { + value = copy_rtx (value); + if (! get_last_value_validate (&value, insn, + reg_last_set_label[regno], 1)) + value = 0; + } + + /* For the main register being modified, update the value, the mode, the + nonzero bits, and the number of sign bit copies. */ + + reg_last_set_value[regno] = value; + + if (value) + { + subst_low_cuid = INSN_CUID (insn); + reg_last_set_mode[regno] = GET_MODE (reg); + reg_last_set_nonzero_bits[regno] = nonzero_bits (value, GET_MODE (reg)); + reg_last_set_sign_bit_copies[regno] + = num_sign_bit_copies (value, GET_MODE (reg)); + } +} + +/* Used for communication between the following two routines. */ +static rtx record_dead_insn; + +/* Called via note_stores from record_dead_and_set_regs to handle one + SET or CLOBBER in an insn. */ + +static void +record_dead_and_set_regs_1 (dest, setter) + rtx dest, setter; +{ + if (GET_CODE (dest) == SUBREG) + dest = SUBREG_REG (dest); + + if (GET_CODE (dest) == REG) + { + /* If we are setting the whole register, we know its value. Otherwise + show that we don't know the value. We can handle SUBREG in + some cases. */ + if (GET_CODE (setter) == SET && dest == SET_DEST (setter)) + record_value_for_reg (dest, record_dead_insn, SET_SRC (setter)); + else if (GET_CODE (setter) == SET + && GET_CODE (SET_DEST (setter)) == SUBREG + && SUBREG_REG (SET_DEST (setter)) == dest + && GET_MODE_BITSIZE (GET_MODE (dest)) <= BITS_PER_WORD + && subreg_lowpart_p (SET_DEST (setter))) + record_value_for_reg (dest, record_dead_insn, + gen_lowpart_for_combine (GET_MODE (dest), + SET_SRC (setter))); + else + record_value_for_reg (dest, record_dead_insn, NULL_RTX); + } + else if (GET_CODE (dest) == MEM + /* Ignore pushes, they clobber nothing. */ + && ! push_operand (dest, GET_MODE (dest))) + mem_last_set = INSN_CUID (record_dead_insn); +} + +/* Update the records of when each REG was most recently set or killed + for the things done by INSN. This is the last thing done in processing + INSN in the combiner loop. + + We update reg_last_set, reg_last_set_value, reg_last_set_mode, + reg_last_set_nonzero_bits, reg_last_set_sign_bit_copies, reg_last_death, + and also the similar information mem_last_set (which insn most recently + modified memory) and last_call_cuid (which insn was the most recent + subroutine call). */ + +static void +record_dead_and_set_regs (insn) + rtx insn; +{ + register rtx link; + int i; + + for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) + { + if (REG_NOTE_KIND (link) == REG_DEAD + && GET_CODE (XEXP (link, 0)) == REG) + { + int regno = REGNO (XEXP (link, 0)); + int endregno + = regno + (regno < FIRST_PSEUDO_REGISTER + ? HARD_REGNO_NREGS (regno, GET_MODE (XEXP (link, 0))) + : 1); + + for (i = regno; i < endregno; i++) + reg_last_death[i] = insn; + } + else if (REG_NOTE_KIND (link) == REG_INC) + record_value_for_reg (XEXP (link, 0), insn, NULL_RTX); + } + + if (GET_CODE (insn) == CALL_INSN) + { + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (call_used_regs[i]) + { + reg_last_set_value[i] = 0; + reg_last_set_mode[i] = 0; + reg_last_set_nonzero_bits[i] = 0; + reg_last_set_sign_bit_copies[i] = 0; + reg_last_death[i] = 0; + } + + last_call_cuid = mem_last_set = INSN_CUID (insn); + } + + record_dead_insn = insn; + note_stores (PATTERN (insn), record_dead_and_set_regs_1); +} + +/* Utility routine for the following function. Verify that all the registers + mentioned in *LOC are valid when *LOC was part of a value set when + label_tick == TICK. Return 0 if some are not. + + If REPLACE is non-zero, replace the invalid reference with + (clobber (const_int 0)) and return 1. This replacement is useful because + we often can get useful information about the form of a value (e.g., if + it was produced by a shift that always produces -1 or 0) even though + we don't know exactly what registers it was produced from. */ + +static int +get_last_value_validate (loc, insn, tick, replace) + rtx *loc; + rtx insn; + int tick; + int replace; +{ + rtx x = *loc; + char *fmt = GET_RTX_FORMAT (GET_CODE (x)); + int len = GET_RTX_LENGTH (GET_CODE (x)); + int i; + + if (GET_CODE (x) == REG) + { + int regno = REGNO (x); + int endregno = regno + (regno < FIRST_PSEUDO_REGISTER + ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1); + int j; + + for (j = regno; j < endregno; j++) + if (reg_last_set_invalid[j] + /* If this is a pseudo-register that was only set once, it is + always valid. */ + || (! (regno >= FIRST_PSEUDO_REGISTER && REG_N_SETS (regno) == 1) + && reg_last_set_label[j] > tick)) + { + if (replace) + *loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx); + return replace; + } + + return 1; + } + /* If this is a memory reference, make sure that there were + no stores after it that might have clobbered the value. We don't + have alias info, so we assume any store invalidates it. */ + else if (GET_CODE (x) == MEM && ! RTX_UNCHANGING_P (x) + && INSN_CUID (insn) <= mem_last_set) + { + if (replace) + *loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx); + return replace; + } + + for (i = 0; i < len; i++) + if ((fmt[i] == 'e' + && get_last_value_validate (&XEXP (x, i), insn, tick, replace) == 0) + /* Don't bother with these. They shouldn't occur anyway. */ + || fmt[i] == 'E') + return 0; + + /* If we haven't found a reason for it to be invalid, it is valid. */ + return 1; +} + +/* Get the last value assigned to X, if known. Some registers + in the value may be replaced with (clobber (const_int 0)) if their value + is known longer known reliably. */ + +static rtx +get_last_value (x) + rtx x; +{ + int regno; + rtx value; + + /* If this is a non-paradoxical SUBREG, get the value of its operand and + then convert it to the desired mode. If this is a paradoxical SUBREG, + we cannot predict what values the "extra" bits might have. */ + if (GET_CODE (x) == SUBREG + && subreg_lowpart_p (x) + && (GET_MODE_SIZE (GET_MODE (x)) + <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) + && (value = get_last_value (SUBREG_REG (x))) != 0) + return gen_lowpart_for_combine (GET_MODE (x), value); + + if (GET_CODE (x) != REG) + return 0; + + regno = REGNO (x); + value = reg_last_set_value[regno]; + + /* If we don't have a value or if it isn't for this basic block, + return 0. */ + + if (value == 0 + || (REG_N_SETS (regno) != 1 + && reg_last_set_label[regno] != label_tick)) + return 0; + + /* If the value was set in a later insn than the ones we are processing, + we can't use it even if the register was only set once, but make a quick + check to see if the previous insn set it to something. This is commonly + the case when the same pseudo is used by repeated insns. + + This does not work if there exists an instruction which is temporarily + not on the insn chain. */ + + if (INSN_CUID (reg_last_set[regno]) >= subst_low_cuid) + { + rtx insn, set; + + /* We can not do anything useful in this case, because there is + an instruction which is not on the insn chain. */ + if (subst_prev_insn) + return 0; + + /* Skip over USE insns. They are not useful here, and they may have + been made by combine, in which case they do not have a INSN_CUID + value. We can't use prev_real_insn, because that would incorrectly + take us backwards across labels. Skip over BARRIERs also, since + they could have been made by combine. If we see one, we must be + optimizing dead code, so it doesn't matter what we do. */ + for (insn = prev_nonnote_insn (subst_insn); + insn && ((GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == USE) + || GET_CODE (insn) == BARRIER + || INSN_CUID (insn) >= subst_low_cuid); + insn = prev_nonnote_insn (insn)) + ; + + if (insn + && (set = single_set (insn)) != 0 + && rtx_equal_p (SET_DEST (set), x)) + { + value = SET_SRC (set); + + /* Make sure that VALUE doesn't reference X. Replace any + explicit references with a CLOBBER. If there are any remaining + references (rare), don't use the value. */ + + if (reg_mentioned_p (x, value)) + value = replace_rtx (copy_rtx (value), x, + gen_rtx_CLOBBER (GET_MODE (x), const0_rtx)); + + if (reg_overlap_mentioned_p (x, value)) + return 0; + } + else + return 0; + } + + /* If the value has all its registers valid, return it. */ + if (get_last_value_validate (&value, reg_last_set[regno], + reg_last_set_label[regno], 0)) + return value; + + /* Otherwise, make a copy and replace any invalid register with + (clobber (const_int 0)). If that fails for some reason, return 0. */ + + value = copy_rtx (value); + if (get_last_value_validate (&value, reg_last_set[regno], + reg_last_set_label[regno], 1)) + return value; + + return 0; +} + +/* Return nonzero if expression X refers to a REG or to memory + that is set in an instruction more recent than FROM_CUID. */ + +static int +use_crosses_set_p (x, from_cuid) + register rtx x; + int from_cuid; +{ + register char *fmt; + register int i; + register enum rtx_code code = GET_CODE (x); + + if (code == REG) + { + register int regno = REGNO (x); + int endreg = regno + (regno < FIRST_PSEUDO_REGISTER + ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1); + +#ifdef PUSH_ROUNDING + /* Don't allow uses of the stack pointer to be moved, + because we don't know whether the move crosses a push insn. */ + if (regno == STACK_POINTER_REGNUM) + return 1; +#endif + for (;regno < endreg; regno++) + if (reg_last_set[regno] + && INSN_CUID (reg_last_set[regno]) > from_cuid) + return 1; + return 0; + } + + if (code == MEM && mem_last_set > from_cuid) + return 1; + + fmt = GET_RTX_FORMAT (code); + + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'E') + { + register int j; + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + if (use_crosses_set_p (XVECEXP (x, i, j), from_cuid)) + return 1; + } + else if (fmt[i] == 'e' + && use_crosses_set_p (XEXP (x, i), from_cuid)) + return 1; + } + return 0; +} + +/* Define three variables used for communication between the following + routines. */ + +static int reg_dead_regno, reg_dead_endregno; +static int reg_dead_flag; + +/* Function called via note_stores from reg_dead_at_p. + + If DEST is within [reg_dead_regno, reg_dead_endregno), set + reg_dead_flag to 1 if X is a CLOBBER and to -1 it is a SET. */ + +static void +reg_dead_at_p_1 (dest, x) + rtx dest; + rtx x; +{ + int regno, endregno; + + if (GET_CODE (dest) != REG) + return; + + regno = REGNO (dest); + endregno = regno + (regno < FIRST_PSEUDO_REGISTER + ? HARD_REGNO_NREGS (regno, GET_MODE (dest)) : 1); + + if (reg_dead_endregno > regno && reg_dead_regno < endregno) + reg_dead_flag = (GET_CODE (x) == CLOBBER) ? 1 : -1; +} + +/* Return non-zero if REG is known to be dead at INSN. + + We scan backwards from INSN. If we hit a REG_DEAD note or a CLOBBER + referencing REG, it is dead. If we hit a SET referencing REG, it is + live. Otherwise, see if it is live or dead at the start of the basic + block we are in. Hard regs marked as being live in NEWPAT_USED_REGS + must be assumed to be always live. */ + +static int +reg_dead_at_p (reg, insn) + rtx reg; + rtx insn; +{ + int block, i; + + /* Set variables for reg_dead_at_p_1. */ + reg_dead_regno = REGNO (reg); + reg_dead_endregno = reg_dead_regno + (reg_dead_regno < FIRST_PSEUDO_REGISTER + ? HARD_REGNO_NREGS (reg_dead_regno, + GET_MODE (reg)) + : 1); + + reg_dead_flag = 0; + + /* Check that reg isn't mentioned in NEWPAT_USED_REGS. */ + if (reg_dead_regno < FIRST_PSEUDO_REGISTER) + { + for (i = reg_dead_regno; i < reg_dead_endregno; i++) + if (TEST_HARD_REG_BIT (newpat_used_regs, i)) + return 0; + } + + /* Scan backwards until we find a REG_DEAD note, SET, CLOBBER, label, or + beginning of function. */ + for (; insn && GET_CODE (insn) != CODE_LABEL && GET_CODE (insn) != BARRIER; + insn = prev_nonnote_insn (insn)) + { + note_stores (PATTERN (insn), reg_dead_at_p_1); + if (reg_dead_flag) + return reg_dead_flag == 1 ? 1 : 0; + + if (find_regno_note (insn, REG_DEAD, reg_dead_regno)) + return 1; + } + + /* Get the basic block number that we were in. */ + if (insn == 0) + block = 0; + else + { + for (block = 0; block < n_basic_blocks; block++) + if (insn == BLOCK_HEAD (block)) + break; + + if (block == n_basic_blocks) + return 0; + } + + for (i = reg_dead_regno; i < reg_dead_endregno; i++) + if (REGNO_REG_SET_P (basic_block_live_at_start[block], i)) + return 0; + + return 1; +} + +/* Note hard registers in X that are used. This code is similar to + that in flow.c, but much simpler since we don't care about pseudos. */ + +static void +mark_used_regs_combine (x) + rtx x; +{ + register RTX_CODE code = GET_CODE (x); + register int regno; + int i; + + switch (code) + { + case LABEL_REF: + case SYMBOL_REF: + case CONST_INT: + case CONST: + case CONST_DOUBLE: + case PC: + case ADDR_VEC: + case ADDR_DIFF_VEC: + case ASM_INPUT: +#ifdef HAVE_cc0 + /* CC0 must die in the insn after it is set, so we don't need to take + special note of it here. */ + case CC0: +#endif + return; + + case CLOBBER: + /* If we are clobbering a MEM, mark any hard registers inside the + address as used. */ + if (GET_CODE (XEXP (x, 0)) == MEM) + mark_used_regs_combine (XEXP (XEXP (x, 0), 0)); + return; + + case REG: + regno = REGNO (x); + /* A hard reg in a wide mode may really be multiple registers. + If so, mark all of them just like the first. */ + if (regno < FIRST_PSEUDO_REGISTER) + { + /* None of this applies to the stack, frame or arg pointers */ + if (regno == STACK_POINTER_REGNUM +#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM + || regno == HARD_FRAME_POINTER_REGNUM +#endif +#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM + || (regno == ARG_POINTER_REGNUM && fixed_regs[regno]) +#endif + || regno == FRAME_POINTER_REGNUM) + return; + + i = HARD_REGNO_NREGS (regno, GET_MODE (x)); + while (i-- > 0) + SET_HARD_REG_BIT (newpat_used_regs, regno + i); + } + return; + + case SET: + { + /* If setting a MEM, or a SUBREG of a MEM, then note any hard regs in + the address. */ + register rtx testreg = SET_DEST (x); + + while (GET_CODE (testreg) == SUBREG + || GET_CODE (testreg) == ZERO_EXTRACT + || GET_CODE (testreg) == SIGN_EXTRACT + || GET_CODE (testreg) == STRICT_LOW_PART) + testreg = XEXP (testreg, 0); + + if (GET_CODE (testreg) == MEM) + mark_used_regs_combine (XEXP (testreg, 0)); + + mark_used_regs_combine (SET_SRC (x)); + } + return; + + default: + break; + } + + /* Recursively scan the operands of this expression. */ + + { + register char *fmt = GET_RTX_FORMAT (code); + + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + mark_used_regs_combine (XEXP (x, i)); + else if (fmt[i] == 'E') + { + register int j; + + for (j = 0; j < XVECLEN (x, i); j++) + mark_used_regs_combine (XVECEXP (x, i, j)); + } + } + } +} + + +/* Remove register number REGNO from the dead registers list of INSN. + + Return the note used to record the death, if there was one. */ + +rtx +remove_death (regno, insn) + int regno; + rtx insn; +{ + register rtx note = find_regno_note (insn, REG_DEAD, regno); + + if (note) + { + REG_N_DEATHS (regno)--; + remove_note (insn, note); + } + + return note; +} + +/* For each register (hardware or pseudo) used within expression X, if its + death is in an instruction with cuid between FROM_CUID (inclusive) and + TO_INSN (exclusive), put a REG_DEAD note for that register in the + list headed by PNOTES. + + That said, don't move registers killed by maybe_kill_insn. + + This is done when X is being merged by combination into TO_INSN. These + notes will then be distributed as needed. */ + +static void +move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes) + rtx x; + rtx maybe_kill_insn; + int from_cuid; + rtx to_insn; + rtx *pnotes; +{ + register char *fmt; + register int len, i; + register enum rtx_code code = GET_CODE (x); + + if (code == REG) + { + register int regno = REGNO (x); + register rtx where_dead = reg_last_death[regno]; + register rtx before_dead, after_dead; + + /* Don't move the register if it gets killed in between from and to */ + if (maybe_kill_insn && reg_set_p (x, maybe_kill_insn) + && !reg_referenced_p (x, maybe_kill_insn)) + return; + + /* WHERE_DEAD could be a USE insn made by combine, so first we + make sure that we have insns with valid INSN_CUID values. */ + before_dead = where_dead; + while (before_dead && INSN_UID (before_dead) > max_uid_cuid) + before_dead = PREV_INSN (before_dead); + after_dead = where_dead; + while (after_dead && INSN_UID (after_dead) > max_uid_cuid) + after_dead = NEXT_INSN (after_dead); + + if (before_dead && after_dead + && INSN_CUID (before_dead) >= from_cuid + && (INSN_CUID (after_dead) < INSN_CUID (to_insn) + || (where_dead != after_dead + && INSN_CUID (after_dead) == INSN_CUID (to_insn)))) + { + rtx note = remove_death (regno, where_dead); + + /* It is possible for the call above to return 0. This can occur + when reg_last_death points to I2 or I1 that we combined with. + In that case make a new note. + + We must also check for the case where X is a hard register + and NOTE is a death note for a range of hard registers + including X. In that case, we must put REG_DEAD notes for + the remaining registers in place of NOTE. */ + + if (note != 0 && regno < FIRST_PSEUDO_REGISTER + && (GET_MODE_SIZE (GET_MODE (XEXP (note, 0))) + > GET_MODE_SIZE (GET_MODE (x)))) + { + int deadregno = REGNO (XEXP (note, 0)); + int deadend + = (deadregno + HARD_REGNO_NREGS (deadregno, + GET_MODE (XEXP (note, 0)))); + int ourend = regno + HARD_REGNO_NREGS (regno, GET_MODE (x)); + int i; + + for (i = deadregno; i < deadend; i++) + if (i < regno || i >= ourend) + REG_NOTES (where_dead) + = gen_rtx_EXPR_LIST (REG_DEAD, + gen_rtx_REG (reg_raw_mode[i], i), + REG_NOTES (where_dead)); + } + /* If we didn't find any note, or if we found a REG_DEAD note that + covers only part of the given reg, and we have a multi-reg hard + register, then to be safe we must check for REG_DEAD notes + for each register other than the first. They could have + their own REG_DEAD notes lying around. */ + else if ((note == 0 + || (note != 0 + && (GET_MODE_SIZE (GET_MODE (XEXP (note, 0))) + < GET_MODE_SIZE (GET_MODE (x))))) + && regno < FIRST_PSEUDO_REGISTER + && HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1) + { + int ourend = regno + HARD_REGNO_NREGS (regno, GET_MODE (x)); + int i, offset; + rtx oldnotes = 0; + + if (note) + offset = HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0))); + else + offset = 1; + + for (i = regno + offset; i < ourend; i++) + move_deaths (gen_rtx_REG (reg_raw_mode[i], i), + maybe_kill_insn, from_cuid, to_insn, &oldnotes); + } + + if (note != 0 && GET_MODE (XEXP (note, 0)) == GET_MODE (x)) + { + XEXP (note, 1) = *pnotes; + *pnotes = note; + } + else + *pnotes = gen_rtx_EXPR_LIST (REG_DEAD, x, *pnotes); + + REG_N_DEATHS (regno)++; + } + + return; + } + + else if (GET_CODE (x) == SET) + { + rtx dest = SET_DEST (x); + + move_deaths (SET_SRC (x), maybe_kill_insn, from_cuid, to_insn, pnotes); + + /* In the case of a ZERO_EXTRACT, a STRICT_LOW_PART, or a SUBREG + that accesses one word of a multi-word item, some + piece of everything register in the expression is used by + this insn, so remove any old death. */ + + if (GET_CODE (dest) == ZERO_EXTRACT + || GET_CODE (dest) == STRICT_LOW_PART + || (GET_CODE (dest) == SUBREG + && (((GET_MODE_SIZE (GET_MODE (dest)) + + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) + + UNITS_PER_WORD - 1) / UNITS_PER_WORD)))) + { + move_deaths (dest, maybe_kill_insn, from_cuid, to_insn, pnotes); + return; + } + + /* If this is some other SUBREG, we know it replaces the entire + value, so use that as the destination. */ + if (GET_CODE (dest) == SUBREG) + dest = SUBREG_REG (dest); + + /* If this is a MEM, adjust deaths of anything used in the address. + For a REG (the only other possibility), the entire value is + being replaced so the old value is not used in this insn. */ + + if (GET_CODE (dest) == MEM) + move_deaths (XEXP (dest, 0), maybe_kill_insn, from_cuid, + to_insn, pnotes); + return; + } + + else if (GET_CODE (x) == CLOBBER) + return; + + len = GET_RTX_LENGTH (code); + fmt = GET_RTX_FORMAT (code); + + for (i = 0; i < len; i++) + { + if (fmt[i] == 'E') + { + register int j; + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + move_deaths (XVECEXP (x, i, j), maybe_kill_insn, from_cuid, + to_insn, pnotes); + } + else if (fmt[i] == 'e') + move_deaths (XEXP (x, i), maybe_kill_insn, from_cuid, to_insn, pnotes); + } +} + +/* Return 1 if X is the target of a bit-field assignment in BODY, the + pattern of an insn. X must be a REG. */ + +static int +reg_bitfield_target_p (x, body) + rtx x; + rtx body; +{ + int i; + + if (GET_CODE (body) == SET) + { + rtx dest = SET_DEST (body); + rtx target; + int regno, tregno, endregno, endtregno; + + if (GET_CODE (dest) == ZERO_EXTRACT) + target = XEXP (dest, 0); + else if (GET_CODE (dest) == STRICT_LOW_PART) + target = SUBREG_REG (XEXP (dest, 0)); + else + return 0; + + if (GET_CODE (target) == SUBREG) + target = SUBREG_REG (target); + + if (GET_CODE (target) != REG) + return 0; + + tregno = REGNO (target), regno = REGNO (x); + if (tregno >= FIRST_PSEUDO_REGISTER || regno >= FIRST_PSEUDO_REGISTER) + return target == x; + + endtregno = tregno + HARD_REGNO_NREGS (tregno, GET_MODE (target)); + endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x)); + + return endregno > tregno && regno < endtregno; + } + + else if (GET_CODE (body) == PARALLEL) + for (i = XVECLEN (body, 0) - 1; i >= 0; i--) + if (reg_bitfield_target_p (x, XVECEXP (body, 0, i))) + return 1; + + return 0; +} + +/* Given a chain of REG_NOTES originally from FROM_INSN, try to place them + as appropriate. I3 and I2 are the insns resulting from the combination + insns including FROM (I2 may be zero). + + ELIM_I2 and ELIM_I1 are either zero or registers that we know will + not need REG_DEAD notes because they are being substituted for. This + saves searching in the most common cases. + + Each note in the list is either ignored or placed on some insns, depending + on the type of note. */ + +static void +distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1) + rtx notes; + rtx from_insn; + rtx i3, i2; + rtx elim_i2, elim_i1; +{ + rtx note, next_note; + rtx tem; + + for (note = notes; note; note = next_note) + { + rtx place = 0, place2 = 0; + + /* If this NOTE references a pseudo register, ensure it references + the latest copy of that register. */ + if (XEXP (note, 0) && GET_CODE (XEXP (note, 0)) == REG + && REGNO (XEXP (note, 0)) >= FIRST_PSEUDO_REGISTER) + XEXP (note, 0) = regno_reg_rtx[REGNO (XEXP (note, 0))]; + + next_note = XEXP (note, 1); + switch (REG_NOTE_KIND (note)) + { + case REG_EH_REGION: + /* This note must remain with the call. It should not be possible + for both I2 and I3 to be a call. */ + if (GET_CODE (i3) == CALL_INSN) + place = i3; + else if (i2 && GET_CODE (i2) == CALL_INSN) + place = i2; + else + abort (); + break; + + case REG_UNUSED: + /* Any clobbers for i3 may still exist, and so we must process + REG_UNUSED notes from that insn. + + Any clobbers from i2 or i1 can only exist if they were added by + recog_for_combine. In that case, recog_for_combine created the + necessary REG_UNUSED notes. Trying to keep any original + REG_UNUSED notes from these insns can cause incorrect output + if it is for the same register as the original i3 dest. + In that case, we will notice that the register is set in i3, + and then add a REG_UNUSED note for the destination of i3, which + is wrong. However, it is possible to have REG_UNUSED notes from + i2 or i1 for register which were both used and clobbered, so + we keep notes from i2 or i1 if they will turn into REG_DEAD + notes. */ + + /* If this register is set or clobbered in I3, put the note there + unless there is one already. */ + if (reg_set_p (XEXP (note, 0), PATTERN (i3))) + { + if (from_insn != i3) + break; + + if (! (GET_CODE (XEXP (note, 0)) == REG + ? find_regno_note (i3, REG_UNUSED, REGNO (XEXP (note, 0))) + : find_reg_note (i3, REG_UNUSED, XEXP (note, 0)))) + place = i3; + } + /* Otherwise, if this register is used by I3, then this register + now dies here, so we must put a REG_DEAD note here unless there + is one already. */ + else if (reg_referenced_p (XEXP (note, 0), PATTERN (i3)) + && ! (GET_CODE (XEXP (note, 0)) == REG + ? find_regno_note (i3, REG_DEAD, REGNO (XEXP (note, 0))) + : find_reg_note (i3, REG_DEAD, XEXP (note, 0)))) + { + PUT_REG_NOTE_KIND (note, REG_DEAD); + place = i3; + } + break; + + case REG_EQUAL: + case REG_EQUIV: + case REG_NONNEG: + case REG_NOALIAS: + /* These notes say something about results of an insn. We can + only support them if they used to be on I3 in which case they + remain on I3. Otherwise they are ignored. + + If the note refers to an expression that is not a constant, we + must also ignore the note since we cannot tell whether the + equivalence is still true. It might be possible to do + slightly better than this (we only have a problem if I2DEST + or I1DEST is present in the expression), but it doesn't + seem worth the trouble. */ + + if (from_insn == i3 + && (XEXP (note, 0) == 0 || CONSTANT_P (XEXP (note, 0)))) + place = i3; + break; + + case REG_INC: + case REG_NO_CONFLICT: + case REG_LABEL: + /* These notes say something about how a register is used. They must + be present on any use of the register in I2 or I3. */ + if (reg_mentioned_p (XEXP (note, 0), PATTERN (i3))) + place = i3; + + if (i2 && reg_mentioned_p (XEXP (note, 0), PATTERN (i2))) + { + if (place) + place2 = i2; + else + place = i2; + } + break; + + case REG_WAS_0: + /* It is too much trouble to try to see if this note is still + correct in all situations. It is better to simply delete it. */ + break; + + case REG_RETVAL: + /* If the insn previously containing this note still exists, + put it back where it was. Otherwise move it to the previous + insn. Adjust the corresponding REG_LIBCALL note. */ + if (GET_CODE (from_insn) != NOTE) + place = from_insn; + else + { + tem = find_reg_note (XEXP (note, 0), REG_LIBCALL, NULL_RTX); + place = prev_real_insn (from_insn); + if (tem && place) + XEXP (tem, 0) = place; + } + break; + + case REG_LIBCALL: + /* This is handled similarly to REG_RETVAL. */ + if (GET_CODE (from_insn) != NOTE) + place = from_insn; + else + { + tem = find_reg_note (XEXP (note, 0), REG_RETVAL, NULL_RTX); + place = next_real_insn (from_insn); + if (tem && place) + XEXP (tem, 0) = place; + } + break; + + case REG_DEAD: + /* If the register is used as an input in I3, it dies there. + Similarly for I2, if it is non-zero and adjacent to I3. + + If the register is not used as an input in either I3 or I2 + and it is not one of the registers we were supposed to eliminate, + there are two possibilities. We might have a non-adjacent I2 + or we might have somehow eliminated an additional register + from a computation. For example, we might have had A & B where + we discover that B will always be zero. In this case we will + eliminate the reference to A. + + In both cases, we must search to see if we can find a previous + use of A and put the death note there. */ + + if (from_insn + && GET_CODE (from_insn) == CALL_INSN + && find_reg_fusage (from_insn, USE, XEXP (note, 0))) + place = from_insn; + else if (reg_referenced_p (XEXP (note, 0), PATTERN (i3))) + place = i3; + else if (i2 != 0 && next_nonnote_insn (i2) == i3 + && reg_referenced_p (XEXP (note, 0), PATTERN (i2))) + place = i2; + + if (XEXP (note, 0) == elim_i2 || XEXP (note, 0) == elim_i1) + break; + + /* If the register is used in both I2 and I3 and it dies in I3, + we might have added another reference to it. If reg_n_refs + was 2, bump it to 3. This has to be correct since the + register must have been set somewhere. The reason this is + done is because local-alloc.c treats 2 references as a + special case. */ + + if (place == i3 && i2 != 0 && GET_CODE (XEXP (note, 0)) == REG + && REG_N_REFS (REGNO (XEXP (note, 0)))== 2 + && reg_referenced_p (XEXP (note, 0), PATTERN (i2))) + REG_N_REFS (REGNO (XEXP (note, 0))) = 3; + + if (place == 0) + { + for (tem = prev_nonnote_insn (i3); + place == 0 && tem + && (GET_CODE (tem) == INSN || GET_CODE (tem) == CALL_INSN); + tem = prev_nonnote_insn (tem)) + { + /* If the register is being set at TEM, see if that is all + TEM is doing. If so, delete TEM. Otherwise, make this + into a REG_UNUSED note instead. */ + if (reg_set_p (XEXP (note, 0), PATTERN (tem))) + { + rtx set = single_set (tem); + rtx inner_dest = 0; +#ifdef HAVE_cc0 + rtx cc0_setter = NULL_RTX; +#endif + + if (set != 0) + for (inner_dest = SET_DEST (set); + GET_CODE (inner_dest) == STRICT_LOW_PART + || GET_CODE (inner_dest) == SUBREG + || GET_CODE (inner_dest) == ZERO_EXTRACT; + inner_dest = XEXP (inner_dest, 0)) + ; + + /* Verify that it was the set, and not a clobber that + modified the register. + + CC0 targets must be careful to maintain setter/user + pairs. If we cannot delete the setter due to side + effects, mark the user with an UNUSED note instead + of deleting it. */ + + if (set != 0 && ! side_effects_p (SET_SRC (set)) + && rtx_equal_p (XEXP (note, 0), inner_dest) +#ifdef HAVE_cc0 + && (! reg_mentioned_p (cc0_rtx, SET_SRC (set)) + || ((cc0_setter = prev_cc0_setter (tem)) != NULL + && sets_cc0_p (PATTERN (cc0_setter)) > 0)) +#endif + ) + { + /* Move the notes and links of TEM elsewhere. + This might delete other dead insns recursively. + First set the pattern to something that won't use + any register. */ + + PATTERN (tem) = pc_rtx; + + distribute_notes (REG_NOTES (tem), tem, tem, + NULL_RTX, NULL_RTX, NULL_RTX); + distribute_links (LOG_LINKS (tem)); + + PUT_CODE (tem, NOTE); + NOTE_LINE_NUMBER (tem) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (tem) = 0; + +#ifdef HAVE_cc0 + /* Delete the setter too. */ + if (cc0_setter) + { + PATTERN (cc0_setter) = pc_rtx; + + distribute_notes (REG_NOTES (cc0_setter), + cc0_setter, cc0_setter, + NULL_RTX, NULL_RTX, NULL_RTX); + distribute_links (LOG_LINKS (cc0_setter)); + + PUT_CODE (cc0_setter, NOTE); + NOTE_LINE_NUMBER (cc0_setter) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (cc0_setter) = 0; + } +#endif + } + /* If the register is both set and used here, put the + REG_DEAD note here, but place a REG_UNUSED note + here too unless there already is one. */ + else if (reg_referenced_p (XEXP (note, 0), + PATTERN (tem))) + { + place = tem; + + if (! find_regno_note (tem, REG_UNUSED, + REGNO (XEXP (note, 0)))) + REG_NOTES (tem) + = gen_rtx_EXPR_LIST (REG_UNUSED, + XEXP (note, 0), + REG_NOTES (tem)); + } + else + { + PUT_REG_NOTE_KIND (note, REG_UNUSED); + + /* If there isn't already a REG_UNUSED note, put one + here. */ + if (! find_regno_note (tem, REG_UNUSED, + REGNO (XEXP (note, 0)))) + place = tem; + break; + } + } + else if (reg_referenced_p (XEXP (note, 0), PATTERN (tem)) + || (GET_CODE (tem) == CALL_INSN + && find_reg_fusage (tem, USE, XEXP (note, 0)))) + { + place = tem; + + /* If we are doing a 3->2 combination, and we have a + register which formerly died in i3 and was not used + by i2, which now no longer dies in i3 and is used in + i2 but does not die in i2, and place is between i2 + and i3, then we may need to move a link from place to + i2. */ + if (i2 && INSN_UID (place) <= max_uid_cuid + && INSN_CUID (place) > INSN_CUID (i2) + && from_insn && INSN_CUID (from_insn) > INSN_CUID (i2) + && reg_referenced_p (XEXP (note, 0), PATTERN (i2))) + { + rtx links = LOG_LINKS (place); + LOG_LINKS (place) = 0; + distribute_links (links); + } + break; + } + } + + /* If we haven't found an insn for the death note and it + is still a REG_DEAD note, but we have hit a CODE_LABEL, + insert a USE insn for the register at that label and + put the death node there. This prevents problems with + call-state tracking in caller-save.c. */ + if (REG_NOTE_KIND (note) == REG_DEAD && place == 0 && tem != 0) + { + place + = emit_insn_after (gen_rtx_USE (VOIDmode, XEXP (note, 0)), + tem); + + /* If this insn was emitted between blocks, then update + BLOCK_HEAD of the current block to include it. */ + if (BLOCK_END (this_basic_block - 1) == tem) + BLOCK_HEAD (this_basic_block) = place; + } + } + + /* If the register is set or already dead at PLACE, we needn't do + anything with this note if it is still a REG_DEAD note. + We can here if it is set at all, not if is it totally replace, + which is what `dead_or_set_p' checks, so also check for it being + set partially. */ + + + if (place && REG_NOTE_KIND (note) == REG_DEAD) + { + int regno = REGNO (XEXP (note, 0)); + + if (dead_or_set_p (place, XEXP (note, 0)) + || reg_bitfield_target_p (XEXP (note, 0), PATTERN (place))) + { + /* Unless the register previously died in PLACE, clear + reg_last_death. [I no longer understand why this is + being done.] */ + if (reg_last_death[regno] != place) + reg_last_death[regno] = 0; + place = 0; + } + else + reg_last_death[regno] = place; + + /* If this is a death note for a hard reg that is occupying + multiple registers, ensure that we are still using all + parts of the object. If we find a piece of the object + that is unused, we must add a USE for that piece before + PLACE and put the appropriate REG_DEAD note on it. + + An alternative would be to put a REG_UNUSED for the pieces + on the insn that set the register, but that can't be done if + it is not in the same block. It is simpler, though less + efficient, to add the USE insns. */ + + if (place && regno < FIRST_PSEUDO_REGISTER + && HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0))) > 1) + { + int endregno + = regno + HARD_REGNO_NREGS (regno, + GET_MODE (XEXP (note, 0))); + int all_used = 1; + int i; + + for (i = regno; i < endregno; i++) + if (! refers_to_regno_p (i, i + 1, PATTERN (place), 0) + && ! find_regno_fusage (place, USE, i)) + { + rtx piece = gen_rtx_REG (reg_raw_mode[i], i); + rtx p; + + /* See if we already placed a USE note for this + register in front of PLACE. */ + for (p = place; + GET_CODE (PREV_INSN (p)) == INSN + && GET_CODE (PATTERN (PREV_INSN (p))) == USE; + p = PREV_INSN (p)) + if (rtx_equal_p (piece, + XEXP (PATTERN (PREV_INSN (p)), 0))) + { + p = 0; + break; + } + + if (p) + { + rtx use_insn + = emit_insn_before (gen_rtx_USE (VOIDmode, + piece), + p); + REG_NOTES (use_insn) + = gen_rtx_EXPR_LIST (REG_DEAD, piece, + REG_NOTES (use_insn)); + } + + all_used = 0; + } + + /* Check for the case where the register dying partially + overlaps the register set by this insn. */ + if (all_used) + for (i = regno; i < endregno; i++) + if (dead_or_set_regno_p (place, i)) + { + all_used = 0; + break; + } + + if (! all_used) + { + /* Put only REG_DEAD notes for pieces that are + still used and that are not already dead or set. */ + + for (i = regno; i < endregno; i++) + { + rtx piece = gen_rtx_REG (reg_raw_mode[i], i); + + if ((reg_referenced_p (piece, PATTERN (place)) + || (GET_CODE (place) == CALL_INSN + && find_reg_fusage (place, USE, piece))) + && ! dead_or_set_p (place, piece) + && ! reg_bitfield_target_p (piece, + PATTERN (place))) + REG_NOTES (place) + = gen_rtx_EXPR_LIST (REG_DEAD, + piece, REG_NOTES (place)); + } + + place = 0; + } + } + } + break; + + default: + /* Any other notes should not be present at this point in the + compilation. */ + abort (); + } + + if (place) + { + XEXP (note, 1) = REG_NOTES (place); + REG_NOTES (place) = note; + } + else if ((REG_NOTE_KIND (note) == REG_DEAD + || REG_NOTE_KIND (note) == REG_UNUSED) + && GET_CODE (XEXP (note, 0)) == REG) + REG_N_DEATHS (REGNO (XEXP (note, 0)))--; + + if (place2) + { + if ((REG_NOTE_KIND (note) == REG_DEAD + || REG_NOTE_KIND (note) == REG_UNUSED) + && GET_CODE (XEXP (note, 0)) == REG) + REG_N_DEATHS (REGNO (XEXP (note, 0)))++; + + REG_NOTES (place2) = gen_rtx_fmt_ee (GET_CODE (note), + REG_NOTE_KIND (note), + XEXP (note, 0), + REG_NOTES (place2)); + } + } +} + +/* Similarly to above, distribute the LOG_LINKS that used to be present on + I3, I2, and I1 to new locations. This is also called in one case to + add a link pointing at I3 when I3's destination is changed. */ + +static void +distribute_links (links) + rtx links; +{ + rtx link, next_link; + + for (link = links; link; link = next_link) + { + rtx place = 0; + rtx insn; + rtx set, reg; + + next_link = XEXP (link, 1); + + /* If the insn that this link points to is a NOTE or isn't a single + set, ignore it. In the latter case, it isn't clear what we + can do other than ignore the link, since we can't tell which + register it was for. Such links wouldn't be used by combine + anyway. + + It is not possible for the destination of the target of the link to + have been changed by combine. The only potential of this is if we + replace I3, I2, and I1 by I3 and I2. But in that case the + destination of I2 also remains unchanged. */ + + if (GET_CODE (XEXP (link, 0)) == NOTE + || (set = single_set (XEXP (link, 0))) == 0) + continue; + + reg = SET_DEST (set); + while (GET_CODE (reg) == SUBREG || GET_CODE (reg) == ZERO_EXTRACT + || GET_CODE (reg) == SIGN_EXTRACT + || GET_CODE (reg) == STRICT_LOW_PART) + reg = XEXP (reg, 0); + + /* A LOG_LINK is defined as being placed on the first insn that uses + a register and points to the insn that sets the register. Start + searching at the next insn after the target of the link and stop + when we reach a set of the register or the end of the basic block. + + Note that this correctly handles the link that used to point from + I3 to I2. Also note that not much searching is typically done here + since most links don't point very far away. */ + + for (insn = NEXT_INSN (XEXP (link, 0)); + (insn && (this_basic_block == n_basic_blocks - 1 + || BLOCK_HEAD (this_basic_block + 1) != insn)); + insn = NEXT_INSN (insn)) + if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' + && reg_overlap_mentioned_p (reg, PATTERN (insn))) + { + if (reg_referenced_p (reg, PATTERN (insn))) + place = insn; + break; + } + else if (GET_CODE (insn) == CALL_INSN + && find_reg_fusage (insn, USE, reg)) + { + place = insn; + break; + } + + /* If we found a place to put the link, place it there unless there + is already a link to the same insn as LINK at that point. */ + + if (place) + { + rtx link2; + + for (link2 = LOG_LINKS (place); link2; link2 = XEXP (link2, 1)) + if (XEXP (link2, 0) == XEXP (link, 0)) + break; + + if (link2 == 0) + { + XEXP (link, 1) = LOG_LINKS (place); + LOG_LINKS (place) = link; + + /* Set added_links_insn to the earliest insn we added a + link to. */ + if (added_links_insn == 0 + || INSN_CUID (added_links_insn) > INSN_CUID (place)) + added_links_insn = place; + } + } + } +} + +/* Compute INSN_CUID for INSN, which is an insn made by combine. */ + +static int +insn_cuid (insn) + rtx insn; +{ + while (insn != 0 && INSN_UID (insn) > max_uid_cuid + && GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == USE) + insn = NEXT_INSN (insn); + + if (INSN_UID (insn) > max_uid_cuid) + abort (); + + return INSN_CUID (insn); +} + +void +dump_combine_stats (file) + FILE *file; +{ + fprintf + (file, + ";; Combiner statistics: %d attempts, %d substitutions (%d requiring new space),\n;; %d successes.\n\n", + combine_attempts, combine_merges, combine_extras, combine_successes); +} + +void +dump_combine_total_stats (file) + FILE *file; +{ + fprintf + (file, + "\n;; Combiner totals: %d attempts, %d substitutions (%d requiring new space),\n;; %d successes.\n", + total_attempts, total_merges, total_extras, total_successes); +} diff --git a/gcc_arm/conditions.h b/gcc_arm/conditions.h new file mode 100755 index 0000000..80d6047 --- /dev/null +++ b/gcc_arm/conditions.h @@ -0,0 +1,118 @@ +/* Definitions for condition code handling in final.c and output routines. + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* None of the things in the files exist if we don't use CC0. */ + +#ifdef HAVE_cc0 + +/* The variable cc_status says how to interpret the condition code. + It is set by output routines for an instruction that sets the cc's + and examined by output routines for jump instructions. + + cc_status contains two components named `value1' and `value2' + that record two equivalent expressions for the values that the + condition codes were set from. (Either or both may be null if + there is no useful expression to record.) These fields are + used for eliminating redundant test and compare instructions + in the cases where the condition codes were already set by the + previous instruction. + + cc_status.flags contains flags which say that the condition codes + were set in a nonstandard manner. The output of jump instructions + uses these flags to compensate and produce the standard result + with the nonstandard condition codes. Standard flags are defined here. + The tm.h file can also define other machine-dependent flags. + + cc_status also contains a machine-dependent component `mdep' + whose type, `CC_STATUS_MDEP', may be defined as a macro in the + tm.h file. */ + +#ifndef CC_STATUS_MDEP +#define CC_STATUS_MDEP int +#endif + +#ifndef CC_STATUS_MDEP_INIT +#define CC_STATUS_MDEP_INIT 0 +#endif + +typedef struct {int flags; rtx value1, value2; CC_STATUS_MDEP mdep;} CC_STATUS; + +/* While outputting an insn as assembler code, + this is the status BEFORE that insn. */ +extern CC_STATUS cc_prev_status; + +/* While outputting an insn as assembler code, + this is being altered to the status AFTER that insn. */ +extern CC_STATUS cc_status; + +/* These are the machine-independent flags: */ + +/* Set if the sign of the cc value is inverted: + output a following jump-if-less as a jump-if-greater, etc. */ +#define CC_REVERSED 1 + +/* This bit means that the current setting of the N bit is bogus + and conditional jumps should use the Z bit in its place. + This state obtains when an extraction of a signed single-bit field + or an arithmetic shift right of a byte by 7 bits + is turned into a btst, because btst does not set the N bit. */ +#define CC_NOT_POSITIVE 2 + +/* This bit means that the current setting of the N bit is bogus + and conditional jumps should pretend that the N bit is clear. + Used after extraction of an unsigned bit + or logical shift right of a byte by 7 bits is turned into a btst. + The btst does not alter the N bit, but the result of that shift + or extract is never negative. */ +#define CC_NOT_NEGATIVE 4 + +/* This bit means that the current setting of the overflow flag + is bogus and conditional jumps should pretend there is no overflow. */ +/* ??? Note that for most targets this macro is misnamed as it applies + to the carry flag, not the overflow flag. */ +#define CC_NO_OVERFLOW 010 + +/* This bit means that what ought to be in the Z bit + should be tested as the complement of the N bit. */ +#define CC_Z_IN_NOT_N 020 + +/* This bit means that what ought to be in the Z bit + should be tested as the N bit. */ +#define CC_Z_IN_N 040 + +/* Nonzero if we must invert the sense of the following branch, i.e. + change EQ to NE. This is not safe for IEEE floating point operations! + It is intended for use only when a combination of arithmetic + or logical insns can leave the condition codes set in a fortuitous + (though inverted) state. */ +#define CC_INVERTED 0100 + +/* Nonzero if we must convert signed condition operators to unsigned. + This is only used by machine description files. */ +#define CC_NOT_SIGNED 0200 + +/* This is how to initialize the variable cc_status. + final does this at appropriate moments. */ + +#define CC_STATUS_INIT \ + (cc_status.flags = 0, cc_status.value1 = 0, cc_status.value2 = 0, \ + CC_STATUS_MDEP_INIT) + +#endif diff --git a/gcc_arm/config.guess b/gcc_arm/config.guess new file mode 100755 index 0000000..fd7602d --- /dev/null +++ b/gcc_arm/config.guess @@ -0,0 +1,4 @@ +#!/bin/sh +# Use the top-level config.guess so that we don't have two of them. +guesssys=`echo $0 | sed 's|config.guess|../config.guess|'` +exec ${guesssys} "$@" diff --git a/gcc_arm/config.h b/gcc_arm/config.h new file mode 100644 index 0000000..0c48f96 --- /dev/null +++ b/gcc_arm/config.h @@ -0,0 +1,12 @@ +#include "auto-host.h" +#include "gansidecl.h" +#include "i386/xm-i386.h" +#ifndef HAVE_ATEXIT +#define HAVE_ATEXIT +#endif +#ifndef POSIX +#define POSIX +#endif +#ifndef BSTRING +#define BSTRING +#endif diff --git a/gcc_arm/config.in b/gcc_arm/config.in new file mode 100755 index 0000000..13f0772 --- /dev/null +++ b/gcc_arm/config.in @@ -0,0 +1,240 @@ +/* config.in. Generated automatically from configure.in by autoheader. */ +/* Define if you can safely include both and . */ +#undef STRING_WITH_STRINGS + +/* Define if printf supports "%p". */ +#undef HAVE_PRINTF_PTR + +/* Define if you want expensive run-time checks. */ +#undef ENABLE_CHECKING + +/* Define if your cpp understands the stringify operator. */ +#undef HAVE_CPP_STRINGIFY + +/* Define if your compiler understands volatile. */ +#undef HAVE_VOLATILE + +/* Define if your assembler supports specifying the maximum number + of bytes to skip when using the GAS .p2align command. */ +#undef HAVE_GAS_MAX_SKIP_P2ALIGN + +/* Define if your assembler supports .balign and .p2align. */ +#undef HAVE_GAS_BALIGN_AND_P2ALIGN + +/* Define if your assembler supports .subsection and .subsection -1 starts + emitting at the beginning of your section */ +#undef HAVE_GAS_SUBSECTION_ORDERING + +/* Define if you have a working header file. */ +#undef HAVE_INTTYPES_H + +/* Whether malloc must be declared even if is included. */ +#undef NEED_DECLARATION_MALLOC + +/* Whether realloc must be declared even if is included. */ +#undef NEED_DECLARATION_REALLOC + +/* Whether calloc must be declared even if is included. */ +#undef NEED_DECLARATION_CALLOC + +/* Whether free must be declared even if is included. */ +#undef NEED_DECLARATION_FREE + +/* Whether bcopy must be declared even if is included. */ +#undef NEED_DECLARATION_BCOPY + +/* Whether bcmp must be declared even if is included. */ +#undef NEED_DECLARATION_BCMP + +/* Whether bzero must be declared even if is included. */ +#undef NEED_DECLARATION_BZERO + +/* Whether index must be declared even if is included. */ +#undef NEED_DECLARATION_INDEX + +/* Whether rindex must be declared even if is included. */ +#undef NEED_DECLARATION_RINDEX + +/* Whether getenv must be declared even if is included. */ +#undef NEED_DECLARATION_GETENV + +/* Whether atol must be declared even if is included. */ +#undef NEED_DECLARATION_ATOL + +/* Whether sbrk must be declared even if is included. */ +#undef NEED_DECLARATION_SBRK + +/* Whether abort must be declared even if is included. */ +#undef NEED_DECLARATION_ABORT + +/* Whether strerror must be declared even if is included. */ +#undef NEED_DECLARATION_STRERROR + +/* Whether strsignal must be declared even if is included. */ +#undef NEED_DECLARATION_STRSIGNAL + +/* Whether getcwd must be declared even if is included. */ +#undef NEED_DECLARATION_GETCWD + +/* Whether getwd must be declared even if is included. */ +#undef NEED_DECLARATION_GETWD + +/* Whether getrlimit must be declared even if is included. */ +#undef NEED_DECLARATION_GETRLIMIT + +/* Whether setrlimit must be declared even if is included. */ +#undef NEED_DECLARATION_SETRLIMIT + +/* Define if you want expensive run-time checks. */ +#undef ENABLE_CHECKING + +/* Define to enable the use of a default assembler. */ +#undef DEFAULT_ASSEMBLER + +/* Define to enable the use of a default linker. */ +#undef DEFAULT_LINKER + + +/* Define if you don't have vprintf but do have _doprnt. */ +#undef HAVE_DOPRNT + +/* Define if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define if you have . */ +#undef HAVE_VFORK_H + +/* Define if you have the vprintf function. */ +#undef HAVE_VPRINTF + +/* Define to `int' if doesn't define. */ +#undef pid_t + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if `sys_siglist' is declared by . */ +#undef SYS_SIGLIST_DECLARED + +/* Define if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Define vfork as fork if vfork does not work. */ +#undef vfork + +/* Define if you have the atoll function. */ +#undef HAVE_ATOLL + +/* Define if you have the atoq function. */ +#undef HAVE_ATOQ + +/* Define if you have the bcmp function. */ +#undef HAVE_BCMP + +/* Define if you have the bcopy function. */ +#undef HAVE_BCOPY + +/* Define if you have the bsearch function. */ +#undef HAVE_BSEARCH + +/* Define if you have the bzero function. */ +#undef HAVE_BZERO + +/* Define if you have the fputc_unlocked function. */ +#undef HAVE_FPUTC_UNLOCKED + +/* Define if you have the fputs_unlocked function. */ +#undef HAVE_FPUTS_UNLOCKED + +/* Define if you have the getrlimit function. */ +#undef HAVE_GETRLIMIT + +/* Define if you have the gettimeofday function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define if you have the index function. */ +#undef HAVE_INDEX + +/* Define if you have the isascii function. */ +#undef HAVE_ISASCII + +/* Define if you have the kill function. */ +#undef HAVE_KILL + +/* Define if you have the popen function. */ +#undef HAVE_POPEN + +/* Define if you have the putc_unlocked function. */ +#undef HAVE_PUTC_UNLOCKED + +/* Define if you have the putenv function. */ +#undef HAVE_PUTENV + +/* Define if you have the rindex function. */ +#undef HAVE_RINDEX + +/* Define if you have the setrlimit function. */ +#undef HAVE_SETRLIMIT + +/* Define if you have the strchr function. */ +#undef HAVE_STRCHR + +/* Define if you have the strerror function. */ +#undef HAVE_STRERROR + +/* Define if you have the strrchr function. */ +#undef HAVE_STRRCHR + +/* Define if you have the strsignal function. */ +#undef HAVE_STRSIGNAL + +/* Define if you have the strtoul function. */ +#undef HAVE_STRTOUL + +/* Define if you have the sysconf function. */ +#undef HAVE_SYSCONF + +/* Define if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define if you have the header file. */ +#undef HAVE_STAB_H + +/* Define if you have the header file. */ +#undef HAVE_STDDEF_H + +/* Define if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define if you have the header file. */ +#undef HAVE_STRING_H + +/* Define if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_FILE_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_RESOURCE_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_TIMES_H + +/* Define if you have the header file. */ +#undef HAVE_TIME_H + +/* Define if you have the header file. */ +#undef HAVE_UNISTD_H diff --git a/gcc_arm/config.sub b/gcc_arm/config.sub new file mode 100755 index 0000000..fec3b6f --- /dev/null +++ b/gcc_arm/config.sub @@ -0,0 +1,1225 @@ +#! /bin/sh +# Configuration validation subroutine script, version 1.1. +# Copyright (C) 1991, 92-97, 1998 Free Software Foundation, Inc. +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file 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 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +if [ x$1 = x ] +then + echo Configuration name missing. 1>&2 + echo "Usage: $0 CPU-MFR-OPSYS" 1>&2 + echo "or $0 ALIAS" 1>&2 + echo where ALIAS is a recognized configuration type. 1>&2 + exit 1 +fi + +# First pass through any local machine types. +case $1 in + *local*) + echo $1 + exit 0 + ;; + *) + ;; +esac + +# CYGNUS LOCAL marketing-names +# Here we handle any "marketing" names - translating them to +# standard triplets +case $1 in + mips-tx39-elf) + set mipstx39-unknown-elf + ;; + *) + ;; +esac +# END CYGNUS LOCAL marketing-names + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + linux-gnu*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond ) # CYGNUS LOCAL + os= + basic_machine=$1 + ;; + -apple*) # CYGNUS LOCAL + os= + basic_machine=$1 + ;; + -wrs) # CYGNUS LOCAL + os=vxworks + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ + | arme[lb] | pyramid | mn10200 | mn10300 \ + | tron | a29k | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 \ + | alpha | alphaev5 | alphaev56 | we32k | ns16k | clipper \ + | i370 | sh | powerpc | powerpcle | 1750a | dsp16xx | pdp11 \ + | mips64 | mipsel | mips64el | mips64orion | mips64orionel \ + | mipstx39 | mipstx39el \ + | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850) + basic_machine=$basic_machine-unknown + ;; + m680[01234]0 | m683?2 | m68360 | z8k | v70 | h8500 | w65 | fr30) # CYGNUS LOCAL + basic_machine=$basic_machine-unknown + ;; + mips64vr4300 | mips64vr4300el) # CYGNUS LOCAL jsmith/vr4300 + basic_machine=$basic_machine-unknown + ;; + mips64vr4100 | mips64vr4100el) # CYGNUS LOCAL jsmith/vr4100 + basic_machine=$basic_machine-unknown + ;; + mips64vr5000 | mips64vr5000el) # CYGNUS LOCAL ian/vr5000 + basic_machine=$basic_machine-unknown + ;; + mips64vr5400 | mips64vr5400el) # CYGNUS LOCAL raeburn/vr5400 + basic_machine=$basic_machine-unknown + ;; + + thumb | thumbel | thumb-pe) + basic_machine=$basic_machine-unknown + ;; + thumb-pe) # CYGNUS LOCAL nickc/thumb-pe + basic_machine=$basic_machine-unknown + ;; + # CYGNUS LOCAL v850e/nick + v850e) + basic_machine=$basic_machine-unknown + ;; + v850ea) + basic_machine=$basic_machine-unknown + ;; + # END CYGNUS LOCAL + d10v) # CYGNUS LOCAL meissner/d10v + basic_machine=$basic_machine-unknown + ;; + # CYGNUS LOCAL d30v + d30v) + basic_machine=$basic_machine-unknown + ;; + # END CYGNUS LOCAL + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i[34567]86) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + vax-* | tahoe-* | i[34567]86-* | i860-* | m32r-* | m68k-* | m68000-* \ + | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ + | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \ + | xmp-* | ymp-* | hppa-* | hppa1.0-* | hppa1.1-* \ + | alpha-* | alphaev5-* | alphaev56-* | we32k-* | cydra-* \ + | ns16k-* | pn-* | np1-* | xps100-* | clipper-* | orion-* \ + | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ + | sparc64-* | sparcv9-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* \ + | mipstx39-* | mipstx39el-* \ + | f301-*) + ;; + m680[01234]0-* | m683?2-* | m68360-* | z8k-* | h8500-*) # CYGNUS LOCAL + ;; + mips64vr4300-* | mips64vr4300el-*) # CYGNUS LOCAL jsmith/vr4300 + ;; + mips64vr4100-* | mips64vr4100el-*) # CYGNUS LOCAL jsmith/vr4100 + ;; + mips64vr5400-* | mips64vr5400el-*) # CYGNUS LOCAL raeburn/vr5400 + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) # CYGNUS LOCAL + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) # CYGNUS LOCAL + basic_machine=a29k-amd + os=-udi + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-cbm + ;; + amigaos | amigados) + basic_machine=m68k-cbm + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-cbm + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) # CYGNUS LOCAL + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + [ctj]90-cray) + basic_machine=c90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) # CYGNUS LOCAL + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) # CYGNUS LOCAL + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) # CYGNUS LOCAL + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + w89k-*) # CYGNUS LOCAL + basic_machine=hppa1.1-winbond + os=-proelf + ;; + op50n-*) # CYGNUS LOCAL + basic_machine=hppa1.1-oki + os=-proelf + ;; + op60c-*) # CYGNUS LOCAL + basic_machine=hppa1.1-oki + os=-proelf + ;; + hppro) # CYGNUS LOCAL + basic_machine=hppa1.1-hp + os=-proelf + ;; + + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9] ) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9] ) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9] ) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | \ + hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893 ) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679] ) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) # CYGNUS LOCAL + basic_machine=hppa1.1-hp + os=-osf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + os=-mvs + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i[34567]86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i[34567]86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i[34567]86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i[34567]86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) # CYGNUS LOCAL + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) # CYGNUS LOCAL + basic_machine=i386-unknown + os=-vsta + ;; + i386-go32 | go32) # CYGNUS LOCAL + basic_machine=i386-unknown + os=-go32 + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + miniframe) + basic_machine=m68000-convergent + ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + os=-linux-gnu + ;; + mips*-linux*) + basic_machine=mips-unknown + os=-linux-gnu + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) # CYGNUS LOCAL + basic_machine=m68k-rom68k + os=-coff + ;; + msdos) # CYGNUS LOCAL + basic_machine=i386-unknown + os=-msdos + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown # CYGNUS LOCAL + os=-netbsd + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) # CYGNUS LOCAL + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) # CYGNUS LOCAL + basic_machine=i960-intel + os=-mon960 + ;; + np1) + basic_machine=np1-gould + ;; + OSE68000 | ose68000) # CYGNUS LOCAL + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) # CYGNUS LOCAL + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | nexen) + basic_machine=i586-pc + ;; + pentiumpro | p6 | k6 | 6x86) + basic_machine=i686-pc + ;; + pentiumii | pentium2) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | nexen-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | k6-* | 6x86-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=rs6000-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + rom68k) # CYGNUS LOCAL + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sa29200) # CYGNUS LOCAL + basic_machine=a29k-amd + os=-udi + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sparclite-wrs) # CYGNUS LOCAL + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) # CYGNUS LOCAL + basic_machine=m68k-tandem + ;; + stratus) # CYGNUS LOCAL + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) # CYGNUS LOCAL + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vr5400 | vr5400el) # CYGNUS LOCAL + basic_machine=mips64vr5400-unknown + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) # CYGNUS LOCAL + basic_machine=w65-wdc + os=-none + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + z8k-*-coff) # CYGNUS LOCAL + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) # CYGNUS LOCAL + basic_machine=hppa1.1-winbond + ;; + op50n) # CYGNUS LOCAL + basic_machine=hppa1.1-oki + ;; + op60c) # CYGNUS LOCAL + basic_machine=hppa1.1-oki + ;; + mips) + if [ x$os = x-linux-gnu ]; then + basic_machine=mips-unknown + else + basic_machine=mips-mips + fi + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sparc | sparcv9) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -cygwin32* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -win32* | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -udk* ) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + # CYGNUS LOCAL + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* \ + | -magic* | -mon960* | -lnews* ) + ;; + # END CYGNUS LOCAL + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -386bsd) # CYGNUS LOCAL + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) # CYGNUS LOCAL + os=-ose + ;; + -es1800*) # CYGNUS LOCAL + os=-ose + ;; + -xenix) + os=-xenix + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-semi) + os=-aout + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) # CYGNUS LOCAL + os=-aout + ;; + mips*-cisco) # CYGNUS LOCAL + os=-elf + ;; + mips*-*) # CYGNUS LOCAL + os=-elf + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-ibm) + os=-aix + ;; + *-wec) # CYGNUS LOCAL + os=-proelf + ;; + *-winbond) # CYGNUS LOCAL + os=-proelf + ;; + *-oki) # CYGNUS LOCAL + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f301-fujitsu) + os=-uxpv + ;; + *-rom68k) # CYGNUS LOCAL + os=-coff + ;; + *-*bug) # CYGNUS LOCAL + os=-coff + ;; + *-be) + os=-beos + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -bosx*) # CYGNUS LOCAL + vendor=bull + ;; + -lynxos*) # CYGNUS LOCAL + vendor=lynx + ;; + -aix*) + vendor=ibm + ;; + -hpux*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) # CYGNUS LOCAL + vendor=hitachi + ;; + -beos*) + vendor=be + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os diff --git a/gcc_arm/config/arm/README-interworking b/gcc_arm/config/arm/README-interworking new file mode 100755 index 0000000..46b76c9 --- /dev/null +++ b/gcc_arm/config/arm/README-interworking @@ -0,0 +1,742 @@ + Arm / Thumb Interworking + ======================== + +The Cygnus GNU Pro Toolkit for the ARM7T processor supports function +calls between code compiled for the ARM instruction set and code +compiled for the Thumb instruction set and vice versa. This document +describes how that interworking support operates and explains the +command line switches that should be used in order to produce working +programs. + +Note: The Cygnus GNU Pro Toolkit does not support switching between +compiling for the ARM instruction set and the Thumb instruction set +on anything other than a per file basis. There are in fact two +completely separate compilers, one that produces ARM assembler +instructions and one that produces Thumb assembler instructions. The +two compilers share the same assembler, linker and so on. + + +1. Explicit interworking support for C and C++ files +==================================================== + +By default if a file is compiled without any special command line +switches then the code produced will not support interworking. +Provided that a program is made up entirely from object files and +libraries produced in this way and which contain either exclusively +ARM instructions or exclusively Thumb instructions then this will not +matter and a working executable will be created. If an attempt is +made to link together mixed ARM and Thumb object files and libraries, +then warning messages will be produced by the linker and a non-working +executable will be created. + +In order to produce code which does support interworking it should be +compiled with the + + -mthumb-interwork + +command line option. Provided that a program is made up entirely from +object files and libraries built with this command line switch a +working executable will be produced, even if both ARM and Thumb +instructions are used by the various components of the program. (No +warning messages will be produced by the linker either). + +Note that specifying -mthumb-interwork does result in slightly larger, +slower code being produced. This is why interworking support must be +specifically enabled by a switch. + + +2. Explicit interworking support for assembler files +==================================================== + +If assembler files are to be included into an interworking program +then the following rules must be obeyed: + + * Any externally visible functions must return by using the BX + instruction. + + * Normal function calls can just use the BL instruction. The + linker will automatically insert code to switch between ARM + and Thumb modes as necessary. + + * Calls via function pointers should use the BX instruction if + the call is made in ARM mode: + + .code 32 + mov lr, pc + bx rX + + This code sequence will not work in Thumb mode however, since + the mov instruction will not set the bottom bit of the lr + register. Instead a branch-and-link to the _call_via_rX + functions should be used instead: + + .code 16 + bl _call_via_rX + + where rX is replaced by the name of the register containing + the function address. + + * All externally visible functions which should be entered in + Thumb mode must have the .thumb_func pseudo op specified just + before their entry point. eg: + + .code 16 + .global function + .thumb_func + function: + ...start of function.... + + * All assembler files must be assembled with the switch + -mthumb-interwork specified on the command line. (If the file + is assembled by calling gcc it will automatically pass on the + -mthumb-interwork switch to the assembler, provided that it + was specified on the gcc command line in the first place.) + + +3. Support for old, non-interworking aware code. +================================================ + +If it is necessary to link together code produced by an older, +non-interworking aware compiler, or code produced by the new compiler +but without the -mthumb-interwork command line switch specified, then +there are two command line switches that can be used to support this. + +The switch + + -mcaller-super-interworking + +will allow calls via function pointers in Thumb mode to work, +regardless of whether the function pointer points to old, +non-interworking aware code or not. Specifying this switch does +produce slightly slower code however. + +Note: There is no switch to allow calls via function pointers in ARM +mode to be handled specially. Calls via function pointers from +interworking aware ARM code to non-interworking aware ARM code work +without any special considerations by the compiler. Calls via +function pointers from interworking aware ARM code to non-interworking +aware Thumb code however will not work. (Actually under some +circumstances they may work, but there are no guarantees). This is +because only the new compiler is able to produce Thumb code, and this +compiler already has a command line switch to produce interworking +aware code. + + +The switch + + -mcallee-super-interworking + +will allow non-interworking aware ARM or Thumb code to call Thumb +functions, either directly or via function pointers. Specifying this +switch does produce slightly larger, slower code however. + +Note: There is no switch to allow non-interworking aware ARM or Thumb +code to call ARM functions. There is no need for any special handling +of calls from non-interworking aware ARM code to interworking aware +ARM functions, they just work normally. Calls from non-interworking +aware Thumb functions to ARM code however, will not work. There is no +option to support this, since it is always possible to recompile the +Thumb code to be interworking aware. + +As an alternative to the command line switch +-mcallee-super-interworking, which affects all externally visible +functions in a file, it is possible to specify an attribute or +declspec for individual functions, indicating that that particular +function should support being called by non-interworking aware code. +The function should be defined like this: + + int __attribute__((interfacearm)) function + { + ... body of function ... + } + +or + + int __declspec(interfacearm) function + { + ... body of function ... + } + + + +4. Interworking support in dlltool +================================== + +It is possible to create DLLs containing mixed ARM and Thumb code. It +is also possible to call Thumb code in a DLL from an ARM program and +vice versa. It is even possible to call ARM DLLs that have been compiled +without interworking support (say by an older version of the compiler), +from Thumb programs and still have things work properly. + + A version of the `dlltool' program which supports the `--interwork' +command line switch is needed, as well as the following special +considerations when building programs and DLLs: + +*Use `-mthumb-interwork'* + When compiling files for a DLL or a program the `-mthumb-interwork' + command line switch should be specified if calling between ARM and + Thumb code can happen. If a program is being compiled and the + mode of the DLLs that it uses is not known, then it should be + assumed that interworking might occur and the switch used. + +*Use `-m thumb'* + If the exported functions from a DLL are all Thumb encoded then the + `-m thumb' command line switch should be given to dlltool when + building the stubs. This will make dlltool create Thumb encoded + stubs, rather than its default of ARM encoded stubs. + + If the DLL consists of both exported Thumb functions and exported + ARM functions then the `-m thumb' switch should not be used. + Instead the Thumb functions in the DLL should be compiled with the + `-mcallee-super-interworking' switch, or with the `interfacearm' + attribute specified on their prototypes. In this way they will be + given ARM encoded prologues, which will work with the ARM encoded + stubs produced by dlltool. + +*Use `-mcaller-super-interworking'* + If it is possible for Thumb functions in a DLL to call + non-interworking aware code via a function pointer, then the Thumb + code must be compiled with the `-mcaller-super-interworking' + command line switch. This will force the function pointer calls + to use the _interwork_call_via_rX stub functions which will + correctly restore Thumb mode upon return from the called function. + +*Link with `libgcc.a'* + When the dll is built it may have to be linked with the GCC + library (`libgcc.a') in order to extract the _call_via_rX functions + or the _interwork_call_via_rX functions. This represents a partial + redundancy since the same functions *may* be present in the + application itself, but since they only take up 372 bytes this + should not be too much of a consideration. + +*Use `--support-old-code'* + When linking a program with an old DLL which does not support + interworking, the `--support-old-code' command line switch to the + linker should be used. This causes the linker to generate special + interworking stubs which can cope with old, non-interworking aware + ARM code, at the cost of generating bulkier code. The linker will + still generate a warning message along the lines of: + "Warning: input file XXX does not support interworking, whereas YYY does." + but this can now be ignored because the --support-old-code switch + has been used. + + + +5. How interworking support works +================================= + +Switching between the ARM and Thumb instruction sets is accomplished +via the BX instruction which takes as an argument a register name. +Control is transfered to the address held in this register (with the +bottom bit masked out), and if the bottom bit is set, then Thumb +instruction processing is enabled, otherwise ARM instruction +processing is enabled. + +When the -mthumb-interwork command line switch is specified, gcc +arranges for all functions to return to their caller by using the BX +instruction. Thus provided that the return address has the bottom bit +correctly initialised to indicate the instruction set of the caller, +correct operation will ensue. + +When a function is called explicitly (rather than via a function +pointer), the compiler generates a BL instruction to do this. The +Thumb version of the BL instruction has the special property of +setting the bottom bit of the LR register after it has stored the +return address into it, so that a future BX instruction will correctly +return the instruction after the BL instruction, in Thumb mode. + +The BL instruction does not change modes itself however, so if an ARM +function is calling a Thumb function, or vice versa, it is necessary +to generate some extra instructions to handle this. This is done in +the linker when it is storing the address of the referenced function +into the BL instruction. If the BL instruction is an ARM style BL +instruction, but the referenced function is a Thumb function, then the +linker automatically generates a calling stub that converts from ARM +mode to Thumb mode, puts the address of this stub into the BL +instruction, and puts the address of the referenced function into the +stub. Similarly if the BL instruction is a Thumb BL instruction, and +the referenced function is an ARM function, the linker generates a +stub which converts from Thumb to ARM mode, puts the address of this +stub into the BL instruction, and the address of the referenced +function into the stub. + +This is why it is necessary to mark Thumb functions with the +.thumb_func pseudo op when creating assembler files. This pseudo op +allows the assembler to distinguish between ARM functions and Thumb +functions. (The Thumb version of GCC automatically generates these +pseudo ops for any Thumb functions that it generates). + +Calls via function pointers work differently. Whenever the address of +a function is taken, the linker examines the type of the function +being referenced. If the function is a Thumb function, then it sets +the bottom bit of the address. Technically this makes the address +incorrect, since it is now one byte into the start of the function, +but this is never a problem because: + + a. with interworking enabled all calls via function pointer + are done using the BX instruction and this ignores the + bottom bit when computing where to go to. + + b. the linker will always set the bottom bit when the address + of the function is taken, so it is never possible to take + the address of the function in two different places and + then compare them and find that they are not equal. + +As already mentioned any call via a function pointer will use the BX +instruction (provided that interworking is enabled). The only problem +with this is computing the return address for the return from the +called function. For ARM code this can easily be done by the code +sequence: + + mov lr, pc + bx rX + +(where rX is the name of the register containing the function +pointer). This code does not work for the Thumb instruction set, +since the MOV instruction will not set the bottom bit of the LR +register, so that when the called function returns, it will return in +ARM mode not Thumb mode. Instead the compiler generates this +sequence: + + bl _call_via_rX + +(again where rX is the name if the register containing the function +pointer). The special call_via_rX functions look like this: + + .thumb_func +_call_via_r0: + bx r0 + nop + +The BL instruction ensures that the correct return address is stored +in the LR register and then the BX instruction jumps to the address +stored in the function pointer, switch modes if necessary. + + +6. How caller-super-interworking support works +============================================== + +When the -mcaller-super-interworking command line switch is specified +it changes the code produced by the Thumb compiler so that all calls +via function pointers (including virtual function calls) now go via a +different stub function. The code to call via a function pointer now +looks like this: + + bl _interwork_call_via_r0 + +Note: The compiler does not insist that r0 be used to hold the +function address. Any register will do, and there are a suite of stub +functions, one for each possible register. The stub functions look +like this: + + .code 16 + .thumb_func +_interwork_call_via_r0 + bx pc + nop + + .code 32 + tst r0, #1 + stmeqdb r13!, {lr} + adreq lr, _arm_return + bx r0 + +The stub first switches to ARM mode, since it is a lot easier to +perform the necessary operations using ARM instructions. It then +tests the bottom bit of the register containing the address of the +function to be called. If this bottom bit is set then the function +being called uses Thumb instructions and the BX instruction to come +will switch back into Thumb mode before calling this function. (Note +that it does not matter how this called function chooses to return to +its caller, since the both the caller and callee are Thumb functions, +and mode switching is necessary). If the function being called is an +ARM mode function however, the stub pushes the return address (with +its bottom bit set) onto the stack, replaces the return address with +the address of the a piece of code called '_arm_return' and then +performs a BX instruction to call the function. + +The '_arm_return' code looks like this: + + .code 32 +_arm_return: + ldmia r13!, {r12} + bx r12 + .code 16 + + +It simply retrieves the return address from the stack, and then +performs a BX operation to return to the caller and switch back into +Thumb mode. + + +7. How callee-super-interworking support works +============================================== + +When -mcallee-super-interworking is specified on the command line the +Thumb compiler behaves as if every externally visible function that it +compiles has had the (interfacearm) attribute specified for it. What +this attribute does is to put a special, ARM mode header onto the +function which forces a switch into Thumb mode: + + without __attribute__((interfacearm)): + + .code 16 + .thumb_func + function: + ... start of function ... + + with __attribute__((interfacearm)): + + .code 32 + function: + orr r12, pc, #1 + bx r12 + + .code 16 + .thumb_func + .real_start_of_function: + + ... start of function ... + +Note that since the function now expects to be entered in ARM mode, it +no longer has the .thumb_func pseudo op specified for its name. +Instead the pseudo op is attached to a new label .real_start_of_ +(where is the name of the function) which indicates the start +of the Thumb code. This does have the interesting side effect in that +if this function is now called from a Thumb mode piece of code +outsside of the current file, the linker will generate a calling stub +to switch from Thumb mode into ARM mode, and then this is immediately +overridden by the function's header which switches back into Thumb +mode. + +In addition the (interfacearm) attribute also forces the function to +return by using the BX instruction, even if has not been compiled with +the -mthumb-interwork command line flag, so that the correct mode will +be restored upon exit from the function. + + +8. Some examples +================ + + Given these two test files: + + int arm (void) { return 1 + thumb (); } + + int thumb (void) { return 2 + arm (); } + + The following pieces of assembler are produced by the ARM and Thumb +version of GCC depending upon the command line options used: + + `-O2': + .code 32 .code 16 + .global _arm .global _thumb + .thumb_func + _arm: _thumb: + mov ip, sp + stmfd sp!, {fp, ip, lr, pc} push {lr} + sub fp, ip, #4 + bl _thumb bl _arm + add r0, r0, #1 add r0, r0, #2 + ldmea fp, {fp, sp, pc} pop {pc} + + Note how the functions return without using the BX instruction. If +these files were assembled and linked together they would fail to work +because they do not change mode when returning to their caller. + + `-O2 -mthumb-interwork': + + .code 32 .code 16 + .global _arm .global _thumb + .thumb_func + _arm: _thumb: + mov ip, sp + stmfd sp!, {fp, ip, lr, pc} push {lr} + sub fp, ip, #4 + bl _thumb bl _arm + add r0, r0, #1 add r0, r0, #2 + ldmea fp, {fp, sp, lr} pop {r1} + bx lr bx r1 + + Now the functions use BX to return their caller. They have grown by +4 and 2 bytes respectively, but they can now successfully be linked +together and be expect to work. The linker will replace the +destinations of the two BL instructions with the addresses of calling +stubs which convert to the correct mode before jumping to the called +function. + + `-O2 -mcallee-super-interworking': + + .code 32 .code 32 + .global _arm .global _thumb + _arm: _thumb: + orr r12, pc, #1 + bx r12 + mov ip, sp .code 16 + stmfd sp!, {fp, ip, lr, pc} push {lr} + sub fp, ip, #4 + bl _thumb bl _arm + add r0, r0, #1 add r0, r0, #2 + ldmea fp, {fp, sp, lr} pop {r1} + bx lr bx r1 + + The thumb function now has an ARM encoded prologue, and it no longer +has the `.thumb-func' pseudo op attached to it. The linker will not +generate a calling stub for the call from arm() to thumb(), but it will +still have to generate a stub for the call from thumb() to arm(). Also +note how specifying `--mcallee-super-interworking' automatically +implies `-mthumb-interworking'. + + +9. Some Function Pointer Examples +================================= + + Given this test file: + + int func (void) { return 1; } + + int call (int (* ptr)(void)) { return ptr (); } + + The following varying pieces of assembler are produced by the Thumb +version of GCC depending upon the command line options used: + + `-O2': + .code 16 + .globl _func + .thumb_func + _func: + mov r0, #1 + bx lr + + .globl _call + .thumb_func + _call: + push {lr} + bl __call_via_r0 + pop {pc} + + Note how the two functions have different exit sequences. In +particular call() uses pop {pc} to return, which would not work if the +caller was in ARM mode. func() however, uses the BX instruction, even +though `-mthumb-interwork' has not been specified, as this is the most +efficient way to exit a function when the return address is held in the +link register. + + `-O2 -mthumb-interwork': + + .code 16 + .globl _func + .thumb_func + _func: + mov r0, #1 + bx lr + + .globl _call + .thumb_func + _call: + push {lr} + bl __call_via_r0 + pop {r1} + bx r1 + + This time both functions return by using the BX instruction. This +means that call() is now two bytes longer and several cycles slower +than the previous version. + + `-O2 -mcaller-super-interworking': + .code 16 + .globl _func + .thumb_func + _func: + mov r0, #1 + bx lr + + .globl _call + .thumb_func + _call: + push {lr} + bl __interwork_call_via_r0 + pop {pc} + + Very similar to the first (non-interworking) version, except that a +different stub is used to call via the function pointer. This new stub +will work even if the called function is not interworking aware, and +tries to return to call() in ARM mode. Note that the assembly code for +call() is still not interworking aware itself, and so should not be +called from ARM code. + + `-O2 -mcallee-super-interworking': + + .code 32 + .globl _func + _func: + orr r12, pc, #1 + bx r12 + + .code 16 + .globl .real_start_of_func + .thumb_func + .real_start_of_func: + mov r0, #1 + bx lr + + .code 32 + .globl _call + _call: + orr r12, pc, #1 + bx r12 + + .code 16 + .globl .real_start_of_call + .thumb_func + .real_start_of_call: + push {lr} + bl __call_via_r0 + pop {r1} + bx r1 + + Now both functions have an ARM coded prologue, and both functions +return by using the BX instruction. These functions are interworking +aware therefore and can safely be called from ARM code. The code for +the call() function is now 10 bytes longer than the original, non +interworking aware version, an increase of over 200%. + + If a prototype for call() is added to the source code, and this +prototype includes the `interfacearm' attribute: + + int __attribute__((interfacearm)) call (int (* ptr)(void)); + + then this code is produced (with only -O2 specified on the command +line): + + .code 16 + .globl _func + .thumb_func + _func: + mov r0, #1 + bx lr + + .globl _call + .code 32 + _call: + orr r12, pc, #1 + bx r12 + + .code 16 + .globl .real_start_of_call + .thumb_func + .real_start_of_call: + push {lr} + bl __call_via_r0 + pop {r1} + bx r1 + + So now both call() and func() can be safely called via +non-interworking aware ARM code. If, when such a file is assembled, +the assembler detects the fact that call() is being called by another +function in the same file, it will automatically adjust the target of +the BL instruction to point to .real_start_of_call. In this way there +is no need for the linker to generate a Thumb-to-ARM calling stub so +that call can be entered in ARM mode. + + +10. How to use dlltool to build ARM/Thumb DLLs +============================================== + Given a program (`prog.c') like this: + + extern int func_in_dll (void); + + int main (void) { return func_in_dll(); } + + And a DLL source file (`dll.c') like this: + + int func_in_dll (void) { return 1; } + + Here is how to build the DLL and the program for a purely ARM based +environment: + +*Step One + Build a `.def' file describing the DLL: + + ; example.def + ; This file describes the contents of the DLL + LIBRARY example + HEAPSIZE 0x40000, 0x2000 + EXPORTS + func_in_dll 1 + +*Step Two + Compile the DLL source code: + + arm-pe-gcc -O2 -c dll.c + +*Step Three + Use `dlltool' to create an exports file and a library file: + + dlltool --def example.def --output-exp example.o --output-lib example.a + +*Step Four + Link together the complete DLL: + + arm-pe-ld dll.o example.o -o example.dll + +*Step Five + Compile the program's source code: + + arm-pe-gcc -O2 -c prog.c + +*Step Six + Link together the program and the DLL's library file: + + arm-pe-gcc prog.o example.a -o prog + + If instead this was a Thumb DLL being called from an ARM program, the +steps would look like this. (To save space only those steps that are +different from the previous version are shown): + +*Step Two + Compile the DLL source code (using the Thumb compiler): + + thumb-pe-gcc -O2 -c dll.c -mthumb-interwork + +*Step Three + Build the exports and library files (and support interworking): + + dlltool -d example.def -z example.o -l example.a --interwork -m thumb + +*Step Five + Compile the program's source code (and support interworking): + + arm-pe-gcc -O2 -c prog.c -mthumb-interwork + + If instead, the DLL was an old, ARM DLL which does not support +interworking, and which cannot be rebuilt, then these steps would be +used. + +*Step One + Skip. If you do not have access to the sources of a DLL, there is + no point in building a `.def' file for it. + +*Step Two + Skip. With no DLL sources there is nothing to compile. + +*Step Three + Skip. Without a `.def' file you cannot use dlltool to build an + exports file or a library file. + +*Step Four + Skip. Without a set of DLL object files you cannot build the DLL. + Besides it has already been built for you by somebody else. + +*Step Five + Compile the program's source code, this is the same as before: + + arm-pe-gcc -O2 -c prog.c + +*Step Six + Link together the program and the DLL's library file, passing the + `--support-old-code' option to the linker: + + arm-pe-gcc prog.o example.a -Wl,--support-old-code -o prog + + Ignore the warning message about the input file not supporting + interworking as the --support-old-code switch has taken care if this. diff --git a/gcc_arm/config/arm/aof.h b/gcc_arm/config/arm/aof.h new file mode 100755 index 0000000..6c21850 --- /dev/null +++ b/gcc_arm/config/arm/aof.h @@ -0,0 +1,453 @@ +/* Definitions of target machine for GNU compiler, for Advanced RISC Machines + ARM compilation, AOF Assembler. + Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. + Contributed by Richard Earnshaw (rearnsha@armltd.co.uk) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + + +#define AOF_ASSEMBLER + +#define LINK_LIBGCC_SPECIAL 1 + +#define LINK_SPEC "%{aof} %{bin} %{aif} %{ihf} %{shl,*} %{reent*} %{split} \ + %{ov*,*} %{reloc*} -nodebug" + +#define STARTFILE_SPEC "crtbegin.o%s" + +#define ENDFILE_SPEC "crtend.o%s" + +#ifndef ASM_SPEC +#define ASM_SPEC "%{g -g} -arch 4 \ +-apcs 3%{mapcs-32:/32bit}%{mapcs-26:/26bit}%{!mapcs-26:%{!macps-32:/26bit}}" +#endif + +#ifndef LIB_SPEC +#define LIB_SPEC "%{Eb: armlib_h.32b%s}%{!Eb: armlib_h.32l%s}" +#endif + +#define LIBGCC_SPEC "libgcc.a%s" + +/* Dividing the Output into Sections (Text, Data, ...) */ +/* AOF Assembler syntax is a nightmare when it comes to areas, since once + we change from one area to another, we can't go back again. Instead, + we must create a new area with the same attributes and add the new output + to that. Unfortunately, there is nothing we can do here to guarantee that + two areas with the same attributes will be linked adjacently in the + resulting executable, so we have to be careful not to do pc-relative + addressing across such boundaries. */ +char *aof_text_section (); +#define TEXT_SECTION_ASM_OP aof_text_section () + +#define SELECT_RTX_SECTION(MODE,RTX) text_section (); + +char *aof_data_section (); +#define DATA_SECTION_ASM_OP aof_data_section () + +#define EXTRA_SECTIONS in_zero_init, in_ctor, in_dtor, in_common + +#define EXTRA_SECTION_FUNCTIONS \ +ZERO_INIT_SECTION \ +CTOR_SECTION \ +DTOR_SECTION \ +COMMON_SECTION + +#define ZERO_INIT_SECTION \ +void \ +zero_init_section () \ +{ \ + static int zero_init_count = 1; \ + if (in_section != in_zero_init) \ + { \ + fprintf (asm_out_file, "\tAREA |C$$zidata%d|,NOINIT\n", \ + zero_init_count++); \ + in_section = in_zero_init; \ + } \ +} + +#define CTOR_SECTION \ +void \ +ctor_section () \ +{ \ + static int ctors_once = 0; \ + if (in_section != in_ctor) \ + { \ + if (ctors_once) \ + { \ + fprintf (stderr, \ + "Attempt to output more than one ctor section\n"); \ + abort (); \ + } \ + fprintf (asm_out_file, "\t%s\n", CTORS_SECTION_ASM_OP); \ + in_section = in_ctor; \ + ctors_once = 1; \ + } \ +} + +#define DTOR_SECTION \ +void \ +dtor_section () \ +{ \ + static int dtors_once = 0; \ + if (in_section != in_dtor) \ + { \ + if (dtors_once) \ + { \ + fprintf (stderr, \ + "Attempt to output more than one dtor section\n"); \ + abort (); \ + } \ + fprintf (asm_out_file, "\t%s\n", DTORS_SECTION_ASM_OP); \ + in_section = in_dtor; \ + dtors_once = 1; \ + } \ +} + +/* Used by ASM_OUTPUT_COMMON (below) to tell varasm.c that we've + changed areas. */ +#define COMMON_SECTION \ +void \ +common_section () \ +{ \ + static int common_count = 1; \ + if (in_section != in_common) \ + { \ + in_section = in_common; \ + } \ +} +#define CTOR_LIST_BEGIN \ +asm (CTORS_SECTION_ASM_OP); \ +extern func_ptr __CTOR_END__[1]; \ +func_ptr __CTOR_LIST__[1] = {__CTOR_END__}; + +#define CTOR_LIST_END \ +asm (CTORS_SECTION_ASM_OP); \ +func_ptr __CTOR_END__[1] = { (func_ptr) 0 }; + +#define DO_GLOBAL_CTORS_BODY \ +do { \ + func_ptr *ptr = __CTOR_LIST__ + 1; \ + while (*ptr) \ + (*ptr++) (); \ +} while (0) + +#define DTOR_LIST_BEGIN \ +asm (DTORS_SECTION_ASM_OP); \ +extern func_ptr __DTOR_END__[1]; \ +func_ptr __DTOR_LIST__[1] = {__DTOR_END__}; + +#define DTOR_LIST_END \ +asm (DTORS_SECTION_ASM_OP); \ +func_ptr __DTOR_END__[1] = { (func_ptr) 0 }; + +#define DO_GLOBAL_DTORS_BODY \ +do { \ + func_ptr *ptr = __DTOR_LIST__ + 1; \ + while (*ptr) \ + (*ptr++) (); \ +} while (0) + +#define JUMP_TABLES_IN_TEXT_SECTION 1 + +#ifndef ARM_OS_NAME +#define ARM_OS_NAME "(generic)" +#endif + +/* For the AOF linker, we need to reference __main to force the standard + library to get linked in. */ + +#define ASM_FILE_START(STREAM) \ +{ \ + extern char *version_string; \ + fprintf ((STREAM), "%s Generated by gcc %s for ARM/%s\n", \ + ASM_COMMENT_START, version_string, ARM_OS_NAME); \ + fprintf ((STREAM), "__a1\tRN\t0\n"); \ + fprintf ((STREAM), "__a2\tRN\t1\n"); \ + fprintf ((STREAM), "__a3\tRN\t2\n"); \ + fprintf ((STREAM), "__a4\tRN\t3\n"); \ + fprintf ((STREAM), "__v1\tRN\t4\n"); \ + fprintf ((STREAM), "__v2\tRN\t5\n"); \ + fprintf ((STREAM), "__v3\tRN\t6\n"); \ + fprintf ((STREAM), "__v4\tRN\t7\n"); \ + fprintf ((STREAM), "__v5\tRN\t8\n"); \ + fprintf ((STREAM), "__v6\tRN\t9\n"); \ + fprintf ((STREAM), "__sl\tRN\t10\n"); \ + fprintf ((STREAM), "__fp\tRN\t11\n"); \ + fprintf ((STREAM), "__ip\tRN\t12\n"); \ + fprintf ((STREAM), "__sp\tRN\t13\n"); \ + fprintf ((STREAM), "__lr\tRN\t14\n"); \ + fprintf ((STREAM), "__pc\tRN\t15\n"); \ + fprintf ((STREAM), "__f0\tFN\t0\n"); \ + fprintf ((STREAM), "__f1\tFN\t1\n"); \ + fprintf ((STREAM), "__f2\tFN\t2\n"); \ + fprintf ((STREAM), "__f3\tFN\t3\n"); \ + fprintf ((STREAM), "__f4\tFN\t4\n"); \ + fprintf ((STREAM), "__f5\tFN\t5\n"); \ + fprintf ((STREAM), "__f6\tFN\t6\n"); \ + fprintf ((STREAM), "__f7\tFN\t7\n"); \ + text_section (); \ +} + +/* 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 + must define both, or neither. */ +#define NAME__MAIN "__gccmain" +#define SYMBOL__MAIN __gccmain + +#define ASM_FILE_END(STREAM) \ +do \ +{ \ + if (flag_pic) \ + aof_dump_pic_table (STREAM); \ + aof_dump_imports (STREAM); \ + fputs ("\tEND\n", (STREAM)); \ +} while (0); + +#define ASM_IDENTIFY_GCC(STREAM) fputs ("|gcc2_compiled.|\n", (STREAM)) + +#define ASM_COMMENT_START ";" + +#define ASM_APP_ON "" + +#define ASM_APP_OFF "" + +#define ASM_OUTPUT_LONG_DOUBLE(STREAM,VALUE) \ + ASM_OUTPUT_DOUBLE((STREAM),(VALUE)) + +#define ASM_OUTPUT_DOUBLE(STREAM,VALUE) \ +do { \ + char dstr[30]; \ + long l[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE ((VALUE), l); \ + REAL_VALUE_TO_DECIMAL ((VALUE), "%.14g", dstr); \ + fprintf ((STREAM), "\tDCD &%lx, &%lx\t%s double %s\n", \ + l[0], l[1], ASM_COMMENT_START, dstr); \ +} while (0) + +#define ASM_OUTPUT_FLOAT(STREAM,VALUE) \ +do { \ + char dstr[30]; \ + long l; \ + REAL_VALUE_TO_TARGET_SINGLE ((VALUE), l); \ + REAL_VALUE_TO_DECIMAL ((VALUE), "%.7g", dstr); \ + fprintf ((STREAM), "\tDCD &%lx\t%s double %s\n", \ + l, ASM_COMMENT_START, dstr); \ +} while (0) + +#define ASM_OUTPUT_INT(STREAM,VALUE) \ + (fprintf ((STREAM), "\tDCD\t"), \ + output_addr_const ((STREAM), (VALUE)), \ + fputc ('\n', (STREAM))) + +#define ASM_OUTPUT_SHORT(STREAM,VALUE) \ + (fprintf ((STREAM), "\tDCW\t"), \ + output_addr_const ((STREAM), (VALUE)), \ + fputc ('\n', (STREAM))) + +#define ASM_OUTPUT_CHAR(STREAM,VALUE) \ + (fprintf ((STREAM), "\tDCB\t"), \ + output_addr_const ((STREAM), (VALUE)), \ + fputc ('\n', (STREAM))) + +#define ASM_OUTPUT_BYTE(STREAM,VALUE) \ + fprintf ((STREAM), "\tDCB\t%d\n", (VALUE)) + +#define ASM_OUTPUT_ASCII(STREAM,PTR,LEN) \ +{ \ + int i; \ + char *ptr = (PTR); \ + fprintf ((STREAM), "\tDCB"); \ + for (i = 0; i < (LEN); i++) \ + fprintf ((STREAM), " &%02x%s", \ + (unsigned ) *(ptr++), \ + (i + 1 < (LEN) \ + ? ((i & 3) == 3 ? "\n\tDCB" : ",") \ + : "\n")); \ +} + +#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == '\n') + +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + +/* Output of Uninitialized Variables */ + +#define ASM_OUTPUT_COMMON(STREAM,NAME,SIZE,ROUNDED) \ + (common_section (), \ + fprintf ((STREAM), "\tAREA "), \ + assemble_name ((STREAM), (NAME)), \ + fprintf ((STREAM), ", DATA, COMMON\n\t%% %d\t%s size=%d\n", \ + (ROUNDED), ASM_COMMENT_START, SIZE)) + +#define ASM_OUTPUT_LOCAL(STREAM,NAME,SIZE,ROUNDED) \ + (zero_init_section (), \ + assemble_name ((STREAM), (NAME)), \ + fprintf ((STREAM), "\n"), \ + fprintf ((STREAM), "\t%% %d\t%s size=%d\n", \ + (ROUNDED), ASM_COMMENT_START, SIZE)) + +/* Output and Generation of Labels */ + +extern int arm_main_function; + +#define ASM_GLOBALIZE_LABEL(STREAM,NAME) \ +do { \ + fprintf ((STREAM), "\tEXPORT\t"); \ + assemble_name ((STREAM), (NAME)); \ + fputc ('\n', (STREAM)); \ + if ((NAME)[0] == 'm' && ! strcmp ((NAME), "main")) \ + arm_main_function = 1; \ +} while (0) + +#define ASM_OUTPUT_LABEL(STREAM,NAME) \ +do { \ + assemble_name (STREAM,NAME); \ + fputs ("\n", STREAM); \ +} while (0) + +#define ASM_DECLARE_FUNCTION_NAME(STREAM,NAME,DECL) \ +{ \ + ASM_OUTPUT_LABEL (STREAM, NAME); \ + if (! TREE_PUBLIC (DECL)) \ + { \ + fputs ("\tKEEP ", STREAM); \ + ASM_OUTPUT_LABEL (STREAM, NAME); \ + } \ + aof_delete_import ((NAME)); \ +} + +#define ASM_DECLARE_OBJECT_NAME(STREAM,NAME,DECL) \ +{ \ + ASM_OUTPUT_LABEL (STREAM, NAME); \ + if (! TREE_PUBLIC (DECL)) \ + { \ + fputs ("\tKEEP ", STREAM); \ + ASM_OUTPUT_LABEL (STREAM, NAME); \ + } \ + aof_delete_import ((NAME)); \ +} + +#define ASM_OUTPUT_EXTERNAL(STREAM,DECL,NAME) \ + aof_add_import ((NAME)) + +#define ASM_OUTPUT_EXTERNAL_LIBCALL(STREAM,SYMREF) \ + (fprintf ((STREAM), "\tIMPORT\t"), \ + assemble_name ((STREAM), XSTR ((SYMREF), 0)), \ + fputc ('\n', (STREAM))) + +#define ASM_OUTPUT_LABELREF(STREAM,NAME) \ + fprintf ((STREAM), "|%s|", NAME) + +#define ASM_GENERATE_INTERNAL_LABEL(STRING,PREFIX,NUM) \ + sprintf ((STRING), "*|%s..%d|", (PREFIX), (NUM)) + +#define ASM_FORMAT_PRIVATE_NAME(OUTVAR,NAME,NUMBER) \ + ((OUTVAR) = (char *) alloca (strlen ((NAME)) + 10), \ + sprintf ((OUTVAR), "%s.%d", (NAME), (NUMBER))) + +/* How initialization functions are handled */ + +#define CTORS_SECTION_ASM_OP "AREA\t|C$$gnu_ctorsvec|, DATA, READONLY" +#define DTORS_SECTION_ASM_OP "AREA\t|C$$gnu_dtorsvec|, DATA, READONLY" + +#define ASM_OUTPUT_CONSTRUCTOR(STREAM,NAME) \ +do { \ + ctor_section (); \ + fprintf ((STREAM), "\tDCD\t"); \ + assemble_name ((STREAM), (NAME)); \ + fputc ('\n', (STREAM)); \ +} while (0); + +#define ASM_OUTPUT_DESTRUCTOR(STREAM,NAME) \ +do { \ + dtor_section (); \ + fprintf ((STREAM), "\tDCD\t"); \ + assemble_name ((STREAM), (NAME)); \ + fputc ('\n', (STREAM)); \ +} while (0); + +/* Output of Assembler Instructions */ + +#define REGISTER_NAMES \ +{ \ + "a1", "a2", "a3", "a4", \ + "v1", "v2", "v3", "v4", \ + "v5", "v6", "sl", "fp", \ + "ip", "sp", "lr", "pc", \ + "f0", "f1", "f2", "f3", \ + "f4", "f5", "f6", "f7", \ + "cc", "sfp", "afp" \ +} + +#define ADDITIONAL_REGISTER_NAMES \ +{ \ + {"r0", 0}, {"a1", 0}, \ + {"r1", 1}, {"a2", 1}, \ + {"r2", 2}, {"a3", 2}, \ + {"r3", 3}, {"a4", 3}, \ + {"r4", 4}, {"v1", 4}, \ + {"r5", 5}, {"v2", 5}, \ + {"r6", 6}, {"v3", 6}, \ + {"r7", 7}, {"wr", 7}, \ + {"r8", 8}, {"v5", 8}, \ + {"r9", 9}, {"v6", 9}, \ + {"r10", 10}, {"sl", 10}, {"v7", 10}, \ + {"r11", 11}, {"fp", 11}, \ + {"r12", 12}, {"ip", 12}, \ + {"r13", 13}, {"sp", 13}, \ + {"r14", 14}, {"lr", 14}, \ + {"r15", 15}, {"pc", 15} \ +} + +#define REGISTER_PREFIX "__" +#define USER_LABEL_PREFIX "" +#define LOCAL_LABEL_PREFIX "" + +/* Output of Dispatch Tables */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM,BODY,VALUE,REL) \ + fprintf ((STREAM), "\tb\t|L..%d|\n", (VALUE)) + +#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM,VALUE) \ + fprintf ((STREAM), "\tDCD\t|L..%d|\n", (VALUE)) + +/* A label marking the start of a jump table is a data label. */ +#define ASM_OUTPUT_CASE_LABEL(STREAM,PREFIX,NUM,TABLE) \ + fprintf ((STREAM), "\tALIGN\n|%s..%d|\n", (PREFIX), (NUM)) + +/* Assembler Commands for Alignment */ + +#define ASM_OUTPUT_SKIP(STREAM,NBYTES) \ + fprintf ((STREAM), "\t%%\t%d\n", (NBYTES)) + +#define ASM_OUTPUT_ALIGN(STREAM,POWER) \ +do { \ + register int amount = 1 << (POWER); \ + if (amount == 2) \ + fprintf ((STREAM), "\tALIGN 2\n"); \ + else if (amount == 4) \ + fprintf ((STREAM), "\tALIGN\n"); \ + else \ + fprintf ((STREAM), "\tALIGN %d\n", amount); \ +} while (0) + +#include "arm/arm.h" + +#undef DBX_DEBUGGING_INFO diff --git a/gcc_arm/config/arm/aout.h b/gcc_arm/config/arm/aout.h new file mode 100755 index 0000000..42a12ea --- /dev/null +++ b/gcc_arm/config/arm/aout.h @@ -0,0 +1,323 @@ +/* Definitions of target machine for GNU compiler, for ARM with a.out + Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + Contributed by Richard Earnshaw (rearnsha@armltd.co.uk). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifndef ARM_OS_NAME +#define ARM_OS_NAME "(generic)" +#endif + +/* The text to go at the start of the assembler file */ +#ifndef ASM_FILE_START +#define ASM_FILE_START(STREAM) \ +{ \ + fprintf (STREAM,"%srfp\t.req\t%sr9\n", REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf (STREAM,"%ssl\t.req\t%sr10\n", REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf (STREAM,"%sfp\t.req\t%sr11\n", REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf (STREAM,"%sip\t.req\t%sr12\n", REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf (STREAM,"%ssp\t.req\t%sr13\n", REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf (STREAM,"%slr\t.req\t%sr14\n", REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf (STREAM,"%spc\t.req\t%sr15\n", REGISTER_PREFIX, REGISTER_PREFIX); \ +} +#endif + +#define ASM_APP_ON "" +#define ASM_APP_OFF "" + +/* Switch to the text or data segment. */ +#define TEXT_SECTION_ASM_OP ".text" +#define DATA_SECTION_ASM_OP ".data" +#define BSS_SECTION_ASM_OP ".bss" + +/* Note: If USER_LABEL_PREFIX or LOCAL_LABEL_PREFIX are changed, + make sure that this change is reflected in the function + coff_arm_is_local_label_name() in bfd/coff-arm.c */ +#ifndef REGISTER_PREFIX +#define REGISTER_PREFIX "" +#endif + +#ifndef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "_" +#endif + +#ifndef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "" +#endif + + +/* The assembler's names for the registers. */ +#ifndef REGISTER_NAMES +#define REGISTER_NAMES \ +{ \ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc", \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ + "cc", "sfp", "afp" \ +} +#endif + +#ifndef ADDITIONAL_REGISTER_NAMES +#define ADDITIONAL_REGISTER_NAMES \ +{ \ + {"a1", 0}, \ + {"a2", 1}, \ + {"a3", 2}, \ + {"a4", 3}, \ + {"v1", 4}, \ + {"v2", 5}, \ + {"v3", 6}, \ + {"v4", 7}, \ + {"v5", 8}, \ + {"v6", 9}, \ + {"rfp", 9}, /* Gcc used to call it this */ \ + {"sb", 9}, \ + {"v7", 10}, \ + {"r10", 10}, /* sl */ \ + {"r11", 11}, /* fp */ \ + {"r12", 12}, /* ip */ \ + {"r13", 13}, /* sp */ \ + {"r14", 14}, /* lr */ \ + {"r15", 15} /* pc */ \ +} +#endif + +/* Arm Assembler barfs on dollars */ +#define DOLLARS_IN_IDENTIFIERS 0 + +#define NO_DOLLAR_IN_LABEL + +/* DBX register number for a given compiler register number */ +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* Generate DBX debugging information. riscix.h will undefine this because + the native assembler does not support stabs. */ +#define DBX_DEBUGGING_INFO 1 + +/* Acorn dbx moans about continuation chars, so don't use any. */ +#ifndef DBX_CONTIN_LENGTH +#define DBX_CONTIN_LENGTH 0 +#endif + +/* Output a source filename for the debugger. RISCiX dbx insists that the + ``desc'' field is set to compiler version number >= 315 (sic). */ +#define DBX_OUTPUT_MAIN_SOURCE_FILENAME(STREAM,NAME) \ +do { \ + fprintf (STREAM, ".stabs \"%s\",%d,0,315,%s\n", (NAME), N_SO, \ + <ext_label_name[1]); \ + text_section (); \ + ASM_OUTPUT_INTERNAL_LABEL (STREAM, "Ltext", 0); \ +} while (0) + +/* Output a function label definition. */ +#ifndef ASM_DECLARE_FUNCTION_NAME +#define ASM_DECLARE_FUNCTION_NAME(STREAM,NAME,DECL) ASM_OUTPUT_LABEL (STREAM, NAME) +#endif + +#ifndef ASM_OUTPUT_LABEL +#define ASM_OUTPUT_LABEL(STREAM,NAME) \ +do { \ + assemble_name (STREAM,NAME); \ + fputs (":\n", STREAM); \ +} while (0) +#endif + +/* Output a globalising directive for a label. */ +#ifndef ASM_GLOBALIZE_LABEL +#define ASM_GLOBALIZE_LABEL(STREAM,NAME) \ + (fprintf (STREAM, "\t.global\t"), \ + assemble_name (STREAM, NAME), \ + fputc ('\n',STREAM)) +#endif + +/* Make an internal label into a string. */ +#ifndef ASM_GENERATE_INTERNAL_LABEL +#define ASM_GENERATE_INTERNAL_LABEL(STRING, PREFIX, NUM) \ + sprintf (STRING, "*%s%s%d", LOCAL_LABEL_PREFIX, PREFIX, NUM) +#endif + +/* Nothing special is done about jump tables */ +/* #define ASM_OUTPUT_CASE_LABEL(STREAM,PREFIX,NUM,TABLE) */ +/* #define ASM_OUTPUT_CASE_END(STREAM,NUM,TABLE) */ + +/* Construct a private name. */ +#define ASM_FORMAT_PRIVATE_NAME(OUTVAR,NAME,NUMBER) \ + ((OUTVAR) = (char *) alloca (strlen (NAME) + 10), \ + sprintf ((OUTVAR), "%s.%d", (NAME), (NUMBER))) + +/* Output an element of a dispatch table. */ +#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM,VALUE) \ + fprintf (STREAM, "\t.word\t%sL%d\n", LOCAL_LABEL_PREFIX, VALUE) + +#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM,BODY,VALUE,REL) \ + fprintf (STREAM, "\tb\t%sL%d\n", LOCAL_LABEL_PREFIX, (VALUE)) + +/* Output various types of constants. For real numbers we output hex, with + a comment containing the "human" value, this allows us to pass NaN's which + the riscix assembler doesn't understand (it also makes cross-assembling + less likely to fail). */ + +#define ASM_OUTPUT_LONG_DOUBLE(STREAM,VALUE) \ +do { char dstr[30]; \ + long l[3]; \ + /* CYGNUS LOCAL */ \ + arm_increase_location (12); \ + /* END CYGNUS LOCAL */ \ + REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ + fprintf (STREAM, "\t.long 0x%lx,0x%lx,0x%lx\t%s long double %s\n", \ + l[0], l[1], l[2], ASM_COMMENT_START, dstr); \ + } while (0) + + +#define ASM_OUTPUT_DOUBLE(STREAM, VALUE) \ +do { char dstr[30]; \ + long l[2]; \ + /* CYGNUS LOCAL */ \ + arm_increase_location (8); \ + /* END CYGNUS LOCAL */ \ + REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.14g", dstr); \ + fprintf (STREAM, "\t.long 0x%lx, 0x%lx\t%s double %s\n", l[0], \ + l[1], ASM_COMMENT_START, dstr); \ + } while (0) + +#define ASM_OUTPUT_FLOAT(STREAM, VALUE) \ +do { char dstr[30]; \ + long l; \ + /* CYGNUS LOCAL */ \ + arm_increase_location (4); \ + /* END CYGNUS LOCAL */ \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.7g", dstr); \ + fprintf (STREAM, "\t.word 0x%lx\t%s float %s\n", l, \ + ASM_COMMENT_START, dstr); \ + } while (0); + +#define ASM_OUTPUT_INT(STREAM, EXP) \ + { \ + fprintf (STREAM, "\t.word\t"); \ + OUTPUT_INT_ADDR_CONST (STREAM, (EXP)); \ + /* CYGNUS LOCAL */ \ + arm_increase_location (4), \ + /* END CYGNUS LOCAL */ \ + fputc ('\n', STREAM); \ + } + +#define ASM_OUTPUT_SHORT(STREAM, EXP) \ + (fprintf (STREAM, "\t.short\t"), \ + output_addr_const (STREAM, (EXP)), \ + /* CYGNUS LOCAL */ \ + arm_increase_location (2), \ + /* END CYGNUS LOCAL */ \ + fputc ('\n', STREAM)) + +#define ASM_OUTPUT_CHAR(STREAM, EXP) \ + (fprintf (STREAM, "\t.byte\t"), \ + output_addr_const (STREAM, (EXP)), \ + /* CYGNUS LOCAL */ \ + arm_increase_location (1), \ + /* END CYGNUS LOCAL */ \ + fputc ('\n', STREAM)) + +#define ASM_OUTPUT_BYTE(STREAM, VALUE) \ + /* CYGNUS LOCAL */ \ + (fprintf (STREAM, "\t.byte\t%d\n", VALUE), \ + arm_increase_location (1)) + /* END CYGNUS LOCAL */ + +#define ASM_OUTPUT_ASCII(STREAM, PTR, LEN) \ + output_ascii_pseudo_op ((STREAM), (unsigned char *)(PTR), (LEN)) + +/* Output a gap. In fact we fill it with nulls. */ +#define ASM_OUTPUT_SKIP(STREAM, NBYTES) \ + /* CYGNUS LOCAL */ \ + (arm_increase_location (NBYTES), \ + fprintf (STREAM, "\t.space\t%d\n", NBYTES)) \ + /* END CYGNUS LOCAL */ + +/* Align output to a power of two. Horrible /bin/as. */ +#define ASM_OUTPUT_ALIGN(STREAM, POWER) \ + do \ + { \ + register int amount = 1 << (POWER); \ + /* CYGNUS LOCAL */ \ + extern int arm_text_location; \ + /* END CYGNUS LOCAL */ \ + \ + if (amount == 2) \ + fprintf (STREAM, "\t.even\n"); \ + else if (amount != 1) \ + fprintf (STREAM, "\t.align\t%d\n", amount - 4); \ + \ + /* CYGNUS LOCAL */ \ + if (in_text_section ()) \ + arm_text_location = ((arm_text_location + amount - 1) \ + & ~(amount - 1)); \ + /* END CYGNUS LOCAL */ \ + } while (0) + +/* Output a common block */ +#ifndef ASM_OUTPUT_COMMON +#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ + (fprintf (STREAM, "\t.comm\t"), \ + assemble_name ((STREAM), (NAME)), \ + fprintf (STREAM, ", %d\t%s %d\n", ROUNDED, ASM_COMMENT_START, SIZE)) +#endif + +/* Output a local common block. /bin/as can't do this, so hack a + `.space' into the bss segment. Note that this is *bad* practice, + which is guaranteed NOT to work since it doesn't define STATIC + COMMON space but merely STATIC BSS space. */ +#ifndef ASM_OUTPUT_ALIGNED_LOCAL +#define ASM_OUTPUT_ALIGNED_LOCAL(STREAM,NAME,SIZE,ALIGN) \ + do { \ + bss_section (); \ + ASM_OUTPUT_ALIGN (STREAM, floor_log2 (ALIGN / BITS_PER_UNIT)); \ + ASM_OUTPUT_LABEL (STREAM, NAME); \ + fprintf (STREAM, "\t.space\t%d\n", SIZE); \ + } while (0) +#endif + +/* Output a zero-initialized block. */ +#ifndef ASM_OUTPUT_ALIGNED_BSS +#define ASM_OUTPUT_ALIGNED_BSS(STREAM,DECL,NAME,SIZE,ALIGN) \ + asm_output_aligned_bss (STREAM, DECL, NAME, SIZE, ALIGN) +#endif + +/* Output a source line for the debugger. */ +/* #define ASM_OUTPUT_SOURCE_LINE(STREAM,LINE) */ + +/* Output a #ident directive. */ +#ifndef ASM_OUTPUT_IDENT +#define ASM_OUTPUT_IDENT(STREAM,STRING) \ + fprintf (STREAM, "%s - - - ident %s\n", ASM_COMMENT_START, STRING) +#endif + +/* The assembler's parentheses characters. */ +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + +#ifndef ASM_COMMENT_START +#define ASM_COMMENT_START "@" +#endif + +/* This works for GAS and some other assemblers. */ +#define SET_ASM_OP ".set" + +#include "arm/arm.h" diff --git a/gcc_arm/config/arm/arm.c b/gcc_arm/config/arm/arm.c new file mode 100755 index 0000000..06d942a --- /dev/null +++ b/gcc_arm/config/arm/arm.c @@ -0,0 +1,7001 @@ +/* Output routines for GCC for ARM. + Copyright (C) 1991, 93, 94, 95, 96, 97, 98, 1999 Free Software Foundation, Inc. + Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl) + and Martin Simmons (@harleqn.co.uk). + More major hacks by Richard Earnshaw (rearnsha@arm.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "real.h" +#include "insn-config.h" +#include "conditions.h" +#include "insn-flags.h" +#include "output.h" +#include "insn-attr.h" +#include "flags.h" +#include "reload.h" +#include "tree.h" +#include "expr.h" +#include "toplev.h" + +/* The maximum number of insns skipped which will be conditionalised if + possible. */ +static int max_insns_skipped = 5; + +extern FILE *asm_out_file; +/* Some function declarations. */ + +/* CYGNUS LOCAL */ +void arm_increase_location PROTO ((int)); +static int get_prologue_size PROTO ((void)); +/* END CYGNUS LOCAL */ + +static HOST_WIDE_INT int_log2 PROTO ((HOST_WIDE_INT)); +static char *output_multi_immediate PROTO ((rtx *, char *, char *, int, + HOST_WIDE_INT)); +static int arm_gen_constant PROTO ((enum rtx_code, enum machine_mode, + HOST_WIDE_INT, rtx, rtx, int, int)); +static int arm_naked_function_p PROTO ((tree)); +static void init_fpa_table PROTO ((void)); +static enum machine_mode select_dominance_cc_mode PROTO ((enum rtx_code, rtx, + rtx, HOST_WIDE_INT)); +static HOST_WIDE_INT add_constant PROTO ((rtx, enum machine_mode, int *)); +static void dump_table PROTO ((rtx)); +static int fixit PROTO ((rtx, enum machine_mode, int)); +static rtx find_barrier PROTO ((rtx, int)); +static int broken_move PROTO ((rtx)); +static char *fp_const_from_val PROTO ((REAL_VALUE_TYPE *)); +static int eliminate_lr2ip PROTO ((rtx *)); +static char *shift_op PROTO ((rtx, HOST_WIDE_INT *)); +static int pattern_really_clobbers_lr PROTO ((rtx)); +static int function_really_clobbers_lr PROTO ((rtx)); +static void emit_multi_reg_push PROTO ((int)); +static void emit_sfm PROTO ((int, int)); +static enum arm_cond_code get_arm_condition_code PROTO ((rtx)); + +/* Define the information needed to generate branch insns. This is + stored from the compare operation. */ + +rtx arm_compare_op0, arm_compare_op1; +int arm_compare_fp; + +/* CYGNUS LOCAL: Definition of arm_cpu deleted. */ + +/* What type of floating point are we tuning for? */ +enum floating_point_type arm_fpu; + +/* What type of floating point instructions are available? */ +enum floating_point_type arm_fpu_arch; + +/* What program mode is the cpu running in? 26-bit mode or 32-bit mode */ +enum prog_mode_type arm_prgmode; + +/* CYGNUS LOCAL: Name changed to fpe. */ +/* Set by the -mfpe=... option */ +char *target_fpe_name = NULL; +/* END CYGNUS LOCAL */ + +/* Used to parse -mstructure_size_boundary command line option. */ +char * structure_size_string = NULL; +int arm_structure_size_boundary = 32; /* Used to be 8 */ + +/* Bit values used to identify processor capabilities. */ +#define FL_CO_PROC 0x01 /* Has external co-processor bus */ +#define FL_FAST_MULT 0x02 /* Fast multiply */ +#define FL_MODE26 0x04 /* 26-bit mode support */ +#define FL_MODE32 0x08 /* 32-bit mode support */ +#define FL_ARCH4 0x10 /* Architecture rel 4 */ +#define FL_THUMB 0x20 /* Thumb aware */ +#define FL_LDSCHED 0x40 /* Load scheduling necessary */ +#define FL_STRONG 0x80 /* StrongARM */ + +/* The bits in this mask specify which instructions we are allowed to generate. */ +static int insn_flags = 0; +/* The bits in this mask specify which instruction scheduling options should + be used. Note - there is an overlap with the FL_FAST_MULT. For some + hardware we want to be able to generate the multiply instructions, but to + tune as if they were not present in the architecture. */ +static int tune_flags = 0; + +/* The following are used in the arm.md file as equivalents to bits + in the above two flag variables. */ + +/* Nonzero if this is an "M" variant of the processor. */ +int arm_fast_multiply = 0; + +/* Nonzero if this chip supports the ARM Architecture 4 extensions */ +int arm_arch4 = 0; + +/* Nonzero if this chip can benefit from load scheduling. */ +int arm_ld_sched = 0; + +/* Nonzero if this chip is a StrongARM. */ +int arm_is_strong = 0; + +/* Nonzero if this chip is a an ARM6 or an ARM7. */ +int arm_is_6_or_7 = 0; + +/* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, we + must report the mode of the memory reference from PRINT_OPERAND to + PRINT_OPERAND_ADDRESS. */ +enum machine_mode output_memory_reference_mode; + +/* Nonzero if the prologue must setup `fp'. */ +int current_function_anonymous_args; + +/* The register number to be used for the PIC offset register. */ +int arm_pic_register = 9; + +/* Location counter of .text segment. */ +int arm_text_location = 0; + +/* Set to one if we think that lr is only saved because of subroutine calls, + but all of these can be `put after' return insns */ +int lr_save_eliminated; + +/* Set to 1 when a return insn is output, this means that the epilogue + is not needed. */ + +static int return_used_this_function; + +/* Set to 1 after arm_reorg has started. Reset to start at the start of + the next function. */ +static int after_arm_reorg = 0; + +/* The maximum number of insns to be used when loading a constant. */ +static int arm_constant_limit = 3; + +/* CYGNUS LOCAL unknown */ +/* A hash table is used to store text segment labels and their associated + offset from the start of the text segment. */ +struct label_offset +{ + char * name; + int offset; + struct label_offset * cdr; +}; + +#define LABEL_HASH_SIZE 257 + +static struct label_offset * offset_table [LABEL_HASH_SIZE]; +/* END CYGNUS LOCAL */ + +/* For an explanation of these variables, see final_prescan_insn below. */ +int arm_ccfsm_state; +enum arm_cond_code arm_current_cc; +rtx arm_target_insn; +int arm_target_label; + +/* The condition codes of the ARM, and the inverse function. */ +char *arm_condition_codes[] = +{ + "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", + "hi", "ls", "ge", "lt", "gt", "le", "al", "nv" +}; + +static enum arm_cond_code get_arm_condition_code (); + + +/* Initialization code */ + +struct processors +{ + char * name; + unsigned int flags; +}; + +/* Not all of these give usefully different compilation alternatives, + but there is no simple way of generalizing them. */ +static struct processors all_cores[] = +{ + /* ARM Cores */ + + {"arm2", FL_CO_PROC | FL_MODE26 }, + {"arm250", FL_CO_PROC | FL_MODE26 }, + {"arm3", FL_CO_PROC | FL_MODE26 }, + {"arm6", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, + {"arm60", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, + {"arm600", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, + {"arm610", FL_MODE26 | FL_MODE32 }, + {"arm620", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, + {"arm7", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, + {"arm7m", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT }, /* arm7m doesn't exist on its own, */ + {"arm7d", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, /* but only with D, (and I), */ + {"arm7dm", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT }, /* but those don't alter the code, */ + {"arm7di", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, /* so arm7m is sometimes used. */ + {"arm7dmi", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT }, + {"arm70", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, + {"arm700", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, + {"arm700i", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, + {"arm710", FL_MODE26 | FL_MODE32 }, + {"arm710c", FL_MODE26 | FL_MODE32 }, + {"arm7100", FL_MODE26 | FL_MODE32 }, + {"arm7500", FL_MODE26 | FL_MODE32 }, + {"arm7500fe", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, /* Doesn't really have an external co-proc, but does have embedded fpu. */ + {"arm7tdmi", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB }, + {"arm8", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED }, + {"arm810", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED }, + {"arm9", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED }, + {"arm920", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED }, + {"arm920t", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED }, + {"arm9tdmi", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED }, + {"strongarm", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_STRONG }, + {"strongarm110", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_STRONG }, + {"strongarm1100", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_STRONG }, + + {NULL, 0} +}; + +static struct processors all_architectures[] = +{ + /* ARM Architectures */ + + {"armv2", FL_CO_PROC | FL_MODE26 }, + {"armv2a", FL_CO_PROC | FL_MODE26 }, + {"armv3", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, + {"armv3m", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT }, + {"armv4", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 }, + /* Strictly, FL_MODE26 is a permitted option for v4t, but there are no + implementations that support it, so we will leave it out for now. */ + {"armv4t", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB }, + {NULL, 0} +}; + +/* This is a magic stucture. The 'string' field is magically filled in + with a pointer to the value specified by the user on the command line + assuming that the user has specified such a value. */ + +struct arm_cpu_select arm_select[] = +{ + /* string name processors */ + { NULL, "-mcpu=", all_cores }, + { NULL, "-march=", all_architectures }, + { NULL, "-mtune=", all_cores } +}; + +/* Return the number of bits set in value' */ +static unsigned int +bit_count (value) + signed int value; +{ + unsigned int count = 0; + + while (value) + { + value &= ~(value & - value); + ++ count; + } + + return count; +} + +/* Fix up any incompatible options that the user has specified. + This has now turned into a maze. */ +void +arm_override_options () +{ + unsigned i; + + /* Set up the flags based on the cpu/architecture selected by the user. */ + for (i = sizeof (arm_select) / sizeof (arm_select[0]); i--;) + { + struct arm_cpu_select * ptr = arm_select + i; + + if (ptr->string != NULL && ptr->string[0] != '\0') + { + const struct processors * sel; + + for (sel = ptr->processors; sel->name != NULL; sel ++) + if (! strcmp (ptr->string, sel->name)) + { + if (i == 2) + tune_flags = sel->flags; + else + { + /* If we have been given an architecture and a processor + make sure that they are compatible. We only generate + a warning though, and we prefer the CPU over the + architecture. */ + if (insn_flags != 0 && (insn_flags ^ sel->flags)) + warning ("switch -mcpu=%s conflicts with -march= switch", + ptr->string); + + insn_flags = sel->flags; + } + + break; + } + + if (sel->name == NULL) + error ("bad value (%s) for %s switch", ptr->string, ptr->name); + } + } + + /* If the user did not specify a processor, choose one for them. */ + if (insn_flags == 0) + { + struct processors * sel; + unsigned int sought; + static struct cpu_default + { + int cpu; + char * name; + } + cpu_defaults[] = + { + { TARGET_CPU_arm2, "arm2" }, + { TARGET_CPU_arm6, "arm6" }, + { TARGET_CPU_arm610, "arm610" }, + { TARGET_CPU_arm710, "arm710" }, + { TARGET_CPU_arm7m, "arm7m" }, + { TARGET_CPU_arm7500fe, "arm7500fe" }, + { TARGET_CPU_arm7tdmi, "arm7tdmi" }, + { TARGET_CPU_arm8, "arm8" }, + { TARGET_CPU_arm810, "arm810" }, + { TARGET_CPU_arm9, "arm9" }, + { TARGET_CPU_strongarm, "strongarm" }, + { TARGET_CPU_generic, "arm" }, + { 0, 0 } + }; + struct cpu_default * def; + + /* Find the default. */ + for (def = cpu_defaults; def->name; def ++) + if (def->cpu == TARGET_CPU_DEFAULT) + break; + + /* Make sure we found the default CPU. */ + if (def->name == NULL) + abort (); + + /* Find the default CPU's flags. */ + for (sel = all_cores; sel->name != NULL; sel ++) + if (! strcmp (def->name, sel->name)) + break; + + if (sel->name == NULL) + abort (); + + insn_flags = sel->flags; + + /* Now check to see if the user has specified some command line + switch that require certain abilities from the cpu. */ + sought = 0; + + if (TARGET_THUMB_INTERWORK) + { + sought |= (FL_THUMB | FL_MODE32); + + /* Force apcs-32 to be used for interworking. */ + target_flags |= ARM_FLAG_APCS_32; + + /* There are no ARM processor that supports both APCS-26 and + interworking. Therefore we force FL_MODE26 to be removed + from insn_flags here (if it was set), so that the search + below will always be able to find a compatible processor. */ + insn_flags &= ~ FL_MODE26; + } + + if (! TARGET_APCS_32) + sought |= FL_MODE26; + + if (sought != 0 && ((sought & insn_flags) != sought)) + { + /* Try to locate a CPU type that supports all of the abilities + of the default CPU, plus the extra abilities requested by + the user. */ + for (sel = all_cores; sel->name != NULL; sel ++) + if ((sel->flags & sought) == (sought | insn_flags)) + break; + + if (sel->name == NULL) + { + unsigned int current_bit_count = 0; + struct processors * best_fit = NULL; + + /* Ideally we would like to issue an error message here + saying that it was not possible to find a CPU compatible + with the default CPU, but which also supports the command + line options specified by the programmer, and so they + ought to use the -mcpu= command line option to + override the default CPU type. + + Unfortunately this does not work with multilibing. We + need to be able to support multilibs for -mapcs-26 and for + -mthumb-interwork and there is no CPU that can support both + options. Instead if we cannot find a cpu that has both the + characteristics of the default cpu and the given command line + options we scan the array again looking for a best match. */ + for (sel = all_cores; sel->name != NULL; sel ++) + if ((sel->flags & sought) == sought) + { + unsigned int count; + + count = bit_count (sel->flags & insn_flags); + + if (count >= current_bit_count) + { + best_fit = sel; + current_bit_count = count; + } + } + + if (best_fit == NULL) + abort (); + else + sel = best_fit; + } + + insn_flags = sel->flags; + } + } + + /* If tuning has not been specified, tune for whichever processor or + architecture has been selected. */ + if (tune_flags == 0) + tune_flags = insn_flags; + + /* Make sure that the processor choice does not conflict with any of the + other command line choices. */ + if (TARGET_APCS_32 && !(insn_flags & FL_MODE32)) + { + /* If APCS-32 was not the default then it must have been set by the + user, so issue a warning message. If the user has specified + "-mapcs-32 -mcpu=arm2" then we loose here. */ + if ((TARGET_DEFAULT & ARM_FLAG_APCS_32) == 0) + warning ("target CPU does not support APCS-32" ); + target_flags &= ~ ARM_FLAG_APCS_32; + } + else if (! TARGET_APCS_32 && !(insn_flags & FL_MODE26)) + { + warning ("target CPU does not support APCS-26" ); + target_flags |= ARM_FLAG_APCS_32; + } + + if (TARGET_THUMB_INTERWORK && !(insn_flags & FL_THUMB)) + { + warning ("target CPU does not support interworking" ); + target_flags &= ~ARM_FLAG_THUMB; + } + + /* If interworking is enabled then APCS-32 must be selected as well. */ + if (TARGET_THUMB_INTERWORK) + { + if (! TARGET_APCS_32) + warning ("interworking forces APCS-32 to be used" ); + target_flags |= ARM_FLAG_APCS_32; + } + + if (TARGET_APCS_STACK && ! TARGET_APCS) + { + warning ("-mapcs-stack-check incompatible with -mno-apcs-frame"); + target_flags |= ARM_FLAG_APCS_FRAME; + } + + if (write_symbols != NO_DEBUG && flag_omit_frame_pointer) + warning ("-g with -fomit-frame-pointer may not give sensible debugging"); + + if (TARGET_POKE_FUNCTION_NAME) + target_flags |= ARM_FLAG_APCS_FRAME; + + if (TARGET_APCS_REENT && flag_pic) + fatal ("-fpic and -mapcs-reent are incompatible"); + + if (TARGET_APCS_REENT) + warning ("APCS reentrant code not supported. Ignored"); + + /* If stack checking is disabled, we can use r10 as the PIC register, + which keeps r9 available. */ + if (flag_pic && ! TARGET_APCS_STACK) + arm_pic_register = 10; + + /* Well, I'm about to have a go, but pic is NOT going to be compatible + with APCS reentrancy, since that requires too much support in the + assembler and linker, and the ARMASM assembler seems to lack some + required directives. */ + if (flag_pic) + warning ("Position independent code not supported"); + + if (TARGET_APCS_FLOAT) + warning ("Passing floating point arguments in fp regs not yet supported"); + + /* Initialise boolean versions of the flags, for use in the arm.md file. */ + arm_fast_multiply = insn_flags & FL_FAST_MULT; + arm_arch4 = insn_flags & FL_ARCH4; + + arm_ld_sched = tune_flags & FL_LDSCHED; + arm_is_strong = tune_flags & FL_STRONG; + arm_is_6_or_7 = ((tune_flags & (FL_MODE26 | FL_MODE32)) + && !(tune_flags & FL_ARCH4)); + + /* Default value for floating point code... if no co-processor + bus, then schedule for emulated floating point. Otherwise, + assume the user has an FPA. + Note: this does not prevent use of floating point instructions, + -msoft-float does that. */ + arm_fpu = (tune_flags & FL_CO_PROC) ? FP_HARD : FP_SOFT3; + + if (target_fpe_name) + { + if (! strcmp (target_fpe_name, "2")) + arm_fpu_arch = FP_SOFT2; + else if (! strcmp (target_fpe_name, "3")) + arm_fpu_arch = FP_SOFT3; + else + fatal ("Invalid floating point emulation option: -mfpe-%s", + target_fpe_name); + } + else + arm_fpu_arch = FP_DEFAULT; + + if (TARGET_FPE && arm_fpu != FP_HARD) + arm_fpu = FP_SOFT2; + + /* For arm2/3 there is no need to do any scheduling if there is only + a floating point emulator, or we are doing software floating-point. */ + if ((TARGET_SOFT_FLOAT || arm_fpu != FP_HARD) && (tune_flags & FL_MODE32) == 0) + flag_schedule_insns = flag_schedule_insns_after_reload = 0; + + arm_prog_mode = TARGET_APCS_32 ? PROG_MODE_PROG32 : PROG_MODE_PROG26; + + if (structure_size_string != NULL) + { + int size = strtol (structure_size_string, NULL, 0); + + if (size == 8 || size == 32) + arm_structure_size_boundary = size; + else + warning ("Structure size boundary can only be set to 8 or 32"); + } + + /* If optimizing for space, don't synthesize constants. + For processors with load scheduling, it never costs more than 2 cycles + to load a constant, and the load scheduler may well reduce that to 1. */ + if (optimize_size || (tune_flags & FL_LDSCHED)) + arm_constant_limit = 1; + + /* If optimizing for size, bump the number of instructions that we + are prepared to conditionally execute (even on a StrongARM). + Otherwise for the StrongARM, which has early execution of branches, + a sequence that is worth skipping is shorter. */ + if (optimize_size) + max_insns_skipped = 6; + else if (arm_is_strong) + max_insns_skipped = 3; +} + + +/* Return 1 if it is possible to return using a single instruction */ + +int +use_return_insn (iscond) + int iscond; +{ + int regno; + + if (!reload_completed ||current_function_pretend_args_size + || current_function_anonymous_args + || ((get_frame_size () + current_function_outgoing_args_size != 0) + /* CYGNUS LOCAL nickc */ + && !(TARGET_APCS && frame_pointer_needed))) + /* END CYGNUS LOCAL */ + return 0; + + /* Can't be done if interworking with Thumb, and any registers have been + stacked. Similarly, on StrongARM, conditional returns are expensive + if they aren't taken and registers have been stacked. */ + if (iscond && arm_is_strong && frame_pointer_needed) + return 0; + if ((iscond && arm_is_strong) + || TARGET_THUMB_INTERWORK) + for (regno = 0; regno < 16; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + return 0; + + /* Can't be done if any of the FPU regs are pushed, since this also + requires an insn */ + for (regno = 16; regno < 24; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + return 0; + + /* If a function is naked, don't use the "return" insn. */ + if (arm_naked_function_p (current_function_decl)) + return 0; + + return 1; +} + +/* Return TRUE if int I is a valid immediate ARM constant. */ + +int +const_ok_for_arm (i) + HOST_WIDE_INT i; +{ + unsigned HOST_WIDE_INT mask = ~(unsigned HOST_WIDE_INT)0xFF; + + /* For machines with >32 bit HOST_WIDE_INT, the bits above bit 31 must + be all zero, or all one. */ + if ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff) != 0 + && ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff) + != ((~(unsigned HOST_WIDE_INT) 0) + & ~(unsigned HOST_WIDE_INT) 0xffffffff))) + return FALSE; + + /* Fast return for 0 and powers of 2 */ + if ((i & (i - 1)) == 0) + return TRUE; + + do + { + if ((i & mask & (unsigned HOST_WIDE_INT) 0xffffffff) == 0) + return TRUE; + mask = + (mask << 2) | ((mask & (unsigned HOST_WIDE_INT) 0xffffffff) + >> (32 - 2)) | ~((unsigned HOST_WIDE_INT) 0xffffffff); + } while (mask != ~(unsigned HOST_WIDE_INT) 0xFF); + + return FALSE; +} + +/* Return true if I is a valid constant for the operation CODE. */ +int +const_ok_for_op (i, code, mode) + HOST_WIDE_INT i; + enum rtx_code code; + enum machine_mode mode; +{ + if (const_ok_for_arm (i)) + return 1; + + switch (code) + { + case PLUS: + return const_ok_for_arm (ARM_SIGN_EXTEND (-i)); + + case MINUS: /* Should only occur with (MINUS I reg) => rsb */ + case XOR: + case IOR: + return 0; + + case AND: + return const_ok_for_arm (ARM_SIGN_EXTEND (~i)); + + default: + abort (); + } +} + +/* Emit a sequence of insns to handle a large constant. + CODE is the code of the operation required, it can be any of SET, PLUS, + IOR, AND, XOR, MINUS; + MODE is the mode in which the operation is being performed; + VAL is the integer to operate on; + SOURCE is the other operand (a register, or a null-pointer for SET); + SUBTARGETS means it is safe to create scratch registers if that will + either produce a simpler sequence, or we will want to cse the values. + Return value is the number of insns emitted. */ + +int +arm_split_constant (code, mode, val, target, source, subtargets) + enum rtx_code code; + enum machine_mode mode; + HOST_WIDE_INT val; + rtx target; + rtx source; + int subtargets; +{ + if (subtargets || code == SET + || (GET_CODE (target) == REG && GET_CODE (source) == REG + && REGNO (target) != REGNO (source))) + { + /* After arm_reorg has been called, we can't fix up expensive + constants by pushing them into memory so we must synthesise + them in-line, regardless of the cost. This is only likely to + be more costly on chips that have load delay slots and we are + compiling without running the scheduler (so no splitting + occurred before the final instruction emission). + + Ref: gcc -O1 -mcpu=strongarm gcc.c-torture/compile/980506-2.c + */ /* CYGNUS LOCAL nickc/strongarm */ + if ((! after_arm_reorg || optimize == 0) + /* END CYGNUS LOCAL */ + && (arm_gen_constant (code, mode, val, target, source, 1, 0) + > arm_constant_limit + (code != SET))) + { + if (code == SET) + { + /* Currently SET is the only monadic value for CODE, all + the rest are diadic. */ + emit_insn (gen_rtx (SET, VOIDmode, target, GEN_INT (val))); + return 1; + } + else + { + rtx temp = subtargets ? gen_reg_rtx (mode) : target; + + emit_insn (gen_rtx (SET, VOIDmode, temp, GEN_INT (val))); + /* For MINUS, the value is subtracted from, since we never + have subtraction of a constant. */ + if (code == MINUS) + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (code, mode, temp, source))); + else + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (code, mode, source, temp))); + return 2; + } + } + } + + return arm_gen_constant (code, mode, val, target, source, subtargets, 1); +} + +/* As above, but extra parameter GENERATE which, if clear, suppresses + RTL generation. */ +int +arm_gen_constant (code, mode, val, target, source, subtargets, generate) + enum rtx_code code; + enum machine_mode mode; + HOST_WIDE_INT val; + rtx target; + rtx source; + int subtargets; + int generate; +{ + int can_invert = 0; + int can_negate = 0; + int can_negate_initial = 0; + int can_shift = 0; + int i; + int num_bits_set = 0; + int set_sign_bit_copies = 0; + int clear_sign_bit_copies = 0; + int clear_zero_bit_copies = 0; + int set_zero_bit_copies = 0; + int insns = 0; + unsigned HOST_WIDE_INT temp1, temp2; + unsigned HOST_WIDE_INT remainder = val & 0xffffffff; + + /* find out which operations are safe for a given CODE. Also do a quick + check for degenerate cases; these can occur when DImode operations + are split. */ + switch (code) + { + case SET: + can_invert = 1; + can_shift = 1; + can_negate = 1; + break; + + case PLUS: + can_negate = 1; + can_negate_initial = 1; + break; + + case IOR: + if (remainder == 0xffffffff) + { + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, + GEN_INT (ARM_SIGN_EXTEND (val)))); + return 1; + } + if (remainder == 0) + { + if (reload_completed && rtx_equal_p (target, source)) + return 0; + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, source)); + return 1; + } + break; + + case AND: + if (remainder == 0) + { + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, const0_rtx)); + return 1; + } + if (remainder == 0xffffffff) + { + if (reload_completed && rtx_equal_p (target, source)) + return 0; + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, source)); + return 1; + } + can_invert = 1; + break; + + case XOR: + if (remainder == 0) + { + if (reload_completed && rtx_equal_p (target, source)) + return 0; + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, source)); + return 1; + } + if (remainder == 0xffffffff) + { + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (NOT, mode, source))); + return 1; + } + + /* We don't know how to handle this yet below. */ + abort (); + + case MINUS: + /* We treat MINUS as (val - source), since (source - val) is always + passed as (source + (-val)). */ + if (remainder == 0) + { + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (NEG, mode, source))); + return 1; + } + if (const_ok_for_arm (val)) + { + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (MINUS, mode, GEN_INT (val), source))); + return 1; + } + can_negate = 1; + + break; + + default: + abort (); + } + + /* If we can do it in one insn get out quickly */ + if (const_ok_for_arm (val) + || (can_negate_initial && const_ok_for_arm (-val)) + || (can_invert && const_ok_for_arm (~val))) + { + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, + (source ? gen_rtx (code, mode, source, + GEN_INT (val)) + : GEN_INT (val)))); + return 1; + } + + + /* Calculate a few attributes that may be useful for specific + optimizations. */ + + for (i = 31; i >= 0; i--) + { + if ((remainder & (1 << i)) == 0) + clear_sign_bit_copies++; + else + break; + } + + for (i = 31; i >= 0; i--) + { + if ((remainder & (1 << i)) != 0) + set_sign_bit_copies++; + else + break; + } + + for (i = 0; i <= 31; i++) + { + if ((remainder & (1 << i)) == 0) + clear_zero_bit_copies++; + else + break; + } + + for (i = 0; i <= 31; i++) + { + if ((remainder & (1 << i)) != 0) + set_zero_bit_copies++; + else + break; + } + + switch (code) + { + case SET: + /* See if we can do this by sign_extending a constant that is known + to be negative. This is a good, way of doing it, since the shift + may well merge into a subsequent insn. */ + if (set_sign_bit_copies > 1) + { + if (const_ok_for_arm + (temp1 = ARM_SIGN_EXTEND (remainder + << (set_sign_bit_copies - 1)))) + { + if (generate) + { + rtx new_src = subtargets ? gen_reg_rtx (mode) : target; + emit_insn (gen_rtx (SET, VOIDmode, new_src, + GEN_INT (temp1))); + emit_insn (gen_ashrsi3 (target, new_src, + GEN_INT (set_sign_bit_copies - 1))); + } + return 2; + } + /* For an inverted constant, we will need to set the low bits, + these will be shifted out of harm's way. */ + temp1 |= (1 << (set_sign_bit_copies - 1)) - 1; + if (const_ok_for_arm (~temp1)) + { + if (generate) + { + rtx new_src = subtargets ? gen_reg_rtx (mode) : target; + emit_insn (gen_rtx (SET, VOIDmode, new_src, + GEN_INT (temp1))); + emit_insn (gen_ashrsi3 (target, new_src, + GEN_INT (set_sign_bit_copies - 1))); + } + return 2; + } + } + + /* See if we can generate this by setting the bottom (or the top) + 16 bits, and then shifting these into the other half of the + word. We only look for the simplest cases, to do more would cost + too much. Be careful, however, not to generate this when the + alternative would take fewer insns. */ + if (val & 0xffff0000) + { + temp1 = remainder & 0xffff0000; + temp2 = remainder & 0x0000ffff; + + /* Overlaps outside this range are best done using other methods. */ + for (i = 9; i < 24; i++) + { + if ((((temp2 | (temp2 << i)) & 0xffffffff) == remainder) + && ! const_ok_for_arm (temp2)) + { + rtx new_src = (subtargets + ? (generate ? gen_reg_rtx (mode) : NULL_RTX) + : target); + insns = arm_gen_constant (code, mode, temp2, new_src, + source, subtargets, generate); + source = new_src; + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (IOR, mode, + gen_rtx (ASHIFT, mode, source, + GEN_INT (i)), + source))); + return insns + 1; + } + } + + /* Don't duplicate cases already considered. */ + for (i = 17; i < 24; i++) + { + if (((temp1 | (temp1 >> i)) == remainder) + && ! const_ok_for_arm (temp1)) + { + rtx new_src = (subtargets + ? (generate ? gen_reg_rtx (mode) : NULL_RTX) + : target); + insns = arm_gen_constant (code, mode, temp1, new_src, + source, subtargets, generate); + source = new_src; + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (IOR, mode, + gen_rtx (LSHIFTRT, mode, + source, GEN_INT (i)), + source))); + return insns + 1; + } + } + } + break; + + case IOR: + case XOR: + /* If we have IOR or XOR, and the constant can be loaded in a + single instruction, and we can find a temporary to put it in, + then this can be done in two instructions instead of 3-4. */ + if (subtargets + /* TARGET can't be NULL if SUBTARGETS is 0 */ + || (reload_completed && ! reg_mentioned_p (target, source))) + { + if (const_ok_for_arm (ARM_SIGN_EXTEND (~ val))) + { + if (generate) + { + rtx sub = subtargets ? gen_reg_rtx (mode) : target; + + emit_insn (gen_rtx (SET, VOIDmode, sub, GEN_INT (val))); + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (code, mode, source, sub))); + } + return 2; + } + } + + if (code == XOR) + break; + + if (set_sign_bit_copies > 8 + && (val & (-1 << (32 - set_sign_bit_copies))) == val) + { + if (generate) + { + rtx sub = subtargets ? gen_reg_rtx (mode) : target; + rtx shift = GEN_INT (set_sign_bit_copies); + + emit_insn (gen_rtx (SET, VOIDmode, sub, + gen_rtx (NOT, mode, + gen_rtx (ASHIFT, mode, source, + shift)))); + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (NOT, mode, + gen_rtx (LSHIFTRT, mode, sub, + shift)))); + } + return 2; + } + + if (set_zero_bit_copies > 8 + && (remainder & ((1 << set_zero_bit_copies) - 1)) == remainder) + { + if (generate) + { + rtx sub = subtargets ? gen_reg_rtx (mode) : target; + rtx shift = GEN_INT (set_zero_bit_copies); + + emit_insn (gen_rtx (SET, VOIDmode, sub, + gen_rtx (NOT, mode, + gen_rtx (LSHIFTRT, mode, source, + shift)))); + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (NOT, mode, + gen_rtx (ASHIFT, mode, sub, + shift)))); + } + return 2; + } + + if (const_ok_for_arm (temp1 = ARM_SIGN_EXTEND (~ val))) + { + if (generate) + { + rtx sub = subtargets ? gen_reg_rtx (mode) : target; + emit_insn (gen_rtx (SET, VOIDmode, sub, + gen_rtx (NOT, mode, source))); + source = sub; + if (subtargets) + sub = gen_reg_rtx (mode); + emit_insn (gen_rtx (SET, VOIDmode, sub, + gen_rtx (AND, mode, source, + GEN_INT (temp1)))); + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (NOT, mode, sub))); + } + return 3; + } + break; + + case AND: + /* See if two shifts will do 2 or more insn's worth of work. */ + if (clear_sign_bit_copies >= 16 && clear_sign_bit_copies < 24) + { + HOST_WIDE_INT shift_mask = ((0xffffffff + << (32 - clear_sign_bit_copies)) + & 0xffffffff); + + if ((remainder | shift_mask) != 0xffffffff) + { + if (generate) + { + rtx new_src = subtargets ? gen_reg_rtx (mode) : target; + insns = arm_gen_constant (AND, mode, remainder | shift_mask, + new_src, source, subtargets, 1); + source = new_src; + } + else + { + rtx targ = subtargets ? NULL_RTX : target; + insns = arm_gen_constant (AND, mode, remainder | shift_mask, + targ, source, subtargets, 0); + } + } + + if (generate) + { + rtx new_src = subtargets ? gen_reg_rtx (mode) : target; + rtx shift = GEN_INT (clear_sign_bit_copies); + + emit_insn (gen_ashlsi3 (new_src, source, shift)); + emit_insn (gen_lshrsi3 (target, new_src, shift)); + } + + return insns + 2; + } + + if (clear_zero_bit_copies >= 16 && clear_zero_bit_copies < 24) + { + HOST_WIDE_INT shift_mask = (1 << clear_zero_bit_copies) - 1; + + if ((remainder | shift_mask) != 0xffffffff) + { + if (generate) + { + rtx new_src = subtargets ? gen_reg_rtx (mode) : target; + + insns = arm_gen_constant (AND, mode, remainder | shift_mask, + new_src, source, subtargets, 1); + source = new_src; + } + else + { + rtx targ = subtargets ? NULL_RTX : target; + + insns = arm_gen_constant (AND, mode, remainder | shift_mask, + targ, source, subtargets, 0); + } + } + + if (generate) + { + rtx new_src = subtargets ? gen_reg_rtx (mode) : target; + rtx shift = GEN_INT (clear_zero_bit_copies); + + emit_insn (gen_lshrsi3 (new_src, source, shift)); + emit_insn (gen_ashlsi3 (target, new_src, shift)); + } + + return insns + 2; + } + + break; + + default: + break; + } + + for (i = 0; i < 32; i++) + if (remainder & (1 << i)) + num_bits_set++; + + if (code == AND || (can_invert && num_bits_set > 16)) + remainder = (~remainder) & 0xffffffff; + else if (code == PLUS && num_bits_set > 16) + remainder = (-remainder) & 0xffffffff; + else + { + can_invert = 0; + can_negate = 0; + } + + /* Now try and find a way of doing the job in either two or three + instructions. + We start by looking for the largest block of zeros that are aligned on + a 2-bit boundary, we then fill up the temps, wrapping around to the + top of the word when we drop off the bottom. + In the worst case this code should produce no more than four insns. */ + { + int best_start = 0; + int best_consecutive_zeros = 0; + + for (i = 0; i < 32; i += 2) + { + int consecutive_zeros = 0; + + if (! (remainder & (3 << i))) + { + while ((i < 32) && ! (remainder & (3 << i))) + { + consecutive_zeros += 2; + i += 2; + } + if (consecutive_zeros > best_consecutive_zeros) + { + best_consecutive_zeros = consecutive_zeros; + best_start = i - consecutive_zeros; + } + i -= 2; + } + } + + /* Now start emitting the insns, starting with the one with the highest + bit set: we do this so that the smallest number will be emitted last; + this is more likely to be combinable with addressing insns. */ + i = best_start; + do + { + int end; + + if (i <= 0) + i += 32; + if (remainder & (3 << (i - 2))) + { + end = i - 8; + if (end < 0) + end += 32; + temp1 = remainder & ((0x0ff << end) + | ((i < end) ? (0xff >> (32 - end)) : 0)); + remainder &= ~temp1; + + if (generate) + { + rtx new_src; + + if (code == SET) + emit_insn (gen_rtx (SET, VOIDmode, + new_src = (subtargets + ? gen_reg_rtx (mode) + : target), + GEN_INT (can_invert ? ~temp1 : temp1))); + else if (code == MINUS) + emit_insn (gen_rtx (SET, VOIDmode, + new_src = (subtargets + ? gen_reg_rtx (mode) + : target), + gen_rtx (code, mode, GEN_INT (temp1), + source))); + else + emit_insn (gen_rtx (SET, VOIDmode, + new_src = (remainder + ? (subtargets + ? gen_reg_rtx (mode) + : target) + : target), + gen_rtx (code, mode, source, + GEN_INT (can_invert ? ~temp1 + : (can_negate + ? -temp1 + : temp1))))); + source = new_src; + } + + if (code == SET) + { + can_invert = 0; + code = PLUS; + } + else if (code == MINUS) + code = PLUS; + + insns++; + i -= 6; + } + i -= 2; + } while (remainder); + } + return insns; +} + +/* Canonicalize a comparison so that we are more likely to recognize it. + This can be done for a few constant compares, where we can make the + immediate value easier to load. */ +enum rtx_code +arm_canonicalize_comparison (code, op1) + enum rtx_code code; + rtx *op1; +{ + unsigned HOST_WIDE_INT i = INTVAL (*op1); + + switch (code) + { + case EQ: + case NE: + return code; + + case GT: + case LE: + if (i != ((((unsigned HOST_WIDE_INT) 1) << (HOST_BITS_PER_WIDE_INT - 1)) + - 1) + && (const_ok_for_arm (i+1) || const_ok_for_arm (- (i+1)))) + { + *op1 = GEN_INT (i+1); + return code == GT ? GE : LT; + } + break; + + case GE: + case LT: + if (i != (((unsigned HOST_WIDE_INT) 1) << (HOST_BITS_PER_WIDE_INT - 1)) + && (const_ok_for_arm (i-1) || const_ok_for_arm (- (i-1)))) + { + *op1 = GEN_INT (i-1); + return code == GE ? GT : LE; + } + break; + + case GTU: + case LEU: + if (i != ~((unsigned HOST_WIDE_INT) 0) + && (const_ok_for_arm (i+1) || const_ok_for_arm (- (i+1)))) + { + *op1 = GEN_INT (i + 1); + return code == GTU ? GEU : LTU; + } + break; + + case GEU: + case LTU: + if (i != 0 + && (const_ok_for_arm (i - 1) || const_ok_for_arm (- (i - 1)))) + { + *op1 = GEN_INT (i - 1); + return code == GEU ? GTU : LEU; + } + break; + + default: + abort (); + } + + return code; +} + +/* CYGNSU LOCAL */ +/* Decide whether a type should be returned in memory (true) + or in a register (false). This is called by the macro + RETURN_IN_MEMORY. */ + +int +arm_return_in_memory (type) + tree type; +{ + if (! AGGREGATE_TYPE_P (type)) + { + /* All simple types are returned in registers. */ + + return 0; + } + else if (int_size_in_bytes (type) > 4) + { + /* All structures/unions bigger than one word are returned in memory. */ + + return 1; + } + else if (TREE_CODE (type) == RECORD_TYPE) + { + tree field; + + /* For a struct the APCS says that we must return in a register if + every addressable element has an offset of zero. For practical + purposes this means that the structure can have at most one non + bit-field element and that this element must be the first one in + the structure. */ + + /* Find the first field, ignoring non FIELD_DECL things which will + have been created by C++. */ + + for (field = TYPE_FIELDS (type); + field && TREE_CODE (field) != FIELD_DECL; + field = TREE_CHAIN (field)) + continue; + + if (field == NULL) + return 0; /* An empty structure. Allowed by an extension to ANSI C. */ + + /* Now check the remaining fields, if any. */ + for (field = TREE_CHAIN (field); + field; + field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + + if (! DECL_BIT_FIELD_TYPE (field)) + return 1; + } + + return 0; + } + else if (TREE_CODE (type) == UNION_TYPE) + { + tree field; + + /* Unions can be returned in registers if every element is + integral, or can be returned in an integer register. */ + + for (field = TYPE_FIELDS (type); + field; + field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + + if (FLOAT_TYPE_P (TREE_TYPE (field))) + return 1; + + if (RETURN_IN_MEMORY (TREE_TYPE (field))) + return 1; + } + + return 0; + } + + /* XXX Not sure what should be done for other aggregates, so put them in + memory. */ + return 1; +} +/* END CYGNUS LOCAL */ + +int +legitimate_pic_operand_p (x) + rtx x; +{ + if (CONSTANT_P (x) && flag_pic + && (GET_CODE (x) == SYMBOL_REF + || (GET_CODE (x) == CONST + && GET_CODE (XEXP (x, 0)) == PLUS + && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF))) + return 0; + + return 1; +} + +rtx +legitimize_pic_address (orig, mode, reg) + rtx orig; + enum machine_mode mode; + rtx reg; +{ + if (GET_CODE (orig) == SYMBOL_REF) + { + rtx pic_ref, address; + rtx insn; + int subregs = 0; + + if (reg == 0) + { + if (reload_in_progress || reload_completed) + abort (); + else + reg = gen_reg_rtx (Pmode); + + subregs = 1; + } + +#ifdef AOF_ASSEMBLER + /* The AOF assembler can generate relocations for these directly, and + understands that the PIC register has to be added into the offset. + */ + insn = emit_insn (gen_pic_load_addr_based (reg, orig)); +#else + if (subregs) + address = gen_reg_rtx (Pmode); + else + address = reg; + + emit_insn (gen_pic_load_addr (address, orig)); + + pic_ref = gen_rtx (MEM, Pmode, + gen_rtx (PLUS, Pmode, pic_offset_table_rtx, address)); + RTX_UNCHANGING_P (pic_ref) = 1; + insn = emit_move_insn (reg, pic_ref); +#endif + current_function_uses_pic_offset_table = 1; + /* Put a REG_EQUAL note on this insn, so that it can be optimized + by loop. */ + REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL, orig, + REG_NOTES (insn)); + return reg; + } + else if (GET_CODE (orig) == CONST) + { + rtx base, offset; + + if (GET_CODE (XEXP (orig, 0)) == PLUS + && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx) + return orig; + + if (reg == 0) + { + if (reload_in_progress || reload_completed) + abort (); + else + reg = gen_reg_rtx (Pmode); + } + + if (GET_CODE (XEXP (orig, 0)) == PLUS) + { + base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg); + offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode, + base == reg ? 0 : reg); + } + else + abort (); + + if (GET_CODE (offset) == CONST_INT) + { + /* The base register doesn't really matter, we only want to + test the index for the appropriate mode. */ + GO_IF_LEGITIMATE_INDEX (mode, 0, offset, win); + + if (! reload_in_progress && ! reload_completed) + offset = force_reg (Pmode, offset); + else + abort (); + + win: + if (GET_CODE (offset) == CONST_INT) + return plus_constant_for_output (base, INTVAL (offset)); + } + + if (GET_MODE_SIZE (mode) > 4 + && (GET_MODE_CLASS (mode) == MODE_INT + || TARGET_SOFT_FLOAT)) + { + emit_insn (gen_addsi3 (reg, base, offset)); + return reg; + } + + return gen_rtx (PLUS, Pmode, base, offset); + } + else if (GET_CODE (orig) == LABEL_REF) + current_function_uses_pic_offset_table = 1; + + return orig; +} + +static rtx pic_rtx; + +int +is_pic(x) + rtx x; +{ + if (x == pic_rtx) + return 1; + return 0; +} + +void +arm_finalize_pic () +{ +#ifndef AOF_ASSEMBLER + rtx l1, pic_tmp, pic_tmp2, seq; + rtx global_offset_table; + + if (current_function_uses_pic_offset_table == 0) + return; + + if (! flag_pic) + abort (); + + start_sequence (); + l1 = gen_label_rtx (); + + global_offset_table = gen_rtx (SYMBOL_REF, Pmode, "_GLOBAL_OFFSET_TABLE_"); + /* The PC contains 'dot'+8, but the label L1 is on the next + instruction, so the offset is only 'dot'+4. */ + pic_tmp = gen_rtx (CONST, VOIDmode, + gen_rtx (PLUS, Pmode, + gen_rtx (LABEL_REF, VOIDmode, l1), + GEN_INT (4))); + pic_tmp2 = gen_rtx (CONST, VOIDmode, + gen_rtx (PLUS, Pmode, + global_offset_table, + pc_rtx)); + + pic_rtx = gen_rtx (CONST, Pmode, + gen_rtx (MINUS, Pmode, pic_tmp2, pic_tmp)); + + emit_insn (gen_pic_load_addr (pic_offset_table_rtx, pic_rtx)); + emit_jump_insn (gen_pic_add_dot_plus_eight(l1, pic_offset_table_rtx)); + emit_label (l1); + + seq = gen_sequence (); + end_sequence (); + emit_insn_after (seq, get_insns ()); + + /* Need to emit this whether or not we obey regdecls, + since setjmp/longjmp can cause life info to screw up. */ + emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx)); +#endif /* AOF_ASSEMBLER */ +} + +#define REG_OR_SUBREG_REG(X) \ + (GET_CODE (X) == REG \ + || (GET_CODE (X) == SUBREG && GET_CODE (SUBREG_REG (X)) == REG)) + +#define REG_OR_SUBREG_RTX(X) \ + (GET_CODE (X) == REG ? (X) : SUBREG_REG (X)) + +#define ARM_FRAME_RTX(X) \ + ((X) == frame_pointer_rtx || (X) == stack_pointer_rtx \ + || (X) == arg_pointer_rtx) + +int +arm_rtx_costs (x, code, outer_code) + rtx x; + enum rtx_code code, outer_code; +{ + enum machine_mode mode = GET_MODE (x); + enum rtx_code subcode; + int extra_cost; + + switch (code) + { + case MEM: + /* Memory costs quite a lot for the first word, but subsequent words + load at the equivalent of a single insn each. */ + return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD) + + (CONSTANT_POOL_ADDRESS_P (x) ? 4 : 0)); + + case DIV: + case MOD: + return 100; + + case ROTATE: + if (mode == SImode && GET_CODE (XEXP (x, 1)) == REG) + return 4; + /* Fall through */ + case ROTATERT: + if (mode != SImode) + return 8; + /* Fall through */ + case ASHIFT: case LSHIFTRT: case ASHIFTRT: + if (mode == DImode) + return (8 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : 8) + + ((GET_CODE (XEXP (x, 0)) == REG + || (GET_CODE (XEXP (x, 0)) == SUBREG + && GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG)) + ? 0 : 8)); + return (1 + ((GET_CODE (XEXP (x, 0)) == REG + || (GET_CODE (XEXP (x, 0)) == SUBREG + && GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG)) + ? 0 : 4) + + ((GET_CODE (XEXP (x, 1)) == REG + || (GET_CODE (XEXP (x, 1)) == SUBREG + && GET_CODE (SUBREG_REG (XEXP (x, 1))) == REG) + || (GET_CODE (XEXP (x, 1)) == CONST_INT)) + ? 0 : 4)); + + case MINUS: + if (mode == DImode) + return (4 + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 8) + + ((REG_OR_SUBREG_REG (XEXP (x, 0)) + || (GET_CODE (XEXP (x, 0)) == CONST_INT + && const_ok_for_arm (INTVAL (XEXP (x, 0))))) + ? 0 : 8)); + + if (GET_MODE_CLASS (mode) == MODE_FLOAT) + return (2 + ((REG_OR_SUBREG_REG (XEXP (x, 1)) + || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE + && const_double_rtx_ok_for_fpu (XEXP (x, 1)))) + ? 0 : 8) + + ((REG_OR_SUBREG_REG (XEXP (x, 0)) + || (GET_CODE (XEXP (x, 0)) == CONST_DOUBLE + && const_double_rtx_ok_for_fpu (XEXP (x, 0)))) + ? 0 : 8)); + + if (((GET_CODE (XEXP (x, 0)) == CONST_INT + && const_ok_for_arm (INTVAL (XEXP (x, 0))) + && REG_OR_SUBREG_REG (XEXP (x, 1)))) + || (((subcode = GET_CODE (XEXP (x, 1))) == ASHIFT + || subcode == ASHIFTRT || subcode == LSHIFTRT + || subcode == ROTATE || subcode == ROTATERT + || (subcode == MULT + && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT + && ((INTVAL (XEXP (XEXP (x, 1), 1)) & + (INTVAL (XEXP (XEXP (x, 1), 1)) - 1)) == 0))) + && REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 0)) + && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 1)) + || GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT) + && REG_OR_SUBREG_REG (XEXP (x, 0)))) + return 1; + /* Fall through */ + + case PLUS: + if (GET_MODE_CLASS (mode) == MODE_FLOAT) + return (2 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8) + + ((REG_OR_SUBREG_REG (XEXP (x, 1)) + || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE + && const_double_rtx_ok_for_fpu (XEXP (x, 1)))) + ? 0 : 8)); + + /* Fall through */ + case AND: case XOR: case IOR: + extra_cost = 0; + + /* Normally the frame registers will be spilt into reg+const during + reload, so it is a bad idea to combine them with other instructions, + since then they might not be moved outside of loops. As a compromise + we allow integration with ops that have a constant as their second + operand. */ + if ((REG_OR_SUBREG_REG (XEXP (x, 0)) + && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0))) + && GET_CODE (XEXP (x, 1)) != CONST_INT) + || (REG_OR_SUBREG_REG (XEXP (x, 0)) + && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0))))) + extra_cost = 4; + + if (mode == DImode) + return (4 + extra_cost + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8) + + ((REG_OR_SUBREG_REG (XEXP (x, 1)) + || (GET_CODE (XEXP (x, 1)) == CONST_INT + && const_ok_for_op (INTVAL (XEXP (x, 1)), code, mode))) + ? 0 : 8)); + + if (REG_OR_SUBREG_REG (XEXP (x, 0))) + return (1 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : extra_cost) + + ((REG_OR_SUBREG_REG (XEXP (x, 1)) + || (GET_CODE (XEXP (x, 1)) == CONST_INT + && const_ok_for_op (INTVAL (XEXP (x, 1)), code, mode))) + ? 0 : 4)); + + else if (REG_OR_SUBREG_REG (XEXP (x, 1))) + return (1 + extra_cost + + ((((subcode = GET_CODE (XEXP (x, 0))) == ASHIFT + || subcode == LSHIFTRT || subcode == ASHIFTRT + || subcode == ROTATE || subcode == ROTATERT + || (subcode == MULT + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && ((INTVAL (XEXP (XEXP (x, 0), 1)) & + (INTVAL (XEXP (XEXP (x, 0), 1)) - 1)) == 0))) + && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 0))) + && ((REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 1))) + || GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)) + ? 0 : 4)); + + return 8; + + case MULT: + /* There is no point basing this on the tuning, since it is always the + fast variant if it exists at all */ + if (arm_fast_multiply && mode == DImode + && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1))) + && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND + || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND)) + return 8; + + if (GET_MODE_CLASS (mode) == MODE_FLOAT + || mode == DImode) + return 30; + + if (GET_CODE (XEXP (x, 1)) == CONST_INT) + { + unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1)) + & (unsigned HOST_WIDE_INT) 0xffffffff); + int add_cost = const_ok_for_arm (i) ? 4 : 8; + int j; + /* Tune as appropriate */ + int booth_unit_size = ((tune_flags & FL_FAST_MULT) ? 8 : 2); + + for (j = 0; i && j < 32; j += booth_unit_size) + { + i >>= booth_unit_size; + add_cost += 2; + } + + return add_cost; + } + + return (((tune_flags & FL_FAST_MULT) ? 8 : 30) + + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4) + + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4)); + + case TRUNCATE: + if (arm_fast_multiply && mode == SImode + && GET_CODE (XEXP (x, 0)) == LSHIFTRT + && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT + && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) + == GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1))) + && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == ZERO_EXTEND + || GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == SIGN_EXTEND)) + return 8; + return 99; + + case NEG: + if (GET_MODE_CLASS (mode) == MODE_FLOAT) + return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 6); + /* Fall through */ + case NOT: + if (mode == DImode) + return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4); + + return 1 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4); + + case IF_THEN_ELSE: + if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC) + return 14; + return 2; + + case COMPARE: + return 1; + + case ABS: + return 4 + (mode == DImode ? 4 : 0); + + case SIGN_EXTEND: + if (GET_MODE (XEXP (x, 0)) == QImode) + return (4 + (mode == DImode ? 4 : 0) + + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); + /* Fall through */ + case ZERO_EXTEND: + switch (GET_MODE (XEXP (x, 0))) + { + case QImode: + return (1 + (mode == DImode ? 4 : 0) + + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); + + case HImode: + return (4 + (mode == DImode ? 4 : 0) + + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); + + case SImode: + return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); + + default: + break; + } + abort (); + + default: + return 99; + } +} + +int +arm_adjust_cost (insn, link, dep, cost) + rtx insn; + rtx link; + rtx dep; + int cost; +{ + rtx i_pat, d_pat; + + if ((i_pat = single_set (insn)) != NULL + && GET_CODE (SET_SRC (i_pat)) == MEM + && (d_pat = single_set (dep)) != NULL + && GET_CODE (SET_DEST (d_pat)) == MEM) + { + /* This is a load after a store, there is no conflict if the load reads + from a cached area. Assume that loads from the stack, and from the + constant pool are cached, and that others will miss. This is a + hack. */ + +/* debug_rtx (insn); + debug_rtx (dep); + debug_rtx (link); + fprintf (stderr, "costs %d\n", cost); */ + + if (CONSTANT_POOL_ADDRESS_P (XEXP (SET_SRC (i_pat), 0)) + || reg_mentioned_p (stack_pointer_rtx, XEXP (SET_SRC (i_pat), 0)) + || reg_mentioned_p (frame_pointer_rtx, XEXP (SET_SRC (i_pat), 0)) + || reg_mentioned_p (hard_frame_pointer_rtx, + XEXP (SET_SRC (i_pat), 0))) + { +/* fprintf (stderr, "***** Now 1\n"); */ + return 1; + } + } + + return cost; +} + +/* This code has been fixed for cross compilation. */ + +static int fpa_consts_inited = 0; + +char *strings_fpa[8] = { + "0", "1", "2", "3", + "4", "5", "0.5", "10" +}; + +static REAL_VALUE_TYPE values_fpa[8]; + +static void +init_fpa_table () +{ + int i; + REAL_VALUE_TYPE r; + + for (i = 0; i < 8; i++) + { + r = REAL_VALUE_ATOF (strings_fpa[i], DFmode); + values_fpa[i] = r; + } + + fpa_consts_inited = 1; +} + +/* Return TRUE if rtx X is a valid immediate FPU constant. */ + +int +const_double_rtx_ok_for_fpu (x) + rtx x; +{ + REAL_VALUE_TYPE r; + int i; + + if (!fpa_consts_inited) + init_fpa_table (); + + REAL_VALUE_FROM_CONST_DOUBLE (r, x); + if (REAL_VALUE_MINUS_ZERO (r)) + return 0; + + for (i = 0; i < 8; i++) + if (REAL_VALUES_EQUAL (r, values_fpa[i])) + return 1; + + return 0; +} + +/* Return TRUE if rtx X is a valid immediate FPU constant. */ + +int +neg_const_double_rtx_ok_for_fpu (x) + rtx x; +{ + REAL_VALUE_TYPE r; + int i; + + if (!fpa_consts_inited) + init_fpa_table (); + + REAL_VALUE_FROM_CONST_DOUBLE (r, x); + r = REAL_VALUE_NEGATE (r); + if (REAL_VALUE_MINUS_ZERO (r)) + return 0; + + for (i = 0; i < 8; i++) + if (REAL_VALUES_EQUAL (r, values_fpa[i])) + return 1; + + return 0; +} + +/* Predicates for `match_operand' and `match_operator'. */ + +/* s_register_operand is the same as register_operand, but it doesn't accept + (SUBREG (MEM)...). + + This function exists because at the time it was put in it led to better + code. SUBREG(MEM) always needs a reload in the places where + s_register_operand is used, and this seemed to lead to excessive + reloading. */ + +int +s_register_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + if (GET_MODE (op) != mode && mode != VOIDmode) + return 0; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + /* We don't consider registers whose class is NO_REGS + to be a register operand. */ + return (GET_CODE (op) == REG + && (REGNO (op) >= FIRST_PSEUDO_REGISTER + || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); +} + +/* Only accept reg, subreg(reg), const_int. */ + +int +reg_or_int_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + if (GET_CODE (op) == CONST_INT) + return 1; + + if (GET_MODE (op) != mode && mode != VOIDmode) + return 0; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + /* We don't consider registers whose class is NO_REGS + to be a register operand. */ + return (GET_CODE (op) == REG + && (REGNO (op) >= FIRST_PSEUDO_REGISTER + || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); +} + +/* Return 1 if OP is an item in memory, given that we are in reload. */ + +int +reload_memory_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + int regno = true_regnum (op); + + return (! CONSTANT_P (op) + && (regno == -1 + || (GET_CODE (op) == REG + && REGNO (op) >= FIRST_PSEUDO_REGISTER))); +} + +/* Return 1 if OP is a valid memory address, but not valid for a signed byte + memory access (architecture V4) */ +int +bad_signed_byte_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (! memory_operand (op, mode) || GET_CODE (op) != MEM) + return 0; + + op = XEXP (op, 0); + + /* A sum of anything more complex than reg + reg or reg + const is bad */ + if ((GET_CODE (op) == PLUS || GET_CODE (op) == MINUS) + && (! s_register_operand (XEXP (op, 0), VOIDmode) + || (! s_register_operand (XEXP (op, 1), VOIDmode) + && GET_CODE (XEXP (op, 1)) != CONST_INT))) + return 1; + + /* Big constants are also bad */ + if (GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT + && (INTVAL (XEXP (op, 1)) > 0xff + || -INTVAL (XEXP (op, 1)) > 0xff)) + return 1; + + /* Everything else is good, or can will automatically be made so. */ + return 0; +} + +/* Return TRUE for valid operands for the rhs of an ARM instruction. */ + +int +arm_rhs_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (s_register_operand (op, mode) + || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op)))); +} + +/* Return TRUE for valid operands for the rhs of an ARM instruction, or a load. + */ + +int +arm_rhsm_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (s_register_operand (op, mode) + || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op))) + || memory_operand (op, mode)); +} + +/* Return TRUE for valid operands for the rhs of an ARM instruction, or if a + constant that is valid when negated. */ + +int +arm_add_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (s_register_operand (op, mode) + || (GET_CODE (op) == CONST_INT + && (const_ok_for_arm (INTVAL (op)) + || const_ok_for_arm (-INTVAL (op))))); +} + +int +arm_not_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (s_register_operand (op, mode) + || (GET_CODE (op) == CONST_INT + && (const_ok_for_arm (INTVAL (op)) + || const_ok_for_arm (~INTVAL (op))))); +} + +/* Return TRUE if the operand is a memory reference which contains an + offsettable address. */ +int +offsettable_memory_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + if (mode == VOIDmode) + mode = GET_MODE (op); + + return (mode == GET_MODE (op) + && GET_CODE (op) == MEM + && offsettable_address_p (reload_completed | reload_in_progress, + mode, XEXP (op, 0))); +} + +/* Return TRUE if the operand is a memory reference which is, or can be + made word aligned by adjusting the offset. */ +int +alignable_memory_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + rtx reg; + + if (mode == VOIDmode) + mode = GET_MODE (op); + + if (mode != GET_MODE (op) || GET_CODE (op) != MEM) + return 0; + + op = XEXP (op, 0); + + return ((GET_CODE (reg = op) == REG + || (GET_CODE (op) == SUBREG + && GET_CODE (reg = SUBREG_REG (op)) == REG) + || (GET_CODE (op) == PLUS + && GET_CODE (XEXP (op, 1)) == CONST_INT + && (GET_CODE (reg = XEXP (op, 0)) == REG + || (GET_CODE (XEXP (op, 0)) == SUBREG + && GET_CODE (reg = SUBREG_REG (XEXP (op, 0))) == REG)))) + && REGNO_POINTER_ALIGN (REGNO (reg)) >= 4); +} + +/* Similar to s_register_operand, but does not allow hard integer + registers. */ +int +f_register_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + if (GET_MODE (op) != mode && mode != VOIDmode) + return 0; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + /* We don't consider registers whose class is NO_REGS + to be a register operand. */ + return (GET_CODE (op) == REG + && (REGNO (op) >= FIRST_PSEUDO_REGISTER + || REGNO_REG_CLASS (REGNO (op)) == FPU_REGS)); +} + +/* Return TRUE for valid operands for the rhs of an FPU instruction. */ + +int +fpu_rhs_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (s_register_operand (op, mode)) + return TRUE; + else if (GET_CODE (op) == CONST_DOUBLE) + return (const_double_rtx_ok_for_fpu (op)); + + return FALSE; +} + +int +fpu_add_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (s_register_operand (op, mode)) + return TRUE; + else if (GET_CODE (op) == CONST_DOUBLE) + return (const_double_rtx_ok_for_fpu (op) + || neg_const_double_rtx_ok_for_fpu (op)); + + return FALSE; +} + +/* Return nonzero if OP is a constant power of two. */ + +int +power_of_two_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (GET_CODE (op) == CONST_INT) + { + HOST_WIDE_INT value = INTVAL(op); + return value != 0 && (value & (value - 1)) == 0; + } + return FALSE; +} + +/* Return TRUE for a valid operand of a DImode operation. + Either: REG, SUBREG, CONST_DOUBLE or MEM(DImode_address). + Note that this disallows MEM(REG+REG), but allows + MEM(PRE/POST_INC/DEC(REG)). */ + +int +di_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (s_register_operand (op, mode)) + return TRUE; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + switch (GET_CODE (op)) + { + case CONST_DOUBLE: + case CONST_INT: + return TRUE; + + case MEM: + return memory_address_p (DImode, XEXP (op, 0)); + + default: + return FALSE; + } +} + +/* Return TRUE for a valid operand of a DFmode operation when -msoft-float. + Either: REG, SUBREG, CONST_DOUBLE or MEM(DImode_address). + Note that this disallows MEM(REG+REG), but allows + MEM(PRE/POST_INC/DEC(REG)). */ + +int +soft_df_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (s_register_operand (op, mode)) + return TRUE; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + switch (GET_CODE (op)) + { + case CONST_DOUBLE: + return TRUE; + + case MEM: + return memory_address_p (DFmode, XEXP (op, 0)); + + default: + return FALSE; + } +} + +/* Return TRUE for valid index operands. */ + +int +index_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (s_register_operand(op, mode) + || (immediate_operand (op, mode) + && INTVAL (op) < 4096 && INTVAL (op) > -4096)); +} + +/* Return TRUE for valid shifts by a constant. This also accepts any + power of two on the (somewhat overly relaxed) assumption that the + shift operator in this case was a mult. */ + +int +const_shift_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (power_of_two_operand (op, mode) + || (immediate_operand (op, mode) + && (INTVAL (op) < 32 && INTVAL (op) > 0))); +} + +/* Return TRUE for arithmetic operators which can be combined with a multiply + (shift). */ + +int +shiftable_operator (x, mode) + rtx x; + enum machine_mode mode; +{ + if (GET_MODE (x) != mode) + return FALSE; + else + { + enum rtx_code code = GET_CODE (x); + + return (code == PLUS || code == MINUS + || code == IOR || code == XOR || code == AND); + } +} + +/* Return TRUE for shift operators. */ + +int +shift_operator (x, mode) + rtx x; + enum machine_mode mode; +{ + if (GET_MODE (x) != mode) + return FALSE; + else + { + enum rtx_code code = GET_CODE (x); + + if (code == MULT) + return power_of_two_operand (XEXP (x, 1)); + + return (code == ASHIFT || code == ASHIFTRT || code == LSHIFTRT + || code == ROTATERT); + } +} + +int equality_operator (x, mode) + rtx x; + enum machine_mode mode; +{ + return GET_CODE (x) == EQ || GET_CODE (x) == NE; +} + +/* Return TRUE for SMIN SMAX UMIN UMAX operators. */ + +int +minmax_operator (x, mode) + rtx x; + enum machine_mode mode; +{ + enum rtx_code code = GET_CODE (x); + + if (GET_MODE (x) != mode) + return FALSE; + + return code == SMIN || code == SMAX || code == UMIN || code == UMAX; +} + +/* return TRUE if x is EQ or NE */ + +/* Return TRUE if this is the condition code register, if we aren't given + a mode, accept any class CCmode register */ + +int +cc_register (x, mode) + rtx x; + enum machine_mode mode; +{ + if (mode == VOIDmode) + { + mode = GET_MODE (x); + if (GET_MODE_CLASS (mode) != MODE_CC) + return FALSE; + } + + if (mode == GET_MODE (x) && GET_CODE (x) == REG && REGNO (x) == 24) + return TRUE; + + return FALSE; +} + +/* Return TRUE if this is the condition code register, if we aren't given + a mode, accept any class CCmode register which indicates a dominance + expression. */ + +int +dominant_cc_register (x, mode) + rtx x; + enum machine_mode mode; +{ + if (mode == VOIDmode) + { + mode = GET_MODE (x); + if (GET_MODE_CLASS (mode) != MODE_CC) + return FALSE; + } + + if (mode != CC_DNEmode && mode != CC_DEQmode + && mode != CC_DLEmode && mode != CC_DLTmode + && mode != CC_DGEmode && mode != CC_DGTmode + && mode != CC_DLEUmode && mode != CC_DLTUmode + && mode != CC_DGEUmode && mode != CC_DGTUmode) + return FALSE; + + if (mode == GET_MODE (x) && GET_CODE (x) == REG && REGNO (x) == 24) + return TRUE; + + return FALSE; +} + +/* Return TRUE if X references a SYMBOL_REF. */ +int +symbol_mentioned_p (x) + rtx x; +{ + register char *fmt; + register int i; + + if (GET_CODE (x) == SYMBOL_REF) + return 1; + + fmt = GET_RTX_FORMAT (GET_CODE (x)); + for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) + { + if (fmt[i] == 'E') + { + register int j; + + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + if (symbol_mentioned_p (XVECEXP (x, i, j))) + return 1; + } + else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i))) + return 1; + } + + return 0; +} + +/* Return TRUE if X references a LABEL_REF. */ +int +label_mentioned_p (x) + rtx x; +{ + register char *fmt; + register int i; + + if (GET_CODE (x) == LABEL_REF) + return 1; + + fmt = GET_RTX_FORMAT (GET_CODE (x)); + for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) + { + if (fmt[i] == 'E') + { + register int j; + + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + if (label_mentioned_p (XVECEXP (x, i, j))) + return 1; + } + else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i))) + return 1; + } + + return 0; +} + +enum rtx_code +minmax_code (x) + rtx x; +{ + enum rtx_code code = GET_CODE (x); + + if (code == SMAX) + return GE; + else if (code == SMIN) + return LE; + else if (code == UMIN) + return LEU; + else if (code == UMAX) + return GEU; + + abort (); +} + +/* Return 1 if memory locations are adjacent */ + +int +adjacent_mem_locations (a, b) + rtx a, b; +{ + int val0 = 0, val1 = 0; + int reg0, reg1; + + if ((GET_CODE (XEXP (a, 0)) == REG + || (GET_CODE (XEXP (a, 0)) == PLUS + && GET_CODE (XEXP (XEXP (a, 0), 1)) == CONST_INT)) + && (GET_CODE (XEXP (b, 0)) == REG + || (GET_CODE (XEXP (b, 0)) == PLUS + && GET_CODE (XEXP (XEXP (b, 0), 1)) == CONST_INT))) + { + if (GET_CODE (XEXP (a, 0)) == PLUS) + { + reg0 = REGNO (XEXP (XEXP (a, 0), 0)); + val0 = INTVAL (XEXP (XEXP (a, 0), 1)); + } + else + reg0 = REGNO (XEXP (a, 0)); + if (GET_CODE (XEXP (b, 0)) == PLUS) + { + reg1 = REGNO (XEXP (XEXP (b, 0), 0)); + val1 = INTVAL (XEXP (XEXP (b, 0), 1)); + } + else + reg1 = REGNO (XEXP (b, 0)); + return (reg0 == reg1) && ((val1 - val0) == 4 || (val0 - val1) == 4); + } + return 0; +} + +/* Return 1 if OP is a load multiple operation. It is known to be + parallel and the first section will be tested. */ + +int +load_multiple_operation (op, mode) + rtx op; + enum machine_mode mode; +{ + HOST_WIDE_INT count = XVECLEN (op, 0); + int dest_regno; + rtx src_addr; + HOST_WIDE_INT i = 1, base = 0; + rtx elt; + + if (count <= 1 + || GET_CODE (XVECEXP (op, 0, 0)) != SET) + return 0; + + /* Check to see if this might be a write-back */ + if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS) + { + i++; + base = 1; + + /* Now check it more carefully */ + if (GET_CODE (SET_DEST (elt)) != REG + || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG + || REGNO (XEXP (SET_SRC (elt), 0)) != REGNO (SET_DEST (elt)) + || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT + || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 2) * 4 + || GET_CODE (XVECEXP (op, 0, count - 1)) != CLOBBER + || GET_CODE (XEXP (XVECEXP (op, 0, count - 1), 0)) != REG + || REGNO (XEXP (XVECEXP (op, 0, count - 1), 0)) + != REGNO (SET_DEST (elt))) + return 0; + + count--; + } + + /* Perform a quick check so we don't blow up below. */ + if (count <= i + || GET_CODE (XVECEXP (op, 0, i - 1)) != SET + || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != REG + || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != MEM) + return 0; + + dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, i - 1))); + src_addr = XEXP (SET_SRC (XVECEXP (op, 0, i - 1)), 0); + + for (; i < count; i++) + { + elt = XVECEXP (op, 0, i); + + if (GET_CODE (elt) != SET + || GET_CODE (SET_DEST (elt)) != REG + || GET_MODE (SET_DEST (elt)) != SImode + || REGNO (SET_DEST (elt)) != dest_regno + i - base + || GET_CODE (SET_SRC (elt)) != MEM + || GET_MODE (SET_SRC (elt)) != SImode + || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS + || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr) + || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT + || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != (i - base) * 4) + return 0; + } + + return 1; +} + +/* Return 1 if OP is a store multiple operation. It is known to be + parallel and the first section will be tested. */ + +int +store_multiple_operation (op, mode) + rtx op; + enum machine_mode mode; +{ + HOST_WIDE_INT count = XVECLEN (op, 0); + int src_regno; + rtx dest_addr; + HOST_WIDE_INT i = 1, base = 0; + rtx elt; + + if (count <= 1 + || GET_CODE (XVECEXP (op, 0, 0)) != SET) + return 0; + + /* Check to see if this might be a write-back */ + if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS) + { + i++; + base = 1; + + /* Now check it more carefully */ + if (GET_CODE (SET_DEST (elt)) != REG + || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG + || REGNO (XEXP (SET_SRC (elt), 0)) != REGNO (SET_DEST (elt)) + || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT + || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 2) * 4 + || GET_CODE (XVECEXP (op, 0, count - 1)) != CLOBBER + || GET_CODE (XEXP (XVECEXP (op, 0, count - 1), 0)) != REG + || REGNO (XEXP (XVECEXP (op, 0, count - 1), 0)) + != REGNO (SET_DEST (elt))) + return 0; + + count--; + } + + /* Perform a quick check so we don't blow up below. */ + if (count <= i + || GET_CODE (XVECEXP (op, 0, i - 1)) != SET + || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != MEM + || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != REG) + return 0; + + src_regno = REGNO (SET_SRC (XVECEXP (op, 0, i - 1))); + dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, i - 1)), 0); + + for (; i < count; i++) + { + elt = XVECEXP (op, 0, i); + + if (GET_CODE (elt) != SET + || GET_CODE (SET_SRC (elt)) != REG + || GET_MODE (SET_SRC (elt)) != SImode + || REGNO (SET_SRC (elt)) != src_regno + i - base + || GET_CODE (SET_DEST (elt)) != MEM + || GET_MODE (SET_DEST (elt)) != SImode + || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS + || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr) + || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT + || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != (i - base) * 4) + return 0; + } + + return 1; +} + +int +load_multiple_sequence (operands, nops, regs, base, load_offset) + rtx *operands; + int nops; + int *regs; + int *base; + HOST_WIDE_INT *load_offset; +{ + int unsorted_regs[4]; + HOST_WIDE_INT unsorted_offsets[4]; + int order[4]; + int base_reg = -1; + int i; + + /* Can only handle 2, 3, or 4 insns at present, though could be easily + extended if required. */ + if (nops < 2 || nops > 4) + abort (); + + /* Loop over the operands and check that the memory references are + suitable (ie immediate offsets from the same base register). At + the same time, extract the target register, and the memory + offsets. */ + for (i = 0; i < nops; i++) + { + rtx reg; + rtx offset; + + /* Convert a subreg of a mem into the mem itself. */ + if (GET_CODE (operands[nops + i]) == SUBREG) + operands[nops + i] = alter_subreg(operands[nops + i]); + + if (GET_CODE (operands[nops + i]) != MEM) + abort (); + + /* Don't reorder volatile memory references; it doesn't seem worth + looking for the case where the order is ok anyway. */ + if (MEM_VOLATILE_P (operands[nops + i])) + return 0; + + offset = const0_rtx; + + if ((GET_CODE (reg = XEXP (operands[nops + i], 0)) == REG + || (GET_CODE (reg) == SUBREG + && GET_CODE (reg = SUBREG_REG (reg)) == REG)) + || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS + && ((GET_CODE (reg = XEXP (XEXP (operands[nops + i], 0), 0)) + == REG) + || (GET_CODE (reg) == SUBREG + && GET_CODE (reg = SUBREG_REG (reg)) == REG)) + && (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1)) + == CONST_INT))) + { + if (i == 0) + { + base_reg = REGNO(reg); + unsorted_regs[0] = (GET_CODE (operands[i]) == REG + ? REGNO (operands[i]) + : REGNO (SUBREG_REG (operands[i]))); + order[0] = 0; + } + else + { + if (base_reg != REGNO (reg)) + /* Not addressed from the same base register. */ + return 0; + + unsorted_regs[i] = (GET_CODE (operands[i]) == REG + ? REGNO (operands[i]) + : REGNO (SUBREG_REG (operands[i]))); + if (unsorted_regs[i] < unsorted_regs[order[0]]) + order[0] = i; + } + + /* If it isn't an integer register, or if it overwrites the + base register but isn't the last insn in the list, then + we can't do this. */ + if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14 + || (i != nops - 1 && unsorted_regs[i] == base_reg)) + return 0; + + unsorted_offsets[i] = INTVAL (offset); + } + else + /* Not a suitable memory address. */ + return 0; + } + + /* All the useful information has now been extracted from the + operands into unsorted_regs and unsorted_offsets; additionally, + order[0] has been set to the lowest numbered register in the + list. Sort the registers into order, and check that the memory + offsets are ascending and adjacent. */ + + for (i = 1; i < nops; i++) + { + int j; + + order[i] = order[i - 1]; + for (j = 0; j < nops; j++) + if (unsorted_regs[j] > unsorted_regs[order[i - 1]] + && (order[i] == order[i - 1] + || unsorted_regs[j] < unsorted_regs[order[i]])) + order[i] = j; + + /* Have we found a suitable register? if not, one must be used more + than once. */ + if (order[i] == order[i - 1]) + return 0; + + /* Is the memory address adjacent and ascending? */ + if (unsorted_offsets[order[i]] != unsorted_offsets[order[i - 1]] + 4) + return 0; + } + + if (base) + { + *base = base_reg; + + for (i = 0; i < nops; i++) + regs[i] = unsorted_regs[order[i]]; + + *load_offset = unsorted_offsets[order[0]]; + } + + if (unsorted_offsets[order[0]] == 0) + return 1; /* ldmia */ + + if (unsorted_offsets[order[0]] == 4) + return 2; /* ldmib */ + + if (unsorted_offsets[order[nops - 1]] == 0) + return 3; /* ldmda */ + + if (unsorted_offsets[order[nops - 1]] == -4) + return 4; /* ldmdb */ + + /* For ARM8,9 & StrongARM, 2 ldr instructions are faster than an ldm if + the offset isn't small enough. The reason 2 ldrs are faster is because + these ARMs are able to do more than one cache access in a single cycle. + The ARM9 and StrongARM have Harvard caches, whilst the ARM8 has a double + bandwidth cache. This means that these cores can do both an instruction + fetch and a data fetch in a single cycle, so the trick of calculating the + address into a scratch register (one of the result regs) and then doing a + load multiple actually becomes slower (and no smaller in code size). That + is the transformation + + ldr rd1, [rbase + offset] + ldr rd2, [rbase + offset + 4] + + to + + add rd1, rbase, offset + ldmia rd1, {rd1, rd2} + + produces worse code -- '3 cycles + any stalls on rd2' instead of '2 cycles + + any stalls on rd2'. On ARMs with only one cache access per cycle, the + first sequence could never complete in less than 6 cycles, whereas the ldm + sequence would only take 5 and would make better use of sequential accesses + if not hitting the cache. + + We cheat here and test 'arm_ld_sched' which we currently know to only be + true for the ARM8, ARM9 and StrongARM. If this ever changes, then the test + below needs to be reworked. */ + if (nops == 2 && arm_ld_sched) + return 0; + + /* Can't do it without setting up the offset, only do this if it takes + no more than one insn. */ + return (const_ok_for_arm (unsorted_offsets[order[0]]) + || const_ok_for_arm (-unsorted_offsets[order[0]])) ? 5 : 0; +} + +char * +emit_ldm_seq (operands, nops) + rtx *operands; + int nops; +{ + int regs[4]; + int base_reg; + HOST_WIDE_INT offset; + char buf[100]; + int i; + + switch (load_multiple_sequence (operands, nops, regs, &base_reg, &offset)) + { + case 1: + strcpy (buf, "ldm%?ia\t"); + break; + + case 2: + strcpy (buf, "ldm%?ib\t"); + break; + + case 3: + strcpy (buf, "ldm%?da\t"); + break; + + case 4: + strcpy (buf, "ldm%?db\t"); + break; + + case 5: + if (offset >= 0) + sprintf (buf, "add%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX, + reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg], + (long) offset); + else + sprintf (buf, "sub%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX, + reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg], + (long) -offset); + output_asm_insn (buf, operands); + base_reg = regs[0]; + strcpy (buf, "ldm%?ia\t"); + break; + + default: + abort (); + } + + sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX, + reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]); + + for (i = 1; i < nops; i++) + sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX, + reg_names[regs[i]]); + + strcat (buf, "}\t%@ phole ldm"); + + output_asm_insn (buf, operands); + return ""; +} + +int +store_multiple_sequence (operands, nops, regs, base, load_offset) + rtx *operands; + int nops; + int *regs; + int *base; + HOST_WIDE_INT *load_offset; +{ + int unsorted_regs[4]; + HOST_WIDE_INT unsorted_offsets[4]; + int order[4]; + int base_reg = -1; + int i; + + /* Can only handle 2, 3, or 4 insns at present, though could be easily + extended if required. */ + if (nops < 2 || nops > 4) + abort (); + + /* Loop over the operands and check that the memory references are + suitable (ie immediate offsets from the same base register). At + the same time, extract the target register, and the memory + offsets. */ + for (i = 0; i < nops; i++) + { + rtx reg; + rtx offset; + + /* Convert a subreg of a mem into the mem itself. */ + if (GET_CODE (operands[nops + i]) == SUBREG) + operands[nops + i] = alter_subreg(operands[nops + i]); + + if (GET_CODE (operands[nops + i]) != MEM) + abort (); + + /* Don't reorder volatile memory references; it doesn't seem worth + looking for the case where the order is ok anyway. */ + if (MEM_VOLATILE_P (operands[nops + i])) + return 0; + + offset = const0_rtx; + + if ((GET_CODE (reg = XEXP (operands[nops + i], 0)) == REG + || (GET_CODE (reg) == SUBREG + && GET_CODE (reg = SUBREG_REG (reg)) == REG)) + || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS + && ((GET_CODE (reg = XEXP (XEXP (operands[nops + i], 0), 0)) + == REG) + || (GET_CODE (reg) == SUBREG + && GET_CODE (reg = SUBREG_REG (reg)) == REG)) + && (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1)) + == CONST_INT))) + { + if (i == 0) + { + base_reg = REGNO(reg); + unsorted_regs[0] = (GET_CODE (operands[i]) == REG + ? REGNO (operands[i]) + : REGNO (SUBREG_REG (operands[i]))); + order[0] = 0; + } + else + { + if (base_reg != REGNO (reg)) + /* Not addressed from the same base register. */ + return 0; + + unsorted_regs[i] = (GET_CODE (operands[i]) == REG + ? REGNO (operands[i]) + : REGNO (SUBREG_REG (operands[i]))); + if (unsorted_regs[i] < unsorted_regs[order[0]]) + order[0] = i; + } + + /* If it isn't an integer register, then we can't do this. */ + if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14) + return 0; + + unsorted_offsets[i] = INTVAL (offset); + } + else + /* Not a suitable memory address. */ + return 0; + } + + /* All the useful information has now been extracted from the + operands into unsorted_regs and unsorted_offsets; additionally, + order[0] has been set to the lowest numbered register in the + list. Sort the registers into order, and check that the memory + offsets are ascending and adjacent. */ + + for (i = 1; i < nops; i++) + { + int j; + + order[i] = order[i - 1]; + for (j = 0; j < nops; j++) + if (unsorted_regs[j] > unsorted_regs[order[i - 1]] + && (order[i] == order[i - 1] + || unsorted_regs[j] < unsorted_regs[order[i]])) + order[i] = j; + + /* Have we found a suitable register? if not, one must be used more + than once. */ + if (order[i] == order[i - 1]) + return 0; + + /* Is the memory address adjacent and ascending? */ + if (unsorted_offsets[order[i]] != unsorted_offsets[order[i - 1]] + 4) + return 0; + } + + if (base) + { + *base = base_reg; + + for (i = 0; i < nops; i++) + regs[i] = unsorted_regs[order[i]]; + + *load_offset = unsorted_offsets[order[0]]; + } + + if (unsorted_offsets[order[0]] == 0) + return 1; /* stmia */ + + if (unsorted_offsets[order[0]] == 4) + return 2; /* stmib */ + + if (unsorted_offsets[order[nops - 1]] == 0) + return 3; /* stmda */ + + if (unsorted_offsets[order[nops - 1]] == -4) + return 4; /* stmdb */ + + return 0; +} + +char * +emit_stm_seq (operands, nops) + rtx *operands; + int nops; +{ + int regs[4]; + int base_reg; + HOST_WIDE_INT offset; + char buf[100]; + int i; + + switch (store_multiple_sequence (operands, nops, regs, &base_reg, &offset)) + { + case 1: + strcpy (buf, "stm%?ia\t"); + break; + + case 2: + strcpy (buf, "stm%?ib\t"); + break; + + case 3: + strcpy (buf, "stm%?da\t"); + break; + + case 4: + strcpy (buf, "stm%?db\t"); + break; + + default: + abort (); + } + + sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX, + reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]); + + for (i = 1; i < nops; i++) + sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX, + reg_names[regs[i]]); + + strcat (buf, "}\t%@ phole stm"); + + output_asm_insn (buf, operands); + return ""; +} + +int +multi_register_push (op, mode) + rtx op; + enum machine_mode mode; +{ + if (GET_CODE (op) != PARALLEL + || (GET_CODE (XVECEXP (op, 0, 0)) != SET) + || (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC) + || (XINT (SET_SRC (XVECEXP (op, 0, 0)), 1) != 2)) + return 0; + + return 1; +} + + +/* Routines for use with attributes */ + +/* Return nonzero if ATTR is a valid attribute for DECL. + ATTRIBUTES are any existing attributes and ARGS are the arguments + supplied with ATTR. + + Supported attributes: + + naked: don't output any prologue or epilogue code, the user is assumed + to do the right thing. */ + +int +arm_valid_machine_decl_attribute (decl, attributes, attr, args) + tree decl; + tree attributes; + tree attr; + tree args; +{ + if (args != NULL_TREE) + return 0; + + if (is_attribute_p ("naked", attr)) + return TREE_CODE (decl) == FUNCTION_DECL; + return 0; +} + +/* Return non-zero if FUNC is a naked function. */ + +static int +arm_naked_function_p (func) + tree func; +{ + tree a; + + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + + a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func)); + return a != NULL_TREE; +} + +/* Routines for use in generating RTL */ + +rtx +arm_gen_load_multiple (base_regno, count, from, up, write_back, unchanging_p, + in_struct_p, scalar_p) + int base_regno; + int count; + rtx from; + int up; + int write_back; + int unchanging_p; + int in_struct_p; + int scalar_p; +{ + int i = 0, j; + rtx result; + int sign = up ? 1 : -1; + rtx mem; + + result = gen_rtx (PARALLEL, VOIDmode, + rtvec_alloc (count + (write_back ? 2 : 0))); + if (write_back) + { + XVECEXP (result, 0, 0) + = gen_rtx (SET, GET_MODE (from), from, + plus_constant (from, count * 4 * sign)); + i = 1; + count++; + } + + for (j = 0; i < count; i++, j++) + { + mem = gen_rtx (MEM, SImode, plus_constant (from, j * 4 * sign)); + RTX_UNCHANGING_P (mem) = unchanging_p; + MEM_IN_STRUCT_P (mem) = in_struct_p; + MEM_SCALAR_P (mem) = scalar_p; + XVECEXP (result, 0, i) = gen_rtx (SET, VOIDmode, + gen_rtx (REG, SImode, base_regno + j), + mem); + } + + if (write_back) + XVECEXP (result, 0, i) = gen_rtx (CLOBBER, SImode, from); + + return result; +} + +rtx +arm_gen_store_multiple (base_regno, count, to, up, write_back, unchanging_p, + in_struct_p, scalar_p) + int base_regno; + int count; + rtx to; + int up; + int write_back; + int unchanging_p; + int in_struct_p; + int scalar_p; +{ + int i = 0, j; + rtx result; + int sign = up ? 1 : -1; + rtx mem; + + result = gen_rtx (PARALLEL, VOIDmode, + rtvec_alloc (count + (write_back ? 2 : 0))); + if (write_back) + { + XVECEXP (result, 0, 0) + = gen_rtx (SET, GET_MODE (to), to, + plus_constant (to, count * 4 * sign)); + i = 1; + count++; + } + + for (j = 0; i < count; i++, j++) + { + mem = gen_rtx (MEM, SImode, plus_constant (to, j * 4 * sign)); + RTX_UNCHANGING_P (mem) = unchanging_p; + MEM_IN_STRUCT_P (mem) = in_struct_p; + MEM_SCALAR_P (mem) = scalar_p; + + XVECEXP (result, 0, i) = gen_rtx (SET, VOIDmode, mem, + gen_rtx (REG, SImode, base_regno + j)); + } + + if (write_back) + XVECEXP (result, 0, i) = gen_rtx (CLOBBER, SImode, to); + + return result; +} + +int +arm_gen_movstrqi (operands) + rtx *operands; +{ + HOST_WIDE_INT in_words_to_go, out_words_to_go, last_bytes; + int i; + rtx src, dst; + rtx st_src, st_dst, fin_src, fin_dst; + rtx part_bytes_reg = NULL; + rtx mem; + int dst_unchanging_p, dst_in_struct_p, src_unchanging_p, src_in_struct_p; + int dst_scalar_p, src_scalar_p; + + if (GET_CODE (operands[2]) != CONST_INT + || GET_CODE (operands[3]) != CONST_INT + || INTVAL (operands[2]) > 64 + || INTVAL (operands[3]) & 3) + return 0; + + st_dst = XEXP (operands[0], 0); + st_src = XEXP (operands[1], 0); + + dst_unchanging_p = RTX_UNCHANGING_P (operands[0]); + dst_in_struct_p = MEM_IN_STRUCT_P (operands[0]); + dst_scalar_p = MEM_SCALAR_P (operands[0]); + src_unchanging_p = RTX_UNCHANGING_P (operands[1]); + src_in_struct_p = MEM_IN_STRUCT_P (operands[1]); + src_scalar_p = MEM_SCALAR_P (operands[1]); + + fin_dst = dst = copy_to_mode_reg (SImode, st_dst); + fin_src = src = copy_to_mode_reg (SImode, st_src); + + in_words_to_go = (INTVAL (operands[2]) + 3) / 4; + out_words_to_go = INTVAL (operands[2]) / 4; + last_bytes = INTVAL (operands[2]) & 3; + + if (out_words_to_go != in_words_to_go && ((in_words_to_go - 1) & 3) != 0) + part_bytes_reg = gen_rtx (REG, SImode, (in_words_to_go - 1) & 3); + + for (i = 0; in_words_to_go >= 2; i+=4) + { + if (in_words_to_go > 4) + emit_insn (arm_gen_load_multiple (0, 4, src, TRUE, TRUE, + src_unchanging_p, + src_in_struct_p, + src_scalar_p)); + else + emit_insn (arm_gen_load_multiple (0, in_words_to_go, src, TRUE, + FALSE, src_unchanging_p, + src_in_struct_p, src_scalar_p)); + + if (out_words_to_go) + { + if (out_words_to_go > 4) + emit_insn (arm_gen_store_multiple (0, 4, dst, TRUE, TRUE, + dst_unchanging_p, + dst_in_struct_p, + dst_scalar_p)); + else if (out_words_to_go != 1) + emit_insn (arm_gen_store_multiple (0, out_words_to_go, + dst, TRUE, + (last_bytes == 0 + ? FALSE : TRUE), + dst_unchanging_p, + dst_in_struct_p, + dst_scalar_p)); + else + { + mem = gen_rtx (MEM, SImode, dst); + RTX_UNCHANGING_P (mem) = dst_unchanging_p; + MEM_IN_STRUCT_P (mem) = dst_in_struct_p; + MEM_SCALAR_P (mem) = dst_scalar_p; + emit_move_insn (mem, gen_rtx (REG, SImode, 0)); + if (last_bytes != 0) + emit_insn (gen_addsi3 (dst, dst, GEN_INT (4))); + } + } + + in_words_to_go -= in_words_to_go < 4 ? in_words_to_go : 4; + out_words_to_go -= out_words_to_go < 4 ? out_words_to_go : 4; + } + + /* OUT_WORDS_TO_GO will be zero here if there are byte stores to do. */ + if (out_words_to_go) + { + rtx sreg; + + mem = gen_rtx (MEM, SImode, src); + RTX_UNCHANGING_P (mem) = src_unchanging_p; + MEM_IN_STRUCT_P (mem) = src_in_struct_p; + MEM_SCALAR_P (mem) = src_scalar_p; + emit_move_insn (sreg = gen_reg_rtx (SImode), mem); + emit_move_insn (fin_src = gen_reg_rtx (SImode), plus_constant (src, 4)); + + mem = gen_rtx (MEM, SImode, dst); + RTX_UNCHANGING_P (mem) = dst_unchanging_p; + MEM_IN_STRUCT_P (mem) = dst_in_struct_p; + MEM_SCALAR_P (mem) = dst_scalar_p; + emit_move_insn (mem, sreg); + emit_move_insn (fin_dst = gen_reg_rtx (SImode), plus_constant (dst, 4)); + in_words_to_go--; + + if (in_words_to_go) /* Sanity check */ + abort (); + } + + if (in_words_to_go) + { + if (in_words_to_go < 0) + abort (); + + mem = gen_rtx (MEM, SImode, src); + RTX_UNCHANGING_P (mem) = src_unchanging_p; + MEM_IN_STRUCT_P (mem) = src_in_struct_p; + MEM_SCALAR_P (mem) = src_scalar_p; + part_bytes_reg = copy_to_mode_reg (SImode, mem); + } + + if (BYTES_BIG_ENDIAN && last_bytes) + { + rtx tmp = gen_reg_rtx (SImode); + + if (part_bytes_reg == NULL) + abort (); + + /* The bytes we want are in the top end of the word */ + emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, + GEN_INT (8 * (4 - last_bytes)))); + part_bytes_reg = tmp; + + while (last_bytes) + { + mem = gen_rtx (MEM, QImode, plus_constant (dst, last_bytes - 1)); + RTX_UNCHANGING_P (mem) = dst_unchanging_p; + MEM_IN_STRUCT_P (mem) = dst_in_struct_p; + MEM_SCALAR_P (mem) = dst_scalar_p; + emit_move_insn (mem, gen_rtx (SUBREG, QImode, part_bytes_reg, 0)); + if (--last_bytes) + { + tmp = gen_reg_rtx (SImode); + emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (8))); + part_bytes_reg = tmp; + } + } + + } + else + { + while (last_bytes) + { + if (part_bytes_reg == NULL) + abort (); + + mem = gen_rtx (MEM, QImode, dst); + RTX_UNCHANGING_P (mem) = dst_unchanging_p; + MEM_IN_STRUCT_P (mem) = dst_in_struct_p; + MEM_SCALAR_P (mem) = dst_scalar_p; + emit_move_insn (mem, gen_rtx (SUBREG, QImode, part_bytes_reg, 0)); + if (--last_bytes) + { + rtx tmp = gen_reg_rtx (SImode); + + emit_insn (gen_addsi3 (dst, dst, const1_rtx)); + emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (8))); + part_bytes_reg = tmp; + } + } + } + + return 1; +} + +/* Generate a memory reference for a half word, such that it will be loaded + into the top 16 bits of the word. We can assume that the address is + known to be alignable and of the form reg, or plus (reg, const). */ +rtx +gen_rotated_half_load (memref) + rtx memref; +{ + HOST_WIDE_INT offset = 0; + rtx base = XEXP (memref, 0); + + if (GET_CODE (base) == PLUS) + { + offset = INTVAL (XEXP (base, 1)); + base = XEXP (base, 0); + } + + /* If we aren't allowed to generate unaligned addresses, then fail. */ + if (TARGET_SHORT_BY_BYTES + && ((BYTES_BIG_ENDIAN ? 1 : 0) ^ ((offset & 2) == 0))) + return NULL; + + base = gen_rtx (MEM, SImode, plus_constant (base, offset & ~2)); + + if ((BYTES_BIG_ENDIAN ? 1 : 0) ^ ((offset & 2) == 2)) + return base; + + return gen_rtx (ROTATE, SImode, base, GEN_INT (16)); +} + +static enum machine_mode +select_dominance_cc_mode (op, x, y, cond_or) + enum rtx_code op; + rtx x; + rtx y; + HOST_WIDE_INT cond_or; +{ + enum rtx_code cond1, cond2; + int swapped = 0; + + /* Currently we will probably get the wrong result if the individual + comparisons are not simple. This also ensures that it is safe to + reverse a comparison if necessary. */ + if ((arm_select_cc_mode (cond1 = GET_CODE (x), XEXP (x, 0), XEXP (x, 1)) + != CCmode) + || (arm_select_cc_mode (cond2 = GET_CODE (y), XEXP (y, 0), XEXP (y, 1)) + != CCmode)) + return CCmode; + + if (cond_or) + cond1 = reverse_condition (cond1); + + /* If the comparisons are not equal, and one doesn't dominate the other, + then we can't do this. */ + if (cond1 != cond2 + && ! comparison_dominates_p (cond1, cond2) + && (swapped = 1, ! comparison_dominates_p (cond2, cond1))) + return CCmode; + + if (swapped) + { + enum rtx_code temp = cond1; + cond1 = cond2; + cond2 = temp; + } + + switch (cond1) + { + case EQ: + if (cond2 == EQ || ! cond_or) + return CC_DEQmode; + + switch (cond2) + { + case LE: return CC_DLEmode; + case LEU: return CC_DLEUmode; + case GE: return CC_DGEmode; + case GEU: return CC_DGEUmode; + default: break; + } + + break; + + case LT: + if (cond2 == LT || ! cond_or) + return CC_DLTmode; + if (cond2 == LE) + return CC_DLEmode; + if (cond2 == NE) + return CC_DNEmode; + break; + + case GT: + if (cond2 == GT || ! cond_or) + return CC_DGTmode; + if (cond2 == GE) + return CC_DGEmode; + if (cond2 == NE) + return CC_DNEmode; + break; + + case LTU: + if (cond2 == LTU || ! cond_or) + return CC_DLTUmode; + if (cond2 == LEU) + return CC_DLEUmode; + if (cond2 == NE) + return CC_DNEmode; + break; + + case GTU: + if (cond2 == GTU || ! cond_or) + return CC_DGTUmode; + if (cond2 == GEU) + return CC_DGEUmode; + if (cond2 == NE) + return CC_DNEmode; + break; + + /* The remaining cases only occur when both comparisons are the + same. */ + case NE: + return CC_DNEmode; + + case LE: + return CC_DLEmode; + + case GE: + return CC_DGEmode; + + case LEU: + return CC_DLEUmode; + + case GEU: + return CC_DGEUmode; + + default: + break; + } + + abort (); +} + +enum machine_mode +arm_select_cc_mode (op, x, y) + enum rtx_code op; + rtx x; + rtx y; +{ + /* All floating point compares return CCFP if it is an equality + comparison, and CCFPE otherwise. */ + if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) + return (op == EQ || op == NE) ? CCFPmode : CCFPEmode; + + /* A compare with a shifted operand. Because of canonicalization, the + comparison will have to be swapped when we emit the assembler. */ + if (GET_MODE (y) == SImode && GET_CODE (y) == REG + && (GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT + || GET_CODE (x) == LSHIFTRT || GET_CODE (x) == ROTATE + || GET_CODE (x) == ROTATERT)) + return CC_SWPmode; + + /* This is a special case that is used by combine to allow a + comparison of a shifted byte load to be split into a zero-extend + followed by a comparison of the shifted integer (only valid for + equalities and unsigned inequalities). */ + if (GET_MODE (x) == SImode + && GET_CODE (x) == ASHIFT + && GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) == 24 + && GET_CODE (XEXP (x, 0)) == SUBREG + && GET_CODE (SUBREG_REG (XEXP (x, 0))) == MEM + && GET_MODE (SUBREG_REG (XEXP (x, 0))) == QImode + && (op == EQ || op == NE + || op == GEU || op == GTU || op == LTU || op == LEU) + && GET_CODE (y) == CONST_INT) + return CC_Zmode; + + /* An operation that sets the condition codes as a side-effect, the + V flag is not set correctly, so we can only use comparisons where + this doesn't matter. (For LT and GE we can use "mi" and "pl" + instead. */ + if (GET_MODE (x) == SImode + && y == const0_rtx + && (op == EQ || op == NE || op == LT || op == GE) + && (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS + || GET_CODE (x) == AND || GET_CODE (x) == IOR + || GET_CODE (x) == XOR || GET_CODE (x) == MULT + || GET_CODE (x) == NOT || GET_CODE (x) == NEG + || GET_CODE (x) == LSHIFTRT + || GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT + || GET_CODE (x) == ROTATERT || GET_CODE (x) == ZERO_EXTRACT)) + return CC_NOOVmode; + + /* A construct for a conditional compare, if the false arm contains + 0, then both conditions must be true, otherwise either condition + must be true. Not all conditions are possible, so CCmode is + returned if it can't be done. */ + if (GET_CODE (x) == IF_THEN_ELSE + && (XEXP (x, 2) == const0_rtx + || XEXP (x, 2) == const1_rtx) + && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<' + && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<') + return select_dominance_cc_mode (op, XEXP (x, 0), XEXP (x, 1), + INTVAL (XEXP (x, 2))); + + if (GET_MODE (x) == QImode && (op == EQ || op == NE)) + return CC_Zmode; + + if (GET_MODE (x) == SImode && (op == LTU || op == GEU) + && GET_CODE (x) == PLUS + && (rtx_equal_p (XEXP (x, 0), y) || rtx_equal_p (XEXP (x, 1), y))) + return CC_Cmode; + + return CCmode; +} + +/* X and Y are two things to compare using CODE. Emit the compare insn and + return the rtx for register 0 in the proper mode. FP means this is a + floating point compare: I don't think that it is needed on the arm. */ + +rtx +gen_compare_reg (code, x, y, fp) + enum rtx_code code; + rtx x, y; + int fp; +{ + enum machine_mode mode = SELECT_CC_MODE (code, x, y); + rtx cc_reg = gen_rtx (REG, mode, 24); + + emit_insn (gen_rtx (SET, VOIDmode, cc_reg, + gen_rtx (COMPARE, mode, x, y))); + + return cc_reg; +} + +void +arm_reload_in_hi (operands) + rtx *operands; +{ + rtx base = find_replacement (&XEXP (operands[1], 0)); + + emit_insn (gen_zero_extendqisi2 (operands[2], gen_rtx (MEM, QImode, base))); + /* Handle the case where the address is too complex to be offset by 1. */ + if (GET_CODE (base) == MINUS + || (GET_CODE (base) == PLUS && GET_CODE (XEXP (base, 1)) != CONST_INT)) + { + rtx base_plus = gen_rtx (REG, SImode, REGNO (operands[0])); + + emit_insn (gen_rtx (SET, VOIDmode, base_plus, base)); + base = base_plus; + } + + emit_insn (gen_zero_extendqisi2 (gen_rtx (SUBREG, SImode, operands[0], 0), + gen_rtx (MEM, QImode, + plus_constant (base, 1)))); + if (BYTES_BIG_ENDIAN) + emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (SUBREG, SImode, + operands[0], 0), + gen_rtx (IOR, SImode, + gen_rtx (ASHIFT, SImode, + gen_rtx (SUBREG, SImode, + operands[0], 0), + GEN_INT (8)), + operands[2]))); + else + emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (SUBREG, SImode, + operands[0], 0), + gen_rtx (IOR, SImode, + gen_rtx (ASHIFT, SImode, + operands[2], + GEN_INT (8)), + gen_rtx (SUBREG, SImode, operands[0], 0)))); +} + +void +arm_reload_out_hi (operands) + rtx *operands; +{ + rtx base = find_replacement (&XEXP (operands[0], 0)); + + if (BYTES_BIG_ENDIAN) + { + emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (base, 1)), + gen_rtx (SUBREG, QImode, operands[1], 0))); + emit_insn (gen_lshrsi3 (operands[2], + gen_rtx (SUBREG, SImode, operands[1], 0), + GEN_INT (8))); + emit_insn (gen_movqi (gen_rtx (MEM, QImode, base), + gen_rtx (SUBREG, QImode, operands[2], 0))); + } + else + { + emit_insn (gen_movqi (gen_rtx (MEM, QImode, base), + gen_rtx (SUBREG, QImode, operands[1], 0))); + emit_insn (gen_lshrsi3 (operands[2], + gen_rtx (SUBREG, SImode, operands[1], 0), + GEN_INT (8))); + emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (base, 1)), + gen_rtx (SUBREG, QImode, operands[2], 0))); + } +} + +/* CYGNUS LOCAL */ +/* Check to see if a branch is forwards or backwards. Return TRUE if it + is backwards. */ + +int +arm_backwards_branch (from, to) + int from, to; +{ + return insn_addresses[to] <= insn_addresses[from]; +} + +/* Check to see if a branch is within the distance that can be done using + an arithmetic expression. */ +int +short_branch (from, to) + int from, to; +{ + int delta = insn_addresses[from] + 8 - insn_addresses[to]; + + return abs (delta) < 980; /* A small margin for safety */ +} + +/* Check to see that the insn isn't the target of the conditionalizing + code */ +int +arm_insn_not_targeted (insn) + rtx insn; +{ + return insn != arm_target_insn; +} +/* END CYGNUS LOCAL */ + +/* Routines for manipulation of the constant pool. */ +/* This is unashamedly hacked from the version in sh.c, since the problem is + extremely similar. */ + +/* Arm instructions cannot load a large constant into a register, + constants have to come from a pc relative load. The reference of a pc + relative load instruction must be less than 1k infront of the instruction. + This means that we often have to dump a constant inside a function, and + generate code to branch around it. + + It is important to minimize this, since the branches will slow things + down and make things bigger. + + Worst case code looks like: + + ldr rn, L1 + b L2 + align + L1: .long value + L2: + .. + + ldr rn, L3 + b L4 + align + L3: .long value + L4: + .. + + We fix this by performing a scan before scheduling, which notices which + instructions need to have their operands fetched from the constant table + and builds the table. + + + The algorithm is: + + scan, find an instruction which needs a pcrel move. Look forward, find th + last barrier which is within MAX_COUNT bytes of the requirement. + If there isn't one, make one. Process all the instructions between + the find and the barrier. + + In the above example, we can tell that L3 is within 1k of L1, so + the first move can be shrunk from the 2 insn+constant sequence into + just 1 insn, and the constant moved to L3 to make: + + ldr rn, L1 + .. + ldr rn, L3 + b L4 + align + L1: .long value + L3: .long value + L4: + + Then the second move becomes the target for the shortening process. + + */ + +typedef struct +{ + rtx value; /* Value in table */ + HOST_WIDE_INT next_offset; + enum machine_mode mode; /* Mode of value */ +} pool_node; + +/* The maximum number of constants that can fit into one pool, since + the pc relative range is 0...1020 bytes and constants are at least 4 + bytes long */ + +#define MAX_POOL_SIZE (1020/4) +static pool_node pool_vector[MAX_POOL_SIZE]; +static int pool_size; +static rtx pool_vector_label; + +/* Add a constant to the pool and return its offset within the current + pool. + + X is the rtx we want to replace. MODE is its mode. On return, + ADDRESS_ONLY will be non-zero if we really want the address of such + a constant, not the constant itself. */ +static HOST_WIDE_INT +add_constant (x, mode, address_only) + rtx x; + enum machine_mode mode; + int * address_only; +{ + int i; + HOST_WIDE_INT offset; + + * address_only = 0; + + if (mode == SImode && GET_CODE (x) == MEM && CONSTANT_P (XEXP (x, 0)) + && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0))) + x = get_pool_constant (XEXP (x, 0)); + else if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P(x)) + { + *address_only = 1; + mode = get_pool_mode (x); + x = get_pool_constant (x); + } +#ifndef AOF_ASSEMBLER + else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == 3) + x = XVECEXP (x, 0, 0); +#endif + +#ifdef AOF_ASSEMBLER + /* PIC Symbol references need to be converted into offsets into the + based area. */ + if (flag_pic && GET_CODE (x) == SYMBOL_REF) + x = aof_pic_entry (x); +#endif /* AOF_ASSEMBLER */ + + /* First see if we've already got it */ + for (i = 0; i < pool_size; i++) + { + if (GET_CODE (x) == pool_vector[i].value->code + && mode == pool_vector[i].mode) + { + if (GET_CODE (x) == CODE_LABEL) + { + if (XINT (x, 3) != XINT (pool_vector[i].value, 3)) + continue; + } + if (rtx_equal_p (x, pool_vector[i].value)) + return pool_vector[i].next_offset - GET_MODE_SIZE (mode); + } + } + + /* Need a new one */ + pool_vector[pool_size].next_offset = GET_MODE_SIZE (mode); + offset = 0; + if (pool_size == 0) + pool_vector_label = gen_label_rtx (); + else + pool_vector[pool_size].next_offset + += (offset = pool_vector[pool_size - 1].next_offset); + + pool_vector[pool_size].value = x; + pool_vector[pool_size].mode = mode; + pool_size++; + return offset; +} + +/* Output the literal table */ +static void +dump_table (scan) + rtx scan; +{ + int i; + + scan = emit_label_after (gen_label_rtx (), scan); + scan = emit_insn_after (gen_align_4 (), scan); + scan = emit_label_after (pool_vector_label, scan); + + for (i = 0; i < pool_size; i++) + { + pool_node *p = pool_vector + i; + + switch (GET_MODE_SIZE (p->mode)) + { + case 4: + scan = emit_insn_after (gen_consttable_4 (p->value), scan); + break; + + case 8: + scan = emit_insn_after (gen_consttable_8 (p->value), scan); + break; + + default: + abort (); + break; + } + } + + scan = emit_insn_after (gen_consttable_end (), scan); + scan = emit_barrier_after (scan); + pool_size = 0; +} + +/* Non zero if the src operand needs to be fixed up */ +static int +fixit (src, mode, destreg) + rtx src; + enum machine_mode mode; + int destreg; +{ + if (CONSTANT_P (src)) + { + if (GET_CODE (src) == CONST_INT) + return (! const_ok_for_arm (INTVAL (src)) + && ! const_ok_for_arm (~INTVAL (src))); + if (GET_CODE (src) == CONST_DOUBLE) + return (GET_MODE (src) == VOIDmode + || destreg < 16 + || (! const_double_rtx_ok_for_fpu (src) + && ! neg_const_double_rtx_ok_for_fpu (src))); + return symbol_mentioned_p (src); + } +#ifndef AOF_ASSEMBLER + else if (GET_CODE (src) == UNSPEC && XINT (src, 1) == 3) + return 1; +#endif + else + return (mode == SImode && GET_CODE (src) == MEM + && GET_CODE (XEXP (src, 0)) == SYMBOL_REF + && CONSTANT_POOL_ADDRESS_P (XEXP (src, 0))); +} + +/* Find the last barrier less than MAX_COUNT bytes from FROM, or create one. */ +static rtx +find_barrier (from, max_count) + rtx from; + int max_count; +{ + int count = 0; + rtx found_barrier = 0; + rtx last = from; + + while (from && count < max_count) + { + rtx tmp; + + if (GET_CODE (from) == BARRIER) + found_barrier = from; + + /* Count the length of this insn */ + if (GET_CODE (from) == INSN + && GET_CODE (PATTERN (from)) == SET + && CONSTANT_P (SET_SRC (PATTERN (from))) + && CONSTANT_POOL_ADDRESS_P (SET_SRC (PATTERN (from)))) + count += 8; + /* Handle table jumps as a single entity. */ + else if (GET_CODE (from) == JUMP_INSN + && JUMP_LABEL (from) != 0 + && ((tmp = next_real_insn (JUMP_LABEL (from))) + == next_real_insn (from)) + && tmp != NULL + && GET_CODE (tmp) == JUMP_INSN + && (GET_CODE (PATTERN (tmp)) == ADDR_VEC + || GET_CODE (PATTERN (tmp)) == ADDR_DIFF_VEC)) + { + int elt = GET_CODE (PATTERN (tmp)) == ADDR_DIFF_VEC ? 1 : 0; + count += (get_attr_length (from) + + GET_MODE_SIZE (SImode) * XVECLEN (PATTERN (tmp), elt)); + /* Continue after the dispatch table. */ + last = from; + from = NEXT_INSN (tmp); + continue; + } + else + count += get_attr_length (from); + + last = from; + from = NEXT_INSN (from); + } + + if (! found_barrier) + { + /* We didn't find a barrier in time to + dump our stuff, so we'll make one. */ + rtx label = gen_label_rtx (); + + if (from) + from = PREV_INSN (last); + else + from = get_last_insn (); + + /* Walk back to be just before any jump. */ + while (GET_CODE (from) == JUMP_INSN + || GET_CODE (from) == NOTE + || GET_CODE (from) == CODE_LABEL) + from = PREV_INSN (from); + + from = emit_jump_insn_after (gen_jump (label), from); + JUMP_LABEL (from) = label; + found_barrier = emit_barrier_after (from); + emit_label_after (label, found_barrier); + } + + return found_barrier; +} + +/* Non zero if the insn is a move instruction which needs to be fixed. */ +static int +broken_move (insn) + rtx insn; +{ + if (!INSN_DELETED_P (insn) + && GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == SET) + { + rtx pat = PATTERN (insn); + rtx src = SET_SRC (pat); + rtx dst = SET_DEST (pat); + int destreg; + enum machine_mode mode = GET_MODE (dst); + + if (dst == pc_rtx) + return 0; + + if (GET_CODE (dst) == REG) + destreg = REGNO (dst); + else if (GET_CODE (dst) == SUBREG && GET_CODE (SUBREG_REG (dst)) == REG) + destreg = REGNO (SUBREG_REG (dst)); + else + return 0; + + return fixit (src, mode, destreg); + } + return 0; +} + +void +arm_reorg (first) + rtx first; +{ + rtx insn; + int count_size; + +#if 0 + /* The ldr instruction can work with up to a 4k offset, and most constants + will be loaded with one of these instructions; however, the adr + instruction and the ldf instructions only work with a 1k offset. This + code needs to be rewritten to use the 4k offset when possible, and to + adjust when a 1k offset is needed. For now we just use a 1k offset + from the start. */ + count_size = 4000; + + /* Floating point operands can't work further than 1024 bytes from the + PC, so to make things simple we restrict all loads for such functions. + */ + if (TARGET_HARD_FLOAT) + { + int regno; + + for (regno = 16; regno < 24; regno++) + if (regs_ever_live[regno]) + { + count_size = 1000; + break; + } + } +#else + count_size = 1000; +#endif /* 0 */ + + for (insn = first; insn; insn = NEXT_INSN (insn)) + { + if (broken_move (insn)) + { + /* This is a broken move instruction, scan ahead looking for + a barrier to stick the constant table behind */ + rtx scan; + rtx barrier = find_barrier (insn, count_size); + + /* Now find all the moves between the points and modify them */ + for (scan = insn; scan != barrier; scan = NEXT_INSN (scan)) + { + if (broken_move (scan)) + { + /* This is a broken move instruction, add it to the pool */ + rtx pat = PATTERN (scan); + rtx src = SET_SRC (pat); + rtx dst = SET_DEST (pat); + enum machine_mode mode = GET_MODE (dst); + HOST_WIDE_INT offset; + rtx newinsn = scan; + rtx newsrc; + rtx addr; + int scratch; + int address_only; + + /* If this is an HImode constant load, convert it into + an SImode constant load. Since the register is always + 32 bits this is safe. We have to do this, since the + load pc-relative instruction only does a 32-bit load. */ + if (mode == HImode) + { + mode = SImode; + if (GET_CODE (dst) != REG) + abort (); + PUT_MODE (dst, SImode); + } + + offset = add_constant (src, mode, &address_only); + addr = plus_constant (gen_rtx (LABEL_REF, VOIDmode, + pool_vector_label), + offset); + + /* If we only want the address of the pool entry, or + for wide moves to integer regs we need to split + the address calculation off into a separate insn. + If necessary, the load can then be done with a + load-multiple. This is safe, since we have + already noted the length of such insns to be 8, + and we are immediately over-writing the scratch + we have grabbed with the final result. */ + if ((address_only || GET_MODE_SIZE (mode) > 4) + && (scratch = REGNO (dst)) < 16) + { + rtx reg; + + if (mode == SImode) + reg = dst; + else + reg = gen_rtx (REG, SImode, scratch); + + newinsn = emit_insn_after (gen_movaddr (reg, addr), + newinsn); + addr = reg; + } + + if (! address_only) + { + newsrc = gen_rtx (MEM, mode, addr); + + /* XXX Fixme -- I think the following is bogus. */ + /* Build a jump insn wrapper around the move instead + of an ordinary insn, because we want to have room for + the target label rtx in fld[7], which an ordinary + insn doesn't have. */ + newinsn = emit_jump_insn_after + (gen_rtx (SET, VOIDmode, dst, newsrc), newinsn); + JUMP_LABEL (newinsn) = pool_vector_label; + + /* But it's still an ordinary insn */ + PUT_CODE (newinsn, INSN); + } + + /* Kill old insn */ + delete_insn (scan); + scan = newinsn; + } + } + dump_table (barrier); + insn = scan; + } + } + + after_arm_reorg = 1; +} + + +/* Routines to output assembly language. */ + +/* If the rtx is the correct value then return the string of the number. + In this way we can ensure that valid double constants are generated even + when cross compiling. */ +char * +fp_immediate_constant (x) + rtx x; +{ + REAL_VALUE_TYPE r; + int i; + + if (!fpa_consts_inited) + init_fpa_table (); + + REAL_VALUE_FROM_CONST_DOUBLE (r, x); + for (i = 0; i < 8; i++) + if (REAL_VALUES_EQUAL (r, values_fpa[i])) + return strings_fpa[i]; + + abort (); +} + +/* As for fp_immediate_constant, but value is passed directly, not in rtx. */ +static char * +fp_const_from_val (r) + REAL_VALUE_TYPE *r; +{ + int i; + + if (! fpa_consts_inited) + init_fpa_table (); + + for (i = 0; i < 8; i++) + if (REAL_VALUES_EQUAL (*r, values_fpa[i])) + return strings_fpa[i]; + + abort (); +} + +/* Output the operands of a LDM/STM instruction to STREAM. + MASK is the ARM register set mask of which only bits 0-15 are important. + INSTR is the possibly suffixed base register. HAT unequals zero if a hat + must follow the register list. */ + +void +print_multi_reg (stream, instr, mask, hat) + FILE *stream; + char *instr; + int mask, hat; +{ + int i; + int not_first = FALSE; + + fputc ('\t', stream); + fprintf (stream, instr, REGISTER_PREFIX); + fputs (", {", stream); + for (i = 0; i < 16; i++) + if (mask & (1 << i)) + { + if (not_first) + fprintf (stream, ", "); + fprintf (stream, "%s%s", REGISTER_PREFIX, reg_names[i]); + not_first = TRUE; + } + + fprintf (stream, "}%s\n", hat ? "^" : ""); +} + +/* Output a 'call' insn. */ + +char * +output_call (operands) + rtx *operands; +{ + /* Handle calls to lr using ip (which may be clobbered in subr anyway). */ + + if (REGNO (operands[0]) == 14) + { + operands[0] = gen_rtx (REG, SImode, 12); + output_asm_insn ("mov%?\t%0, %|lr", operands); + } + output_asm_insn ("mov%?\t%|lr, %|pc", operands); + + if (TARGET_THUMB_INTERWORK) + output_asm_insn ("bx%?\t%0", operands); + else + output_asm_insn ("mov%?\t%|pc, %0", operands); + + return ""; +} + +static int +eliminate_lr2ip (x) + rtx *x; +{ + int something_changed = 0; + rtx x0 = *x; + int code = GET_CODE (x0); + register int i, j; + register char *fmt; + + switch (code) + { + case REG: + if (REGNO (x0) == 14) + { + *x = gen_rtx (REG, SImode, 12); + return 1; + } + return 0; + default: + /* Scan through the sub-elements and change any references there */ + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + if (fmt[i] == 'e') + something_changed |= eliminate_lr2ip (&XEXP (x0, i)); + else if (fmt[i] == 'E') + for (j = 0; j < XVECLEN (x0, i); j++) + something_changed |= eliminate_lr2ip (&XVECEXP (x0, i, j)); + return something_changed; + } +} + +/* Output a 'call' insn that is a reference in memory. */ + +char * +output_call_mem (operands) + rtx *operands; +{ + operands[0] = copy_rtx (operands[0]); /* Be ultra careful */ + /* Handle calls using lr by using ip (which may be clobbered in subr anyway). + */ + if (eliminate_lr2ip (&operands[0])) + output_asm_insn ("mov%?\t%|ip, %|lr", operands); + + if (TARGET_THUMB_INTERWORK) + { + output_asm_insn ("ldr%?\t%|ip, %0", operands); + output_asm_insn ("mov%?\t%|lr, %|pc", operands); + output_asm_insn ("bx%?\t%|ip", operands); + } + else + { + output_asm_insn ("mov%?\t%|lr, %|pc", operands); + output_asm_insn ("ldr%?\t%|pc, %0", operands); + } + + return ""; +} + + +/* Output a move from arm registers to an fpu registers. + OPERANDS[0] is an fpu register. + OPERANDS[1] is the first registers of an arm register pair. */ + +char * +output_mov_long_double_fpu_from_arm (operands) + rtx *operands; +{ + int arm_reg0 = REGNO (operands[1]); + rtx ops[3]; + + if (arm_reg0 == 12) + abort(); + + ops[0] = gen_rtx (REG, SImode, arm_reg0); + ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0); + ops[2] = gen_rtx (REG, SImode, 2 + arm_reg0); + + output_asm_insn ("stm%?fd\t%|sp!, {%0, %1, %2}", ops); + output_asm_insn ("ldf%?e\t%0, [%|sp], #12", operands); + return ""; +} + +/* Output a move from an fpu register to arm registers. + OPERANDS[0] is the first registers of an arm register pair. + OPERANDS[1] is an fpu register. */ + +char * +output_mov_long_double_arm_from_fpu (operands) + rtx *operands; +{ + int arm_reg0 = REGNO (operands[0]); + rtx ops[3]; + + if (arm_reg0 == 12) + abort(); + + ops[0] = gen_rtx (REG, SImode, arm_reg0); + ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0); + ops[2] = gen_rtx (REG, SImode, 2 + arm_reg0); + + output_asm_insn ("stf%?e\t%1, [%|sp, #-12]!", operands); + output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1, %2}", ops); + return ""; +} + +/* Output a move from arm registers to arm registers of a long double + OPERANDS[0] is the destination. + OPERANDS[1] is the source. */ +char * +output_mov_long_double_arm_from_arm (operands) + rtx *operands; +{ + /* We have to be careful here because the two might overlap */ + int dest_start = REGNO (operands[0]); + int src_start = REGNO (operands[1]); + rtx ops[2]; + int i; + + if (dest_start < src_start) + { + for (i = 0; i < 3; i++) + { + ops[0] = gen_rtx (REG, SImode, dest_start + i); + ops[1] = gen_rtx (REG, SImode, src_start + i); + output_asm_insn ("mov%?\t%0, %1", ops); + } + } + else + { + for (i = 2; i >= 0; i--) + { + ops[0] = gen_rtx (REG, SImode, dest_start + i); + ops[1] = gen_rtx (REG, SImode, src_start + i); + output_asm_insn ("mov%?\t%0, %1", ops); + } + } + + return ""; +} + + +/* Output a move from arm registers to an fpu registers. + OPERANDS[0] is an fpu register. + OPERANDS[1] is the first registers of an arm register pair. */ + +char * +output_mov_double_fpu_from_arm (operands) + rtx *operands; +{ + int arm_reg0 = REGNO (operands[1]); + rtx ops[2]; + + if (arm_reg0 == 12) + abort(); + ops[0] = gen_rtx (REG, SImode, arm_reg0); + ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0); + output_asm_insn ("stm%?fd\t%|sp!, {%0, %1}", ops); + output_asm_insn ("ldf%?d\t%0, [%|sp], #8", operands); + return ""; +} + +/* Output a move from an fpu register to arm registers. + OPERANDS[0] is the first registers of an arm register pair. + OPERANDS[1] is an fpu register. */ + +char * +output_mov_double_arm_from_fpu (operands) + rtx *operands; +{ + int arm_reg0 = REGNO (operands[0]); + rtx ops[2]; + + if (arm_reg0 == 12) + abort(); + + ops[0] = gen_rtx (REG, SImode, arm_reg0); + ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0); + output_asm_insn ("stf%?d\t%1, [%|sp, #-8]!", operands); + output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1}", ops); + return ""; +} + +/* Output a move between double words. + It must be REG<-REG, REG<-CONST_DOUBLE, REG<-CONST_INT, REG<-MEM + or MEM<-REG and all MEMs must be offsettable addresses. */ + +char * +output_move_double (operands) + rtx *operands; +{ + enum rtx_code code0 = GET_CODE (operands[0]); + enum rtx_code code1 = GET_CODE (operands[1]); + rtx otherops[3]; + + if (code0 == REG) + { + int reg0 = REGNO (operands[0]); + + otherops[0] = gen_rtx (REG, SImode, 1 + reg0); + if (code1 == REG) + { + int reg1 = REGNO (operands[1]); + if (reg1 == 12) + abort(); + + /* Ensure the second source is not overwritten */ + if (reg1 == reg0 + (WORDS_BIG_ENDIAN ? -1 : 1)) + output_asm_insn("mov%?\t%Q0, %Q1\n\tmov%?\t%R0, %R1", operands); + else + output_asm_insn("mov%?\t%R0, %R1\n\tmov%?\t%Q0, %Q1", operands); + } + else if (code1 == CONST_DOUBLE) + { + if (GET_MODE (operands[1]) == DFmode) + { + long l[2]; + union real_extract u; + + bcopy ((char *) &CONST_DOUBLE_LOW (operands[1]), (char *) &u, + sizeof (u)); + REAL_VALUE_TO_TARGET_DOUBLE (u.d, l); + otherops[1] = GEN_INT(l[1]); + operands[1] = GEN_INT(l[0]); + } + else if (GET_MODE (operands[1]) != VOIDmode) + abort (); + else if (WORDS_BIG_ENDIAN) + { + + otherops[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1])); + operands[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1])); + } + else + { + + otherops[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1])); + operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1])); + } + output_mov_immediate (operands); + output_mov_immediate (otherops); + } + else if (code1 == CONST_INT) + { +#if HOST_BITS_PER_WIDE_INT > 32 + /* If HOST_WIDE_INT is more than 32 bits, the intval tells us + what the upper word is. */ + if (WORDS_BIG_ENDIAN) + { + otherops[1] = GEN_INT (ARM_SIGN_EXTEND (INTVAL (operands[1]))); + operands[1] = GEN_INT (INTVAL (operands[1]) >> 32); + } + else + { + otherops[1] = GEN_INT (INTVAL (operands[1]) >> 32); + operands[1] = GEN_INT (ARM_SIGN_EXTEND (INTVAL (operands[1]))); + } +#else + /* Sign extend the intval into the high-order word */ + if (WORDS_BIG_ENDIAN) + { + otherops[1] = operands[1]; + operands[1] = (INTVAL (operands[1]) < 0 + ? constm1_rtx : const0_rtx); + } + else + otherops[1] = INTVAL (operands[1]) < 0 ? constm1_rtx : const0_rtx; +#endif + output_mov_immediate (otherops); + output_mov_immediate (operands); + } + else if (code1 == MEM) + { + switch (GET_CODE (XEXP (operands[1], 0))) + { + case REG: + output_asm_insn ("ldm%?ia\t%m1, %M0", operands); + break; + + case PRE_INC: + abort (); /* Should never happen now */ + break; + + case PRE_DEC: + output_asm_insn ("ldm%?db\t%m1!, %M0", operands); + break; + + case POST_INC: + output_asm_insn ("ldm%?ia\t%m1!, %M0", operands); + break; + + case POST_DEC: + abort (); /* Should never happen now */ + break; + + case LABEL_REF: + case CONST: + output_asm_insn ("adr%?\t%0, %1", operands); + output_asm_insn ("ldm%?ia\t%0, %M0", operands); + break; + + default: + if (arm_add_operand (XEXP (XEXP (operands[1], 0), 1))) + { + otherops[0] = operands[0]; + otherops[1] = XEXP (XEXP (operands[1], 0), 0); + otherops[2] = XEXP (XEXP (operands[1], 0), 1); + if (GET_CODE (XEXP (operands[1], 0)) == PLUS) + { + if (GET_CODE (otherops[2]) == CONST_INT) + { + switch (INTVAL (otherops[2])) + { + case -8: + output_asm_insn ("ldm%?db\t%1, %M0", otherops); + return ""; + case -4: + output_asm_insn ("ldm%?da\t%1, %M0", otherops); + return ""; + case 4: + output_asm_insn ("ldm%?ib\t%1, %M0", otherops); + return ""; + } + if (!(const_ok_for_arm (INTVAL (otherops[2])))) + output_asm_insn ("sub%?\t%0, %1, #%n2", otherops); + else + output_asm_insn ("add%?\t%0, %1, %2", otherops); + } + else + output_asm_insn ("add%?\t%0, %1, %2", otherops); + } + else + output_asm_insn ("sub%?\t%0, %1, %2", otherops); + return "ldm%?ia\t%0, %M0"; + } + else + { + otherops[1] = adj_offsettable_operand (operands[1], 4); + /* Take care of overlapping base/data reg. */ + if (reg_mentioned_p (operands[0], operands[1])) + { + output_asm_insn ("ldr%?\t%0, %1", otherops); + output_asm_insn ("ldr%?\t%0, %1", operands); + } + else + { + output_asm_insn ("ldr%?\t%0, %1", operands); + output_asm_insn ("ldr%?\t%0, %1", otherops); + } + } + } + } + else + abort(); /* Constraints should prevent this */ + } + else if (code0 == MEM && code1 == REG) + { + if (REGNO (operands[1]) == 12) + abort(); + + switch (GET_CODE (XEXP (operands[0], 0))) + { + case REG: + output_asm_insn ("stm%?ia\t%m0, %M1", operands); + break; + + case PRE_INC: + abort (); /* Should never happen now */ + break; + + case PRE_DEC: + output_asm_insn ("stm%?db\t%m0!, %M1", operands); + break; + + case POST_INC: + output_asm_insn ("stm%?ia\t%m0!, %M1", operands); + break; + + case POST_DEC: + abort (); /* Should never happen now */ + break; + + case PLUS: + if (GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT) + { + switch (INTVAL (XEXP (XEXP (operands[0], 0), 1))) + { + case -8: + output_asm_insn ("stm%?db\t%m0, %M1", operands); + return ""; + + case -4: + output_asm_insn ("stm%?da\t%m0, %M1", operands); + return ""; + + case 4: + output_asm_insn ("stm%?ib\t%m0, %M1", operands); + return ""; + } + } + /* Fall through */ + + default: + otherops[0] = adj_offsettable_operand (operands[0], 4); + otherops[1] = gen_rtx (REG, SImode, 1 + REGNO (operands[1])); + output_asm_insn ("str%?\t%1, %0", operands); + output_asm_insn ("str%?\t%1, %0", otherops); + } + } + else + abort(); /* Constraints should prevent this */ + + return ""; +} + + +/* Output an arbitrary MOV reg, #n. + OPERANDS[0] is a register. OPERANDS[1] is a const_int. */ + +char * +output_mov_immediate (operands) + rtx *operands; +{ + HOST_WIDE_INT n = INTVAL (operands[1]); + int n_ones = 0; + int i; + + /* Try to use one MOV */ + if (const_ok_for_arm (n)) + { + output_asm_insn ("mov%?\t%0, %1", operands); + return ""; + } + + /* Try to use one MVN */ + if (const_ok_for_arm (~n)) + { + operands[1] = GEN_INT (~n); + output_asm_insn ("mvn%?\t%0, %1", operands); + return ""; + } + + /* If all else fails, make it out of ORRs or BICs as appropriate. */ + + for (i=0; i < 32; i++) + if (n & 1 << i) + n_ones++; + + if (n_ones > 16) /* Shorter to use MVN with BIC in this case. */ + output_multi_immediate(operands, "mvn%?\t%0, %1", "bic%?\t%0, %0, %1", 1, + ~n); + else + output_multi_immediate(operands, "mov%?\t%0, %1", "orr%?\t%0, %0, %1", 1, + n); + + return ""; +} + + +/* Output an ADD r, s, #n where n may be too big for one instruction. If + adding zero to one register, output nothing. */ + +char * +output_add_immediate (operands) + rtx *operands; +{ + HOST_WIDE_INT n = INTVAL (operands[2]); + + if (n != 0 || REGNO (operands[0]) != REGNO (operands[1])) + { + if (n < 0) + output_multi_immediate (operands, + "sub%?\t%0, %1, %2", "sub%?\t%0, %0, %2", 2, + -n); + else + output_multi_immediate (operands, + "add%?\t%0, %1, %2", "add%?\t%0, %0, %2", 2, + n); + } + + return ""; +} + +/* Output a multiple immediate operation. + OPERANDS is the vector of operands referred to in the output patterns. + INSTR1 is the output pattern to use for the first constant. + INSTR2 is the output pattern to use for subsequent constants. + IMMED_OP is the index of the constant slot in OPERANDS. + N is the constant value. */ + +static char * +output_multi_immediate (operands, instr1, instr2, immed_op, n) + rtx *operands; + char *instr1, *instr2; + int immed_op; + HOST_WIDE_INT n; +{ +#if HOST_BITS_PER_WIDE_INT > 32 + n &= 0xffffffff; +#endif + + if (n == 0) + { + operands[immed_op] = const0_rtx; + output_asm_insn (instr1, operands); /* Quick and easy output */ + } + else + { + int i; + char *instr = instr1; + + /* Note that n is never zero here (which would give no output) */ + for (i = 0; i < 32; i += 2) + { + if (n & (3 << i)) + { + operands[immed_op] = GEN_INT (n & (255 << i)); + output_asm_insn (instr, operands); + instr = instr2; + i += 6; + } + } + } + return ""; +} + + +/* Return the appropriate ARM instruction for the operation code. + The returned result should not be overwritten. OP is the rtx of the + operation. SHIFT_FIRST_ARG is TRUE if the first argument of the operator + was shifted. */ + +char * +arithmetic_instr (op, shift_first_arg) + rtx op; + int shift_first_arg; +{ + switch (GET_CODE (op)) + { + case PLUS: + return "add"; + + case MINUS: + return shift_first_arg ? "rsb" : "sub"; + + case IOR: + return "orr"; + + case XOR: + return "eor"; + + case AND: + return "and"; + + default: + abort (); + } +} + + +/* Ensure valid constant shifts and return the appropriate shift mnemonic + for the operation code. The returned result should not be overwritten. + OP is the rtx code of the shift. + On exit, *AMOUNTP will be -1 if the shift is by a register, or a constant + shift. */ + +static char * +shift_op (op, amountp) + rtx op; + HOST_WIDE_INT *amountp; +{ + char *mnem; + enum rtx_code code = GET_CODE (op); + + if (GET_CODE (XEXP (op, 1)) == REG || GET_CODE (XEXP (op, 1)) == SUBREG) + *amountp = -1; + else if (GET_CODE (XEXP (op, 1)) == CONST_INT) + *amountp = INTVAL (XEXP (op, 1)); + else + abort (); + + switch (code) + { + case ASHIFT: + mnem = "asl"; + break; + + case ASHIFTRT: + mnem = "asr"; + break; + + case LSHIFTRT: + mnem = "lsr"; + break; + + case ROTATERT: + mnem = "ror"; + break; + + case MULT: + /* We never have to worry about the amount being other than a + power of 2, since this case can never be reloaded from a reg. */ + if (*amountp != -1) + *amountp = int_log2 (*amountp); + else + abort (); + return "asl"; + + default: + abort (); + } + + if (*amountp != -1) + { + /* This is not 100% correct, but follows from the desire to merge + multiplication by a power of 2 with the recognizer for a + shift. >=32 is not a valid shift for "asl", so we must try and + output a shift that produces the correct arithmetical result. + Using lsr #32 is identical except for the fact that the carry bit + is not set correctly if we set the flags; but we never use the + carry bit from such an operation, so we can ignore that. */ + if (code == ROTATERT) + *amountp &= 31; /* Rotate is just modulo 32 */ + else if (*amountp != (*amountp & 31)) + { + if (code == ASHIFT) + mnem = "lsr"; + *amountp = 32; + } + + /* Shifts of 0 are no-ops. */ + if (*amountp == 0) + return NULL; + } + + return mnem; +} + + +/* Obtain the shift from the POWER of two. */ + +static HOST_WIDE_INT +int_log2 (power) + HOST_WIDE_INT power; +{ + HOST_WIDE_INT shift = 0; + + while (((((HOST_WIDE_INT) 1) << shift) & power) == 0) + { + if (shift > 31) + abort (); + shift++; + } + + return shift; +} + +/* Output a .ascii pseudo-op, keeping track of lengths. This is because + /bin/as is horribly restrictive. */ + +void +output_ascii_pseudo_op (stream, p, len) + FILE *stream; + unsigned char *p; + int len; +{ + int i; + int len_so_far = 1000; + int chars_so_far = 0; + + for (i = 0; i < len; i++) + { + register int c = p[i]; + + if (len_so_far > 50) + { + if (chars_so_far) + fputs ("\"\n", stream); + fputs ("\t.ascii\t\"", stream); + len_so_far = 0; + /* CYGNUS LOCAL */ + arm_increase_location (chars_so_far); + /* END CYGNUS LOCAL */ + chars_so_far = 0; + } + + if (c == '\"' || c == '\\') + { + putc('\\', stream); + len_so_far++; + } + + if (c >= ' ' && c < 0177) + { + putc (c, stream); + len_so_far++; + } + else + { + fprintf (stream, "\\%03o", c); + len_so_far +=4; + } + + chars_so_far++; + } + + fputs ("\"\n", stream); + /* CYGNUS LOCAL */ + arm_increase_location (chars_so_far); + /* END CYGNUS LOCAL */ +} + + +/* Try to determine whether a pattern really clobbers the link register. + This information is useful when peepholing, so that lr need not be pushed + if we combine a call followed by a return. + NOTE: This code does not check for side-effect expressions in a SET_SRC: + such a check should not be needed because these only update an existing + value within a register; the register must still be set elsewhere within + the function. */ + +static int +pattern_really_clobbers_lr (x) + rtx x; +{ + int i; + + switch (GET_CODE (x)) + { + case SET: + switch (GET_CODE (SET_DEST (x))) + { + case REG: + return REGNO (SET_DEST (x)) == 14; + + case SUBREG: + if (GET_CODE (XEXP (SET_DEST (x), 0)) == REG) + return REGNO (XEXP (SET_DEST (x), 0)) == 14; + + if (GET_CODE (XEXP (SET_DEST (x), 0)) == MEM) + return 0; + abort (); + + default: + return 0; + } + + case PARALLEL: + for (i = 0; i < XVECLEN (x, 0); i++) + if (pattern_really_clobbers_lr (XVECEXP (x, 0, i))) + return 1; + return 0; + + case CLOBBER: + switch (GET_CODE (XEXP (x, 0))) + { + case REG: + return REGNO (XEXP (x, 0)) == 14; + + case SUBREG: + if (GET_CODE (XEXP (XEXP (x, 0), 0)) == REG) + return REGNO (XEXP (XEXP (x, 0), 0)) == 14; + abort (); + + default: + return 0; + } + + case UNSPEC: + return 1; + + default: + return 0; + } +} + +static int +function_really_clobbers_lr (first) + rtx first; +{ + rtx insn, next; + + for (insn = first; insn; insn = next_nonnote_insn (insn)) + { + switch (GET_CODE (insn)) + { + case BARRIER: + case NOTE: + case CODE_LABEL: + case JUMP_INSN: /* Jump insns only change the PC (and conds) */ + case INLINE_HEADER: + break; + + case INSN: + if (pattern_really_clobbers_lr (PATTERN (insn))) + return 1; + break; + + case CALL_INSN: + /* Don't yet know how to handle those calls that are not to a + SYMBOL_REF */ + if (GET_CODE (PATTERN (insn)) != PARALLEL) + abort (); + + switch (GET_CODE (XVECEXP (PATTERN (insn), 0, 0))) + { + case CALL: + if (GET_CODE (XEXP (XEXP (XVECEXP (PATTERN (insn), 0, 0), 0), 0)) + != SYMBOL_REF) + return 1; + break; + + case SET: + if (GET_CODE (XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (insn), + 0, 0)), 0), 0)) + != SYMBOL_REF) + return 1; + break; + + default: /* Don't recognize it, be safe */ + return 1; + } + + /* A call can be made (by peepholing) not to clobber lr iff it is + followed by a return. There may, however, be a use insn iff + we are returning the result of the call. + If we run off the end of the insn chain, then that means the + call was at the end of the function. Unfortunately we don't + have a return insn for the peephole to recognize, so we + must reject this. (Can this be fixed by adding our own insn?) */ + if ((next = next_nonnote_insn (insn)) == NULL) + return 1; + + /* No need to worry about lr if the call never returns */ + if (GET_CODE (next) == BARRIER) + break; + + if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == USE + && (GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET) + && (REGNO (SET_DEST (XVECEXP (PATTERN (insn), 0, 0))) + == REGNO (XEXP (PATTERN (next), 0)))) + if ((next = next_nonnote_insn (next)) == NULL) + return 1; + + if (GET_CODE (next) == JUMP_INSN + && GET_CODE (PATTERN (next)) == RETURN) + break; + return 1; + + default: + abort (); + } + } + + /* We have reached the end of the chain so lr was _not_ clobbered */ + return 0; +} + +char * +output_return_instruction (operand, really_return, reverse) + rtx operand; + int really_return; + int reverse; +{ + char instr[100]; + int reg, live_regs = 0; + int volatile_func = (optimize > 0 + && TREE_THIS_VOLATILE (current_function_decl)); + + return_used_this_function = 1; + + if (volatile_func) + { + rtx ops[2]; + /* If this function was declared non-returning, and we have found a tail + call, then we have to trust that the called function won't return. */ + if (! really_return) + return ""; + + /* Otherwise, trap an attempted return by aborting. */ + ops[0] = operand; + ops[1] = gen_rtx (SYMBOL_REF, Pmode, "abort"); + assemble_external_libcall (ops[1]); + output_asm_insn (reverse ? "bl%D0\t%a1" : "bl%d0\t%a1", ops); + return ""; + } + + if (current_function_calls_alloca && ! really_return) + abort(); + + for (reg = 0; reg <= 10; reg++) + if (regs_ever_live[reg] && ! call_used_regs[reg]) + live_regs++; + + if (live_regs || (regs_ever_live[14] && ! lr_save_eliminated)) + live_regs++; + + if (frame_pointer_needed) + live_regs += 4; + + if (live_regs) + { + if (lr_save_eliminated || ! regs_ever_live[14]) + live_regs++; + + if (frame_pointer_needed) + strcpy (instr, + reverse ? "ldm%?%D0ea\t%|fp, {" : "ldm%?%d0ea\t%|fp, {"); + else + strcpy (instr, + reverse ? "ldm%?%D0fd\t%|sp!, {" : "ldm%?%d0fd\t%|sp!, {"); + + for (reg = 0; reg <= 10; reg++) + if (regs_ever_live[reg] && ! call_used_regs[reg]) + { + strcat (instr, "%|"); + strcat (instr, reg_names[reg]); + if (--live_regs) + strcat (instr, ", "); + } + + if (frame_pointer_needed) + { + strcat (instr, "%|"); + strcat (instr, reg_names[11]); + strcat (instr, ", "); + strcat (instr, "%|"); + strcat (instr, reg_names[13]); + strcat (instr, ", "); + strcat (instr, "%|"); + strcat (instr, TARGET_THUMB_INTERWORK || (! really_return) + ? reg_names[14] : reg_names[15] ); + } + else + { + strcat (instr, "%|"); + if (TARGET_THUMB_INTERWORK && really_return) + strcat (instr, reg_names[12]); + else + strcat (instr, really_return ? reg_names[15] : reg_names[14]); + } + strcat (instr, (TARGET_APCS_32 || !really_return) ? "}" : "}^"); + output_asm_insn (instr, &operand); + + if (TARGET_THUMB_INTERWORK && really_return) + { + strcpy (instr, "bx%?"); + strcat (instr, reverse ? "%D0" : "%d0"); + strcat (instr, "\t%|"); + strcat (instr, frame_pointer_needed ? "lr" : "ip"); + + output_asm_insn (instr, & operand); + } + } + else if (really_return) + { + /* CYGNUS LOCAL unknown */ + if (operand && GET_MODE_CLASS (GET_MODE (XEXP (operand, 0))) != MODE_CC) + output_asm_insn ("ldr%?\t%|ip, %0", & operand); + /* END CYGNUS LOCAL */ + + if (TARGET_THUMB_INTERWORK) + sprintf (instr, "bx%%?%%%s0\t%%|lr", reverse ? "D" : "d"); + else + sprintf (instr, "mov%%?%%%s0%s\t%%|pc, %%|lr", + reverse ? "D" : "d", TARGET_APCS_32 ? "" : "s"); + + output_asm_insn (instr, & operand); + } + + return ""; +} + +/* Return nonzero if optimizing and the current function is volatile. + Such functions never return, and many memory cycles can be saved + by not storing register values that will never be needed again. + This optimization was added to speed up context switching in a + kernel application. */ + +int +arm_volatile_func () +{ + return (optimize > 0 && TREE_THIS_VOLATILE (current_function_decl)); +} + +/* CYGNUS LOCAL unknown */ +/* Return the size of the prologue. It's not too bad if we slightly + over-estimate. */ + +static int +get_prologue_size () +{ + return profile_flag ? 12 : 0; +} +/* END CYGNUS LOCAL */ + +/* The amount of stack adjustment that happens here, in output_return and in + output_epilogue must be exactly the same as was calculated during reload, + or things will point to the wrong place. The only time we can safely + ignore this constraint is when a function has no arguments on the stack, + no stack frame requirement and no live registers execpt for `lr'. If we + can guarantee that by making all function calls into tail calls and that + lr is not clobbered in any other way, then there is no need to push lr + onto the stack. */ + +void +output_func_prologue (f, frame_size) + FILE *f; + int frame_size; +{ + int reg, live_regs_mask = 0; + int volatile_func = (optimize > 0 + && TREE_THIS_VOLATILE (current_function_decl)); + + /* Nonzero if we must stuff some register arguments onto the stack as if + they were passed there. */ + int store_arg_regs = 0; + + if (arm_ccfsm_state || arm_target_insn) + abort (); /* Sanity check */ + + if (arm_naked_function_p (current_function_decl)) + return; + + return_used_this_function = 0; + lr_save_eliminated = 0; + + fprintf (f, "\t%s args = %d, pretend = %d, frame = %d\n", + ASM_COMMENT_START, current_function_args_size, + current_function_pretend_args_size, frame_size); + fprintf (f, "\t%s frame_needed = %d, current_function_anonymous_args = %d\n", + ASM_COMMENT_START, frame_pointer_needed, + current_function_anonymous_args); + + if (volatile_func) + fprintf (f, "\t%s Volatile function.\n", ASM_COMMENT_START); + + if (current_function_anonymous_args && current_function_pretend_args_size) + store_arg_regs = 1; + + for (reg = 0; reg <= 10; reg++) + if (regs_ever_live[reg] && ! call_used_regs[reg]) + live_regs_mask |= (1 << reg); + + if (frame_pointer_needed) + live_regs_mask |= 0xD800; + else if (regs_ever_live[14]) + { + if (! current_function_args_size + && ! function_really_clobbers_lr (get_insns ())) + lr_save_eliminated = 1; + else + live_regs_mask |= 0x4000; + } + + if (live_regs_mask) + { + /* if a di mode load/store multiple is used, and the base register + is r3, then r4 can become an ever live register without lr + doing so, in this case we need to push lr as well, or we + will fail to get a proper return. */ + + live_regs_mask |= 0x4000; + lr_save_eliminated = 0; + + } + + if (lr_save_eliminated) + fprintf (f,"\t%s I don't think this function clobbers lr\n", + ASM_COMMENT_START); + +#ifdef AOF_ASSEMBLER + if (flag_pic) + fprintf (f, "\tmov\t%sip, %s%s\n", REGISTER_PREFIX, REGISTER_PREFIX, + reg_names[PIC_OFFSET_TABLE_REGNUM]); +#endif +} + + +void +output_func_epilogue (f, frame_size) + FILE *f; + int frame_size; +{ + int reg, live_regs_mask = 0; + /* CYGNUS LOCAL unknown */ + int code_size = 0; + /* END CYGNUS LOCAL */ + /* If we need this then it will always be at least this much */ + int floats_offset = 12; + rtx operands[3]; + int volatile_func = (optimize > 0 + && TREE_THIS_VOLATILE (current_function_decl)); + + if (use_return_insn (FALSE) && return_used_this_function) + { + if ((frame_size + current_function_outgoing_args_size) != 0 + /* CYGNUS LOCAL bug fix */ + && !(frame_pointer_needed && TARGET_APCS)) + /* END CYGNUS LOCAL */ + abort (); + goto epilogue_done; + } + + /* Naked functions don't have epilogues. */ + if (arm_naked_function_p (current_function_decl)) + goto epilogue_done; + + /* A volatile function should never return. Call abort. */ + if (TARGET_ABORT_NORETURN && volatile_func) + { + rtx op = gen_rtx (SYMBOL_REF, Pmode, "abort"); + assemble_external_libcall (op); + output_asm_insn ("bl\t%a0", &op); + /* CYGNUS LOCAL unknown */ + code_size = 4; + /* END CYGNUS LOCAL */ + goto epilogue_done; + } + + for (reg = 0; reg <= 10; reg++) + if (regs_ever_live[reg] && ! call_used_regs[reg]) + { + live_regs_mask |= (1 << reg); + floats_offset += 4; + } + + if (frame_pointer_needed) + { + if (arm_fpu_arch == FP_SOFT2) + { + for (reg = 23; reg > 15; reg--) + if (regs_ever_live[reg] && ! call_used_regs[reg]) + { + floats_offset += 12; + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + fprintf (f, "\tldfe\t%s%s, [%sfp, #-%d]\n", REGISTER_PREFIX, + reg_names[reg], REGISTER_PREFIX, floats_offset); + } + } + else + { + int start_reg = 23; + + for (reg = 23; reg > 15; reg--) + { + if (regs_ever_live[reg] && ! call_used_regs[reg]) + { + floats_offset += 12; + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + /* We can't unstack more than four registers at once */ + if (start_reg - reg == 3) + { + fprintf (f, "\tlfm\t%s%s, 4, [%sfp, #-%d]\n", + REGISTER_PREFIX, reg_names[reg], + REGISTER_PREFIX, floats_offset); + start_reg = reg - 1; + } + } + else + { + if (reg != start_reg) + /* CYGNUS LOCAL unknown */ + { + code_size += 4; + fprintf (f, "\tlfm\t%s%s, %d, [%sfp, #-%d]\n", + REGISTER_PREFIX, reg_names[reg + 1], + start_reg - reg, REGISTER_PREFIX, floats_offset); + } + /* END CYGNUS LOCAL */ + start_reg = reg - 1; + } + } + + /* Just in case the last register checked also needs unstacking. */ + if (reg != start_reg) + /* CYGNUS LOCAL unknown */ + { + code_size += 4; + fprintf (f, "\tlfm\t%s%s, %d, [%sfp, #-%d]\n", + REGISTER_PREFIX, reg_names[reg + 1], + start_reg - reg, REGISTER_PREFIX, floats_offset); + } + /* END CYGNUS LOCAL */ + } + + if (TARGET_THUMB_INTERWORK) + { + live_regs_mask |= 0x6800; + print_multi_reg (f, "ldmea\t%sfp", live_regs_mask, FALSE); + fprintf (f, "\tbx\t%slr\n", REGISTER_PREFIX); + /* CYGNUS LOCAL unknown */ + code_size += 8; + /* END CYGNUS LOCAL */ + } + else + { + live_regs_mask |= 0xA800; + print_multi_reg (f, "ldmea\t%sfp", live_regs_mask, + TARGET_APCS_32 ? FALSE : TRUE); + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + } + } + else + { + /* Restore stack pointer if necessary. */ + if (frame_size + current_function_outgoing_args_size != 0) + { + operands[0] = operands[1] = stack_pointer_rtx; + operands[2] = GEN_INT (frame_size + + current_function_outgoing_args_size); + output_add_immediate (operands); + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + } + + if (arm_fpu_arch == FP_SOFT2) + { + for (reg = 16; reg < 24; reg++) + if (regs_ever_live[reg] && ! call_used_regs[reg]) + { + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + fprintf (f, "\tldfe\t%s%s, [%ssp], #12\n", REGISTER_PREFIX, + reg_names[reg], REGISTER_PREFIX); + } + } + else + { + int start_reg = 16; + + for (reg = 16; reg < 24; reg++) + { + if (regs_ever_live[reg] && ! call_used_regs[reg]) + { + if (reg - start_reg == 3) + { + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + fprintf (f, "\tlfmfd\t%s%s, 4, [%ssp]!\n", + REGISTER_PREFIX, reg_names[start_reg], + REGISTER_PREFIX); + start_reg = reg + 1; + } + } + else + { + if (reg != start_reg) + { + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + fprintf (f, "\tlfmfd\t%s%s, %d, [%ssp]!\n", + REGISTER_PREFIX, reg_names[start_reg], + reg - start_reg, REGISTER_PREFIX); + } + + start_reg = reg + 1; + } + } + + /* Just in case the last register checked also needs unstacking. */ + if (reg != start_reg) + { + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + fprintf (f, "\tlfmfd\t%s%s, %d, [%ssp]!\n", + REGISTER_PREFIX, reg_names[start_reg], + reg - start_reg, REGISTER_PREFIX); + } + } + + if (current_function_pretend_args_size == 0 && regs_ever_live[14]) + { + if (TARGET_THUMB_INTERWORK) + { + /* CYGNUS LOCAL */ + if (! lr_save_eliminated) + live_regs_mask |= 0x4000; + + if (live_regs_mask != 0) + { + code_size += 4; + print_multi_reg (f, "ldmfd\t%ssp!", live_regs_mask, FALSE); + } + /* END CYGNUS LOCAL */ + + fprintf (f, "\tbx\t%slr\n", REGISTER_PREFIX); + } + else if (lr_save_eliminated) + fprintf (f, (TARGET_APCS_32 ? "\tmov\t%spc, %slr\n" + : "\tmovs\t%spc, %slr\n"), + REGISTER_PREFIX, REGISTER_PREFIX, f); + else + print_multi_reg (f, "ldmfd\t%ssp!", live_regs_mask | 0x8000, + TARGET_APCS_32 ? FALSE : TRUE); + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + } + else + { + if (live_regs_mask || regs_ever_live[14]) + { + /* Restore the integer regs, and the return address into lr */ + if (! lr_save_eliminated) + live_regs_mask |= 0x4000; + + if (live_regs_mask != 0) + /* CYGNUS LOCAL unknown */ + { + code_size += 4; + print_multi_reg (f, "ldmfd\t%ssp!", live_regs_mask, FALSE); + } + /* END CYGNUS LOCAL */ + } + + if (current_function_pretend_args_size) + { + /* Unwind the pre-pushed regs */ + operands[0] = operands[1] = stack_pointer_rtx; + operands[2] = GEN_INT (current_function_pretend_args_size); + output_add_immediate (operands); + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + } + /* And finally, go home */ + if (TARGET_THUMB_INTERWORK) + fprintf (f, "\tbx\t%slr\n", REGISTER_PREFIX); + else if (TARGET_APCS_32) + fprintf (f, "\tmov\t%spc, %slr\n", REGISTER_PREFIX, REGISTER_PREFIX ); + else + fprintf (f, "\tmovs\t%spc, %slr\n", REGISTER_PREFIX, REGISTER_PREFIX ); + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + } + } + +epilogue_done: + + /* CYGNUS LOCAL unknown */ + if (optimize > 0) + arm_increase_location (code_size + + insn_addresses[INSN_UID (get_last_insn ())] + + get_prologue_size ()); + /* END CYGNUS LOCAL */ + + current_function_anonymous_args = 0; + after_arm_reorg = 0; +} + +static void +emit_multi_reg_push (mask) + int mask; +{ + int num_regs = 0; + int i, j; + rtx par; + + for (i = 0; i < 16; i++) + if (mask & (1 << i)) + num_regs++; + + if (num_regs == 0 || num_regs > 16) + abort (); + + par = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (num_regs)); + + for (i = 0; i < 16; i++) + { + if (mask & (1 << i)) + { + XVECEXP (par, 0, 0) + = gen_rtx (SET, VOIDmode, gen_rtx (MEM, BLKmode, + gen_rtx (PRE_DEC, BLKmode, + stack_pointer_rtx)), + gen_rtx (UNSPEC, BLKmode, + gen_rtvec (1, gen_rtx (REG, SImode, i)), + 2)); + break; + } + } + + for (j = 1, i++; j < num_regs; i++) + { + if (mask & (1 << i)) + { + XVECEXP (par, 0, j) + = gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, i)); + j++; + } + } + + emit_insn (par); +} + +static void +emit_sfm (base_reg, count) + int base_reg; + int count; +{ + rtx par; + int i; + + par = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (count)); + + XVECEXP (par, 0, 0) = gen_rtx (SET, VOIDmode, + gen_rtx (MEM, BLKmode, + gen_rtx (PRE_DEC, BLKmode, + stack_pointer_rtx)), + gen_rtx (UNSPEC, BLKmode, + gen_rtvec (1, gen_rtx (REG, XFmode, + base_reg++)), + 2)); + for (i = 1; i < count; i++) + XVECEXP (par, 0, i) = gen_rtx (USE, VOIDmode, + gen_rtx (REG, XFmode, base_reg++)); + + emit_insn (par); +} + +void +arm_expand_prologue () +{ + int reg; + rtx amount = GEN_INT (-(get_frame_size () + + current_function_outgoing_args_size)); + int live_regs_mask = 0; + int store_arg_regs = 0; + /* CYGNUS LOCAL unknown */ + int sp_overflow_check = 0; + /* END CYGNUS LOCAL */ + int volatile_func = (optimize > 0 + && TREE_THIS_VOLATILE (current_function_decl)); + + /* Naked functions don't have prologues. */ + if (arm_naked_function_p (current_function_decl)) + return; + + if (current_function_anonymous_args && current_function_pretend_args_size) + store_arg_regs = 1; + + if (! volatile_func) + for (reg = 0; reg <= 10; reg++) + if (regs_ever_live[reg] && ! call_used_regs[reg]) + live_regs_mask |= 1 << reg; + + if (! volatile_func && regs_ever_live[14]) + live_regs_mask |= 0x4000; + + if (frame_pointer_needed) + { + live_regs_mask |= 0xD800; + emit_insn (gen_movsi (gen_rtx (REG, SImode, 12), + stack_pointer_rtx)); + } + + if (current_function_pretend_args_size) + { + if (store_arg_regs) + emit_multi_reg_push ((0xf0 >> (current_function_pretend_args_size / 4)) + & 0xf); + else + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (-current_function_pretend_args_size))); + } + + if (live_regs_mask) + { + /* If we have to push any regs, then we must push lr as well, or + we won't get a proper return. */ + live_regs_mask |= 0x4000; + emit_multi_reg_push (live_regs_mask); + } + + /* For now the integer regs are still pushed in output_func_epilogue (). */ + + if (! volatile_func) + { + if (arm_fpu_arch == FP_SOFT2) + { + for (reg = 23; reg > 15; reg--) + if (regs_ever_live[reg] && ! call_used_regs[reg]) + emit_insn (gen_rtx (SET, VOIDmode, + gen_rtx (MEM, XFmode, + gen_rtx (PRE_DEC, XFmode, + stack_pointer_rtx)), + gen_rtx (REG, XFmode, reg))); + } + else + { + int start_reg = 23; + + for (reg = 23; reg > 15; reg--) + { + if (regs_ever_live[reg] && ! call_used_regs[reg]) + { + if (start_reg - reg == 3) + { + emit_sfm (reg, 4); + start_reg = reg - 1; + } + } + else + { + if (start_reg != reg) + emit_sfm (reg + 1, start_reg - reg); + start_reg = reg - 1; + } + } + + if (start_reg != reg) + emit_sfm (reg + 1, start_reg - reg); + } + } + + if (frame_pointer_needed) + emit_insn (gen_addsi3 (hard_frame_pointer_rtx, gen_rtx (REG, SImode, 12), + (GEN_INT + (-(4 + current_function_pretend_args_size))))); + + /* CYGNUS LOCAL */ + /* The arm vxworks group wants the instructions setting up the frame */ + /* to be unscheduled or unbroken */ + if (TARGET_NO_SCHED_PRO) + emit_insn (gen_blockage ()); + + /* Checking whether the frame amount is zero is not a good enough + marker for deciding whether we need to check for stack overflow. + We are interested in whether anything has/is being stored on the + stack. Since GCC always creates the frame structure at the + moment, this is always true. When we add a machine specific flag + to allow leaf functions to avoid creating an entry frame we will + need to make this conditional (NOTE: This will probably not be a + standard feature, since the debugging world may assume that EVERY + function has a frame, whereas it is not actually a requirement of + the APCS). */ + if (TARGET_APCS_STACK) + { + int bound = get_frame_size (); + + /* The software stack overflow handler has two forms. The first + is for small stack frames, where 256bytes or less of stack is + required: + __rt_stkovf_split_small + + The second is for bigger stack frames of more than 256bytes: + __rt_stkovf_split_big + + The run-time *MUST* provide these routines when software + stack checking is enabled. After calling one of the above + routines the fp/r11 and sp/r12 registers do not necessarily + point into the same stack chunk. This means that arguments + passed on the stack *MUST* be addressed by offsets from + fp/r11 and *NOT* from sp/r13. The sl/r10 register should + always be at the bottom of the current stack chunk, with at + least 256bytes of stack available beneath it (this allows for + leaf functions that use less than 256bytes of stack to avoid + the stack limit check, aswell as giving the overflow + functions some workspace). + + NOTE: The stack-checking APCS does *NOT* cope with alloca(), + since the amount of stack required is not known until + run-time. Similarly the use of run-time sized vectors causes + the same problem. This means that the handler routines + should only be used for raising aborts at the moment, and not + for providing stack chunk extension. + + TODO: Check code generated for late stack pointer + modifications. The APCS allows for these, but a similar + stack overflow check and call must be inserted. */ + + if (bound < 256) + { + /* Leaf functions that use less than 256bytes of stack do + not need to perform a check: */ + if (frame_pointer_needed) + { + /* Stop the prologue being re-ordered: */ + emit_insn (gen_blockage ()); + emit_insn (gen_cond_call (stack_pointer_rtx, + gen_rtx (REG, SImode, 10), + gen_rtx (SYMBOL_REF, Pmode, + "*__rt_stkovf_split_small"), + gen_rtx (LTU, SImode, 24))); + sp_overflow_check = 1; + } + } + else + { + rtx bamount; + + if (!frame_pointer_needed) + abort (); + + if (!const_ok_for_arm ((HOST_WIDE_INT) bound)) + { + /* Find the closest 8bit rotated (by even amount) value + above bound: */ + int count; + for (count = 0; ((bound >> count) & ~0xFF); count +=2); + bound = (bound & (0xFF << count)) + (1 << count); + } + bamount = GEN_INT (- bound); + + emit_insn (gen_blockage ()); /* stop prologue being re-ordered */ + emit_insn (gen_addsi3 (gen_rtx (REG, SImode, 12), + stack_pointer_rtx, bamount)); + emit_insn (gen_cond_call (gen_rtx (REG, SImode, 12), + gen_rtx (REG, SImode, 10), + gen_rtx (SYMBOL_REF, Pmode, + "*__rt_stkovf_split_big"), + gen_rtx (LTU, SImode, 24))); + sp_overflow_check = 1; + } + } + /* END CYGNUS LOCAL */ + + if (amount != const0_rtx) + { + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, amount)); + emit_insn (gen_rtx (CLOBBER, VOIDmode, + gen_rtx (MEM, BLKmode, stack_pointer_rtx))); + } + + /* CYGNUS LOCAL */ + /* If we are profiling, make sure no instructions are scheduled before + the call to mcount. Similarly do not allow instructions + to be moved to before the stack overflow check or if the user has + requested no scheduling in the prolog. */ + if (profile_flag || profile_block_flag || sp_overflow_check) + emit_insn (gen_blockage ()); + /* END CYGNUS LOCAL */ +} + + +/* If CODE is 'd', then the X is a condition operand and the instruction + should only be executed if the condition is true. + if CODE is 'D', then the X is a condition operand and the instruction + should only be executed if the condition is false: however, if the mode + of the comparison is CCFPEmode, then always execute the instruction -- we + do this because in these circumstances !GE does not necessarily imply LT; + in these cases the instruction pattern will take care to make sure that + an instruction containing %d will follow, thereby undoing the effects of + doing this instruction unconditionally. + If CODE is 'N' then X is a floating point operand that must be negated + before output. + If CODE is 'B' then output a bitwise inverted value of X (a const int). + If X is a REG and CODE is `M', output a ldm/stm style multi-reg. */ + +void +arm_print_operand (stream, x, code) + FILE *stream; + rtx x; + int code; +{ + switch (code) + { + case '@': + fputs (ASM_COMMENT_START, stream); + return; + + case '|': + fputs (REGISTER_PREFIX, stream); + return; + + case '?': + if (arm_ccfsm_state == 3 || arm_ccfsm_state == 4) + fputs (arm_condition_codes[arm_current_cc], stream); + return; + + case 'N': + { + REAL_VALUE_TYPE r; + REAL_VALUE_FROM_CONST_DOUBLE (r, x); + r = REAL_VALUE_NEGATE (r); + fprintf (stream, "%s", fp_const_from_val (&r)); + } + return; + + case 'B': + if (GET_CODE (x) == CONST_INT) + fprintf (stream, +#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT + "%d", +#else + "%ld", +#endif + ARM_SIGN_EXTEND (~ INTVAL (x))); + else + { + putc ('~', stream); + output_addr_const (stream, x); + } + return; + + case 'i': + fprintf (stream, "%s", arithmetic_instr (x, 1)); + return; + + case 'I': + fprintf (stream, "%s", arithmetic_instr (x, 0)); + return; + + case 'S': + { + HOST_WIDE_INT val; + char *shift = shift_op (x, &val); + + if (shift) + { + fprintf (stream, ", %s ", shift_op (x, &val)); + if (val == -1) + arm_print_operand (stream, XEXP (x, 1), 0); + else + fprintf (stream, +#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT + "#%d", +#else + "#%ld", +#endif + val); + } + } + return; + + case 'Q': + if (REGNO (x) > 15) + abort (); + fputs (REGISTER_PREFIX, stream); + fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0)], stream); + return; + + case 'R': + if (REGNO (x) > 15) + abort (); + fputs (REGISTER_PREFIX, stream); + fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1)], stream); + return; + + case 'm': + fputs (REGISTER_PREFIX, stream); + if (GET_CODE (XEXP (x, 0)) == REG) + fputs (reg_names[REGNO (XEXP (x, 0))], stream); + else + fputs (reg_names[REGNO (XEXP (XEXP (x, 0), 0))], stream); + return; + + case 'M': + fprintf (stream, "{%s%s-%s%s}", REGISTER_PREFIX, reg_names[REGNO (x)], + REGISTER_PREFIX, reg_names[REGNO (x) - 1 + + ((GET_MODE_SIZE (GET_MODE (x)) + + GET_MODE_SIZE (SImode) - 1) + / GET_MODE_SIZE (SImode))]); + return; + + case 'd': + if (x) + fputs (arm_condition_codes[get_arm_condition_code (x)], + stream); + return; + + case 'D': + if (x) + fputs (arm_condition_codes[ARM_INVERSE_CONDITION_CODE + (get_arm_condition_code (x))], + stream); + return; + + default: + if (x == 0) + abort (); + + if (GET_CODE (x) == REG) + { + fputs (REGISTER_PREFIX, stream); + fputs (reg_names[REGNO (x)], stream); + } + else if (GET_CODE (x) == MEM) + { + output_memory_reference_mode = GET_MODE (x); + output_address (XEXP (x, 0)); + } + else if (GET_CODE (x) == CONST_DOUBLE) + fprintf (stream, "#%s", fp_immediate_constant (x)); + else if (GET_CODE (x) == NEG) + abort (); /* This should never happen now. */ + else + { + fputc ('#', stream); + output_addr_const (stream, x); + } + } +} + +/* CYGNUS LOCAL unknown */ +/* Increase the `arm_text_location' by AMOUNT if we're in the text + segment. */ + +void +arm_increase_location (amount) + int amount; +{ + if (in_text_section ()) + arm_text_location += amount; +} + + +/* Output a label definition. If this label is within the .text segment, it + is stored in OFFSET_TABLE, to be used when building `llc' instructions. + Maybe GCC remembers names not starting with a `*' for a long time, but this + is a minority anyway, so we just make a copy. Do not store the leading `*' + if the name starts with one. */ + +void +arm_asm_output_label (stream, name) + FILE * stream; + char * name; +{ + char * real_name; + char * s; + struct label_offset *cur; + int hash = 0; + + assemble_name (stream, name); + fputs (":\n", stream); + + if (! in_text_section ()) + return; + + if (name[0] == '*') + { + real_name = xmalloc (1 + strlen (&name[1])); + strcpy (real_name, &name[1]); + } + else + { + real_name = xmalloc (2 + strlen (name)); + strcpy (real_name, user_label_prefix); + strcat (real_name, name); + } + for (s = real_name; *s; s++) + hash += *s; + + hash = hash % LABEL_HASH_SIZE; + cur = (struct label_offset *) xmalloc (sizeof (struct label_offset)); + cur->name = real_name; + cur->offset = arm_text_location; + cur->cdr = offset_table[hash]; + offset_table[hash] = cur; +} +/* END CYGNUS LOCAL */ + +/* A finite state machine takes care of noticing whether or not instructions + can be conditionally executed, and thus decrease execution time and code + size by deleting branch instructions. The fsm is controlled by + final_prescan_insn, and controls the actions of ASM_OUTPUT_OPCODE. */ + +/* The state of the fsm controlling condition codes are: + 0: normal, do nothing special + 1: make ASM_OUTPUT_OPCODE not output this instruction + 2: make ASM_OUTPUT_OPCODE not output this instruction + 3: make instructions conditional + 4: make instructions conditional + + State transitions (state->state by whom under condition): + 0 -> 1 final_prescan_insn if the `target' is a label + 0 -> 2 final_prescan_insn if the `target' is an unconditional branch + 1 -> 3 ASM_OUTPUT_OPCODE after not having output the conditional branch + 2 -> 4 ASM_OUTPUT_OPCODE after not having output the conditional branch + 3 -> 0 ASM_OUTPUT_INTERNAL_LABEL if the `target' label is reached + (the target label has CODE_LABEL_NUMBER equal to arm_target_label). + 4 -> 0 final_prescan_insn if the `target' unconditional branch is reached + (the target insn is arm_target_insn). + + If the jump clobbers the conditions then we use states 2 and 4. + + A similar thing can be done with conditional return insns. + + XXX In case the `target' is an unconditional branch, this conditionalising + of the instructions always reduces code size, but not always execution + time. But then, I want to reduce the code size to somewhere near what + /bin/cc produces. */ + +/* Returns the index of the ARM condition code string in + `arm_condition_codes'. COMPARISON should be an rtx like + `(eq (...) (...))'. */ + +static enum arm_cond_code +get_arm_condition_code (comparison) + rtx comparison; +{ + enum machine_mode mode = GET_MODE (XEXP (comparison, 0)); + register int code; + register enum rtx_code comp_code = GET_CODE (comparison); + + if (GET_MODE_CLASS (mode) != MODE_CC) + mode = SELECT_CC_MODE (comp_code, XEXP (comparison, 0), + XEXP (comparison, 1)); + + switch (mode) + { + case CC_DNEmode: code = ARM_NE; goto dominance; + case CC_DEQmode: code = ARM_EQ; goto dominance; + case CC_DGEmode: code = ARM_GE; goto dominance; + case CC_DGTmode: code = ARM_GT; goto dominance; + case CC_DLEmode: code = ARM_LE; goto dominance; + case CC_DLTmode: code = ARM_LT; goto dominance; + case CC_DGEUmode: code = ARM_CS; goto dominance; + case CC_DGTUmode: code = ARM_HI; goto dominance; + case CC_DLEUmode: code = ARM_LS; goto dominance; + case CC_DLTUmode: code = ARM_CC; + + dominance: + if (comp_code != EQ && comp_code != NE) + abort (); + + if (comp_code == EQ) + return ARM_INVERSE_CONDITION_CODE (code); + return code; + + case CC_NOOVmode: + switch (comp_code) + { + case NE: return ARM_NE; + case EQ: return ARM_EQ; + case GE: return ARM_PL; + case LT: return ARM_MI; + default: abort (); + } + + case CC_Zmode: + case CCFPmode: + switch (comp_code) + { + case NE: return ARM_NE; + case EQ: return ARM_EQ; + default: abort (); + } + + case CCFPEmode: + switch (comp_code) + { + case GE: return ARM_GE; + case GT: return ARM_GT; + case LE: return ARM_LS; + case LT: return ARM_MI; + default: abort (); + } + + case CC_SWPmode: + switch (comp_code) + { + case NE: return ARM_NE; + case EQ: return ARM_EQ; + case GE: return ARM_LE; + case GT: return ARM_LT; + case LE: return ARM_GE; + case LT: return ARM_GT; + case GEU: return ARM_LS; + case GTU: return ARM_CC; + case LEU: return ARM_CS; + case LTU: return ARM_HI; + default: abort (); + } + + case CC_Cmode: + switch (comp_code) + { + case LTU: return ARM_CS; + case GEU: return ARM_CC; + default: abort (); + } + + case CCmode: + switch (comp_code) + { + case NE: return ARM_NE; + case EQ: return ARM_EQ; + case GE: return ARM_GE; + case GT: return ARM_GT; + case LE: return ARM_LE; + case LT: return ARM_LT; + case GEU: return ARM_CS; + case GTU: return ARM_HI; + case LEU: return ARM_LS; + case LTU: return ARM_CC; + default: abort (); + } + + default: abort (); + } + + abort (); +} + + +void +final_prescan_insn (insn, opvec, noperands) + rtx insn; + rtx *opvec; + int noperands; +{ + /* BODY will hold the body of INSN. */ + register rtx body = PATTERN (insn); + + /* This will be 1 if trying to repeat the trick, and things need to be + reversed if it appears to fail. */ + int reverse = 0; + + /* JUMP_CLOBBERS will be one implies that the conditions if a branch is + taken are clobbered, even if the rtl suggests otherwise. It also + means that we have to grub around within the jump expression to find + out what the conditions are when the jump isn't taken. */ + int jump_clobbers = 0; + + /* If we start with a return insn, we only succeed if we find another one. */ + int seeking_return = 0; + + /* START_INSN will hold the insn from where we start looking. This is the + first insn after the following code_label if REVERSE is true. */ + rtx start_insn = insn; + + /* If in state 4, check if the target branch is reached, in order to + change back to state 0. */ + if (arm_ccfsm_state == 4) + { + if (insn == arm_target_insn) + { + arm_target_insn = NULL; + arm_ccfsm_state = 0; + } + return; + } + + /* If in state 3, it is possible to repeat the trick, if this insn is an + unconditional branch to a label, and immediately following this branch + is the previous target label which is only used once, and the label this + branch jumps to is not too far off. */ + if (arm_ccfsm_state == 3) + { + if (simplejump_p (insn)) + { + start_insn = next_nonnote_insn (start_insn); + if (GET_CODE (start_insn) == BARRIER) + { + /* XXX Isn't this always a barrier? */ + start_insn = next_nonnote_insn (start_insn); + } + if (GET_CODE (start_insn) == CODE_LABEL + && CODE_LABEL_NUMBER (start_insn) == arm_target_label + && LABEL_NUSES (start_insn) == 1) + reverse = TRUE; + else + return; + } + else if (GET_CODE (body) == RETURN) + { + start_insn = next_nonnote_insn (start_insn); + if (GET_CODE (start_insn) == BARRIER) + start_insn = next_nonnote_insn (start_insn); + if (GET_CODE (start_insn) == CODE_LABEL + && CODE_LABEL_NUMBER (start_insn) == arm_target_label + && LABEL_NUSES (start_insn) == 1) + { + reverse = TRUE; + seeking_return = 1; + } + else + return; + } + else + return; + } + + if (arm_ccfsm_state != 0 && !reverse) + abort (); + if (GET_CODE (insn) != JUMP_INSN) + return; + + /* This jump might be paralleled with a clobber of the condition codes + the jump should always come first */ + if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0) + body = XVECEXP (body, 0, 0); + +#if 0 + /* If this is a conditional return then we don't want to know */ + if (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC + && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE + && (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN + || GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN)) + return; +#endif + + if (reverse + || (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC + && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE)) + { + int insns_skipped; + int fail = FALSE, succeed = FALSE; + /* Flag which part of the IF_THEN_ELSE is the LABEL_REF. */ + int then_not_else = TRUE; + rtx this_insn = start_insn, label = 0; + + if (get_attr_conds (insn) == CONDS_JUMP_CLOB) + { + /* The code below is wrong for these, and I haven't time to + fix it now. So we just do the safe thing and return. This + whole function needs re-writing anyway. */ + jump_clobbers = 1; + return; + } + + /* Register the insn jumped to. */ + if (reverse) + { + if (!seeking_return) + label = XEXP (SET_SRC (body), 0); + } + else if (GET_CODE (XEXP (SET_SRC (body), 1)) == LABEL_REF) + label = XEXP (XEXP (SET_SRC (body), 1), 0); + else if (GET_CODE (XEXP (SET_SRC (body), 2)) == LABEL_REF) + { + label = XEXP (XEXP (SET_SRC (body), 2), 0); + then_not_else = FALSE; + } + else if (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN) + seeking_return = 1; + else if (GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN) + { + seeking_return = 1; + then_not_else = FALSE; + } + else + abort (); + + /* See how many insns this branch skips, and what kind of insns. If all + insns are okay, and the label or unconditional branch to the same + label is not too far away, succeed. */ + for (insns_skipped = 0; + !fail && !succeed && insns_skipped++ < max_insns_skipped;) + { + rtx scanbody; + + this_insn = next_nonnote_insn (this_insn); + if (!this_insn) + break; + + switch (GET_CODE (this_insn)) + { + case CODE_LABEL: + /* Succeed if it is the target label, otherwise fail since + control falls in from somewhere else. */ + if (this_insn == label) + { + if (jump_clobbers) + { + arm_ccfsm_state = 2; + this_insn = next_nonnote_insn (this_insn); + } + else + arm_ccfsm_state = 1; + succeed = TRUE; + } + else + fail = TRUE; + break; + + case BARRIER: + /* Succeed if the following insn is the target label. + Otherwise fail. + If return insns are used then the last insn in a function + will be a barrier. */ + this_insn = next_nonnote_insn (this_insn); + if (this_insn && this_insn == label) + { + if (jump_clobbers) + { + arm_ccfsm_state = 2; + this_insn = next_nonnote_insn (this_insn); + } + else + arm_ccfsm_state = 1; + succeed = TRUE; + } + else + fail = TRUE; + break; + + case CALL_INSN: + /* If using 32-bit addresses the cc is not preserved over + calls */ + if (TARGET_APCS_32) + { + /* Succeed if the following insn is the target label, + or if the following two insns are a barrier and + the target label. */ + this_insn = next_nonnote_insn (this_insn); + if (this_insn && GET_CODE (this_insn) == BARRIER) + this_insn = next_nonnote_insn (this_insn); + + if (this_insn && this_insn == label + && insns_skipped < max_insns_skipped) + { + if (jump_clobbers) + { + arm_ccfsm_state = 2; + this_insn = next_nonnote_insn (this_insn); + } + else + arm_ccfsm_state = 1; + succeed = TRUE; + } + else + fail = TRUE; + } + break; + + case JUMP_INSN: + /* If this is an unconditional branch to the same label, succeed. + If it is to another label, do nothing. If it is conditional, + fail. */ + /* XXX Probably, the tests for SET and the PC are unnecessary. */ + + scanbody = PATTERN (this_insn); + if (GET_CODE (scanbody) == SET + && GET_CODE (SET_DEST (scanbody)) == PC) + { + if (GET_CODE (SET_SRC (scanbody)) == LABEL_REF + && XEXP (SET_SRC (scanbody), 0) == label && !reverse) + { + arm_ccfsm_state = 2; + succeed = TRUE; + } + else if (GET_CODE (SET_SRC (scanbody)) == IF_THEN_ELSE) + fail = TRUE; + } + /* Fail if a conditional return is undesirable (eg on a + StrongARM), but still allow this if optimizing for size. */ + else if (GET_CODE (scanbody) == RETURN + && ! use_return_insn (TRUE) + && ! optimize_size) + fail = TRUE; + else if (GET_CODE (scanbody) == RETURN + && seeking_return) + { + arm_ccfsm_state = 2; + succeed = TRUE; + } + else if (GET_CODE (scanbody) == PARALLEL) + { + switch (get_attr_conds (this_insn)) + { + case CONDS_NOCOND: + break; + default: + fail = TRUE; + break; + } + } + break; + + case INSN: + /* Instructions using or affecting the condition codes make it + fail. */ + scanbody = PATTERN (this_insn); + if (! (GET_CODE (scanbody) == SET + || GET_CODE (scanbody) == PARALLEL) + || get_attr_conds (this_insn) != CONDS_NOCOND) + fail = TRUE; + break; + + default: + break; + } + } + if (succeed) + { + if ((!seeking_return) && (arm_ccfsm_state == 1 || reverse)) + arm_target_label = CODE_LABEL_NUMBER (label); + else if (seeking_return || arm_ccfsm_state == 2) + { + while (this_insn && GET_CODE (PATTERN (this_insn)) == USE) + { + this_insn = next_nonnote_insn (this_insn); + if (this_insn && (GET_CODE (this_insn) == BARRIER + || GET_CODE (this_insn) == CODE_LABEL)) + abort (); + } + if (!this_insn) + { + /* Oh, dear! we ran off the end.. give up */ + recog (PATTERN (insn), insn, NULL_PTR); + arm_ccfsm_state = 0; + arm_target_insn = NULL; + return; + } + arm_target_insn = this_insn; + } + else + abort (); + if (jump_clobbers) + { + if (reverse) + abort (); + arm_current_cc = + get_arm_condition_code (XEXP (XEXP (XEXP (SET_SRC (body), + 0), 0), 1)); + if (GET_CODE (XEXP (XEXP (SET_SRC (body), 0), 0)) == AND) + arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); + if (GET_CODE (XEXP (SET_SRC (body), 0)) == NE) + arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); + } + else + { + /* If REVERSE is true, ARM_CURRENT_CC needs to be inverted from + what it was. */ + if (!reverse) + arm_current_cc = get_arm_condition_code (XEXP (SET_SRC (body), + 0)); + } + + if (reverse || then_not_else) + arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); + } + /* restore recog_operand (getting the attributes of other insns can + destroy this array, but final.c assumes that it remains intact + across this call; since the insn has been recognized already we + call recog direct). */ + recog (PATTERN (insn), insn, NULL_PTR); + } +} + +#ifdef AOF_ASSEMBLER +/* Special functions only needed when producing AOF syntax assembler. */ + +rtx aof_pic_label = NULL_RTX; +struct pic_chain +{ + struct pic_chain *next; + char *symname; +}; + +static struct pic_chain *aof_pic_chain = NULL; + +rtx +aof_pic_entry (x) + rtx x; +{ + struct pic_chain **chainp; + int offset; + + if (aof_pic_label == NULL_RTX) + { + /* This needs to persist throughout the compilation. */ + end_temporary_allocation (); + aof_pic_label = gen_rtx (SYMBOL_REF, Pmode, "x$adcons"); + resume_temporary_allocation (); + } + + for (offset = 0, chainp = &aof_pic_chain; *chainp; + offset += 4, chainp = &(*chainp)->next) + if ((*chainp)->symname == XSTR (x, 0)) + return plus_constant (aof_pic_label, offset); + + *chainp = (struct pic_chain *) xmalloc (sizeof (struct pic_chain)); + (*chainp)->next = NULL; + (*chainp)->symname = XSTR (x, 0); + return plus_constant (aof_pic_label, offset); +} + +void +aof_dump_pic_table (f) + FILE *f; +{ + struct pic_chain *chain; + + if (aof_pic_chain == NULL) + return; + + fprintf (f, "\tAREA |%s$$adcons|, BASED %s%s\n", + reg_names[PIC_OFFSET_TABLE_REGNUM], REGISTER_PREFIX, + reg_names[PIC_OFFSET_TABLE_REGNUM]); + fputs ("|x$adcons|\n", f); + + for (chain = aof_pic_chain; chain; chain = chain->next) + { + fputs ("\tDCD\t", f); + assemble_name (f, chain->symname); + fputs ("\n", f); + } +} + +int arm_text_section_count = 1; + +char * +aof_text_section () +{ + static char buf[100]; + sprintf (buf, "\tAREA |C$$code%d|, CODE, READONLY", + arm_text_section_count++); + if (flag_pic) + strcat (buf, ", PIC, REENTRANT"); + return buf; +} + +static int arm_data_section_count = 1; + +char * +aof_data_section () +{ + static char buf[100]; + sprintf (buf, "\tAREA |C$$data%d|, DATA", arm_data_section_count++); + return buf; +} + +/* The AOF assembler is religiously strict about declarations of + imported and exported symbols, so that it is impossible to declare + a function as imported near the beginning of the file, and then to + export it later on. It is, however, possible to delay the decision + until all the functions in the file have been compiled. To get + around this, we maintain a list of the imports and exports, and + delete from it any that are subsequently defined. At the end of + compilation we spit the remainder of the list out before the END + directive. */ + +struct import +{ + struct import *next; + char *name; +}; + +static struct import *imports_list = NULL; + +void +aof_add_import (name) + char *name; +{ + struct import *new; + + for (new = imports_list; new; new = new->next) + if (new->name == name) + return; + + new = (struct import *) xmalloc (sizeof (struct import)); + new->next = imports_list; + imports_list = new; + new->name = name; +} + +void +aof_delete_import (name) + char *name; +{ + struct import **old; + + for (old = &imports_list; *old; old = & (*old)->next) + { + if ((*old)->name == name) + { + *old = (*old)->next; + return; + } + } +} + +int arm_main_function = 0; + +void +aof_dump_imports (f) + FILE *f; +{ + /* The AOF assembler needs this to cause the startup code to be extracted + from the library. Brining in __main causes the whole thing to work + automagically. */ + if (arm_main_function) + { + text_section (); + fputs ("\tIMPORT __main\n", f); + fputs ("\tDCD __main\n", f); + } + + /* Now dump the remaining imports. */ + while (imports_list) + { + fprintf (f, "\tIMPORT\t"); + assemble_name (f, imports_list->name); + fputc ('\n', f); + imports_list = imports_list->next; + } +} +#endif /* AOF_ASSEMBLER */ + +/* CYGNUS LOCAL */ + +/* Return non-zero if X is a symbolic operand (contains a SYMBOL_REF). */ +int +symbolic_operand (mode, x) + enum machine_mode mode; + rtx x; +{ + switch (GET_CODE (x)) + { + case CONST_DOUBLE: + case CONST: + case MEM: + case PLUS: + return symbolic_operand (mode, XEXP (x, 0)); + case SYMBOL_REF: + case LABEL_REF: + return 1; + default: + return 0; + } +} + +/* Handle a special case when computing the offset + of an argument from the frame pointer. */ +int +arm_debugger_arg_offset (value, addr) + int value; + struct rtx_def * addr; +{ + rtx insn; + + /* We are only interested if dbxout_parms() failed to compute the offset. */ + if (value != 0) + return 0; + + /* We can only cope with the case where the address is held in a register. */ + if (GET_CODE (addr) != REG) + return 0; + + /* If we are using the frame pointer to point at the argument, then an offset of 0 is correct. */ + if (REGNO (addr) == HARD_FRAME_POINTER_REGNUM) + return 0; + + /* Oh dear. The argument is pointed to by a register rather + than being held in a register, or being stored at a known + offset from the frame pointer. Since GDB only understands + those two kinds of argument we must translate the address + held in the register into an offset from the frame pointer. + We do this by searching through the insns for the function + looking to see where this register gets its value. If the + register is initialised from the frame pointer plus an offset + then we are in luck and we can continue, otherwise we give up. + + This code is exercised by producing debugging information + for a function with arguments like this: + + double func (double a, double b, int c, double d) {return d;} + + Without this code the stab for parameter 'd' will be set to + an offset of 0 from the frame pointer, rather than 8. */ + + /* The if() statement says: + + If the insn is a normal instruction + and if the insn is setting the value in a register + and if the register being set is the register holding the address of the argument + and if the address is computing by an addition + that involves adding to a register + which is the frame pointer + a constant integer + + then... */ + + for (insn = get_insns(); insn; insn = NEXT_INSN (insn)) + { + if ( GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == SET + && REGNO (XEXP (PATTERN (insn), 0)) == REGNO (addr) + && GET_CODE (XEXP (PATTERN (insn), 1)) == PLUS + && GET_CODE (XEXP (XEXP (PATTERN (insn), 1), 0)) == REG + && REGNO (XEXP (XEXP (PATTERN (insn), 1), 0)) == HARD_FRAME_POINTER_REGNUM + && GET_CODE (XEXP (XEXP (PATTERN (insn), 1), 1)) == CONST_INT + ) + { + value = INTVAL (XEXP (XEXP (PATTERN (insn), 1), 1)); + + break; + } + } + + if (value == 0) + { + warning ("Unable to compute real location of stacked parameter" ); + value = 8; /* XXX magic hack */ + } + + return value; +} + +/* Return nonzero if this insn is a call insn. */ + +static int +is_call_insn (insn) + rtx insn; +{ + if (GET_CODE (insn) == CALL_INSN) + return 1; + + if (GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == SEQUENCE + && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN) + return 1; + + return 0; +} + +/* Return nonzero if this insn, which is known to occur after a call insn, + will not stop the call from being interpreted as a tail call. */ + +static int +is_safe_after_call_insn (insn) + rtx insn; +{ + if (GET_CODE (insn) == NOTE) + return 1; + + if (GET_CODE (insn) == INSN) + { + rtx pattern = PATTERN (insn); + + if (GET_CODE (pattern) == USE) + return 1; + + /* Special case: Assignment of the result of the call that + has just been made to the return value for this function + will result in a move from the result register to itself. + Detect this case and rely upon the fact that a later pass + will eliminate this redundant move. */ + + if (GET_CODE (pattern) == SET + && GET_CODE (SET_SRC (pattern)) == REG + && GET_CODE (SET_DEST (pattern)) == REG + && REGNO (SET_SRC (pattern)) == REGNO (SET_DEST (pattern))) + return 1; + } + + return 0; +} + +/* Return nonzero if this function is suitable for a tail call optimisation. */ + +int +can_tail_call_optimise () +{ + rtx insn; + int found_call = 0; + + /* Functions that need frames cannot have tail call optimisations applied. */ + if (get_frame_size() > 0 + || current_function_anonymous_args) + return 0; + + /* Functions that perform more than one function call, + or that perform some computation after their only + function call cannot be optimised either. */ + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + if (is_call_insn (insn)) + { + if (found_call) + return 0; + else + found_call = 1; + } + else if (found_call) + { + if (! is_safe_after_call_insn (insn)) + return 0; + } + } + + /* Repeat the tests for the insns in the epilogue list. */ + for (insn = current_function_epilogue_delay_list; insn; insn = XEXP (insn, 1)) + { + if (is_call_insn (insn)) + { + if (found_call) + return 0; + else + found_call = 1; + } + else if (found_call) + { + if (! is_safe_after_call_insn (insn)) + return 0; + } + } + + return found_call; +} +/* END CYGNUS LOCAL */ + +/* CYGNUS LOCAL nickc */ +int +ok_integer_or_other (operand) + rtx operand; +{ + if (GET_CODE (operand) == CONST_INT) + { + if (const_ok_for_arm (INTVAL (operand)) + || const_ok_for_arm (~INTVAL (operand))) + return 1; + return 0; + } + + return 1; +} +/* END CYGNUS LOCAL */ diff --git a/gcc_arm/config/arm/arm.h b/gcc_arm/config/arm/arm.h new file mode 100755 index 0000000..6429c3d --- /dev/null +++ b/gcc_arm/config/arm/arm.h @@ -0,0 +1,2218 @@ +/* Definitions of target machine for GNU compiler, for Acorn RISC Machine. + Copyright (C) 1991, 93, 94, 95, 96, 97, 98, 1999, 2002 Free Software Foundation, Inc. + Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl) + and Martin Simmons (@harleqn.co.uk). + More major hacks by Richard Earnshaw (rwe11@cl.cam.ac.uk) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Configuration triples for ARM ports work as follows: + (This is a bit of a mess and needs some thought) + arm-*-*: little endian + armel-*-*: little endian + armeb-*-*: big endian + If a non-embedded environment (ie: "real" OS) is specified, `arm' + should default to that used by the OS. +*/ + +#ifndef __ARM_H__ +#define __ARM_H__ + +#define TARGET_CPU_arm2 0x0000 +#define TARGET_CPU_arm250 0x0000 +#define TARGET_CPU_arm3 0x0000 +#define TARGET_CPU_arm6 0x0001 +#define TARGET_CPU_arm600 0x0001 +#define TARGET_CPU_arm610 0x0002 +#define TARGET_CPU_arm7 0x0001 +#define TARGET_CPU_arm7m 0x0004 +#define TARGET_CPU_arm7dm 0x0004 +#define TARGET_CPU_arm7dmi 0x0004 +#define TARGET_CPU_arm700 0x0001 +#define TARGET_CPU_arm710 0x0002 +#define TARGET_CPU_arm7100 0x0002 +#define TARGET_CPU_arm7500 0x0002 +#define TARGET_CPU_arm7500fe 0x1001 +#define TARGET_CPU_arm7tdmi 0x0008 +#define TARGET_CPU_arm8 0x0010 +#define TARGET_CPU_arm810 0x0020 +#define TARGET_CPU_strongarm 0x0040 +#define TARGET_CPU_strongarm110 0x0040 +#define TARGET_CPU_strongarm1100 0x0040 +#define TARGET_CPU_arm9 0x0080 +#define TARGET_CPU_arm9tdmi 0x0080 +/* Configure didn't specify */ +#define TARGET_CPU_generic 0x8000 + +enum arm_cond_code +{ + ARM_EQ = 0, ARM_NE, ARM_CS, ARM_CC, ARM_MI, ARM_PL, ARM_VS, ARM_VC, + ARM_HI, ARM_LS, ARM_GE, ARM_LT, ARM_GT, ARM_LE, ARM_AL, ARM_NV +}; +extern enum arm_cond_code arm_current_cc; +extern char *arm_condition_codes[]; + +#define ARM_INVERSE_CONDITION_CODE(X) ((enum arm_cond_code) (((int)X) ^ 1)) + +/* This is needed by the tail-calling peepholes */ +extern int frame_pointer_needed; + + +/* Just in case configure has failed to define anything. */ +#ifndef TARGET_CPU_DEFAULT +#define TARGET_CPU_DEFAULT TARGET_CPU_generic +#endif + +/* If the configuration file doesn't specify the cpu, the subtarget may + override it. If it doesn't, then default to an ARM6. */ +#if TARGET_CPU_DEFAULT == TARGET_CPU_generic +#undef TARGET_CPU_DEFAULT +#ifdef SUBTARGET_CPU_DEFAULT +#define TARGET_CPU_DEFAULT SUBTARGET_CPU_DEFAULT +#else +#define TARGET_CPU_DEFAULT TARGET_CPU_arm6 +#endif +#endif + +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm2 +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_2__" +#else +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm6 || TARGET_CPU_DEFAULT == TARGET_CPU_arm610 || TARGET_CPU_DEFAULT == TARGET_CPU_arm7500fe +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_3__" +#else +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm7m +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_3M__" +#else +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm7tdmi || TARGET_CPU_DEFAULT == TARGET_CPU_arm9 +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_4T__" +#else +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm8 || TARGET_CPU_DEFAULT == TARGET_CPU_arm810 || TARGET_CPU_DEFAULT == TARGET_CPU_strongarm +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_4__" +#else +Unrecognized value in TARGET_CPU_DEFAULT. +#endif +#endif +#endif +#endif +#endif + +#ifndef CPP_PREDEFINES +#define CPP_PREDEFINES "-Darm -Acpu(arm) -Amachine(arm)" +#endif + +#define CPP_SPEC "\ +%(cpp_cpu_arch) %(cpp_apcs_pc) %(cpp_float) \ +%(cpp_endian) %(subtarget_cpp_spec)" + +/* Set the architecture define -- if -march= is set, then it overrides + the -mcpu= setting. */ +#define CPP_CPU_ARCH_SPEC "\ +%{m2:-D__arm2__ -D__ARM_ARCH_2__} \ +%{m3:-D__arm2__ -D__ARM_ARCH_2__} \ +%{m6:-D__arm6__ -D__ARM_ARCH_3__} \ +%{march=arm2:-D__ARM_ARCH_2__} \ +%{march=arm250:-D__ARM_ARCH_2__} \ +%{march=arm3:-D__ARM_ARCH_2__} \ +%{march=arm6:-D__ARM_ARCH_3__} \ +%{march=arm600:-D__ARM_ARCH_3__} \ +%{march=arm610:-D__ARM_ARCH_3__} \ +%{march=arm7:-D__ARM_ARCH_3__} \ +%{march=arm700:-D__ARM_ARCH_3__} \ +%{march=arm710:-D__ARM_ARCH_3__} \ +%{march=arm7100:-D__ARM_ARCH_3__} \ +%{march=arm7500:-D__ARM_ARCH_3__} \ +%{march=arm7500fe:-D__ARM_ARCH_3__} \ +%{march=arm7m:-D__ARM_ARCH_3M__} \ +%{march=arm7dm:-D__ARM_ARCH_3M__} \ +%{march=arm7dmi:-D__ARM_ARCH_3M__} \ +%{march=arm7tdmi:-D__ARM_ARCH_4T__} \ +%{march=arm8:-D__ARM_ARCH_4__} \ +%{march=arm810:-D__ARM_ARCH_4__} \ +%{march=arm9:-D__ARM_ARCH_4T__} \ +%{march=arm920:-D__ARM_ARCH_4__} \ +%{march=arm920t:-D__ARM_ARCH_4T__} \ +%{march=arm9tdmi:-D__ARM_ARCH_4T__} \ +%{march=strongarm:-D__ARM_ARCH_4__} \ +%{march=strongarm110:-D__ARM_ARCH_4__} \ +%{march=strongarm1100:-D__ARM_ARCH_4__} \ +%{march=armv2:-D__ARM_ARCH_2__} \ +%{march=armv2a:-D__ARM_ARCH_2__} \ +%{march=armv3:-D__ARM_ARCH_3__} \ +%{march=armv3m:-D__ARM_ARCH_3M__} \ +%{march=armv4:-D__ARM_ARCH_4__} \ +%{march=armv4t:-D__ARM_ARCH_4T__} \ +%{!march=*: \ + %{mcpu=arm2:-D__ARM_ARCH_2__} \ + %{mcpu=arm250:-D__ARM_ARCH_2__} \ + %{mcpu=arm3:-D__ARM_ARCH_2__} \ + %{mcpu=arm6:-D__ARM_ARCH_3__} \ + %{mcpu=arm600:-D__ARM_ARCH_3__} \ + %{mcpu=arm610:-D__ARM_ARCH_3__} \ + %{mcpu=arm7:-D__ARM_ARCH_3__} \ + %{mcpu=arm700:-D__ARM_ARCH_3__} \ + %{mcpu=arm710:-D__ARM_ARCH_3__} \ + %{mcpu=arm7100:-D__ARM_ARCH_3__} \ + %{mcpu=arm7500:-D__ARM_ARCH_3__} \ + %{mcpu=arm7500fe:-D__ARM_ARCH_3__} \ + %{mcpu=arm7m:-D__ARM_ARCH_3M__} \ + %{mcpu=arm7dm:-D__ARM_ARCH_3M__} \ + %{mcpu=arm7dmi:-D__ARM_ARCH_3M__} \ + %{mcpu=arm7tdmi:-D__ARM_ARCH_4T__} \ + %{mcpu=arm8:-D__ARM_ARCH_4__} \ + %{mcpu=arm810:-D__ARM_ARCH_4__} \ + %{mcpu=arm9:-D__ARM_ARCH_4T__} \ + %{mcpu=arm920:-D__ARM_ARCH_4__} \ + %{mcpu=arm920t:-D__ARM_ARCH_4T__} \ + %{mcpu=arm9tdmi:-D__ARM_ARCH_4T__} \ + %{mcpu=strongarm:-D__ARM_ARCH_4__} \ + %{mcpu=strongarm110:-D__ARM_ARCH_4__} \ + %{mcpu=strongarm1100:-D__ARM_ARCH_4__} \ + %{!mcpu*:%{!m6:%{!m2:%{!m3:%(cpp_cpu_arch_default)}}}}} \ +" + +/* Define __APCS_26__ if the PC also contains the PSR */ +/* This also examines deprecated -m[236] if neither of -mapcs-{26,32} is set, + ??? Delete this for 2.9. */ +#define CPP_APCS_PC_SPEC "\ +%{mapcs-32:%{mapcs-26:%e-mapcs-26 and -mapcs-32 may not be used together} \ + -D__APCS_32__} \ +%{mapcs-26:-D__APCS_26__} \ +%{!mapcs-32: %{!mapcs-26:%{m6:-D__APCS_32__} %{m2:-D__APCS_26__} \ + %{m3:-D__APCS_26__} %{!m6:%{!m3:%{!m2:%(cpp_apcs_pc_default)}}}}} \ +" + +#ifndef CPP_APCS_PC_DEFAULT_SPEC +#define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_26__" +#endif + +#define CPP_FLOAT_SPEC "\ +%{msoft-float:\ + %{mhard-float:%e-msoft-float and -mhard_float may not be used together} \ + -D__SOFTFP__} \ +%{!mhard-float:%{!msoft-float:%(cpp_float_default)}} \ +" + +/* Default is hard float, which doesn't define anything */ +#define CPP_FLOAT_DEFAULT_SPEC "" + +#define CPP_ENDIAN_SPEC "\ +%{mbig-endian: \ + %{mlittle-endian: \ + %e-mbig-endian and -mlittle-endian may not be used together} \ + -D__ARMEB__ %{mwords-little-endian:-D__ARMWEL__}} \ +%{!mlittle-endian:%{!mbig-endian:%(cpp_endian_default)}} \ +" + +/* Default is little endian, which doesn't define anything. */ +#define CPP_ENDIAN_DEFAULT_SPEC "" + +/* Translate (for now) the old -m[236] option into the appropriate -mcpu=... + and -mapcs-xx equivalents. + ??? Remove support for this style in 2.9.*/ +#define CC1_SPEC "\ +%{m2:-mcpu=arm2 -mapcs-26} \ +%{m3:-mcpu=arm3 -mapcs-26} \ +%{m6:-mcpu=arm6 -mapcs-32} \ +" + +/* This macro defines names of additional specifications to put in the specs + that can be used in various specifications like CC1_SPEC. Its definition + is an initializer with a subgrouping for each command option. + + Each subgrouping contains a string constant, that defines the + specification name, and a string constant that used by the GNU CC driver + program. + + Do not define this macro if it does not need to do anything. */ +#define EXTRA_SPECS \ + { "cpp_cpu_arch", CPP_CPU_ARCH_SPEC }, \ + { "cpp_cpu_arch_default", CPP_ARCH_DEFAULT_SPEC }, \ + { "cpp_apcs_pc", CPP_APCS_PC_SPEC }, \ + { "cpp_apcs_pc_default", CPP_APCS_PC_DEFAULT_SPEC }, \ + { "cpp_float", CPP_FLOAT_SPEC }, \ + { "cpp_float_default", CPP_FLOAT_DEFAULT_SPEC }, \ + { "cpp_endian", CPP_ENDIAN_SPEC }, \ + { "cpp_endian_default", CPP_ENDIAN_DEFAULT_SPEC }, \ + { "subtarget_cpp_spec", SUBTARGET_CPP_SPEC }, \ + SUBTARGET_EXTRA_SPECS + +#define SUBTARGET_EXTRA_SPECS +#define SUBTARGET_CPP_SPEC "" + + +/* Run-time Target Specification. */ +#ifndef TARGET_VERSION +#define TARGET_VERSION \ + fputs (" (ARM/generic)", stderr); +#endif + +/* Run-time compilation parameters selecting different hardware subsets. */ +extern int target_flags; + +/* The floating point instruction architecture, can be 2 or 3 */ +/* CYGNUS LOCAL nickc/renamed from target_fp_name */ +extern char * target_fpe_name; +/* END CYGNUS LOCAL */ + +/* Nonzero if the function prologue (and epilogue) should obey + the ARM Procedure Call Standard. */ +#define ARM_FLAG_APCS_FRAME (0x0001) + +/* Nonzero if the function prologue should output the function name to enable + the post mortem debugger to print a backtrace (very useful on RISCOS, + unused on RISCiX). Specifying this flag also enables + -fno-omit-frame-pointer. + XXX Must still be implemented in the prologue. */ +#define ARM_FLAG_POKE (0x0002) + +/* Nonzero if floating point instructions are emulated by the FPE, in which + case instruction scheduling becomes very uninteresting. */ +#define ARM_FLAG_FPE (0x0004) + +/* Nonzero if destined for an ARM6xx. Takes out bits that assume restoration + of condition flags when returning from a branch & link (ie. a function) */ +/* ********* DEPRECATED ******** */ +#define ARM_FLAG_ARM6 (0x0008) + +/* ********* DEPRECATED ******** */ +#define ARM_FLAG_ARM3 (0x0010) + +/* Nonzero if destined for a processor in 32-bit program mode. Takes out bit + that assume restoration of the condition flags when returning from a + branch and link (ie a function). */ +#define ARM_FLAG_APCS_32 (0x0020) + +/* Nonzero if stack checking should be performed on entry to each function + which allocates temporary variables on the stack. */ +#define ARM_FLAG_APCS_STACK (0x0040) + +/* Nonzero if floating point parameters should be passed to functions in + floating point registers. */ +#define ARM_FLAG_APCS_FLOAT (0x0080) + +/* Nonzero if re-entrant, position independent code should be generated. + This is equivalent to -fpic. */ +#define ARM_FLAG_APCS_REENT (0x0100) + +/* Nonzero if the MMU will trap unaligned word accesses, so shorts must be + loaded byte-at-a-time. */ +#define ARM_FLAG_SHORT_BYTE (0x0200) + +/* Nonzero if all floating point instructions are missing (and there is no + emulator either). Generate function calls for all ops in this case. */ +#define ARM_FLAG_SOFT_FLOAT (0x0400) + +/* Nonzero if we should compile with BYTES_BIG_ENDIAN set to 1. */ +#define ARM_FLAG_BIG_END (0x0800) + +/* Nonzero if we should compile for Thumb interworking. */ +#define ARM_FLAG_THUMB (0x1000) + +/* Nonzero if we should have little-endian words even when compiling for + big-endian (for backwards compatibility with older versions of GCC). */ +#define ARM_FLAG_LITTLE_WORDS (0x2000) + +/* CYGNUS LOCAL */ +/* Nonzero if we need to protect the prolog from scheduling */ +#define ARM_FLAG_NO_SCHED_PRO (0x4000) +/* END CYGNUS LOCAL */ + +/* Nonzero if a call to abort should be generated if a noreturn +function tries to return. */ +#define ARM_FLAG_ABORT_NORETURN (0x8000) + +/* Nonzero if all call instructions should be indirect. */ +#define ARM_FLAG_LONG_CALLS (0x10000) + +#define TARGET_APCS (target_flags & ARM_FLAG_APCS_FRAME) +#define TARGET_POKE_FUNCTION_NAME (target_flags & ARM_FLAG_POKE) +#define TARGET_FPE (target_flags & ARM_FLAG_FPE) +#define TARGET_6 (target_flags & ARM_FLAG_ARM6) +#define TARGET_3 (target_flags & ARM_FLAG_ARM3) +#define TARGET_APCS_32 (target_flags & ARM_FLAG_APCS_32) +#define TARGET_APCS_STACK (target_flags & ARM_FLAG_APCS_STACK) +#define TARGET_APCS_FLOAT (target_flags & ARM_FLAG_APCS_FLOAT) +#define TARGET_APCS_REENT (target_flags & ARM_FLAG_APCS_REENT) +#define TARGET_SHORT_BY_BYTES (target_flags & ARM_FLAG_SHORT_BYTE) +#define TARGET_SOFT_FLOAT (target_flags & ARM_FLAG_SOFT_FLOAT) +#define TARGET_HARD_FLOAT (! TARGET_SOFT_FLOAT) +#define TARGET_BIG_END (target_flags & ARM_FLAG_BIG_END) +#define TARGET_THUMB_INTERWORK (target_flags & ARM_FLAG_THUMB) +#define TARGET_LITTLE_WORDS (target_flags & ARM_FLAG_LITTLE_WORDS) +/* CYGNUS LOCAL */ +#define TARGET_NO_SCHED_PRO (target_flags & ARM_FLAG_NO_SCHED_PRO) +/* END CYGNUS LOCAL */ +#define TARGET_ABORT_NORETURN (target_flags & ARM_FLAG_ABORT_NORETURN) +#define TARGET_LONG_CALLS (target_flags & ARM_FLAG_LONG_CALLS) + +/* SUBTARGET_SWITCHES is used to add flags on a per-config basis. + Bit 31 is reserved. See riscix.h. */ +#ifndef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES +#endif + +#define TARGET_SWITCHES \ +{ \ + {"apcs", ARM_FLAG_APCS_FRAME, "" }, \ + {"apcs-frame", ARM_FLAG_APCS_FRAME, \ + "Generate APCS conformant stack frames" }, \ + {"no-apcs-frame", -ARM_FLAG_APCS_FRAME, "" }, \ + {"poke-function-name", ARM_FLAG_POKE, \ + "Store function names in object code" }, \ + {"fpe", ARM_FLAG_FPE, "" }, \ + {"6", ARM_FLAG_ARM6, "" }, \ + {"2", ARM_FLAG_ARM3, "" }, \ + {"3", ARM_FLAG_ARM3, "" }, \ + {"apcs-32", ARM_FLAG_APCS_32, \ + "Use the 32bit version of the APCS" }, \ + {"apcs-26", -ARM_FLAG_APCS_32, \ + "Use the 26bit version of the APCS" }, \ + {"apcs-stack-check", ARM_FLAG_APCS_STACK, "" }, \ + {"no-apcs-stack-check", -ARM_FLAG_APCS_STACK, "" }, \ + {"apcs-float", ARM_FLAG_APCS_FLOAT, \ + "Pass FP arguments in FP registers" }, \ + {"no-apcs-float", -ARM_FLAG_APCS_FLOAT, "" }, \ + {"apcs-reentrant", ARM_FLAG_APCS_REENT, \ + "Generate re-entrant, PIC code" }, \ + {"no-apcs-reentrant", -ARM_FLAG_APCS_REENT, "" }, \ + {"short-load-bytes", ARM_FLAG_SHORT_BYTE, \ + "Load shorts a byte at a time" }, \ + {"no-short-load-bytes", -ARM_FLAG_SHORT_BYTE, "" }, \ + {"short-load-words", -ARM_FLAG_SHORT_BYTE, \ + "Load words a byte at a time" }, \ + {"no-short-load-words", ARM_FLAG_SHORT_BYTE, "" }, \ + {"soft-float", ARM_FLAG_SOFT_FLOAT, \ + "Use library calls to perform FP operations" }, \ + {"hard-float", -ARM_FLAG_SOFT_FLOAT, \ + "Use hardware floating point instructions" }, \ + {"big-endian", ARM_FLAG_BIG_END, \ + "Assume target CPU is configured as big endian" }, \ + {"little-endian", -ARM_FLAG_BIG_END, \ + "Assume target CPU is configured as little endian" }, \ + {"words-little-endian", ARM_FLAG_LITTLE_WORDS, \ + "Assume big endian bytes, little endian words" }, \ + {"thumb-interwork", ARM_FLAG_THUMB, \ + "Support calls between THUMB and ARM instructions sets" }, \ + {"no-thumb-interwork", -ARM_FLAG_THUMB, "" }, \ + {"abort-on-noreturn", ARM_FLAG_ABORT_NORETURN, \ + "Generate a call to abort if a noreturn function returns"}, \ + {"no-abort-on-noreturn", -ARM_FLAG_ABORT_NORETURN, ""}, \ + /* CYGNUS LOCAL */ \ + {"sched-prolog", -ARM_FLAG_NO_SCHED_PRO, \ + "Do not move instructions into a function's prologue" }, \ + {"no-sched-prolog", ARM_FLAG_NO_SCHED_PRO, "" }, \ + /* END CYGNUS LOCAL */ \ + {"long-calls", ARM_FLAG_LONG_CALLS, \ + "Generate all call instructions as indirect calls"}, \ + {"no-long-calls", -ARM_FLAG_LONG_CALLS, ""}, \ + SUBTARGET_SWITCHES \ + {"", TARGET_DEFAULT } \ +} + +#define TARGET_OPTIONS \ +{ \ + {"cpu=", & arm_select[0].string, \ + "Specify the name of the target CPU" }, \ + {"arch=", & arm_select[1].string, \ + "Specify the name of the target architecture" }, \ + {"tune=", & arm_select[2].string, "" }, \ + {"fpe=", & target_fpe_name, "" }, \ + {"fp=", & target_fpe_name, \ + "Specify the version of the floating point emulator" }, \ + { "structure-size-boundary=", & structure_size_string, \ + "Specify the minumum bit alignment of structures" } \ +} + +struct arm_cpu_select +{ + char * string; + char * name; + struct processors * processors; +}; + +/* This is a magic array. If the user specifies a command line switch + which matches one of the entries in TARGET_OPTIONS then the corresponding + string pointer will be set to the value specified by the user. */ +extern struct arm_cpu_select arm_select[]; + +enum prog_mode_type +{ + prog_mode26, + prog_mode32 +}; + +/* Recast the program mode class to be the prog_mode attribute */ +#define arm_prog_mode (arm_prgmode) + +extern enum prog_mode_type arm_prgmode; + +/* What sort of floating point unit do we have? Hardware or software. + If software, is it issue 2 or issue 3? */ +enum floating_point_type +{ + FP_HARD, + FP_SOFT2, + FP_SOFT3 +}; + +/* Recast the floating point class to be the floating point attribute. */ +#define arm_fpu_attr ((enum attr_fpu) arm_fpu) + +/* What type of floating point to tune for */ +extern enum floating_point_type arm_fpu; + +/* What type of floating point instructions are available */ +extern enum floating_point_type arm_fpu_arch; + +/* Default floating point architecture. Override in sub-target if + necessary. */ +#define FP_DEFAULT FP_SOFT2 + +/* Nonzero if the processor has a fast multiply insn, and one that does + a 64-bit multiply of two 32-bit values. */ +extern int arm_fast_multiply; + +/* Nonzero if this chip supports the ARM Architecture 4 extensions */ +extern int arm_arch4; + +/* CYGNUS LOCAL nickc/load scheduling */ +/* Nonzero if this chip can benefit from load scheduling. */ +extern int arm_ld_sched; +/* END CYGNUS LOCAL */ + +/* Nonzero if this chip is a StrongARM. */ +extern int arm_is_strong; + +/* Nonzero if this chip is a an ARM6 or an ARM7. */ +extern int arm_is_6_or_7; + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT 0 +#endif + +/* The frame pointer register used in gcc has nothing to do with debugging; + that is controlled by the APCS-FRAME option. */ +/* Not fully implemented yet */ +/* #define CAN_DEBUG_WITHOUT_FP 1 */ + +#define TARGET_MEM_FUNCTIONS 1 + +#define OVERRIDE_OPTIONS arm_override_options () + +/* Target machine storage Layout. */ + + +/* Define this macro if it is advisable to hold scalars in registers + in a wider mode than that declared by the program. In such cases, + the value is constrained to be within the bounds of the declared + type, but kept valid in the wider mode. The signedness of the + extension may differ from that of the type. */ + +/* It is far faster to zero extend chars than to sign extend them */ + +#define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \ + if (GET_MODE_CLASS (MODE) == MODE_INT \ + && GET_MODE_SIZE (MODE) < 4) \ + { \ + if (MODE == QImode) \ + UNSIGNEDP = 1; \ + else if (MODE == HImode) \ + UNSIGNEDP = TARGET_SHORT_BY_BYTES != 0; \ + (MODE) = SImode; \ + } + +/* Define this macro if the promotion described by `PROMOTE_MODE' + should also be done for outgoing function arguments. */ +/* This is required to ensure that push insns always push a word. */ +#define PROMOTE_FUNCTION_ARGS + +/* Define for XFmode extended real floating point support. + This will automatically cause REAL_ARITHMETIC to be defined. */ +/* For the ARM: + I think I have added all the code to make this work. Unfortunately, + early releases of the floating point emulation code on RISCiX used a + different format for extended precision numbers. On my RISCiX box there + is a bug somewhere which causes the machine to lock up when running enquire + with long doubles. There is the additional aspect that Norcroft C + treats long doubles as doubles and we ought to remain compatible. + Perhaps someone with an FPA coprocessor and not running RISCiX would like + to try this someday. */ +/* #define LONG_DOUBLE_TYPE_SIZE 96 */ + +/* Disable XFmode patterns in md file */ +#define ENABLE_XF_PATTERNS 0 + +/* Define if you don't want extended real, but do want to use the + software floating point emulator for REAL_ARITHMETIC and + decimal <-> binary conversion. */ +/* See comment above */ +#define REAL_ARITHMETIC + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. */ +#define BITS_BIG_ENDIAN 0 + +/* Define this if most significant byte of a word is the lowest numbered. + Most ARM processors are run in little endian mode, so that is the default. + If you want to have it run-time selectable, change the definition in a + cover file to be TARGET_BIG_ENDIAN. */ +#define BYTES_BIG_ENDIAN (TARGET_BIG_END != 0) + +/* Define this if most significant word of a multiword number is the lowest + numbered. + This is always false, even when in big-endian mode. */ +#define WORDS_BIG_ENDIAN (BYTES_BIG_ENDIAN && ! TARGET_LITTLE_WORDS) + +/* LIBGCC2_WORDS_BIG_ENDIAN has to be a constant, so we define this based + on processor pre-defineds when compiling libgcc2.c. */ +#if defined(__ARMEB__) && !defined(__ARMWEL__) +#define LIBGCC2_WORDS_BIG_ENDIAN 1 +#else +#define LIBGCC2_WORDS_BIG_ENDIAN 0 +#endif + +/* Define this if most significant word of doubles is the lowest numbered. + This is always true, even when in little-endian mode. */ +#define FLOAT_WORDS_BIG_ENDIAN 1 + +/* Number of bits in an addressable storage unit */ +#define BITS_PER_UNIT 8 + +#define BITS_PER_WORD 32 + +#define UNITS_PER_WORD 4 + +#define POINTER_SIZE 32 + +#define PARM_BOUNDARY 32 + +#define STACK_BOUNDARY 32 + +#define FUNCTION_BOUNDARY 32 + +#define EMPTY_FIELD_BOUNDARY 32 + +#define BIGGEST_ALIGNMENT 32 + +/* Make strings word-aligned so strcpy from constants will be faster. */ +#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ + (TREE_CODE (EXP) == STRING_CST \ + && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) + +/* Every structures size must be a multiple of 32 bits. */ +/* This is for compatibility with ARMCC. ARM SDT Reference Manual + (ARM DUI 0020D) page 2-20 says "Structures are aligned on word + boundaries". */ +#ifndef STRUCTURE_SIZE_BOUNDARY +#define STRUCTURE_SIZE_BOUNDARY 32 +#endif + +/* Used when parsing command line option -mstructure_size_boundary. */ +extern char * structure_size_string; + +/* Non-zero if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT 1 + +#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT + + +/* Standard register usage. */ + +/* Register allocation in ARM Procedure Call Standard (as used on RISCiX): + (S - saved over call). + + r0 * argument word/integer result + r1-r3 argument word + + r4-r8 S register variable + r9 S (rfp) register variable (real frame pointer) + CYGNUS LOCAL nickc/comment change + r10 F S (sl) stack limit (used by -mapcs-stack-check) + END CYGNUS LOCAL + r11 F S (fp) argument pointer + r12 (ip) temp workspace + r13 F S (sp) lower end of current stack frame + r14 (lr) link address/workspace + r15 F (pc) program counter + + f0 floating point result + f1-f3 floating point scratch + + f4-f7 S floating point variable + + cc This is NOT a real register, but is used internally + to represent things that use or set the condition + codes. + sfp This isn't either. It is used during rtl generation + since the offset between the frame pointer and the + auto's isn't known until after register allocation. + afp Nor this, we only need this because of non-local + goto. Without it fp appears to be used and the + elimination code won't get rid of sfp. It tracks + fp exactly at all times. + + *: See CONDITIONAL_REGISTER_USAGE */ + +/* The stack backtrace structure is as follows: + fp points to here: | save code pointer | [fp] + | return link value | [fp, #-4] + | return sp value | [fp, #-8] + | return fp value | [fp, #-12] + [| saved r10 value |] + [| saved r9 value |] + [| saved r8 value |] + [| saved r7 value |] + [| saved r6 value |] + [| saved r5 value |] + [| saved r4 value |] + [| saved r3 value |] + [| saved r2 value |] + [| saved r1 value |] + [| saved r0 value |] + [| saved f7 value |] three words + [| saved f6 value |] three words + [| saved f5 value |] three words + [| saved f4 value |] three words + r0-r3 are not normally saved in a C function. */ + +/* The number of hard registers is 16 ARM + 8 FPU + 1 CC + 1 SFP. */ +#define FIRST_PSEUDO_REGISTER 27 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. */ +#define FIXED_REGISTERS \ +{ \ + 0,0,0,0,0,0,0,0, \ + 0,0,1,1,0,1,0,1, \ + 0,0,0,0,0,0,0,0, \ + 1,1,1 \ +} + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. + The CC is not preserved over function calls on the ARM 6, so it is + easier to assume this for all. SFP is preserved, since FP is. */ +#define CALL_USED_REGISTERS \ +{ \ + 1,1,1,1,0,0,0,0, \ + 0,0,1,1,1,1,1,1, \ + 1,1,1,1,0,0,0,0, \ + 1,1,1 \ +} + +/* If doing stupid life analysis, avoid a bug causing a return value r0 to be + trampled. This effectively reduces the number of available registers by 1. + XXX It is a hack, I know. + XXX Is this still needed? */ +#define CONDITIONAL_REGISTER_USAGE \ +{ \ + if (obey_regdecls) \ + fixed_regs[0] = 1; \ + if (TARGET_SOFT_FLOAT) \ + { \ + int regno; \ + for (regno = 16; regno < 24; ++regno) \ + fixed_regs[regno] = call_used_regs[regno] = 1; \ + } \ + if (flag_pic) \ + { \ + fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ + call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 0; \ + } \ + /* CYGNUS LOCAL */ \ + else if (! TARGET_APCS_STACK) \ + { \ + fixed_regs[10] = 0; \ + call_used_regs[10] = 0; \ + } \ + /* END CYGNUS LOCAL */ \ +} + +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. + + On the ARM regs are UNITS_PER_WORD bits wide; FPU regs can hold any FP + mode. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + (((REGNO) >= 16 && REGNO != FRAME_POINTER_REGNUM \ + && (REGNO) != ARG_POINTER_REGNUM) ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + This is TRUE for ARM regs since they can hold anything, and TRUE for FPU + regs holding FP. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + ((GET_MODE_CLASS (MODE) == MODE_CC) ? (REGNO == CC_REGNUM) : \ + ((REGNO) < 16 || REGNO == FRAME_POINTER_REGNUM \ + || REGNO == ARG_POINTER_REGNUM \ + || GET_MODE_CLASS (MODE) == MODE_FLOAT)) + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + 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) \ + (GET_MODE_CLASS (MODE1) == GET_MODE_CLASS (MODE2)) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* Define this if the program counter is overloaded on a register. */ +#define PC_REGNUM 15 + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 13 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 25 + +/* Define this to be where the real frame pointer is if it is not possible to + work out the offset between the frame pointer and the automatic variables + until after register allocation has taken place. FRAME_POINTER_REGNUM + should point to a special register that we will make sure is eliminated. */ +#define HARD_FRAME_POINTER_REGNUM 11 + +/* 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. + If we have to have a frame pointer we might as well make use of it. + APCS says that the frame pointer does not need to be pushed in leaf + functions, or simple tail call functions. */ +/* CYGNUS LOCAL */ +#define FRAME_POINTER_REQUIRED \ + (current_function_has_nonlocal_label \ + || (TARGET_APCS && (! leaf_function_p () && ! can_tail_call_optimise ()))) + +extern int can_tail_call_optimise (); +/* END CYGNUS LOCAL */ + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 26 + +/* The native (Norcroft) Pascal compiler for the ARM passes the static chain + as an invisible last argument (possible since varargs don't exist in + Pascal), so the following is not true. */ +#define STATIC_CHAIN_REGNUM 8 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 0 + +/* Internal, so that we don't need to refer to a raw number */ +#define CC_REGNUM 24 + +/* The order in which register should be allocated. It is good to use ip + since no saving is required (though calls clobber it) and it never contains + function parameters. It is quite good to use lr since other calls may + clobber it anyway. Allocate r0 through r3 in reverse order since r3 is + least likely to contain a function parameter; in addition results are + returned in r0. + */ +#define REG_ALLOC_ORDER \ +{ \ + 3, 2, 1, 0, 12, 14, 4, 5, \ + 6, 7, 8, 10, 9, 11, 13, 15, \ + 16, 17, 18, 19, 20, 21, 22, 23, \ + 24, 25, 26 \ +} + +/* Register and constant classes. */ + +/* Register classes: all ARM regs or all FPU regs---simple! */ +enum reg_class +{ + NO_REGS, + FPU_REGS, + GENERAL_REGS, + ALL_REGS, + LIM_REG_CLASSES +}; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Give names of register classes as strings for dump file. */ +#define REG_CLASS_NAMES \ +{ \ + "NO_REGS", \ + "FPU_REGS", \ + "GENERAL_REGS", \ + "ALL_REGS", \ +} + +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ +#define REG_CLASS_CONTENTS \ +{ \ + 0x0000000, /* NO_REGS */ \ + 0x0FF0000, /* FPU_REGS */ \ + 0x200FFFF, /* GENERAL_REGS */ \ + 0x2FFFFFF /* ALL_REGS */ \ +} + +/* The same information, inverted: + Return the class number of the smallest class containing + reg number REGNO. This could be a conditional expression + or could index an array. */ +#define REGNO_REG_CLASS(REGNO) \ + (((REGNO) < 16 || REGNO == FRAME_POINTER_REGNUM \ + || REGNO == ARG_POINTER_REGNUM) \ + ? GENERAL_REGS : (REGNO) == CC_REGNUM \ + ? NO_REGS : FPU_REGS) + +/* The class value for index registers, and the one for base regs. */ +#define INDEX_REG_CLASS GENERAL_REGS +#define BASE_REG_CLASS GENERAL_REGS + +/* Get reg_class from a letter such as appears in the machine description. + We only need constraint `f' for FPU_REGS (`r' == GENERAL_REGS). */ +#define REG_CLASS_FROM_LETTER(C) \ + ((C)=='f' ? FPU_REGS : 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: immediate arithmetic operand (i.e. 8 bits shifted as required). + J: valid indexing constants. + K: ~value ok in rhs argument of data operand. + L: -value ok in rhs argument of data operand. + M: 0..32, or a power of 2 (for shifts, or mult done by shift). */ +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? const_ok_for_arm (VALUE) : \ + (C) == 'J' ? ((VALUE) < 4096 && (VALUE) > -4096) : \ + (C) == 'K' ? (const_ok_for_arm (~(VALUE))) : \ + (C) == 'L' ? (const_ok_for_arm (-(VALUE))) : \ + (C) == 'M' ? (((VALUE >= 0 && VALUE <= 32)) \ + || (((VALUE) & ((VALUE) - 1)) == 0)) \ + : 0) + +/* For the ARM, `Q' means that this is a memory operand that is just + an offset from a register. + `S' means any symbol that has the SYMBOL_REF_FLAG set or a CONSTANT_POOL + address. This means that the symbol is in the text segment and can be + accessed without using a load. */ + +#define EXTRA_CONSTRAINT(OP, C) \ + ((C) == 'Q' ? GET_CODE (OP) == MEM && GET_CODE (XEXP (OP, 0)) == REG \ + : (C) == 'R' ? (GET_CODE (OP) == MEM \ + && GET_CODE (XEXP (OP, 0)) == SYMBOL_REF \ + && CONSTANT_POOL_ADDRESS_P (XEXP (OP, 0))) \ + : (C) == 'S' ? (optimize > 0 && CONSTANT_ADDRESS_P (OP)) \ + : 0) + +/* Constant letter 'G' for the FPU immediate constants. + 'H' means the same constant negated. */ +#define CONST_DOUBLE_OK_FOR_LETTER_P(X,C) \ + ((C) == 'G' ? const_double_rtx_ok_for_fpu (X) \ + : (C) == 'H' ? neg_const_double_rtx_ok_for_fpu (X) : 0) + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. */ +#define PREFERRED_RELOAD_CLASS(X, CLASS) (CLASS) + +/* Return the register class of a scratch register needed to copy IN into + or out of a register in CLASS in MODE. If it can be done directly, + NO_REGS is returned. */ +#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS,MODE,X) \ + (((MODE) == HImode && ! arm_arch4 && true_regnum (X) == -1) \ + ? GENERAL_REGS : NO_REGS) + +/* If we need to load shorts byte-at-a-time, then we need a scratch. */ +#define SECONDARY_INPUT_RELOAD_CLASS(CLASS,MODE,X) \ + (((MODE) == HImode && ! arm_arch4 && TARGET_SHORT_BY_BYTES \ + && (GET_CODE (X) == MEM \ + || ((GET_CODE (X) == REG || GET_CODE (X) == SUBREG) \ + && true_regnum (X) == -1))) \ + ? GENERAL_REGS : NO_REGS) + +/* Try a machine-dependent way of reloading an illegitimate address + operand. If we find one, push the reload and jump to WIN. This + macro is used in only one place: `find_reloads_address' in reload.c. + + For the ARM, we wish to handle large displacements off a base + register by splitting the addend across a MOV and the mem insn. + This can cut the number of reloads needed. */ +#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \ +do { \ + if (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REGNO (XEXP (X, 0)) < FIRST_PSEUDO_REGISTER \ + && REG_MODE_OK_FOR_BASE_P (XEXP (X, 0), MODE) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT) \ + { \ + HOST_WIDE_INT val = INTVAL (XEXP (X, 1)); \ + HOST_WIDE_INT low, high; \ + \ + if (MODE == DImode || (TARGET_SOFT_FLOAT && MODE == DFmode)) \ + low = ((val & 0xf) ^ 0x8) - 0x8; \ + else if (MODE == SImode || MODE == QImode \ + || (MODE == SFmode && TARGET_SOFT_FLOAT) \ + || (MODE == HImode && ! arm_arch4)) \ + /* Need to be careful, -4096 is not a valid offset */ \ + low = val >= 0 ? (val & 0xfff) : -((-val) & 0xfff); \ + else if (MODE == HImode && arm_arch4) \ + /* Need to be careful, -256 is not a valid offset */ \ + low = val >= 0 ? (val & 0xff) : -((-val) & 0xff); \ + else if (GET_MODE_CLASS (MODE) == MODE_FLOAT \ + && TARGET_HARD_FLOAT) \ + /* Need to be careful, -1024 is not a valid offset */ \ + low = val >= 0 ? (val & 0x3ff) : -((-val) & 0x3ff); \ + else \ + break; \ + \ + high = ((((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000); \ + /* Check for overflow or zero */ \ + if (low == 0 || high == 0 || (high + low != val)) \ + break; \ + \ + /* Reload the high part into a base reg; leave the low part \ + in the mem. */ \ + X = gen_rtx_PLUS (GET_MODE (X), \ + gen_rtx_PLUS (GET_MODE (X), XEXP (X, 0), \ + GEN_INT (high)), \ + GEN_INT (low)); \ + push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL_PTR, \ + BASE_REG_CLASS, GET_MODE (X), VOIDmode, 0, 0, \ + OPNUM, TYPE); \ + goto WIN; \ + } \ +} while (0) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. + ARM regs are UNITS_PER_WORD bits while FPU regs can hold any FP mode */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((CLASS) == FPU_REGS ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Moves between FPU_REGS and GENERAL_REGS are two memory insns. */ +#define REGISTER_MOVE_COST(CLASS1, CLASS2) \ + ((((CLASS1) == FPU_REGS && (CLASS2) != FPU_REGS) \ + || ((CLASS2) == FPU_REGS && (CLASS1) != FPU_REGS)) \ + ? 20 : 2) + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD 1 + +/* 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 + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. */ +/* The push insns do not do this rounding implicitly. So don't define this. */ +/* #define PUSH_ROUNDING(NPUSHED) (((NPUSHED) + 3) & ~3) */ + +/* Define this if the maximum size of all the outgoing args is to be + accumulated and pushed during the prologue. The amount can be + found in the variable current_function_outgoing_args_size. */ +#define ACCUMULATE_OUTGOING_ARGS + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 4 + +/* Value is the number of byte of arguments automatically + popped when returning from a subroutine call. + FUNDECL is the declaration node of the function (as a tree), + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. + SIZE is the number of bytes of arguments passed on the stack. + + On the ARM, the caller does not pop any of its arguments that were passed + on the stack. */ +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 + +/* 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) \ + (GET_MODE_CLASS (TYPE_MODE (VALTYPE)) == MODE_FLOAT && TARGET_HARD_FLOAT \ + ? gen_rtx (REG, TYPE_MODE (VALTYPE), 16) \ + : gen_rtx (REG, TYPE_MODE (VALTYPE), 0)) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ +#define LIBCALL_VALUE(MODE) \ + (GET_MODE_CLASS (MODE) == MODE_FLOAT && TARGET_HARD_FLOAT \ + ? gen_rtx (REG, MODE, 16) \ + : gen_rtx (REG, MODE, 0)) + +/* 1 if N is a possible register number for a function value. + On the ARM, only r0 and f0 can return results. */ +#define FUNCTION_VALUE_REGNO_P(REGNO) \ + ((REGNO) == 0 || ((REGNO) == 16) && TARGET_HARD_FLOAT) + +/* How large values are returned */ +/* A C expression which can inhibit the returning of certain function values + in registers, based on the type of value. */ +/* CYGNUS LOCAL */ +#define RETURN_IN_MEMORY(TYPE) arm_return_in_memory (TYPE) +/* END CYGNUS LOCAL */ + +/* Define DEFAULT_PCC_STRUCT_RETURN to 1 if all structure and union return + values must be in memory. On the ARM, they need only do so if larger + than a word, or if they contain elements offset from zero in the struct. */ +#define DEFAULT_PCC_STRUCT_RETURN 0 + +/* Define where to put the arguments to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). + + On the ARM, normally the first 16 bytes are passed in registers r0-r3; all + other arguments are passed on the stack. If (NAMED == 0) (which happens + only in assign_parms, since SETUP_INCOMING_VARARGS is defined), say it is + passed in the stack (function_prologue will indeed make it pass in the + stack if necessary). */ +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + ((NAMED) \ + ? ((CUM) >= 16 ? 0 : gen_rtx (REG, MODE, (CUM) / 4)) \ + : 0) + +/* 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) \ + ((CUM) < 16 && 16 < (CUM) + ((MODE) != BLKmode \ + ? GET_MODE_SIZE (MODE) \ + : int_size_in_bytes (TYPE)) \ + ? 4 - (CUM) / 4 : 0) + +/* A C type for declaring a variable that is used as the first argument of + `FUNCTION_ARG' and other related values. For some target machines, the + type `int' suffices and can hold the number of bytes of argument so far. + + On the ARM, this is the number of bytes of arguments scanned so far. */ +#define CUMULATIVE_ARGS int + +/* 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. + On the ARM, the offset starts at 0. */ +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ + ((CUM) = (((FNTYPE) && aggregate_value_p (TREE_TYPE ((FNTYPE)))) ? 4 : 0)) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + (CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3) \ + +/* 1 if N is a possible register number for function argument passing. + On the ARM, r0-r3 are used to pass args. */ +#define FUNCTION_ARG_REGNO_P(REGNO) \ + ((REGNO) >= 0 && (REGNO) <= 3) + +/* Perform any 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. + + On the ARM, PRETEND_SIZE is set in order to have the prologue push the last + named arg and all anonymous args onto the stack. + XXX I know the prologue shouldn't be pushing registers, but it is faster + that way. */ +#define SETUP_INCOMING_VARARGS(CUM, MODE, TYPE, PRETEND_SIZE, NO_RTL) \ +{ \ + extern int current_function_anonymous_args; \ + current_function_anonymous_args = 1; \ + if ((CUM) < 16) \ + (PRETEND_SIZE) = 16 - (CUM); \ +} + +/* Generate assembly output for the start of a function. */ +#define FUNCTION_PROLOGUE(STREAM, SIZE) \ + output_func_prologue ((STREAM), (SIZE)) + +/* Call the function profiler with a given profile label. The Acorn compiler + puts this BEFORE the prolog but gcc puts it afterwards. The ``mov ip,lr'' + seems like a good idea to stick with cc convention. ``prof'' doesn't seem + to mind about this! */ +#define FUNCTION_PROFILER(STREAM,LABELNO) \ +{ \ + fprintf(STREAM, "\tmov\t%sip, %slr\n", REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf(STREAM, "\tbl\tmcount\n"); \ + fprintf(STREAM, "\t.word\tLP%d\n", (LABELNO)); \ +} + +/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, + the stack pointer does not matter. The value is tested only in + functions that have frame pointers. + No definition is equivalent to always zero. + + On the ARM, the function epilogue recovers the stack pointer from the + frame. */ +#define EXIT_IGNORE_STACK 1 + +/* Generate the assembly code for function exit. */ +#define FUNCTION_EPILOGUE(STREAM, SIZE) \ + output_func_epilogue ((STREAM), (SIZE)) + +/* Determine if the epilogue should be output as RTL. + You should override this if you define FUNCTION_EXTRA_EPILOGUE. */ +#define USE_RETURN_INSN(ISCOND) use_return_insn (ISCOND) + +/* Definitions for register eliminations. + + This is an array of structures. Each structure initializes one pair + of eliminable registers. The "from" register number is given first, + followed by "to". Eliminations of the same "from" register are listed + in order of preference. + + We have two registers that can be eliminated on the ARM. First, the + arg pointer register can often be eliminated in favor of the stack + pointer register. Secondly, the pseudo frame pointer register can always + be eliminated; it is replaced with either the stack or the real frame + pointer. */ + +#define ELIMINABLE_REGS \ +{{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + {ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ + {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + {FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} + +/* Given FROM and TO register numbers, say whether this elimination is allowed. + Frame pointer elimination is automatically handled. + + All eliminations are permissible. Note that ARG_POINTER_REGNUM and + HARD_FRAME_POINTER_REGNUM are in fact the same thing. If we need a frame + pointer, we must eliminate FRAME_POINTER_REGNUM into + HARD_FRAME_POINTER_REGNUM and not into STACK_POINTER_REGNUM. */ +#define CAN_ELIMINATE(FROM, TO) \ + (((TO) == STACK_POINTER_REGNUM && frame_pointer_needed) ? 0 : 1) + +/* Define the offset between two registers, one to be eliminated, and the other + its replacement, at the start of a routine. */ +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ +{ \ + int volatile_func = arm_volatile_func (); \ + if ((FROM) == ARG_POINTER_REGNUM && (TO) == HARD_FRAME_POINTER_REGNUM)\ + (OFFSET) = 0; \ + else if ((FROM) == FRAME_POINTER_REGNUM \ + && (TO) == STACK_POINTER_REGNUM) \ + (OFFSET) = (current_function_outgoing_args_size \ + + (get_frame_size () + 3 & ~3)); \ + else \ + { \ + int regno; \ + int offset = 12; \ + int saved_hard_reg = 0; \ + \ + if (! volatile_func) \ + { \ + for (regno = 0; regno <= 10; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + saved_hard_reg = 1, offset += 4; \ + for (regno = 16; regno <=23; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 12; \ + } \ + if ((FROM) == FRAME_POINTER_REGNUM) \ + (OFFSET) = -offset; \ + else \ + { \ + if (! frame_pointer_needed) \ + offset -= 16; \ + if (! volatile_func \ + && (regs_ever_live[14] || saved_hard_reg)) \ + offset += 4; \ + offset += current_function_outgoing_args_size; \ + (OFFSET) = (get_frame_size () + 3 & ~3) + offset; \ + } \ + } \ +} + +/* CYGNUS LOCAL */ +/* Special case handling of the location of arguments passed on the stack. */ +#define DEBUGGER_ARG_OFFSET(value, addr) value ? value : arm_debugger_arg_offset (value, addr) +/* END CYGNUS LOCAL */ + +/* Output assembler code for a block containing the constant parts + of a trampoline, leaving space for the variable parts. + + On the ARM, (if r8 is the static chain regnum, and remembering that + referencing pc adds an offset of 8) the trampoline looks like: + ldr r8, [pc, #0] + ldr pc, [pc] + .word static chain value + .word function's address + ??? FIXME: When the trampoline returns, r8 will be clobbered. */ +#define TRAMPOLINE_TEMPLATE(FILE) \ +{ \ + fprintf ((FILE), "\tldr\t%sr8, [%spc, #0]\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\tldr\t%spc, [%spc, #0]\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\t.word\t0\n"); \ + fprintf ((FILE), "\t.word\t0\n"); \ +} + +/* Length in units of the trampoline for entering a nested function. */ +#define TRAMPOLINE_SIZE 16 + +/* Alignment required for a trampoline in units. */ +#define TRAMPOLINE_ALIGN 4 + +/* Emit RTL insns to initialize the variable parts of a trampoline. + FNADDR is an RTX for the address of the function's pure code. + CXT is an RTX for the static chain value for the function. */ +#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ +{ \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 8)), \ + (CXT)); \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 12)), \ + (FNADDR)); \ +} + + +/* Addressing modes, and classification of registers for them. */ + +#define HAVE_POST_INCREMENT 1 +#define HAVE_PRE_INCREMENT 1 +#define HAVE_POST_DECREMENT 1 +#define HAVE_PRE_DECREMENT 1 + +/* Macros to check register numbers against specific register classes. */ + +/* These assume that REGNO is a hard or pseudo reg number. + They give nonzero only if REGNO is a hard reg of the suitable class + or a pseudo reg currently allocated to a suitable hard reg. + Since they use reg_renumber, they are safe only once reg_renumber + has been allocated, which happens in local-alloc.c. + + On the ARM, don't allow the pc to be used. */ +#define REGNO_OK_FOR_BASE_P(REGNO) \ + ((REGNO) < 15 || (REGNO) == FRAME_POINTER_REGNUM \ + || (REGNO) == ARG_POINTER_REGNUM \ + || (unsigned) reg_renumber[(REGNO)] < 15 \ + || (unsigned) reg_renumber[(REGNO)] == FRAME_POINTER_REGNUM \ + || (unsigned) reg_renumber[(REGNO)] == ARG_POINTER_REGNUM) +#define REGNO_OK_FOR_INDEX_P(REGNO) \ + REGNO_OK_FOR_BASE_P(REGNO) + +/* Maximum number of registers that can appear in a valid memory address. + Shifts in addresses can't be by a register. */ + +#define MAX_REGS_PER_ADDRESS 2 + +/* Recognize any constant value that is a valid address. */ +/* XXX We can address any constant, eventually... */ + +#ifdef AOF_ASSEMBLER + +#define CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == SYMBOL_REF \ + && CONSTANT_POOL_ADDRESS_P (X)) + +#else + +#define CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == SYMBOL_REF \ + && (CONSTANT_POOL_ADDRESS_P (X) \ + || (optimize > 0 && SYMBOL_REF_FLAG (X)))) + +#endif /* AOF_ASSEMBLER */ + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. + + On the ARM, allow any integer (invalid ones are removed later by insn + patterns), nice doubles and symbol_refs which refer to the function's + constant pool XXX. */ +#define LEGITIMATE_CONSTANT_P(X) (! label_mentioned_p (X)) + +/* Symbols in the text segment can be accessed without indirecting via the + constant pool; it may take an extra binary operation, but this is still + faster than indirecting via memory. Don't do this when not optimizing, + since we won't be calculating al of the offsets necessary to do this + simplification. */ +/* This doesn't work with AOF syntax, since the string table may be in + a different AREA. */ +#ifndef AOF_ASSEMBLER +#define ENCODE_SECTION_INFO(decl) \ +{ \ + if (optimize > 0 && TREE_CONSTANT (decl) \ + && (!flag_writable_strings || TREE_CODE (decl) != STRING_CST)) \ + { \ + rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd' \ + ? TREE_CST_RTL (decl) : DECL_RTL (decl)); \ + SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1; \ + } \ +} +#endif + +/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx + and check its validity for a certain class. + We have two alternate definitions for each of them. + The usual definition accepts all pseudo regs; the other rejects + them unless they have been allocated suitable hard regs. + The symbol REG_OK_STRICT causes the latter definition to be used. */ +#ifndef REG_OK_STRICT + +/* Nonzero if X is a hard reg that can be used as a base reg + or if it is a pseudo reg. */ +#define REG_OK_FOR_BASE_P(X) \ + (REGNO (X) < 16 || REGNO (X) >= FIRST_PSEUDO_REGISTER \ + || REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM) + +/* Nonzero if X is a hard reg that can be used as an index + or if it is a pseudo reg. */ +#define REG_OK_FOR_INDEX_P(X) \ + REG_OK_FOR_BASE_P(X) + +#define REG_OK_FOR_PRE_POST_P(X) \ + (REGNO (X) < 16 || REGNO (X) >= FIRST_PSEUDO_REGISTER \ + || REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM) + +#else + +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + +/* Nonzero if X is a hard reg that can be used as an index. */ +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) + +#define REG_OK_FOR_PRE_POST_P(X) \ + (REGNO (X) < 16 || (unsigned) reg_renumber[REGNO (X)] < 16 \ + || REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO (X)] == FRAME_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO (X)] == ARG_POINTER_REGNUM) + +#endif + +/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression + that is a valid memory address for an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS. */ +#define BASE_REGISTER_RTX_P(X) \ + (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) + +#define INDEX_REGISTER_RTX_P(X) \ + (GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X)) + +/* A C statement (sans semicolon) to jump to LABEL for legitimate index RTXs + used by the macro GO_IF_LEGITIMATE_ADDRESS. Floating point indices can + only be small constants. */ +#define GO_IF_LEGITIMATE_INDEX(MODE, BASE_REGNO, INDEX, LABEL) \ +do \ +{ \ + HOST_WIDE_INT range; \ + enum rtx_code code = GET_CODE (INDEX); \ + \ + if (TARGET_HARD_FLOAT && GET_MODE_CLASS (MODE) == MODE_FLOAT) \ + { \ + if (code == CONST_INT && INTVAL (INDEX) < 1024 \ + && INTVAL (INDEX) > -1024 \ + && (INTVAL (INDEX) & 3) == 0) \ + goto LABEL; \ + } \ + else \ + { \ + if (INDEX_REGISTER_RTX_P (INDEX) && GET_MODE_SIZE (MODE) <= 4) \ + goto LABEL; \ + if (GET_MODE_SIZE (MODE) <= 4 && code == MULT \ + && (! arm_arch4 || (MODE) != HImode)) \ + { \ + rtx xiop0 = XEXP (INDEX, 0); \ + rtx xiop1 = XEXP (INDEX, 1); \ + if (INDEX_REGISTER_RTX_P (xiop0) \ + && power_of_two_operand (xiop1, SImode)) \ + goto LABEL; \ + if (INDEX_REGISTER_RTX_P (xiop1) \ + && power_of_two_operand (xiop0, SImode)) \ + goto LABEL; \ + } \ + if (GET_MODE_SIZE (MODE) <= 4 \ + && (code == LSHIFTRT || code == ASHIFTRT \ + || code == ASHIFT || code == ROTATERT) \ + && (! arm_arch4 || (MODE) != HImode)) \ + { \ + rtx op = XEXP (INDEX, 1); \ + if (INDEX_REGISTER_RTX_P (XEXP (INDEX, 0)) \ + && GET_CODE (op) == CONST_INT && INTVAL (op) > 0 \ + && INTVAL (op) <= 31) \ + goto LABEL; \ + } \ + /* NASTY: Since this limits the addressing of unsigned byte loads */ \ + range = ((MODE) == HImode || (MODE) == QImode) \ + ? (arm_arch4 ? 256 : 4095) : 4096; \ + if (code == CONST_INT && INTVAL (INDEX) < range \ + && INTVAL (INDEX) > -range) \ + goto LABEL; \ + } \ +} while (0) + +/* Jump to LABEL if X is a valid address RTX. This must also take + REG_OK_STRICT into account when deciding about valid registers, but it uses + the above macros so we are in luck. Allow REG, REG+REG, REG+INDEX, + INDEX+REG, REG-INDEX, and non floating SYMBOL_REF to the constant pool. + Allow REG-only and AUTINC-REG if handling TImode or HImode. Other symbol + refs must be forced though a static cell to ensure addressability. */ +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \ +{ \ + if (BASE_REGISTER_RTX_P (X)) \ + goto LABEL; \ + else if ((GET_CODE (X) == POST_INC || GET_CODE (X) == PRE_DEC) \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_PRE_POST_P (XEXP (X, 0))) \ + goto LABEL; \ + else if (GET_MODE_SIZE (MODE) >= 4 && reload_completed \ + && (GET_CODE (X) == LABEL_REF \ + || (GET_CODE (X) == CONST \ + && GET_CODE (XEXP ((X), 0)) == PLUS \ + && GET_CODE (XEXP (XEXP ((X), 0), 0)) == LABEL_REF \ + && GET_CODE (XEXP (XEXP ((X), 0), 1)) == CONST_INT)))\ + goto LABEL; \ + else if ((MODE) == TImode) \ + ; \ + else if ((MODE) == DImode || (TARGET_SOFT_FLOAT && (MODE) == DFmode)) \ + { \ + if (GET_CODE (X) == PLUS && BASE_REGISTER_RTX_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT) \ + { \ + HOST_WIDE_INT val = INTVAL (XEXP (X, 1)); \ + if (val == 4 || val == -4 || val == -8) \ + goto LABEL; \ + } \ + } \ + else if (GET_CODE (X) == PLUS) \ + { \ + rtx xop0 = XEXP(X,0); \ + rtx xop1 = XEXP(X,1); \ + \ + if (BASE_REGISTER_RTX_P (xop0)) \ + GO_IF_LEGITIMATE_INDEX (MODE, REGNO (xop0), xop1, LABEL); \ + else if (BASE_REGISTER_RTX_P (xop1)) \ + GO_IF_LEGITIMATE_INDEX (MODE, REGNO (xop1), xop0, LABEL); \ + } \ + /* Reload currently can't handle MINUS, so disable this for now */ \ + /* else if (GET_CODE (X) == MINUS) \ + { \ + rtx xop0 = XEXP (X,0); \ + rtx xop1 = XEXP (X,1); \ + \ + if (BASE_REGISTER_RTX_P (xop0)) \ + GO_IF_LEGITIMATE_INDEX (MODE, -1, xop1, LABEL); \ + } */ \ + else if (GET_MODE_CLASS (MODE) != MODE_FLOAT \ + && GET_CODE (X) == SYMBOL_REF \ + && CONSTANT_POOL_ADDRESS_P (X)) \ + goto LABEL; \ + else if ((GET_CODE (X) == PRE_INC || GET_CODE (X) == POST_DEC) \ + && (GET_MODE_SIZE (MODE) <= 4) \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_PRE_POST_P (XEXP (X, 0))) \ + goto LABEL; \ +} + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. + + On the ARM, try to convert [REG, #BIGCONST] + into ADD BASE, REG, #UPPERCONST and [BASE, #VALIDCONST], + where VALIDCONST == 0 in case of TImode. */ +extern struct rtx_def *legitimize_pic_address (); +#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ +{ \ + if (GET_CODE (X) == PLUS) \ + { \ + rtx xop0 = XEXP (X, 0); \ + rtx xop1 = XEXP (X, 1); \ + \ + if (CONSTANT_P (xop0) && ! symbol_mentioned_p (xop0)) \ + xop0 = force_reg (SImode, xop0); \ + if (CONSTANT_P (xop1) && ! symbol_mentioned_p (xop1)) \ + xop1 = force_reg (SImode, xop1); \ + if (BASE_REGISTER_RTX_P (xop0) && GET_CODE (xop1) == CONST_INT) \ + { \ + HOST_WIDE_INT n, low_n; \ + rtx base_reg, val; \ + n = INTVAL (xop1); \ + \ + if (MODE == DImode || (TARGET_SOFT_FLOAT && MODE == DFmode)) \ + { \ + low_n = n & 0x0f; \ + n &= ~0x0f; \ + if (low_n > 4) \ + { \ + n += 16; \ + low_n -= 16; \ + } \ + } \ + else \ + { \ + low_n = ((MODE) == TImode ? 0 \ + : n >= 0 ? (n & 0xfff) : -((-n) & 0xfff)); \ + n -= low_n; \ + } \ + base_reg = gen_reg_rtx (SImode); \ + val = force_operand (gen_rtx (PLUS, SImode, xop0, \ + GEN_INT (n)), NULL_RTX); \ + emit_move_insn (base_reg, val); \ + (X) = (low_n == 0 ? base_reg \ + : gen_rtx (PLUS, SImode, base_reg, GEN_INT (low_n))); \ + } \ + else if (xop0 != XEXP (X, 0) || xop1 != XEXP (x, 1)) \ + (X) = gen_rtx (PLUS, SImode, xop0, xop1); \ + } \ + else if (GET_CODE (X) == MINUS) \ + { \ + rtx xop0 = XEXP (X, 0); \ + rtx xop1 = XEXP (X, 1); \ + \ + if (CONSTANT_P (xop0)) \ + xop0 = force_reg (SImode, xop0); \ + if (CONSTANT_P (xop1) && ! symbol_mentioned_p (xop1)) \ + xop1 = force_reg (SImode, xop1); \ + if (xop0 != XEXP (X, 0) || xop1 != XEXP (X, 1)) \ + (X) = gen_rtx (MINUS, SImode, xop0, xop1); \ + } \ + if (flag_pic) \ + (X) = legitimize_pic_address (OLDX, MODE, NULL_RTX); \ + if (memory_address_p (MODE, X)) \ + goto WIN; \ +} + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. */ +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ +{ \ + if (GET_CODE(ADDR) == PRE_DEC || GET_CODE(ADDR) == POST_DEC \ + || GET_CODE(ADDR) == PRE_INC || GET_CODE(ADDR) == POST_INC) \ + goto LABEL; \ +} + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE SImode + +/* 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 */ + +/* Specify the tree operation to be used to convert reals to integers. */ +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* This is the kind of divide that is easiest to do in the general case. */ +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* signed 'char' is most compatible, but RISC OS wants it unsigned. + unsigned is probably best, but may break some code. */ +#ifndef DEFAULT_SIGNED_CHAR +#define DEFAULT_SIGNED_CHAR 0 +#endif + +/* Don't cse the address of the function being compiled. */ +#define NO_RECURSIVE_FUNCTION_CSE 1 + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 4 + +/* Define if operations between registers always perform the operation + on the full register even if a narrower mode is specified. */ +#define WORD_REGISTER_OPERATIONS + +/* Define if loading in MODE, an integral mode narrower than BITS_PER_WORD + will either zero-extend or sign-extend. The value of this macro should + be the code that says which one of the two operations is implicitly + done, NIL if none. */ +#define LOAD_EXTEND_OP(MODE) \ + ((arm_arch4 || (MODE) == QImode) ? ZERO_EXTEND \ + : ((BYTES_BIG_ENDIAN && (MODE) == HImode) ? SIGN_EXTEND : NIL)) + +/* Define this if zero-extension is slow (more than one real instruction). + On the ARM, it is more than one instruction only if not fetching from + memory. */ +/* #define SLOW_ZERO_EXTEND */ + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* Immediate shift counts are truncated by the output routines (or was it + the assembler?). Shift counts in a register are truncated by ARM. Note + that the native compiler puts too large (> 32) immediate shift counts + into a register and shifts by the register, letting the ARM decide what + to do instead of doing that itself. */ +/* This is all wrong. Defining SHIFT_COUNT_TRUNCATED tells combine that + code like (X << (Y % 32)) for register X, Y is equivalent to (X << Y). + On the arm, Y in a register is used modulo 256 for the shift. Only for + rotates is modulo 32 used. */ +/* #define SHIFT_COUNT_TRUNCATED 1 */ + +/* All integers have the same format so truncation is easy. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) 1 + +/* Calling from registers is a massive pain. */ +#define NO_FUNCTION_CSE 1 + +/* Chars and shorts should be passed as ints. */ +#define PROMOTE_PROTOTYPES 1 + +/* The machine modes of pointers and functions */ +#define Pmode SImode +#define FUNCTION_MODE Pmode + +/* The structure type of the machine dependent info field of insns + No uses for this yet. */ +/* #define INSN_MACHINE_INFO struct machine_info */ + +/* The relative costs of various types of constants. Note that cse.c defines + REG = 1, SUBREG = 2, any node = (2 + sum of subnodes). */ +#define CONST_COSTS(RTX, CODE, OUTER_CODE) \ + case CONST_INT: \ + if (const_ok_for_arm (INTVAL (RTX))) \ + return (OUTER_CODE) == SET ? 2 : -1; \ + else if (OUTER_CODE == AND \ + && const_ok_for_arm (~INTVAL (RTX))) \ + return -1; \ + else if ((OUTER_CODE == COMPARE \ + || OUTER_CODE == PLUS || OUTER_CODE == MINUS) \ + && const_ok_for_arm (-INTVAL (RTX))) \ + return -1; \ + else \ + return 5; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 6; \ + case CONST_DOUBLE: \ + if (const_double_rtx_ok_for_fpu (RTX)) \ + return (OUTER_CODE) == SET ? 2 : -1; \ + else if (((OUTER_CODE) == COMPARE || (OUTER_CODE) == PLUS) \ + && neg_const_double_rtx_ok_for_fpu (RTX)) \ + return -1; \ + return(7); + +#define ARM_FRAME_RTX(X) \ + ((X) == frame_pointer_rtx || (X) == stack_pointer_rtx \ + || (X) == arg_pointer_rtx) + +#define DEFAULT_RTX_COSTS(X,CODE,OUTER_CODE) \ + return arm_rtx_costs (X, CODE, OUTER_CODE); + +/* Moves to and from memory are quite expensive */ +#define MEMORY_MOVE_COST(MODE,CLASS,IN) 10 + +/* All address computations that can be done are free, but rtx cost returns + the same for practically all of them. So we weight the different types + of address here in the order (most pref first): + PRE/POST_INC/DEC, SHIFT or NON-INT sum, INT sum, REG, MEM or LABEL. */ +#define ADDRESS_COST(X) \ + (10 - ((GET_CODE (X) == MEM || GET_CODE (X) == LABEL_REF \ + || GET_CODE (X) == SYMBOL_REF) \ + ? 0 \ + : ((GET_CODE (X) == PRE_INC || GET_CODE (X) == PRE_DEC \ + || GET_CODE (X) == POST_INC || GET_CODE (X) == POST_DEC) \ + ? 10 \ + : (((GET_CODE (X) == PLUS || GET_CODE (X) == MINUS) \ + ? 6 + (GET_CODE (XEXP (X, 1)) == CONST_INT ? 2 \ + : ((GET_RTX_CLASS (GET_CODE (XEXP (X, 0))) == '2' \ + || GET_RTX_CLASS (GET_CODE (XEXP (X, 0))) == 'c' \ + || GET_RTX_CLASS (GET_CODE (XEXP (X, 1))) == '2' \ + || GET_RTX_CLASS (GET_CODE (XEXP (X, 1))) == 'c') \ + ? 1 : 0)) \ + : 4))))) + + + +/* Try to generate sequences that don't involve branches, we can then use + conditional instructions */ +#define BRANCH_COST 4 + +/* A C statement to update the variable COST based on the relationship + between INSN that is dependent on DEP through dependence LINK. */ +#define ADJUST_COST(INSN,LINK,DEP,COST) \ + (COST) = arm_adjust_cost ((INSN), (LINK), (DEP), (COST)) + +/* Position Independent Code. */ +/* We decide which register to use based on the compilation options and + the assembler in use; this is more general than the APCS restriction of + using sb (r9) all the time. */ +extern int arm_pic_register; + +/* The register number of the register used to address a table of static + data addresses in memory. */ +#define PIC_OFFSET_TABLE_REGNUM arm_pic_register + +#define FINALIZE_PIC arm_finalize_pic () + +#define LEGITIMATE_PIC_OPERAND_P(X) (! symbol_mentioned_p (X)) + + + +/* Condition code information. */ +/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, + return the mode to be used for the comparison. + CCFPEmode should be used with floating inequalities, + CCFPmode should be used with floating equalities. + CC_NOOVmode should be used with SImode integer equalities. + CC_Zmode should be used if only the Z flag is set correctly + CCmode should be used otherwise. */ + +#define EXTRA_CC_MODES CC_NOOVmode, CC_Zmode, CC_SWPmode, \ + CCFPmode, CCFPEmode, CC_DNEmode, CC_DEQmode, CC_DLEmode, \ + CC_DLTmode, CC_DGEmode, CC_DGTmode, CC_DLEUmode, CC_DLTUmode, \ + CC_DGEUmode, CC_DGTUmode, CC_Cmode + +#define EXTRA_CC_NAMES "CC_NOOV", "CC_Z", "CC_SWP", "CCFP", "CCFPE", \ + "CC_DNE", "CC_DEQ", "CC_DLE", "CC_DLT", "CC_DGE", "CC_DGT", "CC_DLEU", \ + "CC_DLTU", "CC_DGEU", "CC_DGTU", "CC_C" + +enum machine_mode arm_select_cc_mode (); +#define SELECT_CC_MODE(OP,X,Y) arm_select_cc_mode ((OP), (X), (Y)) + +#define REVERSIBLE_CC_MODE(MODE) ((MODE) != CCFPEmode) + +enum rtx_code arm_canonicalize_comparison (); +#define CANONICALIZE_COMPARISON(CODE,OP0,OP1) \ +do \ +{ \ + if (GET_CODE (OP1) == CONST_INT \ + && ! (const_ok_for_arm (INTVAL (OP1)) \ + || (const_ok_for_arm (- INTVAL (OP1))))) \ + { \ + rtx const_op = OP1; \ + CODE = arm_canonicalize_comparison ((CODE), &const_op); \ + OP1 = const_op; \ + } \ +} while (0) + +#define STORE_FLAG_VALUE 1 + +/* Define the information needed to generate branch insns. This is + stored from the compare operation. Note that we can't use "rtx" here + since it hasn't been defined! */ + +extern struct rtx_def *arm_compare_op0, *arm_compare_op1; +extern int arm_compare_fp; + +/* Define the codes that are matched by predicates in arm.c */ +#define PREDICATE_CODES \ + {"s_register_operand", {SUBREG, REG}}, \ + {"f_register_operand", {SUBREG, REG}}, \ + {"arm_add_operand", {SUBREG, REG, CONST_INT}}, \ + {"fpu_add_operand", {SUBREG, REG, CONST_DOUBLE}}, \ + {"arm_rhs_operand", {SUBREG, REG, CONST_INT}}, \ + {"fpu_rhs_operand", {SUBREG, REG, CONST_DOUBLE}}, \ + {"arm_not_operand", {SUBREG, REG, CONST_INT}}, \ + {"offsettable_memory_operand", {MEM}}, \ + {"bad_signed_byte_operand", {MEM}}, \ + {"alignable_memory_operand", {MEM}}, \ + {"shiftable_operator", {PLUS, MINUS, AND, IOR, XOR}}, \ + {"minmax_operator", {SMIN, SMAX, UMIN, UMAX}}, \ + {"shift_operator", {ASHIFT, ASHIFTRT, LSHIFTRT, ROTATERT, MULT}}, \ + {"di_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE, MEM}}, \ + {"soft_df_operand", {SUBREG, REG, CONST_DOUBLE, MEM}}, \ + {"load_multiple_operation", {PARALLEL}}, \ + {"store_multiple_operation", {PARALLEL}}, \ + {"equality_operator", {EQ, NE}}, \ + {"arm_rhsm_operand", {SUBREG, REG, CONST_INT, MEM}}, \ + {"const_shift_operand", {CONST_INT}}, \ + {"index_operand", {SUBREG, REG, CONST_INT}}, \ + {"reg_or_int_operand", {SUBREG, REG, CONST_INT}}, \ + {"multi_register_push", {PARALLEL}}, \ + {"cc_register", {REG}}, \ + {"dominant_cc_register", {REG}}, + + + +/* Gcc puts the pool in the wrong place for ARM, since we can only + load addresses a limited distance around the pc. We do some + special munging to move the constant pool values to the correct + point in the code. */ +#define MACHINE_DEPENDENT_REORG(INSN) arm_reorg ((INSN)) + +/* The pool is empty, since we have moved everything into the code. */ +#define ASM_OUTPUT_SPECIAL_POOL_ENTRY(FILE,X,MODE,ALIGN,LABELNO,JUMPTO) \ + goto JUMPTO + +/* Output an internal label definition. */ +#ifndef ASM_OUTPUT_INTERNAL_LABEL +#define ASM_OUTPUT_INTERNAL_LABEL(STREAM, PREFIX, NUM) \ + do \ + { \ + char * s = (char *) alloca (40 + strlen (PREFIX)); \ + extern int arm_target_label, arm_ccfsm_state; \ + extern rtx arm_target_insn; \ + \ + if (arm_ccfsm_state == 3 && arm_target_label == (NUM) \ + && !strcmp (PREFIX, "L")) \ + { \ + arm_ccfsm_state = 0; \ + arm_target_insn = NULL; \ + } \ + ASM_GENERATE_INTERNAL_LABEL (s, (PREFIX), (NUM)); \ + /* CYGNUS LOCAL variation */ \ + arm_asm_output_label (STREAM, s); \ + /* END CYGNUS LOCAL variation */ \ + } while (0) +#endif + +/* CYGNUS LOCAL */ +/* Output a label definition. */ +#undef ASM_OUTPUT_LABEL +#define ASM_OUTPUT_LABEL(STREAM,NAME) arm_asm_output_label ((STREAM), (NAME)) +/* END CYGNUS LOCAL */ + +/* Output a push or a pop instruction (only used when profiling). */ +#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ + fprintf (STREAM,"\tstmfd\t%ssp!,{%s%s}\n", \ + REGISTER_PREFIX, REGISTER_PREFIX, reg_names [REGNO]) + +#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \ + fprintf (STREAM,"\tldmfd\t%ssp!,{%s%s}\n", \ + REGISTER_PREFIX, REGISTER_PREFIX, reg_names [REGNO]) + +/* Target characters. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* Only perform branch elimination (by making instructions conditional) if + we're optimising. Otherwise it's of no use anyway. */ +#define FINAL_PRESCAN_INSN(INSN, OPVEC, NOPERANDS) \ + if (optimize) \ + final_prescan_insn (INSN, OPVEC, NOPERANDS) + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '?' || (CODE) == '|' || (CODE) == '@') +/* Output an operand of an instruction. */ +#define PRINT_OPERAND(STREAM, X, CODE) \ + arm_print_operand (STREAM, X, CODE) + +#define ARM_SIGN_EXTEND(x) ((HOST_WIDE_INT) \ + (HOST_BITS_PER_WIDE_INT <= 32 ? (x) \ + : (((x) & (unsigned HOST_WIDE_INT) 0xffffffff) | \ + (((x) & (unsigned HOST_WIDE_INT) 0x80000000) \ + ? ((~ (HOST_WIDE_INT) 0) \ + & ~ (unsigned HOST_WIDE_INT) 0xffffffff) \ + : 0)))) + +/* Output the address of an operand. */ +#define PRINT_OPERAND_ADDRESS(STREAM,X) \ +{ \ + int is_minus = GET_CODE (X) == MINUS; \ + \ + if (GET_CODE (X) == REG) \ + fprintf (STREAM, "[%s%s, #0]", REGISTER_PREFIX, \ + reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == PLUS || is_minus) \ + { \ + rtx base = XEXP (X, 0); \ + rtx index = XEXP (X, 1); \ + char * base_reg_name; \ + HOST_WIDE_INT offset = 0; \ + if (GET_CODE (base) != REG) \ + { \ + /* Ensure that BASE is a register (one of them must be). */ \ + rtx temp = base; \ + base = index; \ + index = temp; \ + } \ + base_reg_name = reg_names[REGNO (base)]; \ + switch (GET_CODE (index)) \ + { \ + case CONST_INT: \ + offset = INTVAL (index); \ + if (is_minus) \ + offset = -offset; \ + fprintf (STREAM, "[%s%s, #%d]", REGISTER_PREFIX, \ + base_reg_name, offset); \ + break; \ + \ + case REG: \ + fprintf (STREAM, "[%s%s, %s%s%s]", REGISTER_PREFIX, \ + base_reg_name, is_minus ? "-" : "", \ + REGISTER_PREFIX, reg_names[REGNO (index)] ); \ + break; \ + \ + case MULT: \ + case ASHIFTRT: \ + case LSHIFTRT: \ + case ASHIFT: \ + case ROTATERT: \ + { \ + fprintf (STREAM, "[%s%s, %s%s%s", REGISTER_PREFIX, \ + base_reg_name, is_minus ? "-" : "", REGISTER_PREFIX,\ + reg_names[REGNO (XEXP (index, 0))]); \ + arm_print_operand (STREAM, index, 'S'); \ + fputs ("]", STREAM); \ + break; \ + } \ + \ + default: \ + abort(); \ + } \ + } \ + else if (GET_CODE (X) == PRE_INC || GET_CODE (X) == POST_INC \ + || GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_DEC) \ + { \ + extern int output_memory_reference_mode; \ + \ + if (GET_CODE (XEXP (X, 0)) != REG) \ + abort (); \ + \ + if (GET_CODE (X) == PRE_DEC || GET_CODE (X) == PRE_INC) \ + fprintf (STREAM, "[%s%s, #%s%d]!", REGISTER_PREFIX, \ + reg_names[REGNO (XEXP (X, 0))], \ + GET_CODE (X) == PRE_DEC ? "-" : "", \ + GET_MODE_SIZE (output_memory_reference_mode)); \ + else \ + fprintf (STREAM, "[%s%s], #%s%d", REGISTER_PREFIX, \ + reg_names[REGNO (XEXP (X, 0))], \ + GET_CODE (X) == POST_DEC ? "-" : "", \ + GET_MODE_SIZE (output_memory_reference_mode)); \ + } \ + else output_addr_const(STREAM, X); \ +} + +/* Handles PIC addr specially */ +#define OUTPUT_INT_ADDR_CONST(STREAM,X) \ + { \ + if (flag_pic && GET_CODE(X) == CONST && is_pic(X)) \ + { \ + output_addr_const(STREAM, XEXP (XEXP (XEXP (X, 0), 0), 0)); \ + fputs(" - (", STREAM); \ + output_addr_const(STREAM, XEXP (XEXP (XEXP (X, 0), 1), 0)); \ + fputs(")", STREAM); \ + } \ + else output_addr_const(STREAM, X); \ + } + +/* Output code to add DELTA to the first argument, and then jump to FUNCTION. + Used for C++ multiple inheritance. */ +#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ +do { \ + int mi_delta = (DELTA); \ + char *mi_op = mi_delta < 0 ? "sub" : "add"; \ + int shift = 0; \ + int this_regno = (aggregate_value_p (TREE_TYPE (TREE_TYPE (FUNCTION))) \ + ? 1 : 0); \ + if (mi_delta < 0) mi_delta = -mi_delta; \ + while (mi_delta != 0) \ + { \ + if (mi_delta & (3 << shift) == 0) \ + shift += 2; \ + else \ + { \ + fprintf (FILE, "\t%s\t%s%s, %s%s, #%d\n", \ + mi_op, REGISTER_PREFIX, reg_names[this_regno], \ + REGISTER_PREFIX, reg_names[this_regno], \ + mi_delta & (0xff << shift)); \ + /* CYGNUS LOCAL */ \ + arm_increase_location (4); \ + /* END CYGNUS LOCAL */ \ + mi_delta &= ~(0xff << shift); \ + shift += 8; \ + } \ + } \ + fputs ("\tb\t", FILE); \ + assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ + fputc ('\n', FILE); \ + /* CYGNUS LOCAL */ \ + arm_increase_location (4); \ + /* END CYGNUS LOCAL */ \ +} while (0) + +/* A C expression whose value is RTL representing the value of the return + address for the frame COUNT steps up from the current frame. */ + +#define RETURN_ADDR_RTX(COUNT, FRAME) \ + ((COUNT == 0) \ + ? gen_rtx (MEM, Pmode, plus_constant (FRAME, -4)) \ + : NULL_RTX) + +/* Used to mask out junk bits from the return address, such as + processor state, interrupt status, condition codes and the like. */ +#define MASK_RETURN_ADDR \ + /* If we are generating code for an ARM2/ARM3 machine or for an ARM6 \ + in 26 bit mode, the condition codes must be masked out of the \ + return address. This does not apply to ARM6 and later processors \ + when running in 32 bit mode. */ \ + ((!TARGET_APCS_32) ? (GEN_INT (0x03fffffc)) : (GEN_INT (0xffffffff))) + +/* Prototypes for arm.c -- actually, they aren't since the types aren't + fully defined yet. */ + +void arm_override_options (/* void */); +int use_return_insn (/* void */); +int const_ok_for_arm (/* HOST_WIDE_INT */); +int const_ok_for_op (/* HOST_WIDE_INT, enum rtx_code, + enum machine_mode */); +int arm_split_constant (/* enum rtx_code, enum machine_mode, + HOST_WIDE_INT, struct rtx_def *, + struct rtx_def *, int */); +enum rtx_code arm_canonicalize_comparison (/* enum rtx_code, + struct rtx_def ** */); +int arm_return_in_memory (/* union tree_node * */); +int legitimate_pic_operand_p (/* struct rtx_def * */); +struct rtx_def *legitimize_pic_address (/* struct rtx_def *, + enum machine_mode, + struct rtx_def * */); +int is_pic (/* struct rtx_def * */); +void arm_finalize_pic (/* void */); +int arm_rtx_costs (/* struct rtx_def *, enum rtx_code, enum rtx_code */); +int arm_adjust_cost (/* struct rtx_def *, struct rtx_def *, + struct rtx_def *, int */); +int const_double_rtx_ok_for_fpu (/* struct rtx_def * */); +int neg_const_double_rtx_ok_for_fpu (/* struct rtx_def * */); +int s_register_operand (/* struct rtx_def *, enum machine_mode */); +int f_register_operand (/* struct rtx_def *, enum machine_mode */); +int reg_or_int_operand (/* struct rtx_def *, enum machine_mode */); +int reload_memory_operand (/* struct rtx_def *, enum machine_mode */); +int arm_rhs_operand (/* struct rtx_def *, enum machine_mode */); +int arm_rhsm_operand (/* struct rtx_def *, enum machine_mode */); +int arm_add_operand (/* struct rtx_def *, enum machine_mode */); +int arm_not_operand (/* struct rtx_def *, enum machine_mode */); +int offsettable_memory_operand (/* struct rtx_def *, enum machine_mode */); +int alignable_memory_operand (/* struct rtx_def *, enum machine_mode */); +int bad_signed_byte_operand (/* struct rtx_def *, enum machine_mode */); +int fpu_rhs_operand (/* struct rtx_def *, enum machine_mode */); +int fpu_add_operand (/* struct rtx_def *, enum machine_mode */); +int power_of_two_operand (/* struct rtx_def *, enum machine_mode */); +int di_operand (/* struct rtx_def *, enum machine_mode */); +int soft_df_operand (/* struct rtx_def *, enum machine_mode */); +int index_operand (/* struct rtx_def *, enum machine_mode */); +int const_shift_operand (/* struct rtx_def *, enum machine_mode */); +int shiftable_operator (/* struct rtx_def *, enum machine_mode */); +int shift_operator (/* struct rtx_def *, enum machine_mode */); +int equality_operator (/* struct rtx_def *, enum machine_mode */); +int minmax_operator (/* struct rtx_def *, enum machine_mode */); +int cc_register (/* struct rtx_def *, enum machine_mode */); +int dominant_cc_register (/* struct rtx_def *, enum machine_mode */); +int symbol_mentioned_p (/* struct rtx_def * */); +int label_mentioned_p (/* struct rtx_def * */); +enum rtx_code minmax_code (/* struct rtx_def * */); +int adjacent_mem_locations (/* struct rtx_def *, struct rtx_def * */); +int load_multiple_operation (/* struct rtx_def *, enum machine_mode */); +int store_multiple_operation (/* struct rtx_def *, enum machine_mode */); +int load_multiple_sequence (/* struct rtx_def **, int, int *, int *, + HOST_WIDE_INT * */); +char *emit_ldm_seq (/* struct rtx_def **, int */); +int store_multiple_sequence (/* struct rtx_def **, int, int *, int *, + HOST_WIDE_INT * */); +char *emit_stm_seq (/* struct rtx_def **, int */); +int multi_register_push (/* struct rtx_def *, enum machine_mode */); +int arm_valid_machine_decl_attribute (/* union tree_node *, union tree_node *, + union tree_node *, + union tree_node * */); +struct rtx_def *arm_gen_load_multiple (/* int, int, struct rtx_def *, + int, int, int, int, int */); +struct rtx_def *arm_gen_store_multiple (/* int, int, struct rtx_def *, + int, int, int, int, int */); +int arm_gen_movstrqi (/* struct rtx_def ** */); +struct rtx_def *gen_rotated_half_load (/* struct rtx_def * */); +enum machine_mode arm_select_cc_mode (/* enum rtx_code, struct rtx_def *, + struct rtx_def * */); +struct rtx_def *gen_compare_reg (/* enum rtx_code, struct rtx_def *, + struct rtx_def * */); +void arm_reload_in_hi (/* struct rtx_def ** */); +void arm_reload_out_hi (/* struct rtx_def ** */); +void arm_reorg (/* struct rtx_def * */); +char *fp_immediate_constant (/* struct rtx_def * */); +void print_multi_reg (/* FILE *, char *, int, int */); +char *output_call (/* struct rtx_def ** */); +char *output_call_mem (/* struct rtx_def ** */); +char *output_mov_long_double_fpu_from_arm (/* struct rtx_def ** */); +char *output_mov_long_double_arm_from_fpu (/* struct rtx_def ** */); +char *output_mov_long_double_arm_from_arm (/* struct rtx_def ** */); +char *output_mov_double_fpu_from_arm (/* struct rtx_def ** */); +char *output_mov_double_arm_from_fpu (/* struct rtx_def ** */); +char *output_move_double (/* struct rtx_def ** */); +char *output_mov_immediate (/* struct rtx_def ** */); +char *output_add_immediate (/* struct rtx_def ** */); +char *arithmetic_instr (/* struct rtx_def *, int */); +void output_ascii_pseudo_op (/* FILE *, unsigned char *, int */); +char *output_return_instruction (/* struct rtx_def *, int, int */); +int arm_volatile_func (/* void */); +void output_func_prologue (/* FILE *, int */); +void output_func_epilogue (/* FILE *, int */); +void arm_expand_prologue (/* void */); +void arm_print_operand (/* FILE *, struct rtx_def *, int */); +void final_prescan_insn (/* struct rtx_def *, struct rtx_def **, int */); +#ifdef AOF_ASSEMBLER +struct rtx_def *aof_pic_entry (/* struct rtx_def * */); +void aof_dump_pic_table (/* FILE * */); +char *aof_text_section (/* void */); +char *aof_data_section (/* void */); +void aof_add_import (/* char * */); +void aof_delete_import (/* char * */); +void aof_dump_imports (/* FILE * */); +#endif +/* CYGNUS LOCAL nickc */ +int ok_integer_or_other (); +/* END CYGNUS LOCAL */ +int s_register_operand (/* register rtx op, enum machine_mode mode */); + +#endif /* __ARM_H__ */ diff --git a/gcc_arm/config/arm/arm.md b/gcc_arm/config/arm/arm.md new file mode 100755 index 0000000..77f98e3 --- /dev/null +++ b/gcc_arm/config/arm/arm.md @@ -0,0 +1,6496 @@ +;;- Machine description for Advanced RISC Machines' ARM for GNU compiler +;; Copyright (C) 1991, 93-98, 1999, 2002 Free Software Foundation, Inc. +;; Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl) +;; and Martin Simmons (@harleqn.co.uk). +;; More major hacks by Richard Earnshaw (rwe11@cl.cam.ac.uk) + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + +;; There are patterns in this file to support XFmode arithmetic. +;; Unfortunately RISC iX doesn't work well with these so they are disabled. +;; (See arm.h) + +;; UNSPEC Usage: +;; 0 `sin' operation: operand 0 is the result, operand 1 the parameter, +;; the mode is MODE_FLOAT +;; 1 `cos' operation: operand 0 is the result, operand 1 the parameter, +;; the mode is MODE_FLOAT +;; 2 `push multiple' operation: operand 0 is the first register. Subsequent +;; registers are in parallel (use...) expressions. +;; 3 A symbol that has been treated properly for pic usage, that is, we +;; will add the pic_register value to it before trying to dereference it. +;; Note: sin and cos are no-longer used. + +;; Attributes + +; PROG_MODE attribute is used to determine whether condition codes are +; clobbered by a call insn: they are if in prog32 mode. This is controlled +; by the -mapcs-{32,26} flag, and possibly the -mcpu=... option. +(define_attr "prog_mode" "prog26,prog32" (const (symbol_ref "arm_prog_mode"))) + +(define_attr "is_strongarm" "no,yes" (const (symbol_ref "arm_is_strong"))) + +; Floating Point Unit. If we only have floating point emulation, then there +; is no point in scheduling the floating point insns. (Well, for best +; performance we should try and group them together). + +(define_attr "fpu" "fpa,fpe2,fpe3" (const (symbol_ref "arm_fpu_attr"))) + +; LENGTH of an instruction (in bytes) +(define_attr "length" "" (const_int 4)) + +; An assembler sequence may clobber the condition codes without us knowing +(define_asm_attributes + [(set_attr "conds" "clob") + (set_attr "length" "4")]) + +; TYPE attribute is used to detect floating point instructions which, if +; running on a co-processor can run in parallel with other, basic instructions +; If write-buffer scheduling is enabled then it can also be used in the +; scheduling of writes. + +; Classification of each insn +; normal any data instruction that doesn't hit memory or fp regs +; mult a multiply instruction +; block blockage insn, this blocks all functional units +; float a floating point arithmetic operation (subject to expansion) +; fdivx XFmode floating point division +; fdivd DFmode floating point division +; fdivs SFmode floating point division +; fmul Floating point multiply +; ffmul Fast floating point multiply +; farith Floating point arithmetic (4 cycle) +; ffarith Fast floating point arithmetic (2 cycle) +; float_em a floating point arithmetic operation that is normally emulated +; even on a machine with an fpa. +; f_load a floating point load from memory +; f_store a floating point store to memory +; f_mem_r a transfer of a floating point register to a real reg via mem +; r_mem_f the reverse of f_mem_r +; f_2_r fast transfer float to arm (no memory needed) +; r_2_f fast transfer arm to float +; call a subroutine call +; load any load from memory +; store1 store 1 word to memory from arm registers +; store2 store 2 words +; store3 store 3 words +; store4 store 4 words +; +(define_attr "type" + "normal,mult,block,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith,float_em,f_load,f_store,f_mem_r,r_mem_f,f_2_r,r_2_f,call,load,store1,store2,store3,store4" + (const_string "normal")) + +;; CYGNUS LOCAL load scheduling +; Load scheduling, set from the arm_ld_sched variable +; initialised by arm_override_options() +(define_attr "ldsched" "no,yes" + (const (symbol_ref "arm_ld_sched"))) +;; END CYGNUS LOCAL + +; condition codes: this one is used by final_prescan_insn to speed up +; conditionalizing instructions. It saves having to scan the rtl to see if +; it uses or alters the condition codes. + +; USE means that the condition codes are used by the insn in the process of +; outputting code, this means (at present) that we can't use the insn in +; inlined branches + +; SET means that the purpose of the insn is to set the condition codes in a +; well defined manner. + +; CLOB means that the condition codes are altered in an undefined manner, if +; they are altered at all + +; JUMP_CLOB is used when the conditions are not defined if a branch is taken, +; but are if the branch wasn't taken; the effect is to limit the branch +; elimination scanning. + +; NOCOND means that the condition codes are neither altered nor affect the +; output of this insn + +(define_attr "conds" "use,set,clob,jump_clob,nocond" + (if_then_else (eq_attr "type" "call") + (if_then_else (eq_attr "prog_mode" "prog32") + (const_string "clob") (const_string "nocond")) + (const_string "nocond"))) + +; Only model the write buffer for ARM6 and ARM7. Earlier processors don't +; have one. Later ones, such as StrongARM, have write-back caches, so don't +; suffer blockages enough to warrent modelling this (and it can adversely +; affect the schedule). +(define_attr "model_wbuf" "no,yes" (const (symbol_ref "arm_is_6_or_7"))) + +(define_attr "write_conflict" "no,yes" + (if_then_else (eq_attr "type" + "block,float_em,f_load,f_store,f_mem_r,r_mem_f,call,load") + (const_string "yes") + (const_string "no"))) + +(define_attr "core_cycles" "single,multi" + (if_then_else (eq_attr "type" + "normal,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith") + (const_string "single") + (const_string "multi"))) + +; The write buffer on some of the arm6 processors is hard to model exactly. +; There is room in the buffer for up to two addresses and up to eight words +; of memory, but the two needn't be split evenly. When writing the two +; addresses are fully pipelined. However, a read from memory that is not +; currently in the cache will block until the writes have completed. +; It is normally the case that FCLK and MCLK will be in the ratio 2:1, so +; writes will take 2 FCLK cycles per word, if FCLK and MCLK are asynchronous +; (they aren't allowed to be at present) then there is a startup cost of 1MCLK +; cycle to add as well. + +;; (define_function_unit {name} {num-units} {n-users} {test} +;; {ready-delay} {issue-delay} [{conflict-list}]) +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "fdivx")) 71 69) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "fdivd")) 59 57) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "fdivs")) 31 29) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "fmul")) 9 7) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "ffmul")) 6 4) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "farith")) 4 2) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "ffarith")) 2 2) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "r_2_f")) 5 3) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "f_2_r")) 1 2) + +;; The fpa10 doesn't really have a memory read unit, but it can start to +;; speculatively execute the instruction in the pipeline, provided the data +;; is already loaded, so pretend reads have a delay of 2 (and that the +;; pipeline is infinite. + +(define_function_unit "fpa_mem" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "f_load")) 3 1) + +;;-------------------------------------------------------------------- +;; Write buffer +;;-------------------------------------------------------------------- +;; Strictly we should model a 4-deep write buffer for ARM7xx based chips +(define_function_unit "write_buf" 1 2 + (and (eq_attr "model_wbuf" "yes") + (eq_attr "type" "store1,r_mem_f")) 5 3) +(define_function_unit "write_buf" 1 2 + (and (eq_attr "model_wbuf" "yes") + (eq_attr "type" "store2")) 7 4) +(define_function_unit "write_buf" 1 2 + (and (eq_attr "model_wbuf" "yes") + (eq_attr "type" "store3")) 9 5) +(define_function_unit "write_buf" 1 2 + (and (eq_attr "model_wbuf" "yes") + (eq_attr "type" "store4")) 11 6) + +;;-------------------------------------------------------------------- +;; Write blockage unit +;;-------------------------------------------------------------------- +;; The write_blockage unit models (partially), the fact that reads will stall +;; until the write buffer empties. +;; The f_mem_r and r_mem_f could also block, but they are to the stack, +;; so we don't model them here +(define_function_unit "write_blockage" 1 0 (and (eq_attr "model_wbuf" "yes") + (eq_attr "type" "store1")) 5 5 + [(eq_attr "write_conflict" "yes")]) +(define_function_unit "write_blockage" 1 0 (and (eq_attr "model_wbuf" "yes") + (eq_attr "type" "store2")) 7 7 + [(eq_attr "write_conflict" "yes")]) +(define_function_unit "write_blockage" 1 0 (and (eq_attr "model_wbuf" "yes") + (eq_attr "type" "store3")) 9 9 + [(eq_attr "write_conflict" "yes")]) +(define_function_unit "write_blockage" 1 0 + (and (eq_attr "model_wbuf" "yes") (eq_attr "type" "store4")) 11 11 + [(eq_attr "write_conflict" "yes")]) +(define_function_unit "write_blockage" 1 0 + (and (eq_attr "model_wbuf" "yes") + (eq_attr "write_conflict" "yes")) 1 1) + +;;-------------------------------------------------------------------- +;; Core unit +;;-------------------------------------------------------------------- +;; Everything must spend at least one cycle in the core unit +(define_function_unit "core" 1 0 + (and (eq_attr "ldsched" "yes") (eq_attr "type" "store1")) 1 1) + +(define_function_unit "core" 1 0 + (and (eq_attr "ldsched" "yes") (eq_attr "type" "load")) 2 1) + +(define_function_unit "core" 1 0 + (and (eq_attr "ldsched" "!yes") (eq_attr "type" "load,store1")) 2 2) + +(define_function_unit "core" 1 0 + (and (eq_attr "fpu" "fpa") (eq_attr "type" "f_load")) 3 3) + +(define_function_unit "core" 1 0 + (and (eq_attr "fpu" "fpa") (eq_attr "type" "f_store")) 4 4) + +(define_function_unit "core" 1 0 + (and (eq_attr "fpu" "fpa") (eq_attr "type" "r_mem_f")) 6 6) + +(define_function_unit "core" 1 0 + (and (eq_attr "fpu" "fpa") (eq_attr "type" "f_mem_r")) 7 7) + +(define_function_unit "core" 1 0 + (and (eq_attr "ldsched" "no") (eq_attr "type" "mult")) 16 16) + +(define_function_unit "core" 1 0 + (and (and (eq_attr "ldsched" "yes") (eq_attr "is_strongarm" "no")) + (eq_attr "type" "mult")) 4 4) + +(define_function_unit "core" 1 0 + (and (and (eq_attr "ldsched" "yes") (eq_attr "is_strongarm" "yes")) + (eq_attr "type" "mult")) 3 2) + +(define_function_unit "core" 1 0 (eq_attr "type" "store2") 3 3) + +(define_function_unit "core" 1 0 (eq_attr "type" "store3") 4 4) + +(define_function_unit "core" 1 0 (eq_attr "type" "store4") 5 5) + +;; CYGNUS LOCAL +;; APCS support: When generating code for the software stack checking +;; model, we need to be able to perform calls to the special exception +;; handler routines. These routines are *NOT* APCS conforming, so we +;; do not need to mark any registers as clobbered over the call other +;; than the lr/r14 modified by the actual BL instruction. Rather than +;; trying to force the RTL for the existing comparison and call to +;; achieve this, we simply have a pattern that does the desired job. + +;; TODO: This is not ideal since it does not specify all of the +;; operators involved: +;; cmp %op0,%op1 cmpsi_insn (compare) +;; bl%op3 %op2 call_value_symbol (call) +;; Unfortunately since we do not go through the normal arm_ccfsm_state +;; processing we cannot use the %? operand replacment for the BL +;; condition. + +(define_insn "cond_call" + [(compare:CC (match_operand:SI 0 "s_register_operand" "r") + (match_operand:SI 1 "s_register_operand" "r")) + (match_operand:SI 2 "" "X") + (match_operator 3 "comparison_operator" [(reg:CC 24) (const_int 0)]) + (clobber (reg:CC 24)) + (clobber (reg:SI 14))] + "GET_CODE (operands[2]) == SYMBOL_REF && GET_CODE (operands[3]) == LTU" + "cmp\\t%0, %1\;bllt\\t%a2" +[(set_attr "conds" "clob") + (set_attr "type" "call") + (set_attr "length" "8")]) + +;; END CYGNUS LOCAL + +;; Note: For DImode insns, there is normally no reason why operands should +;; not be in the same register, what we don't want is for something being +;; written to partially overlap something that is an input. + +;; Addition insns. + +(define_insn "adddi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (plus:DI (match_operand:DI 1 "s_register_operand" "%0,0") + (match_operand:DI 2 "s_register_operand" "r,0"))) + (clobber (reg:CC 24))] + "" + "adds\\t%Q0, %Q1, %Q2\;adc\\t%R0, %R1, %R2" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*adddi_sesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (plus:DI (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "r,0"))) + (clobber (reg:CC 24))] + "" + "adds\\t%Q0, %Q1, %2\;adc\\t%R0, %R1, %2, asr #31" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*adddi_zesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (plus:DI (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "r,0"))) + (clobber (reg:CC 24))] + "" + "adds\\t%Q0, %Q1, %2\;adc\\t%R0, %R1, #0" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_expand "addsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (plus:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "reg_or_int_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT) + { + arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0], + operands[1], + (reload_in_progress || reload_completed ? 0 + : preserve_subexpressions_p ())); + DONE; + } +") + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (plus:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "const_int_operand" "")))] + "! (const_ok_for_arm (INTVAL (operands[2])) + || const_ok_for_arm (-INTVAL (operands[2])))" + [(clobber (const_int 0))] + " + arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0], + operands[1], 0); + DONE; +") + +(define_insn "*addsi3_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (plus:SI (match_operand:SI 1 "s_register_operand" "r,r,r") + (match_operand:SI 2 "reg_or_int_operand" "rI,L,?n")))] + "" + "@ + add%?\\t%0, %1, %2 + sub%?\\t%0, %1, #%n2 + #" +[(set_attr "length" "4,4,16")]) + +(define_insn "*addsi3_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (plus:SI (match_operand:SI 1 "s_register_operand" "r,r") + (match_operand:SI 2 "arm_add_operand" "rI,L")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") + (plus:SI (match_dup 1) (match_dup 2)))] + "" + "@ + add%?s\\t%0, %1, %2 + sub%?s\\t%0, %1, #%n2" +[(set_attr "conds" "set")]) + +(define_insn "*addsi3_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (plus:SI (match_operand:SI 0 "s_register_operand" "r,r") + (match_operand:SI 1 "arm_add_operand" "rI,L")) + (const_int 0)))] + "" + "@ + cmn%?\\t%0, %1 + cmp%?\\t%0, #%n1" +[(set_attr "conds" "set")]) + +;; The next four insns work because they compare the result with one of +;; the operands, and we know that the use of the condition code is +;; either GEU or LTU, so we can use the carry flag from the addition +;; instead of doing the compare a second time. +(define_insn "*addsi3_compare_op1" + [(set (reg:CC_C 24) + (compare:CC_C + (plus:SI (match_operand:SI 1 "s_register_operand" "r,r") + (match_operand:SI 2 "arm_add_operand" "rI,L")) + (match_dup 1))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") + (plus:SI (match_dup 1) (match_dup 2)))] + "" + "@ + add%?s\\t%0, %1, %2 + sub%?s\\t%0, %1, #%n2" +[(set_attr "conds" "set")]) + +(define_insn "*addsi3_compare_op2" + [(set (reg:CC_C 24) + (compare:CC_C + (plus:SI (match_operand:SI 1 "s_register_operand" "r,r") + (match_operand:SI 2 "arm_add_operand" "rI,L")) + (match_dup 2))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") + (plus:SI (match_dup 1) (match_dup 2)))] + "" + "@ + add%?s\\t%0, %1, %2 + sub%?s\\t%0, %1, #%n2" +[(set_attr "conds" "set")]) + +(define_insn "*compare_addsi2_op0" + [(set (reg:CC_C 24) + (compare:CC_C + (plus:SI (match_operand:SI 0 "s_register_operand" "r,r") + (match_operand:SI 1 "arm_add_operand" "rI,L")) + (match_dup 0)))] + "" + "@ + cmn%?\\t%0, %1 + cmp%?\\t%0, #%n1" +[(set_attr "conds" "set")]) + +(define_insn "*compare_addsi2_op1" + [(set (reg:CC_C 24) + (compare:CC_C + (plus:SI (match_operand:SI 0 "s_register_operand" "r,r") + (match_operand:SI 1 "arm_add_operand" "rI,L")) + (match_dup 1)))] + "" + "@ + cmn%?\\t%0, %1 + cmp%?\\t%0, #%n1" +[(set_attr "conds" "set")]) + +(define_insn "*addsi3_carryin" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (ltu:SI (reg:CC_C 24) (const_int 0)) + (plus:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rI"))))] + "" + "adc%?\\t%0, %1, %2" +[(set_attr "conds" "use")]) + +(define_insn "*addsi3_carryin_alt1" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (plus:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rI")) + (ltu:SI (reg:CC_C 24) (const_int 0))))] + "" + "adc%?\\t%0, %1, %2" +[(set_attr "conds" "use")]) + +(define_insn "*addsi3_carryin_alt2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (plus:SI (ltu:SI (reg:CC_C 24) (const_int 0)) + (match_operand:SI 1 "s_register_operand" "r")) + (match_operand:SI 2 "arm_rhs_operand" "rI")))] + "" + "adc%?\\t%0, %1, %2" +[(set_attr "conds" "use")]) + +(define_insn "*addsi3_carryin_alt3" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (plus:SI (ltu:SI (reg:CC_C 24) (const_int 0)) + (match_operand:SI 2 "arm_rhs_operand" "rI")) + (match_operand:SI 1 "s_register_operand" "r")))] + "" + "adc%?\\t%0, %1, %2" +[(set_attr "conds" "use")]) + +(define_insn "incscc" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (plus:SI (match_operator:SI 2 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "s_register_operand" "0,?r")))] + "" + "@ + add%d2\\t%0, %1, #1 + mov%D2\\t%0, %1\;add%d2\\t%0, %1, #1" +[(set_attr "conds" "use") + (set_attr "length" "4,8")]) + +; If a constant is too big to fit in a single instruction then the constant +; will be pre-loaded into a register taking at least two insns, we might be +; able to merge it with an add, but it depends on the exact value. + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "const_int_operand" "n")))] + "!(const_ok_for_arm (INTVAL (operands[2])) + || const_ok_for_arm (-INTVAL (operands[2])))" + [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2))) + (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 3)))] + " +{ + unsigned int val = (unsigned) INTVAL (operands[2]); + int i; + unsigned int temp; + + /* this code is similar to the approach followed in movsi, but it must + generate exactly two insns */ + + for (i = 30; i >= 0; i -= 2) + { + if (val & (3 << i)) + { + i -= 6; + if (i < 0) i = 0; + if (const_ok_for_arm (temp = (val & ~(255 << i)))) + { + val &= 255 << i; + break; + } + /* we might be able to do this as (larger number - small number) */ + temp = ((val >> i) & 255) + 1; + if (temp > 255 && i < 24) + { + i += 2; + temp = ((val >> i) & 255) + 1; + } + if (const_ok_for_arm ((temp << i) - val)) + { + i = temp << i; + temp = (unsigned) - (int) (i - val); + val = i; + break; + } + FAIL; + } + } + /* if we got here, we have found a way of doing it in two instructions. + the two constants are in val and temp */ + operands[2] = GEN_INT ((int)val); + operands[3] = GEN_INT ((int)temp); +} +") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "s_register_operand" "=f,f") + (plus:SF (match_operand:SF 1 "s_register_operand" "f,f") + (match_operand:SF 2 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + adf%?s\\t%0, %1, %2 + suf%?s\\t%0, %1, #%N2" +[(set_attr "type" "farith")]) + +(define_insn "adddf3" + [(set (match_operand:DF 0 "s_register_operand" "=f,f") + (plus:DF (match_operand:DF 1 "s_register_operand" "f,f") + (match_operand:DF 2 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + adf%?d\\t%0, %1, %2 + suf%?d\\t%0, %1, #%N2" +[(set_attr "type" "farith")]) + +(define_insn "*adddf_df_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f,f") + (plus:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f,f")) + (match_operand:DF 2 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + adf%?d\\t%0, %1, %2 + suf%?d\\t%0, %1, #%N2" +[(set_attr "type" "farith")]) + +(define_insn "*adddf_df_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (plus:DF (match_operand:DF 1 "s_register_operand" "f") + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "adf%?d\\t%0, %1, %2" +[(set_attr "type" "farith")]) + +(define_insn "*adddf_esfdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (plus:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "adf%?d\\t%0, %1, %2" +[(set_attr "type" "farith")]) + +(define_insn "addxf3" + [(set (match_operand:XF 0 "s_register_operand" "=f,f") + (plus:XF (match_operand:XF 1 "s_register_operand" "f,f") + (match_operand:XF 2 "fpu_add_operand" "fG,H")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "@ + adf%?e\\t%0, %1, %2 + suf%?e\\t%0, %1, #%N2" +[(set_attr "type" "farith")]) + +(define_insn "subdi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r,&r") + (minus:DI (match_operand:DI 1 "s_register_operand" "0,r,0") + (match_operand:DI 2 "s_register_operand" "r,0,0"))) + (clobber (reg:CC 24))] + "" + "subs\\t%Q0, %Q1, %Q2\;sbc\\t%R0, %R1, %R2" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*subdi_di_zesidi" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (minus:DI (match_operand:DI 1 "s_register_operand" "?r,0") + (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")))) + (clobber (reg:CC 24))] + "" + "subs\\t%Q0, %Q1, %2\;sbc\\t%R0, %R1, #0" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*subdi_di_sesidi" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (minus:DI (match_operand:DI 1 "s_register_operand" "r,0") + (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")))) + (clobber (reg:CC 24))] + "" + "subs\\t%Q0, %Q1, %2\;sbc\\t%R0, %R1, %2, asr #31" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*subdi_zesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (minus:DI (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "?r,0"))) + (clobber (reg:CC 24))] + "" + "rsbs\\t%Q0, %Q1, %2\;rsc\\t%R0, %R1, #0" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*subdi_sesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (minus:DI (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "?r,0"))) + (clobber (reg:CC 24))] + "" + "rsbs\\t%Q0, %Q1, %2\;rsc\\t%R0, %R1, %2, asr #31" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*subdi_zesidi_zesidi" + [(set (match_operand:DI 0 "s_register_operand" "=r") + (minus:DI (zero_extend:DI + (match_operand:SI 1 "s_register_operand" "r")) + (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r")))) + (clobber (reg:CC 24))] + "" + "subs\\t%Q0, %1, %2\;rsc\\t%R0, %1, %1" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_expand "subsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (minus:SI (match_operand:SI 1 "reg_or_int_operand" "") + (match_operand:SI 2 "s_register_operand" "")))] + "" + " + if (GET_CODE (operands[1]) == CONST_INT) + { + arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0], + operands[2], + (reload_in_progress || reload_completed ? 0 + : preserve_subexpressions_p ())); + DONE; + } +") + +(define_insn "*subsi3_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (minus:SI (match_operand:SI 1 "reg_or_int_operand" "rI,?n") + (match_operand:SI 2 "s_register_operand" "r,r")))] + "" + "@ + rsb%?\\t%0, %2, %1 + #" +[(set_attr "length" "4,16")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (minus:SI (match_operand:SI 1 "const_int_operand" "") + (match_operand:SI 2 "s_register_operand" "")))] + "! const_ok_for_arm (INTVAL (operands[1]))" + [(clobber (const_int 0))] + " + arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0], + operands[2], 0); + DONE; +") + +(define_insn "*subsi3_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (minus:SI (match_operand:SI 1 "arm_rhs_operand" "r,I") + (match_operand:SI 2 "arm_rhs_operand" "rI,r")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") + (minus:SI (match_dup 1) (match_dup 2)))] + "" + "@ + sub%?s\\t%0, %1, %2 + rsb%?s\\t%0, %2, %1" +[(set_attr "conds" "set")]) + +(define_insn "decscc" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (minus:SI (match_operand:SI 1 "s_register_operand" "0,?r") + (match_operator:SI 2 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)])))] + "" + "@ + sub%d2\\t%0, %1, #1 + mov%D2\\t%0, %1\;sub%d2\\t%0, %1, #1" +[(set_attr "conds" "use") + (set_attr "length" "*,8")]) + +(define_insn "subsf3" + [(set (match_operand:SF 0 "s_register_operand" "=f,f") + (minus:SF (match_operand:SF 1 "fpu_rhs_operand" "f,G") + (match_operand:SF 2 "fpu_rhs_operand" "fG,f")))] + "TARGET_HARD_FLOAT" + "@ + suf%?s\\t%0, %1, %2 + rsf%?s\\t%0, %2, %1" +[(set_attr "type" "farith")]) + +(define_insn "subdf3" + [(set (match_operand:DF 0 "s_register_operand" "=f,f") + (minus:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G") + (match_operand:DF 2 "fpu_rhs_operand" "fG,f")))] + "TARGET_HARD_FLOAT" + "@ + suf%?d\\t%0, %1, %2 + rsf%?d\\t%0, %2, %1" +[(set_attr "type" "farith")]) + +(define_insn "*subdf_esfdf_df" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (minus:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (match_operand:DF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "suf%?d\\t%0, %1, %2" +[(set_attr "type" "farith")]) + +(define_insn "*subdf_df_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f,f") + (minus:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G") + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f,f"))))] + "TARGET_HARD_FLOAT" + "@ + suf%?d\\t%0, %1, %2 + rsf%?d\\t%0, %2, %1" +[(set_attr "type" "farith")]) + +(define_insn "*subdf_esfdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (minus:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "suf%?d\\t%0, %1, %2" +[(set_attr "type" "farith")]) + +(define_insn "subxf3" + [(set (match_operand:XF 0 "s_register_operand" "=f,f") + (minus:XF (match_operand:XF 1 "fpu_rhs_operand" "f,G") + (match_operand:XF 2 "fpu_rhs_operand" "fG,f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "@ + suf%?e\\t%0, %1, %2 + rsf%?e\\t%0, %2, %1" +[(set_attr "type" "farith")]) + +;; Multiplication insns + +;; Use `&' and then `0' to prevent the operands 0 and 1 being the same +(define_insn "mulsi3" + [(set (match_operand:SI 0 "s_register_operand" "=&r,&r") + (mult:SI (match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 1 "s_register_operand" "%?r,0")))] + "" + "mul%?\\t%0, %2, %1" +[(set_attr "type" "mult")]) + +(define_insn "*mulsi3_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (mult:SI + (match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 1 "s_register_operand" "%?r,0")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=&r,&r") + (mult:SI (match_dup 2) (match_dup 1)))] + "" + "mul%?s\\t%0, %2, %1" +[(set_attr "conds" "set") + (set_attr "type" "mult")]) + +(define_insn "*mulsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (mult:SI + (match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 1 "s_register_operand" "%?r,0")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=&r,&r"))] + "" + "mul%?s\\t%0, %2, %1" +[(set_attr "conds" "set") + (set_attr "type" "mult")]) + +;; Unnamed templates to match MLA instruction. + +(define_insn "*mulsi3addsi" + [(set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r,&r") + (plus:SI + (mult:SI (match_operand:SI 2 "s_register_operand" "r,r,r,r") + (match_operand:SI 1 "s_register_operand" "%r,0,r,0")) + (match_operand:SI 3 "s_register_operand" "?r,r,0,0")))] + "" + "mla%?\\t%0, %2, %1, %3" +[(set_attr "type" "mult")]) + +(define_insn "*mulsi3addsi_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (plus:SI + (mult:SI + (match_operand:SI 2 "s_register_operand" "r,r,r,r") + (match_operand:SI 1 "s_register_operand" "%r,0,r,0")) + (match_operand:SI 3 "s_register_operand" "?r,r,0,0")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r,&r") + (plus:SI (mult:SI (match_dup 2) (match_dup 1)) + (match_dup 3)))] + "" + "mla%?s\\t%0, %2, %1, %3" +[(set_attr "conds" "set") + (set_attr "type" "mult")]) + +(define_insn "*mulsi3addsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (plus:SI + (mult:SI + (match_operand:SI 2 "s_register_operand" "r,r,r,r") + (match_operand:SI 1 "s_register_operand" "%r,0,r,0")) + (match_operand:SI 3 "s_register_operand" "?r,r,0,0")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=&r,&r,&r,&r"))] + "" + "mla%?s\\t%0, %2, %1, %3" +[(set_attr "conds" "set") + (set_attr "type" "mult")]) + +(define_insn "mulsidi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r") + (mult:DI (sign_extend:DI + (match_operand:SI 1 "s_register_operand" "%r")) + (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r"))))] + "arm_fast_multiply" + "smull%?\\t%Q0, %R0, %1, %2" +[(set_attr "type" "mult")]) + +(define_insn "umulsidi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r") + (mult:DI (zero_extend:DI + (match_operand:SI 1 "s_register_operand" "%r")) + (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r"))))] + "arm_fast_multiply" + "umull%?\\t%Q0, %R0, %1, %2" +[(set_attr "type" "mult")]) + +(define_insn "smulsi3_highpart" + [(set (match_operand:SI 0 "s_register_operand" "=&r,&r") + (truncate:SI + (lshiftrt:DI + (mult:DI (sign_extend:DI + (match_operand:SI 1 "s_register_operand" "%r,0")) + (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r"))) + (const_int 32)))) + (clobber (match_scratch:SI 3 "=&r,&r"))] + "arm_fast_multiply" + "smull%?\\t%3, %0, %2, %1" +[(set_attr "type" "mult")]) + +(define_insn "umulsi3_highpart" + [(set (match_operand:SI 0 "s_register_operand" "=&r,&r") + (truncate:SI + (lshiftrt:DI + (mult:DI (zero_extend:DI + (match_operand:SI 1 "s_register_operand" "%r,0")) + (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r"))) + (const_int 32)))) + (clobber (match_scratch:SI 3 "=&r,&r"))] + "arm_fast_multiply" + "umull%?\\t%3, %0, %2, %1" +[(set_attr "type" "mult")]) + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (mult:SF (match_operand:SF 1 "s_register_operand" "f") + (match_operand:SF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "fml%?s\\t%0, %1, %2" +[(set_attr "type" "ffmul")]) + +(define_insn "muldf3" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mult:DF (match_operand:DF 1 "s_register_operand" "f") + (match_operand:DF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "muf%?d\\t%0, %1, %2" +[(set_attr "type" "fmul")]) + +(define_insn "*muldf_esfdf_df" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mult:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (match_operand:DF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "muf%?d\\t%0, %1, %2" +[(set_attr "type" "fmul")]) + +(define_insn "*muldf_df_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mult:DF (match_operand:DF 1 "s_register_operand" "f") + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "muf%?d\\t%0, %1, %2" +[(set_attr "type" "fmul")]) + +(define_insn "*muldf_esfdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mult:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "muf%?d\\t%0, %1, %2" +[(set_attr "type" "fmul")]) + +(define_insn "mulxf3" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (mult:XF (match_operand:XF 1 "s_register_operand" "f") + (match_operand:XF 2 "fpu_rhs_operand" "fG")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "muf%?e\\t%0, %1, %2" +[(set_attr "type" "fmul")]) + +;; Division insns + +(define_insn "divsf3" + [(set (match_operand:SF 0 "s_register_operand" "=f,f") + (div:SF (match_operand:SF 1 "fpu_rhs_operand" "f,G") + (match_operand:SF 2 "fpu_rhs_operand" "fG,f")))] + "TARGET_HARD_FLOAT" + "@ + fdv%?s\\t%0, %1, %2 + frd%?s\\t%0, %2, %1" +[(set_attr "type" "fdivs")]) + +(define_insn "divdf3" + [(set (match_operand:DF 0 "s_register_operand" "=f,f") + (div:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G") + (match_operand:DF 2 "fpu_rhs_operand" "fG,f")))] + "TARGET_HARD_FLOAT" + "@ + dvf%?d\\t%0, %1, %2 + rdf%?d\\t%0, %2, %1" +[(set_attr "type" "fdivd")]) + +(define_insn "*divdf_esfdf_df" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (div:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (match_operand:DF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "dvf%?d\\t%0, %1, %2" +[(set_attr "type" "fdivd")]) + +(define_insn "*divdf_df_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (div:DF (match_operand:DF 1 "fpu_rhs_operand" "fG") + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "rdf%?d\\t%0, %2, %1" +[(set_attr "type" "fdivd")]) + +(define_insn "*divdf_esfdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (div:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "dvf%?d\\t%0, %1, %2" +[(set_attr "type" "fdivd")]) + +(define_insn "divxf3" + [(set (match_operand:XF 0 "s_register_operand" "=f,f") + (div:XF (match_operand:XF 1 "fpu_rhs_operand" "f,G") + (match_operand:XF 2 "fpu_rhs_operand" "fG,f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "@ + dvf%?e\\t%0, %1, %2 + rdf%?e\\t%0, %2, %1" +[(set_attr "type" "fdivx")]) + +;; Modulo insns + +(define_insn "modsf3" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (mod:SF (match_operand:SF 1 "s_register_operand" "f") + (match_operand:SF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "rmf%?s\\t%0, %1, %2" +[(set_attr "type" "fdivs")]) + +(define_insn "moddf3" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mod:DF (match_operand:DF 1 "s_register_operand" "f") + (match_operand:DF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "rmf%?d\\t%0, %1, %2" +[(set_attr "type" "fdivd")]) + +(define_insn "*moddf_esfdf_df" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mod:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (match_operand:DF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "rmf%?d\\t%0, %1, %2" +[(set_attr "type" "fdivd")]) + +(define_insn "*moddf_df_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mod:DF (match_operand:DF 1 "s_register_operand" "f") + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "rmf%?d\\t%0, %1, %2" +[(set_attr "type" "fdivd")]) + +(define_insn "*moddf_esfdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mod:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "rmf%?d\\t%0, %1, %2" +[(set_attr "type" "fdivd")]) + +(define_insn "modxf3" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (mod:XF (match_operand:XF 1 "s_register_operand" "f") + (match_operand:XF 2 "fpu_rhs_operand" "fG")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "rmf%?e\\t%0, %1, %2" +[(set_attr "type" "fdivx")]) + +;; Boolean and,ior,xor insns + +(define_insn "anddi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (and:DI (match_operand:DI 1 "s_register_operand" "%0,0") + (match_operand:DI 2 "s_register_operand" "r,0")))] + "" + "and%?\\t%Q0, %Q1, %Q2\;and%?\\t%R0, %R1, %R2" +[(set_attr "length" "8")]) + +(define_insn "*anddi_zesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (and:DI (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "?r,0")))] + "" + "and%?\\t%Q0, %Q1, %2\;mov%?\\t%R0, #0" +[(set_attr "length" "8")]) + +(define_insn "*anddi_sesdi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (and:DI (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "?r,0")))] + "" + "and%?\\t%Q0, %Q1, %2\;and%?\\t%R0, %R1, %2, asr #31" +[(set_attr "length" "8")]) + +(define_expand "andsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (and:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "reg_or_int_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT) + { + arm_split_constant (AND, SImode, INTVAL (operands[2]), operands[0], + operands[1], + (reload_in_progress || reload_completed + ? 0 : preserve_subexpressions_p ())); + DONE; + } +") + +(define_insn "*andsi3_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (and:SI (match_operand:SI 1 "s_register_operand" "r,r,r") + (match_operand:SI 2 "reg_or_int_operand" "rI,K,?n")))] + "" + "@ + and%?\\t%0, %1, %2 + bic%?\\t%0, %1, #%B2 + #" +[(set_attr "length" "4,4,16")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (and:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "const_int_operand" "")))] + "! (const_ok_for_arm (INTVAL (operands[2])) + || const_ok_for_arm (~ INTVAL (operands[2])))" + [(clobber (const_int 0))] + " + arm_split_constant (AND, SImode, INTVAL (operands[2]), operands[0], + operands[1], 0); + DONE; +") + +(define_insn "*andsi3_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (and:SI (match_operand:SI 1 "s_register_operand" "r,r") + (match_operand:SI 2 "arm_not_operand" "rI,K")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") + (and:SI (match_dup 1) (match_dup 2)))] + "" + "@ + and%?s\\t%0, %1, %2 + bic%?s\\t%0, %1, #%B2" +[(set_attr "conds" "set")]) + +(define_insn "*andsi3_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (and:SI (match_operand:SI 0 "s_register_operand" "r,r") + (match_operand:SI 1 "arm_not_operand" "rI,K")) + (const_int 0))) + (clobber (match_scratch:SI 3 "=X,r"))] + "" + "@ + tst%?\\t%0, %1 + bic%?s\\t%3, %0, #%B1" +[(set_attr "conds" "set")]) + +(define_insn "*zeroextractsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (zero_extract:SI + (match_operand:SI 0 "s_register_operand" "r") + (match_operand 1 "const_int_operand" "n") + (match_operand 2 "const_int_operand" "n")) + (const_int 0)))] + "INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) < 32 + && INTVAL (operands[1]) > 0 + && INTVAL (operands[1]) + (INTVAL (operands[2]) & 1) <= 8 + && INTVAL (operands[1]) + INTVAL (operands[2]) <= 32" + "* +{ + unsigned int mask = 0; + int cnt = INTVAL (operands[1]); + + while (cnt--) + mask = (mask << 1) | 1; + operands[1] = GEN_INT (mask << INTVAL (operands[2])); + output_asm_insn (\"tst%?\\t%0, %1\", operands); + return \"\"; +} +" +[(set_attr "conds" "set")]) + +;; ??? This pattern does not work because it does not check for start+length +;; less than or equal to 8. This is necessary for the bitfield to fit within +;; a single byte. This pattern was deleted Feb 25, 1999 in egcs, so we can +;; just disabled it for 99r1. + +(define_insn "*zeroextractqi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (zero_extract:SI + (match_operand:QI 0 "memory_operand" "m") + (match_operand 1 "const_int_operand" "n") + (match_operand 2 "const_int_operand" "n")) + (const_int 0))) + (clobber (match_scratch:QI 3 "=r"))] + "0 && INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) < 8 + && INTVAL (operands[1]) > 0 && INTVAL (operands[1]) <= 8" + "* +{ + unsigned int mask = 0; + int cnt = INTVAL (operands[1]); + + while (cnt--) + mask = (mask << 1) | 1; + operands[1] = GEN_INT (mask << INTVAL (operands[2])); + output_asm_insn (\"ldr%?b\\t%3, %0\", operands); + output_asm_insn (\"tst%?\\t%3, %1\", operands); + return \"\"; +} +" +[(set_attr "conds" "set") + (set_attr "length" "8")]) + +;;; ??? This pattern is bogus. If operand3 has bits outside the range +;;; represented by the bitfield, then this will produce incorrect results. +;;; Somewhere, the value needs to be truncated. On targets like the m68k, +;;; which have a real bitfield insert instruction, the truncation happens +;;; in the bitfield insert instruction itself. Since arm does not have a +;;; bitfield insert instruction, we would have to emit code here to truncate +;;; the value before we insert. This loses some of the advantage of having +;;; this insv pattern, so this pattern needs to be reevalutated. + +(define_expand "insv" + [(set (zero_extract:SI (match_operand:SI 0 "s_register_operand" "") + (match_operand:SI 1 "general_operand" "") + (match_operand:SI 2 "general_operand" "")) + (match_operand:SI 3 "nonmemory_operand" ""))] + "" + " +{ + int start_bit = INTVAL (operands[2]); + int width = INTVAL (operands[1]); + HOST_WIDE_INT mask = (((HOST_WIDE_INT)1) << width) - 1; + rtx target, subtarget; + + target = operands[0]; + /* Avoid using a subreg as a subtarget, and avoid writing a paradoxical + subreg as the final target. */ + if (GET_CODE (target) == SUBREG) + { + subtarget = gen_reg_rtx (SImode); + if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (target))) + < GET_MODE_SIZE (SImode)) + target = SUBREG_REG (target); + } + else + subtarget = target; + + if (GET_CODE (operands[3]) == CONST_INT) + { + /* Since we are inserting a known constant, we may be able to + reduce the number of bits that we have to clear so that + the mask becomes simple. */ + /* ??? This code does not check to see if the new mask is actually + simpler. It may not be. */ + rtx op1 = gen_reg_rtx (SImode); + /* ??? Truncate operand3 to fit in the bitfield. See comment before + start of this pattern. */ + HOST_WIDE_INT op3_value = mask & INTVAL (operands[3]); + HOST_WIDE_INT mask2 = ((mask & ~op3_value) << start_bit); + + emit_insn (gen_andsi3 (op1, operands[0], GEN_INT (~mask2))); + emit_insn (gen_iorsi3 (subtarget, op1, + GEN_INT (op3_value << start_bit))); + } + else if (start_bit == 0 + && ! (const_ok_for_arm (mask) + || const_ok_for_arm (~mask))) + { + /* A Trick, since we are setting the bottom bits in the word, + we can shift operand[3] up, operand[0] down, OR them together + and rotate the result back again. This takes 3 insns, and + the third might be mergable into another op. */ + /* The shift up copes with the possibility that operand[3] is + wider than the bitfield. */ + rtx op0 = gen_reg_rtx (SImode); + rtx op1 = gen_reg_rtx (SImode); + + emit_insn (gen_ashlsi3 (op0, operands[3], GEN_INT (32 - width))); + emit_insn (gen_iorsi3 (op1, gen_rtx (LSHIFTRT, SImode, operands[0], + operands[1]), + op0)); + emit_insn (gen_rotlsi3 (subtarget, op1, operands[1])); + } + else if ((width + start_bit == 32) + && ! (const_ok_for_arm (mask) + || const_ok_for_arm (~mask))) + { + /* Similar trick, but slightly less efficient. */ + + rtx op0 = gen_reg_rtx (SImode); + rtx op1 = gen_reg_rtx (SImode); + + emit_insn (gen_ashlsi3 (op0, operands[3], GEN_INT (32 - width))); + emit_insn (gen_ashlsi3 (op1, operands[0], operands[1])); + emit_insn (gen_iorsi3 (subtarget, + gen_rtx (LSHIFTRT, SImode, op1, + operands[1]), op0)); + } + else + { + rtx op0 = GEN_INT (mask); + rtx op1 = gen_reg_rtx (SImode); + rtx op2 = gen_reg_rtx (SImode); + + if (! (const_ok_for_arm (mask) || const_ok_for_arm (~mask))) + { + rtx tmp = gen_reg_rtx (SImode); + + emit_insn (gen_movsi (tmp, op0)); + op0 = tmp; + } + + /* Mask out any bits in operand[3] that are not needed. */ + emit_insn (gen_andsi3 (op1, operands[3], op0)); + + if (GET_CODE (op0) == CONST_INT + && (const_ok_for_arm (mask << start_bit) + || const_ok_for_arm (~ (mask << start_bit)))) + { + op0 = GEN_INT (~(mask << start_bit)); + emit_insn (gen_andsi3 (op2, operands[0], op0)); + } + else + { + if (GET_CODE (op0) == CONST_INT) + { + rtx tmp = gen_reg_rtx (SImode); + + emit_insn (gen_movsi (tmp, op0)); + op0 = tmp; + } + + if (start_bit != 0) + op0 = gen_rtx (ASHIFT, SImode, op0, operands[2]); + + emit_insn (gen_andsi_notsi_si (op2, operands[0], op0)); + } + + if (start_bit != 0) + op1 = gen_rtx (ASHIFT, SImode, op1, operands[2]); + + emit_insn (gen_iorsi3 (subtarget, op1, op2)); + } + + if (subtarget != target) + { + /* If TARGET is still a SUBREG, then it must be wider than a word, + so we must be careful only to set the subword we were asked to. */ + if (GET_CODE (target) == SUBREG) + emit_move_insn (target, subtarget); + else + emit_move_insn (target, gen_lowpart (GET_MODE (target), subtarget)); + } + + DONE; +} +") + +;; constants for op 2 will never be given to these patterns. +(define_insn "*anddi_notdi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (and:DI (not:DI (match_operand:DI 2 "s_register_operand" "r,0")) + (match_operand:DI 1 "s_register_operand" "0,r")))] + "" + "bic%?\\t%Q0, %Q1, %Q2\;bic%?\\t%R0, %R1, %R2" +[(set_attr "length" "8")]) + +(define_insn "*anddi_notzesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (and:DI (not:DI (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r"))) + (match_operand:DI 1 "s_register_operand" "0,?r")))] + "" + "@ + bic%?\\t%Q0, %Q1, %2 + bic%?\\t%Q0, %Q1, %2\;mov%?\\t%R0, %R1" +[(set_attr "length" "4,8")]) + +(define_insn "*anddi_notsesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (and:DI (not:DI (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r"))) + (match_operand:DI 1 "s_register_operand" "?r,0")))] + "" + "bic%?\\t%Q0, %Q1, %2\;bic%?\\t%R0, %R1, %2, asr #31" +[(set_attr "length" "8")]) + +(define_insn "andsi_notsi_si" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (and:SI (not:SI (match_operand:SI 2 "s_register_operand" "r")) + (match_operand:SI 1 "s_register_operand" "r")))] + "" + "bic%?\\t%0, %1, %2") + +(define_insn "andsi_not_shiftsi_si" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (and:SI (not:SI (match_operator:SI 4 "shift_operator" + [(match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 3 "arm_rhs_operand" "rM")])) + (match_operand:SI 1 "s_register_operand" "r")))] + "" + "bic%?\\t%0, %1, %2%S4") + +(define_insn "*andsi_notsi_si_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (and:SI (not:SI (match_operand:SI 2 "s_register_operand" "r")) + (match_operand:SI 1 "s_register_operand" "r")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (and:SI (not:SI (match_dup 2)) (match_dup 1)))] + "" + "bic%?s\\t%0, %1, %2" +[(set_attr "conds" "set")]) + +(define_insn "*andsi_notsi_si_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (and:SI (not:SI (match_operand:SI 2 "s_register_operand" "r")) + (match_operand:SI 1 "s_register_operand" "r")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "" + "bic%?s\\t%0, %1, %2" +[(set_attr "conds" "set")]) + +(define_insn "iordi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r") + (ior:DI (match_operand:DI 1 "s_register_operand" "%0") + (match_operand:DI 2 "s_register_operand" "r")))] + "" + "orr%?\\t%Q0, %Q1, %Q2\;orr%?\\t%R0, %R1, %R2" +[(set_attr "length" "8")]) + +(define_insn "*iordi_zesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (ior:DI (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "0,?r")))] + "" + "@ + orr%?\\t%Q0, %Q1, %2 + orr%?\\t%Q0, %Q1, %2\;mov%?\\t%R0, %R1" +[(set_attr "length" "4,8")]) + +(define_insn "*iordi_sesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (ior:DI (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "?r,0")))] + "" + "orr%?\\t%Q0, %Q1, %2\;orr%?\\t%R0, %R1, %2, asr #31" +[(set_attr "length" "8")]) + +(define_expand "iorsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (ior:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "reg_or_int_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT) + { + arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0], + operands[1], + (reload_in_progress || reload_completed + ? 0 : preserve_subexpressions_p ())); + DONE; + } +") + +(define_insn "*iorsi3_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (ior:SI (match_operand:SI 1 "s_register_operand" "r,r") + (match_operand:SI 2 "reg_or_int_operand" "rI,?n")))] + "" + "@ + orr%?\\t%0, %1, %2 + #" +[(set_attr "length" "4,16")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (ior:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "const_int_operand" "")))] + "! const_ok_for_arm (INTVAL (operands[2]))" + [(clobber (const_int 0))] + " + arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0], + operands[1], 0); + DONE; +") + +(define_insn "*iorsi3_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (ior:SI (match_operand:SI 1 "s_register_operand" "%r") + (match_operand:SI 2 "arm_rhs_operand" "rI")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (ior:SI (match_dup 1) (match_dup 2)))] + "" + "orr%?s\\t%0, %1, %2" +[(set_attr "conds" "set")]) + +(define_insn "*iorsi3_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (ior:SI (match_operand:SI 1 "s_register_operand" "%r") + (match_operand:SI 2 "arm_rhs_operand" "rI")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "" + "orr%?s\\t%0, %1, %2" +[(set_attr "conds" "set")]) + +(define_insn "xordi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (xor:DI (match_operand:DI 1 "s_register_operand" "%0,0") + (match_operand:DI 2 "s_register_operand" "r,0")))] + "" + "eor%?\\t%Q0, %Q1, %Q2\;eor%?\\t%R0, %R1, %R2" +[(set_attr "length" "8")]) + +(define_insn "*xordi_zesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (xor:DI (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "0,?r")))] + "" + "@ + eor%?\\t%Q0, %Q1, %2 + eor%?\\t%Q0, %Q1, %2\;mov%?\\t%R0, %R1" +[(set_attr "length" "4,8")]) + +(define_insn "*xordi_sesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (xor:DI (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "?r,0")))] + "" + "eor%?\\t%Q0, %Q1, %2\;eor%?\\t%R0, %R1, %2, asr #31" +[(set_attr "length" "8")]) + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (xor:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rI")))] + "" + "eor%?\\t%0, %1, %2") + +(define_insn "*xorsi3_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (xor:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rI")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (xor:SI (match_dup 1) (match_dup 2)))] + "" + "eor%?s\\t%0, %1, %2" +[(set_attr "conds" "set")]) + +(define_insn "*xorsi3_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (xor:SI (match_operand:SI 0 "s_register_operand" "r") + (match_operand:SI 1 "arm_rhs_operand" "rI")) + (const_int 0)))] + "" + "teq%?\\t%0, %1" +[(set_attr "conds" "set")]) + +;; by splitting (IOR (AND (NOT A) (NOT B)) C) as D = AND (IOR A B) (NOT C), +;; (NOT D) we can sometimes merge the final NOT into one of the following +;; insns + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "=r") + (ior:SI (and:SI (not:SI (match_operand:SI 1 "s_register_operand" "r")) + (not:SI (match_operand:SI 2 "arm_rhs_operand" "rI"))) + (match_operand:SI 3 "arm_rhs_operand" "rI"))) + (clobber (match_operand:SI 4 "s_register_operand" "=r"))] + "" + [(set (match_dup 4) (and:SI (ior:SI (match_dup 1) (match_dup 2)) + (not:SI (match_dup 3)))) + (set (match_dup 0) (not:SI (match_dup 4)))] + "" +) + +(define_insn "*andsi_iorsi3_notsi" + [(set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r") + (and:SI (ior:SI (match_operand:SI 1 "s_register_operand" "r,r,0") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")) + (not:SI (match_operand:SI 3 "arm_rhs_operand" "rI,rI,rI"))))] + "" + "orr%?\\t%0, %1, %2\;bic%?\\t%0, %0, %3" +[(set_attr "length" "8")]) + + + +;; Minimum and maximum insns + +(define_insn "smaxsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (smax:SI (match_operand:SI 1 "s_register_operand" "0,r,?r") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) + (clobber (reg:CC 24))] + "" + "@ + cmp\\t%1, %2\;movlt\\t%0, %2 + cmp\\t%1, %2\;movge\\t%0, %1 + cmp\\t%1, %2\;movge\\t%0, %1\;movlt\\t%0, %2" +[(set_attr "conds" "clob") + (set_attr "length" "8,8,12")]) + +(define_insn "sminsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (smin:SI (match_operand:SI 1 "s_register_operand" "0,r,?r") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) + (clobber (reg:CC 24))] + "" + "@ + cmp\\t%1, %2\;movge\\t%0, %2 + cmp\\t%1, %2\;movlt\\t%0, %1 + cmp\\t%1, %2\;movlt\\t%0, %1\;movge\\t%0, %2" +[(set_attr "conds" "clob") + (set_attr "length" "8,8,12")]) + +(define_insn "umaxsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (umax:SI (match_operand:SI 1 "s_register_operand" "0,r,?r") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) + (clobber (reg:CC 24))] + "" + "@ + cmp\\t%1, %2\;movcc\\t%0, %2 + cmp\\t%1, %2\;movcs\\t%0, %1 + cmp\\t%1, %2\;movcs\\t%0, %1\;movcc\\t%0, %2" +[(set_attr "conds" "clob") + (set_attr "length" "8,8,12")]) + +(define_insn "uminsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (umin:SI (match_operand:SI 1 "s_register_operand" "0,r,?r") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) + (clobber (reg:CC 24))] + "" + "@ + cmp\\t%1, %2\;movcs\\t%0, %2 + cmp\\t%1, %2\;movcc\\t%0, %1 + cmp\\t%1, %2\;movcc\\t%0, %1\;movcs\\t%0, %2" +[(set_attr "conds" "clob") + (set_attr "length" "8,8,12")]) + +(define_insn "*store_minmaxsi" + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operator:SI 3 "minmax_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "s_register_operand" "r")])) + (clobber (reg:CC 24))] + "" + "* + operands[3] = gen_rtx (minmax_code (operands[3]), SImode, operands[1], + operands[2]); + output_asm_insn (\"cmp\\t%1, %2\", operands); + output_asm_insn (\"str%d3\\t%1, %0\", operands); + output_asm_insn (\"str%D3\\t%2, %0\", operands); + return \"\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "12") + (set_attr "type" "store1")]) + +; Reject the frame pointer in operand[1], since reloading this after +; it has been eliminated can cause carnage. +(define_insn "*minmax_arithsi" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (match_operator:SI 4 "shiftable_operator" + [(match_operator:SI 5 "minmax_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_rhs_operand" "rI,rI")]) + (match_operand:SI 1 "s_register_operand" "0,?r")])) + (clobber (reg:CC 24))] + "GET_CODE (operands[1]) != REG + || (REGNO(operands[1]) != FRAME_POINTER_REGNUM + && REGNO(operands[1]) != ARG_POINTER_REGNUM)" + "* +{ + enum rtx_code code = GET_CODE (operands[4]); + + operands[5] = gen_rtx (minmax_code (operands[5]), SImode, operands[2], + operands[3]); + output_asm_insn (\"cmp\\t%2, %3\", operands); + output_asm_insn (\"%i4%d5\\t%0, %1, %2\", operands); + if (which_alternative != 0 || operands[3] != const0_rtx + || (code != PLUS && code != MINUS && code != IOR && code != XOR)) + output_asm_insn (\"%i4%D5\\t%0, %1, %3\", operands); + return \"\"; +} +" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + + +;; Shift and rotation insns + +(define_expand "ashlsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (ashift:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "arm_rhs_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT + && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31) + { + emit_insn (gen_movsi (operands[0], const0_rtx)); + DONE; + } +") + +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (ashiftrt:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "arm_rhs_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT + && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31) + operands[2] = GEN_INT (31); +") + +(define_expand "lshrsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (lshiftrt:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "arm_rhs_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT + && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31) + { + emit_insn (gen_movsi (operands[0], const0_rtx)); + DONE; + } +") + +(define_expand "rotlsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (rotatert:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "reg_or_int_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT) + operands[2] = GEN_INT ((32 - INTVAL (operands[2])) % 32); + else + { + rtx reg = gen_reg_rtx (SImode); + emit_insn (gen_subsi3 (reg, GEN_INT (32), operands[2])); + operands[2] = reg; + } +") + +(define_expand "rotrsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (rotatert:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "arm_rhs_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT + && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31) + operands[2] = GEN_INT (INTVAL (operands[2]) % 32); +") + +(define_insn "*shiftsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "reg_or_int_operand" "rM")]))] + "" + "mov%?\\t%0, %1%S3") + +(define_insn "*shiftsi3_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")]) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (match_op_dup 3 [(match_dup 1) (match_dup 2)]))] + "" + "mov%?s\\t%0, %1%S3" +[(set_attr "conds" "set")]) + +(define_insn "*shiftsi3_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")]) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "" + "mov%?s\\t%0, %1%S3" +[(set_attr "conds" "set")]) + +(define_insn "*notsi_shiftsi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (not:SI (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")])))] + "" + "mvn%?\\t%0, %1%S3") + +(define_insn "*notsi_shiftsi_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (not:SI (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")])) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (not:SI (match_op_dup 3 [(match_dup 1) (match_dup 2)])))] + "" + "mvn%?s\\t%0, %1%S3" +[(set_attr "conds" "set")]) + +(define_insn "*not_shiftsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (not:SI (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")])) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "" + "mvn%?s\\t%0, %1%S3" +[(set_attr "conds" "set")]) + + +;; Unary arithmetic insns + +(define_insn "negdi2" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (neg:DI (match_operand:DI 1 "s_register_operand" "?r,0")))] + "" + "rsbs\\t%Q0, %Q1, #0\;rsc\\t%R0, %R1, #0" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "negsi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (neg:SI (match_operand:SI 1 "s_register_operand" "r")))] + "" + "rsb%?\\t%0, %1, #0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (neg:SF (match_operand:SF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "mnf%?s\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "negdf2" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (neg:DF (match_operand:DF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "mnf%?d\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "*negdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (neg:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "mnf%?d\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "negxf2" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (neg:XF (match_operand:XF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "mnf%?e\\t%0, %1" +[(set_attr "type" "ffarith")]) + +;; abssi2 doesn't really clobber the condition codes if a different register +;; is being set. To keep things simple, assume during rtl manipulations that +;; it does, but tell the final scan operator the truth. Similarly for +;; (neg (abs...)) + +(define_insn "abssi2" + [(set (match_operand:SI 0 "s_register_operand" "=r,&r") + (abs:SI (match_operand:SI 1 "s_register_operand" "0,r"))) + (clobber (reg:CC 24))] + "" + "@ + cmp\\t%0, #0\;rsblt\\t%0, %0, #0 + eor%?\\t%0, %1, %1, asr #31\;sub%?\\t%0, %0, %1, asr #31" +[(set_attr "conds" "clob,*") + (set_attr "length" "8")]) + +(define_insn "*neg_abssi2" + [(set (match_operand:SI 0 "s_register_operand" "=r,&r") + (neg:SI (abs:SI (match_operand:SI 1 "s_register_operand" "0,r")))) + (clobber (reg:CC 24))] + "" + "@ + cmp\\t%0, #0\;rsbgt\\t%0, %0, #0 + eor%?\\t%0, %1, %1, asr #31\;rsb%?\\t%0, %0, %1, asr #31" +[(set_attr "conds" "clob,*") + (set_attr "length" "8")]) + +(define_insn "abssf2" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (abs:SF (match_operand:SF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "abs%?s\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "absdf2" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (abs:DF (match_operand:DF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "abs%?d\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "*absdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (abs:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "abs%?d\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "absxf2" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (abs:XF (match_operand:XF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "abs%?e\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "sqrtsf2" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (sqrt:SF (match_operand:SF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "sqt%?s\\t%0, %1" +[(set_attr "type" "float_em")]) + +(define_insn "sqrtdf2" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (sqrt:DF (match_operand:DF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "sqt%?d\\t%0, %1" +[(set_attr "type" "float_em")]) + +(define_insn "*sqrtdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (sqrt:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "sqt%?d\\t%0, %1" +[(set_attr "type" "float_em")]) + +(define_insn "sqrtxf2" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (sqrt:XF (match_operand:XF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "sqt%?e\\t%0, %1" +[(set_attr "type" "float_em")]) + +;; SIN COS TAN and family are always emulated, so it's probably better +;; to always call a library function. +;(define_insn "sinsf2" +; [(set (match_operand:SF 0 "s_register_operand" "=f") +; (unspec:SF [(match_operand:SF 1 "s_register_operand" "f")] 0))] +; "TARGET_HARD_FLOAT" +; "sin%?s\\t%0, %1" +;[(set_attr "type" "float_em")]) +; +;(define_insn "sindf2" +; [(set (match_operand:DF 0 "s_register_operand" "=f") +; (unspec:DF [(match_operand:DF 1 "s_register_operand" "f")] 0))] +; "TARGET_HARD_FLOAT" +; "sin%?d\\t%0, %1" +;[(set_attr "type" "float_em")]) +; +;(define_insn "*sindf_esfdf" +; [(set (match_operand:DF 0 "s_register_operand" "=f") +; (unspec:DF [(float_extend:DF +; (match_operand:SF 1 "s_register_operand" "f"))] 0))] +; "TARGET_HARD_FLOAT" +; "sin%?d\\t%0, %1" +;[(set_attr "type" "float_em")]) +; +;(define_insn "sinxf2" +; [(set (match_operand:XF 0 "s_register_operand" "=f") +; (unspec:XF [(match_operand:XF 1 "s_register_operand" "f")] 0))] +; "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" +; "sin%?e\\t%0, %1" +;[(set_attr "type" "float_em")]) +; +;(define_insn "cossf2" +; [(set (match_operand:SF 0 "s_register_operand" "=f") +; (unspec:SF [(match_operand:SF 1 "s_register_operand" "f")] 1))] +; "TARGET_HARD_FLOAT" +; "cos%?s\\t%0, %1" +;[(set_attr "type" "float_em")]) +; +;(define_insn "cosdf2" +; [(set (match_operand:DF 0 "s_register_operand" "=f") +; (unspec:DF [(match_operand:DF 1 "s_register_operand" "f")] 1))] +; "TARGET_HARD_FLOAT" +; "cos%?d\\t%0, %1" +;[(set_attr "type" "float_em")]) +; +;(define_insn "*cosdf_esfdf" +; [(set (match_operand:DF 0 "s_register_operand" "=f") +; (unspec:DF [(float_extend:DF +; (match_operand:SF 1 "s_register_operand" "f"))] 1))] +; "TARGET_HARD_FLOAT" +; "cos%?d\\t%0, %1" +;[(set_attr "type" "float_em")]) +; +;(define_insn "cosxf2" +; [(set (match_operand:XF 0 "s_register_operand" "=f") +; (unspec:XF [(match_operand:XF 1 "s_register_operand" "f")] 1))] +; "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" +; "cos%?e\\t%0, %1" +;[(set_attr "type" "float_em")]) + +(define_insn "one_cmpldi2" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (not:DI (match_operand:DI 1 "s_register_operand" "?r,0")))] + "" + "mvn%?\\t%Q0, %Q1\;mvn%?\\t%R0, %R1" +[(set_attr "length" "8")]) + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (not:SI (match_operand:SI 1 "s_register_operand" "r")))] + "" + "mvn%?\\t%0, %1") + +(define_insn "*notsi_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (not:SI (match_operand:SI 1 "s_register_operand" "r")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (not:SI (match_dup 1)))] + "" + "mvn%?s\\t%0, %1" +[(set_attr "conds" "set")]) + +(define_insn "*notsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (not:SI (match_operand:SI 1 "s_register_operand" "r")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "" + "mvn%?s\\t%0, %1" +[(set_attr "conds" "set")]) + +;; Fixed <--> Floating conversion insns + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (float:SF (match_operand:SI 1 "s_register_operand" "r")))] + "TARGET_HARD_FLOAT" + "flt%?s\\t%0, %1" +[(set_attr "type" "r_2_f")]) + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (float:DF (match_operand:SI 1 "s_register_operand" "r")))] + "TARGET_HARD_FLOAT" + "flt%?d\\t%0, %1" +[(set_attr "type" "r_2_f")]) + +(define_insn "floatsixf2" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (float:XF (match_operand:SI 1 "s_register_operand" "r")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "flt%?e\\t%0, %1" +[(set_attr "type" "r_2_f")]) + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (fix:SI (match_operand:SF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "fix%?z\\t%0, %1" +[(set_attr "type" "f_2_r")]) + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (fix:SI (match_operand:DF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "fix%?z\\t%0, %1" +[(set_attr "type" "f_2_r")]) + +(define_insn "fix_truncxfsi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (fix:SI (match_operand:XF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "fix%?z\\t%0, %1" +[(set_attr "type" "f_2_r")]) + +;; Truncation insns + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (float_truncate:SF + (match_operand:DF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "mvf%?s\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "truncxfsf2" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (float_truncate:SF + (match_operand:XF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "mvf%?s\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "truncxfdf2" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (float_truncate:DF + (match_operand:XF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "mvf%?d\\t%0, %1" +[(set_attr "type" "ffarith")]) + +;; Zero and sign extension instructions. + +(define_insn "zero_extendsidi2" + [(set (match_operand:DI 0 "s_register_operand" "=r") + (zero_extend:DI (match_operand:SI 1 "s_register_operand" "r")))] + "" + "* + if (REGNO (operands[1]) != REGNO (operands[0]) + (WORDS_BIG_ENDIAN ? 1 : 0)) + output_asm_insn (\"mov%?\\t%Q0, %1\", operands); + return \"mov%?\\t%R0, #0\"; +" +[(set_attr "length" "8")]) + +(define_insn "zero_extendqidi2" + [(set (match_operand:DI 0 "s_register_operand" "=r,r") + (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] + "" + "@ + and%?\\t%Q0, %1, #255\;mov%?\\t%R0, #0 + ldr%?b\\t%Q0, %1\;mov%?\\t%R0, #0" +[(set_attr "length" "8") + (set_attr "type" "*,load")]) + +(define_insn "extendsidi2" + [(set (match_operand:DI 0 "s_register_operand" "=r") + (sign_extend:DI (match_operand:SI 1 "s_register_operand" "r")))] + "" + "* + if (REGNO (operands[1]) != REGNO (operands[0]) + (WORDS_BIG_ENDIAN ? 1 : 0)) + output_asm_insn (\"mov%?\\t%Q0, %1\", operands); + return \"mov%?\\t%R0, %Q0, asr #31\"; +" +[(set_attr "length" "8")]) + +(define_expand "zero_extendhisi2" + [(set (match_dup 2) (ashift:SI (match_operand:HI 1 "nonimmediate_operand" "") + (const_int 16))) + (set (match_operand:SI 0 "s_register_operand" "") + (lshiftrt:SI (match_dup 2) (const_int 16)))] + "" + " +{ + if (arm_arch4 && GET_CODE (operands[1]) == MEM) + { + /* Note: We do not have to worry about TARGET_SHORT_BY_BYTES + here because the insn below will generate an LDRH instruction + rather than an LDR instruction, so we cannot get an unaligned + word access. */ + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_ZERO_EXTEND (SImode, operands[1]))); + DONE; + } + if (TARGET_SHORT_BY_BYTES && GET_CODE (operands[1]) == MEM) + { + emit_insn (gen_movhi_bytes (operands[0], operands[1])); + DONE; + } + if (! s_register_operand (operands[1], HImode)) + operands[1] = copy_to_mode_reg (HImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); +}") + +(define_insn "*zero_extendhisi_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + "arm_arch4" + "ldr%?h\\t%0, %1" +[(set_attr "type" "load")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (zero_extend:SI (match_operand:HI 1 "alignable_memory_operand" ""))) + (clobber (match_operand:SI 2 "s_register_operand" ""))] + "! arm_arch4" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (lshiftrt:SI (match_dup 2) (const_int 16)))] + " +{ + if ((operands[1] = gen_rotated_half_load (operands[1])) == NULL) + FAIL; +}") + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operator:SI 3 "shiftable_operator" + [(zero_extend:SI (match_operand:HI 1 "alignable_memory_operand" "")) + (match_operand:SI 4 "s_register_operand" "")])) + (clobber (match_operand:SI 2 "s_register_operand" ""))] + "! arm_arch4" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) + (match_op_dup 3 + [(lshiftrt:SI (match_dup 2) (const_int 16)) (match_dup 4)]))] + " +{ + if ((operands[1] = gen_rotated_half_load (operands[1])) == NULL) + FAIL; +}") + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (zero_extend:SI + (match_operand:QI 1 "nonimmediate_operand" "r,m")))] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + emit_insn (gen_andsi3 (operands[0], gen_lowpart (SImode, operands[1]), + GEN_INT (255))); + DONE; + } +") + +(define_insn "*load_extendqisi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + "" + "ldr%?b\\t%0, %1\\t%@ zero_extendqisi2" +[(set_attr "type" "load")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (zero_extend:SI (subreg:QI (match_operand:SI 1 "" "") 0))) + (clobber (match_operand:SI 2 "s_register_operand" ""))] + "GET_CODE (operands[1]) != MEM" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (and:SI (match_dup 2) (const_int 255)))] + "") + +(define_insn "*compareqi_eq0" + [(set (reg:CC_Z 24) + (compare:CC_Z (match_operand:QI 0 "s_register_operand" "r") + (const_int 0)))] + "" + "tst\\t%0, #255" +[(set_attr "conds" "set")]) + +(define_expand "extendhisi2" + [(set (match_dup 2) + (ashift:SI (match_operand:HI 1 "nonimmediate_operand" "") + (const_int 16))) + (set (match_operand:SI 0 "s_register_operand" "") + (ashiftrt:SI (match_dup 2) + (const_int 16)))] + "" + " +{ + if (arm_arch4 && GET_CODE (operands[1]) == MEM) + { + /* Note: We do not have to worry about TARGET_SHORT_BY_BYTES + here because the insn below will generate an LDRH instruction + rather than an LDR instruction, so we cannot get an unaligned + word access. */ + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_SIGN_EXTEND (SImode, operands[1]))); + DONE; + } + + if (TARGET_SHORT_BY_BYTES && GET_CODE (operands[1]) == MEM) + { + emit_insn (gen_extendhisi2_mem (operands[0], operands[1])); + DONE; + } + if (! s_register_operand (operands[1], HImode)) + operands[1] = copy_to_mode_reg (HImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); +}") + +(define_expand "extendhisi2_mem" + [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" ""))) + (set (match_dup 3) + (zero_extend:SI (match_dup 7))) + (set (match_dup 6) (ashift:SI (match_dup 4) (const_int 24))) + (set (match_operand:SI 0 "" "") + (ior:SI (ashiftrt:SI (match_dup 6) (const_int 16)) (match_dup 5)))] + "" + " +{ + rtx mem1, mem2; + rtx addr = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); + + mem1 = gen_rtx (MEM, QImode, addr); + MEM_COPY_ATTRIBUTES (mem1, operands[1]); + RTX_UNCHANGING_P (mem1) = RTX_UNCHANGING_P (operands[1]); + mem2 = gen_rtx (MEM, QImode, plus_constant (addr, 1)); + MEM_COPY_ATTRIBUTES (mem2, operands[1]); + RTX_UNCHANGING_P (mem2) = RTX_UNCHANGING_P (operands[1]); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = mem1; + operands[2] = gen_reg_rtx (SImode); + operands[3] = gen_reg_rtx (SImode); + operands[6] = gen_reg_rtx (SImode); + operands[7] = mem2; + + if (BYTES_BIG_ENDIAN) + { + operands[4] = operands[2]; + operands[5] = operands[3]; + } + else + { + operands[4] = operands[3]; + operands[5] = operands[2]; + } +} +") + +(define_insn "*extendhisi_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + "arm_arch4" + "ldr%?sh\\t%0, %1" +[(set_attr "type" "load")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (sign_extend:SI (match_operand:HI 1 "alignable_memory_operand" ""))) + (clobber (match_operand:SI 2 "s_register_operand" ""))] + "! arm_arch4" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (ashiftrt:SI (match_dup 2) (const_int 16)))] + " +{ + if ((operands[1] = gen_rotated_half_load (operands[1])) == NULL) + FAIL; +}") + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operator:SI 3 "shiftable_operator" + [(sign_extend:SI (match_operand:HI 1 "alignable_memory_operand" "")) + (match_operand:SI 4 "s_register_operand" "")])) + (clobber (match_operand:SI 2 "s_register_operand" ""))] + "! arm_arch4" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) + (match_op_dup 3 + [(ashiftrt:SI (match_dup 2) (const_int 16)) (match_dup 4)]))] + " +{ + if ((operands[1] = gen_rotated_half_load (operands[1])) == NULL) + FAIL; +}") + +(define_expand "extendqihi2" + [(set (match_dup 2) + (ashift:SI (match_operand:QI 1 "general_operand" "") + (const_int 24))) + (set (match_operand:HI 0 "s_register_operand" "") + (ashiftrt:SI (match_dup 2) + (const_int 24)))] + "" + " +{ + if (arm_arch4 && GET_CODE (operands[1]) == MEM) + { + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (SIGN_EXTEND, HImode, operands[1]))); + DONE; + } + if (! s_register_operand (operands[1], QImode)) + operands[1] = copy_to_mode_reg (QImode, operands[1]); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); +}") + +; Rather than restricting all byte accesses to memory addresses that ldrsb +; can handle, we fix up the ones that ldrsb can't grok with a split. +(define_insn "*extendqihi_insn" + [(set (match_operand:HI 0 "s_register_operand" "=r") + (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))] + "arm_arch4" + "* + /* If the address is invalid, this will split the instruction into two. */ + if (bad_signed_byte_operand(operands[1], QImode)) + return \"#\"; + return \"ldr%?sb\\t%0, %1\"; +" +[(set_attr "type" "load") + (set_attr "length" "8")]) + +(define_split + [(set (match_operand:HI 0 "s_register_operand" "") + (sign_extend:HI (match_operand:QI 1 "bad_signed_byte_operand" "")))] + "arm_arch4 && reload_completed" + [(set (match_dup 3) (match_dup 1)) + (set (match_dup 0) (sign_extend:HI (match_dup 2)))] + " + { + HOST_WIDE_INT offset; + + operands[3] = gen_rtx (REG, SImode, REGNO (operands[0])); + operands[2] = gen_rtx (MEM, QImode, operands[3]); + MEM_COPY_ATTRIBUTES (operands[2], operands[1]); + RTX_UNCHANGING_P (operands[2]) = RTX_UNCHANGING_P (operands[1]); + operands[1] = XEXP (operands[1], 0); + if (GET_CODE (operands[1]) == PLUS + && GET_CODE (XEXP (operands[1], 1)) == CONST_INT + && ! (const_ok_for_arm (offset = INTVAL (XEXP (operands[1], 1))) + || const_ok_for_arm (-offset))) + { + HOST_WIDE_INT low = (offset > 0 + ? (offset & 0xff) : -((-offset) & 0xff)); + XEXP (operands[2], 0) = plus_constant (operands[3], low); + operands[1] = plus_constant (XEXP (operands[1], 0), offset - low); + } + /* Ensure the sum is in correct canonical form */ + else if (GET_CODE (operands[1]) == PLUS + && GET_CODE (XEXP (operands[1], 1)) != CONST_INT + && ! s_register_operand (XEXP (operands[1], 1), VOIDmode)) + operands[1] = gen_rtx (PLUS, GET_MODE (operands[1]), + XEXP (operands[1], 1), XEXP (operands[1], 0)); + } +") + +(define_expand "extendqisi2" + [(set (match_dup 2) + (ashift:SI (match_operand:QI 1 "general_operand" "") + (const_int 24))) + (set (match_operand:SI 0 "s_register_operand" "") + (ashiftrt:SI (match_dup 2) + (const_int 24)))] + "" + " +{ + if (arm_arch4 && GET_CODE (operands[1]) == MEM) + { + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (SIGN_EXTEND, SImode, operands[1]))); + DONE; + } + if (! s_register_operand (operands[1], QImode)) + operands[1] = copy_to_mode_reg (QImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); +}") + +; Rather than restricting all byte accesses to memory addresses that ldrsb +; can handle, we fix up the ones that ldrsb can't grok with a split. +(define_insn "*extendqisi_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + "arm_arch4" + "* + /* If the address is invalid, this will split the instruction into two. */ + if (bad_signed_byte_operand(operands[1], QImode)) + return \"#\"; + return \"ldr%?sb\\t%0, %1\"; +" +[(set_attr "type" "load") + (set_attr "length" "8")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (sign_extend:SI (match_operand:QI 1 "bad_signed_byte_operand" "")))] + "arm_arch4 && reload_completed" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 0) (sign_extend:SI (match_dup 2)))] + " + { + HOST_WIDE_INT offset; + + operands[2] = gen_rtx (MEM, QImode, operands[0]); + MEM_COPY_ATTRIBUTES (operands[2], operands[1]); + RTX_UNCHANGING_P (operands[2]) = RTX_UNCHANGING_P (operands[1]); + operands[1] = XEXP (operands[1], 0); + if (GET_CODE (operands[1]) == PLUS + && GET_CODE (XEXP (operands[1], 1)) == CONST_INT + && ! (const_ok_for_arm (offset = INTVAL (XEXP (operands[1], 1))) + || const_ok_for_arm (-offset))) + { + HOST_WIDE_INT low = (offset > 0 + ? (offset & 0xff) : -((-offset) & 0xff)); + XEXP (operands[2], 0) = plus_constant (operands[0], low); + operands[1] = plus_constant (XEXP (operands[1], 0), offset - low); + } + /* Ensure the sum is in correct canonical form */ + else if (GET_CODE (operands[1]) == PLUS + && GET_CODE (XEXP (operands[1], 1)) != CONST_INT + && ! s_register_operand (XEXP (operands[1], 1), VOIDmode)) + operands[1] = gen_rtx (PLUS, GET_MODE (operands[1]), + XEXP (operands[1], 1), XEXP (operands[1], 0)); + } +") + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (float_extend:DF (match_operand:SF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "mvf%?d\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "extendsfxf2" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (float_extend:XF (match_operand:SF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "mvf%?e\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "extenddfxf2" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (float_extend:XF (match_operand:DF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "mvf%?e\\t%0, %1" +[(set_attr "type" "ffarith")]) + + +;; Move insns (including loads and stores) + +;; XXX Just some ideas about movti. +;; I don't think these are a good idea on the arm, there just aren't enough +;; registers +;;(define_expand "loadti" +;; [(set (match_operand:TI 0 "s_register_operand" "") +;; (mem:TI (match_operand:SI 1 "address_operand" "")))] +;; "" "") + +;;(define_expand "storeti" +;; [(set (mem:TI (match_operand:TI 0 "address_operand" "")) +;; (match_operand:TI 1 "s_register_operand" ""))] +;; "" "") + +;;(define_expand "movti" +;; [(set (match_operand:TI 0 "general_operand" "") +;; (match_operand:TI 1 "general_operand" ""))] +;; "" +;; " +;;{ +;; rtx insn; +;; +;; if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) +;; operands[1] = copy_to_reg (operands[1]); +;; if (GET_CODE (operands[0]) == MEM) +;; insn = gen_storeti (XEXP (operands[0], 0), operands[1]); +;; else if (GET_CODE (operands[1]) == MEM) +;; insn = gen_loadti (operands[0], XEXP (operands[1], 0)); +;; else +;; FAIL; +;; +;; emit_insn (insn); +;; DONE; +;;}") + +;; Recognise garbage generated above. + +;;(define_insn "" +;; [(set (match_operand:TI 0 "general_operand" "=r,r,r,<,>,m") +;; (match_operand:TI 1 "general_operand" "<,>,m,r,r,r"))] +;; "" +;; "* +;; { +;; register mem = (which_alternative < 3); +;; register char *template; +;; +;; operands[mem] = XEXP (operands[mem], 0); +;; switch (which_alternative) +;; { +;; case 0: template = \"ldmdb\\t%1!, %M0\"; break; +;; case 1: template = \"ldmia\\t%1!, %M0\"; break; +;; case 2: template = \"ldmia\\t%1, %M0\"; break; +;; case 3: template = \"stmdb\\t%0!, %M1\"; break; +;; case 4: template = \"stmia\\t%0!, %M1\"; break; +;; case 5: template = \"stmia\\t%0, %M1\"; break; +;; } +;; output_asm_insn (template, operands); +;; return \"\"; +;; }") + + +(define_insn "movdi" + [(set (match_operand:DI 0 "di_operand" "=r,r,o<>") + (match_operand:DI 1 "di_operand" "rIK,mi,r"))] + "" + "* + return (output_move_double (operands)); +" +[(set_attr "length" "8,8,8") + (set_attr "type" "*,load,store2")]) + +(define_expand "movsi" + [(set (match_operand:SI 0 "general_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "" + " + /* Everything except mem = const or mem = mem can be done easily */ + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (SImode, operands[1]); + /* CYGNUS LOCAL nickc */ + if (! ok_integer_or_other (operands[1])) + /* END CYGNUS LOCAL */ + { + arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0], + NULL_RTX, + (reload_in_progress || reload_completed ? 0 + : preserve_subexpressions_p ())); + DONE; + } + if (CONSTANT_P (operands[1]) && flag_pic) + operands[1] = legitimize_pic_address (operands[1], SImode, + ((reload_in_progress + || reload_completed) + ? operands[0] : 0)); +") + +(define_insn "*movsi_insn" + [(set (match_operand:SI 0 "general_operand" "=r,r,r,m") + (match_operand:SI 1 "general_operand" "rI,K,mi,r"))] + "register_operand (operands[0], SImode) + || register_operand (operands[1], SImode)" + "@ + mov%?\\t%0, %1 + mvn%?\\t%0, #%B1 + ldr%?\\t%0, %1 + str%?\\t%1, %0" +[(set_attr "type" "*,*,load,store1")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "! (const_ok_for_arm (INTVAL (operands[1])) + || const_ok_for_arm (~INTVAL (operands[1])))" + [(clobber (const_int 0))] + " + arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0], + NULL_RTX, 0); + DONE; +") + +(define_expand "movaddr" + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operand:DI 1 "address_operand" ""))] + "" + "") + +(define_insn "*movaddr_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operand:DI 1 "address_operand" "p"))] + "reload_completed + && (GET_CODE (operands[1]) == LABEL_REF + || (GET_CODE (operands[1]) == CONST + && GET_CODE (XEXP (operands[1], 0)) == PLUS + && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF + && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT))" + "adr%?\\t%0, %a1") + +/* When generating pic, we need to load the symbol offset into a register. + So that the optimizer does not confuse this with a normal symbol load + we use an unspec. The offset will be loaded from a constant pool entry, + since that is the only type of relocation we can use. */ + +(define_insn "pic_load_addr" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (unspec:SI [(match_operand 1 "" "")] 3))] + "flag_pic" + "ldr%?\\t%0, %a1" + [(set_attr "type" "load")]) + +;; This variant is used for AOF assembly, since it needs to mention the +;; pic register in the rtl. +(define_expand "pic_load_addr_based" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (unspec:SI [(match_operand 1 "" "") (match_dup 2)] 3))] + "flag_pic" + "operands[2] = pic_offset_table_rtx;") + +(define_insn "*pic_load_addr_based_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (unspec:SI [(match_operand 1 "" "") + (match_operand 2 "s_register_operand" "r")] 3))] + "flag_pic && operands[2] == pic_offset_table_rtx" + "* +#ifdef AOF_ASSEMBLER + operands[1] = aof_pic_entry (operands[1]); +#endif + output_asm_insn (\"ldr%?\\t%0, %a1\", operands); + return \"\"; +" [(set_attr "type" "load")]) + +(define_insn "pic_add_dot_plus_eight" + [(set (pc) (label_ref (match_operand 0 "" ""))) + (set (match_operand 1 "register_operand" "+r") + (plus:SI (match_dup 1) (const (plus:SI (pc) (const_int 8)))))] + "flag_pic" + "add%?\\t%1, %|pc, %1") + +;; If copying one reg to another we can set the condition codes according to +;; its value. Such a move is common after a return from subroutine and the +;; result is being tested against zero. + +(define_insn "*movsi_compare0" + [(set (reg:CC 24) (compare:CC (match_operand:SI 1 "s_register_operand" "0,r") + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") (match_dup 1))] + "" + "@ + cmp%?\\t%0, #0 + sub%?s\\t%0, %1, #0" +[(set_attr "conds" "set")]) + +;; Subroutine to store a half word from a register into memory. +;; Operand 0 is the source register (HImode) +;; Operand 1 is the destination address in a register (SImode) + +;; In both this routine and the next, we must be careful not to spill +;; a memory address of reg+large_const into a separate PLUS insn, since this +;; can generate unrecognizable rtl. + +(define_expand "storehi" + [;; store the low byte + (set (match_operand 1 "" "") (match_dup 3)) + ;; extract the high byte + (set (match_dup 2) + (ashiftrt:SI (match_operand 0 "" "") (const_int 8))) + ;; store the high byte + (set (match_dup 4) (subreg:QI (match_dup 2) 0))] ;explicit subreg safe + "" + " +{ + rtx addr = XEXP (operands[1], 0); + enum rtx_code code = GET_CODE (addr); + + if ((code == PLUS && GET_CODE (XEXP (addr, 1)) != CONST_INT) + || code == MINUS) + addr = force_reg (SImode, addr); + + operands[4] = change_address (operands[1], QImode, plus_constant (addr, 1)); + operands[1] = change_address (operands[1], QImode, NULL_RTX); + operands[3] = gen_lowpart (QImode, operands[0]); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[2] = gen_reg_rtx (SImode); +} +") + +(define_expand "storehi_bigend" + [(set (match_dup 4) (match_dup 3)) + (set (match_dup 2) + (ashiftrt:SI (match_operand 0 "" "") (const_int 8))) + (set (match_operand 1 "" "") (subreg:QI (match_dup 2) 0))] + "" + " +{ + rtx addr = XEXP (operands[1], 0); + enum rtx_code code = GET_CODE (addr); + + if ((code == PLUS && GET_CODE (XEXP (addr, 1)) != CONST_INT) + || code == MINUS) + addr = force_reg (SImode, addr); + + operands[4] = change_address (operands[1], QImode, plus_constant (addr, 1)); + operands[1] = change_address (operands[1], QImode, NULL_RTX); + operands[3] = gen_lowpart (QImode, operands[0]); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[2] = gen_reg_rtx (SImode); +} +") + +;; Subroutine to store a half word integer constant into memory. +(define_expand "storeinthi" + [(set (match_operand 0 "" "") + (subreg:QI (match_operand 1 "" "") 0)) + (set (match_dup 3) (subreg:QI (match_dup 2) 0))] + "" + " +{ + HOST_WIDE_INT value = INTVAL (operands[1]); + rtx addr = XEXP (operands[0], 0); + enum rtx_code code = GET_CODE (addr); + + if ((code == PLUS && GET_CODE (XEXP (addr, 1)) != CONST_INT) + || code == MINUS) + addr = force_reg (SImode, addr); + + operands[1] = gen_reg_rtx (SImode); + if (BYTES_BIG_ENDIAN) + { + emit_insn (gen_movsi (operands[1], GEN_INT ((value >> 8) & 255))); + if ((value & 255) == ((value >> 8) & 255)) + operands[2] = operands[1]; + else + { + operands[2] = gen_reg_rtx (SImode); + emit_insn (gen_movsi (operands[2], GEN_INT (value & 255))); + } + } + else + { + emit_insn (gen_movsi (operands[1], GEN_INT (value & 255))); + if ((value & 255) == ((value >> 8) & 255)) + operands[2] = operands[1]; + else + { + operands[2] = gen_reg_rtx (SImode); + emit_insn (gen_movsi (operands[2], GEN_INT ((value >> 8) & 255))); + } + } + + operands[3] = change_address (operands[0], QImode, plus_constant (addr, 1)); + operands[0] = change_address (operands[0], QImode, NULL_RTX); +} +") + +(define_expand "storehi_single_op" + [(set (match_operand:HI 0 "memory_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "arm_arch4" + " + if (! s_register_operand (operands[1], HImode)) + operands[1] = copy_to_mode_reg (HImode, operands[1]); +") + +(define_expand "movhi" + [(set (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + " +{ + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) == MEM) + { + if (arm_arch4) + { + emit_insn (gen_storehi_single_op (operands[0], operands[1])); + DONE; + } + if (GET_CODE (operands[1]) == CONST_INT) + emit_insn (gen_storeinthi (operands[0], operands[1])); + else + { + if (GET_CODE (operands[1]) == MEM) + operands[1] = force_reg (HImode, operands[1]); + if (BYTES_BIG_ENDIAN) + emit_insn (gen_storehi_bigend (operands[1], operands[0])); + else + emit_insn (gen_storehi (operands[1], operands[0])); + } + DONE; + } + /* Sign extend a constant, and keep it in an SImode reg. */ + else if (GET_CODE (operands[1]) == CONST_INT) + { + rtx reg = gen_reg_rtx (SImode); + HOST_WIDE_INT val = INTVAL (operands[1]) & 0xffff; + + /* If the constant is already valid, leave it alone. */ + if (! const_ok_for_arm (val)) + { + /* If setting all the top bits will make the constant + loadable in a single instruction, then set them. + Otherwise, sign extend the number. */ + + if (const_ok_for_arm (~ (val | ~0xffff))) + val |= ~0xffff; + else if (val & 0x8000) + val |= ~0xffff; + } + + emit_insn (gen_movsi (reg, GEN_INT (val))); + operands[1] = gen_rtx_SUBREG (HImode, reg, 0); + } + else if (! arm_arch4) + { + /* Note: We do not have to worry about TARGET_SHORT_BY_BYTES + for v4 and up architectures because LDRH instructions will + be used to access the HI values, and these cannot generate + unaligned word access faults in the MMU. */ + if (GET_CODE (operands[1]) == MEM) + { + if (TARGET_SHORT_BY_BYTES) + { + rtx base; + rtx offset = const0_rtx; + rtx reg = gen_reg_rtx (SImode); + + if ((GET_CODE (base = XEXP (operands[1], 0)) == REG + || (GET_CODE (base) == PLUS + && GET_CODE (offset = XEXP (base, 1)) == CONST_INT + && ((INTVAL(offset) & 1) != 1) + && GET_CODE (base = XEXP (base, 0)) == REG)) + && REGNO_POINTER_ALIGN (REGNO (base)) >= 4) + { + HOST_WIDE_INT new_offset = INTVAL (offset) & ~3; + rtx new; + + new = gen_rtx_MEM (SImode, + plus_constant (base, new_offset)); + MEM_COPY_ATTRIBUTES (new, operands[1]); + RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (operands[1]); + emit_insn (gen_movsi (reg, new)); + if (((INTVAL (offset) & 2) != 0) + ^ (BYTES_BIG_ENDIAN ? 1 : 0)) + { + rtx reg2 = gen_reg_rtx (SImode); + + emit_insn (gen_lshrsi3 (reg2, reg, GEN_INT (16))); + reg = reg2; + } + } + else + emit_insn (gen_movhi_bytes (reg, operands[1])); + + operands[1] = gen_lowpart (HImode, reg); + } + else if (BYTES_BIG_ENDIAN) + { + rtx base; + rtx offset = const0_rtx; + + if ((GET_CODE (base = XEXP (operands[1], 0)) == REG + || (GET_CODE (base) == PLUS + && GET_CODE (offset = XEXP (base, 1)) == CONST_INT + && GET_CODE (base = XEXP (base, 0)) == REG)) + && REGNO_POINTER_ALIGN (REGNO (base)) >= 4) + { + rtx reg = gen_reg_rtx (SImode); + rtx new; + + if ((INTVAL (offset) & 2) == 2) + { + HOST_WIDE_INT new_offset = INTVAL (offset) ^ 2; + new = gen_rtx_MEM (SImode, + plus_constant (base, new_offset)); + MEM_COPY_ATTRIBUTES (new, operands[1]); + RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (operands[1]); + emit_insn (gen_movsi (reg, new)); + } + else + { + new = gen_rtx_MEM (SImode, XEXP (operands[1], 0)); + MEM_COPY_ATTRIBUTES (new, operands[1]); + RTX_UNCHANGING_P (new) + = RTX_UNCHANGING_P (operands[1]); + emit_insn (gen_rotated_loadsi (reg, new)); + } + + operands[1] = gen_lowpart (HImode, reg); + } + else + { + emit_insn (gen_movhi_bigend (operands[0], operands[1])); + DONE; + } + } + } + } + } + /* Handle loading a large integer during reload */ + else if (GET_CODE (operands[1]) == CONST_INT + && ! const_ok_for_arm (INTVAL (operands[1])) + && ! const_ok_for_arm (~INTVAL (operands[1]))) + { + /* Writing a constant to memory needs a scratch, which should + be handled with SECONDARY_RELOADs. */ + if (GET_CODE (operands[0]) != REG) + abort (); + + operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0); + emit_insn (gen_movsi (operands[0], operands[1])); + DONE; + } +} +") + +(define_insn "rotated_loadsi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (rotate:SI (match_operand:SI 1 "offsettable_memory_operand" "o") + (const_int 16)))] + "! TARGET_SHORT_BY_BYTES" + "* +{ + rtx ops[2]; + + ops[0] = operands[0]; + ops[1] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 2)); + output_asm_insn (\"ldr%?\\t%0, %1\\t%@ load-rotate\", ops); + return \"\"; +}" +[(set_attr "type" "load")]) + +(define_expand "movhi_bytes" + [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" ""))) + (set (match_dup 3) + (zero_extend:SI (match_dup 6))) + (set (match_operand:SI 0 "" "") + (ior:SI (ashift:SI (match_dup 4) (const_int 8)) (match_dup 5)))] + "" + " +{ + rtx mem1, mem2; + rtx addr = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); + + mem1 = gen_rtx (MEM, QImode, addr); + MEM_COPY_ATTRIBUTES (mem1, operands[1]); + RTX_UNCHANGING_P (mem1) = RTX_UNCHANGING_P (operands[1]); + mem2 = gen_rtx (MEM, QImode, plus_constant (addr, 1)); + MEM_COPY_ATTRIBUTES (mem2, operands[1]); + RTX_UNCHANGING_P (mem2) = RTX_UNCHANGING_P (operands[1]); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = mem1; + operands[2] = gen_reg_rtx (SImode); + operands[3] = gen_reg_rtx (SImode); + operands[6] = mem2; + + if (BYTES_BIG_ENDIAN) + { + operands[4] = operands[2]; + operands[5] = operands[3]; + } + else + { + operands[4] = operands[3]; + operands[5] = operands[2]; + } +} +") + +(define_expand "movhi_bigend" + [(set (match_dup 2) + (rotate:SI (subreg:SI (match_operand:HI 1 "memory_operand" "") 0) + (const_int 16))) + (set (match_dup 3) + (ashiftrt:SI (match_dup 2) (const_int 16))) + (set (match_operand:HI 0 "s_register_operand" "") + (subreg:HI (match_dup 3) 0))] + "" + " + operands[2] = gen_reg_rtx (SImode); + operands[3] = gen_reg_rtx (SImode); +") + +;; Pattern to recognise insn generated default case above +;; CYGNUS LOCAL nickc: Store before load to avoid problem with reload. +(define_insn "*movhi_insn_arch4" + [(set (match_operand:HI 0 "general_operand" "=r,r,m,r") + (match_operand:HI 1 "general_operand" "rI,K,r,m"))] + "arm_arch4 + && ok_integer_or_other (operands[0]) + && ok_integer_or_other (operands[1])" ;; CYGNUS LOCAL nickc + "@ + mov%?\\t%0, %1\\t%@ movhi + mvn%?\\t%0, #%B1\\t%@ movhi + str%?h\\t%1, %0\\t%@ movhi ;; CYGNUS LOCAL nickc + ldr%?h\\t%0, %1\\t%@ movhi" ;; CYGNUS LOCAL nickc +[(set_attr "type" "*,*,store1,load")]) ;; CYGNUS LOCAL nickc +;; END CYGNUS LOCAL + +(define_insn "*movhi_insn_littleend" + [(set (match_operand:HI 0 "general_operand" "=r,r,r") + (match_operand:HI 1 "general_operand" "rI,K,m"))] + "! arm_arch4 + && ! BYTES_BIG_ENDIAN + && ! TARGET_SHORT_BY_BYTES + /* CYGNUS LOCAL nickc */ + && ok_integer_or_other (operands[1])" + ;; END CYGNUS LOCAL nickc + "@ + mov%?\\t%0, %1\\t%@ movhi + mvn%?\\t%0, #%B1\\t%@ movhi + ldr%?\\t%0, %1\\t%@ movhi" +[(set_attr "type" "*,*,load")]) + +(define_insn "*movhi_insn_bigend" + [(set (match_operand:HI 0 "s_register_operand" "=r,r,r") + (match_operand:HI 1 "general_operand" "rI,K,m"))] + "! arm_arch4 + && BYTES_BIG_ENDIAN + && ! TARGET_SHORT_BY_BYTES + /* CYGNUS LOCAL NICKC */ + && ok_integer_or_other (operands[1])" + ;; END CYGNUS LOCAL + "@ + mov%?\\t%0, %1\\t%@ movhi + mvn%?\\t%0, #%B1\\t%@ movhi + ldr%?\\t%0, %1\\t%@ movhi_bigend\;mov%?\\t%0, %0, asr #16" +[(set_attr "type" "*,*,load") + (set_attr "length" "4,4,8")]) + +(define_insn "*loadhi_si_bigend" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (rotate:SI (subreg:SI (match_operand:HI 1 "memory_operand" "m") 0) + (const_int 16)))] + "BYTES_BIG_ENDIAN + && ! TARGET_SHORT_BY_BYTES" + "ldr%?\\t%0, %1\\t%@ movhi_bigend" +[(set_attr "type" "load")]) + +(define_insn "*movhi_bytes" + [(set (match_operand:HI 0 "s_register_operand" "=r,r") + (match_operand:HI 1 "arm_rhs_operand" "rI,K"))] + "TARGET_SHORT_BY_BYTES" + "@ + mov%?\\t%0, %1\\t%@ movhi + mvn%?\\t%0, #%B1\\t%@ movhi") + + +(define_expand "reload_outhi" + [(parallel [(match_operand:HI 0 "reload_memory_operand" "=o") + (match_operand:HI 1 "s_register_operand" "r") + (match_operand:SI 2 "s_register_operand" "=&r")])] + "" + " + arm_reload_out_hi (operands); + DONE; +") + +(define_expand "reload_inhi" + [(parallel [(match_operand:HI 0 "s_register_operand" "=r") + (match_operand:HI 1 "reload_memory_operand" "o") + (match_operand:SI 2 "s_register_operand" "=&r")])] + "TARGET_SHORT_BY_BYTES" + " + arm_reload_in_hi (operands); + DONE; +") + +(define_expand "movqi" + [(set (match_operand:QI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" + " + /* Everything except mem = const or mem = mem can be done easily */ + + if (!(reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[1]) == CONST_INT) + { + rtx reg = gen_reg_rtx (SImode); + + emit_insn (gen_movsi (reg, operands[1])); + operands[1] = gen_rtx (SUBREG, QImode, reg, 0); + } + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (QImode, operands[1]); + } +") + + +(define_insn "*movqi_insn" + [(set (match_operand:QI 0 "general_operand" "=r,r,r,m") + (match_operand:QI 1 "general_operand" "rI,K,m,r"))] + "register_operand (operands[0], QImode) + || register_operand (operands[1], QImode)" + "@ + mov%?\\t%0, %1 + mvn%?\\t%0, #%B1 + ldr%?b\\t%0, %1 + str%?b\\t%1, %0" +[(set_attr "type" "*,*,load,store1")]) + +(define_expand "movsf" + [(set (match_operand:SF 0 "general_operand" "") + (match_operand:SF 1 "general_operand" ""))] + "" + " + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (SFmode, operands[1]); +") + +(define_insn "*movsf_hard_insn" + [(set (match_operand:SF 0 "general_operand" "=f,f,f,m,f,r,r,r,m") + (match_operand:SF 1 "general_operand" "fG,H,mE,f,r,f,r,mE,r"))] + "TARGET_HARD_FLOAT + && (GET_CODE (operands[0]) != MEM || register_operand (operands[1], SFmode))" + "@ + mvf%?s\\t%0, %1 + mnf%?s\\t%0, #%N1 + ldf%?s\\t%0, %1 + stf%?s\\t%1, %0 + str%?\\t%1, [%|sp, #-4]!\;ldf%?s\\t%0, [%|sp], #4 + stf%?s\\t%1, [%|sp, #-4]!\;ldr%?\\t%0, [%|sp], #4 + mov%?\\t%0, %1 + ldr%?\\t%0, %1\\t%@ float + str%?\\t%1, %0\\t%@ float" +[(set_attr "length" "4,4,4,4,8,8,4,4,4") + (set_attr "type" + "ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r,*,load,store1")]) + +;; Exactly the same as above, except that all `f' cases are deleted. +;; This is necessary to prevent reload from ever trying to use a `f' reg +;; when -msoft-float. + +(define_insn "*movsf_soft_insn" + [(set (match_operand:SF 0 "general_operand" "=r,r,m") + (match_operand:SF 1 "general_operand" "r,mE,r"))] + "TARGET_SOFT_FLOAT + && (GET_CODE (operands[0]) != MEM || register_operand (operands[1], SFmode))" + "@ + mov%?\\t%0, %1 + ldr%?\\t%0, %1\\t%@ float + str%?\\t%1, %0\\t%@ float" +[(set_attr "length" "4,4,4") + (set_attr "type" "*,load,store1")]) + +(define_expand "movdf" + [(set (match_operand:DF 0 "general_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "" + " + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (DFmode, operands[1]); +") + +;; Reloading a df mode value stored in integer regs to memory can require a +;; scratch reg. +(define_expand "reload_outdf" + [(match_operand:DF 0 "reload_memory_operand" "=o") + (match_operand:DF 1 "s_register_operand" "r") + (match_operand:SI 2 "s_register_operand" "=&r")] + "" + " +{ + enum rtx_code code = GET_CODE (XEXP (operands[0], 0)); + + if (code == REG) + operands[2] = XEXP (operands[0], 0); + else if (code == POST_INC || code == PRE_DEC) + { + operands[0] = gen_rtx (SUBREG, DImode, operands[0], 0); + operands[1] = gen_rtx (SUBREG, DImode, operands[1], 0); + emit_insn (gen_movdi (operands[0], operands[1])); + DONE; + } + else if (code == PRE_INC) + { + rtx reg = XEXP (XEXP (operands[0], 0), 0); + emit_insn (gen_addsi3 (reg, reg, GEN_INT (8))); + operands[2] = reg; + } + else if (code == POST_DEC) + operands[2] = XEXP (XEXP (operands[0], 0), 0); + else + emit_insn (gen_addsi3 (operands[2], XEXP (XEXP (operands[0], 0), 0), + XEXP (XEXP (operands[0], 0), 1))); + + emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (MEM, DFmode, operands[2]), + operands[1])); + + if (code == POST_DEC) + emit_insn (gen_addsi3 (operands[2], operands[2], GEN_INT (-8))); + + DONE; +} +") + +(define_insn "*movdf_hard_insn" + [(set (match_operand:DF 0 "general_operand" "=r,Q,r,m,r,f,f,f,m,!f,!r") + (match_operand:DF 1 "general_operand" "Q,r,r,r,mF,fG,H,mF,f,r,f"))] + "TARGET_HARD_FLOAT + && (GET_CODE (operands[0]) != MEM + || register_operand (operands[1], DFmode))" + "* +{ + rtx ops[3]; + + switch (which_alternative) + { + case 0: return \"ldm%?ia\\t%m1, %M0\\t%@ double\"; + case 1: return \"stm%?ia\\t%m0, %M1\\t%@ double\"; + case 2: case 3: case 4: return output_move_double (operands); + case 5: return \"mvf%?d\\t%0, %1\"; + case 6: return \"mnf%?d\\t%0, #%N1\"; + case 7: return \"ldf%?d\\t%0, %1\"; + case 8: return \"stf%?d\\t%1, %0\"; + case 9: return output_mov_double_fpu_from_arm (operands); + case 10: return output_mov_double_arm_from_fpu (operands); + } +} +" +[(set_attr "length" "4,4,8,8,8,4,4,4,4,8,8") + (set_attr "type" +"load,store2,*,store2,load,ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r")]) + +;; Software floating point version. This is essentially the same as movdi. +;; Do not use `f' as a constraint to prevent reload from ever trying to use +;; an `f' reg. + +(define_insn "*movdf_soft_insn" + [(set (match_operand:DF 0 "soft_df_operand" "=r,r,m") + (match_operand:DF 1 "soft_df_operand" "r,mF,r"))] + "TARGET_SOFT_FLOAT" + "* return output_move_double (operands);" +[(set_attr "length" "8,8,8") + (set_attr "type" "*,load,store2")]) + +(define_expand "movxf" + [(set (match_operand:XF 0 "general_operand" "") + (match_operand:XF 1 "general_operand" ""))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "") + +;; Even when the XFmode patterns aren't enabled, we enable this after +;; reloading so that we can push floating point registers in the prologue. + +(define_insn "*movxf_hard_insn" + [(set (match_operand:XF 0 "general_operand" "=f,f,f,m,f,r,r") + (match_operand:XF 1 "general_operand" "fG,H,m,f,r,f,r"))] + "TARGET_HARD_FLOAT && (ENABLE_XF_PATTERNS || reload_completed)" + "* + switch (which_alternative) + { + case 0: return \"mvf%?e\\t%0, %1\"; + case 1: return \"mnf%?e\\t%0, #%N1\"; + case 2: return \"ldf%?e\\t%0, %1\"; + case 3: return \"stf%?e\\t%1, %0\"; + case 4: return output_mov_long_double_fpu_from_arm (operands); + case 5: return output_mov_long_double_arm_from_fpu (operands); + case 6: return output_mov_long_double_arm_from_arm (operands); + } +" +[(set_attr "length" "4,4,4,4,8,8,12") + (set_attr "type" "ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r,*")]) + + +;; load- and store-multiple insns +;; The arm can load/store any set of registers, provided that they are in +;; ascending order; but that is beyond GCC so stick with what it knows. + +(define_expand "load_multiple" + [(match_par_dup 3 [(set (match_operand:SI 0 "" "") + (match_operand:SI 1 "" "")) + (use (match_operand:SI 2 "" ""))])] + "" + " + /* Support only fixed point registers */ + if (GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) > 14 + || INTVAL (operands[2]) < 2 + || GET_CODE (operands[1]) != MEM + || GET_CODE (operands[0]) != REG + || REGNO (operands[0]) > 14 + || REGNO (operands[0]) + INTVAL (operands[2]) > 15) + FAIL; + + operands[3] + = arm_gen_load_multiple (REGNO (operands[0]), INTVAL (operands[2]), + force_reg (SImode, XEXP (operands[1], 0)), + TRUE, FALSE, RTX_UNCHANGING_P(operands[1]), + MEM_IN_STRUCT_P(operands[1]), + MEM_SCALAR_P (operands[1])); +") + +;; Load multiple with write-back + +(define_insn "*ldmsi_postinc" + [(match_parallel 0 "load_multiple_operation" + [(set (match_operand:SI 1 "s_register_operand" "+r") + (plus:SI (match_dup 1) + (match_operand:SI 2 "const_int_operand" "n"))) + (set (match_operand:SI 3 "s_register_operand" "=r") + (mem:SI (match_dup 1)))])] + "(INTVAL (operands[2]) == 4 * (XVECLEN (operands[0], 0) - 2))" + "* +{ + rtx ops[3]; + int count = XVECLEN (operands[0], 0); + + ops[0] = XEXP (SET_SRC (XVECEXP (operands[0], 0, 0)), 0); + ops[1] = SET_DEST (XVECEXP (operands[0], 0, 1)); + ops[2] = SET_DEST (XVECEXP (operands[0], 0, count - 2)); + + output_asm_insn (\"ldm%?ia\\t%0!, {%1-%2}\\t%@ load multiple\", ops); + return \"\"; +} +" +[(set_attr "type" "load")]) + +;; Ordinary load multiple + +(define_insn "*ldmsi" + [(match_parallel 0 "load_multiple_operation" + [(set (match_operand:SI 1 "s_register_operand" "=r") + (mem:SI (match_operand:SI 2 "s_register_operand" "r")))])] + "" + "* +{ + rtx ops[3]; + int count = XVECLEN (operands[0], 0); + + ops[0] = XEXP (SET_SRC (XVECEXP (operands[0], 0, 0)), 0); + ops[1] = SET_DEST (XVECEXP (operands[0], 0, 0)); + ops[2] = SET_DEST (XVECEXP (operands[0], 0, count - 1)); + + output_asm_insn (\"ldm%?ia\\t%0, {%1-%2}\\t%@ load multiple\", ops); + return \"\"; +} +" +[(set_attr "type" "load")]) + +(define_expand "store_multiple" + [(match_par_dup 3 [(set (match_operand:SI 0 "" "") + (match_operand:SI 1 "" "")) + (use (match_operand:SI 2 "" ""))])] + "" + " + /* Support only fixed point registers */ + if (GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) > 14 + || INTVAL (operands[2]) < 2 + || GET_CODE (operands[1]) != REG + || GET_CODE (operands[0]) != MEM + || REGNO (operands[1]) > 14 + || REGNO (operands[1]) + INTVAL (operands[2]) > 15) + FAIL; + + operands[3] + = arm_gen_store_multiple (REGNO (operands[1]), INTVAL (operands[2]), + force_reg (SImode, XEXP (operands[0], 0)), + TRUE, FALSE, RTX_UNCHANGING_P (operands[0]), + MEM_IN_STRUCT_P(operands[0]), + MEM_SCALAR_P (operands[0])); +") + +;; Store multiple with write-back + +(define_insn "*stmsi_postinc" + [(match_parallel 0 "store_multiple_operation" + [(set (match_operand:SI 1 "s_register_operand" "+r") + (plus:SI (match_dup 1) + (match_operand:SI 2 "const_int_operand" "n"))) + (set (mem:SI (match_dup 1)) + (match_operand:SI 3 "s_register_operand" "r"))])] + "(INTVAL (operands[2]) == 4 * (XVECLEN (operands[0], 0) - 2))" + "* +{ + rtx ops[3]; + int count = XVECLEN (operands[0], 0); + + ops[0] = XEXP (SET_SRC (XVECEXP (operands[0], 0, 0)), 0); + ops[1] = SET_SRC (XVECEXP (operands[0], 0, 1)); + ops[2] = SET_SRC (XVECEXP (operands[0], 0, count - 2)); + + output_asm_insn (\"stm%?ia\\t%0!, {%1-%2}\\t%@ str multiple\", ops); + return \"\"; +} +" +[(set (attr "type") + (cond [(eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 4)) + (const_string "store2") + (eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 5)) + (const_string "store3")] + (const_string "store4")))]) + +;; Ordinary store multiple + +(define_insn "*stmsi" + [(match_parallel 0 "store_multiple_operation" + [(set (mem:SI (match_operand:SI 2 "s_register_operand" "r")) + (match_operand:SI 1 "s_register_operand" "r"))])] + "" + "* +{ + rtx ops[3]; + int count = XVECLEN (operands[0], 0); + + ops[0] = XEXP (SET_DEST (XVECEXP (operands[0], 0, 0)), 0); + ops[1] = SET_SRC (XVECEXP (operands[0], 0, 0)); + ops[2] = SET_SRC (XVECEXP (operands[0], 0, count - 1)); + + output_asm_insn (\"stm%?ia\\t%0, {%1-%2}\\t%@ str multiple\", ops); + return \"\"; +} +" +[(set (attr "type") + (cond [(eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 3)) + (const_string "store2") + (eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 4)) + (const_string "store3")] + (const_string "store4")))]) + +;; Move a block of memory if it is word aligned and MORE than 2 words long. +;; We could let this apply for blocks of less than this, but it clobbers so +;; many registers that there is then probably a better way. + +(define_expand "movstrqi" + [(match_operand:BLK 0 "general_operand" "") + (match_operand:BLK 1 "general_operand" "") + (match_operand:SI 2 "const_int_operand" "") + (match_operand:SI 3 "const_int_operand" "")] + "" + " + if (arm_gen_movstrqi (operands)) + DONE; + FAIL; +") + + +;; Comparison and test insns + +(define_expand "cmpsi" + [(match_operand:SI 0 "s_register_operand" "") + (match_operand:SI 1 "arm_add_operand" "")] + "" + " +{ + arm_compare_op0 = operands[0]; + arm_compare_op1 = operands[1]; + arm_compare_fp = 0; + DONE; +} +") + +(define_expand "cmpsf" + [(match_operand:SF 0 "s_register_operand" "") + (match_operand:SF 1 "fpu_rhs_operand" "")] + "TARGET_HARD_FLOAT" + " +{ + arm_compare_op0 = operands[0]; + arm_compare_op1 = operands[1]; + arm_compare_fp = 1; + DONE; +} +") + +(define_expand "cmpdf" + [(match_operand:DF 0 "s_register_operand" "") + (match_operand:DF 1 "fpu_rhs_operand" "")] + "TARGET_HARD_FLOAT" + " +{ + arm_compare_op0 = operands[0]; + arm_compare_op1 = operands[1]; + arm_compare_fp = 1; + DONE; +} +") + +(define_expand "cmpxf" + [(match_operand:XF 0 "s_register_operand" "") + (match_operand:XF 1 "fpu_rhs_operand" "")] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + " +{ + arm_compare_op0 = operands[0]; + arm_compare_op1 = operands[1]; + arm_compare_fp = 1; + DONE; +} +") + +(define_insn "*cmpsi_insn" + [(set (reg:CC 24) + (compare:CC (match_operand:SI 0 "s_register_operand" "r,r") + (match_operand:SI 1 "arm_add_operand" "rI,L")))] + "" + "@ + cmp%?\\t%0, %1 + cmn%?\\t%0, #%n1" +[(set_attr "conds" "set")]) + +(define_insn "*cmpsi_shiftsi" + [(set (reg:CC 24) + (compare:CC (match_operand:SI 0 "s_register_operand" "r") + (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")])))] + "" + "cmp%?\\t%0, %1%S3" +[(set_attr "conds" "set")]) + +(define_insn "*cmpsi_shiftsi_swp" + [(set (reg:CC_SWP 24) + (compare:CC_SWP (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "reg_or_int_operand" "rM")]) + (match_operand:SI 0 "s_register_operand" "r")))] + "" + "cmp%?\\t%0, %1%S3" +[(set_attr "conds" "set")]) + +(define_insn "*cmpsi_neg_shiftsi" + [(set (reg:CC 24) + (compare:CC (match_operand:SI 0 "s_register_operand" "r") + (neg:SI (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")]))))] + "" + "cmn%?\\t%0, %1%S3" +[(set_attr "conds" "set")]) + +(define_insn "*cmpsf_insn" + [(set (reg:CCFP 24) + (compare:CCFP (match_operand:SF 0 "s_register_operand" "f,f") + (match_operand:SF 1 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + cmf%?\\t%0, %1 + cnf%?\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmpdf_insn" + [(set (reg:CCFP 24) + (compare:CCFP (match_operand:DF 0 "s_register_operand" "f,f") + (match_operand:DF 1 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + cmf%?\\t%0, %1 + cnf%?\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmpesfdf_df" + [(set (reg:CCFP 24) + (compare:CCFP (float_extend:DF + (match_operand:SF 0 "s_register_operand" "f,f")) + (match_operand:DF 1 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + cmf%?\\t%0, %1 + cnf%?\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmpdf_esfdf" + [(set (reg:CCFP 24) + (compare:CCFP (match_operand:DF 0 "s_register_operand" "f") + (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "cmf%?\\t%0, %1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmpxf_insn" + [(set (reg:CCFP 24) + (compare:CCFP (match_operand:XF 0 "s_register_operand" "f,f") + (match_operand:XF 1 "fpu_add_operand" "fG,H")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "@ + cmf%?\\t%0, %1 + cnf%?\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmpsf_trap" + [(set (reg:CCFPE 24) + (compare:CCFPE (match_operand:SF 0 "s_register_operand" "f,f") + (match_operand:SF 1 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + cmf%?e\\t%0, %1 + cnf%?e\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmpdf_trap" + [(set (reg:CCFPE 24) + (compare:CCFPE (match_operand:DF 0 "s_register_operand" "f,f") + (match_operand:DF 1 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + cmf%?e\\t%0, %1 + cnf%?e\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmp_esfdf_df_trap" + [(set (reg:CCFPE 24) + (compare:CCFPE (float_extend:DF + (match_operand:SF 0 "s_register_operand" "f,f")) + (match_operand:DF 1 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + cmf%?e\\t%0, %1 + cnf%?e\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmp_df_esfdf_trap" + [(set (reg:CCFPE 24) + (compare:CCFPE (match_operand:DF 0 "s_register_operand" "f") + (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "cmf%?e\\t%0, %1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmpxf_trap" + [(set (reg:CCFPE 24) + (compare:CCFPE (match_operand:XF 0 "s_register_operand" "f,f") + (match_operand:XF 1 "fpu_add_operand" "fG,H")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "@ + cmf%?e\\t%0, %1 + cnf%?e\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +; This insn allows redundant compares to be removed by cse, nothing should +; ever appear in the output file since (set (reg x) (reg x)) is a no-op that +; is deleted later on. The match_dup will match the mode here, so that +; mode changes of the condition codes aren't lost by this even though we don't +; specify what they are. + +(define_insn "*deleted_compare" + [(set (match_operand 0 "cc_register" "") (match_dup 0))] + "" + "\\t%@ deleted compare" +[(set_attr "conds" "set") + (set_attr "length" "0")]) + + +;; Conditional branch insns + +(define_expand "beq" + [(set (pc) + (if_then_else (eq (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (EQ, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "bne" + [(set (pc) + (if_then_else (ne (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (NE, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "bgt" + [(set (pc) + (if_then_else (gt (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (GT, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "ble" + [(set (pc) + (if_then_else (le (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (LE, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "bge" + [(set (pc) + (if_then_else (ge (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (GE, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "blt" + [(set (pc) + (if_then_else (lt (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (LT, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "bgtu" + [(set (pc) + (if_then_else (gtu (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (GTU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "bleu" + [(set (pc) + (if_then_else (leu (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (LEU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "bgeu" + [(set (pc) + (if_then_else (geu (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (GEU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "bltu" + [(set (pc) + (if_then_else (ltu (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (LTU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +;; patterns to match conditional branch insns + +(define_insn "*condbranch" + [(set (pc) + (if_then_else (match_operator 1 "comparison_operator" + [(match_operand 2 "cc_register" "") (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + extern int arm_ccfsm_state; + + if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2) + { + arm_ccfsm_state += 2; + return \"\"; + } + return \"b%d1\\t%l0\"; +}" +[(set_attr "conds" "use")]) + +(define_insn "*condbranch_reversed" + [(set (pc) + (if_then_else (match_operator 1 "comparison_operator" + [(match_operand 2 "cc_register" "") (const_int 0)]) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + extern int arm_ccfsm_state; + + if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2) + { + arm_ccfsm_state += 2; + return \"\"; + } + return \"b%D1\\t%l0\"; +}" +[(set_attr "conds" "use")]) + + +; scc insns + +(define_expand "seq" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (eq:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (EQ, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sne" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (ne:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (NE, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sgt" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (gt:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (GT, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sle" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (le:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (LE, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sge" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (ge:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (GE, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "slt" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (lt:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (LT, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sgtu" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (gtu:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (GTU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sleu" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (leu:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (LEU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sgeu" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (geu:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (GEU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sltu" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (ltu:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (LTU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_insn "*mov_scc" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operator:SI 1 "comparison_operator" + [(match_operand 2 "cc_register" "") (const_int 0)]))] + "" + "mov%D1\\t%0, #0\;mov%d1\\t%0, #1" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + +(define_insn "*mov_negscc" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (neg:SI (match_operator:SI 1 "comparison_operator" + [(match_operand 2 "cc_register" "") (const_int 0)])))] + "" + "mov%D1\\t%0, #0\;mvn%d1\\t%0, #0" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + +(define_insn "*mov_notscc" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (not:SI (match_operator:SI 1 "comparison_operator" + [(match_operand 2 "cc_register" "") (const_int 0)])))] + "" + "mov%D1\\t%0, #0\;mvn%d1\\t%0, #1" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + + +;; Conditional move insns + +(define_expand "movsicc" + [(set (match_operand:SI 0 "s_register_operand" "") + (if_then_else:SI (match_operand 1 "comparison_operator" "") + (match_operand:SI 2 "arm_not_operand" "") + (match_operand:SI 3 "arm_not_operand" "")))] + "" + " +{ + enum rtx_code code = GET_CODE (operands[1]); + rtx ccreg = gen_compare_reg (code, arm_compare_op0, arm_compare_op1, + arm_compare_fp); + + operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); +}") + +(define_expand "movsfcc" + [(set (match_operand:SF 0 "s_register_operand" "") + (if_then_else:SF (match_operand 1 "comparison_operator" "") + (match_operand:SF 2 "s_register_operand" "") + (match_operand:SF 3 "nonmemory_operand" "")))] + "" + " +{ + enum rtx_code code = GET_CODE (operands[1]); + rtx ccreg; + + /* When compiling for SOFT_FLOAT, ensure both arms are in registers. + Otherwise, ensure it is a valid FP add operand */ + if ((! TARGET_HARD_FLOAT) + || (! fpu_add_operand (operands[3], SFmode))) + operands[3] = force_reg (SFmode, operands[3]); + + ccreg = gen_compare_reg (code, arm_compare_op0, arm_compare_op1, + arm_compare_fp); + + operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); +}") + +(define_expand "movdfcc" + [(set (match_operand:DF 0 "s_register_operand" "") + (if_then_else:DF (match_operand 1 "comparison_operator" "") + (match_operand:DF 2 "s_register_operand" "") + (match_operand:DF 3 "fpu_add_operand" "")))] + "TARGET_HARD_FLOAT" + " +{ + enum rtx_code code = GET_CODE (operands[1]); + rtx ccreg = gen_compare_reg (code, arm_compare_op0, arm_compare_op1, + arm_compare_fp); + + operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); +}") + +(define_insn "*movsicc_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r,r,r,r,r") + (if_then_else:SI + (match_operator 3 "comparison_operator" + [(match_operand 4 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_not_operand" "0,0,rI,K,rI,rI,K,K") + (match_operand:SI 2 "arm_not_operand" "rI,K,0,0,rI,K,rI,K")))] + "" + "@ + mov%D3\\t%0, %2 + mvn%D3\\t%0, #%B2 + mov%d3\\t%0, %1 + mvn%d3\\t%0, #%B1 + mov%d3\\t%0, %1\;mov%D3\\t%0, %2 + mov%d3\\t%0, %1\;mvn%D3\\t%0, #%B2 + mvn%d3\\t%0, #%B1\;mov%D3\\t%0, %2 + mvn%d3\\t%0, #%B1\;mvn%D3\\t%0, #%B2" + [(set_attr "length" "4,4,4,4,8,8,8,8") + (set_attr "conds" "use")]) + +(define_insn "*movsfcc_hard_insn" + [(set (match_operand:SF 0 "s_register_operand" "=f,f,f,f,f,f,f,f") + (if_then_else:SF + (match_operator 3 "comparison_operator" + [(match_operand 4 "cc_register" "") (const_int 0)]) + (match_operand:SF 1 "fpu_add_operand" "0,0,fG,H,fG,fG,H,H") + (match_operand:SF 2 "fpu_add_operand" "fG,H,0,0,fG,H,fG,H")))] + "TARGET_HARD_FLOAT" + "@ + mvf%D3s\\t%0, %2 + mnf%D3s\\t%0, #%N2 + mvf%d3s\\t%0, %1 + mnf%d3s\\t%0, #%N1 + mvf%d3s\\t%0, %1\;mvf%D3s\\t%0, %2 + mvf%d3s\\t%0, %1\;mnf%D3s\\t%0, #%N2 + mnf%d3s\\t%0, #%N1\;mvf%D3s\\t%0, %2 + mnf%d3s\\t%0, #%N1\;mnf%D3s\\t%0, #%N2" + [(set_attr "length" "4,4,4,4,8,8,8,8") + (set_attr "type" "ffarith") + (set_attr "conds" "use")]) + +(define_insn "*movsfcc_soft_insn" + [(set (match_operand:SF 0 "s_register_operand" "=r,r") + (if_then_else:SF (match_operator 3 "comparison_operator" + [(match_operand 4 "cc_register" "") (const_int 0)]) + (match_operand:SF 1 "s_register_operand" "0,r") + (match_operand:SF 2 "s_register_operand" "r,0")))] + "TARGET_SOFT_FLOAT" + "@ + mov%D3\\t%0, %2 + mov%d3\\t%0, %1" + [(set_attr "conds" "use")]) + +(define_insn "*movdfcc_insn" + [(set (match_operand:DF 0 "s_register_operand" "=f,f,f,f,f,f,f,f") + (if_then_else:DF + (match_operator 3 "comparison_operator" + [(match_operand 4 "cc_register" "") (const_int 0)]) + (match_operand:DF 1 "fpu_add_operand" "0,0,fG,H,fG,fG,H,H") + (match_operand:DF 2 "fpu_add_operand" "fG,H,0,0,fG,H,fG,H")))] + "TARGET_HARD_FLOAT" + "@ + mvf%D3d\\t%0, %2 + mnf%D3d\\t%0, #%N2 + mvf%d3d\\t%0, %1 + mnf%d3d\\t%0, #%N1 + mvf%d3d\\t%0, %1\;mvf%D3d\\t%0, %2 + mvf%d3d\\t%0, %1\;mnf%D3d\\t%0, #%N2 + mnf%d3d\\t%0, #%N1\;mvf%D3d\\t%0, %2 + mnf%d3d\\t%0, #%N1\;mnf%D3d\\t%0, #%N2" + [(set_attr "length" "4,4,4,4,8,8,8,8") + (set_attr "type" "ffarith") + (set_attr "conds" "use")]) + +;; Jump and linkage insns + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "* +{ + extern int arm_ccfsm_state; + + if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2) + { + arm_ccfsm_state += 2; + return \"\"; + } + return \"b%?\\t%l0\"; +}") + +(define_expand "call" + [(parallel [(call (match_operand 0 "memory_operand" "") + (match_operand 1 "general_operand" "")) + (clobber (reg:SI 14))])] + "" + " +{ + if (TARGET_LONG_CALLS && GET_CODE (XEXP (operands[0], 0)) != REG) + XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0)); +}") + +(define_insn "*call_reg" + [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r")) + (match_operand 1 "" "g")) + (clobber (reg:SI 14))] + "" + "* + return output_call (operands); +" +;; length is worst case, normally it is only two +[(set_attr "length" "12") + (set_attr "type" "call")]) + +(define_insn "*call_mem" + [(call (mem:SI (match_operand 0 "memory_operand" "m")) + (match_operand 1 "general_operand" "g")) + (clobber (reg:SI 14))] + "" + "* + return output_call_mem (operands); +" +[(set_attr "length" "12") + (set_attr "type" "call")]) + +(define_expand "call_value" + [(parallel [(set (match_operand 0 "" "=rf") + (call (match_operand 1 "memory_operand" "m") + (match_operand 2 "general_operand" "g"))) + (clobber (reg:SI 14))])] + "" + " +{ + if (TARGET_LONG_CALLS && GET_CODE (XEXP (operands[1], 0)) != REG) + XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0)); +}") + +(define_insn "*call_value_reg" + [(set (match_operand 0 "" "=rf") + (call (mem:SI (match_operand:SI 1 "s_register_operand" "r")) + (match_operand 2 "general_operand" "g"))) + (clobber (reg:SI 14))] + "" + "* + return output_call (&operands[1]); +" +[(set_attr "length" "12") + (set_attr "type" "call")]) + +(define_insn "*call_value_mem" + [(set (match_operand 0 "" "=rf") + (call (mem:SI (match_operand 1 "memory_operand" "m")) + (match_operand 2 "general_operand" "g"))) + (clobber (reg:SI 14))] + "! CONSTANT_ADDRESS_P (XEXP (operands[1], 0))" + "* + return output_call_mem (&operands[1]); +" +[(set_attr "length" "12") + (set_attr "type" "call")]) + +;; Allow calls to SYMBOL_REFs specially as they are not valid general addresses +;; The 'a' causes the operand to be treated as an address, i.e. no '#' output. + +(define_insn "*call_symbol" + [(call (mem:SI (match_operand:SI 0 "" "X")) + (match_operand:SI 1 "general_operand" "g")) + (clobber (reg:SI 14))] + "! TARGET_LONG_CALLS && GET_CODE (operands[0]) == SYMBOL_REF" + "bl%?\\t%a0" +[(set_attr "type" "call")]) + +(define_insn "*call_value_symbol" + [(set (match_operand 0 "s_register_operand" "=rf") + (call (mem:SI (match_operand:SI 1 "" "X")) + (match_operand:SI 2 "general_operand" "g"))) + (clobber (reg:SI 14))] + "! TARGET_LONG_CALLS && GET_CODE(operands[1]) == SYMBOL_REF" + "bl%?\\t%a1" +[(set_attr "type" "call")]) + +;; Often the return insn will be the same as loading from memory, so set attr +(define_insn "return" + [(return)] + "USE_RETURN_INSN (FALSE)" + "* +{ + extern int arm_ccfsm_state; + + if (arm_ccfsm_state == 2) + { + arm_ccfsm_state += 2; + return \"\"; + } + return output_return_instruction (NULL, TRUE, FALSE); +}" +[(set_attr "type" "load")]) + +(define_insn "*cond_return" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand 1 "cc_register" "") (const_int 0)]) + (return) + (pc)))] + "USE_RETURN_INSN (TRUE)" + "* +{ + extern int arm_ccfsm_state; + + if (arm_ccfsm_state == 2) + { + arm_ccfsm_state += 2; + return \"\"; + } + return output_return_instruction (operands[0], TRUE, FALSE); +}" +[(set_attr "conds" "use") + (set_attr "type" "load")]) + +(define_insn "*cond_return_inverted" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand 1 "cc_register" "") (const_int 0)]) + (pc) + (return)))] + "USE_RETURN_INSN (TRUE)" + "* +{ + extern int arm_ccfsm_state; + + if (arm_ccfsm_state == 2) + { + arm_ccfsm_state += 2; + return \"\"; + } + return output_return_instruction (operands[0], TRUE, TRUE); +}" +[(set_attr "conds" "use") + (set_attr "type" "load")]) + +;; Call subroutine returning any type. + +(define_expand "untyped_call" + [(parallel [(call (match_operand 0 "" "") + (const_int 0)) + (match_operand 1 "" "") + (match_operand 2 "" "")])] + "" + " +{ + int i; + + emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx)); + + for (i = 0; i < XVECLEN (operands[2], 0); i++) + { + rtx set = XVECEXP (operands[2], 0, i); + emit_move_insn (SET_DEST (set), SET_SRC (set)); + } + + /* The optimizer does not know that the call sets the function value + registers we stored in the result block. We avoid problems by + claiming that all hard registers are used and clobbered at this + point. */ + emit_insn (gen_blockage ()); + + DONE; +}") + +;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and +;; all of memory. This blocks insns from being moved across this point. + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] 0)] + "" + "" +[(set_attr "length" "0") + (set_attr "type" "block")]) + +(define_expand "casesi" + [(match_operand:SI 0 "s_register_operand" "") ; index to jump on + (match_operand:SI 1 "const_int_operand" "") ; lower bound + (match_operand:SI 2 "const_int_operand" "") ; total range + (match_operand:SI 3 "" "") ; table label + (match_operand:SI 4 "" "")] ; Out of range label + "" + " +{ + rtx reg; + if (operands[1] != const0_rtx) + { + reg = gen_reg_rtx (SImode); + emit_insn (gen_addsi3 (reg, operands[0], + GEN_INT (-INTVAL (operands[1])))); + operands[0] = reg; + } + + if (! const_ok_for_arm (INTVAL (operands[2]))) + operands[2] = force_reg (SImode, operands[2]); + + emit_jump_insn (gen_casesi_internal (operands[0], operands[2], operands[3], + operands[4])); + DONE; +}") + +;; The USE in this pattern is needed to tell flow analysis that this is +;; a CASESI insn. It has no other purpose. +(define_insn "casesi_internal" + [(parallel [(set (pc) + (if_then_else + (leu (match_operand:SI 0 "s_register_operand" "r") + (match_operand:SI 1 "arm_rhs_operand" "rI")) + (mem:SI (plus:SI (mult:SI (match_dup 0) (const_int 4)) + (label_ref (match_operand 2 "" "")))) + (label_ref (match_operand 3 "" "")))) + (use (label_ref (match_dup 2)))])] + "" + "* + if (flag_pic) + return \"cmp\\t%0, %1\;addls\\t%|pc, %|pc, %0, asl #2\;b\\t%l3\"; + return \"cmp\\t%0, %1\;ldrls\\t%|pc, [%|pc, %0, asl #2]\;b\\t%l3\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "indirect_jump" + [(set (pc) + (match_operand:SI 0 "s_register_operand" "r"))] + "" + "mov%?\\t%|pc, %0\\t%@ indirect jump") + +(define_insn "*load_indirect_jump" + [(set (pc) + (match_operand:SI 0 "memory_operand" "m"))] + "" + "ldr%?\\t%|pc, %0\\t%@ indirect jump" +[(set_attr "type" "load")]) + +;; Misc insns + +(define_insn "nop" + [(const_int 0)] + "" + "mov%?\\tr0, r0\\t%@ nop") + +;; Patterns to allow combination of arithmetic, cond code and shifts + +(define_insn "*arith_shiftsi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operator:SI 1 "shiftable_operator" + [(match_operator:SI 3 "shift_operator" + [(match_operand:SI 4 "s_register_operand" "r") + (match_operand:SI 5 "reg_or_int_operand" "rI")]) + (match_operand:SI 2 "s_register_operand" "r")]))] + "" + "%i1%?\\t%0, %2, %4%S3") + +(define_insn "*arith_shiftsi_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (match_operator:SI 1 "shiftable_operator" + [(match_operator:SI 3 "shift_operator" + [(match_operand:SI 4 "s_register_operand" "r") + (match_operand:SI 5 "reg_or_int_operand" "rI")]) + (match_operand:SI 2 "s_register_operand" "r")]) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (match_op_dup 1 [(match_op_dup 3 [(match_dup 4) (match_dup 5)]) + (match_dup 2)]))] + "" + "%i1%?s\\t%0, %2, %4%S3" +[(set_attr "conds" "set")]) + +(define_insn "*arith_shiftsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (match_operator:SI 1 "shiftable_operator" + [(match_operator:SI 3 "shift_operator" + [(match_operand:SI 4 "s_register_operand" "r") + (match_operand:SI 5 "reg_or_int_operand" "rI")]) + (match_operand:SI 2 "s_register_operand" "r")]) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "" + "%i1%?s\\t%0, %2, %4%S3" +[(set_attr "conds" "set")]) + +(define_insn "*sub_shiftsi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "reg_or_int_operand" "rM")])))] + "" + "sub%?\\t%0, %1, %3%S2") + +(define_insn "*sub_shiftsi_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (minus:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "reg_or_int_operand" "rM")])) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) + (match_dup 4)])))] + "" + "sub%?s\\t%0, %1, %3%S2" +[(set_attr "conds" "set")]) + +(define_insn "*sub_shiftsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (minus:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "reg_or_int_operand" "rM")])) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "" + "sub%?s\\t%0, %1, %3%S2" +[(set_attr "conds" "set")]) + +;; These variants of the above insns can occur if the first operand is the +;; frame pointer and we eliminate that. This is a kludge, but there doesn't +;; seem to be a way around it. Most of the predicates have to be null +;; because the format can be generated part way through reload, so +;; if we don't match it as soon as it becomes available, reload doesn't know +;; how to reload pseudos that haven't got hard registers; the constraints will +;; sort everything out. + +(define_insn "*reload_mulsi3" + [(set (match_operand:SI 0 "" "=&r") + (plus:SI (plus:SI (match_operator:SI 5 "shift_operator" + [(match_operand:SI 3 "" "r") + (match_operand:SI 4 "" "rM")]) + (match_operand:SI 2 "" "r")) + (match_operand:SI 1 "const_int_operand" "n")))] + "reload_in_progress" + "* + output_asm_insn (\"add%?\\t%0, %2, %3%S5\", operands); + operands[2] = operands[1]; + operands[1] = operands[0]; + return output_add_immediate (operands); +" +; we have no idea how long the add_immediate is, it could be up to 4. +[(set_attr "length" "20")]) + +(define_insn "*reload_mulsi_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (plus:SI + (plus:SI + (match_operator:SI 5 "shift_operator" + [(match_operand:SI 3 "" "r") + (match_operand:SI 4 "" "rM")]) + (match_operand:SI 1 "" "r")) + (match_operand:SI 2 "const_int_operand" "n")) + (const_int 0))) + (set (match_operand:SI 0 "" "=&r") + (plus:SI (plus:SI (match_op_dup 5 [(match_dup 3) (match_dup 4)]) + (match_dup 1)) + (match_dup 2)))] + "reload_in_progress" + "* + output_add_immediate (operands); + return \"add%?s\\t%0, %0, %3%S5\"; +" +[(set_attr "conds" "set") + (set_attr "length" "20")]) + +(define_insn "*reload_mulsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (plus:SI + (plus:SI + (match_operator:SI 5 "shift_operator" + [(match_operand:SI 3 "" "r") + (match_operand:SI 4 "" "rM")]) + (match_operand:SI 1 "" "r")) + (match_operand:SI 2 "const_int_operand" "n")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=&r"))] + "reload_in_progress" + "* + output_add_immediate (operands); + return \"add%?s\\t%0, %0, %3%S5\"; +" +[(set_attr "conds" "set") + (set_attr "length" "20")]) + +;; These are similar, but are needed when the mla pattern contains the +;; eliminated register as operand 3. + +(define_insn "*reload_muladdsi" + [(set (match_operand:SI 0 "" "=&r,&r") + (plus:SI (plus:SI (mult:SI (match_operand:SI 1 "" "%0,r") + (match_operand:SI 2 "" "r,r")) + (match_operand:SI 3 "" "r,r")) + (match_operand:SI 4 "const_int_operand" "n,n")))] + "reload_in_progress" + "* + output_asm_insn (\"mla%?\\t%0, %2, %1, %3\", operands); + operands[2] = operands[4]; + operands[1] = operands[0]; + return output_add_immediate (operands); +" +[(set_attr "length" "20") + (set_attr "type" "mult")]) + +(define_insn "*reload_muladdsi_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (plus:SI (plus:SI (mult:SI + (match_operand:SI 3 "" "r") + (match_operand:SI 4 "" "r")) + (match_operand:SI 1 "" "r")) + (match_operand:SI 2 "const_int_operand" "n")) + (const_int 0))) + (set (match_operand:SI 0 "" "=&r") + (plus:SI (plus:SI (mult:SI (match_dup 3) (match_dup 4)) (match_dup 1)) + (match_dup 2)))] + "reload_in_progress" + "* + output_add_immediate (operands); + output_asm_insn (\"mla%?s\\t%0, %3, %4, %0\", operands); + return \"\"; +" +[(set_attr "length" "20") + (set_attr "conds" "set") + (set_attr "type" "mult")]) + +(define_insn "*reload_muladdsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (plus:SI (plus:SI (mult:SI + (match_operand:SI 3 "" "r") + (match_operand:SI 4 "" "r")) + (match_operand:SI 1 "" "r")) + (match_operand:SI 2 "const_int_operand" "n")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=&r"))] + "reload_in_progress" + "* + output_add_immediate (operands); + return \"mla%?s\\t%0, %3, %4, %0\"; +" +[(set_attr "length" "20") + (set_attr "conds" "set") + (set_attr "type" "mult")]) + + + +(define_insn "*and_scc" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (and:SI (match_operator 1 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (match_operand:SI 2 "s_register_operand" "r")))] + "" + "mov%D1\\t%0, #0\;and%d1\\t%0, %2, #1" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + +(define_insn "*ior_scc" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (ior:SI (match_operator 2 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "s_register_operand" "0,?r")))] + "" + "@ + orr%d2\\t%0, %1, #1 + mov%D2\\t%0, %1\;orr%d2\\t%0, %1, #1" +[(set_attr "conds" "use") + (set_attr "length" "4,8")]) + +(define_insn "*compare_scc" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (match_operator 1 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_add_operand" "rI,L")])) + (clobber (reg:CC 24))] + "" + "* + if (GET_CODE (operands[1]) == LT && operands[3] == const0_rtx) + return \"mov\\t%0, %2, lsr #31\"; + + if (GET_CODE (operands[1]) == GE && operands[3] == const0_rtx) + return \"mvn\\t%0, %2\;mov\\t%0, %0, lsr #31\"; + + if (GET_CODE (operands[1]) == NE) + { + if (which_alternative == 1) + return \"adds\\t%0, %2, #%n3\;movne\\t%0, #1\"; + return \"subs\\t%0, %2, %3\;movne\\t%0, #1\"; + } + if (which_alternative == 1) + output_asm_insn (\"cmn\\t%2, #%n3\", operands); + else + output_asm_insn (\"cmp\\t%2, %3\", operands); + return \"mov%D1\\t%0, #0\;mov%d1\\t%0, #1\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "*cond_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI (match_operator 3 "equality_operator" + [(match_operator 4 "comparison_operator" + [(match_operand 5 "cc_register" "") (const_int 0)]) + (const_int 0)]) + (match_operand:SI 1 "arm_rhs_operand" "0,rI,?rI") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))] + "" + "* + if (GET_CODE (operands[3]) == NE) + { + if (which_alternative != 1) + output_asm_insn (\"mov%D4\\t%0, %2\", operands); + if (which_alternative != 0) + output_asm_insn (\"mov%d4\\t%0, %1\", operands); + return \"\"; + } + if (which_alternative != 0) + output_asm_insn (\"mov%D4\\t%0, %1\", operands); + if (which_alternative != 1) + output_asm_insn (\"mov%d4\\t%0, %2\", operands); + return \"\"; +" +[(set_attr "conds" "use") + (set_attr "length" "4,4,8")]) + +(define_insn "*cond_arith" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (match_operator:SI 5 "shiftable_operator" + [(match_operator:SI 4 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_rhs_operand" "rI,rI")]) + (match_operand:SI 1 "s_register_operand" "0,?r")])) + (clobber (reg:CC 24))] + "" + "* + if (GET_CODE (operands[4]) == LT && operands[3] == const0_rtx) + return \"%i5\\t%0, %1, %2, lsr #31\"; + + output_asm_insn (\"cmp\\t%2, %3\", operands); + if (GET_CODE (operands[5]) == AND) + output_asm_insn (\"mov%D4\\t%0, #0\", operands); + else if (GET_CODE (operands[5]) == MINUS) + output_asm_insn (\"rsb%D4\\t%0, %1, #0\", operands); + else if (which_alternative != 0) + output_asm_insn (\"mov%D4\\t%0, %1\", operands); + return \"%i5%d4\\t%0, %1, #1\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "*cond_sub" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (minus:SI (match_operand:SI 1 "s_register_operand" "0,?r") + (match_operator:SI 4 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_rhs_operand" "rI,rI")]))) + (clobber (reg:CC 24))] + "" + "* + output_asm_insn (\"cmp\\t%2, %3\", operands); + if (which_alternative != 0) + output_asm_insn (\"mov%D4\\t%0, %1\", operands); + return \"sub%d4\\t%0, %1, #1\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*cmp_ite0" + [(set (match_operand 6 "dominant_cc_register" "") + (compare + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand:SI 0 "s_register_operand" "r,r,r,r") + (match_operand:SI 1 "arm_add_operand" "rI,L,rI,L")]) + (match_operator:SI 5 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "r,r,r,r") + (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")]) + (const_int 0)) + (const_int 0)))] + "" + "* +{ + char* opcodes[4][2] = + { + {\"cmp\\t%2, %3\;cmp%d5\\t%0, %1\",\"cmp\\t%0, %1\;cmp%d4\\t%2, %3\"}, + {\"cmp\\t%2, %3\;cmn%d5\\t%0, #%n1\", \"cmn\\t%0, #%n1\;cmp%d4\\t%2, %3\"}, + {\"cmn\\t%2, #%n3\;cmp%d5\\t%0, %1\", \"cmp\\t%0, %1\;cmn%d4\\t%2, #%n3\"}, + {\"cmn\\t%2, #%n3\;cmn%d5\\t%0, #%n1\", + \"cmn\\t%0, #%n1\;cmn%d4\\t%2, #%n3\"} + }; + int swap = + comparison_dominates_p (GET_CODE (operands[5]), GET_CODE (operands[4])); + + return opcodes[which_alternative][swap]; +} +" +[(set_attr "conds" "set") + (set_attr "length" "8")]) + +(define_insn "*cmp_ite1" + [(set (match_operand 6 "dominant_cc_register" "") + (compare + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand:SI 0 "s_register_operand" "r,r,r,r") + (match_operand:SI 1 "arm_add_operand" "rI,L,rI,L")]) + (match_operator:SI 5 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "r,r,r,r") + (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")]) + (const_int 1)) + (const_int 0)))] + "" + "* +{ + char* opcodes[4][2] = + { + {\"cmp\\t%0, %1\;cmp%d4\\t%2, %3\", \"cmp\\t%2, %3\;cmp%D5\\t%0, %1\"}, + {\"cmn\\t%0, #%n1\;cmp%d4\\t%2, %3\", \"cmp\\t%2, %3\;cmn%D5\\t%0, #%n1\"}, + {\"cmp\\t%0, %1\;cmn%d4\\t%2, #%n3\", \"cmn\\t%2, #%n3\;cmp%D5\\t%0, %1\"}, + {\"cmn\\t%0, #%n1\;cmn%d4\\t%2, #%n3\", + \"cmn\\t%2, #%n3\;cmn%D5\\t%0, #%n1\"} + }; + int swap = + comparison_dominates_p (GET_CODE (operands[5]), + reverse_condition (GET_CODE (operands[4]))); + + return opcodes[which_alternative][swap]; +} +" +[(set_attr "conds" "set") + (set_attr "length" "8")]) + +(define_insn "*negscc" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (neg:SI (match_operator 3 "comparison_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rI")]))) + (clobber (reg:CC 24))] + "" + "* + if (GET_CODE (operands[3]) == LT && operands[3] == const0_rtx) + return \"mov\\t%0, %1, asr #31\"; + + if (GET_CODE (operands[3]) == NE) + return \"subs\\t%0, %1, %2\;mvnne\\t%0, #0\"; + + if (GET_CODE (operands[3]) == GT) + return \"subs\\t%0, %1, %2\;mvnne\\t%0, %0, asr #31\"; + + output_asm_insn (\"cmp\\t%1, %2\", operands); + output_asm_insn (\"mov%D3\\t%0, #0\", operands); + return \"mvn%d3\\t%0, #0\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "movcond" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand:SI 3 "s_register_operand" "r,r,r") + (match_operand:SI 4 "arm_add_operand" "rIL,rIL,rIL")]) + (match_operand:SI 1 "arm_rhs_operand" "0,rI,?rI") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) + (clobber (reg:CC 24))] + "" + "* + if (GET_CODE (operands[5]) == LT + && (operands[4] == const0_rtx)) + { + if (which_alternative != 1 && GET_CODE (operands[1]) == REG) + { + if (operands[2] == const0_rtx) + return \"and\\t%0, %1, %3, asr #31\"; + return \"ands\\t%0, %1, %3, asr #32\;movcc\\t%0, %2\"; + } + else if (which_alternative != 0 && GET_CODE (operands[2]) == REG) + { + if (operands[1] == const0_rtx) + return \"bic\\t%0, %2, %3, asr #31\"; + return \"bics\\t%0, %2, %3, asr #32\;movcs\\t%0, %1\"; + } + /* The only case that falls through to here is when both ops 1 & 2 + are constants */ + } + + if (GET_CODE (operands[5]) == GE + && (operands[4] == const0_rtx)) + { + if (which_alternative != 1 && GET_CODE (operands[1]) == REG) + { + if (operands[2] == const0_rtx) + return \"bic\\t%0, %1, %3, asr #31\"; + return \"bics\\t%0, %1, %3, asr #32\;movcs\\t%0, %2\"; + } + else if (which_alternative != 0 && GET_CODE (operands[2]) == REG) + { + if (operands[1] == const0_rtx) + return \"and\\t%0, %2, %3, asr #31\"; + return \"ands\\t%0, %2, %3, asr #32\;movcc\\t%0, %1\"; + } + /* The only case that falls through to here is when both ops 1 & 2 + are constants */ + } + if (GET_CODE (operands[4]) == CONST_INT + && !const_ok_for_arm (INTVAL (operands[4]))) + output_asm_insn (\"cmn\\t%3, #%n4\", operands); + else + output_asm_insn (\"cmp\\t%3, %4\", operands); + if (which_alternative != 0) + output_asm_insn (\"mov%d5\\t%0, %1\", operands); + if (which_alternative != 1) + output_asm_insn (\"mov%D5\\t%0, %2\", operands); + return \"\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "8,8,12")]) + +(define_insn "*ifcompare_plus_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI (match_operator 6 "comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r,r") + (match_operand:SI 5 "arm_add_operand" "rIL,rIL")]) + (plus:SI + (match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_add_operand" "rIL,rIL")) + (match_operand:SI 1 "arm_rhsm_operand" "0,?rIm"))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_plus_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r,r,r") + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand 5 "cc_register" "") (const_int 0)]) + (plus:SI + (match_operand:SI 2 "s_register_operand" "r,r,r,r,r,r") + (match_operand:SI 3 "arm_add_operand" "rI,L,rI,L,rI,L")) + (match_operand:SI 1 "arm_rhsm_operand" "0,0,?rI,?rI,m,m")))] + "" + "@ + add%d4\\t%0, %2, %3 + sub%d4\\t%0, %2, #%n3 + add%d4\\t%0, %2, %3\;mov%D4\\t%0, %1 + sub%d4\\t%0, %2, #%n3\;mov%D4\\t%0, %1 + add%d4\\t%0, %2, %3\;ldr%D4\\t%0, %1 + sub%d4\\t%0, %2, #%n3\;ldr%D4\\t%0, %1" +[(set_attr "conds" "use") + (set_attr "length" "4,4,8,8,8,8") + (set_attr "type" "*,*,*,*,load,load")]) + +(define_insn "*ifcompare_move_plus" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI (match_operator 6 "comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r,r") + (match_operand:SI 5 "arm_add_operand" "rIL,rIL")]) + (match_operand:SI 1 "arm_rhsm_operand" "0,?rIm") + (plus:SI + (match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_add_operand" "rIL,rIL")))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_move_plus" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r,r,r") + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand 5 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_rhsm_operand" "0,0,?rI,?rI,m,m") + (plus:SI + (match_operand:SI 2 "s_register_operand" "r,r,r,r,r,r") + (match_operand:SI 3 "arm_add_operand" "rI,L,rI,L,rI,L"))))] + "" + "@ + add%D4\\t%0, %2, %3 + sub%D4\\t%0, %2, #%n3 + add%D4\\t%0, %2, %3\;mov%d4\\t%0, %1 + sub%D4\\t%0, %2, #%n3\;mov%d4\\t%0, %1 + add%D4\\t%0, %2, %3\;ldr%d4\\t%0, %1 + sub%D4\\t%0, %2, #%n3\;ldr%d4\\t%0, %1" +[(set_attr "conds" "use") + (set_attr "length" "4,4,8,8,8,8") + (set_attr "type" "*,*,*,*,load,load")]) + +(define_insn "*ifcompare_arith_arith" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI (match_operator 9 "comparison_operator" + [(match_operand:SI 5 "s_register_operand" "r") + (match_operand:SI 6 "arm_add_operand" "rIL")]) + (match_operator:SI 8 "shiftable_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rI")]) + (match_operator:SI 7 "shiftable_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "arm_rhs_operand" "rI")]))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "*if_arith_arith" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI (match_operator 5 "comparison_operator" + [(match_operand 8 "cc_register" "") (const_int 0)]) + (match_operator:SI 6 "shiftable_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rI")]) + (match_operator:SI 7 "shiftable_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "arm_rhs_operand" "rI")])))] + "" + "%I6%d5\\t%0, %1, %2\;%I7%D5\\t%0, %3, %4" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + +(define_insn "*ifcompare_arith_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI (match_operator 6 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_add_operand" "rIL,rIL")]) + (match_operator:SI 7 "shiftable_operator" + [(match_operand:SI 4 "s_register_operand" "r,r") + (match_operand:SI 5 "arm_rhs_operand" "rI,rI")]) + (match_operand:SI 1 "arm_rhsm_operand" "0,?rIm"))) + (clobber (reg:CC 24))] + "" + "* + /* If we have an operation where (op x 0) is the identity operation and + the conditional operator is LT or GE and we are comparing against zero and + everything is in registers then we can do this in two instructions */ + if (operands[3] == const0_rtx + && GET_CODE (operands[7]) != AND + && GET_CODE (operands[5]) == REG + && GET_CODE (operands[1]) == REG + && REGNO (operands[1]) == REGNO (operands[4]) + && REGNO (operands[4]) != REGNO (operands[0])) + { + if (GET_CODE (operands[6]) == LT) + return \"and\\t%0, %5, %2, asr #31\;%I7\\t%0, %4, %0\"; + else if (GET_CODE (operands[6]) == GE) + return \"bic\\t%0, %5, %2, asr #31\;%I7\\t%0, %4, %0\"; + } + if (GET_CODE (operands[3]) == CONST_INT + && !const_ok_for_arm (INTVAL (operands[3]))) + output_asm_insn (\"cmn\\t%2, #%n3\", operands); + else + output_asm_insn (\"cmp\\t%2, %3\", operands); + output_asm_insn (\"%I7%d6\\t%0, %4, %5\", operands); + if (which_alternative != 0) + { + if (GET_CODE (operands[1]) == MEM) + return \"ldr%D6\\t%0, %1\"; + else + return \"mov%D6\\t%0, %1\"; + } + return \"\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_arith_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI (match_operator 4 "comparison_operator" + [(match_operand 6 "cc_register" "") (const_int 0)]) + (match_operator:SI 5 "shiftable_operator" + [(match_operand:SI 2 "s_register_operand" "r,r,r") + (match_operand:SI 3 "arm_rhs_operand" "rI,rI,rI")]) + (match_operand:SI 1 "arm_rhsm_operand" "0,?rI,m")))] + "" + "@ + %I5%d4\\t%0, %2, %3 + %I5%d4\\t%0, %2, %3\;mov%D4\\t%0, %1 + %I5%d4\\t%0, %2, %3\;ldr%D4\\t%0, %1" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8") + (set_attr "type" "*,*,load")]) + +(define_insn "*ifcompare_move_arith" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI (match_operator 6 "comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r,r") + (match_operand:SI 5 "arm_add_operand" "rIL,rIL")]) + (match_operand:SI 1 "arm_rhsm_operand" "0,?rIm") + (match_operator:SI 7 "shiftable_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_rhs_operand" "rI,rI")]))) + (clobber (reg:CC 24))] + "" + "* + /* If we have an operation where (op x 0) is the identity operation and + the conditional operator is LT or GE and we are comparing against zero and + everything is in registers then we can do this in two instructions */ + if (operands[5] == const0_rtx + && GET_CODE (operands[7]) != AND + && GET_CODE (operands[3]) == REG + && GET_CODE (operands[1]) == REG + && REGNO (operands[1]) == REGNO (operands[2]) + && REGNO (operands[2]) != REGNO (operands[0])) + { + if (GET_CODE (operands[6]) == GE) + return \"and\\t%0, %3, %4, asr #31\;%I7\\t%0, %2, %0\"; + else if (GET_CODE (operands[6]) == LT) + return \"bic\\t%0, %3, %4, asr #31\;%I7\\t%0, %2, %0\"; + } + + if (GET_CODE (operands[5]) == CONST_INT + && !const_ok_for_arm (INTVAL (operands[5]))) + output_asm_insn (\"cmn\\t%4, #%n5\", operands); + else + output_asm_insn (\"cmp\\t%4, %5\", operands); + + if (which_alternative != 0) + { + if (GET_CODE (operands[1]) == MEM) + output_asm_insn (\"ldr%d6\\t%0, %1\", operands); + else + output_asm_insn (\"mov%d6\\t%0, %1\", operands); + } + return \"%I7%D6\\t%0, %2, %3\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_move_arith" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand 6 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_rhsm_operand" "0,?rI,m") + (match_operator:SI 5 "shiftable_operator" + [(match_operand:SI 2 "s_register_operand" "r,r,r") + (match_operand:SI 3 "arm_rhs_operand" "rI,rI,rI")])))] + "" + "@ + %I5%D4\\t%0, %2, %3 + %I5%D4\\t%0, %2, %3\;mov%d4\\t%0, %1 + %I5%D4\\t%0, %2, %3\;ldr%d4\\t%0, %1" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8") + (set_attr "type" "*,*,load")]) + +(define_insn "*ifcompare_move_not" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand:SI 3 "s_register_operand" "r,r") + (match_operand:SI 4 "arm_add_operand" "rIL,rIL")]) + (match_operand:SI 1 "arm_not_operand" "0,?rIK") + (not:SI + (match_operand:SI 2 "s_register_operand" "r,r")))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_move_not" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_not_operand" "0,?rI,K") + (not:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))))] + "" + "@ + mvn%D4\\t%0, %2 + mov%d4\\t%0, %1\;mvn%D4\\t%0, %2 + mvn%d4\\t%0, #%B1\;mvn%D4\\t%0, %2" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8")]) + +(define_insn "*ifcompare_not_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand:SI 3 "s_register_operand" "r,r") + (match_operand:SI 4 "arm_add_operand" "rIL,rIL")]) + (not:SI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:SI 1 "arm_not_operand" "0,?rIK"))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_not_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (not:SI (match_operand:SI 2 "s_register_operand" "r,r,r")) + (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))] + "" + "@ + mvn%d4\\t%0, %2 + mov%D4\\t%0, %1\;mvn%d4\\t%0, %2 + mvn%D4\\t%0, #%B1\;mvn%d4\\t%0, %2" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8")]) + +(define_insn "*ifcompare_shift_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI + (match_operator 6 "comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r,r") + (match_operand:SI 5 "arm_add_operand" "rIL,rIL")]) + (match_operator:SI 7 "shift_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_rhs_operand" "rM,rM")]) + (match_operand:SI 1 "arm_not_operand" "0,?rIK"))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_shift_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand 6 "cc_register" "") (const_int 0)]) + (match_operator:SI 4 "shift_operator" + [(match_operand:SI 2 "s_register_operand" "r,r,r") + (match_operand:SI 3 "arm_rhs_operand" "rM,rM,rM")]) + (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))] + "" + "@ + mov%d5\\t%0, %2%S4 + mov%D5\\t%0, %1\;mov%d5\\t%0, %2%S4 + mvn%D5\\t%0, #%B1\;mov%d5\\t%0, %2%S4" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8")]) + +(define_insn "*ifcompare_move_shift" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI + (match_operator 6 "comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r,r") + (match_operand:SI 5 "arm_add_operand" "rIL,rIL")]) + (match_operand:SI 1 "arm_not_operand" "0,?rIK") + (match_operator:SI 7 "shift_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_rhs_operand" "rM,rM")]))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_move_shift" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand 6 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_not_operand" "0,?rI,K") + (match_operator:SI 4 "shift_operator" + [(match_operand:SI 2 "s_register_operand" "r,r,r") + (match_operand:SI 3 "arm_rhs_operand" "rM,rM,rM")])))] + "" + "@ + mov%D5\\t%0, %2%S4 + mov%d5\\t%0, %1\;mov%D5\\t%0, %2%S4 + mvn%d5\\t%0, #%B1\;mov%D5\\t%0, %2%S4" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8")]) + +(define_insn "*ifcompare_shift_shift" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI + (match_operator 7 "comparison_operator" + [(match_operand:SI 5 "s_register_operand" "r") + (match_operand:SI 6 "arm_add_operand" "rIL")]) + (match_operator:SI 8 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")]) + (match_operator:SI 9 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "arm_rhs_operand" "rM")]))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "*if_shift_shift" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand 8 "cc_register" "") (const_int 0)]) + (match_operator:SI 6 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")]) + (match_operator:SI 7 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "arm_rhs_operand" "rM")])))] + "" + "mov%d5\\t%0, %1%S6\;mov%D5\\t%0, %3%S7" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + +(define_insn "*ifcompare_not_arith" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI + (match_operator 6 "comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r") + (match_operand:SI 5 "arm_add_operand" "rIL")]) + (not:SI (match_operand:SI 1 "s_register_operand" "r")) + (match_operator:SI 7 "shiftable_operator" + [(match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 3 "arm_rhs_operand" "rI")]))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "*if_not_arith" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand 4 "cc_register" "") (const_int 0)]) + (not:SI (match_operand:SI 1 "s_register_operand" "r")) + (match_operator:SI 6 "shiftable_operator" + [(match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 3 "arm_rhs_operand" "rI")])))] + "" + "mvn%d5\\t%0, %1\;%I6%D5\\t%0, %2, %3" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + +(define_insn "*ifcompare_arith_not" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI + (match_operator 6 "comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r") + (match_operand:SI 5 "arm_add_operand" "rIL")]) + (match_operator:SI 7 "shiftable_operator" + [(match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 3 "arm_rhs_operand" "rI")]) + (not:SI (match_operand:SI 1 "s_register_operand" "r")))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "*if_arith_not" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand 4 "cc_register" "") (const_int 0)]) + (match_operator:SI 6 "shiftable_operator" + [(match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 3 "arm_rhs_operand" "rI")]) + (not:SI (match_operand:SI 1 "s_register_operand" "r"))))] + "" + "mvn%D5\\t%0, %1\;%I6%d5\\t%0, %2, %3" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + +(define_insn "*ifcompare_neg_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand:SI 3 "s_register_operand" "r,r") + (match_operand:SI 4 "arm_add_operand" "rIL,rIL")]) + (neg:SI (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:SI 1 "arm_not_operand" "0,?rIK"))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_neg_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (neg:SI (match_operand:SI 2 "s_register_operand" "r,r,r")) + (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))] + "" + "@ + rsb%d4\\t%0, %2, #0 + mov%D4\\t%0, %1\;rsb%d4\\t%0, %2, #0 + mvn%D4\\t%0, #%B1\;rsb%d4\\t%0, %2, #0" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8")]) + +(define_insn "*ifcompare_move_neg" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand:SI 3 "s_register_operand" "r,r") + (match_operand:SI 4 "arm_add_operand" "rIL,rIL")]) + (match_operand:SI 1 "arm_not_operand" "0,?rIK") + (neg:SI (match_operand:SI 2 "s_register_operand" "r,r")))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_move_neg" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_not_operand" "0,?rI,K") + (neg:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))))] + "" + "@ + rsb%D4\\t%0, %2, #0 + mov%d4\\t%0, %1\;rsb%D4\\t%0, %2, #0 + mvn%d4\\t%0, #%B1\;rsb%D4\\t%0, %2, #0" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8")]) + +(define_insn "*arith_adjacentmem" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operator:SI 1 "shiftable_operator" + [(match_operand:SI 2 "memory_operand" "m") + (match_operand:SI 3 "memory_operand" "m")])) + (clobber (match_scratch:SI 4 "=r"))] + "adjacent_mem_locations (operands[2], operands[3])" + "* +{ + rtx ldm[3]; + rtx arith[4]; + int val1 = 0, val2 = 0; + + if (REGNO (operands[0]) > REGNO (operands[4])) + { + ldm[1] = operands[4]; + ldm[2] = operands[0]; + } + else + { + ldm[1] = operands[0]; + ldm[2] = operands[4]; + } + if (GET_CODE (XEXP (operands[2], 0)) != REG) + val1 = INTVAL (XEXP (XEXP (operands[2], 0), 1)); + if (GET_CODE (XEXP (operands[3], 0)) != REG) + val2 = INTVAL (XEXP (XEXP (operands[3], 0), 1)); + arith[0] = operands[0]; + arith[3] = operands[1]; + if (val1 < val2) + { + arith[1] = ldm[1]; + arith[2] = ldm[2]; + } + else + { + arith[1] = ldm[2]; + arith[2] = ldm[1]; + } + if (val1 && val2) + { + rtx ops[3]; + ldm[0] = ops[0] = operands[4]; + ops[1] = XEXP (XEXP (operands[2], 0), 0); + ops[2] = XEXP (XEXP (operands[2], 0), 1); + output_add_immediate (ops); + if (val1 < val2) + output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm); + else + output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm); + } + else if (val1) + { + ldm[0] = XEXP (operands[3], 0); + if (val1 < val2) + output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm); + else + output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm); + } + else + { + ldm[0] = XEXP (operands[2], 0); + if (val1 < val2) + output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm); + else + output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm); + } + output_asm_insn (\"%I3%?\\t%0, %1, %2\", arith); + return \"\"; +} +" +[(set_attr "length" "12") + (set_attr "type" "load")]) + +;; the arm can support extended pre-inc instructions + +;; In all these cases, we use operands 0 and 1 for the register being +;; incremented because those are the operands that local-alloc will +;; tie and these are the pair most likely to be tieable (and the ones +;; that will benefit the most). + +;; We reject the frame pointer if it occurs anywhere in these patterns since +;; elimination will cause too many headaches. + +(define_insn "*strqi_preinc" + [(set (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "index_operand" "rJ"))) + (match_operand:QI 3 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "str%?b\\t%3, [%0, %2]!" +[(set_attr "type" "store1")]) + +(define_insn "*strqi_predec" + [(set (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "r"))) + (match_operand:QI 3 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "str%?b\\t%3, [%0, -%2]!" +[(set_attr "type" "store1")]) + +(define_insn "*loadqi_preinc" + [(set (match_operand:QI 3 "s_register_operand" "=r") + (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "index_operand" "rJ")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?b\\t%3, [%0, %2]!" +[(set_attr "type" "load")]) + +(define_insn "*loadqi_predec" + [(set (match_operand:QI 3 "s_register_operand" "=r") + (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "r")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?b\\t%3, [%0, -%2]!" +[(set_attr "type" "load")]) + +(define_insn "*loadqisi_preinc" + [(set (match_operand:SI 3 "s_register_operand" "=r") + (zero_extend:SI + (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "index_operand" "rJ"))))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?b\\t%3, [%0, %2]!\\t%@ z_extendqisi" +[(set_attr "type" "load")]) + +(define_insn "*loadqisi_predec" + [(set (match_operand:SI 3 "s_register_operand" "=r") + (zero_extend:SI + (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "r"))))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?b\\t%3, [%0, -%2]!\\t%@ z_extendqisi" +[(set_attr "type" "load")]) + +(define_insn "*strsi_preinc" + [(set (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "index_operand" "rJ"))) + (match_operand:SI 3 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "str%?\\t%3, [%0, %2]!" +[(set_attr "type" "store1")]) + +(define_insn "*strqi_predec" + [(set (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "r"))) + (match_operand:SI 3 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "str%?\\t%3, [%0, -%2]!" +[(set_attr "type" "store1")]) + +(define_insn "*loadsi_preinc" + [(set (match_operand:SI 3 "s_register_operand" "=r") + (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "index_operand" "rJ")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?\\t%3, [%0, %2]!" +[(set_attr "type" "load")]) + +(define_insn "*loadsi_predec" + [(set (match_operand:SI 3 "s_register_operand" "=r") + (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "r")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?\\t%3, [%0, -%2]!" +[(set_attr "type" "load")]) + +(define_insn "*loadhi_preinc" + [(set (match_operand:HI 3 "s_register_operand" "=r") + (mem:HI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "index_operand" "rJ")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_dup 1) (match_dup 2)))] + "(! BYTES_BIG_ENDIAN) + && ! TARGET_SHORT_BY_BYTES + && REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?\\t%3, [%0, %2]!\\t%@ loadhi" +[(set_attr "type" "load")]) + +(define_insn "*loadhi_predec" + [(set (match_operand:HI 3 "s_register_operand" "=r") + (mem:HI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "r")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_dup 2)))] + "(!BYTES_BIG_ENDIAN) + && ! TARGET_SHORT_BY_BYTES + && REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?\\t%3, [%0, -%2]!\\t%@ loadhi" +[(set_attr "type" "load")]) + +(define_insn "*strqi_shiftpreinc" + [(set (mem:QI (plus:SI (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")]) + (match_operand:SI 1 "s_register_operand" "0"))) + (match_operand:QI 5 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) + (match_dup 1)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "str%?b\\t%5, [%0, %3%S2]!" +[(set_attr "type" "store1")]) + +(define_insn "*strqi_shiftpredec" + [(set (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")]))) + (match_operand:QI 5 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) + (match_dup 4)])))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "str%?b\\t%5, [%0, -%3%S2]!" +[(set_attr "type" "store1")]) + +(define_insn "*loadqi_shiftpreinc" + [(set (match_operand:QI 5 "s_register_operand" "=r") + (mem:QI (plus:SI (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")]) + (match_operand:SI 1 "s_register_operand" "0")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) + (match_dup 1)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "ldr%?b\\t%5, [%0, %3%S2]!" +[(set_attr "type" "load")]) + +(define_insn "*loadqi_shiftpredec" + [(set (match_operand:QI 5 "s_register_operand" "=r") + (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")])))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) + (match_dup 4)])))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "ldr%?b\\t%5, [%0, -%3%S2]!" +[(set_attr "type" "load")]) + +(define_insn "*strsi_shiftpreinc" + [(set (mem:SI (plus:SI (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")]) + (match_operand:SI 1 "s_register_operand" "0"))) + (match_operand:SI 5 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) + (match_dup 1)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "str%?\\t%5, [%0, %3%S2]!" +[(set_attr "type" "store1")]) + +(define_insn "*strsi_shiftpredec" + [(set (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")]))) + (match_operand:SI 5 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) + (match_dup 4)])))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "str%?\\t%5, [%0, -%3%S2]!" +[(set_attr "type" "store1")]) + +(define_insn "*loadqi_shiftpreinc" + [(set (match_operand:SI 5 "s_register_operand" "=r") + (mem:SI (plus:SI (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")]) + (match_operand:SI 1 "s_register_operand" "0")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) + (match_dup 1)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "ldr%?\\t%5, [%0, %3%S2]!" +[(set_attr "type" "load")]) + +(define_insn "*loadqi_shiftpredec" + [(set (match_operand:SI 5 "s_register_operand" "=r") + (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")])))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) + (match_dup 4)])))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "ldr%?\\t%5, [%0, -%3%S2]!" +[(set_attr "type" "load")]) + +(define_insn "*loadhi_shiftpreinc" + [(set (match_operand:HI 5 "s_register_operand" "=r") + (mem:HI (plus:SI (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")]) + (match_operand:SI 1 "s_register_operand" "0")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) + (match_dup 1)))] + "(! BYTES_BIG_ENDIAN) + && ! TARGET_SHORT_BY_BYTES + && REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "ldr%?\\t%5, [%0, %3%S2]!\\t%@ loadhi" +[(set_attr "type" "load")]) + +(define_insn "*loadhi_shiftpredec" + [(set (match_operand:HI 5 "s_register_operand" "=r") + (mem:HI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")])))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) + (match_dup 4)])))] + "(! BYTES_BIG_ENDIAN) + && ! TARGET_SHORT_BY_BYTES + && REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "ldr%?\\t%5, [%0, -%3%S2]!\\t%@ loadhi" +[(set_attr "type" "load")]) + +; It can also support extended post-inc expressions, but combine doesn't +; try these.... +; It doesn't seem worth adding peepholes for anything but the most common +; cases since, unlike combine, the increment must immediately follow the load +; for this pattern to match. +; When loading we must watch to see that the base register isn't trampled by +; the load. In such cases this isn't a post-inc expression. + +(define_peephole + [(set (mem:QI (match_operand:SI 0 "s_register_operand" "+r")) + (match_operand:QI 2 "s_register_operand" "r")) + (set (match_dup 0) + (plus:SI (match_dup 0) (match_operand:SI 1 "index_operand" "rJ")))] + "" + "str%?b\\t%2, [%0], %1") + +(define_peephole + [(set (match_operand:QI 0 "s_register_operand" "=r") + (mem:QI (match_operand:SI 1 "s_register_operand" "+r"))) + (set (match_dup 1) + (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))] + "REGNO(operands[0]) != REGNO(operands[1]) + && (GET_CODE (operands[2]) != REG + || REGNO(operands[0]) != REGNO (operands[2]))" + "ldr%?b\\t%0, [%1], %2") + +(define_peephole + [(set (mem:SI (match_operand:SI 0 "s_register_operand" "+r")) + (match_operand:SI 2 "s_register_operand" "r")) + (set (match_dup 0) + (plus:SI (match_dup 0) (match_operand:SI 1 "index_operand" "rJ")))] + "" + "str%?\\t%2, [%0], %1") + +(define_peephole + [(set (match_operand:HI 0 "s_register_operand" "=r") + (mem:HI (match_operand:SI 1 "s_register_operand" "+r"))) + (set (match_dup 1) + (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))] + "(! BYTES_BIG_ENDIAN) + && ! TARGET_SHORT_BY_BYTES + && REGNO(operands[0]) != REGNO(operands[1]) + && (GET_CODE (operands[2]) != REG + || REGNO(operands[0]) != REGNO (operands[2]))" + "ldr%?\\t%0, [%1], %2\\t%@ loadhi") + +(define_peephole + [(set (match_operand:SI 0 "s_register_operand" "=r") + (mem:SI (match_operand:SI 1 "s_register_operand" "+r"))) + (set (match_dup 1) + (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))] + "REGNO(operands[0]) != REGNO(operands[1]) + && (GET_CODE (operands[2]) != REG + || REGNO(operands[0]) != REGNO (operands[2]))" + "ldr%?\\t%0, [%1], %2") + +(define_peephole + [(set (mem:QI (plus:SI (match_operand:SI 0 "s_register_operand" "+r") + (match_operand:SI 1 "index_operand" "rJ"))) + (match_operand:QI 2 "s_register_operand" "r")) + (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))] + "" + "str%?b\\t%2, [%0, %1]!") + +(define_peephole + [(set (mem:QI (plus:SI (match_operator:SI 4 "shift_operator" + [(match_operand:SI 0 "s_register_operand" "r") + (match_operand:SI 1 "const_int_operand" "n")]) + (match_operand:SI 2 "s_register_operand" "+r"))) + (match_operand:QI 3 "s_register_operand" "r")) + (set (match_dup 2) (plus:SI (match_op_dup 4 [(match_dup 0) (match_dup 1)]) + (match_dup 2)))] + "" + "str%?b\\t%3, [%2, %0%S4]!") + +; This pattern is never tried by combine, so do it as a peephole + +(define_peephole + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operand:SI 1 "s_register_operand" "r")) + (set (reg:CC 24) + (compare:CC (match_dup 1) (const_int 0)))] + "" + "sub%?s\\t%0, %1, #0" +[(set_attr "conds" "set")]) + +; Peepholes to spot possible load- and store-multiples, if the ordering is +; reversed, check that the memory references aren't volatile. + +(define_peephole + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operand:SI 4 "memory_operand" "m")) + (set (match_operand:SI 1 "s_register_operand" "=r") + (match_operand:SI 5 "memory_operand" "m")) + (set (match_operand:SI 2 "s_register_operand" "=r") + (match_operand:SI 6 "memory_operand" "m")) + (set (match_operand:SI 3 "s_register_operand" "=r") + (match_operand:SI 7 "memory_operand" "m"))] + "load_multiple_sequence (operands, 4, NULL, NULL, NULL)" + "* + return emit_ldm_seq (operands, 4); +") + +(define_peephole + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operand:SI 3 "memory_operand" "m")) + (set (match_operand:SI 1 "s_register_operand" "=r") + (match_operand:SI 4 "memory_operand" "m")) + (set (match_operand:SI 2 "s_register_operand" "=r") + (match_operand:SI 5 "memory_operand" "m"))] + "load_multiple_sequence (operands, 3, NULL, NULL, NULL)" + "* + return emit_ldm_seq (operands, 3); +") + +(define_peephole + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operand:SI 2 "memory_operand" "m")) + (set (match_operand:SI 1 "s_register_operand" "=r") + (match_operand:SI 3 "memory_operand" "m"))] + "load_multiple_sequence (operands, 2, NULL, NULL, NULL)" + "* + return emit_ldm_seq (operands, 2); +") + +(define_peephole + [(set (match_operand:SI 4 "memory_operand" "=m") + (match_operand:SI 0 "s_register_operand" "r")) + (set (match_operand:SI 5 "memory_operand" "=m") + (match_operand:SI 1 "s_register_operand" "r")) + (set (match_operand:SI 6 "memory_operand" "=m") + (match_operand:SI 2 "s_register_operand" "r")) + (set (match_operand:SI 7 "memory_operand" "=m") + (match_operand:SI 3 "s_register_operand" "r"))] + "store_multiple_sequence (operands, 4, NULL, NULL, NULL)" + "* + return emit_stm_seq (operands, 4); +") + +(define_peephole + [(set (match_operand:SI 3 "memory_operand" "=m") + (match_operand:SI 0 "s_register_operand" "r")) + (set (match_operand:SI 4 "memory_operand" "=m") + (match_operand:SI 1 "s_register_operand" "r")) + (set (match_operand:SI 5 "memory_operand" "=m") + (match_operand:SI 2 "s_register_operand" "r"))] + "store_multiple_sequence (operands, 3, NULL, NULL, NULL)" + "* + return emit_stm_seq (operands, 3); +") + +(define_peephole + [(set (match_operand:SI 2 "memory_operand" "=m") + (match_operand:SI 0 "s_register_operand" "r")) + (set (match_operand:SI 3 "memory_operand" "=m") + (match_operand:SI 1 "s_register_operand" "r"))] + "store_multiple_sequence (operands, 2, NULL, NULL, NULL)" + "* + return emit_stm_seq (operands, 2); +") + +;; A call followed by return can be replaced by restoring the regs and +;; jumping to the subroutine, provided we aren't passing the address of +;; any of our local variables. If we call alloca then this is unsafe +;; since restoring the frame frees the memory, which is not what we want. +;; Sometimes the return might have been targeted by the final prescan: +;; if so then emit a proper return insn as well. +;; Unfortunately, if the frame pointer is required, we don't know if the +;; current function has any implicit stack pointer adjustments that will +;; be restored by the return: we can't therefore do a tail call. +;; Another unfortunate that we can't handle is if current_function_args_size +;; is non-zero: in this case elimination of the argument pointer assumed +;; that lr was pushed onto the stack, so eliminating upsets the offset +;; calculations. + +(define_peephole + [(parallel [(call (mem:SI (match_operand:SI 0 "" "X")) + (match_operand:SI 1 "general_operand" "g")) + (clobber (reg:SI 14))]) + (return)] + "(GET_CODE (operands[0]) == SYMBOL_REF && USE_RETURN_INSN (FALSE) + && !get_frame_size () && !current_function_calls_alloca + && !frame_pointer_needed && !current_function_args_size)" + "* +{ + extern rtx arm_target_insn; + extern int arm_ccfsm_state; + + if (arm_ccfsm_state && arm_target_insn && INSN_DELETED_P (arm_target_insn)) + { + arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); + output_return_instruction (NULL, TRUE, FALSE); + arm_ccfsm_state = 0; + arm_target_insn = NULL; + } + + output_return_instruction (NULL, FALSE, FALSE); + return \"b%?\\t%a0\"; +}" +[(set_attr "type" "call") + (set_attr "length" "8")]) + +(define_peephole + [(parallel [(set (match_operand 0 "s_register_operand" "=rf") + (call (mem:SI (match_operand:SI 1 "" "X")) + (match_operand:SI 2 "general_operand" "g"))) + (clobber (reg:SI 14))]) + (return)] + "(GET_CODE (operands[1]) == SYMBOL_REF && USE_RETURN_INSN (FALSE) + && !get_frame_size () && !current_function_calls_alloca + && !frame_pointer_needed && !current_function_args_size)" + "* +{ + extern rtx arm_target_insn; + extern int arm_ccfsm_state; + + if (arm_ccfsm_state && arm_target_insn && INSN_DELETED_P (arm_target_insn)) + { + arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); + output_return_instruction (NULL, TRUE, FALSE); + arm_ccfsm_state = 0; + arm_target_insn = NULL; + } + + output_return_instruction (NULL, FALSE, FALSE); + return \"b%?\\t%a1\"; +}" +[(set_attr "type" "call") + (set_attr "length" "8")]) + +;; As above but when this function is not void, we must be returning the +;; result of the called subroutine. + +(define_peephole + [(parallel [(set (match_operand 0 "s_register_operand" "=rf") + (call (mem:SI (match_operand:SI 1 "" "X")) + (match_operand:SI 2 "general_operand" "g"))) + (clobber (reg:SI 14))]) + (use (match_dup 0)) + (return)] + "(GET_CODE (operands[1]) == SYMBOL_REF && USE_RETURN_INSN (FALSE) + && !get_frame_size () && !current_function_calls_alloca + && !frame_pointer_needed && !current_function_args_size)" + "* +{ + extern rtx arm_target_insn; + extern int arm_ccfsm_state; + + if (arm_ccfsm_state && arm_target_insn && INSN_DELETED_P (arm_target_insn)) + { + arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); + output_return_instruction (NULL, TRUE, FALSE); + arm_ccfsm_state = 0; + arm_target_insn = NULL; + } + + output_return_instruction (NULL, FALSE, FALSE); + return \"b%?\\t%a1\"; +}" +[(set_attr "type" "call") + (set_attr "length" "8")]) + +;; CYGNUS LOCAL +;; If calling a subroutine and then jumping back to somewhere else, but not +;; too far away, then we can set the link register with the branch address +;; and jump direct to the subroutine. On return from the subroutine +;; execution continues at the branch; this avoids a prefetch stall. +;; We use the length attribute (via short_branch ()) to establish whether or +;; not this is possible, this is the same as the sparc does. + +(define_peephole + [(parallel[(call (mem:SI (match_operand:SI 0 "" "X")) + (match_operand:SI 1 "general_operand" "g")) + (clobber (reg:SI 14))]) + (set (pc) + (label_ref (match_operand 2 "" "")))] + "0 && GET_CODE (operands[0]) == SYMBOL_REF + && short_branch (INSN_UID (insn), INSN_UID (operands[2])) + && arm_insn_not_targeted (insn)" + "* +{ + int backward = arm_backwards_branch (INSN_UID (insn), + INSN_UID (operands[2])); + +#if 0 + /* Putting this in means that TARGET_6 code will ONLY run on an arm6 or + * above, leaving it out means that the code will still run on an arm 2 or 3 + */ + if (TARGET_6) + { + if (backward) + output_asm_insn (\"sub%?\\t%|lr, %|pc, #(8 + . -%l2)\", operands); + else + output_asm_insn (\"add%?\\t%|lr, %|pc, #(%l2 - . -8)\", operands); + } + else +#endif + { + output_asm_insn (\"mov%?\\t%|lr, %|pc\\t%@ protect cc\", operands); + if (backward) + output_asm_insn (\"sub%?\\t%|lr, %|lr, #(4 + . -%l2)\", operands); + else + output_asm_insn (\"add%?\\t%|lr, %|lr, #(%l2 - . -4)\", operands); + } + return \"b%?\\t%a0\"; +}" +[(set_attr "type" "call") + (set (attr "length") + (if_then_else (eq_attr "prog_mode" "prog32") + (const_int 8) + (const_int 12)))]) + +(define_peephole + [(parallel[(set (match_operand:SI 0 "s_register_operand" "=r") + (call (mem:SI (match_operand:SI 1 "" "X")) + (match_operand:SI 2 "general_operand" "g"))) + (clobber (reg:SI 14))]) + (set (pc) + (label_ref (match_operand 3 "" "")))] + "0 && GET_CODE (operands[0]) == SYMBOL_REF + && short_branch (INSN_UID (insn), INSN_UID (operands[3])) + && arm_insn_not_targeted (insn)" + "* +{ + int backward = arm_backwards_branch (INSN_UID (insn), + INSN_UID (operands[3])); + +#if 0 + /* Putting this in means that TARGET_6 code will ONLY run on an arm6 or + * above, leaving it out means that the code will still run on an arm 2 or 3 + */ + if (TARGET_6) + { + if (backward) + output_asm_insn (\"sub%?\\t%|lr, %|pc, #(8 + . -%l3)\", operands); + else + output_asm_insn (\"add%?\\t%|lr, %|pc, #(%l3 - . -8)\", operands); + } + else +#endif + { + output_asm_insn (\"mov%?\\t%|lr, %|pc\\t%@ protect cc\", operands); + if (backward) + output_asm_insn (\"sub%?\\t%|lr, %|lr, #(4 + . -%l3)\", operands); + else + output_asm_insn (\"add%?\\t%|lr, %|lr, #(%l3 - . -4)\", operands); + } + return \"b%?\\t%a1\"; +}" +[(set_attr "type" "call") + (set (attr "length") + (if_then_else (eq_attr "prog_mode" "prog32") + (const_int 8) + (const_int 12)))]) +;; END CYGNUS LOCAL + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (and:SI (ge:SI (match_operand:SI 1 "s_register_operand" "") + (const_int 0)) + (neg:SI (match_operator:SI 2 "comparison_operator" + [(match_operand:SI 3 "s_register_operand" "") + (match_operand:SI 4 "arm_rhs_operand" "")])))) + (clobber (match_operand:SI 5 "s_register_operand" ""))] + "" + [(set (match_dup 5) (not:SI (ashiftrt:SI (match_dup 1) (const_int 31)))) + (set (match_dup 0) (and:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) + (match_dup 5)))] + "") + +;; This split can be used because CC_Z mode implies that the following +;; branch will be an equality, or an unsigned inequality, so the sign +;; extension is not needed. + +(define_split + [(set (reg:CC_Z 24) + (compare:CC_Z + (ashift:SI (subreg:SI (match_operand:QI 0 "memory_operand" "") 0) + (const_int 24)) + (match_operand 1 "const_int_operand" ""))) + (clobber (match_scratch:SI 2 ""))] + "((unsigned HOST_WIDE_INT) INTVAL (operands[1])) + == (((unsigned HOST_WIDE_INT) INTVAL (operands[1])) >> 24) << 24" + [(set (match_dup 2) (zero_extend:SI (match_dup 0))) + (set (reg:CC 24) (compare:CC (match_dup 2) (match_dup 1)))] + " + operands[1] = GEN_INT (((unsigned long) INTVAL (operands[1])) >> 24); +") + +(define_expand "prologue" + [(clobber (const_int 0))] + "" + " + arm_expand_prologue (); + DONE; +") + +;; This split is only used during output to reduce the number of patterns +;; that need assembler instructions adding to them. We allowed the setting +;; of the conditions to be implicit during rtl generation so that +;; the conditional compare patterns would work. However this conflicts to +;; some extent with the conditional data operations, so we have to split them +;; up again here. + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(match_operand 2 "" "") (match_operand 3 "" "")]) + (match_operand 4 "" "") + (match_operand 5 "" ""))) + (clobber (reg:CC 24))] + "reload_completed" + [(set (match_dup 6) (match_dup 7)) + (set (match_dup 0) + (if_then_else:SI (match_op_dup 1 [(match_dup 6) (const_int 0)]) + (match_dup 4) + (match_dup 5)))] + " +{ + enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]), operands[2], + operands[3]); + + operands[6] = gen_rtx (REG, mode, 24); + operands[7] = gen_rtx (COMPARE, mode, operands[2], operands[3]); +} +") + +;; CYGNUS LOCAL +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "") + (match_operand:SI 3 "arm_add_operand" "")]) + (match_operand:SI 4 "arm_rhs_operand" "") + (not:SI + (match_operand:SI 5 "s_register_operand" "")))) + (clobber (reg:CC 24))] + "reload_completed" + [(set (match_dup 6) (match_dup 7)) + (set (match_dup 0) + (if_then_else:SI (match_op_dup 1 [(match_dup 6) (const_int 0)]) + (match_dup 4) + (not:SI (match_dup 5))))] + " +{ + enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]), operands[2], + operands[3]); + + operands[6] = gen_rtx (REG, mode, 24); + operands[7] = gen_rtx (COMPARE, mode, operands[2], operands[3]); +} +") + +(define_insn "*cond_move_not" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI (match_operator 4 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_rhs_operand" "0,?rI") + (not:SI + (match_operand:SI 2 "s_register_operand" "r,r"))))] + "" + "@ + mvn%D4\\t%0, %2 + mov%d4\\t%0, %1\;mvn%D4\\t%0, %2" +[(set_attr "conds" "use") + (set_attr "length" "4,8")]) +;; END CYGNUS LOCAL + +;; The next two patterns occur when an AND operation is followed by a +;; scc insn sequence + +(define_insn "*sign_extract_onebit" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (sign_extract:SI (match_operand:SI 1 "s_register_operand" "r") + (const_int 1) + (match_operand:SI 2 "const_int_operand" "n")))] + "" + "* + operands[2] = GEN_INT (1 << INTVAL (operands[2])); + output_asm_insn (\"ands\\t%0, %1, %2\", operands); + return \"mvnne\\t%0, #0\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*not_signextract_onebit" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (not:SI + (sign_extract:SI (match_operand:SI 1 "s_register_operand" "r") + (const_int 1) + (match_operand:SI 2 "const_int_operand" "n"))))] + "" + "* + operands[2] = GEN_INT (1 << INTVAL (operands[2])); + output_asm_insn (\"tst\\t%1, %2\", operands); + output_asm_insn (\"mvneq\\t%0, #0\", operands); + return \"movne\\t%0, #0\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +;; Push multiple registers to the stack. The first register is in the +;; unspec part of the insn; subsequent registers are in parallel (use ...) +;; expressions. +(define_insn "*push_multi" + [(match_parallel 2 "multi_register_push" + [(set (match_operand:BLK 0 "memory_operand" "=m") + (unspec:BLK [(match_operand:SI 1 "s_register_operand" "r")] 2))])] + "" + "* +{ + char pattern[100]; + int i; + extern int lr_save_eliminated; + + if (lr_save_eliminated) + { + if (XVECLEN (operands[2], 0) > 1) + abort (); + return \"\"; + } + strcpy (pattern, \"stmfd\\t%m0!, {%1\"); + for (i = 1; i < XVECLEN (operands[2], 0); i++) + { + strcat (pattern, \", %|\"); + strcat (pattern, reg_names[REGNO (XEXP (XVECEXP (operands[2], 0, i), + 0))]); + } + strcat (pattern, \"}\"); + output_asm_insn (pattern, operands); + return \"\"; +}" +[(set_attr "type" "store4")]) + +;; Similarly for the floating point registers +(define_insn "*push_fp_multi" + [(match_parallel 2 "multi_register_push" + [(set (match_operand:BLK 0 "memory_operand" "=m") + (unspec:BLK [(match_operand:XF 1 "f_register_operand" "f")] 2))])] + "" + "* +{ + char pattern[100]; + int i; + + sprintf (pattern, \"sfmfd\\t%%1, %d, [%%m0]!\", XVECLEN (operands[2], 0)); + output_asm_insn (pattern, operands); + return \"\"; +}" +[(set_attr "type" "f_store")]) + +;; Special patterns for dealing with the constant pool + +(define_insn "consttable_4" + [(unspec_volatile [(match_operand 0 "" "")] 2)] + "" + "* +{ + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) + { + case MODE_FLOAT: + { + union real_extract u; + bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); + assemble_real (u.d, GET_MODE (operands[0])); + break; + } + default: + assemble_integer (operands[0], 4, 1); + break; + } + return \"\"; +}" +[(set_attr "length" "4")]) + +(define_insn "consttable_8" + [(unspec_volatile [(match_operand 0 "" "")] 3)] + "" + "* +{ + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) + { + case MODE_FLOAT: + { + union real_extract u; + bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); + assemble_real (u.d, GET_MODE (operands[0])); + break; + } + default: + assemble_integer (operands[0], 8, 1); + break; + } + return \"\"; +}" +[(set_attr "length" "8")]) + +(define_insn "consttable_end" + [(unspec_volatile [(const_int 0)] 4)] + "" + "* + /* Nothing to do (currently). */ + return \"\"; +") + +(define_insn "align_4" + [(unspec_volatile [(const_int 0)] 5)] + "" + "* + assemble_align (32); + return \"\"; +") diff --git a/gcc_arm/config/arm/arm_010110a.h b/gcc_arm/config/arm/arm_010110a.h new file mode 100755 index 0000000..91f440e --- /dev/null +++ b/gcc_arm/config/arm/arm_010110a.h @@ -0,0 +1,2211 @@ +/* Definitions of target machine for GNU compiler, for Acorn RISC Machine. + Copyright (C) 1991, 93, 94, 95, 96, 97, 98, 1999 Free Software Foundation, Inc. + Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl) + and Martin Simmons (@harleqn.co.uk). + More major hacks by Richard Earnshaw (rwe11@cl.cam.ac.uk) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Configuration triples for ARM ports work as follows: + (This is a bit of a mess and needs some thought) + arm-*-*: little endian + armel-*-*: little endian + armeb-*-*: big endian + If a non-embedded environment (ie: "real" OS) is specified, `arm' + should default to that used by the OS. +*/ + +#ifndef __ARM_H__ +#define __ARM_H__ + +#define TARGET_CPU_arm2 0x0000 +#define TARGET_CPU_arm250 0x0000 +#define TARGET_CPU_arm3 0x0000 +#define TARGET_CPU_arm6 0x0001 +#define TARGET_CPU_arm600 0x0001 +#define TARGET_CPU_arm610 0x0002 +#define TARGET_CPU_arm7 0x0001 +#define TARGET_CPU_arm7m 0x0004 +#define TARGET_CPU_arm7dm 0x0004 +#define TARGET_CPU_arm7dmi 0x0004 +#define TARGET_CPU_arm700 0x0001 +#define TARGET_CPU_arm710 0x0002 +#define TARGET_CPU_arm7100 0x0002 +#define TARGET_CPU_arm7500 0x0002 +#define TARGET_CPU_arm7500fe 0x1001 +#define TARGET_CPU_arm7tdmi 0x0008 +#define TARGET_CPU_arm8 0x0010 +#define TARGET_CPU_arm810 0x0020 +#define TARGET_CPU_strongarm 0x0040 +#define TARGET_CPU_strongarm110 0x0040 +#define TARGET_CPU_strongarm1100 0x0040 +#define TARGET_CPU_arm9 0x0080 +#define TARGET_CPU_arm9tdmi 0x0080 +/* Configure didn't specify */ +#define TARGET_CPU_generic 0x8000 + +enum arm_cond_code +{ + ARM_EQ = 0, ARM_NE, ARM_CS, ARM_CC, ARM_MI, ARM_PL, ARM_VS, ARM_VC, + ARM_HI, ARM_LS, ARM_GE, ARM_LT, ARM_GT, ARM_LE, ARM_AL, ARM_NV +}; +extern enum arm_cond_code arm_current_cc; +extern char *arm_condition_codes[]; + +#define ARM_INVERSE_CONDITION_CODE(X) ((enum arm_cond_code) (((int)X) ^ 1)) + +/* This is needed by the tail-calling peepholes */ +extern int frame_pointer_needed; + + +/* Just in case configure has failed to define anything. */ +#ifndef TARGET_CPU_DEFAULT +#define TARGET_CPU_DEFAULT TARGET_CPU_generic +#endif + +/* If the configuration file doesn't specify the cpu, the subtarget may + override it. If it doesn't, then default to an ARM6. */ +#if TARGET_CPU_DEFAULT == TARGET_CPU_generic +#undef TARGET_CPU_DEFAULT +#ifdef SUBTARGET_CPU_DEFAULT +#define TARGET_CPU_DEFAULT SUBTARGET_CPU_DEFAULT +#else +#define TARGET_CPU_DEFAULT TARGET_CPU_arm6 +#endif +#endif + +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm2 +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_2__" +#else +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm6 || TARGET_CPU_DEFAULT == TARGET_CPU_arm610 || TARGET_CPU_DEFAULT == TARGET_CPU_arm7500fe +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_3__" +#else +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm7m +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_3M__" +#else +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm7tdmi || TARGET_CPU_DEFAULT == TARGET_CPU_arm9 +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_4T__" +#else +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm8 || TARGET_CPU_DEFAULT == TARGET_CPU_arm810 || TARGET_CPU_DEFAULT == TARGET_CPU_strongarm +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_4__" +#else +Unrecognized value in TARGET_CPU_DEFAULT. +#endif +#endif +#endif +#endif +#endif + +#ifndef CPP_PREDEFINES +#define CPP_PREDEFINES "-Darm -Acpu(arm) -Amachine(arm)" +#endif + +#define CPP_SPEC "\ +%(cpp_cpu_arch) %(cpp_apcs_pc) %(cpp_float) \ +%(cpp_endian) %(subtarget_cpp_spec)" + +/* Set the architecture define -- if -march= is set, then it overrides + the -mcpu= setting. */ +#define CPP_CPU_ARCH_SPEC "\ +%{m2:-D__arm2__ -D__ARM_ARCH_2__} \ +%{m3:-D__arm2__ -D__ARM_ARCH_2__} \ +%{m6:-D__arm6__ -D__ARM_ARCH_3__} \ +%{march=arm2:-D__ARM_ARCH_2__} \ +%{march=arm250:-D__ARM_ARCH_2__} \ +%{march=arm3:-D__ARM_ARCH_2__} \ +%{march=arm6:-D__ARM_ARCH_3__} \ +%{march=arm600:-D__ARM_ARCH_3__} \ +%{march=arm610:-D__ARM_ARCH_3__} \ +%{march=arm7:-D__ARM_ARCH_3__} \ +%{march=arm700:-D__ARM_ARCH_3__} \ +%{march=arm710:-D__ARM_ARCH_3__} \ +%{march=arm7100:-D__ARM_ARCH_3__} \ +%{march=arm7500:-D__ARM_ARCH_3__} \ +%{march=arm7500fe:-D__ARM_ARCH_3__} \ +%{march=arm7m:-D__ARM_ARCH_3M__} \ +%{march=arm7dm:-D__ARM_ARCH_3M__} \ +%{march=arm7dmi:-D__ARM_ARCH_3M__} \ +%{march=arm7tdmi:-D__ARM_ARCH_4T__} \ +%{march=arm8:-D__ARM_ARCH_4__} \ +%{march=arm810:-D__ARM_ARCH_4__} \ +%{march=arm9:-D__ARM_ARCH_4T__} \ +%{march=arm920:-D__ARM_ARCH_4__} \ +%{march=arm920t:-D__ARM_ARCH_4T__} \ +%{march=arm9tdmi:-D__ARM_ARCH_4T__} \ +%{march=strongarm:-D__ARM_ARCH_4__} \ +%{march=strongarm110:-D__ARM_ARCH_4__} \ +%{march=strongarm1100:-D__ARM_ARCH_4__} \ +%{march=armv2:-D__ARM_ARCH_2__} \ +%{march=armv2a:-D__ARM_ARCH_2__} \ +%{march=armv3:-D__ARM_ARCH_3__} \ +%{march=armv3m:-D__ARM_ARCH_3M__} \ +%{march=armv4:-D__ARM_ARCH_4__} \ +%{march=armv4t:-D__ARM_ARCH_4T__} \ +%{!march=*: \ + %{mcpu=arm2:-D__ARM_ARCH_2__} \ + %{mcpu=arm250:-D__ARM_ARCH_2__} \ + %{mcpu=arm3:-D__ARM_ARCH_2__} \ + %{mcpu=arm6:-D__ARM_ARCH_3__} \ + %{mcpu=arm600:-D__ARM_ARCH_3__} \ + %{mcpu=arm610:-D__ARM_ARCH_3__} \ + %{mcpu=arm7:-D__ARM_ARCH_3__} \ + %{mcpu=arm700:-D__ARM_ARCH_3__} \ + %{mcpu=arm710:-D__ARM_ARCH_3__} \ + %{mcpu=arm7100:-D__ARM_ARCH_3__} \ + %{mcpu=arm7500:-D__ARM_ARCH_3__} \ + %{mcpu=arm7500fe:-D__ARM_ARCH_3__} \ + %{mcpu=arm7m:-D__ARM_ARCH_3M__} \ + %{mcpu=arm7dm:-D__ARM_ARCH_3M__} \ + %{mcpu=arm7dmi:-D__ARM_ARCH_3M__} \ + %{mcpu=arm7tdmi:-D__ARM_ARCH_4T__} \ + %{mcpu=arm8:-D__ARM_ARCH_4__} \ + %{mcpu=arm810:-D__ARM_ARCH_4__} \ + %{mcpu=arm9:-D__ARM_ARCH_4T__} \ + %{mcpu=arm920:-D__ARM_ARCH_4__} \ + %{mcpu=arm920t:-D__ARM_ARCH_4T__} \ + %{mcpu=arm9tdmi:-D__ARM_ARCH_4T__} \ + %{mcpu=strongarm:-D__ARM_ARCH_4__} \ + %{mcpu=strongarm110:-D__ARM_ARCH_4__} \ + %{mcpu=strongarm1100:-D__ARM_ARCH_4__} \ + %{!mcpu*:%{!m6:%{!m2:%{!m3:%(cpp_cpu_arch_default)}}}}} \ +" + +/* Define __APCS_26__ if the PC also contains the PSR */ +/* This also examines deprecated -m[236] if neither of -mapcs-{26,32} is set, + ??? Delete this for 2.9. */ +#define CPP_APCS_PC_SPEC "\ +%{mapcs-32:%{mapcs-26:%e-mapcs-26 and -mapcs-32 may not be used together} \ + -D__APCS_32__} \ +%{mapcs-26:-D__APCS_26__} \ +%{!mapcs-32: %{!mapcs-26:%{m6:-D__APCS_32__} %{m2:-D__APCS_26__} \ + %{m3:-D__APCS_26__} %{!m6:%{!m3:%{!m2:%(cpp_apcs_pc_default)}}}}} \ +" + +#ifndef CPP_APCS_PC_DEFAULT_SPEC +#define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_26__" +#endif + +#define CPP_FLOAT_SPEC "\ +%{msoft-float:\ + %{mhard-float:%e-msoft-float and -mhard_float may not be used together} \ + -D__SOFTFP__} \ +%{!mhard-float:%{!msoft-float:%(cpp_float_default)}} \ +" + +/* Default is hard float, which doesn't define anything */ +#define CPP_FLOAT_DEFAULT_SPEC "" + +#define CPP_ENDIAN_SPEC "\ +%{mbig-endian: \ + %{mlittle-endian: \ + %e-mbig-endian and -mlittle-endian may not be used together} \ + -D__ARMEB__ %{mwords-little-endian:-D__ARMWEL__}} \ +%{!mlittle-endian:%{!mbig-endian:%(cpp_endian_default)}} \ +" + +/* Default is little endian, which doesn't define anything. */ +#define CPP_ENDIAN_DEFAULT_SPEC "" + +/* Translate (for now) the old -m[236] option into the appropriate -mcpu=... + and -mapcs-xx equivalents. + ??? Remove support for this style in 2.9.*/ +#define CC1_SPEC "\ +%{m2:-mcpu=arm2 -mapcs-26} \ +%{m3:-mcpu=arm3 -mapcs-26} \ +%{m6:-mcpu=arm6 -mapcs-32} \ +" + +/* This macro defines names of additional specifications to put in the specs + that can be used in various specifications like CC1_SPEC. Its definition + is an initializer with a subgrouping for each command option. + + Each subgrouping contains a string constant, that defines the + specification name, and a string constant that used by the GNU CC driver + program. + + Do not define this macro if it does not need to do anything. */ +#define EXTRA_SPECS \ + { "cpp_cpu_arch", CPP_CPU_ARCH_SPEC }, \ + { "cpp_cpu_arch_default", CPP_ARCH_DEFAULT_SPEC }, \ + { "cpp_apcs_pc", CPP_APCS_PC_SPEC }, \ + { "cpp_apcs_pc_default", CPP_APCS_PC_DEFAULT_SPEC }, \ + { "cpp_float", CPP_FLOAT_SPEC }, \ + { "cpp_float_default", CPP_FLOAT_DEFAULT_SPEC }, \ + { "cpp_endian", CPP_ENDIAN_SPEC }, \ + { "cpp_endian_default", CPP_ENDIAN_DEFAULT_SPEC }, \ + { "subtarget_cpp_spec", SUBTARGET_CPP_SPEC }, \ + SUBTARGET_EXTRA_SPECS + +#define SUBTARGET_EXTRA_SPECS +#define SUBTARGET_CPP_SPEC "" + + +/* Run-time Target Specification. */ +#ifndef TARGET_VERSION +#define TARGET_VERSION \ + fputs (" (ARM/generic)", stderr); +#endif + +/* Run-time compilation parameters selecting different hardware subsets. */ +extern int target_flags; + +/* The floating point instruction architecture, can be 2 or 3 */ +/* CYGNUS LOCAL nickc/renamed from target_fp_name */ +extern char * target_fpe_name; +/* END CYGNUS LOCAL */ + +/* Nonzero if the function prologue (and epilogue) should obey + the ARM Procedure Call Standard. */ +#define ARM_FLAG_APCS_FRAME (0x0001) + +/* Nonzero if the function prologue should output the function name to enable + the post mortem debugger to print a backtrace (very useful on RISCOS, + unused on RISCiX). Specifying this flag also enables + -fno-omit-frame-pointer. + XXX Must still be implemented in the prologue. */ +#define ARM_FLAG_POKE (0x0002) + +/* Nonzero if floating point instructions are emulated by the FPE, in which + case instruction scheduling becomes very uninteresting. */ +#define ARM_FLAG_FPE (0x0004) + +/* Nonzero if destined for an ARM6xx. Takes out bits that assume restoration + of condition flags when returning from a branch & link (ie. a function) */ +/* ********* DEPRECATED ******** */ +#define ARM_FLAG_ARM6 (0x0008) + +/* ********* DEPRECATED ******** */ +#define ARM_FLAG_ARM3 (0x0010) + +/* Nonzero if destined for a processor in 32-bit program mode. Takes out bit + that assume restoration of the condition flags when returning from a + branch and link (ie a function). */ +#define ARM_FLAG_APCS_32 (0x0020) + +/* Nonzero if stack checking should be performed on entry to each function + which allocates temporary variables on the stack. */ +#define ARM_FLAG_APCS_STACK (0x0040) + +/* Nonzero if floating point parameters should be passed to functions in + floating point registers. */ +#define ARM_FLAG_APCS_FLOAT (0x0080) + +/* Nonzero if re-entrant, position independent code should be generated. + This is equivalent to -fpic. */ +#define ARM_FLAG_APCS_REENT (0x0100) + +/* Nonzero if the MMU will trap unaligned word accesses, so shorts must be + loaded byte-at-a-time. */ +#define ARM_FLAG_SHORT_BYTE (0x0200) + +/* Nonzero if all floating point instructions are missing (and there is no + emulator either). Generate function calls for all ops in this case. */ +#define ARM_FLAG_SOFT_FLOAT (0x0400) + +/* Nonzero if we should compile with BYTES_BIG_ENDIAN set to 1. */ +#define ARM_FLAG_BIG_END (0x0800) + +/* Nonzero if we should compile for Thumb interworking. */ +#define ARM_FLAG_THUMB (0x1000) + +/* Nonzero if we should have little-endian words even when compiling for + big-endian (for backwards compatibility with older versions of GCC). */ +#define ARM_FLAG_LITTLE_WORDS (0x2000) + +/* CYGNUS LOCAL */ +/* Nonzero if we need to protect the prolog from scheduling */ +#define ARM_FLAG_NO_SCHED_PRO (0x4000) +/* END CYGNUS LOCAL */ + +/* Nonzero if a call to abort should be generated if a noreturn +function tries to return. */ +#define ARM_FLAG_ABORT_NORETURN (0x8000) + +#define TARGET_APCS (target_flags & ARM_FLAG_APCS_FRAME) +#define TARGET_POKE_FUNCTION_NAME (target_flags & ARM_FLAG_POKE) +#define TARGET_FPE (target_flags & ARM_FLAG_FPE) +#define TARGET_6 (target_flags & ARM_FLAG_ARM6) +#define TARGET_3 (target_flags & ARM_FLAG_ARM3) +#define TARGET_APCS_32 (target_flags & ARM_FLAG_APCS_32) +#define TARGET_APCS_STACK (target_flags & ARM_FLAG_APCS_STACK) +#define TARGET_APCS_FLOAT (target_flags & ARM_FLAG_APCS_FLOAT) +#define TARGET_APCS_REENT (target_flags & ARM_FLAG_APCS_REENT) +#define TARGET_SHORT_BY_BYTES (target_flags & ARM_FLAG_SHORT_BYTE) +#define TARGET_SOFT_FLOAT (target_flags & ARM_FLAG_SOFT_FLOAT) +#define TARGET_HARD_FLOAT (! TARGET_SOFT_FLOAT) +#define TARGET_BIG_END (target_flags & ARM_FLAG_BIG_END) +#define TARGET_THUMB_INTERWORK (target_flags & ARM_FLAG_THUMB) +#define TARGET_LITTLE_WORDS (target_flags & ARM_FLAG_LITTLE_WORDS) +/* CYGNUS LOCAL */ +#define TARGET_NO_SCHED_PRO (target_flags & ARM_FLAG_NO_SCHED_PRO) +/* END CYGNUS LOCAL */ +#define TARGET_ABORT_NORETURN (target_flags & ARM_FLAG_ABORT_NORETURN) + +/* SUBTARGET_SWITCHES is used to add flags on a per-config basis. + Bit 31 is reserved. See riscix.h. */ +#ifndef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES +#endif + +#define TARGET_SWITCHES \ +{ \ + {"apcs", ARM_FLAG_APCS_FRAME, "" }, \ + {"apcs-frame", ARM_FLAG_APCS_FRAME, \ + "Generate APCS conformant stack frames" }, \ + {"no-apcs-frame", -ARM_FLAG_APCS_FRAME, "" }, \ + {"poke-function-name", ARM_FLAG_POKE, \ + "Store function names in object code" }, \ + {"fpe", ARM_FLAG_FPE, "" }, \ + {"6", ARM_FLAG_ARM6, "" }, \ + {"2", ARM_FLAG_ARM3, "" }, \ + {"3", ARM_FLAG_ARM3, "" }, \ + {"apcs-32", ARM_FLAG_APCS_32, \ + "Use the 32bit version of the APCS" }, \ + {"apcs-26", -ARM_FLAG_APCS_32, \ + "Use the 26bit version of the APCS" }, \ + {"apcs-stack-check", ARM_FLAG_APCS_STACK, "" }, \ + {"no-apcs-stack-check", -ARM_FLAG_APCS_STACK, "" }, \ + {"apcs-float", ARM_FLAG_APCS_FLOAT, \ + "Pass FP arguments in FP registers" }, \ + {"no-apcs-float", -ARM_FLAG_APCS_FLOAT, "" }, \ + {"apcs-reentrant", ARM_FLAG_APCS_REENT, \ + "Generate re-entrant, PIC code" }, \ + {"no-apcs-reentrant", -ARM_FLAG_APCS_REENT, "" }, \ + {"short-load-bytes", ARM_FLAG_SHORT_BYTE, \ + "Load shorts a byte at a time" }, \ + {"no-short-load-bytes", -ARM_FLAG_SHORT_BYTE, "" }, \ + {"short-load-words", -ARM_FLAG_SHORT_BYTE, \ + "Load words a byte at a time" }, \ + {"no-short-load-words", ARM_FLAG_SHORT_BYTE, "" }, \ + {"soft-float", ARM_FLAG_SOFT_FLOAT, \ + "Use library calls to perform FP operations" }, \ + {"hard-float", -ARM_FLAG_SOFT_FLOAT, \ + "Use hardware floating point instructions" }, \ + {"big-endian", ARM_FLAG_BIG_END, \ + "Assume target CPU is configured as big endian" }, \ + {"little-endian", -ARM_FLAG_BIG_END, \ + "Assume target CPU is configured as little endian" }, \ + {"words-little-endian", ARM_FLAG_LITTLE_WORDS, \ + "Assume big endian bytes, little endian words" }, \ + {"thumb-interwork", ARM_FLAG_THUMB, \ + "Support calls between THUMB and ARM instructions sets" }, \ + {"no-thumb-interwork", -ARM_FLAG_THUMB, "" }, \ + {"abort-on-noreturn", ARM_FLAG_ABORT_NORETURN, \ + "Generate a call to abort if a noreturn function returns"}, \ + {"no-abort-on-noreturn", -ARM_FLAG_ABORT_NORETURN, ""}, \ + /* CYGNUS LOCAL */ \ + {"sched-prolog", -ARM_FLAG_NO_SCHED_PRO, \ + "Do not move instructions into a function's prologue" }, \ + {"no-sched-prolog", ARM_FLAG_NO_SCHED_PRO, "" }, \ + /* END CYGNUS LOCAL */ \ + SUBTARGET_SWITCHES \ + {"", TARGET_DEFAULT } \ +} + +#define TARGET_OPTIONS \ +{ \ + {"cpu=", & arm_select[0].string, \ + "Specify the name of the target CPU" }, \ + {"arch=", & arm_select[1].string, \ + "Specify the name of the target architecture" }, \ + {"tune=", & arm_select[2].string, "" }, \ + {"fpe=", & target_fpe_name, "" }, \ + {"fp=", & target_fpe_name, \ + "Specify the version of the floating point emulator" }, \ + { "structure-size-boundary=", & structure_size_string, \ + "Specify the minumum bit alignment of structures" } \ +} + +struct arm_cpu_select +{ + char * string; + char * name; + struct processors * processors; +}; + +/* This is a magic array. If the user specifies a command line switch + which matches one of the entries in TARGET_OPTIONS then the corresponding + string pointer will be set to the value specified by the user. */ +extern struct arm_cpu_select arm_select[]; + +enum prog_mode_type +{ + prog_mode26, + prog_mode32 +}; + +/* Recast the program mode class to be the prog_mode attribute */ +#define arm_prog_mode ((enum attr_prog_mode) arm_prgmode) + +extern enum prog_mode_type arm_prgmode; + +/* What sort of floating point unit do we have? Hardware or software. + If software, is it issue 2 or issue 3? */ +enum floating_point_type +{ + FP_HARD, + FP_SOFT2, + FP_SOFT3 +}; + +/* Recast the floating point class to be the floating point attribute. */ +#define arm_fpu_attr ((enum attr_fpu) arm_fpu) + +/* What type of floating point to tune for */ +extern enum floating_point_type arm_fpu; + +/* What type of floating point instructions are available */ +extern enum floating_point_type arm_fpu_arch; + +/* Default floating point architecture. Override in sub-target if + necessary. */ +#define FP_DEFAULT FP_SOFT2 + +/* Nonzero if the processor has a fast multiply insn, and one that does + a 64-bit multiply of two 32-bit values. */ +extern int arm_fast_multiply; + +/* Nonzero if this chip supports the ARM Architecture 4 extensions */ +extern int arm_arch4; + +/* CYGNUS LOCAL nickc/load scheduling */ +/* Nonzero if this chip can benefit from load scheduling. */ +extern int arm_ld_sched; +/* END CYGNUS LOCAL */ + +/* Nonzero if this chip is a StrongARM. */ +extern int arm_is_strong; + +/* Nonzero if this chip is a an ARM6 or an ARM7. */ +extern int arm_is_6_or_7; + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT 0 +#endif + +/* The frame pointer register used in gcc has nothing to do with debugging; + that is controlled by the APCS-FRAME option. */ +/* Not fully implemented yet */ +/* #define CAN_DEBUG_WITHOUT_FP 1 */ + +#define TARGET_MEM_FUNCTIONS 1 + +#define OVERRIDE_OPTIONS arm_override_options () + +/* Target machine storage Layout. */ + + +/* Define this macro if it is advisable to hold scalars in registers + in a wider mode than that declared by the program. In such cases, + the value is constrained to be within the bounds of the declared + type, but kept valid in the wider mode. The signedness of the + extension may differ from that of the type. */ + +/* It is far faster to zero extend chars than to sign extend them */ + +#define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \ + if (GET_MODE_CLASS (MODE) == MODE_INT \ + && GET_MODE_SIZE (MODE) < 4) \ + { \ + if (MODE == QImode) \ + UNSIGNEDP = 1; \ + else if (MODE == HImode) \ + UNSIGNEDP = TARGET_SHORT_BY_BYTES != 0; \ + (MODE) = SImode; \ + } + +/* Define this macro if the promotion described by `PROMOTE_MODE' + should also be done for outgoing function arguments. */ +/* This is required to ensure that push insns always push a word. */ +#define PROMOTE_FUNCTION_ARGS + +/* Define for XFmode extended real floating point support. + This will automatically cause REAL_ARITHMETIC to be defined. */ +/* For the ARM: + I think I have added all the code to make this work. Unfortunately, + early releases of the floating point emulation code on RISCiX used a + different format for extended precision numbers. On my RISCiX box there + is a bug somewhere which causes the machine to lock up when running enquire + with long doubles. There is the additional aspect that Norcroft C + treats long doubles as doubles and we ought to remain compatible. + Perhaps someone with an FPA coprocessor and not running RISCiX would like + to try this someday. */ +/* #define LONG_DOUBLE_TYPE_SIZE 96 */ + +/* Disable XFmode patterns in md file */ +#define ENABLE_XF_PATTERNS 0 + +/* Define if you don't want extended real, but do want to use the + software floating point emulator for REAL_ARITHMETIC and + decimal <-> binary conversion. */ +/* See comment above */ +#define REAL_ARITHMETIC + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. */ +#define BITS_BIG_ENDIAN 0 + +/* Define this if most significant byte of a word is the lowest numbered. + Most ARM processors are run in little endian mode, so that is the default. + If you want to have it run-time selectable, change the definition in a + cover file to be TARGET_BIG_ENDIAN. */ +#define BYTES_BIG_ENDIAN (TARGET_BIG_END != 0) + +/* Define this if most significant word of a multiword number is the lowest + numbered. + This is always false, even when in big-endian mode. */ +#define WORDS_BIG_ENDIAN (BYTES_BIG_ENDIAN && ! TARGET_LITTLE_WORDS) + +/* LIBGCC2_WORDS_BIG_ENDIAN has to be a constant, so we define this based + on processor pre-defineds when compiling libgcc2.c. */ +#if defined(__ARMEB__) && !defined(__ARMWEL__) +#define LIBGCC2_WORDS_BIG_ENDIAN 1 +#else +#define LIBGCC2_WORDS_BIG_ENDIAN 0 +#endif + +/* Define this if most significant word of doubles is the lowest numbered. + This is always true, even when in little-endian mode. */ +#define FLOAT_WORDS_BIG_ENDIAN 1 + +/* Number of bits in an addressable storage unit */ +#define BITS_PER_UNIT 8 + +#define BITS_PER_WORD 32 + +#define UNITS_PER_WORD 4 + +#define POINTER_SIZE 32 + +#define PARM_BOUNDARY 32 + +#define STACK_BOUNDARY 32 + +#define FUNCTION_BOUNDARY 32 + +#define EMPTY_FIELD_BOUNDARY 32 + +#define BIGGEST_ALIGNMENT 32 + +/* Make strings word-aligned so strcpy from constants will be faster. */ +#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ + (TREE_CODE (EXP) == STRING_CST \ + && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) + +/* Every structures size must be a multiple of 32 bits. */ +/* This is for compatibility with ARMCC. ARM SDT Reference Manual + (ARM DUI 0020D) page 2-20 says "Structures are aligned on word + boundaries". */ +#ifndef STRUCTURE_SIZE_BOUNDARY +#define STRUCTURE_SIZE_BOUNDARY 32 +#endif + +/* Used when parsing command line option -mstructure_size_boundary. */ +extern char * structure_size_string; + +/* Non-zero if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT 1 + +#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT + + +/* Standard register usage. */ + +/* Register allocation in ARM Procedure Call Standard (as used on RISCiX): + (S - saved over call). + + r0 * argument word/integer result + r1-r3 argument word + + r4-r8 S register variable + r9 S (rfp) register variable (real frame pointer) + CYGNUS LOCAL nickc/comment change + r10 F S (sl) stack limit (used by -mapcs-stack-check) + END CYGNUS LOCAL + r11 F S (fp) argument pointer + r12 (ip) temp workspace + r13 F S (sp) lower end of current stack frame + r14 (lr) link address/workspace + r15 F (pc) program counter + + f0 floating point result + f1-f3 floating point scratch + + f4-f7 S floating point variable + + cc This is NOT a real register, but is used internally + to represent things that use or set the condition + codes. + sfp This isn't either. It is used during rtl generation + since the offset between the frame pointer and the + auto's isn't known until after register allocation. + afp Nor this, we only need this because of non-local + goto. Without it fp appears to be used and the + elimination code won't get rid of sfp. It tracks + fp exactly at all times. + + *: See CONDITIONAL_REGISTER_USAGE */ + +/* The stack backtrace structure is as follows: + fp points to here: | save code pointer | [fp] + | return link value | [fp, #-4] + | return sp value | [fp, #-8] + | return fp value | [fp, #-12] + [| saved r10 value |] + [| saved r9 value |] + [| saved r8 value |] + [| saved r7 value |] + [| saved r6 value |] + [| saved r5 value |] + [| saved r4 value |] + [| saved r3 value |] + [| saved r2 value |] + [| saved r1 value |] + [| saved r0 value |] + [| saved f7 value |] three words + [| saved f6 value |] three words + [| saved f5 value |] three words + [| saved f4 value |] three words + r0-r3 are not normally saved in a C function. */ + +/* The number of hard registers is 16 ARM + 8 FPU + 1 CC + 1 SFP. */ +#define FIRST_PSEUDO_REGISTER 27 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. */ +#define FIXED_REGISTERS \ +{ \ + 0,0,0,0,0,0,0,0, \ + 0,0,1,1,0,1,0,1, \ + 0,0,0,0,0,0,0,0, \ + 1,1,1 \ +} + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. + The CC is not preserved over function calls on the ARM 6, so it is + easier to assume this for all. SFP is preserved, since FP is. */ +#define CALL_USED_REGISTERS \ +{ \ + 1,1,1,1,0,0,0,0, \ + 0,0,1,1,1,1,1,1, \ + 1,1,1,1,0,0,0,0, \ + 1,1,1 \ +} + +/* If doing stupid life analysis, avoid a bug causing a return value r0 to be + trampled. This effectively reduces the number of available registers by 1. + XXX It is a hack, I know. + XXX Is this still needed? */ +#define CONDITIONAL_REGISTER_USAGE \ +{ \ + if (obey_regdecls) \ + fixed_regs[0] = 1; \ + if (TARGET_SOFT_FLOAT) \ + { \ + int regno; \ + for (regno = 16; regno < 24; ++regno) \ + fixed_regs[regno] = call_used_regs[regno] = 1; \ + } \ + if (flag_pic) \ + { \ + fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ + call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 0; \ + } \ + /* CYGNUS LOCAL */ \ + else if (! TARGET_APCS_STACK) \ + { \ + fixed_regs[10] = 0; \ + call_used_regs[10] = 0; \ + } \ + /* END CYGNUS LOCAL */ \ +} + +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. + + On the ARM regs are UNITS_PER_WORD bits wide; FPU regs can hold any FP + mode. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + (((REGNO) >= 16 && REGNO != FRAME_POINTER_REGNUM \ + && (REGNO) != ARG_POINTER_REGNUM) ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + This is TRUE for ARM regs since they can hold anything, and TRUE for FPU + regs holding FP. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + ((GET_MODE_CLASS (MODE) == MODE_CC) ? (REGNO == CC_REGNUM) : \ + ((REGNO) < 16 || REGNO == FRAME_POINTER_REGNUM \ + || REGNO == ARG_POINTER_REGNUM \ + || GET_MODE_CLASS (MODE) == MODE_FLOAT)) + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + 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) \ + (GET_MODE_CLASS (MODE1) == GET_MODE_CLASS (MODE2)) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* Define this if the program counter is overloaded on a register. */ +#define PC_REGNUM 15 + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 13 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 25 + +/* Define this to be where the real frame pointer is if it is not possible to + work out the offset between the frame pointer and the automatic variables + until after register allocation has taken place. FRAME_POINTER_REGNUM + should point to a special register that we will make sure is eliminated. */ +#define HARD_FRAME_POINTER_REGNUM 11 + +/* 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. + If we have to have a frame pointer we might as well make use of it. + APCS says that the frame pointer does not need to be pushed in leaf + functions, or simple tail call functions. */ +/* CYGNUS LOCAL */ +#define FRAME_POINTER_REQUIRED \ + (current_function_has_nonlocal_label \ + || (TARGET_APCS && (! leaf_function_p () && ! can_tail_call_optimise ()))) + +extern int can_tail_call_optimise (); +/* END CYGNUS LOCAL */ + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 26 + +/* The native (Norcroft) Pascal compiler for the ARM passes the static chain + as an invisible last argument (possible since varargs don't exist in + Pascal), so the following is not true. */ +#define STATIC_CHAIN_REGNUM 8 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 0 + +/* Internal, so that we don't need to refer to a raw number */ +#define CC_REGNUM 24 + +/* The order in which register should be allocated. It is good to use ip + since no saving is required (though calls clobber it) and it never contains + function parameters. It is quite good to use lr since other calls may + clobber it anyway. Allocate r0 through r3 in reverse order since r3 is + least likely to contain a function parameter; in addition results are + returned in r0. + */ +#define REG_ALLOC_ORDER \ +{ \ + 3, 2, 1, 0, 12, 14, 4, 5, \ + 6, 7, 8, 10, 9, 11, 13, 15, \ + 16, 17, 18, 19, 20, 21, 22, 23, \ + 24, 25, 26 \ +} + +/* Register and constant classes. */ + +/* Register classes: all ARM regs or all FPU regs---simple! */ +enum reg_class +{ + NO_REGS, + FPU_REGS, + GENERAL_REGS, + ALL_REGS, + LIM_REG_CLASSES +}; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Give names of register classes as strings for dump file. */ +#define REG_CLASS_NAMES \ +{ \ + "NO_REGS", \ + "FPU_REGS", \ + "GENERAL_REGS", \ + "ALL_REGS", \ +} + +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ +#define REG_CLASS_CONTENTS \ +{ \ + 0x0000000, /* NO_REGS */ \ + 0x0FF0000, /* FPU_REGS */ \ + 0x200FFFF, /* GENERAL_REGS */ \ + 0x2FFFFFF /* ALL_REGS */ \ +} + +/* The same information, inverted: + Return the class number of the smallest class containing + reg number REGNO. This could be a conditional expression + or could index an array. */ +#define REGNO_REG_CLASS(REGNO) \ + (((REGNO) < 16 || REGNO == FRAME_POINTER_REGNUM \ + || REGNO == ARG_POINTER_REGNUM) \ + ? GENERAL_REGS : (REGNO) == CC_REGNUM \ + ? NO_REGS : FPU_REGS) + +/* The class value for index registers, and the one for base regs. */ +#define INDEX_REG_CLASS GENERAL_REGS +#define BASE_REG_CLASS GENERAL_REGS + +/* Get reg_class from a letter such as appears in the machine description. + We only need constraint `f' for FPU_REGS (`r' == GENERAL_REGS). */ +#define REG_CLASS_FROM_LETTER(C) \ + ((C)=='f' ? FPU_REGS : 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: immediate arithmetic operand (i.e. 8 bits shifted as required). + J: valid indexing constants. + K: ~value ok in rhs argument of data operand. + L: -value ok in rhs argument of data operand. + M: 0..32, or a power of 2 (for shifts, or mult done by shift). */ +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? const_ok_for_arm (VALUE) : \ + (C) == 'J' ? ((VALUE) < 4096 && (VALUE) > -4096) : \ + (C) == 'K' ? (const_ok_for_arm (~(VALUE))) : \ + (C) == 'L' ? (const_ok_for_arm (-(VALUE))) : \ + (C) == 'M' ? (((VALUE >= 0 && VALUE <= 32)) \ + || (((VALUE) & ((VALUE) - 1)) == 0)) \ + : 0) + +/* For the ARM, `Q' means that this is a memory operand that is just + an offset from a register. + `S' means any symbol that has the SYMBOL_REF_FLAG set or a CONSTANT_POOL + address. This means that the symbol is in the text segment and can be + accessed without using a load. */ + +#define EXTRA_CONSTRAINT(OP, C) \ + ((C) == 'Q' ? GET_CODE (OP) == MEM && GET_CODE (XEXP (OP, 0)) == REG \ + : (C) == 'R' ? (GET_CODE (OP) == MEM \ + && GET_CODE (XEXP (OP, 0)) == SYMBOL_REF \ + && CONSTANT_POOL_ADDRESS_P (XEXP (OP, 0))) \ + : (C) == 'S' ? (optimize > 0 && CONSTANT_ADDRESS_P (OP)) \ + : 0) + +/* Constant letter 'G' for the FPU immediate constants. + 'H' means the same constant negated. */ +#define CONST_DOUBLE_OK_FOR_LETTER_P(X,C) \ + ((C) == 'G' ? const_double_rtx_ok_for_fpu (X) \ + : (C) == 'H' ? neg_const_double_rtx_ok_for_fpu (X) : 0) + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. */ +#define PREFERRED_RELOAD_CLASS(X, CLASS) (CLASS) + +/* Return the register class of a scratch register needed to copy IN into + or out of a register in CLASS in MODE. If it can be done directly, + NO_REGS is returned. */ +#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS,MODE,X) \ + (((MODE) == HImode && ! arm_arch4 && true_regnum (X) == -1) \ + ? GENERAL_REGS : NO_REGS) + +/* If we need to load shorts byte-at-a-time, then we need a scratch. */ +#define SECONDARY_INPUT_RELOAD_CLASS(CLASS,MODE,X) \ + (((MODE) == HImode && ! arm_arch4 && TARGET_SHORT_BY_BYTES \ + && (GET_CODE (X) == MEM \ + || ((GET_CODE (X) == REG || GET_CODE (X) == SUBREG) \ + && true_regnum (X) == -1))) \ + ? GENERAL_REGS : NO_REGS) + +/* Try a machine-dependent way of reloading an illegitimate address + operand. If we find one, push the reload and jump to WIN. This + macro is used in only one place: `find_reloads_address' in reload.c. + + For the ARM, we wish to handle large displacements off a base + register by splitting the addend across a MOV and the mem insn. + This can cut the number of reloads needed. */ +#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \ +do { \ + if (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REGNO (XEXP (X, 0)) < FIRST_PSEUDO_REGISTER \ + && REG_MODE_OK_FOR_BASE_P (XEXP (X, 0), MODE) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT) \ + { \ + HOST_WIDE_INT val = INTVAL (XEXP (X, 1)); \ + HOST_WIDE_INT low, high; \ + \ + if (MODE == DImode || (TARGET_SOFT_FLOAT && MODE == DFmode)) \ + low = ((val & 0xf) ^ 0x8) - 0x8; \ + else if (MODE == SImode || MODE == QImode \ + || (MODE == SFmode && TARGET_SOFT_FLOAT) \ + || (MODE == HImode && ! arm_arch4)) \ + /* Need to be careful, -4096 is not a valid offset */ \ + low = val >= 0 ? (val & 0xfff) : -((-val) & 0xfff); \ + else if (MODE == HImode && arm_arch4) \ + /* Need to be careful, -256 is not a valid offset */ \ + low = val >= 0 ? (val & 0xff) : -((-val) & 0xff); \ + else if (GET_MODE_CLASS (MODE) == MODE_FLOAT \ + && TARGET_HARD_FLOAT) \ + /* Need to be careful, -1024 is not a valid offset */ \ + low = val >= 0 ? (val & 0x3ff) : -((-val) & 0x3ff); \ + else \ + break; \ + \ + high = ((((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000); \ + /* Check for overflow or zero */ \ + if (low == 0 || high == 0 || (high + low != val)) \ + break; \ + \ + /* Reload the high part into a base reg; leave the low part \ + in the mem. */ \ + X = gen_rtx_PLUS (GET_MODE (X), \ + gen_rtx_PLUS (GET_MODE (X), XEXP (X, 0), \ + GEN_INT (high)), \ + GEN_INT (low)); \ + push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL_PTR, \ + BASE_REG_CLASS, GET_MODE (X), VOIDmode, 0, 0, \ + OPNUM, TYPE); \ + goto WIN; \ + } \ +} while (0) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. + ARM regs are UNITS_PER_WORD bits while FPU regs can hold any FP mode */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((CLASS) == FPU_REGS ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Moves between FPU_REGS and GENERAL_REGS are two memory insns. */ +#define REGISTER_MOVE_COST(CLASS1, CLASS2) \ + ((((CLASS1) == FPU_REGS && (CLASS2) != FPU_REGS) \ + || ((CLASS2) == FPU_REGS && (CLASS1) != FPU_REGS)) \ + ? 20 : 2) + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD 1 + +/* 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 + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. */ +/* The push insns do not do this rounding implicitly. So don't define this. */ +/* #define PUSH_ROUNDING(NPUSHED) (((NPUSHED) + 3) & ~3) */ + +/* Define this if the maximum size of all the outgoing args is to be + accumulated and pushed during the prologue. The amount can be + found in the variable current_function_outgoing_args_size. */ +#define ACCUMULATE_OUTGOING_ARGS + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 4 + +/* Value is the number of byte of arguments automatically + popped when returning from a subroutine call. + FUNDECL is the declaration node of the function (as a tree), + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. + SIZE is the number of bytes of arguments passed on the stack. + + On the ARM, the caller does not pop any of its arguments that were passed + on the stack. */ +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 + +/* 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) \ + (GET_MODE_CLASS (TYPE_MODE (VALTYPE)) == MODE_FLOAT && TARGET_HARD_FLOAT \ + ? gen_rtx (REG, TYPE_MODE (VALTYPE), 16) \ + : gen_rtx (REG, TYPE_MODE (VALTYPE), 0)) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ +#define LIBCALL_VALUE(MODE) \ + (GET_MODE_CLASS (MODE) == MODE_FLOAT && TARGET_HARD_FLOAT \ + ? gen_rtx (REG, MODE, 16) \ + : gen_rtx (REG, MODE, 0)) + +/* 1 if N is a possible register number for a function value. + On the ARM, only r0 and f0 can return results. */ +#define FUNCTION_VALUE_REGNO_P(REGNO) \ + ((REGNO) == 0 || ((REGNO) == 16) && TARGET_HARD_FLOAT) + +/* How large values are returned */ +/* A C expression which can inhibit the returning of certain function values + in registers, based on the type of value. */ +/* CYGNUS LOCAL */ +#define RETURN_IN_MEMORY(TYPE) arm_return_in_memory (TYPE) +/* END CYGNUS LOCAL */ + +/* Define DEFAULT_PCC_STRUCT_RETURN to 1 if all structure and union return + values must be in memory. On the ARM, they need only do so if larger + than a word, or if they contain elements offset from zero in the struct. */ +#define DEFAULT_PCC_STRUCT_RETURN 0 + +/* Define where to put the arguments to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). + + On the ARM, normally the first 16 bytes are passed in registers r0-r3; all + other arguments are passed on the stack. If (NAMED == 0) (which happens + only in assign_parms, since SETUP_INCOMING_VARARGS is defined), say it is + passed in the stack (function_prologue will indeed make it pass in the + stack if necessary). */ +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + ((NAMED) \ + ? ((CUM) >= 16 ? 0 : gen_rtx (REG, MODE, (CUM) / 4)) \ + : 0) + +/* 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) \ + ((CUM) < 16 && 16 < (CUM) + ((MODE) != BLKmode \ + ? GET_MODE_SIZE (MODE) \ + : int_size_in_bytes (TYPE)) \ + ? 4 - (CUM) / 4 : 0) + +/* A C type for declaring a variable that is used as the first argument of + `FUNCTION_ARG' and other related values. For some target machines, the + type `int' suffices and can hold the number of bytes of argument so far. + + On the ARM, this is the number of bytes of arguments scanned so far. */ +#define CUMULATIVE_ARGS int + +/* 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. + On the ARM, the offset starts at 0. */ +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ + ((CUM) = (((FNTYPE) && aggregate_value_p (TREE_TYPE ((FNTYPE)))) ? 4 : 0)) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + (CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3) \ + +/* 1 if N is a possible register number for function argument passing. + On the ARM, r0-r3 are used to pass args. */ +#define FUNCTION_ARG_REGNO_P(REGNO) \ + ((REGNO) >= 0 && (REGNO) <= 3) + +/* Perform any 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. + + On the ARM, PRETEND_SIZE is set in order to have the prologue push the last + named arg and all anonymous args onto the stack. + XXX I know the prologue shouldn't be pushing registers, but it is faster + that way. */ +#define SETUP_INCOMING_VARARGS(CUM, MODE, TYPE, PRETEND_SIZE, NO_RTL) \ +{ \ + extern int current_function_anonymous_args; \ + current_function_anonymous_args = 1; \ + if ((CUM) < 16) \ + (PRETEND_SIZE) = 16 - (CUM); \ +} + +/* Generate assembly output for the start of a function. */ +#define FUNCTION_PROLOGUE(STREAM, SIZE) \ + output_func_prologue ((STREAM), (SIZE)) + +/* Call the function profiler with a given profile label. The Acorn compiler + puts this BEFORE the prolog but gcc puts it afterwards. The ``mov ip,lr'' + seems like a good idea to stick with cc convention. ``prof'' doesn't seem + to mind about this! */ +#define FUNCTION_PROFILER(STREAM,LABELNO) \ +{ \ + fprintf(STREAM, "\tmov\t%sip, %slr\n", REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf(STREAM, "\tbl\tmcount\n"); \ + fprintf(STREAM, "\t.word\tLP%d\n", (LABELNO)); \ +} + +/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, + the stack pointer does not matter. The value is tested only in + functions that have frame pointers. + No definition is equivalent to always zero. + + On the ARM, the function epilogue recovers the stack pointer from the + frame. */ +#define EXIT_IGNORE_STACK 1 + +/* Generate the assembly code for function exit. */ +#define FUNCTION_EPILOGUE(STREAM, SIZE) \ + output_func_epilogue ((STREAM), (SIZE)) + +/* Determine if the epilogue should be output as RTL. + You should override this if you define FUNCTION_EXTRA_EPILOGUE. */ +#define USE_RETURN_INSN(ISCOND) use_return_insn (ISCOND) + +/* Definitions for register eliminations. + + This is an array of structures. Each structure initializes one pair + of eliminable registers. The "from" register number is given first, + followed by "to". Eliminations of the same "from" register are listed + in order of preference. + + We have two registers that can be eliminated on the ARM. First, the + arg pointer register can often be eliminated in favor of the stack + pointer register. Secondly, the pseudo frame pointer register can always + be eliminated; it is replaced with either the stack or the real frame + pointer. */ + +#define ELIMINABLE_REGS \ +{{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + {ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ + {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + {FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} + +/* Given FROM and TO register numbers, say whether this elimination is allowed. + Frame pointer elimination is automatically handled. + + All eliminations are permissible. Note that ARG_POINTER_REGNUM and + HARD_FRAME_POINTER_REGNUM are in fact the same thing. If we need a frame + pointer, we must eliminate FRAME_POINTER_REGNUM into + HARD_FRAME_POINTER_REGNUM and not into STACK_POINTER_REGNUM. */ +#define CAN_ELIMINATE(FROM, TO) \ + (((TO) == STACK_POINTER_REGNUM && frame_pointer_needed) ? 0 : 1) + +/* Define the offset between two registers, one to be eliminated, and the other + its replacement, at the start of a routine. */ +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ +{ \ + int volatile_func = arm_volatile_func (); \ + if ((FROM) == ARG_POINTER_REGNUM && (TO) == HARD_FRAME_POINTER_REGNUM)\ + (OFFSET) = 0; \ + else if ((FROM) == FRAME_POINTER_REGNUM \ + && (TO) == STACK_POINTER_REGNUM) \ + (OFFSET) = (current_function_outgoing_args_size \ + + (get_frame_size () + 3 & ~3)); \ + else \ + { \ + int regno; \ + int offset = 12; \ + int saved_hard_reg = 0; \ + \ + if (! volatile_func) \ + { \ + for (regno = 0; regno <= 10; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + saved_hard_reg = 1, offset += 4; \ + for (regno = 16; regno <=23; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 12; \ + } \ + if ((FROM) == FRAME_POINTER_REGNUM) \ + (OFFSET) = -offset; \ + else \ + { \ + if (! frame_pointer_needed) \ + offset -= 16; \ + if (! volatile_func \ + && (regs_ever_live[14] || saved_hard_reg)) \ + offset += 4; \ + offset += current_function_outgoing_args_size; \ + (OFFSET) = (get_frame_size () + 3 & ~3) + offset; \ + } \ + } \ +} + +/* CYGNUS LOCAL */ +/* Special case handling of the location of arguments passed on the stack. */ +#define DEBUGGER_ARG_OFFSET(value, addr) value ? value : arm_debugger_arg_offset (value, addr) +/* END CYGNUS LOCAL */ + +/* Output assembler code for a block containing the constant parts + of a trampoline, leaving space for the variable parts. + + On the ARM, (if r8 is the static chain regnum, and remembering that + referencing pc adds an offset of 8) the trampoline looks like: + ldr r8, [pc, #0] + ldr pc, [pc] + .word static chain value + .word function's address + ??? FIXME: When the trampoline returns, r8 will be clobbered. */ +#define TRAMPOLINE_TEMPLATE(FILE) \ +{ \ + fprintf ((FILE), "\tldr\t%sr8, [%spc, #0]\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\tldr\t%spc, [%spc, #0]\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\t.word\t0\n"); \ + fprintf ((FILE), "\t.word\t0\n"); \ +} + +/* Length in units of the trampoline for entering a nested function. */ +#define TRAMPOLINE_SIZE 16 + +/* Alignment required for a trampoline in units. */ +#define TRAMPOLINE_ALIGN 4 + +/* Emit RTL insns to initialize the variable parts of a trampoline. + FNADDR is an RTX for the address of the function's pure code. + CXT is an RTX for the static chain value for the function. */ +#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ +{ \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 8)), \ + (CXT)); \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 12)), \ + (FNADDR)); \ +} + + +/* Addressing modes, and classification of registers for them. */ + +#define HAVE_POST_INCREMENT 1 +#define HAVE_PRE_INCREMENT 1 +#define HAVE_POST_DECREMENT 1 +#define HAVE_PRE_DECREMENT 1 + +/* Macros to check register numbers against specific register classes. */ + +/* These assume that REGNO is a hard or pseudo reg number. + They give nonzero only if REGNO is a hard reg of the suitable class + or a pseudo reg currently allocated to a suitable hard reg. + Since they use reg_renumber, they are safe only once reg_renumber + has been allocated, which happens in local-alloc.c. + + On the ARM, don't allow the pc to be used. */ +#define REGNO_OK_FOR_BASE_P(REGNO) \ + ((REGNO) < 15 || (REGNO) == FRAME_POINTER_REGNUM \ + || (REGNO) == ARG_POINTER_REGNUM \ + || (unsigned) reg_renumber[(REGNO)] < 15 \ + || (unsigned) reg_renumber[(REGNO)] == FRAME_POINTER_REGNUM \ + || (unsigned) reg_renumber[(REGNO)] == ARG_POINTER_REGNUM) +#define REGNO_OK_FOR_INDEX_P(REGNO) \ + REGNO_OK_FOR_BASE_P(REGNO) + +/* Maximum number of registers that can appear in a valid memory address. + Shifts in addresses can't be by a register. */ + +#define MAX_REGS_PER_ADDRESS 2 + +/* Recognize any constant value that is a valid address. */ +/* XXX We can address any constant, eventually... */ + +#ifdef AOF_ASSEMBLER + +#define CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == SYMBOL_REF \ + && CONSTANT_POOL_ADDRESS_P (X)) + +#else + +#define CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == SYMBOL_REF \ + && (CONSTANT_POOL_ADDRESS_P (X) \ + || (optimize > 0 && SYMBOL_REF_FLAG (X)))) + +#endif /* AOF_ASSEMBLER */ + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. + + On the ARM, allow any integer (invalid ones are removed later by insn + patterns), nice doubles and symbol_refs which refer to the function's + constant pool XXX. */ +#define LEGITIMATE_CONSTANT_P(X) (! label_mentioned_p (X)) + +/* Symbols in the text segment can be accessed without indirecting via the + constant pool; it may take an extra binary operation, but this is still + faster than indirecting via memory. Don't do this when not optimizing, + since we won't be calculating al of the offsets necessary to do this + simplification. */ +/* This doesn't work with AOF syntax, since the string table may be in + a different AREA. */ +#ifndef AOF_ASSEMBLER +#define ENCODE_SECTION_INFO(decl) \ +{ \ + if (optimize > 0 && TREE_CONSTANT (decl) \ + && (!flag_writable_strings || TREE_CODE (decl) != STRING_CST)) \ + { \ + rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd' \ + ? TREE_CST_RTL (decl) : DECL_RTL (decl)); \ + SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1; \ + } \ +} +#endif + +/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx + and check its validity for a certain class. + We have two alternate definitions for each of them. + The usual definition accepts all pseudo regs; the other rejects + them unless they have been allocated suitable hard regs. + The symbol REG_OK_STRICT causes the latter definition to be used. */ +#ifndef REG_OK_STRICT + +/* Nonzero if X is a hard reg that can be used as a base reg + or if it is a pseudo reg. */ +#define REG_OK_FOR_BASE_P(X) \ + (REGNO (X) < 16 || REGNO (X) >= FIRST_PSEUDO_REGISTER \ + || REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM) + +/* Nonzero if X is a hard reg that can be used as an index + or if it is a pseudo reg. */ +#define REG_OK_FOR_INDEX_P(X) \ + REG_OK_FOR_BASE_P(X) + +#define REG_OK_FOR_PRE_POST_P(X) \ + (REGNO (X) < 16 || REGNO (X) >= FIRST_PSEUDO_REGISTER \ + || REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM) + +#else + +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + +/* Nonzero if X is a hard reg that can be used as an index. */ +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) + +#define REG_OK_FOR_PRE_POST_P(X) \ + (REGNO (X) < 16 || (unsigned) reg_renumber[REGNO (X)] < 16 \ + || REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO (X)] == FRAME_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO (X)] == ARG_POINTER_REGNUM) + +#endif + +/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression + that is a valid memory address for an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS. */ +#define BASE_REGISTER_RTX_P(X) \ + (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) + +#define INDEX_REGISTER_RTX_P(X) \ + (GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X)) + +/* A C statement (sans semicolon) to jump to LABEL for legitimate index RTXs + used by the macro GO_IF_LEGITIMATE_ADDRESS. Floating point indices can + only be small constants. */ +#define GO_IF_LEGITIMATE_INDEX(MODE, BASE_REGNO, INDEX, LABEL) \ +do \ +{ \ + HOST_WIDE_INT range; \ + enum rtx_code code = GET_CODE (INDEX); \ + \ + if (TARGET_HARD_FLOAT && GET_MODE_CLASS (MODE) == MODE_FLOAT) \ + { \ + if (code == CONST_INT && INTVAL (INDEX) < 1024 \ + && INTVAL (INDEX) > -1024 \ + && (INTVAL (INDEX) & 3) == 0) \ + goto LABEL; \ + } \ + else \ + { \ + if (INDEX_REGISTER_RTX_P (INDEX) && GET_MODE_SIZE (MODE) <= 4) \ + goto LABEL; \ + if (GET_MODE_SIZE (MODE) <= 4 && code == MULT \ + && (! arm_arch4 || (MODE) != HImode)) \ + { \ + rtx xiop0 = XEXP (INDEX, 0); \ + rtx xiop1 = XEXP (INDEX, 1); \ + if (INDEX_REGISTER_RTX_P (xiop0) \ + && power_of_two_operand (xiop1, SImode)) \ + goto LABEL; \ + if (INDEX_REGISTER_RTX_P (xiop1) \ + && power_of_two_operand (xiop0, SImode)) \ + goto LABEL; \ + } \ + if (GET_MODE_SIZE (MODE) <= 4 \ + && (code == LSHIFTRT || code == ASHIFTRT \ + || code == ASHIFT || code == ROTATERT) \ + && (! arm_arch4 || (MODE) != HImode)) \ + { \ + rtx op = XEXP (INDEX, 1); \ + if (INDEX_REGISTER_RTX_P (XEXP (INDEX, 0)) \ + && GET_CODE (op) == CONST_INT && INTVAL (op) > 0 \ + && INTVAL (op) <= 31) \ + goto LABEL; \ + } \ + /* NASTY: Since this limits the addressing of unsigned byte loads */ \ + range = ((MODE) == HImode || (MODE) == QImode) \ + ? (arm_arch4 ? 256 : 4095) : 4096; \ + if (code == CONST_INT && INTVAL (INDEX) < range \ + && INTVAL (INDEX) > -range) \ + goto LABEL; \ + } \ +} while (0) + +/* Jump to LABEL if X is a valid address RTX. This must also take + REG_OK_STRICT into account when deciding about valid registers, but it uses + the above macros so we are in luck. Allow REG, REG+REG, REG+INDEX, + INDEX+REG, REG-INDEX, and non floating SYMBOL_REF to the constant pool. + Allow REG-only and AUTINC-REG if handling TImode or HImode. Other symbol + refs must be forced though a static cell to ensure addressability. */ +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \ +{ \ + if (BASE_REGISTER_RTX_P (X)) \ + goto LABEL; \ + else if ((GET_CODE (X) == POST_INC || GET_CODE (X) == PRE_DEC) \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_PRE_POST_P (XEXP (X, 0))) \ + goto LABEL; \ + else if (GET_MODE_SIZE (MODE) >= 4 && reload_completed \ + && (GET_CODE (X) == LABEL_REF \ + || (GET_CODE (X) == CONST \ + && GET_CODE (XEXP ((X), 0)) == PLUS \ + && GET_CODE (XEXP (XEXP ((X), 0), 0)) == LABEL_REF \ + && GET_CODE (XEXP (XEXP ((X), 0), 1)) == CONST_INT)))\ + goto LABEL; \ + else if ((MODE) == TImode) \ + ; \ + else if ((MODE) == DImode || (TARGET_SOFT_FLOAT && (MODE) == DFmode)) \ + { \ + if (GET_CODE (X) == PLUS && BASE_REGISTER_RTX_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT) \ + { \ + HOST_WIDE_INT val = INTVAL (XEXP (X, 1)); \ + if (val == 4 || val == -4 || val == -8) \ + goto LABEL; \ + } \ + } \ + else if (GET_CODE (X) == PLUS) \ + { \ + rtx xop0 = XEXP(X,0); \ + rtx xop1 = XEXP(X,1); \ + \ + if (BASE_REGISTER_RTX_P (xop0)) \ + GO_IF_LEGITIMATE_INDEX (MODE, REGNO (xop0), xop1, LABEL); \ + else if (BASE_REGISTER_RTX_P (xop1)) \ + GO_IF_LEGITIMATE_INDEX (MODE, REGNO (xop1), xop0, LABEL); \ + } \ + /* Reload currently can't handle MINUS, so disable this for now */ \ + /* else if (GET_CODE (X) == MINUS) \ + { \ + rtx xop0 = XEXP (X,0); \ + rtx xop1 = XEXP (X,1); \ + \ + if (BASE_REGISTER_RTX_P (xop0)) \ + GO_IF_LEGITIMATE_INDEX (MODE, -1, xop1, LABEL); \ + } */ \ + else if (GET_MODE_CLASS (MODE) != MODE_FLOAT \ + && GET_CODE (X) == SYMBOL_REF \ + && CONSTANT_POOL_ADDRESS_P (X)) \ + goto LABEL; \ + else if ((GET_CODE (X) == PRE_INC || GET_CODE (X) == POST_DEC) \ + && (GET_MODE_SIZE (MODE) <= 4) \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_PRE_POST_P (XEXP (X, 0))) \ + goto LABEL; \ +} + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. + + On the ARM, try to convert [REG, #BIGCONST] + into ADD BASE, REG, #UPPERCONST and [BASE, #VALIDCONST], + where VALIDCONST == 0 in case of TImode. */ +extern struct rtx_def *legitimize_pic_address (); +#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ +{ \ + if (GET_CODE (X) == PLUS) \ + { \ + rtx xop0 = XEXP (X, 0); \ + rtx xop1 = XEXP (X, 1); \ + \ + if (CONSTANT_P (xop0) && ! symbol_mentioned_p (xop0)) \ + xop0 = force_reg (SImode, xop0); \ + if (CONSTANT_P (xop1) && ! symbol_mentioned_p (xop1)) \ + xop1 = force_reg (SImode, xop1); \ + if (BASE_REGISTER_RTX_P (xop0) && GET_CODE (xop1) == CONST_INT) \ + { \ + HOST_WIDE_INT n, low_n; \ + rtx base_reg, val; \ + n = INTVAL (xop1); \ + \ + if (MODE == DImode || (TARGET_SOFT_FLOAT && MODE == DFmode)) \ + { \ + low_n = n & 0x0f; \ + n &= ~0x0f; \ + if (low_n > 4) \ + { \ + n += 16; \ + low_n -= 16; \ + } \ + } \ + else \ + { \ + low_n = ((MODE) == TImode ? 0 \ + : n >= 0 ? (n & 0xfff) : -((-n) & 0xfff)); \ + n -= low_n; \ + } \ + base_reg = gen_reg_rtx (SImode); \ + val = force_operand (gen_rtx (PLUS, SImode, xop0, \ + GEN_INT (n)), NULL_RTX); \ + emit_move_insn (base_reg, val); \ + (X) = (low_n == 0 ? base_reg \ + : gen_rtx (PLUS, SImode, base_reg, GEN_INT (low_n))); \ + } \ + else if (xop0 != XEXP (X, 0) || xop1 != XEXP (x, 1)) \ + (X) = gen_rtx (PLUS, SImode, xop0, xop1); \ + } \ + else if (GET_CODE (X) == MINUS) \ + { \ + rtx xop0 = XEXP (X, 0); \ + rtx xop1 = XEXP (X, 1); \ + \ + if (CONSTANT_P (xop0)) \ + xop0 = force_reg (SImode, xop0); \ + if (CONSTANT_P (xop1) && ! symbol_mentioned_p (xop1)) \ + xop1 = force_reg (SImode, xop1); \ + if (xop0 != XEXP (X, 0) || xop1 != XEXP (X, 1)) \ + (X) = gen_rtx (MINUS, SImode, xop0, xop1); \ + } \ + if (flag_pic) \ + (X) = legitimize_pic_address (OLDX, MODE, NULL_RTX); \ + if (memory_address_p (MODE, X)) \ + goto WIN; \ +} + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. */ +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ +{ \ + if (GET_CODE(ADDR) == PRE_DEC || GET_CODE(ADDR) == POST_DEC \ + || GET_CODE(ADDR) == PRE_INC || GET_CODE(ADDR) == POST_INC) \ + goto LABEL; \ +} + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE SImode + +/* 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 */ + +/* Specify the tree operation to be used to convert reals to integers. */ +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* This is the kind of divide that is easiest to do in the general case. */ +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* signed 'char' is most compatible, but RISC OS wants it unsigned. + unsigned is probably best, but may break some code. */ +#ifndef DEFAULT_SIGNED_CHAR +#define DEFAULT_SIGNED_CHAR 0 +#endif + +/* Don't cse the address of the function being compiled. */ +#define NO_RECURSIVE_FUNCTION_CSE 1 + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 4 + +/* Define if operations between registers always perform the operation + on the full register even if a narrower mode is specified. */ +#define WORD_REGISTER_OPERATIONS + +/* Define if loading in MODE, an integral mode narrower than BITS_PER_WORD + will either zero-extend or sign-extend. The value of this macro should + be the code that says which one of the two operations is implicitly + done, NIL if none. */ +#define LOAD_EXTEND_OP(MODE) \ + ((arm_arch4 || (MODE) == QImode) ? ZERO_EXTEND \ + : ((BYTES_BIG_ENDIAN && (MODE) == HImode) ? SIGN_EXTEND : NIL)) + +/* Define this if zero-extension is slow (more than one real instruction). + On the ARM, it is more than one instruction only if not fetching from + memory. */ +/* #define SLOW_ZERO_EXTEND */ + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* Immediate shift counts are truncated by the output routines (or was it + the assembler?). Shift counts in a register are truncated by ARM. Note + that the native compiler puts too large (> 32) immediate shift counts + into a register and shifts by the register, letting the ARM decide what + to do instead of doing that itself. */ +/* This is all wrong. Defining SHIFT_COUNT_TRUNCATED tells combine that + code like (X << (Y % 32)) for register X, Y is equivalent to (X << Y). + On the arm, Y in a register is used modulo 256 for the shift. Only for + rotates is modulo 32 used. */ +/* #define SHIFT_COUNT_TRUNCATED 1 */ + +/* All integers have the same format so truncation is easy. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) 1 + +/* Calling from registers is a massive pain. */ +#define NO_FUNCTION_CSE 1 + +/* Chars and shorts should be passed as ints. */ +#define PROMOTE_PROTOTYPES 1 + +/* The machine modes of pointers and functions */ +#define Pmode SImode +#define FUNCTION_MODE Pmode + +/* The structure type of the machine dependent info field of insns + No uses for this yet. */ +/* #define INSN_MACHINE_INFO struct machine_info */ + +/* The relative costs of various types of constants. Note that cse.c defines + REG = 1, SUBREG = 2, any node = (2 + sum of subnodes). */ +#define CONST_COSTS(RTX, CODE, OUTER_CODE) \ + case CONST_INT: \ + if (const_ok_for_arm (INTVAL (RTX))) \ + return (OUTER_CODE) == SET ? 2 : -1; \ + else if (OUTER_CODE == AND \ + && const_ok_for_arm (~INTVAL (RTX))) \ + return -1; \ + else if ((OUTER_CODE == COMPARE \ + || OUTER_CODE == PLUS || OUTER_CODE == MINUS) \ + && const_ok_for_arm (-INTVAL (RTX))) \ + return -1; \ + else \ + return 5; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 6; \ + case CONST_DOUBLE: \ + if (const_double_rtx_ok_for_fpu (RTX)) \ + return (OUTER_CODE) == SET ? 2 : -1; \ + else if (((OUTER_CODE) == COMPARE || (OUTER_CODE) == PLUS) \ + && neg_const_double_rtx_ok_for_fpu (RTX)) \ + return -1; \ + return(7); + +#define ARM_FRAME_RTX(X) \ + ((X) == frame_pointer_rtx || (X) == stack_pointer_rtx \ + || (X) == arg_pointer_rtx) + +#define DEFAULT_RTX_COSTS(X,CODE,OUTER_CODE) \ + return arm_rtx_costs (X, CODE, OUTER_CODE); + +/* Moves to and from memory are quite expensive */ +#define MEMORY_MOVE_COST(MODE,CLASS,IN) 10 + +/* All address computations that can be done are free, but rtx cost returns + the same for practically all of them. So we weight the different types + of address here in the order (most pref first): + PRE/POST_INC/DEC, SHIFT or NON-INT sum, INT sum, REG, MEM or LABEL. */ +#define ADDRESS_COST(X) \ + (10 - ((GET_CODE (X) == MEM || GET_CODE (X) == LABEL_REF \ + || GET_CODE (X) == SYMBOL_REF) \ + ? 0 \ + : ((GET_CODE (X) == PRE_INC || GET_CODE (X) == PRE_DEC \ + || GET_CODE (X) == POST_INC || GET_CODE (X) == POST_DEC) \ + ? 10 \ + : (((GET_CODE (X) == PLUS || GET_CODE (X) == MINUS) \ + ? 6 + (GET_CODE (XEXP (X, 1)) == CONST_INT ? 2 \ + : ((GET_RTX_CLASS (GET_CODE (XEXP (X, 0))) == '2' \ + || GET_RTX_CLASS (GET_CODE (XEXP (X, 0))) == 'c' \ + || GET_RTX_CLASS (GET_CODE (XEXP (X, 1))) == '2' \ + || GET_RTX_CLASS (GET_CODE (XEXP (X, 1))) == 'c') \ + ? 1 : 0)) \ + : 4))))) + + + +/* Try to generate sequences that don't involve branches, we can then use + conditional instructions */ +#define BRANCH_COST 4 + +/* A C statement to update the variable COST based on the relationship + between INSN that is dependent on DEP through dependence LINK. */ +#define ADJUST_COST(INSN,LINK,DEP,COST) \ + (COST) = arm_adjust_cost ((INSN), (LINK), (DEP), (COST)) + +/* Position Independent Code. */ +/* We decide which register to use based on the compilation options and + the assembler in use; this is more general than the APCS restriction of + using sb (r9) all the time. */ +extern int arm_pic_register; + +/* The register number of the register used to address a table of static + data addresses in memory. */ +#define PIC_OFFSET_TABLE_REGNUM arm_pic_register + +#define FINALIZE_PIC arm_finalize_pic () + +#define LEGITIMATE_PIC_OPERAND_P(X) (! symbol_mentioned_p (X)) + + + +/* Condition code information. */ +/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, + return the mode to be used for the comparison. + CCFPEmode should be used with floating inequalities, + CCFPmode should be used with floating equalities. + CC_NOOVmode should be used with SImode integer equalities. + CC_Zmode should be used if only the Z flag is set correctly + CCmode should be used otherwise. */ + +#define EXTRA_CC_MODES CC_NOOVmode, CC_Zmode, CC_SWPmode, \ + CCFPmode, CCFPEmode, CC_DNEmode, CC_DEQmode, CC_DLEmode, \ + CC_DLTmode, CC_DGEmode, CC_DGTmode, CC_DLEUmode, CC_DLTUmode, \ + CC_DGEUmode, CC_DGTUmode, CC_Cmode + +#define EXTRA_CC_NAMES "CC_NOOV", "CC_Z", "CC_SWP", "CCFP", "CCFPE", \ + "CC_DNE", "CC_DEQ", "CC_DLE", "CC_DLT", "CC_DGE", "CC_DGT", "CC_DLEU", \ + "CC_DLTU", "CC_DGEU", "CC_DGTU", "CC_C" + +enum machine_mode arm_select_cc_mode (); +#define SELECT_CC_MODE(OP,X,Y) arm_select_cc_mode ((OP), (X), (Y)) + +#define REVERSIBLE_CC_MODE(MODE) ((MODE) != CCFPEmode) + +enum rtx_code arm_canonicalize_comparison (); +#define CANONICALIZE_COMPARISON(CODE,OP0,OP1) \ +do \ +{ \ + if (GET_CODE (OP1) == CONST_INT \ + && ! (const_ok_for_arm (INTVAL (OP1)) \ + || (const_ok_for_arm (- INTVAL (OP1))))) \ + { \ + rtx const_op = OP1; \ + CODE = arm_canonicalize_comparison ((CODE), &const_op); \ + OP1 = const_op; \ + } \ +} while (0) + +#define STORE_FLAG_VALUE 1 + +/* Define the information needed to generate branch insns. This is + stored from the compare operation. Note that we can't use "rtx" here + since it hasn't been defined! */ + +extern struct rtx_def *arm_compare_op0, *arm_compare_op1; +extern int arm_compare_fp; + +/* Define the codes that are matched by predicates in arm.c */ +#define PREDICATE_CODES \ + {"s_register_operand", {SUBREG, REG}}, \ + {"f_register_operand", {SUBREG, REG}}, \ + {"arm_add_operand", {SUBREG, REG, CONST_INT}}, \ + {"fpu_add_operand", {SUBREG, REG, CONST_DOUBLE}}, \ + {"arm_rhs_operand", {SUBREG, REG, CONST_INT}}, \ + {"fpu_rhs_operand", {SUBREG, REG, CONST_DOUBLE}}, \ + {"arm_not_operand", {SUBREG, REG, CONST_INT}}, \ + {"offsettable_memory_operand", {MEM}}, \ + {"bad_signed_byte_operand", {MEM}}, \ + {"alignable_memory_operand", {MEM}}, \ + {"shiftable_operator", {PLUS, MINUS, AND, IOR, XOR}}, \ + {"minmax_operator", {SMIN, SMAX, UMIN, UMAX}}, \ + {"shift_operator", {ASHIFT, ASHIFTRT, LSHIFTRT, ROTATERT, MULT}}, \ + {"di_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE, MEM}}, \ + {"soft_df_operand", {SUBREG, REG, CONST_DOUBLE, MEM}}, \ + {"load_multiple_operation", {PARALLEL}}, \ + {"store_multiple_operation", {PARALLEL}}, \ + {"equality_operator", {EQ, NE}}, \ + {"arm_rhsm_operand", {SUBREG, REG, CONST_INT, MEM}}, \ + {"const_shift_operand", {CONST_INT}}, \ + {"index_operand", {SUBREG, REG, CONST_INT}}, \ + {"reg_or_int_operand", {SUBREG, REG, CONST_INT}}, \ + {"multi_register_push", {PARALLEL}}, \ + {"cc_register", {REG}}, \ + {"dominant_cc_register", {REG}}, + + + +/* Gcc puts the pool in the wrong place for ARM, since we can only + load addresses a limited distance around the pc. We do some + special munging to move the constant pool values to the correct + point in the code. */ +#define MACHINE_DEPENDENT_REORG(INSN) arm_reorg ((INSN)) + +/* The pool is empty, since we have moved everything into the code. */ +#define ASM_OUTPUT_SPECIAL_POOL_ENTRY(FILE,X,MODE,ALIGN,LABELNO,JUMPTO) \ + goto JUMPTO + +/* Output an internal label definition. */ +#ifndef ASM_OUTPUT_INTERNAL_LABEL +#define ASM_OUTPUT_INTERNAL_LABEL(STREAM, PREFIX, NUM) \ + do \ + { \ + char * s = (char *) alloca (40 + strlen (PREFIX)); \ + extern int arm_target_label, arm_ccfsm_state; \ + extern rtx arm_target_insn; \ + \ + if (arm_ccfsm_state == 3 && arm_target_label == (NUM) \ + && !strcmp (PREFIX, "L")) \ + { \ + arm_ccfsm_state = 0; \ + arm_target_insn = NULL; \ + } \ + ASM_GENERATE_INTERNAL_LABEL (s, (PREFIX), (NUM)); \ + /* CYGNUS LOCAL variation */ \ + arm_asm_output_label (STREAM, s); \ + /* END CYGNUS LOCAL variation */ \ + } while (0) +#endif + +/* CYGNUS LOCAL */ +/* Output a label definition. */ +#undef ASM_OUTPUT_LABEL +#define ASM_OUTPUT_LABEL(STREAM,NAME) arm_asm_output_label ((STREAM), (NAME)) +/* END CYGNUS LOCAL */ + +/* Output a push or a pop instruction (only used when profiling). */ +#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ + fprintf (STREAM,"\tstmfd\t%ssp!,{%s%s}\n", \ + REGISTER_PREFIX, REGISTER_PREFIX, reg_names [REGNO]) + +#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \ + fprintf (STREAM,"\tldmfd\t%ssp!,{%s%s}\n", \ + REGISTER_PREFIX, REGISTER_PREFIX, reg_names [REGNO]) + +/* Target characters. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* Only perform branch elimination (by making instructions conditional) if + we're optimising. Otherwise it's of no use anyway. */ +#define FINAL_PRESCAN_INSN(INSN, OPVEC, NOPERANDS) \ + if (optimize) \ + final_prescan_insn (INSN, OPVEC, NOPERANDS) + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '?' || (CODE) == '|' || (CODE) == '@') +/* Output an operand of an instruction. */ +#define PRINT_OPERAND(STREAM, X, CODE) \ + arm_print_operand (STREAM, X, CODE) + +#define ARM_SIGN_EXTEND(x) ((HOST_WIDE_INT) \ + (HOST_BITS_PER_WIDE_INT <= 32 ? (x) \ + : (((x) & (unsigned HOST_WIDE_INT) 0xffffffff) | \ + (((x) & (unsigned HOST_WIDE_INT) 0x80000000) \ + ? ((~ (HOST_WIDE_INT) 0) \ + & ~ (unsigned HOST_WIDE_INT) 0xffffffff) \ + : 0)))) + +/* Output the address of an operand. */ +#define PRINT_OPERAND_ADDRESS(STREAM,X) \ +{ \ + int is_minus = GET_CODE (X) == MINUS; \ + \ + if (GET_CODE (X) == REG) \ + fprintf (STREAM, "[%s%s, #0]", REGISTER_PREFIX, \ + reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == PLUS || is_minus) \ + { \ + rtx base = XEXP (X, 0); \ + rtx index = XEXP (X, 1); \ + char * base_reg_name; \ + HOST_WIDE_INT offset = 0; \ + if (GET_CODE (base) != REG) \ + { \ + /* Ensure that BASE is a register (one of them must be). */ \ + rtx temp = base; \ + base = index; \ + index = temp; \ + } \ + base_reg_name = reg_names[REGNO (base)]; \ + switch (GET_CODE (index)) \ + { \ + case CONST_INT: \ + offset = INTVAL (index); \ + if (is_minus) \ + offset = -offset; \ + fprintf (STREAM, "[%s%s, #%d]", REGISTER_PREFIX, \ + base_reg_name, offset); \ + break; \ + \ + case REG: \ + fprintf (STREAM, "[%s%s, %s%s%s]", REGISTER_PREFIX, \ + base_reg_name, is_minus ? "-" : "", \ + REGISTER_PREFIX, reg_names[REGNO (index)] ); \ + break; \ + \ + case MULT: \ + case ASHIFTRT: \ + case LSHIFTRT: \ + case ASHIFT: \ + case ROTATERT: \ + { \ + fprintf (STREAM, "[%s%s, %s%s%s", REGISTER_PREFIX, \ + base_reg_name, is_minus ? "-" : "", REGISTER_PREFIX,\ + reg_names[REGNO (XEXP (index, 0))]); \ + arm_print_operand (STREAM, index, 'S'); \ + fputs ("]", STREAM); \ + break; \ + } \ + \ + default: \ + abort(); \ + } \ + } \ + else if (GET_CODE (X) == PRE_INC || GET_CODE (X) == POST_INC \ + || GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_DEC) \ + { \ + extern int output_memory_reference_mode; \ + \ + if (GET_CODE (XEXP (X, 0)) != REG) \ + abort (); \ + \ + if (GET_CODE (X) == PRE_DEC || GET_CODE (X) == PRE_INC) \ + fprintf (STREAM, "[%s%s, #%s%d]!", REGISTER_PREFIX, \ + reg_names[REGNO (XEXP (X, 0))], \ + GET_CODE (X) == PRE_DEC ? "-" : "", \ + GET_MODE_SIZE (output_memory_reference_mode)); \ + else \ + fprintf (STREAM, "[%s%s], #%s%d", REGISTER_PREFIX, \ + reg_names[REGNO (XEXP (X, 0))], \ + GET_CODE (X) == POST_DEC ? "-" : "", \ + GET_MODE_SIZE (output_memory_reference_mode)); \ + } \ + else output_addr_const(STREAM, X); \ +} + +/* Handles PIC addr specially */ +#define OUTPUT_INT_ADDR_CONST(STREAM,X) \ + { \ + if (flag_pic && GET_CODE(X) == CONST && is_pic(X)) \ + { \ + output_addr_const(STREAM, XEXP (XEXP (XEXP (X, 0), 0), 0)); \ + fputs(" - (", STREAM); \ + output_addr_const(STREAM, XEXP (XEXP (XEXP (X, 0), 1), 0)); \ + fputs(")", STREAM); \ + } \ + else output_addr_const(STREAM, X); \ + } + +/* Output code to add DELTA to the first argument, and then jump to FUNCTION. + Used for C++ multiple inheritance. */ +#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ +do { \ + int mi_delta = (DELTA); \ + char *mi_op = mi_delta < 0 ? "sub" : "add"; \ + int shift = 0; \ + int this_regno = (aggregate_value_p (TREE_TYPE (TREE_TYPE (FUNCTION))) \ + ? 1 : 0); \ + if (mi_delta < 0) mi_delta = -mi_delta; \ + while (mi_delta != 0) \ + { \ + if (mi_delta & (3 << shift) == 0) \ + shift += 2; \ + else \ + { \ + fprintf (FILE, "\t%s\t%s%s, %s%s, #%d\n", \ + mi_op, REGISTER_PREFIX, reg_names[this_regno], \ + REGISTER_PREFIX, reg_names[this_regno], \ + mi_delta & (0xff << shift)); \ + /* CYGNUS LOCAL */ \ + arm_increase_location (4); \ + /* END CYGNUS LOCAL */ \ + mi_delta &= ~(0xff << shift); \ + shift += 8; \ + } \ + } \ + fputs ("\tb\t", FILE); \ + assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ + fputc ('\n', FILE); \ + /* CYGNUS LOCAL */ \ + arm_increase_location (4); \ + /* END CYGNUS LOCAL */ \ +} while (0) + +/* A C expression whose value is RTL representing the value of the return + address for the frame COUNT steps up from the current frame. */ + +#define RETURN_ADDR_RTX(COUNT, FRAME) \ + ((COUNT == 0) \ + ? gen_rtx (MEM, Pmode, plus_constant (FRAME, -4)) \ + : NULL_RTX) + +/* Used to mask out junk bits from the return address, such as + processor state, interrupt status, condition codes and the like. */ +#define MASK_RETURN_ADDR \ + /* If we are generating code for an ARM2/ARM3 machine or for an ARM6 \ + in 26 bit mode, the condition codes must be masked out of the \ + return address. This does not apply to ARM6 and later processors \ + when running in 32 bit mode. */ \ + ((!TARGET_APCS_32) ? (GEN_INT (0x03fffffc)) : (GEN_INT (0xffffffff))) + +/* Prototypes for arm.c -- actually, they aren't since the types aren't + fully defined yet. */ + +void arm_override_options (/* void */); +int use_return_insn (/* void */); +int const_ok_for_arm (/* HOST_WIDE_INT */); +int const_ok_for_op (/* HOST_WIDE_INT, enum rtx_code, + enum machine_mode */); +int arm_split_constant (/* enum rtx_code, enum machine_mode, + HOST_WIDE_INT, struct rtx_def *, + struct rtx_def *, int */); +enum rtx_code arm_canonicalize_comparison (/* enum rtx_code, + struct rtx_def ** */); +int arm_return_in_memory (/* union tree_node * */); +int legitimate_pic_operand_p (/* struct rtx_def * */); +struct rtx_def *legitimize_pic_address (/* struct rtx_def *, + enum machine_mode, + struct rtx_def * */); +int is_pic (/* struct rtx_def * */); +void arm_finalize_pic (/* void */); +int arm_rtx_costs (/* struct rtx_def *, enum rtx_code, enum rtx_code */); +int arm_adjust_cost (/* struct rtx_def *, struct rtx_def *, + struct rtx_def *, int */); +int const_double_rtx_ok_for_fpu (/* struct rtx_def * */); +int neg_const_double_rtx_ok_for_fpu (/* struct rtx_def * */); +int s_register_operand (/* struct rtx_def *, enum machine_mode */); +int f_register_operand (/* struct rtx_def *, enum machine_mode */); +int reg_or_int_operand (/* struct rtx_def *, enum machine_mode */); +int reload_memory_operand (/* struct rtx_def *, enum machine_mode */); +int arm_rhs_operand (/* struct rtx_def *, enum machine_mode */); +int arm_rhsm_operand (/* struct rtx_def *, enum machine_mode */); +int arm_add_operand (/* struct rtx_def *, enum machine_mode */); +int arm_not_operand (/* struct rtx_def *, enum machine_mode */); +int offsettable_memory_operand (/* struct rtx_def *, enum machine_mode */); +int alignable_memory_operand (/* struct rtx_def *, enum machine_mode */); +int bad_signed_byte_operand (/* struct rtx_def *, enum machine_mode */); +int fpu_rhs_operand (/* struct rtx_def *, enum machine_mode */); +int fpu_add_operand (/* struct rtx_def *, enum machine_mode */); +int power_of_two_operand (/* struct rtx_def *, enum machine_mode */); +int di_operand (/* struct rtx_def *, enum machine_mode */); +int soft_df_operand (/* struct rtx_def *, enum machine_mode */); +int index_operand (/* struct rtx_def *, enum machine_mode */); +int const_shift_operand (/* struct rtx_def *, enum machine_mode */); +int shiftable_operator (/* struct rtx_def *, enum machine_mode */); +int shift_operator (/* struct rtx_def *, enum machine_mode */); +int equality_operator (/* struct rtx_def *, enum machine_mode */); +int minmax_operator (/* struct rtx_def *, enum machine_mode */); +int cc_register (/* struct rtx_def *, enum machine_mode */); +int dominant_cc_register (/* struct rtx_def *, enum machine_mode */); +int symbol_mentioned_p (/* struct rtx_def * */); +int label_mentioned_p (/* struct rtx_def * */); +enum rtx_code minmax_code (/* struct rtx_def * */); +int adjacent_mem_locations (/* struct rtx_def *, struct rtx_def * */); +int load_multiple_operation (/* struct rtx_def *, enum machine_mode */); +int store_multiple_operation (/* struct rtx_def *, enum machine_mode */); +int load_multiple_sequence (/* struct rtx_def **, int, int *, int *, + HOST_WIDE_INT * */); +char *emit_ldm_seq (/* struct rtx_def **, int */); +int store_multiple_sequence (/* struct rtx_def **, int, int *, int *, + HOST_WIDE_INT * */); +char *emit_stm_seq (/* struct rtx_def **, int */); +int multi_register_push (/* struct rtx_def *, enum machine_mode */); +int arm_valid_machine_decl_attribute (/* union tree_node *, union tree_node *, + union tree_node *, + union tree_node * */); +struct rtx_def *arm_gen_load_multiple (/* int, int, struct rtx_def *, + int, int, int, int, int */); +struct rtx_def *arm_gen_store_multiple (/* int, int, struct rtx_def *, + int, int, int, int, int */); +int arm_gen_movstrqi (/* struct rtx_def ** */); +struct rtx_def *gen_rotated_half_load (/* struct rtx_def * */); +enum machine_mode arm_select_cc_mode (/* enum rtx_code, struct rtx_def *, + struct rtx_def * */); +struct rtx_def *gen_compare_reg (/* enum rtx_code, struct rtx_def *, + struct rtx_def * */); +void arm_reload_in_hi (/* struct rtx_def ** */); +void arm_reload_out_hi (/* struct rtx_def ** */); +void arm_reorg (/* struct rtx_def * */); +char *fp_immediate_constant (/* struct rtx_def * */); +void print_multi_reg (/* FILE *, char *, int, int */); +char *output_call (/* struct rtx_def ** */); +char *output_call_mem (/* struct rtx_def ** */); +char *output_mov_long_double_fpu_from_arm (/* struct rtx_def ** */); +char *output_mov_long_double_arm_from_fpu (/* struct rtx_def ** */); +char *output_mov_long_double_arm_from_arm (/* struct rtx_def ** */); +char *output_mov_double_fpu_from_arm (/* struct rtx_def ** */); +char *output_mov_double_arm_from_fpu (/* struct rtx_def ** */); +char *output_move_double (/* struct rtx_def ** */); +char *output_mov_immediate (/* struct rtx_def ** */); +char *output_add_immediate (/* struct rtx_def ** */); +char *arithmetic_instr (/* struct rtx_def *, int */); +void output_ascii_pseudo_op (/* FILE *, unsigned char *, int */); +char *output_return_instruction (/* struct rtx_def *, int, int */); +int arm_volatile_func (/* void */); +void output_func_prologue (/* FILE *, int */); +void output_func_epilogue (/* FILE *, int */); +void arm_expand_prologue (/* void */); +void arm_print_operand (/* FILE *, struct rtx_def *, int */); +void final_prescan_insn (/* struct rtx_def *, struct rtx_def **, int */); +#ifdef AOF_ASSEMBLER +struct rtx_def *aof_pic_entry (/* struct rtx_def * */); +void aof_dump_pic_table (/* FILE * */); +char *aof_text_section (/* void */); +char *aof_data_section (/* void */); +void aof_add_import (/* char * */); +void aof_delete_import (/* char * */); +void aof_dump_imports (/* FILE * */); +#endif +/* CYGNUS LOCAL nickc */ +int ok_integer_or_other (); +/* END CYGNUS LOCAL */ +int s_register_operand (/* register rtx op, enum machine_mode mode */); + +#endif /* __ARM_H__ */ diff --git a/gcc_arm/config/arm/arm_020422.c b/gcc_arm/config/arm/arm_020422.c new file mode 100755 index 0000000..65a08dc --- /dev/null +++ b/gcc_arm/config/arm/arm_020422.c @@ -0,0 +1,7160 @@ +/* Output routines for GCC for ARM. + Copyright (C) 1991, 93, 94, 95, 96, 97, 98, 1999 Free Software Foundation, Inc. + Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl) + and Martin Simmons (@harleqn.co.uk). + More major hacks by Richard Earnshaw (rearnsha@arm.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "real.h" +#include "insn-config.h" +#include "conditions.h" +#include "insn-flags.h" +#include "output.h" +#include "insn-attr.h" +#include "flags.h" +#include "reload.h" +#include "tree.h" +#include "expr.h" +#include "toplev.h" + +/* The maximum number of insns skipped which will be conditionalised if + possible. */ +static int max_insns_skipped = 5; + +extern FILE *asm_out_file; +/* Some function declarations. */ + +/* CYGNUS LOCAL */ +void arm_increase_location PROTO ((int)); +static int get_prologue_size PROTO ((void)); +/* END CYGNUS LOCAL */ + +static HOST_WIDE_INT int_log2 PROTO ((HOST_WIDE_INT)); +static char *output_multi_immediate PROTO ((rtx *, char *, char *, int, + HOST_WIDE_INT)); +static int arm_gen_constant PROTO ((enum rtx_code, enum machine_mode, + HOST_WIDE_INT, rtx, rtx, int, int)); +static int arm_naked_function_p PROTO ((tree)); +static void init_fpa_table PROTO ((void)); +static enum machine_mode select_dominance_cc_mode PROTO ((enum rtx_code, rtx, + rtx, HOST_WIDE_INT)); +static HOST_WIDE_INT add_constant PROTO ((rtx, enum machine_mode, int *)); +static void dump_table PROTO ((rtx)); +static int fixit PROTO ((rtx, enum machine_mode, int)); +static rtx find_barrier PROTO ((rtx, int)); +static int broken_move PROTO ((rtx)); +static char *fp_const_from_val PROTO ((REAL_VALUE_TYPE *)); +static int eliminate_lr2ip PROTO ((rtx *)); +static char *shift_op PROTO ((rtx, HOST_WIDE_INT *)); +static int pattern_really_clobbers_lr PROTO ((rtx)); +static int function_really_clobbers_lr PROTO ((rtx)); +static void emit_multi_reg_push PROTO ((int)); +static void emit_sfm PROTO ((int, int)); +static enum arm_cond_code get_arm_condition_code PROTO ((rtx)); + +/* Define the information needed to generate branch insns. This is + stored from the compare operation. */ + +rtx arm_compare_op0, arm_compare_op1; +int arm_compare_fp; + +/* CYGNUS LOCAL: Definition of arm_cpu deleted. */ + +/* What type of floating point are we tuning for? */ +enum floating_point_type arm_fpu; + +/* What type of floating point instructions are available? */ +enum floating_point_type arm_fpu_arch; + +/* What program mode is the cpu running in? 26-bit mode or 32-bit mode */ +enum prog_mode_type arm_prgmode; + +/* CYGNUS LOCAL: Name changed to fpe. */ +/* Set by the -mfpe=... option */ +char *target_fpe_name = NULL; +/* END CYGNUS LOCAL */ + +/* Used to parse -mstructure_size_boundary command line option. */ +char * structure_size_string = NULL; +int arm_structure_size_boundary = 32; /* Used to be 8 */ + +/* Bit values used to identify processor capabilities. */ +#define FL_CO_PROC 0x01 /* Has external co-processor bus */ +#define FL_FAST_MULT 0x02 /* Fast multiply */ +#define FL_MODE26 0x04 /* 26-bit mode support */ +#define FL_MODE32 0x08 /* 32-bit mode support */ +#define FL_ARCH4 0x10 /* Architecture rel 4 */ +#define FL_THUMB 0x20 /* Thumb aware */ +#define FL_LDSCHED 0x40 /* Load scheduling necessary */ +#define FL_STRONG 0x80 /* StrongARM */ + +/* The bits in this mask specify which instructions we are allowed to generate. */ +static int insn_flags = 0; +/* The bits in this mask specify which instruction scheduling options should + be used. Note - there is an overlap with the FL_FAST_MULT. For some + hardware we want to be able to generate the multiply instructions, but to + tune as if they were not present in the architecture. */ +static int tune_flags = 0; + +/* The following are used in the arm.md file as equivalents to bits + in the above two flag variables. */ + +/* Nonzero if this is an "M" variant of the processor. */ +int arm_fast_multiply = 0; + +/* Nonzero if this chip supports the ARM Architecture 4 extensions */ +int arm_arch4 = 0; + +/* Nonzero if this chip can benefit from load scheduling. */ +int arm_ld_sched = 0; + +/* Nonzero if this chip is a StrongARM. */ +int arm_is_strong = 0; + +/* Nonzero if this chip is a an ARM6 or an ARM7. */ +int arm_is_6_or_7 = 0; + +/* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, we + must report the mode of the memory reference from PRINT_OPERAND to + PRINT_OPERAND_ADDRESS. */ +enum machine_mode output_memory_reference_mode; + +/* Nonzero if the prologue must setup `fp'. */ +int current_function_anonymous_args; + +/* The register number to be used for the PIC offset register. */ +int arm_pic_register = 9; + +/* Location counter of .text segment. */ +int arm_text_location = 0; + +/* Set to one if we think that lr is only saved because of subroutine calls, + but all of these can be `put after' return insns */ +int lr_save_eliminated; + +/* Set to 1 when a return insn is output, this means that the epilogue + is not needed. */ + +static int return_used_this_function; + +/* Set to 1 after arm_reorg has started. Reset to start at the start of + the next function. */ +static int after_arm_reorg = 0; + +/* The maximum number of insns to be used when loading a constant. */ +static int arm_constant_limit = 3; + +/* CYGNUS LOCAL unknown */ +/* A hash table is used to store text segment labels and their associated + offset from the start of the text segment. */ +struct label_offset +{ + char * name; + int offset; + struct label_offset * cdr; +}; + +#define LABEL_HASH_SIZE 257 + +static struct label_offset * offset_table [LABEL_HASH_SIZE]; +/* END CYGNUS LOCAL */ + +/* For an explanation of these variables, see final_prescan_insn below. */ +int arm_ccfsm_state; +enum arm_cond_code arm_current_cc; +rtx arm_target_insn; +int arm_target_label; + +/* The condition codes of the ARM, and the inverse function. */ +char *arm_condition_codes[] = +{ + "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", + "hi", "ls", "ge", "lt", "gt", "le", "al", "nv" +}; + +static enum arm_cond_code get_arm_condition_code (); + + +/* Initialization code */ + +struct processors +{ + char * name; + unsigned int flags; +}; + +/* Not all of these give usefully different compilation alternatives, + but there is no simple way of generalizing them. */ +static struct processors all_cores[] = +{ + /* ARM Cores */ + + {"arm2", FL_CO_PROC | FL_MODE26 }, + {"arm250", FL_CO_PROC | FL_MODE26 }, + {"arm3", FL_CO_PROC | FL_MODE26 }, + {"arm6", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, + {"arm60", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, + {"arm600", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, + {"arm610", FL_MODE26 | FL_MODE32 }, + {"arm620", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, + {"arm7", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, + {"arm7m", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT }, /* arm7m doesn't exist on its own, */ + {"arm7d", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, /* but only with D, (and I), */ + {"arm7dm", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT }, /* but those don't alter the code, */ + {"arm7di", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, /* so arm7m is sometimes used. */ + {"arm7dmi", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT }, + {"arm70", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, + {"arm700", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, + {"arm700i", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, + {"arm710", FL_MODE26 | FL_MODE32 }, + {"arm710c", FL_MODE26 | FL_MODE32 }, + {"arm7100", FL_MODE26 | FL_MODE32 }, + {"arm7500", FL_MODE26 | FL_MODE32 }, + {"arm7500fe", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, /* Doesn't really have an external co-proc, but does have embedded fpu. */ + {"arm7tdmi", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB }, + {"arm8", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED }, + {"arm810", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED }, + {"arm9", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED }, + {"arm920", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED }, + {"arm920t", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED }, + {"arm9tdmi", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED }, + {"strongarm", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_STRONG }, + {"strongarm110", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_STRONG }, + {"strongarm1100", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_STRONG }, + + {NULL, 0} +}; + +static struct processors all_architectures[] = +{ + /* ARM Architectures */ + + {"armv2", FL_CO_PROC | FL_MODE26 }, + {"armv2a", FL_CO_PROC | FL_MODE26 }, + {"armv3", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, + {"armv3m", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT }, + {"armv4", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 }, + /* Strictly, FL_MODE26 is a permitted option for v4t, but there are no + implementations that support it, so we will leave it out for now. */ + {"armv4t", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB }, + {NULL, 0} +}; + +/* This is a magic stucture. The 'string' field is magically filled in + with a pointer to the value specified by the user on the command line + assuming that the user has specified such a value. */ + +struct arm_cpu_select arm_select[] = +{ + /* string name processors */ + { NULL, "-mcpu=", all_cores }, + { NULL, "-march=", all_architectures }, + { NULL, "-mtune=", all_cores } +}; + +/* Return the number of bits set in value' */ +static unsigned int +bit_count (value) + signed int value; +{ + unsigned int count = 0; + + while (value) + { + value &= ~(value & - value); + ++ count; + } + + return count; +} + +/* Fix up any incompatible options that the user has specified. + This has now turned into a maze. */ +void +arm_override_options () +{ + unsigned i; + + /* Set up the flags based on the cpu/architecture selected by the user. */ + for (i = sizeof (arm_select) / sizeof (arm_select[0]); i--;) + { + struct arm_cpu_select * ptr = arm_select + i; + + if (ptr->string != NULL && ptr->string[0] != '\0') + { + const struct processors * sel; + + for (sel = ptr->processors; sel->name != NULL; sel ++) + if (! strcmp (ptr->string, sel->name)) + { + if (i == 2) + tune_flags = sel->flags; + else + { + /* If we have been given an architecture and a processor + make sure that they are compatible. We only generate + a warning though, and we prefer the CPU over the + architecture. */ + if (insn_flags != 0 && (insn_flags ^ sel->flags)) + warning ("switch -mcpu=%s conflicts with -march= switch", + ptr->string); + + insn_flags = sel->flags; + } + + break; + } + + if (sel->name == NULL) + error ("bad value (%s) for %s switch", ptr->string, ptr->name); + } + } + + /* If the user did not specify a processor, choose one for them. */ + if (insn_flags == 0) + { + struct processors * sel; + unsigned int sought; + static struct cpu_default + { + int cpu; + char * name; + } + cpu_defaults[] = + { + { TARGET_CPU_arm2, "arm2" }, + { TARGET_CPU_arm6, "arm6" }, + { TARGET_CPU_arm610, "arm610" }, + { TARGET_CPU_arm710, "arm710" }, + { TARGET_CPU_arm7m, "arm7m" }, + { TARGET_CPU_arm7500fe, "arm7500fe" }, + { TARGET_CPU_arm7tdmi, "arm7tdmi" }, + { TARGET_CPU_arm8, "arm8" }, + { TARGET_CPU_arm810, "arm810" }, + { TARGET_CPU_arm9, "arm9" }, + { TARGET_CPU_strongarm, "strongarm" }, + { TARGET_CPU_generic, "arm" }, + { 0, 0 } + }; + struct cpu_default * def; + + /* Find the default. */ + for (def = cpu_defaults; def->name; def ++) + if (def->cpu == TARGET_CPU_DEFAULT) + break; + + /* Make sure we found the default CPU. */ + if (def->name == NULL) + abort (); + + /* Find the default CPU's flags. */ + for (sel = all_cores; sel->name != NULL; sel ++) + if (! strcmp (def->name, sel->name)) + break; + + if (sel->name == NULL) + abort (); + + insn_flags = sel->flags; + + /* Now check to see if the user has specified some command line + switch that require certain abilities from the cpu. */ + sought = 0; + + if (TARGET_THUMB_INTERWORK) + { + sought |= (FL_THUMB | FL_MODE32); + + /* Force apcs-32 to be used for interworking. */ + target_flags |= ARM_FLAG_APCS_32; + + /* There are no ARM processor that supports both APCS-26 and + interworking. Therefore we force FL_MODE26 to be removed + from insn_flags here (if it was set), so that the search + below will always be able to find a compatible processor. */ + insn_flags &= ~ FL_MODE26; + } + + if (! TARGET_APCS_32) + sought |= FL_MODE26; + + if (sought != 0 && ((sought & insn_flags) != sought)) + { + /* Try to locate a CPU type that supports all of the abilities + of the default CPU, plus the extra abilities requested by + the user. */ + for (sel = all_cores; sel->name != NULL; sel ++) + if ((sel->flags & sought) == (sought | insn_flags)) + break; + + if (sel->name == NULL) + { + unsigned int current_bit_count = 0; + struct processors * best_fit = NULL; + + /* Ideally we would like to issue an error message here + saying that it was not possible to find a CPU compatible + with the default CPU, but which also supports the command + line options specified by the programmer, and so they + ought to use the -mcpu= command line option to + override the default CPU type. + + Unfortunately this does not work with multilibing. We + need to be able to support multilibs for -mapcs-26 and for + -mthumb-interwork and there is no CPU that can support both + options. Instead if we cannot find a cpu that has both the + characteristics of the default cpu and the given command line + options we scan the array again looking for a best match. */ + for (sel = all_cores; sel->name != NULL; sel ++) + if ((sel->flags & sought) == sought) + { + unsigned int count; + + count = bit_count (sel->flags & insn_flags); + + if (count >= current_bit_count) + { + best_fit = sel; + current_bit_count = count; + } + } + + if (best_fit == NULL) + abort (); + else + sel = best_fit; + } + + insn_flags = sel->flags; + } + } + + /* If tuning has not been specified, tune for whichever processor or + architecture has been selected. */ + if (tune_flags == 0) + tune_flags = insn_flags; + + /* Make sure that the processor choice does not conflict with any of the + other command line choices. */ + if (TARGET_APCS_32 && !(insn_flags & FL_MODE32)) + { + /* If APCS-32 was not the default then it must have been set by the + user, so issue a warning message. If the user has specified + "-mapcs-32 -mcpu=arm2" then we loose here. */ + if ((TARGET_DEFAULT & ARM_FLAG_APCS_32) == 0) + warning ("target CPU does not support APCS-32" ); + target_flags &= ~ ARM_FLAG_APCS_32; + } + else if (! TARGET_APCS_32 && !(insn_flags & FL_MODE26)) + { + warning ("target CPU does not support APCS-26" ); + target_flags |= ARM_FLAG_APCS_32; + } + + if (TARGET_THUMB_INTERWORK && !(insn_flags & FL_THUMB)) + { + warning ("target CPU does not support interworking" ); + target_flags &= ~ARM_FLAG_THUMB; + } + + /* If interworking is enabled then APCS-32 must be selected as well. */ + if (TARGET_THUMB_INTERWORK) + { + if (! TARGET_APCS_32) + warning ("interworking forces APCS-32 to be used" ); + target_flags |= ARM_FLAG_APCS_32; + } + + if (TARGET_APCS_STACK && ! TARGET_APCS) + { + warning ("-mapcs-stack-check incompatible with -mno-apcs-frame"); + target_flags |= ARM_FLAG_APCS_FRAME; + } + + if (write_symbols != NO_DEBUG && flag_omit_frame_pointer) + warning ("-g with -fomit-frame-pointer may not give sensible debugging"); + + if (TARGET_POKE_FUNCTION_NAME) + target_flags |= ARM_FLAG_APCS_FRAME; + + if (TARGET_APCS_REENT && flag_pic) + fatal ("-fpic and -mapcs-reent are incompatible"); + + if (TARGET_APCS_REENT) + warning ("APCS reentrant code not supported. Ignored"); + + /* If stack checking is disabled, we can use r10 as the PIC register, + which keeps r9 available. */ + if (flag_pic && ! TARGET_APCS_STACK) + arm_pic_register = 10; + + /* Well, I'm about to have a go, but pic is NOT going to be compatible + with APCS reentrancy, since that requires too much support in the + assembler and linker, and the ARMASM assembler seems to lack some + required directives. */ + if (flag_pic) + warning ("Position independent code not supported"); + + if (TARGET_APCS_FLOAT) + warning ("Passing floating point arguments in fp regs not yet supported"); + + /* Initialise boolean versions of the flags, for use in the arm.md file. */ + arm_fast_multiply = insn_flags & FL_FAST_MULT; + arm_arch4 = insn_flags & FL_ARCH4; + + arm_ld_sched = tune_flags & FL_LDSCHED; + arm_is_strong = tune_flags & FL_STRONG; + arm_is_6_or_7 = ((tune_flags & (FL_MODE26 | FL_MODE32)) + && !(tune_flags & FL_ARCH4)); + + /* Default value for floating point code... if no co-processor + bus, then schedule for emulated floating point. Otherwise, + assume the user has an FPA. + Note: this does not prevent use of floating point instructions, + -msoft-float does that. */ + arm_fpu = (tune_flags & FL_CO_PROC) ? FP_HARD : FP_SOFT3; + + if (target_fpe_name) + { + if (! strcmp (target_fpe_name, "2")) + arm_fpu_arch = FP_SOFT2; + else if (! strcmp (target_fpe_name, "3")) + arm_fpu_arch = FP_SOFT3; + else + fatal ("Invalid floating point emulation option: -mfpe-%s", + target_fpe_name); + } + else + arm_fpu_arch = FP_DEFAULT; + + if (TARGET_FPE && arm_fpu != FP_HARD) + arm_fpu = FP_SOFT2; + + /* For arm2/3 there is no need to do any scheduling if there is only + a floating point emulator, or we are doing software floating-point. */ + if ((TARGET_SOFT_FLOAT || arm_fpu != FP_HARD) && (tune_flags & FL_MODE32) == 0) + flag_schedule_insns = flag_schedule_insns_after_reload = 0; + + arm_prog_mode = TARGET_APCS_32 ? PROG_MODE_PROG32 : PROG_MODE_PROG26; + + if (structure_size_string != NULL) + { + int size = strtol (structure_size_string, NULL, 0); + + if (size == 8 || size == 32) + arm_structure_size_boundary = size; + else + warning ("Structure size boundary can only be set to 8 or 32"); + } + + /* If optimizing for space, don't synthesize constants. + For processors with load scheduling, it never costs more than 2 cycles + to load a constant, and the load scheduler may well reduce that to 1. */ + if (optimize_size || (tune_flags & FL_LDSCHED)) + arm_constant_limit = 1; + + /* If optimizing for size, bump the number of instructions that we + are prepared to conditionally execute (even on a StrongARM). + Otherwise for the StrongARM, which has early execution of branches, + a sequence that is worth skipping is shorter. */ + if (optimize_size) + max_insns_skipped = 6; + else if (arm_is_strong) + max_insns_skipped = 3; +} + + +/* Return 1 if it is possible to return using a single instruction */ + +int +use_return_insn (iscond) + int iscond; +{ + int regno; + + if (!reload_completed ||current_function_pretend_args_size + || current_function_anonymous_args + || ((get_frame_size () + current_function_outgoing_args_size != 0) + /* CYGNUS LOCAL nickc */ + && !(TARGET_APCS && frame_pointer_needed))) + /* END CYGNUS LOCAL */ + return 0; + + /* Can't be done if interworking with Thumb, and any registers have been + stacked. Similarly, on StrongARM, conditional returns are expensive + if they aren't taken and registers have been stacked. */ + if (iscond && arm_is_strong && frame_pointer_needed) + return 0; + if ((iscond && arm_is_strong) + || TARGET_THUMB_INTERWORK) + for (regno = 0; regno < 16; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + return 0; + + /* Can't be done if any of the FPU regs are pushed, since this also + requires an insn */ + for (regno = 16; regno < 24; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + return 0; + + /* If a function is naked, don't use the "return" insn. */ + if (arm_naked_function_p (current_function_decl)) + return 0; + + return 1; +} + +/* Return TRUE if int I is a valid immediate ARM constant. */ + +int +const_ok_for_arm (i) + HOST_WIDE_INT i; +{ + unsigned HOST_WIDE_INT mask = ~(unsigned HOST_WIDE_INT)0xFF; + + /* For machines with >32 bit HOST_WIDE_INT, the bits above bit 31 must + be all zero, or all one. */ + if ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff) != 0 + && ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff) + != ((~(unsigned HOST_WIDE_INT) 0) + & ~(unsigned HOST_WIDE_INT) 0xffffffff))) + return FALSE; + + /* Fast return for 0 and powers of 2 */ + if ((i & (i - 1)) == 0) + return TRUE; + + do + { + if ((i & mask & (unsigned HOST_WIDE_INT) 0xffffffff) == 0) + return TRUE; + mask = + (mask << 2) | ((mask & (unsigned HOST_WIDE_INT) 0xffffffff) + >> (32 - 2)) | ~((unsigned HOST_WIDE_INT) 0xffffffff); + } while (mask != ~(unsigned HOST_WIDE_INT) 0xFF); + + return FALSE; +} + +/* Return true if I is a valid constant for the operation CODE. */ +int +const_ok_for_op (i, code, mode) + HOST_WIDE_INT i; + enum rtx_code code; + enum machine_mode mode; +{ + if (const_ok_for_arm (i)) + return 1; + + switch (code) + { + case PLUS: + return const_ok_for_arm (ARM_SIGN_EXTEND (-i)); + + case MINUS: /* Should only occur with (MINUS I reg) => rsb */ + case XOR: + case IOR: + return 0; + + case AND: + return const_ok_for_arm (ARM_SIGN_EXTEND (~i)); + + default: + abort (); + } +} + +/* Emit a sequence of insns to handle a large constant. + CODE is the code of the operation required, it can be any of SET, PLUS, + IOR, AND, XOR, MINUS; + MODE is the mode in which the operation is being performed; + VAL is the integer to operate on; + SOURCE is the other operand (a register, or a null-pointer for SET); + SUBTARGETS means it is safe to create scratch registers if that will + either produce a simpler sequence, or we will want to cse the values. + Return value is the number of insns emitted. */ + +int +arm_split_constant (code, mode, val, target, source, subtargets) + enum rtx_code code; + enum machine_mode mode; + HOST_WIDE_INT val; + rtx target; + rtx source; + int subtargets; +{ + if (subtargets || code == SET + || (GET_CODE (target) == REG && GET_CODE (source) == REG + && REGNO (target) != REGNO (source))) + { + /* After arm_reorg has been called, we can't fix up expensive + constants by pushing them into memory so we must synthesise + them in-line, regardless of the cost. This is only likely to + be more costly on chips that have load delay slots and we are + compiling without running the scheduler (so no splitting + occurred before the final instruction emission). + + Ref: gcc -O1 -mcpu=strongarm gcc.c-torture/compile/980506-2.c + */ /* CYGNUS LOCAL nickc/strongarm */ + if ((! after_arm_reorg || optimize == 0) + /* END CYGNUS LOCAL */ + && (arm_gen_constant (code, mode, val, target, source, 1, 0) + > arm_constant_limit + (code != SET))) + { + if (code == SET) + { + /* Currently SET is the only monadic value for CODE, all + the rest are diadic. */ + emit_insn (gen_rtx (SET, VOIDmode, target, GEN_INT (val))); + return 1; + } + else + { + rtx temp = subtargets ? gen_reg_rtx (mode) : target; + + emit_insn (gen_rtx (SET, VOIDmode, temp, GEN_INT (val))); + /* For MINUS, the value is subtracted from, since we never + have subtraction of a constant. */ + if (code == MINUS) + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (code, mode, temp, source))); + else + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (code, mode, source, temp))); + return 2; + } + } + } + + return arm_gen_constant (code, mode, val, target, source, subtargets, 1); +} + +/* As above, but extra parameter GENERATE which, if clear, suppresses + RTL generation. */ +int +arm_gen_constant (code, mode, val, target, source, subtargets, generate) + enum rtx_code code; + enum machine_mode mode; + HOST_WIDE_INT val; + rtx target; + rtx source; + int subtargets; + int generate; +{ + int can_invert = 0; + int can_negate = 0; + int can_negate_initial = 0; + int can_shift = 0; + int i; + int num_bits_set = 0; + int set_sign_bit_copies = 0; + int clear_sign_bit_copies = 0; + int clear_zero_bit_copies = 0; + int set_zero_bit_copies = 0; + int insns = 0; + unsigned HOST_WIDE_INT temp1, temp2; + unsigned HOST_WIDE_INT remainder = val & 0xffffffff; + + /* find out which operations are safe for a given CODE. Also do a quick + check for degenerate cases; these can occur when DImode operations + are split. */ + switch (code) + { + case SET: + can_invert = 1; + can_shift = 1; + can_negate = 1; + break; + + case PLUS: + can_negate = 1; + can_negate_initial = 1; + break; + + case IOR: + if (remainder == 0xffffffff) + { + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, + GEN_INT (ARM_SIGN_EXTEND (val)))); + return 1; + } + if (remainder == 0) + { + if (reload_completed && rtx_equal_p (target, source)) + return 0; + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, source)); + return 1; + } + break; + + case AND: + if (remainder == 0) + { + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, const0_rtx)); + return 1; + } + if (remainder == 0xffffffff) + { + if (reload_completed && rtx_equal_p (target, source)) + return 0; + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, source)); + return 1; + } + can_invert = 1; + break; + + case XOR: + if (remainder == 0) + { + if (reload_completed && rtx_equal_p (target, source)) + return 0; + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, source)); + return 1; + } + if (remainder == 0xffffffff) + { + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (NOT, mode, source))); + return 1; + } + + /* We don't know how to handle this yet below. */ + abort (); + + case MINUS: + /* We treat MINUS as (val - source), since (source - val) is always + passed as (source + (-val)). */ + if (remainder == 0) + { + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (NEG, mode, source))); + return 1; + } + if (const_ok_for_arm (val)) + { + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (MINUS, mode, GEN_INT (val), source))); + return 1; + } + can_negate = 1; + + break; + + default: + abort (); + } + + /* If we can do it in one insn get out quickly */ + if (const_ok_for_arm (val) + || (can_negate_initial && const_ok_for_arm (-val)) + || (can_invert && const_ok_for_arm (~val))) + { + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, + (source ? gen_rtx (code, mode, source, + GEN_INT (val)) + : GEN_INT (val)))); + return 1; + } + + + /* Calculate a few attributes that may be useful for specific + optimizations. */ + + for (i = 31; i >= 0; i--) + { + if ((remainder & (1 << i)) == 0) + clear_sign_bit_copies++; + else + break; + } + + for (i = 31; i >= 0; i--) + { + if ((remainder & (1 << i)) != 0) + set_sign_bit_copies++; + else + break; + } + + for (i = 0; i <= 31; i++) + { + if ((remainder & (1 << i)) == 0) + clear_zero_bit_copies++; + else + break; + } + + for (i = 0; i <= 31; i++) + { + if ((remainder & (1 << i)) != 0) + set_zero_bit_copies++; + else + break; + } + + switch (code) + { + case SET: + /* See if we can do this by sign_extending a constant that is known + to be negative. This is a good, way of doing it, since the shift + may well merge into a subsequent insn. */ + if (set_sign_bit_copies > 1) + { + if (const_ok_for_arm + (temp1 = ARM_SIGN_EXTEND (remainder + << (set_sign_bit_copies - 1)))) + { + if (generate) + { + rtx new_src = subtargets ? gen_reg_rtx (mode) : target; + emit_insn (gen_rtx (SET, VOIDmode, new_src, + GEN_INT (temp1))); + emit_insn (gen_ashrsi3 (target, new_src, + GEN_INT (set_sign_bit_copies - 1))); + } + return 2; + } + /* For an inverted constant, we will need to set the low bits, + these will be shifted out of harm's way. */ + temp1 |= (1 << (set_sign_bit_copies - 1)) - 1; + if (const_ok_for_arm (~temp1)) + { + if (generate) + { + rtx new_src = subtargets ? gen_reg_rtx (mode) : target; + emit_insn (gen_rtx (SET, VOIDmode, new_src, + GEN_INT (temp1))); + emit_insn (gen_ashrsi3 (target, new_src, + GEN_INT (set_sign_bit_copies - 1))); + } + return 2; + } + } + + /* See if we can generate this by setting the bottom (or the top) + 16 bits, and then shifting these into the other half of the + word. We only look for the simplest cases, to do more would cost + too much. Be careful, however, not to generate this when the + alternative would take fewer insns. */ + if (val & 0xffff0000) + { + temp1 = remainder & 0xffff0000; + temp2 = remainder & 0x0000ffff; + + /* Overlaps outside this range are best done using other methods. */ + for (i = 9; i < 24; i++) + { + if ((((temp2 | (temp2 << i)) & 0xffffffff) == remainder) + && ! const_ok_for_arm (temp2)) + { + rtx new_src = (subtargets + ? (generate ? gen_reg_rtx (mode) : NULL_RTX) + : target); + insns = arm_gen_constant (code, mode, temp2, new_src, + source, subtargets, generate); + source = new_src; + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (IOR, mode, + gen_rtx (ASHIFT, mode, source, + GEN_INT (i)), + source))); + return insns + 1; + } + } + + /* Don't duplicate cases already considered. */ + for (i = 17; i < 24; i++) + { + if (((temp1 | (temp1 >> i)) == remainder) + && ! const_ok_for_arm (temp1)) + { + rtx new_src = (subtargets + ? (generate ? gen_reg_rtx (mode) : NULL_RTX) + : target); + insns = arm_gen_constant (code, mode, temp1, new_src, + source, subtargets, generate); + source = new_src; + if (generate) + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (IOR, mode, + gen_rtx (LSHIFTRT, mode, + source, GEN_INT (i)), + source))); + return insns + 1; + } + } + } + break; + + case IOR: + case XOR: + /* If we have IOR or XOR, and the constant can be loaded in a + single instruction, and we can find a temporary to put it in, + then this can be done in two instructions instead of 3-4. */ + if (subtargets + /* TARGET can't be NULL if SUBTARGETS is 0 */ + || (reload_completed && ! reg_mentioned_p (target, source))) + { + if (const_ok_for_arm (ARM_SIGN_EXTEND (~ val))) + { + if (generate) + { + rtx sub = subtargets ? gen_reg_rtx (mode) : target; + + emit_insn (gen_rtx (SET, VOIDmode, sub, GEN_INT (val))); + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (code, mode, source, sub))); + } + return 2; + } + } + + if (code == XOR) + break; + + if (set_sign_bit_copies > 8 + && (val & (-1 << (32 - set_sign_bit_copies))) == val) + { + if (generate) + { + rtx sub = subtargets ? gen_reg_rtx (mode) : target; + rtx shift = GEN_INT (set_sign_bit_copies); + + emit_insn (gen_rtx (SET, VOIDmode, sub, + gen_rtx (NOT, mode, + gen_rtx (ASHIFT, mode, source, + shift)))); + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (NOT, mode, + gen_rtx (LSHIFTRT, mode, sub, + shift)))); + } + return 2; + } + + if (set_zero_bit_copies > 8 + && (remainder & ((1 << set_zero_bit_copies) - 1)) == remainder) + { + if (generate) + { + rtx sub = subtargets ? gen_reg_rtx (mode) : target; + rtx shift = GEN_INT (set_zero_bit_copies); + + emit_insn (gen_rtx (SET, VOIDmode, sub, + gen_rtx (NOT, mode, + gen_rtx (LSHIFTRT, mode, source, + shift)))); + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (NOT, mode, + gen_rtx (ASHIFT, mode, sub, + shift)))); + } + return 2; + } + + if (const_ok_for_arm (temp1 = ARM_SIGN_EXTEND (~ val))) + { + if (generate) + { + rtx sub = subtargets ? gen_reg_rtx (mode) : target; + emit_insn (gen_rtx (SET, VOIDmode, sub, + gen_rtx (NOT, mode, source))); + source = sub; + if (subtargets) + sub = gen_reg_rtx (mode); + emit_insn (gen_rtx (SET, VOIDmode, sub, + gen_rtx (AND, mode, source, + GEN_INT (temp1)))); + emit_insn (gen_rtx (SET, VOIDmode, target, + gen_rtx (NOT, mode, sub))); + } + return 3; + } + break; + + case AND: + /* See if two shifts will do 2 or more insn's worth of work. */ + if (clear_sign_bit_copies >= 16 && clear_sign_bit_copies < 24) + { + HOST_WIDE_INT shift_mask = ((0xffffffff + << (32 - clear_sign_bit_copies)) + & 0xffffffff); + + if ((remainder | shift_mask) != 0xffffffff) + { + if (generate) + { + rtx new_src = subtargets ? gen_reg_rtx (mode) : target; + insns = arm_gen_constant (AND, mode, remainder | shift_mask, + new_src, source, subtargets, 1); + source = new_src; + } + else + { + rtx targ = subtargets ? NULL_RTX : target; + insns = arm_gen_constant (AND, mode, remainder | shift_mask, + targ, source, subtargets, 0); + } + } + + if (generate) + { + rtx new_src = subtargets ? gen_reg_rtx (mode) : target; + rtx shift = GEN_INT (clear_sign_bit_copies); + + emit_insn (gen_ashlsi3 (new_src, source, shift)); + emit_insn (gen_lshrsi3 (target, new_src, shift)); + } + + return insns + 2; + } + + if (clear_zero_bit_copies >= 16 && clear_zero_bit_copies < 24) + { + HOST_WIDE_INT shift_mask = (1 << clear_zero_bit_copies) - 1; + + if ((remainder | shift_mask) != 0xffffffff) + { + if (generate) + { + rtx new_src = subtargets ? gen_reg_rtx (mode) : target; + + insns = arm_gen_constant (AND, mode, remainder | shift_mask, + new_src, source, subtargets, 1); + source = new_src; + } + else + { + rtx targ = subtargets ? NULL_RTX : target; + + insns = arm_gen_constant (AND, mode, remainder | shift_mask, + targ, source, subtargets, 0); + } + } + + if (generate) + { + rtx new_src = subtargets ? gen_reg_rtx (mode) : target; + rtx shift = GEN_INT (clear_zero_bit_copies); + + emit_insn (gen_lshrsi3 (new_src, source, shift)); + emit_insn (gen_ashlsi3 (target, new_src, shift)); + } + + return insns + 2; + } + + break; + + default: + break; + } + + for (i = 0; i < 32; i++) + if (remainder & (1 << i)) + num_bits_set++; + + if (code == AND || (can_invert && num_bits_set > 16)) + remainder = (~remainder) & 0xffffffff; + else if (code == PLUS && num_bits_set > 16) + remainder = (-remainder) & 0xffffffff; + else + { + can_invert = 0; + can_negate = 0; + } + + /* Now try and find a way of doing the job in either two or three + instructions. + We start by looking for the largest block of zeros that are aligned on + a 2-bit boundary, we then fill up the temps, wrapping around to the + top of the word when we drop off the bottom. + In the worst case this code should produce no more than four insns. */ + { + int best_start = 0; + int best_consecutive_zeros = 0; + + for (i = 0; i < 32; i += 2) + { + int consecutive_zeros = 0; + + if (! (remainder & (3 << i))) + { + while ((i < 32) && ! (remainder & (3 << i))) + { + consecutive_zeros += 2; + i += 2; + } + if (consecutive_zeros > best_consecutive_zeros) + { + best_consecutive_zeros = consecutive_zeros; + best_start = i - consecutive_zeros; + } + i -= 2; + } + } + + /* Now start emitting the insns, starting with the one with the highest + bit set: we do this so that the smallest number will be emitted last; + this is more likely to be combinable with addressing insns. */ + i = best_start; + do + { + int end; + + if (i <= 0) + i += 32; + if (remainder & (3 << (i - 2))) + { + end = i - 8; + if (end < 0) + end += 32; + temp1 = remainder & ((0x0ff << end) + | ((i < end) ? (0xff >> (32 - end)) : 0)); + remainder &= ~temp1; + + if (generate) + { + rtx new_src; + + if (code == SET) + emit_insn (gen_rtx (SET, VOIDmode, + new_src = (subtargets + ? gen_reg_rtx (mode) + : target), + GEN_INT (can_invert ? ~temp1 : temp1))); + else if (code == MINUS) + emit_insn (gen_rtx (SET, VOIDmode, + new_src = (subtargets + ? gen_reg_rtx (mode) + : target), + gen_rtx (code, mode, GEN_INT (temp1), + source))); + else + emit_insn (gen_rtx (SET, VOIDmode, + new_src = (remainder + ? (subtargets + ? gen_reg_rtx (mode) + : target) + : target), + gen_rtx (code, mode, source, + GEN_INT (can_invert ? ~temp1 + : (can_negate + ? -temp1 + : temp1))))); + source = new_src; + } + + if (code == SET) + { + can_invert = 0; + code = PLUS; + } + else if (code == MINUS) + code = PLUS; + + insns++; + i -= 6; + } + i -= 2; + } while (remainder); + } + return insns; +} + +/* Canonicalize a comparison so that we are more likely to recognize it. + This can be done for a few constant compares, where we can make the + immediate value easier to load. */ +enum rtx_code +arm_canonicalize_comparison (code, op1) + enum rtx_code code; + rtx *op1; +{ + unsigned HOST_WIDE_INT i = INTVAL (*op1); + + switch (code) + { + case EQ: + case NE: + return code; + + case GT: + case LE: + if (i != ((((unsigned HOST_WIDE_INT) 1) << (HOST_BITS_PER_WIDE_INT - 1)) + - 1) + && (const_ok_for_arm (i+1) || const_ok_for_arm (- (i+1)))) + { + *op1 = GEN_INT (i+1); + return code == GT ? GE : LT; + } + break; + + case GE: + case LT: + if (i != (((unsigned HOST_WIDE_INT) 1) << (HOST_BITS_PER_WIDE_INT - 1)) + && (const_ok_for_arm (i-1) || const_ok_for_arm (- (i-1)))) + { + *op1 = GEN_INT (i-1); + return code == GE ? GT : LE; + } + break; + + case GTU: + case LEU: + if (i != ~((unsigned HOST_WIDE_INT) 0) + && (const_ok_for_arm (i+1) || const_ok_for_arm (- (i+1)))) + { + *op1 = GEN_INT (i + 1); + return code == GTU ? GEU : LTU; + } + break; + + case GEU: + case LTU: + if (i != 0 + && (const_ok_for_arm (i - 1) || const_ok_for_arm (- (i - 1)))) + { + *op1 = GEN_INT (i - 1); + return code == GEU ? GTU : LEU; + } + break; + + default: + abort (); + } + + return code; +} + +/* CYGNSU LOCAL */ +/* Decide whether a type should be returned in memory (true) + or in a register (false). This is called by the macro + RETURN_IN_MEMORY. */ + +int +arm_return_in_memory (type) + tree type; +{ + if (! AGGREGATE_TYPE_P (type)) + { + /* All simple types are returned in registers. */ + + return 0; + } + else if (int_size_in_bytes (type) > 4) + { + /* All structures/unions bigger than one word are returned in memory. */ + + return 1; + } + else if (TREE_CODE (type) == RECORD_TYPE) + { + tree field; + + /* For a struct the APCS says that we must return in a register if + every addressable element has an offset of zero. For practical + purposes this means that the structure can have at most one non + bit-field element and that this element must be the first one in + the structure. */ + + /* Find the first field, ignoring non FIELD_DECL things which will + have been created by C++. */ + + for (field = TYPE_FIELDS (type); + field && TREE_CODE (field) != FIELD_DECL; + field = TREE_CHAIN (field)) + continue; + + if (field == NULL) + return 0; /* An empty structure. Allowed by an extension to ANSI C. */ + + /* Now check the remaining fields, if any. */ + for (field = TREE_CHAIN (field); + field; + field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + + if (! DECL_BIT_FIELD_TYPE (field)) + return 1; + } + + return 0; + } + else if (TREE_CODE (type) == UNION_TYPE) + { + tree field; + + /* Unions can be returned in registers if every element is + integral, or can be returned in an integer register. */ + + for (field = TYPE_FIELDS (type); + field; + field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + + if (FLOAT_TYPE_P (TREE_TYPE (field))) + return 1; + + if (RETURN_IN_MEMORY (TREE_TYPE (field))) + return 1; + } + + return 0; + } + + /* XXX Not sure what should be done for other aggregates, so put them in + memory. */ + return 1; +} +/* END CYGNUS LOCAL */ + +int +legitimate_pic_operand_p (x) + rtx x; +{ + if (CONSTANT_P (x) && flag_pic + && (GET_CODE (x) == SYMBOL_REF + || (GET_CODE (x) == CONST + && GET_CODE (XEXP (x, 0)) == PLUS + && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF))) + return 0; + + return 1; +} + +rtx +legitimize_pic_address (orig, mode, reg) + rtx orig; + enum machine_mode mode; + rtx reg; +{ + if (GET_CODE (orig) == SYMBOL_REF) + { + rtx pic_ref, address; + rtx insn; + int subregs = 0; + + if (reg == 0) + { + if (reload_in_progress || reload_completed) + abort (); + else + reg = gen_reg_rtx (Pmode); + + subregs = 1; + } + +#ifdef AOF_ASSEMBLER + /* The AOF assembler can generate relocations for these directly, and + understands that the PIC register has to be added into the offset. + */ + insn = emit_insn (gen_pic_load_addr_based (reg, orig)); +#else + if (subregs) + address = gen_reg_rtx (Pmode); + else + address = reg; + + emit_insn (gen_pic_load_addr (address, orig)); + + pic_ref = gen_rtx (MEM, Pmode, + gen_rtx (PLUS, Pmode, pic_offset_table_rtx, address)); + RTX_UNCHANGING_P (pic_ref) = 1; + insn = emit_move_insn (reg, pic_ref); +#endif + current_function_uses_pic_offset_table = 1; + /* Put a REG_EQUAL note on this insn, so that it can be optimized + by loop. */ + REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL, orig, + REG_NOTES (insn)); + return reg; + } + else if (GET_CODE (orig) == CONST) + { + rtx base, offset; + + if (GET_CODE (XEXP (orig, 0)) == PLUS + && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx) + return orig; + + if (reg == 0) + { + if (reload_in_progress || reload_completed) + abort (); + else + reg = gen_reg_rtx (Pmode); + } + + if (GET_CODE (XEXP (orig, 0)) == PLUS) + { + base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg); + offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode, + base == reg ? 0 : reg); + } + else + abort (); + + if (GET_CODE (offset) == CONST_INT) + { + /* The base register doesn't really matter, we only want to + test the index for the appropriate mode. */ + GO_IF_LEGITIMATE_INDEX (mode, 0, offset, win); + + if (! reload_in_progress && ! reload_completed) + offset = force_reg (Pmode, offset); + else + abort (); + + win: + if (GET_CODE (offset) == CONST_INT) + return plus_constant_for_output (base, INTVAL (offset)); + } + + if (GET_MODE_SIZE (mode) > 4 + && (GET_MODE_CLASS (mode) == MODE_INT + || TARGET_SOFT_FLOAT)) + { + emit_insn (gen_addsi3 (reg, base, offset)); + return reg; + } + + return gen_rtx (PLUS, Pmode, base, offset); + } + else if (GET_CODE (orig) == LABEL_REF) + current_function_uses_pic_offset_table = 1; + + return orig; +} + +static rtx pic_rtx; + +int +is_pic(x) + rtx x; +{ + if (x == pic_rtx) + return 1; + return 0; +} + +void +arm_finalize_pic () +{ +#ifndef AOF_ASSEMBLER + rtx l1, pic_tmp, pic_tmp2, seq; + rtx global_offset_table; + + if (current_function_uses_pic_offset_table == 0) + return; + + if (! flag_pic) + abort (); + + start_sequence (); + l1 = gen_label_rtx (); + + global_offset_table = gen_rtx (SYMBOL_REF, Pmode, "_GLOBAL_OFFSET_TABLE_"); + /* The PC contains 'dot'+8, but the label L1 is on the next + instruction, so the offset is only 'dot'+4. */ + pic_tmp = gen_rtx (CONST, VOIDmode, + gen_rtx (PLUS, Pmode, + gen_rtx (LABEL_REF, VOIDmode, l1), + GEN_INT (4))); + pic_tmp2 = gen_rtx (CONST, VOIDmode, + gen_rtx (PLUS, Pmode, + global_offset_table, + pc_rtx)); + + pic_rtx = gen_rtx (CONST, Pmode, + gen_rtx (MINUS, Pmode, pic_tmp2, pic_tmp)); + + emit_insn (gen_pic_load_addr (pic_offset_table_rtx, pic_rtx)); + emit_jump_insn (gen_pic_add_dot_plus_eight(l1, pic_offset_table_rtx)); + emit_label (l1); + + seq = gen_sequence (); + end_sequence (); + emit_insn_after (seq, get_insns ()); + + /* Need to emit this whether or not we obey regdecls, + since setjmp/longjmp can cause life info to screw up. */ + emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx)); +#endif /* AOF_ASSEMBLER */ +} + +#define REG_OR_SUBREG_REG(X) \ + (GET_CODE (X) == REG \ + || (GET_CODE (X) == SUBREG && GET_CODE (SUBREG_REG (X)) == REG)) + +#define REG_OR_SUBREG_RTX(X) \ + (GET_CODE (X) == REG ? (X) : SUBREG_REG (X)) + +#define ARM_FRAME_RTX(X) \ + ((X) == frame_pointer_rtx || (X) == stack_pointer_rtx \ + || (X) == arg_pointer_rtx) + +int +arm_rtx_costs (x, code, outer_code) + rtx x; + enum rtx_code code, outer_code; +{ + enum machine_mode mode = GET_MODE (x); + enum rtx_code subcode; + int extra_cost; + + switch (code) + { + case MEM: + /* Memory costs quite a lot for the first word, but subsequent words + load at the equivalent of a single insn each. */ + return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD) + + (CONSTANT_POOL_ADDRESS_P (x) ? 4 : 0)); + + case DIV: + case MOD: + return 100; + + case ROTATE: + if (mode == SImode && GET_CODE (XEXP (x, 1)) == REG) + return 4; + /* Fall through */ + case ROTATERT: + if (mode != SImode) + return 8; + /* Fall through */ + case ASHIFT: case LSHIFTRT: case ASHIFTRT: + if (mode == DImode) + return (8 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : 8) + + ((GET_CODE (XEXP (x, 0)) == REG + || (GET_CODE (XEXP (x, 0)) == SUBREG + && GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG)) + ? 0 : 8)); + return (1 + ((GET_CODE (XEXP (x, 0)) == REG + || (GET_CODE (XEXP (x, 0)) == SUBREG + && GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG)) + ? 0 : 4) + + ((GET_CODE (XEXP (x, 1)) == REG + || (GET_CODE (XEXP (x, 1)) == SUBREG + && GET_CODE (SUBREG_REG (XEXP (x, 1))) == REG) + || (GET_CODE (XEXP (x, 1)) == CONST_INT)) + ? 0 : 4)); + + case MINUS: + if (mode == DImode) + return (4 + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 8) + + ((REG_OR_SUBREG_REG (XEXP (x, 0)) + || (GET_CODE (XEXP (x, 0)) == CONST_INT + && const_ok_for_arm (INTVAL (XEXP (x, 0))))) + ? 0 : 8)); + + if (GET_MODE_CLASS (mode) == MODE_FLOAT) + return (2 + ((REG_OR_SUBREG_REG (XEXP (x, 1)) + || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE + && const_double_rtx_ok_for_fpu (XEXP (x, 1)))) + ? 0 : 8) + + ((REG_OR_SUBREG_REG (XEXP (x, 0)) + || (GET_CODE (XEXP (x, 0)) == CONST_DOUBLE + && const_double_rtx_ok_for_fpu (XEXP (x, 0)))) + ? 0 : 8)); + + if (((GET_CODE (XEXP (x, 0)) == CONST_INT + && const_ok_for_arm (INTVAL (XEXP (x, 0))) + && REG_OR_SUBREG_REG (XEXP (x, 1)))) + || (((subcode = GET_CODE (XEXP (x, 1))) == ASHIFT + || subcode == ASHIFTRT || subcode == LSHIFTRT + || subcode == ROTATE || subcode == ROTATERT + || (subcode == MULT + && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT + && ((INTVAL (XEXP (XEXP (x, 1), 1)) & + (INTVAL (XEXP (XEXP (x, 1), 1)) - 1)) == 0))) + && REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 0)) + && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 1)) + || GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT) + && REG_OR_SUBREG_REG (XEXP (x, 0)))) + return 1; + /* Fall through */ + + case PLUS: + if (GET_MODE_CLASS (mode) == MODE_FLOAT) + return (2 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8) + + ((REG_OR_SUBREG_REG (XEXP (x, 1)) + || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE + && const_double_rtx_ok_for_fpu (XEXP (x, 1)))) + ? 0 : 8)); + + /* Fall through */ + case AND: case XOR: case IOR: + extra_cost = 0; + + /* Normally the frame registers will be spilt into reg+const during + reload, so it is a bad idea to combine them with other instructions, + since then they might not be moved outside of loops. As a compromise + we allow integration with ops that have a constant as their second + operand. */ + if ((REG_OR_SUBREG_REG (XEXP (x, 0)) + && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0))) + && GET_CODE (XEXP (x, 1)) != CONST_INT) + || (REG_OR_SUBREG_REG (XEXP (x, 0)) + && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0))))) + extra_cost = 4; + + if (mode == DImode) + return (4 + extra_cost + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8) + + ((REG_OR_SUBREG_REG (XEXP (x, 1)) + || (GET_CODE (XEXP (x, 1)) == CONST_INT + && const_ok_for_op (INTVAL (XEXP (x, 1)), code, mode))) + ? 0 : 8)); + + if (REG_OR_SUBREG_REG (XEXP (x, 0))) + return (1 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : extra_cost) + + ((REG_OR_SUBREG_REG (XEXP (x, 1)) + || (GET_CODE (XEXP (x, 1)) == CONST_INT + && const_ok_for_op (INTVAL (XEXP (x, 1)), code, mode))) + ? 0 : 4)); + + else if (REG_OR_SUBREG_REG (XEXP (x, 1))) + return (1 + extra_cost + + ((((subcode = GET_CODE (XEXP (x, 0))) == ASHIFT + || subcode == LSHIFTRT || subcode == ASHIFTRT + || subcode == ROTATE || subcode == ROTATERT + || (subcode == MULT + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && ((INTVAL (XEXP (XEXP (x, 0), 1)) & + (INTVAL (XEXP (XEXP (x, 0), 1)) - 1)) == 0))) + && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 0))) + && ((REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 1))) + || GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)) + ? 0 : 4)); + + return 8; + + case MULT: + /* There is no point basing this on the tuning, since it is always the + fast variant if it exists at all */ + if (arm_fast_multiply && mode == DImode + && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1))) + && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND + || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND)) + return 8; + + if (GET_MODE_CLASS (mode) == MODE_FLOAT + || mode == DImode) + return 30; + + if (GET_CODE (XEXP (x, 1)) == CONST_INT) + { + unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1)) + & (unsigned HOST_WIDE_INT) 0xffffffff); + int add_cost = const_ok_for_arm (i) ? 4 : 8; + int j; + /* Tune as appropriate */ + int booth_unit_size = ((tune_flags & FL_FAST_MULT) ? 8 : 2); + + for (j = 0; i && j < 32; j += booth_unit_size) + { + i >>= booth_unit_size; + add_cost += 2; + } + + return add_cost; + } + + return (((tune_flags & FL_FAST_MULT) ? 8 : 30) + + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4) + + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4)); + + case TRUNCATE: + if (arm_fast_multiply && mode == SImode + && GET_CODE (XEXP (x, 0)) == LSHIFTRT + && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT + && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) + == GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1))) + && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == ZERO_EXTEND + || GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == SIGN_EXTEND)) + return 8; + return 99; + + case NEG: + if (GET_MODE_CLASS (mode) == MODE_FLOAT) + return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 6); + /* Fall through */ + case NOT: + if (mode == DImode) + return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4); + + return 1 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4); + + case IF_THEN_ELSE: + if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC) + return 14; + return 2; + + case COMPARE: + return 1; + + case ABS: + return 4 + (mode == DImode ? 4 : 0); + + case SIGN_EXTEND: + if (GET_MODE (XEXP (x, 0)) == QImode) + return (4 + (mode == DImode ? 4 : 0) + + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); + /* Fall through */ + case ZERO_EXTEND: + switch (GET_MODE (XEXP (x, 0))) + { + case QImode: + return (1 + (mode == DImode ? 4 : 0) + + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); + + case HImode: + return (4 + (mode == DImode ? 4 : 0) + + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); + + case SImode: + return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); + + default: + break; + } + abort (); + + default: + return 99; + } +} + +int +arm_adjust_cost (insn, link, dep, cost) + rtx insn; + rtx link; + rtx dep; + int cost; +{ + rtx i_pat, d_pat; + + if ((i_pat = single_set (insn)) != NULL + && GET_CODE (SET_SRC (i_pat)) == MEM + && (d_pat = single_set (dep)) != NULL + && GET_CODE (SET_DEST (d_pat)) == MEM) + { + /* This is a load after a store, there is no conflict if the load reads + from a cached area. Assume that loads from the stack, and from the + constant pool are cached, and that others will miss. This is a + hack. */ + +/* debug_rtx (insn); + debug_rtx (dep); + debug_rtx (link); + fprintf (stderr, "costs %d\n", cost); */ + + if (CONSTANT_POOL_ADDRESS_P (XEXP (SET_SRC (i_pat), 0)) + || reg_mentioned_p (stack_pointer_rtx, XEXP (SET_SRC (i_pat), 0)) + || reg_mentioned_p (frame_pointer_rtx, XEXP (SET_SRC (i_pat), 0)) + || reg_mentioned_p (hard_frame_pointer_rtx, + XEXP (SET_SRC (i_pat), 0))) + { +/* fprintf (stderr, "***** Now 1\n"); */ + return 1; + } + } + + return cost; +} + +/* This code has been fixed for cross compilation. */ + +static int fpa_consts_inited = 0; + +char *strings_fpa[8] = { + "0", "1", "2", "3", + "4", "5", "0.5", "10" +}; + +static REAL_VALUE_TYPE values_fpa[8]; + +static void +init_fpa_table () +{ + int i; + REAL_VALUE_TYPE r; + + for (i = 0; i < 8; i++) + { + r = REAL_VALUE_ATOF (strings_fpa[i], DFmode); + values_fpa[i] = r; + } + + fpa_consts_inited = 1; +} + +/* Return TRUE if rtx X is a valid immediate FPU constant. */ + +int +const_double_rtx_ok_for_fpu (x) + rtx x; +{ + REAL_VALUE_TYPE r; + int i; + + if (!fpa_consts_inited) + init_fpa_table (); + + REAL_VALUE_FROM_CONST_DOUBLE (r, x); + if (REAL_VALUE_MINUS_ZERO (r)) + return 0; + + for (i = 0; i < 8; i++) + if (REAL_VALUES_EQUAL (r, values_fpa[i])) + return 1; + + return 0; +} + +/* Return TRUE if rtx X is a valid immediate FPU constant. */ + +int +neg_const_double_rtx_ok_for_fpu (x) + rtx x; +{ + REAL_VALUE_TYPE r; + int i; + + if (!fpa_consts_inited) + init_fpa_table (); + + REAL_VALUE_FROM_CONST_DOUBLE (r, x); + r = REAL_VALUE_NEGATE (r); + if (REAL_VALUE_MINUS_ZERO (r)) + return 0; + + for (i = 0; i < 8; i++) + if (REAL_VALUES_EQUAL (r, values_fpa[i])) + return 1; + + return 0; +} + +/* Predicates for `match_operand' and `match_operator'. */ + +/* s_register_operand is the same as register_operand, but it doesn't accept + (SUBREG (MEM)...). + + This function exists because at the time it was put in it led to better + code. SUBREG(MEM) always needs a reload in the places where + s_register_operand is used, and this seemed to lead to excessive + reloading. */ + +int +s_register_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + if (GET_MODE (op) != mode && mode != VOIDmode) + return 0; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + /* We don't consider registers whose class is NO_REGS + to be a register operand. */ + return (GET_CODE (op) == REG + && (REGNO (op) >= FIRST_PSEUDO_REGISTER + || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); +} + +/* Only accept reg, subreg(reg), const_int. */ + +int +reg_or_int_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + if (GET_CODE (op) == CONST_INT) + return 1; + + if (GET_MODE (op) != mode && mode != VOIDmode) + return 0; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + /* We don't consider registers whose class is NO_REGS + to be a register operand. */ + return (GET_CODE (op) == REG + && (REGNO (op) >= FIRST_PSEUDO_REGISTER + || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); +} + +/* Return 1 if OP is an item in memory, given that we are in reload. */ + +int +reload_memory_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + int regno = true_regnum (op); + + return (! CONSTANT_P (op) + && (regno == -1 + || (GET_CODE (op) == REG + && REGNO (op) >= FIRST_PSEUDO_REGISTER))); +} + +/* Return 1 if OP is a valid memory address, but not valid for a signed byte + memory access (architecture V4) */ +int +bad_signed_byte_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (! memory_operand (op, mode) || GET_CODE (op) != MEM) + return 0; + + op = XEXP (op, 0); + + /* A sum of anything more complex than reg + reg or reg + const is bad */ + if ((GET_CODE (op) == PLUS || GET_CODE (op) == MINUS) + && (! s_register_operand (XEXP (op, 0), VOIDmode) + || (! s_register_operand (XEXP (op, 1), VOIDmode) + && GET_CODE (XEXP (op, 1)) != CONST_INT))) + return 1; + + /* Big constants are also bad */ + if (GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT + && (INTVAL (XEXP (op, 1)) > 0xff + || -INTVAL (XEXP (op, 1)) > 0xff)) + return 1; + + /* Everything else is good, or can will automatically be made so. */ + return 0; +} + +/* Return TRUE for valid operands for the rhs of an ARM instruction. */ + +int +arm_rhs_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (s_register_operand (op, mode) + || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op)))); +} + +/* Return TRUE for valid operands for the rhs of an ARM instruction, or a load. + */ + +int +arm_rhsm_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (s_register_operand (op, mode) + || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op))) + || memory_operand (op, mode)); +} + +/* Return TRUE for valid operands for the rhs of an ARM instruction, or if a + constant that is valid when negated. */ + +int +arm_add_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (s_register_operand (op, mode) + || (GET_CODE (op) == CONST_INT + && (const_ok_for_arm (INTVAL (op)) + || const_ok_for_arm (-INTVAL (op))))); +} + +int +arm_not_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (s_register_operand (op, mode) + || (GET_CODE (op) == CONST_INT + && (const_ok_for_arm (INTVAL (op)) + || const_ok_for_arm (~INTVAL (op))))); +} + +/* Return TRUE if the operand is a memory reference which contains an + offsettable address. */ +int +offsettable_memory_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + if (mode == VOIDmode) + mode = GET_MODE (op); + + return (mode == GET_MODE (op) + && GET_CODE (op) == MEM + && offsettable_address_p (reload_completed | reload_in_progress, + mode, XEXP (op, 0))); +} + +/* Return TRUE if the operand is a memory reference which is, or can be + made word aligned by adjusting the offset. */ +int +alignable_memory_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + rtx reg; + + if (mode == VOIDmode) + mode = GET_MODE (op); + + if (mode != GET_MODE (op) || GET_CODE (op) != MEM) + return 0; + + op = XEXP (op, 0); + + return ((GET_CODE (reg = op) == REG + || (GET_CODE (op) == SUBREG + && GET_CODE (reg = SUBREG_REG (op)) == REG) + || (GET_CODE (op) == PLUS + && GET_CODE (XEXP (op, 1)) == CONST_INT + && (GET_CODE (reg = XEXP (op, 0)) == REG + || (GET_CODE (XEXP (op, 0)) == SUBREG + && GET_CODE (reg = SUBREG_REG (XEXP (op, 0))) == REG)))) + && REGNO_POINTER_ALIGN (REGNO (reg)) >= 4); +} + +/* Similar to s_register_operand, but does not allow hard integer + registers. */ +int +f_register_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + if (GET_MODE (op) != mode && mode != VOIDmode) + return 0; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + /* We don't consider registers whose class is NO_REGS + to be a register operand. */ + return (GET_CODE (op) == REG + && (REGNO (op) >= FIRST_PSEUDO_REGISTER + || REGNO_REG_CLASS (REGNO (op)) == FPU_REGS)); +} + +/* Return TRUE for valid operands for the rhs of an FPU instruction. */ + +int +fpu_rhs_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (s_register_operand (op, mode)) + return TRUE; + else if (GET_CODE (op) == CONST_DOUBLE) + return (const_double_rtx_ok_for_fpu (op)); + + return FALSE; +} + +int +fpu_add_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (s_register_operand (op, mode)) + return TRUE; + else if (GET_CODE (op) == CONST_DOUBLE) + return (const_double_rtx_ok_for_fpu (op) + || neg_const_double_rtx_ok_for_fpu (op)); + + return FALSE; +} + +/* Return nonzero if OP is a constant power of two. */ + +int +power_of_two_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (GET_CODE (op) == CONST_INT) + { + HOST_WIDE_INT value = INTVAL(op); + return value != 0 && (value & (value - 1)) == 0; + } + return FALSE; +} + +/* Return TRUE for a valid operand of a DImode operation. + Either: REG, SUBREG, CONST_DOUBLE or MEM(DImode_address). + Note that this disallows MEM(REG+REG), but allows + MEM(PRE/POST_INC/DEC(REG)). */ + +int +di_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (s_register_operand (op, mode)) + return TRUE; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + switch (GET_CODE (op)) + { + case CONST_DOUBLE: + case CONST_INT: + return TRUE; + + case MEM: + return memory_address_p (DImode, XEXP (op, 0)); + + default: + return FALSE; + } +} + +/* Return TRUE for a valid operand of a DFmode operation when -msoft-float. + Either: REG, SUBREG, CONST_DOUBLE or MEM(DImode_address). + Note that this disallows MEM(REG+REG), but allows + MEM(PRE/POST_INC/DEC(REG)). */ + +int +soft_df_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (s_register_operand (op, mode)) + return TRUE; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + switch (GET_CODE (op)) + { + case CONST_DOUBLE: + return TRUE; + + case MEM: + return memory_address_p (DFmode, XEXP (op, 0)); + + default: + return FALSE; + } +} + +/* Return TRUE for valid index operands. */ + +int +index_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (s_register_operand(op, mode) + || (immediate_operand (op, mode) + && INTVAL (op) < 4096 && INTVAL (op) > -4096)); +} + +/* Return TRUE for valid shifts by a constant. This also accepts any + power of two on the (somewhat overly relaxed) assumption that the + shift operator in this case was a mult. */ + +int +const_shift_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (power_of_two_operand (op, mode) + || (immediate_operand (op, mode) + && (INTVAL (op) < 32 && INTVAL (op) > 0))); +} + +/* Return TRUE for arithmetic operators which can be combined with a multiply + (shift). */ + +int +shiftable_operator (x, mode) + rtx x; + enum machine_mode mode; +{ + if (GET_MODE (x) != mode) + return FALSE; + else + { + enum rtx_code code = GET_CODE (x); + + return (code == PLUS || code == MINUS + || code == IOR || code == XOR || code == AND); + } +} + +/* Return TRUE for shift operators. */ + +int +shift_operator (x, mode) + rtx x; + enum machine_mode mode; +{ + if (GET_MODE (x) != mode) + return FALSE; + else + { + enum rtx_code code = GET_CODE (x); + + if (code == MULT) + return power_of_two_operand (XEXP (x, 1)); + + return (code == ASHIFT || code == ASHIFTRT || code == LSHIFTRT + || code == ROTATERT); + } +} + +int equality_operator (x, mode) + rtx x; + enum machine_mode mode; +{ + return GET_CODE (x) == EQ || GET_CODE (x) == NE; +} + +/* Return TRUE for SMIN SMAX UMIN UMAX operators. */ + +int +minmax_operator (x, mode) + rtx x; + enum machine_mode mode; +{ + enum rtx_code code = GET_CODE (x); + + if (GET_MODE (x) != mode) + return FALSE; + + return code == SMIN || code == SMAX || code == UMIN || code == UMAX; +} + +/* return TRUE if x is EQ or NE */ + +/* Return TRUE if this is the condition code register, if we aren't given + a mode, accept any class CCmode register */ + +int +cc_register (x, mode) + rtx x; + enum machine_mode mode; +{ + if (mode == VOIDmode) + { + mode = GET_MODE (x); + if (GET_MODE_CLASS (mode) != MODE_CC) + return FALSE; + } + + if (mode == GET_MODE (x) && GET_CODE (x) == REG && REGNO (x) == 24) + return TRUE; + + return FALSE; +} + +/* Return TRUE if this is the condition code register, if we aren't given + a mode, accept any class CCmode register which indicates a dominance + expression. */ + +int +dominant_cc_register (x, mode) + rtx x; + enum machine_mode mode; +{ + if (mode == VOIDmode) + { + mode = GET_MODE (x); + if (GET_MODE_CLASS (mode) != MODE_CC) + return FALSE; + } + + if (mode != CC_DNEmode && mode != CC_DEQmode + && mode != CC_DLEmode && mode != CC_DLTmode + && mode != CC_DGEmode && mode != CC_DGTmode + && mode != CC_DLEUmode && mode != CC_DLTUmode + && mode != CC_DGEUmode && mode != CC_DGTUmode) + return FALSE; + + if (mode == GET_MODE (x) && GET_CODE (x) == REG && REGNO (x) == 24) + return TRUE; + + return FALSE; +} + +/* Return TRUE if X references a SYMBOL_REF. */ +int +symbol_mentioned_p (x) + rtx x; +{ + register char *fmt; + register int i; + + if (GET_CODE (x) == SYMBOL_REF) + return 1; + + fmt = GET_RTX_FORMAT (GET_CODE (x)); + for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) + { + if (fmt[i] == 'E') + { + register int j; + + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + if (symbol_mentioned_p (XVECEXP (x, i, j))) + return 1; + } + else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i))) + return 1; + } + + return 0; +} + +/* Return TRUE if X references a LABEL_REF. */ +int +label_mentioned_p (x) + rtx x; +{ + register char *fmt; + register int i; + + if (GET_CODE (x) == LABEL_REF) + return 1; + + fmt = GET_RTX_FORMAT (GET_CODE (x)); + for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) + { + if (fmt[i] == 'E') + { + register int j; + + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + if (label_mentioned_p (XVECEXP (x, i, j))) + return 1; + } + else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i))) + return 1; + } + + return 0; +} + +enum rtx_code +minmax_code (x) + rtx x; +{ + enum rtx_code code = GET_CODE (x); + + if (code == SMAX) + return GE; + else if (code == SMIN) + return LE; + else if (code == UMIN) + return LEU; + else if (code == UMAX) + return GEU; + + abort (); +} + +/* Return 1 if memory locations are adjacent */ + +int +adjacent_mem_locations (a, b) + rtx a, b; +{ + int val0 = 0, val1 = 0; + int reg0, reg1; + + if ((GET_CODE (XEXP (a, 0)) == REG + || (GET_CODE (XEXP (a, 0)) == PLUS + && GET_CODE (XEXP (XEXP (a, 0), 1)) == CONST_INT)) + && (GET_CODE (XEXP (b, 0)) == REG + || (GET_CODE (XEXP (b, 0)) == PLUS + && GET_CODE (XEXP (XEXP (b, 0), 1)) == CONST_INT))) + { + if (GET_CODE (XEXP (a, 0)) == PLUS) + { + reg0 = REGNO (XEXP (XEXP (a, 0), 0)); + val0 = INTVAL (XEXP (XEXP (a, 0), 1)); + } + else + reg0 = REGNO (XEXP (a, 0)); + if (GET_CODE (XEXP (b, 0)) == PLUS) + { + reg1 = REGNO (XEXP (XEXP (b, 0), 0)); + val1 = INTVAL (XEXP (XEXP (b, 0), 1)); + } + else + reg1 = REGNO (XEXP (b, 0)); + return (reg0 == reg1) && ((val1 - val0) == 4 || (val0 - val1) == 4); + } + return 0; +} + +/* Return 1 if OP is a load multiple operation. It is known to be + parallel and the first section will be tested. */ + +int +load_multiple_operation (op, mode) + rtx op; + enum machine_mode mode; +{ + HOST_WIDE_INT count = XVECLEN (op, 0); + int dest_regno; + rtx src_addr; + HOST_WIDE_INT i = 1, base = 0; + rtx elt; + + if (count <= 1 + || GET_CODE (XVECEXP (op, 0, 0)) != SET) + return 0; + + /* Check to see if this might be a write-back */ + if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS) + { + i++; + base = 1; + + /* Now check it more carefully */ + if (GET_CODE (SET_DEST (elt)) != REG + || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG + || REGNO (XEXP (SET_SRC (elt), 0)) != REGNO (SET_DEST (elt)) + || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT + || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 2) * 4 + || GET_CODE (XVECEXP (op, 0, count - 1)) != CLOBBER + || GET_CODE (XEXP (XVECEXP (op, 0, count - 1), 0)) != REG + || REGNO (XEXP (XVECEXP (op, 0, count - 1), 0)) + != REGNO (SET_DEST (elt))) + return 0; + + count--; + } + + /* Perform a quick check so we don't blow up below. */ + if (count <= i + || GET_CODE (XVECEXP (op, 0, i - 1)) != SET + || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != REG + || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != MEM) + return 0; + + dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, i - 1))); + src_addr = XEXP (SET_SRC (XVECEXP (op, 0, i - 1)), 0); + + for (; i < count; i++) + { + elt = XVECEXP (op, 0, i); + + if (GET_CODE (elt) != SET + || GET_CODE (SET_DEST (elt)) != REG + || GET_MODE (SET_DEST (elt)) != SImode + || REGNO (SET_DEST (elt)) != dest_regno + i - base + || GET_CODE (SET_SRC (elt)) != MEM + || GET_MODE (SET_SRC (elt)) != SImode + || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS + || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr) + || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT + || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != (i - base) * 4) + return 0; + } + + return 1; +} + +/* Return 1 if OP is a store multiple operation. It is known to be + parallel and the first section will be tested. */ + +int +store_multiple_operation (op, mode) + rtx op; + enum machine_mode mode; +{ + HOST_WIDE_INT count = XVECLEN (op, 0); + int src_regno; + rtx dest_addr; + HOST_WIDE_INT i = 1, base = 0; + rtx elt; + + if (count <= 1 + || GET_CODE (XVECEXP (op, 0, 0)) != SET) + return 0; + + /* Check to see if this might be a write-back */ + if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS) + { + i++; + base = 1; + + /* Now check it more carefully */ + if (GET_CODE (SET_DEST (elt)) != REG + || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG + || REGNO (XEXP (SET_SRC (elt), 0)) != REGNO (SET_DEST (elt)) + || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT + || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 2) * 4 + || GET_CODE (XVECEXP (op, 0, count - 1)) != CLOBBER + || GET_CODE (XEXP (XVECEXP (op, 0, count - 1), 0)) != REG + || REGNO (XEXP (XVECEXP (op, 0, count - 1), 0)) + != REGNO (SET_DEST (elt))) + return 0; + + count--; + } + + /* Perform a quick check so we don't blow up below. */ + if (count <= i + || GET_CODE (XVECEXP (op, 0, i - 1)) != SET + || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != MEM + || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != REG) + return 0; + + src_regno = REGNO (SET_SRC (XVECEXP (op, 0, i - 1))); + dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, i - 1)), 0); + + for (; i < count; i++) + { + elt = XVECEXP (op, 0, i); + + if (GET_CODE (elt) != SET + || GET_CODE (SET_SRC (elt)) != REG + || GET_MODE (SET_SRC (elt)) != SImode + || REGNO (SET_SRC (elt)) != src_regno + i - base + || GET_CODE (SET_DEST (elt)) != MEM + || GET_MODE (SET_DEST (elt)) != SImode + || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS + || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr) + || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT + || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != (i - base) * 4) + return 0; + } + + return 1; +} + +int +load_multiple_sequence (operands, nops, regs, base, load_offset) + rtx *operands; + int nops; + int *regs; + int *base; + HOST_WIDE_INT *load_offset; +{ + int unsorted_regs[4]; + HOST_WIDE_INT unsorted_offsets[4]; + int order[4]; + int base_reg = -1; + int i; + + /* Can only handle 2, 3, or 4 insns at present, though could be easily + extended if required. */ + if (nops < 2 || nops > 4) + abort (); + + /* Loop over the operands and check that the memory references are + suitable (ie immediate offsets from the same base register). At + the same time, extract the target register, and the memory + offsets. */ + for (i = 0; i < nops; i++) + { + rtx reg; + rtx offset; + + /* Convert a subreg of a mem into the mem itself. */ + if (GET_CODE (operands[nops + i]) == SUBREG) + operands[nops + i] = alter_subreg(operands[nops + i]); + + if (GET_CODE (operands[nops + i]) != MEM) + abort (); + + /* Don't reorder volatile memory references; it doesn't seem worth + looking for the case where the order is ok anyway. */ + if (MEM_VOLATILE_P (operands[nops + i])) + return 0; + + offset = const0_rtx; + + if ((GET_CODE (reg = XEXP (operands[nops + i], 0)) == REG + || (GET_CODE (reg) == SUBREG + && GET_CODE (reg = SUBREG_REG (reg)) == REG)) + || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS + && ((GET_CODE (reg = XEXP (XEXP (operands[nops + i], 0), 0)) + == REG) + || (GET_CODE (reg) == SUBREG + && GET_CODE (reg = SUBREG_REG (reg)) == REG)) + && (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1)) + == CONST_INT))) + { + if (i == 0) + { + base_reg = REGNO(reg); + unsorted_regs[0] = (GET_CODE (operands[i]) == REG + ? REGNO (operands[i]) + : REGNO (SUBREG_REG (operands[i]))); + order[0] = 0; + } + else + { + if (base_reg != REGNO (reg)) + /* Not addressed from the same base register. */ + return 0; + + unsorted_regs[i] = (GET_CODE (operands[i]) == REG + ? REGNO (operands[i]) + : REGNO (SUBREG_REG (operands[i]))); + if (unsorted_regs[i] < unsorted_regs[order[0]]) + order[0] = i; + } + + /* If it isn't an integer register, or if it overwrites the + base register but isn't the last insn in the list, then + we can't do this. */ + if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14 + || (i != nops - 1 && unsorted_regs[i] == base_reg)) + return 0; + + unsorted_offsets[i] = INTVAL (offset); + } + else + /* Not a suitable memory address. */ + return 0; + } + + /* All the useful information has now been extracted from the + operands into unsorted_regs and unsorted_offsets; additionally, + order[0] has been set to the lowest numbered register in the + list. Sort the registers into order, and check that the memory + offsets are ascending and adjacent. */ + + for (i = 1; i < nops; i++) + { + int j; + + order[i] = order[i - 1]; + for (j = 0; j < nops; j++) + if (unsorted_regs[j] > unsorted_regs[order[i - 1]] + && (order[i] == order[i - 1] + || unsorted_regs[j] < unsorted_regs[order[i]])) + order[i] = j; + + /* Have we found a suitable register? if not, one must be used more + than once. */ + if (order[i] == order[i - 1]) + return 0; + + /* Is the memory address adjacent and ascending? */ + if (unsorted_offsets[order[i]] != unsorted_offsets[order[i - 1]] + 4) + return 0; + } + + if (base) + { + *base = base_reg; + + for (i = 0; i < nops; i++) + regs[i] = unsorted_regs[order[i]]; + + *load_offset = unsorted_offsets[order[0]]; + } + + if (unsorted_offsets[order[0]] == 0) + return 1; /* ldmia */ + + if (unsorted_offsets[order[0]] == 4) + return 2; /* ldmib */ + + if (unsorted_offsets[order[nops - 1]] == 0) + return 3; /* ldmda */ + + if (unsorted_offsets[order[nops - 1]] == -4) + return 4; /* ldmdb */ + + /* For ARM8,9 & StrongARM, 2 ldr instructions are faster than an ldm if + the offset isn't small enough. The reason 2 ldrs are faster is because + these ARMs are able to do more than one cache access in a single cycle. + The ARM9 and StrongARM have Harvard caches, whilst the ARM8 has a double + bandwidth cache. This means that these cores can do both an instruction + fetch and a data fetch in a single cycle, so the trick of calculating the + address into a scratch register (one of the result regs) and then doing a + load multiple actually becomes slower (and no smaller in code size). That + is the transformation + + ldr rd1, [rbase + offset] + ldr rd2, [rbase + offset + 4] + + to + + add rd1, rbase, offset + ldmia rd1, {rd1, rd2} + + produces worse code -- '3 cycles + any stalls on rd2' instead of '2 cycles + + any stalls on rd2'. On ARMs with only one cache access per cycle, the + first sequence could never complete in less than 6 cycles, whereas the ldm + sequence would only take 5 and would make better use of sequential accesses + if not hitting the cache. + + We cheat here and test 'arm_ld_sched' which we currently know to only be + true for the ARM8, ARM9 and StrongARM. If this ever changes, then the test + below needs to be reworked. */ + if (nops == 2 && arm_ld_sched) + return 0; + + /* Can't do it without setting up the offset, only do this if it takes + no more than one insn. */ + return (const_ok_for_arm (unsorted_offsets[order[0]]) + || const_ok_for_arm (-unsorted_offsets[order[0]])) ? 5 : 0; +} + +char * +emit_ldm_seq (operands, nops) + rtx *operands; + int nops; +{ + int regs[4]; + int base_reg; + HOST_WIDE_INT offset; + char buf[100]; + int i; + + switch (load_multiple_sequence (operands, nops, regs, &base_reg, &offset)) + { + case 1: + strcpy (buf, "ldm%?ia\t"); + break; + + case 2: + strcpy (buf, "ldm%?ib\t"); + break; + + case 3: + strcpy (buf, "ldm%?da\t"); + break; + + case 4: + strcpy (buf, "ldm%?db\t"); + break; + + case 5: + if (offset >= 0) + sprintf (buf, "add%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX, + reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg], + (long) offset); + else + sprintf (buf, "sub%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX, + reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg], + (long) -offset); + output_asm_insn (buf, operands); + base_reg = regs[0]; + strcpy (buf, "ldm%?ia\t"); + break; + + default: + abort (); + } + + sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX, + reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]); + + for (i = 1; i < nops; i++) + sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX, + reg_names[regs[i]]); + + strcat (buf, "}\t%@ phole ldm"); + + output_asm_insn (buf, operands); + return ""; +} + +int +store_multiple_sequence (operands, nops, regs, base, load_offset) + rtx *operands; + int nops; + int *regs; + int *base; + HOST_WIDE_INT *load_offset; +{ + int unsorted_regs[4]; + HOST_WIDE_INT unsorted_offsets[4]; + int order[4]; + int base_reg = -1; + int i; + + /* Can only handle 2, 3, or 4 insns at present, though could be easily + extended if required. */ + if (nops < 2 || nops > 4) + abort (); + + /* Loop over the operands and check that the memory references are + suitable (ie immediate offsets from the same base register). At + the same time, extract the target register, and the memory + offsets. */ + for (i = 0; i < nops; i++) + { + rtx reg; + rtx offset; + + /* Convert a subreg of a mem into the mem itself. */ + if (GET_CODE (operands[nops + i]) == SUBREG) + operands[nops + i] = alter_subreg(operands[nops + i]); + + if (GET_CODE (operands[nops + i]) != MEM) + abort (); + + /* Don't reorder volatile memory references; it doesn't seem worth + looking for the case where the order is ok anyway. */ + if (MEM_VOLATILE_P (operands[nops + i])) + return 0; + + offset = const0_rtx; + + if ((GET_CODE (reg = XEXP (operands[nops + i], 0)) == REG + || (GET_CODE (reg) == SUBREG + && GET_CODE (reg = SUBREG_REG (reg)) == REG)) + || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS + && ((GET_CODE (reg = XEXP (XEXP (operands[nops + i], 0), 0)) + == REG) + || (GET_CODE (reg) == SUBREG + && GET_CODE (reg = SUBREG_REG (reg)) == REG)) + && (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1)) + == CONST_INT))) + { + if (i == 0) + { + base_reg = REGNO(reg); + unsorted_regs[0] = (GET_CODE (operands[i]) == REG + ? REGNO (operands[i]) + : REGNO (SUBREG_REG (operands[i]))); + order[0] = 0; + } + else + { + if (base_reg != REGNO (reg)) + /* Not addressed from the same base register. */ + return 0; + + unsorted_regs[i] = (GET_CODE (operands[i]) == REG + ? REGNO (operands[i]) + : REGNO (SUBREG_REG (operands[i]))); + if (unsorted_regs[i] < unsorted_regs[order[0]]) + order[0] = i; + } + + /* If it isn't an integer register, then we can't do this. */ + if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14) + return 0; + + unsorted_offsets[i] = INTVAL (offset); + } + else + /* Not a suitable memory address. */ + return 0; + } + + /* All the useful information has now been extracted from the + operands into unsorted_regs and unsorted_offsets; additionally, + order[0] has been set to the lowest numbered register in the + list. Sort the registers into order, and check that the memory + offsets are ascending and adjacent. */ + + for (i = 1; i < nops; i++) + { + int j; + + order[i] = order[i - 1]; + for (j = 0; j < nops; j++) + if (unsorted_regs[j] > unsorted_regs[order[i - 1]] + && (order[i] == order[i - 1] + || unsorted_regs[j] < unsorted_regs[order[i]])) + order[i] = j; + + /* Have we found a suitable register? if not, one must be used more + than once. */ + if (order[i] == order[i - 1]) + return 0; + + /* Is the memory address adjacent and ascending? */ + if (unsorted_offsets[order[i]] != unsorted_offsets[order[i - 1]] + 4) + return 0; + } + + if (base) + { + *base = base_reg; + + for (i = 0; i < nops; i++) + regs[i] = unsorted_regs[order[i]]; + + *load_offset = unsorted_offsets[order[0]]; + } + + if (unsorted_offsets[order[0]] == 0) + return 1; /* stmia */ + + if (unsorted_offsets[order[0]] == 4) + return 2; /* stmib */ + + if (unsorted_offsets[order[nops - 1]] == 0) + return 3; /* stmda */ + + if (unsorted_offsets[order[nops - 1]] == -4) + return 4; /* stmdb */ + + return 0; +} + +char * +emit_stm_seq (operands, nops) + rtx *operands; + int nops; +{ + int regs[4]; + int base_reg; + HOST_WIDE_INT offset; + char buf[100]; + int i; + + switch (store_multiple_sequence (operands, nops, regs, &base_reg, &offset)) + { + case 1: + strcpy (buf, "stm%?ia\t"); + break; + + case 2: + strcpy (buf, "stm%?ib\t"); + break; + + case 3: + strcpy (buf, "stm%?da\t"); + break; + + case 4: + strcpy (buf, "stm%?db\t"); + break; + + default: + abort (); + } + + sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX, + reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]); + + for (i = 1; i < nops; i++) + sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX, + reg_names[regs[i]]); + + strcat (buf, "}\t%@ phole stm"); + + output_asm_insn (buf, operands); + return ""; +} + +int +multi_register_push (op, mode) + rtx op; + enum machine_mode mode; +{ + if (GET_CODE (op) != PARALLEL + || (GET_CODE (XVECEXP (op, 0, 0)) != SET) + || (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC) + || (XINT (SET_SRC (XVECEXP (op, 0, 0)), 1) != 2)) + return 0; + + return 1; +} + + +/* Routines for use with attributes */ + +/* Return nonzero if ATTR is a valid attribute for DECL. + ATTRIBUTES are any existing attributes and ARGS are the arguments + supplied with ATTR. + + Supported attributes: + + naked: don't output any prologue or epilogue code, the user is assumed + to do the right thing. */ + +int +arm_valid_machine_decl_attribute (decl, attributes, attr, args) + tree decl; + tree attributes; + tree attr; + tree args; +{ + if (args != NULL_TREE) + return 0; + + if (is_attribute_p ("naked", attr)) + return TREE_CODE (decl) == FUNCTION_DECL; + return 0; +} + +/* Return nonzero if ATTR is a valid attribute for TYPE. + ATTRIBUTES are any existing attributes and ARGS are the arguments + supplied with ATTR. + + Supported attributes: + + short_call: assume the offset from the caller to the callee is small. + + long_call: don't assume the offset is small. */ + +int +arm_valid_machine_type_attribute (type, attributes, attr, args) + tree type; + tree attributes; + tree attr; + tree args; +{ + if (args != NULL_TREE) + return 0; + + if (is_attribute_p ("long_call", attr)) + return 1; + + if (is_attribute_p ("short_call", attr)) + return 1; + + return 0; +} + +/* Encode long_call or short_call attribute by prefixing + symbol name in DECL with a special character FLAG. */ + +void +arm_encode_call_attribute (decl, flag) + tree decl; + int flag; +{ + const char * str = XSTR (XEXP (DECL_RTL (decl), 0), 0); + int len = strlen (str); + char * newstr; + + /* Do not allow weak functions to be treated as short call. */ + if (DECL_WEAK (decl) && flag == SHORT_CALL_FLAG_CHAR) + return; + + if (ENCODED_SHORT_CALL_ATTR_P (str) + || ENCODED_LONG_CALL_ATTR_P (str)) + return; + + newstr = malloc (len + 2); + newstr[0] = flag; + strcpy (newstr + 1, str); + + XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr; +} + +/* Return the length of a function name prefix + that starts with the character 'c'. */ + +static int +arm_get_strip_length (char c) +{ + switch (c) + { + ARM_NAME_ENCODING_LENGTHS + default: return 0; + } +} + +/* Return a pointer to a function's name with any + and all prefix encodings stripped from it. */ + +char * +arm_strip_name_encoding (char * name) +{ + int skip; + + while ((skip = arm_get_strip_length (* name))) + name += skip; + + return name; +} + +/* Return 1 if the operand is a SYMBOL_REF for a function known to be + defined within the current compilation unit. If this caanot be + determined, then 0 is returned. */ + +static int +current_file_function_operand (sym_ref) + rtx sym_ref; +{ + /* This is a bit of a fib. A function will have a short call flag + applied to its name if it has the short call attribute, or it has + already been defined within the current compilation unit. */ + if (ENCODED_SHORT_CALL_ATTR_P (XSTR (sym_ref, 0))) + return 1; + + /* The current function is always defined within the current compilation + unit. if it s a weak definition however, then this may not be the real + definition of the function, and so we have to say no. */ + if (sym_ref == XEXP (DECL_RTL (current_function_decl), 0) + && !DECL_WEAK (current_function_decl)) + return 1; + + /* We cannot make the determination - default to returning 0. */ + return 0; +} + +/* Return non-zero if a 32 bit "long_call" should be generated for + this call. We generate a long_call if the function: + + a. has an __attribute__((long call)) + or b. the -mlong-calls command line switch has been specified + + However we do not generate a long call if the function: + + c. has an __attribute__ ((short_call)) + or d. has an __attribute__ ((section)) + or e. is defined within the current compilation unit. + + This function will be called by C fragments contained in the machine + description file. CALL_REF and CALL_COOKIE correspond to the matched + rtl operands. CALL_SYMBOL is used to distinguish between + two different callers of the function. It is set to 1 in the + "call_symbol" and "call_symbol_value" patterns and to 0 in the "call" + and "call_value" patterns. This is because of the difference in the + SYM_REFs passed by these patterns. */ + +int +arm_is_longcall_p (sym_ref, call_cookie, call_symbol) + rtx sym_ref; + int call_cookie; + int call_symbol; +{ + if (!call_symbol) + { + if (GET_CODE (sym_ref) != MEM) + return 0; + + sym_ref = XEXP (sym_ref, 0); + } + + if (GET_CODE (sym_ref) != SYMBOL_REF) + return 0; + + if (call_cookie & CALL_SHORT) + return 0; + + if (TARGET_LONG_CALLS && flag_function_sections) + return 1; + + if (current_file_function_operand (sym_ref)) + return 0; + + return (call_cookie & CALL_LONG) + || ENCODED_LONG_CALL_ATTR_P (XSTR (sym_ref, 0)) + || TARGET_LONG_CALLS; +} + +/* Return non-zero if FUNC is a naked function. */ + +static int +arm_naked_function_p (func) + tree func; +{ + tree a; + + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + + a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func)); + return a != NULL_TREE; +} + +/* Routines for use in generating RTL */ + +rtx +arm_gen_load_multiple (base_regno, count, from, up, write_back, unchanging_p, + in_struct_p, scalar_p) + int base_regno; + int count; + rtx from; + int up; + int write_back; + int unchanging_p; + int in_struct_p; + int scalar_p; +{ + int i = 0, j; + rtx result; + int sign = up ? 1 : -1; + rtx mem; + + result = gen_rtx (PARALLEL, VOIDmode, + rtvec_alloc (count + (write_back ? 2 : 0))); + if (write_back) + { + XVECEXP (result, 0, 0) + = gen_rtx (SET, GET_MODE (from), from, + plus_constant (from, count * 4 * sign)); + i = 1; + count++; + } + + for (j = 0; i < count; i++, j++) + { + mem = gen_rtx (MEM, SImode, plus_constant (from, j * 4 * sign)); + RTX_UNCHANGING_P (mem) = unchanging_p; + MEM_IN_STRUCT_P (mem) = in_struct_p; + MEM_SCALAR_P (mem) = scalar_p; + XVECEXP (result, 0, i) = gen_rtx (SET, VOIDmode, + gen_rtx (REG, SImode, base_regno + j), + mem); + } + + if (write_back) + XVECEXP (result, 0, i) = gen_rtx (CLOBBER, SImode, from); + + return result; +} + +rtx +arm_gen_store_multiple (base_regno, count, to, up, write_back, unchanging_p, + in_struct_p, scalar_p) + int base_regno; + int count; + rtx to; + int up; + int write_back; + int unchanging_p; + int in_struct_p; + int scalar_p; +{ + int i = 0, j; + rtx result; + int sign = up ? 1 : -1; + rtx mem; + + result = gen_rtx (PARALLEL, VOIDmode, + rtvec_alloc (count + (write_back ? 2 : 0))); + if (write_back) + { + XVECEXP (result, 0, 0) + = gen_rtx (SET, GET_MODE (to), to, + plus_constant (to, count * 4 * sign)); + i = 1; + count++; + } + + for (j = 0; i < count; i++, j++) + { + mem = gen_rtx (MEM, SImode, plus_constant (to, j * 4 * sign)); + RTX_UNCHANGING_P (mem) = unchanging_p; + MEM_IN_STRUCT_P (mem) = in_struct_p; + MEM_SCALAR_P (mem) = scalar_p; + + XVECEXP (result, 0, i) = gen_rtx (SET, VOIDmode, mem, + gen_rtx (REG, SImode, base_regno + j)); + } + + if (write_back) + XVECEXP (result, 0, i) = gen_rtx (CLOBBER, SImode, to); + + return result; +} + +int +arm_gen_movstrqi (operands) + rtx *operands; +{ + HOST_WIDE_INT in_words_to_go, out_words_to_go, last_bytes; + int i; + rtx src, dst; + rtx st_src, st_dst, fin_src, fin_dst; + rtx part_bytes_reg = NULL; + rtx mem; + int dst_unchanging_p, dst_in_struct_p, src_unchanging_p, src_in_struct_p; + int dst_scalar_p, src_scalar_p; + + if (GET_CODE (operands[2]) != CONST_INT + || GET_CODE (operands[3]) != CONST_INT + || INTVAL (operands[2]) > 64 + || INTVAL (operands[3]) & 3) + return 0; + + st_dst = XEXP (operands[0], 0); + st_src = XEXP (operands[1], 0); + + dst_unchanging_p = RTX_UNCHANGING_P (operands[0]); + dst_in_struct_p = MEM_IN_STRUCT_P (operands[0]); + dst_scalar_p = MEM_SCALAR_P (operands[0]); + src_unchanging_p = RTX_UNCHANGING_P (operands[1]); + src_in_struct_p = MEM_IN_STRUCT_P (operands[1]); + src_scalar_p = MEM_SCALAR_P (operands[1]); + + fin_dst = dst = copy_to_mode_reg (SImode, st_dst); + fin_src = src = copy_to_mode_reg (SImode, st_src); + + in_words_to_go = (INTVAL (operands[2]) + 3) / 4; + out_words_to_go = INTVAL (operands[2]) / 4; + last_bytes = INTVAL (operands[2]) & 3; + + if (out_words_to_go != in_words_to_go && ((in_words_to_go - 1) & 3) != 0) + part_bytes_reg = gen_rtx (REG, SImode, (in_words_to_go - 1) & 3); + + for (i = 0; in_words_to_go >= 2; i+=4) + { + if (in_words_to_go > 4) + emit_insn (arm_gen_load_multiple (0, 4, src, TRUE, TRUE, + src_unchanging_p, + src_in_struct_p, + src_scalar_p)); + else + emit_insn (arm_gen_load_multiple (0, in_words_to_go, src, TRUE, + FALSE, src_unchanging_p, + src_in_struct_p, src_scalar_p)); + + if (out_words_to_go) + { + if (out_words_to_go > 4) + emit_insn (arm_gen_store_multiple (0, 4, dst, TRUE, TRUE, + dst_unchanging_p, + dst_in_struct_p, + dst_scalar_p)); + else if (out_words_to_go != 1) + emit_insn (arm_gen_store_multiple (0, out_words_to_go, + dst, TRUE, + (last_bytes == 0 + ? FALSE : TRUE), + dst_unchanging_p, + dst_in_struct_p, + dst_scalar_p)); + else + { + mem = gen_rtx (MEM, SImode, dst); + RTX_UNCHANGING_P (mem) = dst_unchanging_p; + MEM_IN_STRUCT_P (mem) = dst_in_struct_p; + MEM_SCALAR_P (mem) = dst_scalar_p; + emit_move_insn (mem, gen_rtx (REG, SImode, 0)); + if (last_bytes != 0) + emit_insn (gen_addsi3 (dst, dst, GEN_INT (4))); + } + } + + in_words_to_go -= in_words_to_go < 4 ? in_words_to_go : 4; + out_words_to_go -= out_words_to_go < 4 ? out_words_to_go : 4; + } + + /* OUT_WORDS_TO_GO will be zero here if there are byte stores to do. */ + if (out_words_to_go) + { + rtx sreg; + + mem = gen_rtx (MEM, SImode, src); + RTX_UNCHANGING_P (mem) = src_unchanging_p; + MEM_IN_STRUCT_P (mem) = src_in_struct_p; + MEM_SCALAR_P (mem) = src_scalar_p; + emit_move_insn (sreg = gen_reg_rtx (SImode), mem); + emit_move_insn (fin_src = gen_reg_rtx (SImode), plus_constant (src, 4)); + + mem = gen_rtx (MEM, SImode, dst); + RTX_UNCHANGING_P (mem) = dst_unchanging_p; + MEM_IN_STRUCT_P (mem) = dst_in_struct_p; + MEM_SCALAR_P (mem) = dst_scalar_p; + emit_move_insn (mem, sreg); + emit_move_insn (fin_dst = gen_reg_rtx (SImode), plus_constant (dst, 4)); + in_words_to_go--; + + if (in_words_to_go) /* Sanity check */ + abort (); + } + + if (in_words_to_go) + { + if (in_words_to_go < 0) + abort (); + + mem = gen_rtx (MEM, SImode, src); + RTX_UNCHANGING_P (mem) = src_unchanging_p; + MEM_IN_STRUCT_P (mem) = src_in_struct_p; + MEM_SCALAR_P (mem) = src_scalar_p; + part_bytes_reg = copy_to_mode_reg (SImode, mem); + } + + if (BYTES_BIG_ENDIAN && last_bytes) + { + rtx tmp = gen_reg_rtx (SImode); + + if (part_bytes_reg == NULL) + abort (); + + /* The bytes we want are in the top end of the word */ + emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, + GEN_INT (8 * (4 - last_bytes)))); + part_bytes_reg = tmp; + + while (last_bytes) + { + mem = gen_rtx (MEM, QImode, plus_constant (dst, last_bytes - 1)); + RTX_UNCHANGING_P (mem) = dst_unchanging_p; + MEM_IN_STRUCT_P (mem) = dst_in_struct_p; + MEM_SCALAR_P (mem) = dst_scalar_p; + emit_move_insn (mem, gen_rtx (SUBREG, QImode, part_bytes_reg, 0)); + if (--last_bytes) + { + tmp = gen_reg_rtx (SImode); + emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (8))); + part_bytes_reg = tmp; + } + } + + } + else + { + while (last_bytes) + { + if (part_bytes_reg == NULL) + abort (); + + mem = gen_rtx (MEM, QImode, dst); + RTX_UNCHANGING_P (mem) = dst_unchanging_p; + MEM_IN_STRUCT_P (mem) = dst_in_struct_p; + MEM_SCALAR_P (mem) = dst_scalar_p; + emit_move_insn (mem, gen_rtx (SUBREG, QImode, part_bytes_reg, 0)); + if (--last_bytes) + { + rtx tmp = gen_reg_rtx (SImode); + + emit_insn (gen_addsi3 (dst, dst, const1_rtx)); + emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (8))); + part_bytes_reg = tmp; + } + } + } + + return 1; +} + +/* Generate a memory reference for a half word, such that it will be loaded + into the top 16 bits of the word. We can assume that the address is + known to be alignable and of the form reg, or plus (reg, const). */ +rtx +gen_rotated_half_load (memref) + rtx memref; +{ + HOST_WIDE_INT offset = 0; + rtx base = XEXP (memref, 0); + + if (GET_CODE (base) == PLUS) + { + offset = INTVAL (XEXP (base, 1)); + base = XEXP (base, 0); + } + + /* If we aren't allowed to generate unaligned addresses, then fail. */ + if (TARGET_SHORT_BY_BYTES + && ((BYTES_BIG_ENDIAN ? 1 : 0) ^ ((offset & 2) == 0))) + return NULL; + + base = gen_rtx (MEM, SImode, plus_constant (base, offset & ~2)); + + if ((BYTES_BIG_ENDIAN ? 1 : 0) ^ ((offset & 2) == 2)) + return base; + + return gen_rtx (ROTATE, SImode, base, GEN_INT (16)); +} + +static enum machine_mode +select_dominance_cc_mode (op, x, y, cond_or) + enum rtx_code op; + rtx x; + rtx y; + HOST_WIDE_INT cond_or; +{ + enum rtx_code cond1, cond2; + int swapped = 0; + + /* Currently we will probably get the wrong result if the individual + comparisons are not simple. This also ensures that it is safe to + reverse a comparison if necessary. */ + if ((arm_select_cc_mode (cond1 = GET_CODE (x), XEXP (x, 0), XEXP (x, 1)) + != CCmode) + || (arm_select_cc_mode (cond2 = GET_CODE (y), XEXP (y, 0), XEXP (y, 1)) + != CCmode)) + return CCmode; + + if (cond_or) + cond1 = reverse_condition (cond1); + + /* If the comparisons are not equal, and one doesn't dominate the other, + then we can't do this. */ + if (cond1 != cond2 + && ! comparison_dominates_p (cond1, cond2) + && (swapped = 1, ! comparison_dominates_p (cond2, cond1))) + return CCmode; + + if (swapped) + { + enum rtx_code temp = cond1; + cond1 = cond2; + cond2 = temp; + } + + switch (cond1) + { + case EQ: + if (cond2 == EQ || ! cond_or) + return CC_DEQmode; + + switch (cond2) + { + case LE: return CC_DLEmode; + case LEU: return CC_DLEUmode; + case GE: return CC_DGEmode; + case GEU: return CC_DGEUmode; + default: break; + } + + break; + + case LT: + if (cond2 == LT || ! cond_or) + return CC_DLTmode; + if (cond2 == LE) + return CC_DLEmode; + if (cond2 == NE) + return CC_DNEmode; + break; + + case GT: + if (cond2 == GT || ! cond_or) + return CC_DGTmode; + if (cond2 == GE) + return CC_DGEmode; + if (cond2 == NE) + return CC_DNEmode; + break; + + case LTU: + if (cond2 == LTU || ! cond_or) + return CC_DLTUmode; + if (cond2 == LEU) + return CC_DLEUmode; + if (cond2 == NE) + return CC_DNEmode; + break; + + case GTU: + if (cond2 == GTU || ! cond_or) + return CC_DGTUmode; + if (cond2 == GEU) + return CC_DGEUmode; + if (cond2 == NE) + return CC_DNEmode; + break; + + /* The remaining cases only occur when both comparisons are the + same. */ + case NE: + return CC_DNEmode; + + case LE: + return CC_DLEmode; + + case GE: + return CC_DGEmode; + + case LEU: + return CC_DLEUmode; + + case GEU: + return CC_DGEUmode; + + default: + break; + } + + abort (); +} + +enum machine_mode +arm_select_cc_mode (op, x, y) + enum rtx_code op; + rtx x; + rtx y; +{ + /* All floating point compares return CCFP if it is an equality + comparison, and CCFPE otherwise. */ + if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) + return (op == EQ || op == NE) ? CCFPmode : CCFPEmode; + + /* A compare with a shifted operand. Because of canonicalization, the + comparison will have to be swapped when we emit the assembler. */ + if (GET_MODE (y) == SImode && GET_CODE (y) == REG + && (GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT + || GET_CODE (x) == LSHIFTRT || GET_CODE (x) == ROTATE + || GET_CODE (x) == ROTATERT)) + return CC_SWPmode; + + /* This is a special case that is used by combine to allow a + comparison of a shifted byte load to be split into a zero-extend + followed by a comparison of the shifted integer (only valid for + equalities and unsigned inequalities). */ + if (GET_MODE (x) == SImode + && GET_CODE (x) == ASHIFT + && GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) == 24 + && GET_CODE (XEXP (x, 0)) == SUBREG + && GET_CODE (SUBREG_REG (XEXP (x, 0))) == MEM + && GET_MODE (SUBREG_REG (XEXP (x, 0))) == QImode + && (op == EQ || op == NE + || op == GEU || op == GTU || op == LTU || op == LEU) + && GET_CODE (y) == CONST_INT) + return CC_Zmode; + + /* An operation that sets the condition codes as a side-effect, the + V flag is not set correctly, so we can only use comparisons where + this doesn't matter. (For LT and GE we can use "mi" and "pl" + instead. */ + if (GET_MODE (x) == SImode + && y == const0_rtx + && (op == EQ || op == NE || op == LT || op == GE) + && (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS + || GET_CODE (x) == AND || GET_CODE (x) == IOR + || GET_CODE (x) == XOR || GET_CODE (x) == MULT + || GET_CODE (x) == NOT || GET_CODE (x) == NEG + || GET_CODE (x) == LSHIFTRT + || GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT + || GET_CODE (x) == ROTATERT || GET_CODE (x) == ZERO_EXTRACT)) + return CC_NOOVmode; + + /* A construct for a conditional compare, if the false arm contains + 0, then both conditions must be true, otherwise either condition + must be true. Not all conditions are possible, so CCmode is + returned if it can't be done. */ + if (GET_CODE (x) == IF_THEN_ELSE + && (XEXP (x, 2) == const0_rtx + || XEXP (x, 2) == const1_rtx) + && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<' + && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<') + return select_dominance_cc_mode (op, XEXP (x, 0), XEXP (x, 1), + INTVAL (XEXP (x, 2))); + + if (GET_MODE (x) == QImode && (op == EQ || op == NE)) + return CC_Zmode; + + if (GET_MODE (x) == SImode && (op == LTU || op == GEU) + && GET_CODE (x) == PLUS + && (rtx_equal_p (XEXP (x, 0), y) || rtx_equal_p (XEXP (x, 1), y))) + return CC_Cmode; + + return CCmode; +} + +/* X and Y are two things to compare using CODE. Emit the compare insn and + return the rtx for register 0 in the proper mode. FP means this is a + floating point compare: I don't think that it is needed on the arm. */ + +rtx +gen_compare_reg (code, x, y, fp) + enum rtx_code code; + rtx x, y; + int fp; +{ + enum machine_mode mode = SELECT_CC_MODE (code, x, y); + rtx cc_reg = gen_rtx (REG, mode, 24); + + emit_insn (gen_rtx (SET, VOIDmode, cc_reg, + gen_rtx (COMPARE, mode, x, y))); + + return cc_reg; +} + +void +arm_reload_in_hi (operands) + rtx *operands; +{ + rtx base = find_replacement (&XEXP (operands[1], 0)); + + emit_insn (gen_zero_extendqisi2 (operands[2], gen_rtx (MEM, QImode, base))); + /* Handle the case where the address is too complex to be offset by 1. */ + if (GET_CODE (base) == MINUS + || (GET_CODE (base) == PLUS && GET_CODE (XEXP (base, 1)) != CONST_INT)) + { + rtx base_plus = gen_rtx (REG, SImode, REGNO (operands[0])); + + emit_insn (gen_rtx (SET, VOIDmode, base_plus, base)); + base = base_plus; + } + + emit_insn (gen_zero_extendqisi2 (gen_rtx (SUBREG, SImode, operands[0], 0), + gen_rtx (MEM, QImode, + plus_constant (base, 1)))); + if (BYTES_BIG_ENDIAN) + emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (SUBREG, SImode, + operands[0], 0), + gen_rtx (IOR, SImode, + gen_rtx (ASHIFT, SImode, + gen_rtx (SUBREG, SImode, + operands[0], 0), + GEN_INT (8)), + operands[2]))); + else + emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (SUBREG, SImode, + operands[0], 0), + gen_rtx (IOR, SImode, + gen_rtx (ASHIFT, SImode, + operands[2], + GEN_INT (8)), + gen_rtx (SUBREG, SImode, operands[0], 0)))); +} + +void +arm_reload_out_hi (operands) + rtx *operands; +{ + rtx base = find_replacement (&XEXP (operands[0], 0)); + + if (BYTES_BIG_ENDIAN) + { + emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (base, 1)), + gen_rtx (SUBREG, QImode, operands[1], 0))); + emit_insn (gen_lshrsi3 (operands[2], + gen_rtx (SUBREG, SImode, operands[1], 0), + GEN_INT (8))); + emit_insn (gen_movqi (gen_rtx (MEM, QImode, base), + gen_rtx (SUBREG, QImode, operands[2], 0))); + } + else + { + emit_insn (gen_movqi (gen_rtx (MEM, QImode, base), + gen_rtx (SUBREG, QImode, operands[1], 0))); + emit_insn (gen_lshrsi3 (operands[2], + gen_rtx (SUBREG, SImode, operands[1], 0), + GEN_INT (8))); + emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (base, 1)), + gen_rtx (SUBREG, QImode, operands[2], 0))); + } +} + +/* CYGNUS LOCAL */ +/* Check to see if a branch is forwards or backwards. Return TRUE if it + is backwards. */ + +int +arm_backwards_branch (from, to) + int from, to; +{ + return insn_addresses[to] <= insn_addresses[from]; +} + +/* Check to see if a branch is within the distance that can be done using + an arithmetic expression. */ +int +short_branch (from, to) + int from, to; +{ + int delta = insn_addresses[from] + 8 - insn_addresses[to]; + + return abs (delta) < 980; /* A small margin for safety */ +} + +/* Check to see that the insn isn't the target of the conditionalizing + code */ +int +arm_insn_not_targeted (insn) + rtx insn; +{ + return insn != arm_target_insn; +} +/* END CYGNUS LOCAL */ + +/* Routines for manipulation of the constant pool. */ +/* This is unashamedly hacked from the version in sh.c, since the problem is + extremely similar. */ + +/* Arm instructions cannot load a large constant into a register, + constants have to come from a pc relative load. The reference of a pc + relative load instruction must be less than 1k infront of the instruction. + This means that we often have to dump a constant inside a function, and + generate code to branch around it. + + It is important to minimize this, since the branches will slow things + down and make things bigger. + + Worst case code looks like: + + ldr rn, L1 + b L2 + align + L1: .long value + L2: + .. + + ldr rn, L3 + b L4 + align + L3: .long value + L4: + .. + + We fix this by performing a scan before scheduling, which notices which + instructions need to have their operands fetched from the constant table + and builds the table. + + + The algorithm is: + + scan, find an instruction which needs a pcrel move. Look forward, find th + last barrier which is within MAX_COUNT bytes of the requirement. + If there isn't one, make one. Process all the instructions between + the find and the barrier. + + In the above example, we can tell that L3 is within 1k of L1, so + the first move can be shrunk from the 2 insn+constant sequence into + just 1 insn, and the constant moved to L3 to make: + + ldr rn, L1 + .. + ldr rn, L3 + b L4 + align + L1: .long value + L3: .long value + L4: + + Then the second move becomes the target for the shortening process. + + */ + +typedef struct +{ + rtx value; /* Value in table */ + HOST_WIDE_INT next_offset; + enum machine_mode mode; /* Mode of value */ +} pool_node; + +/* The maximum number of constants that can fit into one pool, since + the pc relative range is 0...1020 bytes and constants are at least 4 + bytes long */ + +#define MAX_POOL_SIZE (1020/4) +static pool_node pool_vector[MAX_POOL_SIZE]; +static int pool_size; +static rtx pool_vector_label; + +/* Add a constant to the pool and return its offset within the current + pool. + + X is the rtx we want to replace. MODE is its mode. On return, + ADDRESS_ONLY will be non-zero if we really want the address of such + a constant, not the constant itself. */ +static HOST_WIDE_INT +add_constant (x, mode, address_only) + rtx x; + enum machine_mode mode; + int * address_only; +{ + int i; + HOST_WIDE_INT offset; + + * address_only = 0; + + if (mode == SImode && GET_CODE (x) == MEM && CONSTANT_P (XEXP (x, 0)) + && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0))) + x = get_pool_constant (XEXP (x, 0)); + else if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P(x)) + { + *address_only = 1; + mode = get_pool_mode (x); + x = get_pool_constant (x); + } +#ifndef AOF_ASSEMBLER + else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == 3) + x = XVECEXP (x, 0, 0); +#endif + +#ifdef AOF_ASSEMBLER + /* PIC Symbol references need to be converted into offsets into the + based area. */ + if (flag_pic && GET_CODE (x) == SYMBOL_REF) + x = aof_pic_entry (x); +#endif /* AOF_ASSEMBLER */ + + /* First see if we've already got it */ + for (i = 0; i < pool_size; i++) + { + if (GET_CODE (x) == pool_vector[i].value->code + && mode == pool_vector[i].mode) + { + if (GET_CODE (x) == CODE_LABEL) + { + if (XINT (x, 3) != XINT (pool_vector[i].value, 3)) + continue; + } + if (rtx_equal_p (x, pool_vector[i].value)) + return pool_vector[i].next_offset - GET_MODE_SIZE (mode); + } + } + + /* Need a new one */ + pool_vector[pool_size].next_offset = GET_MODE_SIZE (mode); + offset = 0; + if (pool_size == 0) + pool_vector_label = gen_label_rtx (); + else + pool_vector[pool_size].next_offset + += (offset = pool_vector[pool_size - 1].next_offset); + + pool_vector[pool_size].value = x; + pool_vector[pool_size].mode = mode; + pool_size++; + return offset; +} + +/* Output the literal table */ +static void +dump_table (scan) + rtx scan; +{ + int i; + + scan = emit_label_after (gen_label_rtx (), scan); + scan = emit_insn_after (gen_align_4 (), scan); + scan = emit_label_after (pool_vector_label, scan); + + for (i = 0; i < pool_size; i++) + { + pool_node *p = pool_vector + i; + + switch (GET_MODE_SIZE (p->mode)) + { + case 4: + scan = emit_insn_after (gen_consttable_4 (p->value), scan); + break; + + case 8: + scan = emit_insn_after (gen_consttable_8 (p->value), scan); + break; + + default: + abort (); + break; + } + } + + scan = emit_insn_after (gen_consttable_end (), scan); + scan = emit_barrier_after (scan); + pool_size = 0; +} + +/* Non zero if the src operand needs to be fixed up */ +static int +fixit (src, mode, destreg) + rtx src; + enum machine_mode mode; + int destreg; +{ + if (CONSTANT_P (src)) + { + if (GET_CODE (src) == CONST_INT) + return (! const_ok_for_arm (INTVAL (src)) + && ! const_ok_for_arm (~INTVAL (src))); + if (GET_CODE (src) == CONST_DOUBLE) + return (GET_MODE (src) == VOIDmode + || destreg < 16 + || (! const_double_rtx_ok_for_fpu (src) + && ! neg_const_double_rtx_ok_for_fpu (src))); + return symbol_mentioned_p (src); + } +#ifndef AOF_ASSEMBLER + else if (GET_CODE (src) == UNSPEC && XINT (src, 1) == 3) + return 1; +#endif + else + return (mode == SImode && GET_CODE (src) == MEM + && GET_CODE (XEXP (src, 0)) == SYMBOL_REF + && CONSTANT_POOL_ADDRESS_P (XEXP (src, 0))); +} + +/* Find the last barrier less than MAX_COUNT bytes from FROM, or create one. */ +static rtx +find_barrier (from, max_count) + rtx from; + int max_count; +{ + int count = 0; + rtx found_barrier = 0; + rtx last = from; + + while (from && count < max_count) + { + rtx tmp; + + if (GET_CODE (from) == BARRIER) + found_barrier = from; + + /* Count the length of this insn */ + if (GET_CODE (from) == INSN + && GET_CODE (PATTERN (from)) == SET + && CONSTANT_P (SET_SRC (PATTERN (from))) + && CONSTANT_POOL_ADDRESS_P (SET_SRC (PATTERN (from)))) + count += 8; + /* Handle table jumps as a single entity. */ + else if (GET_CODE (from) == JUMP_INSN + && JUMP_LABEL (from) != 0 + && ((tmp = next_real_insn (JUMP_LABEL (from))) + == next_real_insn (from)) + && tmp != NULL + && GET_CODE (tmp) == JUMP_INSN + && (GET_CODE (PATTERN (tmp)) == ADDR_VEC + || GET_CODE (PATTERN (tmp)) == ADDR_DIFF_VEC)) + { + int elt = GET_CODE (PATTERN (tmp)) == ADDR_DIFF_VEC ? 1 : 0; + count += (get_attr_length (from) + + GET_MODE_SIZE (SImode) * XVECLEN (PATTERN (tmp), elt)); + /* Continue after the dispatch table. */ + last = from; + from = NEXT_INSN (tmp); + continue; + } + else + count += get_attr_length (from); + + last = from; + from = NEXT_INSN (from); + } + + if (! found_barrier) + { + /* We didn't find a barrier in time to + dump our stuff, so we'll make one. */ + rtx label = gen_label_rtx (); + + if (from) + from = PREV_INSN (last); + else + from = get_last_insn (); + + /* Walk back to be just before any jump. */ + while (GET_CODE (from) == JUMP_INSN + || GET_CODE (from) == NOTE + || GET_CODE (from) == CODE_LABEL) + from = PREV_INSN (from); + + from = emit_jump_insn_after (gen_jump (label), from); + JUMP_LABEL (from) = label; + found_barrier = emit_barrier_after (from); + emit_label_after (label, found_barrier); + } + + return found_barrier; +} + +/* Non zero if the insn is a move instruction which needs to be fixed. */ +static int +broken_move (insn) + rtx insn; +{ + if (!INSN_DELETED_P (insn) + && GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == SET) + { + rtx pat = PATTERN (insn); + rtx src = SET_SRC (pat); + rtx dst = SET_DEST (pat); + int destreg; + enum machine_mode mode = GET_MODE (dst); + + if (dst == pc_rtx) + return 0; + + if (GET_CODE (dst) == REG) + destreg = REGNO (dst); + else if (GET_CODE (dst) == SUBREG && GET_CODE (SUBREG_REG (dst)) == REG) + destreg = REGNO (SUBREG_REG (dst)); + else + return 0; + + return fixit (src, mode, destreg); + } + return 0; +} + +void +arm_reorg (first) + rtx first; +{ + rtx insn; + int count_size; + +#if 0 + /* The ldr instruction can work with up to a 4k offset, and most constants + will be loaded with one of these instructions; however, the adr + instruction and the ldf instructions only work with a 1k offset. This + code needs to be rewritten to use the 4k offset when possible, and to + adjust when a 1k offset is needed. For now we just use a 1k offset + from the start. */ + count_size = 4000; + + /* Floating point operands can't work further than 1024 bytes from the + PC, so to make things simple we restrict all loads for such functions. + */ + if (TARGET_HARD_FLOAT) + { + int regno; + + for (regno = 16; regno < 24; regno++) + if (regs_ever_live[regno]) + { + count_size = 1000; + break; + } + } +#else + count_size = 1000; +#endif /* 0 */ + + for (insn = first; insn; insn = NEXT_INSN (insn)) + { + if (broken_move (insn)) + { + /* This is a broken move instruction, scan ahead looking for + a barrier to stick the constant table behind */ + rtx scan; + rtx barrier = find_barrier (insn, count_size); + + /* Now find all the moves between the points and modify them */ + for (scan = insn; scan != barrier; scan = NEXT_INSN (scan)) + { + if (broken_move (scan)) + { + /* This is a broken move instruction, add it to the pool */ + rtx pat = PATTERN (scan); + rtx src = SET_SRC (pat); + rtx dst = SET_DEST (pat); + enum machine_mode mode = GET_MODE (dst); + HOST_WIDE_INT offset; + rtx newinsn = scan; + rtx newsrc; + rtx addr; + int scratch; + int address_only; + + /* If this is an HImode constant load, convert it into + an SImode constant load. Since the register is always + 32 bits this is safe. We have to do this, since the + load pc-relative instruction only does a 32-bit load. */ + if (mode == HImode) + { + mode = SImode; + if (GET_CODE (dst) != REG) + abort (); + PUT_MODE (dst, SImode); + } + + offset = add_constant (src, mode, &address_only); + addr = plus_constant (gen_rtx (LABEL_REF, VOIDmode, + pool_vector_label), + offset); + + /* If we only want the address of the pool entry, or + for wide moves to integer regs we need to split + the address calculation off into a separate insn. + If necessary, the load can then be done with a + load-multiple. This is safe, since we have + already noted the length of such insns to be 8, + and we are immediately over-writing the scratch + we have grabbed with the final result. */ + if ((address_only || GET_MODE_SIZE (mode) > 4) + && (scratch = REGNO (dst)) < 16) + { + rtx reg; + + if (mode == SImode) + reg = dst; + else + reg = gen_rtx (REG, SImode, scratch); + + newinsn = emit_insn_after (gen_movaddr (reg, addr), + newinsn); + addr = reg; + } + + if (! address_only) + { + newsrc = gen_rtx (MEM, mode, addr); + + /* XXX Fixme -- I think the following is bogus. */ + /* Build a jump insn wrapper around the move instead + of an ordinary insn, because we want to have room for + the target label rtx in fld[7], which an ordinary + insn doesn't have. */ + newinsn = emit_jump_insn_after + (gen_rtx (SET, VOIDmode, dst, newsrc), newinsn); + JUMP_LABEL (newinsn) = pool_vector_label; + + /* But it's still an ordinary insn */ + PUT_CODE (newinsn, INSN); + } + + /* Kill old insn */ + delete_insn (scan); + scan = newinsn; + } + } + dump_table (barrier); + insn = scan; + } + } + + after_arm_reorg = 1; +} + + +/* Routines to output assembly language. */ + +/* If the rtx is the correct value then return the string of the number. + In this way we can ensure that valid double constants are generated even + when cross compiling. */ +char * +fp_immediate_constant (x) + rtx x; +{ + REAL_VALUE_TYPE r; + int i; + + if (!fpa_consts_inited) + init_fpa_table (); + + REAL_VALUE_FROM_CONST_DOUBLE (r, x); + for (i = 0; i < 8; i++) + if (REAL_VALUES_EQUAL (r, values_fpa[i])) + return strings_fpa[i]; + + abort (); +} + +/* As for fp_immediate_constant, but value is passed directly, not in rtx. */ +static char * +fp_const_from_val (r) + REAL_VALUE_TYPE *r; +{ + int i; + + if (! fpa_consts_inited) + init_fpa_table (); + + for (i = 0; i < 8; i++) + if (REAL_VALUES_EQUAL (*r, values_fpa[i])) + return strings_fpa[i]; + + abort (); +} + +/* Output the operands of a LDM/STM instruction to STREAM. + MASK is the ARM register set mask of which only bits 0-15 are important. + INSTR is the possibly suffixed base register. HAT unequals zero if a hat + must follow the register list. */ + +void +print_multi_reg (stream, instr, mask, hat) + FILE *stream; + char *instr; + int mask, hat; +{ + int i; + int not_first = FALSE; + + fputc ('\t', stream); + fprintf (stream, instr, REGISTER_PREFIX); + fputs (", {", stream); + for (i = 0; i < 16; i++) + if (mask & (1 << i)) + { + if (not_first) + fprintf (stream, ", "); + fprintf (stream, "%s%s", REGISTER_PREFIX, reg_names[i]); + not_first = TRUE; + } + + fprintf (stream, "}%s\n", hat ? "^" : ""); +} + +/* Output a 'call' insn. */ + +char * +output_call (operands) + rtx *operands; +{ + /* Handle calls to lr using ip (which may be clobbered in subr anyway). */ + + if (REGNO (operands[0]) == 14) + { + operands[0] = gen_rtx (REG, SImode, 12); + output_asm_insn ("mov%?\t%0, %|lr", operands); + } + output_asm_insn ("mov%?\t%|lr, %|pc", operands); + + if (TARGET_THUMB_INTERWORK) + output_asm_insn ("bx%?\t%0", operands); + else + output_asm_insn ("mov%?\t%|pc, %0", operands); + + return ""; +} + +static int +eliminate_lr2ip (x) + rtx *x; +{ + int something_changed = 0; + rtx x0 = *x; + int code = GET_CODE (x0); + register int i, j; + register char *fmt; + + switch (code) + { + case REG: + if (REGNO (x0) == 14) + { + *x = gen_rtx (REG, SImode, 12); + return 1; + } + return 0; + default: + /* Scan through the sub-elements and change any references there */ + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + if (fmt[i] == 'e') + something_changed |= eliminate_lr2ip (&XEXP (x0, i)); + else if (fmt[i] == 'E') + for (j = 0; j < XVECLEN (x0, i); j++) + something_changed |= eliminate_lr2ip (&XVECEXP (x0, i, j)); + return something_changed; + } +} + +/* Output a 'call' insn that is a reference in memory. */ + +char * +output_call_mem (operands) + rtx *operands; +{ + operands[0] = copy_rtx (operands[0]); /* Be ultra careful */ + /* Handle calls using lr by using ip (which may be clobbered in subr anyway). + */ + if (eliminate_lr2ip (&operands[0])) + output_asm_insn ("mov%?\t%|ip, %|lr", operands); + + if (TARGET_THUMB_INTERWORK) + { + output_asm_insn ("ldr%?\t%|ip, %0", operands); + output_asm_insn ("mov%?\t%|lr, %|pc", operands); + output_asm_insn ("bx%?\t%|ip", operands); + } + else + { + output_asm_insn ("mov%?\t%|lr, %|pc", operands); + output_asm_insn ("ldr%?\t%|pc, %0", operands); + } + + return ""; +} + + +/* Output a move from arm registers to an fpu registers. + OPERANDS[0] is an fpu register. + OPERANDS[1] is the first registers of an arm register pair. */ + +char * +output_mov_long_double_fpu_from_arm (operands) + rtx *operands; +{ + int arm_reg0 = REGNO (operands[1]); + rtx ops[3]; + + if (arm_reg0 == 12) + abort(); + + ops[0] = gen_rtx (REG, SImode, arm_reg0); + ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0); + ops[2] = gen_rtx (REG, SImode, 2 + arm_reg0); + + output_asm_insn ("stm%?fd\t%|sp!, {%0, %1, %2}", ops); + output_asm_insn ("ldf%?e\t%0, [%|sp], #12", operands); + return ""; +} + +/* Output a move from an fpu register to arm registers. + OPERANDS[0] is the first registers of an arm register pair. + OPERANDS[1] is an fpu register. */ + +char * +output_mov_long_double_arm_from_fpu (operands) + rtx *operands; +{ + int arm_reg0 = REGNO (operands[0]); + rtx ops[3]; + + if (arm_reg0 == 12) + abort(); + + ops[0] = gen_rtx (REG, SImode, arm_reg0); + ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0); + ops[2] = gen_rtx (REG, SImode, 2 + arm_reg0); + + output_asm_insn ("stf%?e\t%1, [%|sp, #-12]!", operands); + output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1, %2}", ops); + return ""; +} + +/* Output a move from arm registers to arm registers of a long double + OPERANDS[0] is the destination. + OPERANDS[1] is the source. */ +char * +output_mov_long_double_arm_from_arm (operands) + rtx *operands; +{ + /* We have to be careful here because the two might overlap */ + int dest_start = REGNO (operands[0]); + int src_start = REGNO (operands[1]); + rtx ops[2]; + int i; + + if (dest_start < src_start) + { + for (i = 0; i < 3; i++) + { + ops[0] = gen_rtx (REG, SImode, dest_start + i); + ops[1] = gen_rtx (REG, SImode, src_start + i); + output_asm_insn ("mov%?\t%0, %1", ops); + } + } + else + { + for (i = 2; i >= 0; i--) + { + ops[0] = gen_rtx (REG, SImode, dest_start + i); + ops[1] = gen_rtx (REG, SImode, src_start + i); + output_asm_insn ("mov%?\t%0, %1", ops); + } + } + + return ""; +} + + +/* Output a move from arm registers to an fpu registers. + OPERANDS[0] is an fpu register. + OPERANDS[1] is the first registers of an arm register pair. */ + +char * +output_mov_double_fpu_from_arm (operands) + rtx *operands; +{ + int arm_reg0 = REGNO (operands[1]); + rtx ops[2]; + + if (arm_reg0 == 12) + abort(); + ops[0] = gen_rtx (REG, SImode, arm_reg0); + ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0); + output_asm_insn ("stm%?fd\t%|sp!, {%0, %1}", ops); + output_asm_insn ("ldf%?d\t%0, [%|sp], #8", operands); + return ""; +} + +/* Output a move from an fpu register to arm registers. + OPERANDS[0] is the first registers of an arm register pair. + OPERANDS[1] is an fpu register. */ + +char * +output_mov_double_arm_from_fpu (operands) + rtx *operands; +{ + int arm_reg0 = REGNO (operands[0]); + rtx ops[2]; + + if (arm_reg0 == 12) + abort(); + + ops[0] = gen_rtx (REG, SImode, arm_reg0); + ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0); + output_asm_insn ("stf%?d\t%1, [%|sp, #-8]!", operands); + output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1}", ops); + return ""; +} + +/* Output a move between double words. + It must be REG<-REG, REG<-CONST_DOUBLE, REG<-CONST_INT, REG<-MEM + or MEM<-REG and all MEMs must be offsettable addresses. */ + +char * +output_move_double (operands) + rtx *operands; +{ + enum rtx_code code0 = GET_CODE (operands[0]); + enum rtx_code code1 = GET_CODE (operands[1]); + rtx otherops[3]; + + if (code0 == REG) + { + int reg0 = REGNO (operands[0]); + + otherops[0] = gen_rtx (REG, SImode, 1 + reg0); + if (code1 == REG) + { + int reg1 = REGNO (operands[1]); + if (reg1 == 12) + abort(); + + /* Ensure the second source is not overwritten */ + if (reg1 == reg0 + (WORDS_BIG_ENDIAN ? -1 : 1)) + output_asm_insn("mov%?\t%Q0, %Q1\n\tmov%?\t%R0, %R1", operands); + else + output_asm_insn("mov%?\t%R0, %R1\n\tmov%?\t%Q0, %Q1", operands); + } + else if (code1 == CONST_DOUBLE) + { + if (GET_MODE (operands[1]) == DFmode) + { + long l[2]; + union real_extract u; + + bcopy ((char *) &CONST_DOUBLE_LOW (operands[1]), (char *) &u, + sizeof (u)); + REAL_VALUE_TO_TARGET_DOUBLE (u.d, l); + otherops[1] = GEN_INT(l[1]); + operands[1] = GEN_INT(l[0]); + } + else if (GET_MODE (operands[1]) != VOIDmode) + abort (); + else if (WORDS_BIG_ENDIAN) + { + + otherops[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1])); + operands[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1])); + } + else + { + + otherops[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1])); + operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1])); + } + output_mov_immediate (operands); + output_mov_immediate (otherops); + } + else if (code1 == CONST_INT) + { +#if HOST_BITS_PER_WIDE_INT > 32 + /* If HOST_WIDE_INT is more than 32 bits, the intval tells us + what the upper word is. */ + if (WORDS_BIG_ENDIAN) + { + otherops[1] = GEN_INT (ARM_SIGN_EXTEND (INTVAL (operands[1]))); + operands[1] = GEN_INT (INTVAL (operands[1]) >> 32); + } + else + { + otherops[1] = GEN_INT (INTVAL (operands[1]) >> 32); + operands[1] = GEN_INT (ARM_SIGN_EXTEND (INTVAL (operands[1]))); + } +#else + /* Sign extend the intval into the high-order word */ + if (WORDS_BIG_ENDIAN) + { + otherops[1] = operands[1]; + operands[1] = (INTVAL (operands[1]) < 0 + ? constm1_rtx : const0_rtx); + } + else + otherops[1] = INTVAL (operands[1]) < 0 ? constm1_rtx : const0_rtx; +#endif + output_mov_immediate (otherops); + output_mov_immediate (operands); + } + else if (code1 == MEM) + { + switch (GET_CODE (XEXP (operands[1], 0))) + { + case REG: + output_asm_insn ("ldm%?ia\t%m1, %M0", operands); + break; + + case PRE_INC: + abort (); /* Should never happen now */ + break; + + case PRE_DEC: + output_asm_insn ("ldm%?db\t%m1!, %M0", operands); + break; + + case POST_INC: + output_asm_insn ("ldm%?ia\t%m1!, %M0", operands); + break; + + case POST_DEC: + abort (); /* Should never happen now */ + break; + + case LABEL_REF: + case CONST: + output_asm_insn ("adr%?\t%0, %1", operands); + output_asm_insn ("ldm%?ia\t%0, %M0", operands); + break; + + default: + if (arm_add_operand (XEXP (XEXP (operands[1], 0), 1))) + { + otherops[0] = operands[0]; + otherops[1] = XEXP (XEXP (operands[1], 0), 0); + otherops[2] = XEXP (XEXP (operands[1], 0), 1); + if (GET_CODE (XEXP (operands[1], 0)) == PLUS) + { + if (GET_CODE (otherops[2]) == CONST_INT) + { + switch (INTVAL (otherops[2])) + { + case -8: + output_asm_insn ("ldm%?db\t%1, %M0", otherops); + return ""; + case -4: + output_asm_insn ("ldm%?da\t%1, %M0", otherops); + return ""; + case 4: + output_asm_insn ("ldm%?ib\t%1, %M0", otherops); + return ""; + } + if (!(const_ok_for_arm (INTVAL (otherops[2])))) + output_asm_insn ("sub%?\t%0, %1, #%n2", otherops); + else + output_asm_insn ("add%?\t%0, %1, %2", otherops); + } + else + output_asm_insn ("add%?\t%0, %1, %2", otherops); + } + else + output_asm_insn ("sub%?\t%0, %1, %2", otherops); + return "ldm%?ia\t%0, %M0"; + } + else + { + otherops[1] = adj_offsettable_operand (operands[1], 4); + /* Take care of overlapping base/data reg. */ + if (reg_mentioned_p (operands[0], operands[1])) + { + output_asm_insn ("ldr%?\t%0, %1", otherops); + output_asm_insn ("ldr%?\t%0, %1", operands); + } + else + { + output_asm_insn ("ldr%?\t%0, %1", operands); + output_asm_insn ("ldr%?\t%0, %1", otherops); + } + } + } + } + else + abort(); /* Constraints should prevent this */ + } + else if (code0 == MEM && code1 == REG) + { + if (REGNO (operands[1]) == 12) + abort(); + + switch (GET_CODE (XEXP (operands[0], 0))) + { + case REG: + output_asm_insn ("stm%?ia\t%m0, %M1", operands); + break; + + case PRE_INC: + abort (); /* Should never happen now */ + break; + + case PRE_DEC: + output_asm_insn ("stm%?db\t%m0!, %M1", operands); + break; + + case POST_INC: + output_asm_insn ("stm%?ia\t%m0!, %M1", operands); + break; + + case POST_DEC: + abort (); /* Should never happen now */ + break; + + case PLUS: + if (GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT) + { + switch (INTVAL (XEXP (XEXP (operands[0], 0), 1))) + { + case -8: + output_asm_insn ("stm%?db\t%m0, %M1", operands); + return ""; + + case -4: + output_asm_insn ("stm%?da\t%m0, %M1", operands); + return ""; + + case 4: + output_asm_insn ("stm%?ib\t%m0, %M1", operands); + return ""; + } + } + /* Fall through */ + + default: + otherops[0] = adj_offsettable_operand (operands[0], 4); + otherops[1] = gen_rtx (REG, SImode, 1 + REGNO (operands[1])); + output_asm_insn ("str%?\t%1, %0", operands); + output_asm_insn ("str%?\t%1, %0", otherops); + } + } + else + abort(); /* Constraints should prevent this */ + + return ""; +} + + +/* Output an arbitrary MOV reg, #n. + OPERANDS[0] is a register. OPERANDS[1] is a const_int. */ + +char * +output_mov_immediate (operands) + rtx *operands; +{ + HOST_WIDE_INT n = INTVAL (operands[1]); + int n_ones = 0; + int i; + + /* Try to use one MOV */ + if (const_ok_for_arm (n)) + { + output_asm_insn ("mov%?\t%0, %1", operands); + return ""; + } + + /* Try to use one MVN */ + if (const_ok_for_arm (~n)) + { + operands[1] = GEN_INT (~n); + output_asm_insn ("mvn%?\t%0, %1", operands); + return ""; + } + + /* If all else fails, make it out of ORRs or BICs as appropriate. */ + + for (i=0; i < 32; i++) + if (n & 1 << i) + n_ones++; + + if (n_ones > 16) /* Shorter to use MVN with BIC in this case. */ + output_multi_immediate(operands, "mvn%?\t%0, %1", "bic%?\t%0, %0, %1", 1, + ~n); + else + output_multi_immediate(operands, "mov%?\t%0, %1", "orr%?\t%0, %0, %1", 1, + n); + + return ""; +} + + +/* Output an ADD r, s, #n where n may be too big for one instruction. If + adding zero to one register, output nothing. */ + +char * +output_add_immediate (operands) + rtx *operands; +{ + HOST_WIDE_INT n = INTVAL (operands[2]); + + if (n != 0 || REGNO (operands[0]) != REGNO (operands[1])) + { + if (n < 0) + output_multi_immediate (operands, + "sub%?\t%0, %1, %2", "sub%?\t%0, %0, %2", 2, + -n); + else + output_multi_immediate (operands, + "add%?\t%0, %1, %2", "add%?\t%0, %0, %2", 2, + n); + } + + return ""; +} + +/* Output a multiple immediate operation. + OPERANDS is the vector of operands referred to in the output patterns. + INSTR1 is the output pattern to use for the first constant. + INSTR2 is the output pattern to use for subsequent constants. + IMMED_OP is the index of the constant slot in OPERANDS. + N is the constant value. */ + +static char * +output_multi_immediate (operands, instr1, instr2, immed_op, n) + rtx *operands; + char *instr1, *instr2; + int immed_op; + HOST_WIDE_INT n; +{ +#if HOST_BITS_PER_WIDE_INT > 32 + n &= 0xffffffff; +#endif + + if (n == 0) + { + operands[immed_op] = const0_rtx; + output_asm_insn (instr1, operands); /* Quick and easy output */ + } + else + { + int i; + char *instr = instr1; + + /* Note that n is never zero here (which would give no output) */ + for (i = 0; i < 32; i += 2) + { + if (n & (3 << i)) + { + operands[immed_op] = GEN_INT (n & (255 << i)); + output_asm_insn (instr, operands); + instr = instr2; + i += 6; + } + } + } + return ""; +} + + +/* Return the appropriate ARM instruction for the operation code. + The returned result should not be overwritten. OP is the rtx of the + operation. SHIFT_FIRST_ARG is TRUE if the first argument of the operator + was shifted. */ + +char * +arithmetic_instr (op, shift_first_arg) + rtx op; + int shift_first_arg; +{ + switch (GET_CODE (op)) + { + case PLUS: + return "add"; + + case MINUS: + return shift_first_arg ? "rsb" : "sub"; + + case IOR: + return "orr"; + + case XOR: + return "eor"; + + case AND: + return "and"; + + default: + abort (); + } +} + + +/* Ensure valid constant shifts and return the appropriate shift mnemonic + for the operation code. The returned result should not be overwritten. + OP is the rtx code of the shift. + On exit, *AMOUNTP will be -1 if the shift is by a register, or a constant + shift. */ + +static char * +shift_op (op, amountp) + rtx op; + HOST_WIDE_INT *amountp; +{ + char *mnem; + enum rtx_code code = GET_CODE (op); + + if (GET_CODE (XEXP (op, 1)) == REG || GET_CODE (XEXP (op, 1)) == SUBREG) + *amountp = -1; + else if (GET_CODE (XEXP (op, 1)) == CONST_INT) + *amountp = INTVAL (XEXP (op, 1)); + else + abort (); + + switch (code) + { + case ASHIFT: + mnem = "asl"; + break; + + case ASHIFTRT: + mnem = "asr"; + break; + + case LSHIFTRT: + mnem = "lsr"; + break; + + case ROTATERT: + mnem = "ror"; + break; + + case MULT: + /* We never have to worry about the amount being other than a + power of 2, since this case can never be reloaded from a reg. */ + if (*amountp != -1) + *amountp = int_log2 (*amountp); + else + abort (); + return "asl"; + + default: + abort (); + } + + if (*amountp != -1) + { + /* This is not 100% correct, but follows from the desire to merge + multiplication by a power of 2 with the recognizer for a + shift. >=32 is not a valid shift for "asl", so we must try and + output a shift that produces the correct arithmetical result. + Using lsr #32 is identical except for the fact that the carry bit + is not set correctly if we set the flags; but we never use the + carry bit from such an operation, so we can ignore that. */ + if (code == ROTATERT) + *amountp &= 31; /* Rotate is just modulo 32 */ + else if (*amountp != (*amountp & 31)) + { + if (code == ASHIFT) + mnem = "lsr"; + *amountp = 32; + } + + /* Shifts of 0 are no-ops. */ + if (*amountp == 0) + return NULL; + } + + return mnem; +} + + +/* Obtain the shift from the POWER of two. */ + +static HOST_WIDE_INT +int_log2 (power) + HOST_WIDE_INT power; +{ + HOST_WIDE_INT shift = 0; + + while (((((HOST_WIDE_INT) 1) << shift) & power) == 0) + { + if (shift > 31) + abort (); + shift++; + } + + return shift; +} + +/* Output a .ascii pseudo-op, keeping track of lengths. This is because + /bin/as is horribly restrictive. */ + +void +output_ascii_pseudo_op (stream, p, len) + FILE *stream; + unsigned char *p; + int len; +{ + int i; + int len_so_far = 1000; + int chars_so_far = 0; + + for (i = 0; i < len; i++) + { + register int c = p[i]; + + if (len_so_far > 50) + { + if (chars_so_far) + fputs ("\"\n", stream); + fputs ("\t.ascii\t\"", stream); + len_so_far = 0; + /* CYGNUS LOCAL */ + arm_increase_location (chars_so_far); + /* END CYGNUS LOCAL */ + chars_so_far = 0; + } + + if (c == '\"' || c == '\\') + { + putc('\\', stream); + len_so_far++; + } + + if (c >= ' ' && c < 0177) + { + putc (c, stream); + len_so_far++; + } + else + { + fprintf (stream, "\\%03o", c); + len_so_far +=4; + } + + chars_so_far++; + } + + fputs ("\"\n", stream); + /* CYGNUS LOCAL */ + arm_increase_location (chars_so_far); + /* END CYGNUS LOCAL */ +} + + +/* Try to determine whether a pattern really clobbers the link register. + This information is useful when peepholing, so that lr need not be pushed + if we combine a call followed by a return. + NOTE: This code does not check for side-effect expressions in a SET_SRC: + such a check should not be needed because these only update an existing + value within a register; the register must still be set elsewhere within + the function. */ + +static int +pattern_really_clobbers_lr (x) + rtx x; +{ + int i; + + switch (GET_CODE (x)) + { + case SET: + switch (GET_CODE (SET_DEST (x))) + { + case REG: + return REGNO (SET_DEST (x)) == 14; + + case SUBREG: + if (GET_CODE (XEXP (SET_DEST (x), 0)) == REG) + return REGNO (XEXP (SET_DEST (x), 0)) == 14; + + if (GET_CODE (XEXP (SET_DEST (x), 0)) == MEM) + return 0; + abort (); + + default: + return 0; + } + + case PARALLEL: + for (i = 0; i < XVECLEN (x, 0); i++) + if (pattern_really_clobbers_lr (XVECEXP (x, 0, i))) + return 1; + return 0; + + case CLOBBER: + switch (GET_CODE (XEXP (x, 0))) + { + case REG: + return REGNO (XEXP (x, 0)) == 14; + + case SUBREG: + if (GET_CODE (XEXP (XEXP (x, 0), 0)) == REG) + return REGNO (XEXP (XEXP (x, 0), 0)) == 14; + abort (); + + default: + return 0; + } + + case UNSPEC: + return 1; + + default: + return 0; + } +} + +static int +function_really_clobbers_lr (first) + rtx first; +{ + rtx insn, next; + + for (insn = first; insn; insn = next_nonnote_insn (insn)) + { + switch (GET_CODE (insn)) + { + case BARRIER: + case NOTE: + case CODE_LABEL: + case JUMP_INSN: /* Jump insns only change the PC (and conds) */ + case INLINE_HEADER: + break; + + case INSN: + if (pattern_really_clobbers_lr (PATTERN (insn))) + return 1; + break; + + case CALL_INSN: + /* Don't yet know how to handle those calls that are not to a + SYMBOL_REF */ + if (GET_CODE (PATTERN (insn)) != PARALLEL) + abort (); + + switch (GET_CODE (XVECEXP (PATTERN (insn), 0, 0))) + { + case CALL: + if (GET_CODE (XEXP (XEXP (XVECEXP (PATTERN (insn), 0, 0), 0), 0)) + != SYMBOL_REF) + return 1; + break; + + case SET: + if (GET_CODE (XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (insn), + 0, 0)), 0), 0)) + != SYMBOL_REF) + return 1; + break; + + default: /* Don't recognize it, be safe */ + return 1; + } + + /* A call can be made (by peepholing) not to clobber lr iff it is + followed by a return. There may, however, be a use insn iff + we are returning the result of the call. + If we run off the end of the insn chain, then that means the + call was at the end of the function. Unfortunately we don't + have a return insn for the peephole to recognize, so we + must reject this. (Can this be fixed by adding our own insn?) */ + if ((next = next_nonnote_insn (insn)) == NULL) + return 1; + + /* No need to worry about lr if the call never returns */ + if (GET_CODE (next) == BARRIER) + break; + + if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == USE + && (GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET) + && (REGNO (SET_DEST (XVECEXP (PATTERN (insn), 0, 0))) + == REGNO (XEXP (PATTERN (next), 0)))) + if ((next = next_nonnote_insn (next)) == NULL) + return 1; + + if (GET_CODE (next) == JUMP_INSN + && GET_CODE (PATTERN (next)) == RETURN) + break; + return 1; + + default: + abort (); + } + } + + /* We have reached the end of the chain so lr was _not_ clobbered */ + return 0; +} + +char * +output_return_instruction (operand, really_return, reverse) + rtx operand; + int really_return; + int reverse; +{ + char instr[100]; + int reg, live_regs = 0; + int volatile_func = (optimize > 0 + && TREE_THIS_VOLATILE (current_function_decl)); + + return_used_this_function = 1; + + if (volatile_func) + { + rtx ops[2]; + /* If this function was declared non-returning, and we have found a tail + call, then we have to trust that the called function won't return. */ + if (! really_return) + return ""; + + /* Otherwise, trap an attempted return by aborting. */ + ops[0] = operand; + ops[1] = gen_rtx (SYMBOL_REF, Pmode, "abort"); + assemble_external_libcall (ops[1]); + output_asm_insn (reverse ? "bl%D0\t%a1" : "bl%d0\t%a1", ops); + return ""; + } + + if (current_function_calls_alloca && ! really_return) + abort(); + + for (reg = 0; reg <= 10; reg++) + if (regs_ever_live[reg] && ! call_used_regs[reg]) + live_regs++; + + if (live_regs || (regs_ever_live[14] && ! lr_save_eliminated)) + live_regs++; + + if (frame_pointer_needed) + live_regs += 4; + + if (live_regs) + { + if (lr_save_eliminated || ! regs_ever_live[14]) + live_regs++; + + if (frame_pointer_needed) + strcpy (instr, + reverse ? "ldm%?%D0ea\t%|fp, {" : "ldm%?%d0ea\t%|fp, {"); + else + strcpy (instr, + reverse ? "ldm%?%D0fd\t%|sp!, {" : "ldm%?%d0fd\t%|sp!, {"); + + for (reg = 0; reg <= 10; reg++) + if (regs_ever_live[reg] && ! call_used_regs[reg]) + { + strcat (instr, "%|"); + strcat (instr, reg_names[reg]); + if (--live_regs) + strcat (instr, ", "); + } + + if (frame_pointer_needed) + { + strcat (instr, "%|"); + strcat (instr, reg_names[11]); + strcat (instr, ", "); + strcat (instr, "%|"); + strcat (instr, reg_names[13]); + strcat (instr, ", "); + strcat (instr, "%|"); + strcat (instr, TARGET_THUMB_INTERWORK || (! really_return) + ? reg_names[14] : reg_names[15] ); + } + else + { + strcat (instr, "%|"); + if (TARGET_THUMB_INTERWORK && really_return) + strcat (instr, reg_names[12]); + else + strcat (instr, really_return ? reg_names[15] : reg_names[14]); + } + strcat (instr, (TARGET_APCS_32 || !really_return) ? "}" : "}^"); + output_asm_insn (instr, &operand); + + if (TARGET_THUMB_INTERWORK && really_return) + { + strcpy (instr, "bx%?"); + strcat (instr, reverse ? "%D0" : "%d0"); + strcat (instr, "\t%|"); + strcat (instr, frame_pointer_needed ? "lr" : "ip"); + + output_asm_insn (instr, & operand); + } + } + else if (really_return) + { + /* CYGNUS LOCAL unknown */ + if (operand && GET_MODE_CLASS (GET_MODE (XEXP (operand, 0))) != MODE_CC) + output_asm_insn ("ldr%?\t%|ip, %0", & operand); + /* END CYGNUS LOCAL */ + + if (TARGET_THUMB_INTERWORK) + sprintf (instr, "bx%%?%%%s0\t%%|lr", reverse ? "D" : "d"); + else + sprintf (instr, "mov%%?%%%s0%s\t%%|pc, %%|lr", + reverse ? "D" : "d", TARGET_APCS_32 ? "" : "s"); + + output_asm_insn (instr, & operand); + } + + return ""; +} + +/* Return nonzero if optimizing and the current function is volatile. + Such functions never return, and many memory cycles can be saved + by not storing register values that will never be needed again. + This optimization was added to speed up context switching in a + kernel application. */ + +int +arm_volatile_func () +{ + return (optimize > 0 && TREE_THIS_VOLATILE (current_function_decl)); +} + +/* CYGNUS LOCAL unknown */ +/* Return the size of the prologue. It's not too bad if we slightly + over-estimate. */ + +static int +get_prologue_size () +{ + return profile_flag ? 12 : 0; +} +/* END CYGNUS LOCAL */ + +/* The amount of stack adjustment that happens here, in output_return and in + output_epilogue must be exactly the same as was calculated during reload, + or things will point to the wrong place. The only time we can safely + ignore this constraint is when a function has no arguments on the stack, + no stack frame requirement and no live registers execpt for `lr'. If we + can guarantee that by making all function calls into tail calls and that + lr is not clobbered in any other way, then there is no need to push lr + onto the stack. */ + +void +output_func_prologue (f, frame_size) + FILE *f; + int frame_size; +{ + int reg, live_regs_mask = 0; + int volatile_func = (optimize > 0 + && TREE_THIS_VOLATILE (current_function_decl)); + + /* Nonzero if we must stuff some register arguments onto the stack as if + they were passed there. */ + int store_arg_regs = 0; + + if (arm_ccfsm_state || arm_target_insn) + abort (); /* Sanity check */ + + if (arm_naked_function_p (current_function_decl)) + return; + + return_used_this_function = 0; + lr_save_eliminated = 0; + + fprintf (f, "\t%s args = %d, pretend = %d, frame = %d\n", + ASM_COMMENT_START, current_function_args_size, + current_function_pretend_args_size, frame_size); + fprintf (f, "\t%s frame_needed = %d, current_function_anonymous_args = %d\n", + ASM_COMMENT_START, frame_pointer_needed, + current_function_anonymous_args); + + if (volatile_func) + fprintf (f, "\t%s Volatile function.\n", ASM_COMMENT_START); + + if (current_function_anonymous_args && current_function_pretend_args_size) + store_arg_regs = 1; + + for (reg = 0; reg <= 10; reg++) + if (regs_ever_live[reg] && ! call_used_regs[reg]) + live_regs_mask |= (1 << reg); + + if (frame_pointer_needed) + live_regs_mask |= 0xD800; + else if (regs_ever_live[14]) + { + if (! current_function_args_size + && ! function_really_clobbers_lr (get_insns ())) + lr_save_eliminated = 1; + else + live_regs_mask |= 0x4000; + } + + if (live_regs_mask) + { + /* if a di mode load/store multiple is used, and the base register + is r3, then r4 can become an ever live register without lr + doing so, in this case we need to push lr as well, or we + will fail to get a proper return. */ + + live_regs_mask |= 0x4000; + lr_save_eliminated = 0; + + } + + if (lr_save_eliminated) + fprintf (f,"\t%s I don't think this function clobbers lr\n", + ASM_COMMENT_START); + +#ifdef AOF_ASSEMBLER + if (flag_pic) + fprintf (f, "\tmov\t%sip, %s%s\n", REGISTER_PREFIX, REGISTER_PREFIX, + reg_names[PIC_OFFSET_TABLE_REGNUM]); +#endif +} + + +void +output_func_epilogue (f, frame_size) + FILE *f; + int frame_size; +{ + int reg, live_regs_mask = 0; + /* CYGNUS LOCAL unknown */ + int code_size = 0; + /* END CYGNUS LOCAL */ + /* If we need this then it will always be at least this much */ + int floats_offset = 12; + rtx operands[3]; + int volatile_func = (optimize > 0 + && TREE_THIS_VOLATILE (current_function_decl)); + + if (use_return_insn (FALSE) && return_used_this_function) + { + if ((frame_size + current_function_outgoing_args_size) != 0 + /* CYGNUS LOCAL bug fix */ + && !(frame_pointer_needed && TARGET_APCS)) + /* END CYGNUS LOCAL */ + abort (); + goto epilogue_done; + } + + /* Naked functions don't have epilogues. */ + if (arm_naked_function_p (current_function_decl)) + goto epilogue_done; + + /* A volatile function should never return. Call abort. */ + if (TARGET_ABORT_NORETURN && volatile_func) + { + rtx op = gen_rtx (SYMBOL_REF, Pmode, "abort"); + assemble_external_libcall (op); + output_asm_insn ("bl\t%a0", &op); + /* CYGNUS LOCAL unknown */ + code_size = 4; + /* END CYGNUS LOCAL */ + goto epilogue_done; + } + + for (reg = 0; reg <= 10; reg++) + if (regs_ever_live[reg] && ! call_used_regs[reg]) + { + live_regs_mask |= (1 << reg); + floats_offset += 4; + } + + if (frame_pointer_needed) + { + if (arm_fpu_arch == FP_SOFT2) + { + for (reg = 23; reg > 15; reg--) + if (regs_ever_live[reg] && ! call_used_regs[reg]) + { + floats_offset += 12; + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + fprintf (f, "\tldfe\t%s%s, [%sfp, #-%d]\n", REGISTER_PREFIX, + reg_names[reg], REGISTER_PREFIX, floats_offset); + } + } + else + { + int start_reg = 23; + + for (reg = 23; reg > 15; reg--) + { + if (regs_ever_live[reg] && ! call_used_regs[reg]) + { + floats_offset += 12; + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + /* We can't unstack more than four registers at once */ + if (start_reg - reg == 3) + { + fprintf (f, "\tlfm\t%s%s, 4, [%sfp, #-%d]\n", + REGISTER_PREFIX, reg_names[reg], + REGISTER_PREFIX, floats_offset); + start_reg = reg - 1; + } + } + else + { + if (reg != start_reg) + /* CYGNUS LOCAL unknown */ + { + code_size += 4; + fprintf (f, "\tlfm\t%s%s, %d, [%sfp, #-%d]\n", + REGISTER_PREFIX, reg_names[reg + 1], + start_reg - reg, REGISTER_PREFIX, floats_offset); + } + /* END CYGNUS LOCAL */ + start_reg = reg - 1; + } + } + + /* Just in case the last register checked also needs unstacking. */ + if (reg != start_reg) + /* CYGNUS LOCAL unknown */ + { + code_size += 4; + fprintf (f, "\tlfm\t%s%s, %d, [%sfp, #-%d]\n", + REGISTER_PREFIX, reg_names[reg + 1], + start_reg - reg, REGISTER_PREFIX, floats_offset); + } + /* END CYGNUS LOCAL */ + } + + if (TARGET_THUMB_INTERWORK) + { + live_regs_mask |= 0x6800; + print_multi_reg (f, "ldmea\t%sfp", live_regs_mask, FALSE); + fprintf (f, "\tbx\t%slr\n", REGISTER_PREFIX); + /* CYGNUS LOCAL unknown */ + code_size += 8; + /* END CYGNUS LOCAL */ + } + else + { + live_regs_mask |= 0xA800; + print_multi_reg (f, "ldmea\t%sfp", live_regs_mask, + TARGET_APCS_32 ? FALSE : TRUE); + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + } + } + else + { + /* Restore stack pointer if necessary. */ + if (frame_size + current_function_outgoing_args_size != 0) + { + operands[0] = operands[1] = stack_pointer_rtx; + operands[2] = GEN_INT (frame_size + + current_function_outgoing_args_size); + output_add_immediate (operands); + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + } + + if (arm_fpu_arch == FP_SOFT2) + { + for (reg = 16; reg < 24; reg++) + if (regs_ever_live[reg] && ! call_used_regs[reg]) + { + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + fprintf (f, "\tldfe\t%s%s, [%ssp], #12\n", REGISTER_PREFIX, + reg_names[reg], REGISTER_PREFIX); + } + } + else + { + int start_reg = 16; + + for (reg = 16; reg < 24; reg++) + { + if (regs_ever_live[reg] && ! call_used_regs[reg]) + { + if (reg - start_reg == 3) + { + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + fprintf (f, "\tlfmfd\t%s%s, 4, [%ssp]!\n", + REGISTER_PREFIX, reg_names[start_reg], + REGISTER_PREFIX); + start_reg = reg + 1; + } + } + else + { + if (reg != start_reg) + { + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + fprintf (f, "\tlfmfd\t%s%s, %d, [%ssp]!\n", + REGISTER_PREFIX, reg_names[start_reg], + reg - start_reg, REGISTER_PREFIX); + } + + start_reg = reg + 1; + } + } + + /* Just in case the last register checked also needs unstacking. */ + if (reg != start_reg) + { + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + fprintf (f, "\tlfmfd\t%s%s, %d, [%ssp]!\n", + REGISTER_PREFIX, reg_names[start_reg], + reg - start_reg, REGISTER_PREFIX); + } + } + + if (current_function_pretend_args_size == 0 && regs_ever_live[14]) + { + if (TARGET_THUMB_INTERWORK) + { + /* CYGNUS LOCAL */ + if (! lr_save_eliminated) + live_regs_mask |= 0x4000; + + if (live_regs_mask != 0) + { + code_size += 4; + print_multi_reg (f, "ldmfd\t%ssp!", live_regs_mask, FALSE); + } + /* END CYGNUS LOCAL */ + + fprintf (f, "\tbx\t%slr\n", REGISTER_PREFIX); + } + else if (lr_save_eliminated) + fprintf (f, (TARGET_APCS_32 ? "\tmov\t%spc, %slr\n" + : "\tmovs\t%spc, %slr\n"), + REGISTER_PREFIX, REGISTER_PREFIX, f); + else + print_multi_reg (f, "ldmfd\t%ssp!", live_regs_mask | 0x8000, + TARGET_APCS_32 ? FALSE : TRUE); + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + } + else + { + if (live_regs_mask || regs_ever_live[14]) + { + /* Restore the integer regs, and the return address into lr */ + if (! lr_save_eliminated) + live_regs_mask |= 0x4000; + + if (live_regs_mask != 0) + /* CYGNUS LOCAL unknown */ + { + code_size += 4; + print_multi_reg (f, "ldmfd\t%ssp!", live_regs_mask, FALSE); + } + /* END CYGNUS LOCAL */ + } + + if (current_function_pretend_args_size) + { + /* Unwind the pre-pushed regs */ + operands[0] = operands[1] = stack_pointer_rtx; + operands[2] = GEN_INT (current_function_pretend_args_size); + output_add_immediate (operands); + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + } + /* And finally, go home */ + if (TARGET_THUMB_INTERWORK) + fprintf (f, "\tbx\t%slr\n", REGISTER_PREFIX); + else if (TARGET_APCS_32) + fprintf (f, "\tmov\t%spc, %slr\n", REGISTER_PREFIX, REGISTER_PREFIX ); + else + fprintf (f, "\tmovs\t%spc, %slr\n", REGISTER_PREFIX, REGISTER_PREFIX ); + /* CYGNUS LOCAL unknown */ + code_size += 4; + /* END CYGNUS LOCAL */ + } + } + +epilogue_done: + + /* CYGNUS LOCAL unknown */ + if (optimize > 0) + arm_increase_location (code_size + + insn_addresses[INSN_UID (get_last_insn ())] + + get_prologue_size ()); + /* END CYGNUS LOCAL */ + + current_function_anonymous_args = 0; + after_arm_reorg = 0; +} + +static void +emit_multi_reg_push (mask) + int mask; +{ + int num_regs = 0; + int i, j; + rtx par; + + for (i = 0; i < 16; i++) + if (mask & (1 << i)) + num_regs++; + + if (num_regs == 0 || num_regs > 16) + abort (); + + par = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (num_regs)); + + for (i = 0; i < 16; i++) + { + if (mask & (1 << i)) + { + XVECEXP (par, 0, 0) + = gen_rtx (SET, VOIDmode, gen_rtx (MEM, BLKmode, + gen_rtx (PRE_DEC, BLKmode, + stack_pointer_rtx)), + gen_rtx (UNSPEC, BLKmode, + gen_rtvec (1, gen_rtx (REG, SImode, i)), + 2)); + break; + } + } + + for (j = 1, i++; j < num_regs; i++) + { + if (mask & (1 << i)) + { + XVECEXP (par, 0, j) + = gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, i)); + j++; + } + } + + emit_insn (par); +} + +static void +emit_sfm (base_reg, count) + int base_reg; + int count; +{ + rtx par; + int i; + + par = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (count)); + + XVECEXP (par, 0, 0) = gen_rtx (SET, VOIDmode, + gen_rtx (MEM, BLKmode, + gen_rtx (PRE_DEC, BLKmode, + stack_pointer_rtx)), + gen_rtx (UNSPEC, BLKmode, + gen_rtvec (1, gen_rtx (REG, XFmode, + base_reg++)), + 2)); + for (i = 1; i < count; i++) + XVECEXP (par, 0, i) = gen_rtx (USE, VOIDmode, + gen_rtx (REG, XFmode, base_reg++)); + + emit_insn (par); +} + +void +arm_expand_prologue () +{ + int reg; + rtx amount = GEN_INT (-(get_frame_size () + + current_function_outgoing_args_size)); + int live_regs_mask = 0; + int store_arg_regs = 0; + /* CYGNUS LOCAL unknown */ + int sp_overflow_check = 0; + /* END CYGNUS LOCAL */ + int volatile_func = (optimize > 0 + && TREE_THIS_VOLATILE (current_function_decl)); + + /* Naked functions don't have prologues. */ + if (arm_naked_function_p (current_function_decl)) + return; + + if (current_function_anonymous_args && current_function_pretend_args_size) + store_arg_regs = 1; + + if (! volatile_func) + for (reg = 0; reg <= 10; reg++) + if (regs_ever_live[reg] && ! call_used_regs[reg]) + live_regs_mask |= 1 << reg; + + if (! volatile_func && regs_ever_live[14]) + live_regs_mask |= 0x4000; + + if (frame_pointer_needed) + { + live_regs_mask |= 0xD800; + emit_insn (gen_movsi (gen_rtx (REG, SImode, 12), + stack_pointer_rtx)); + } + + if (current_function_pretend_args_size) + { + if (store_arg_regs) + emit_multi_reg_push ((0xf0 >> (current_function_pretend_args_size / 4)) + & 0xf); + else + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (-current_function_pretend_args_size))); + } + + if (live_regs_mask) + { + /* If we have to push any regs, then we must push lr as well, or + we won't get a proper return. */ + live_regs_mask |= 0x4000; + emit_multi_reg_push (live_regs_mask); + } + + /* For now the integer regs are still pushed in output_func_epilogue (). */ + + if (! volatile_func) + { + if (arm_fpu_arch == FP_SOFT2) + { + for (reg = 23; reg > 15; reg--) + if (regs_ever_live[reg] && ! call_used_regs[reg]) + emit_insn (gen_rtx (SET, VOIDmode, + gen_rtx (MEM, XFmode, + gen_rtx (PRE_DEC, XFmode, + stack_pointer_rtx)), + gen_rtx (REG, XFmode, reg))); + } + else + { + int start_reg = 23; + + for (reg = 23; reg > 15; reg--) + { + if (regs_ever_live[reg] && ! call_used_regs[reg]) + { + if (start_reg - reg == 3) + { + emit_sfm (reg, 4); + start_reg = reg - 1; + } + } + else + { + if (start_reg != reg) + emit_sfm (reg + 1, start_reg - reg); + start_reg = reg - 1; + } + } + + if (start_reg != reg) + emit_sfm (reg + 1, start_reg - reg); + } + } + + if (frame_pointer_needed) + emit_insn (gen_addsi3 (hard_frame_pointer_rtx, gen_rtx (REG, SImode, 12), + (GEN_INT + (-(4 + current_function_pretend_args_size))))); + + /* CYGNUS LOCAL */ + /* The arm vxworks group wants the instructions setting up the frame */ + /* to be unscheduled or unbroken */ + if (TARGET_NO_SCHED_PRO) + emit_insn (gen_blockage ()); + + /* Checking whether the frame amount is zero is not a good enough + marker for deciding whether we need to check for stack overflow. + We are interested in whether anything has/is being stored on the + stack. Since GCC always creates the frame structure at the + moment, this is always true. When we add a machine specific flag + to allow leaf functions to avoid creating an entry frame we will + need to make this conditional (NOTE: This will probably not be a + standard feature, since the debugging world may assume that EVERY + function has a frame, whereas it is not actually a requirement of + the APCS). */ + if (TARGET_APCS_STACK) + { + int bound = get_frame_size (); + + /* The software stack overflow handler has two forms. The first + is for small stack frames, where 256bytes or less of stack is + required: + __rt_stkovf_split_small + + The second is for bigger stack frames of more than 256bytes: + __rt_stkovf_split_big + + The run-time *MUST* provide these routines when software + stack checking is enabled. After calling one of the above + routines the fp/r11 and sp/r12 registers do not necessarily + point into the same stack chunk. This means that arguments + passed on the stack *MUST* be addressed by offsets from + fp/r11 and *NOT* from sp/r13. The sl/r10 register should + always be at the bottom of the current stack chunk, with at + least 256bytes of stack available beneath it (this allows for + leaf functions that use less than 256bytes of stack to avoid + the stack limit check, aswell as giving the overflow + functions some workspace). + + NOTE: The stack-checking APCS does *NOT* cope with alloca(), + since the amount of stack required is not known until + run-time. Similarly the use of run-time sized vectors causes + the same problem. This means that the handler routines + should only be used for raising aborts at the moment, and not + for providing stack chunk extension. + + TODO: Check code generated for late stack pointer + modifications. The APCS allows for these, but a similar + stack overflow check and call must be inserted. */ + + if (bound < 256) + { + /* Leaf functions that use less than 256bytes of stack do + not need to perform a check: */ + if (frame_pointer_needed) + { + /* Stop the prologue being re-ordered: */ + emit_insn (gen_blockage ()); + emit_insn (gen_cond_call (stack_pointer_rtx, + gen_rtx (REG, SImode, 10), + gen_rtx (SYMBOL_REF, Pmode, + "*__rt_stkovf_split_small"), + gen_rtx (LTU, SImode, 24))); + sp_overflow_check = 1; + } + } + else + { + rtx bamount; + + if (!frame_pointer_needed) + abort (); + + if (!const_ok_for_arm ((HOST_WIDE_INT) bound)) + { + /* Find the closest 8bit rotated (by even amount) value + above bound: */ + int count; + for (count = 0; ((bound >> count) & ~0xFF); count +=2); + bound = (bound & (0xFF << count)) + (1 << count); + } + bamount = GEN_INT (- bound); + + emit_insn (gen_blockage ()); /* stop prologue being re-ordered */ + emit_insn (gen_addsi3 (gen_rtx (REG, SImode, 12), + stack_pointer_rtx, bamount)); + emit_insn (gen_cond_call (gen_rtx (REG, SImode, 12), + gen_rtx (REG, SImode, 10), + gen_rtx (SYMBOL_REF, Pmode, + "*__rt_stkovf_split_big"), + gen_rtx (LTU, SImode, 24))); + sp_overflow_check = 1; + } + } + /* END CYGNUS LOCAL */ + + if (amount != const0_rtx) + { + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, amount)); + emit_insn (gen_rtx (CLOBBER, VOIDmode, + gen_rtx (MEM, BLKmode, stack_pointer_rtx))); + } + + /* CYGNUS LOCAL */ + /* If we are profiling, make sure no instructions are scheduled before + the call to mcount. Similarly do not allow instructions + to be moved to before the stack overflow check or if the user has + requested no scheduling in the prolog. */ + if (profile_flag || profile_block_flag || sp_overflow_check) + emit_insn (gen_blockage ()); + /* END CYGNUS LOCAL */ +} + + +/* If CODE is 'd', then the X is a condition operand and the instruction + should only be executed if the condition is true. + if CODE is 'D', then the X is a condition operand and the instruction + should only be executed if the condition is false: however, if the mode + of the comparison is CCFPEmode, then always execute the instruction -- we + do this because in these circumstances !GE does not necessarily imply LT; + in these cases the instruction pattern will take care to make sure that + an instruction containing %d will follow, thereby undoing the effects of + doing this instruction unconditionally. + If CODE is 'N' then X is a floating point operand that must be negated + before output. + If CODE is 'B' then output a bitwise inverted value of X (a const int). + If X is a REG and CODE is `M', output a ldm/stm style multi-reg. */ + +void +arm_print_operand (stream, x, code) + FILE *stream; + rtx x; + int code; +{ + switch (code) + { + case '@': + fputs (ASM_COMMENT_START, stream); + return; + + case '|': + fputs (REGISTER_PREFIX, stream); + return; + + case '?': + if (arm_ccfsm_state == 3 || arm_ccfsm_state == 4) + fputs (arm_condition_codes[arm_current_cc], stream); + return; + + case 'N': + { + REAL_VALUE_TYPE r; + REAL_VALUE_FROM_CONST_DOUBLE (r, x); + r = REAL_VALUE_NEGATE (r); + fprintf (stream, "%s", fp_const_from_val (&r)); + } + return; + + case 'B': + if (GET_CODE (x) == CONST_INT) + fprintf (stream, +#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT + "%d", +#else + "%ld", +#endif + ARM_SIGN_EXTEND (~ INTVAL (x))); + else + { + putc ('~', stream); + output_addr_const (stream, x); + } + return; + + case 'i': + fprintf (stream, "%s", arithmetic_instr (x, 1)); + return; + + case 'I': + fprintf (stream, "%s", arithmetic_instr (x, 0)); + return; + + case 'S': + { + HOST_WIDE_INT val; + char *shift = shift_op (x, &val); + + if (shift) + { + fprintf (stream, ", %s ", shift_op (x, &val)); + if (val == -1) + arm_print_operand (stream, XEXP (x, 1), 0); + else + fprintf (stream, +#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT + "#%d", +#else + "#%ld", +#endif + val); + } + } + return; + + case 'Q': + if (REGNO (x) > 15) + abort (); + fputs (REGISTER_PREFIX, stream); + fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0)], stream); + return; + + case 'R': + if (REGNO (x) > 15) + abort (); + fputs (REGISTER_PREFIX, stream); + fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1)], stream); + return; + + case 'm': + fputs (REGISTER_PREFIX, stream); + if (GET_CODE (XEXP (x, 0)) == REG) + fputs (reg_names[REGNO (XEXP (x, 0))], stream); + else + fputs (reg_names[REGNO (XEXP (XEXP (x, 0), 0))], stream); + return; + + case 'M': + fprintf (stream, "{%s%s-%s%s}", REGISTER_PREFIX, reg_names[REGNO (x)], + REGISTER_PREFIX, reg_names[REGNO (x) - 1 + + ((GET_MODE_SIZE (GET_MODE (x)) + + GET_MODE_SIZE (SImode) - 1) + / GET_MODE_SIZE (SImode))]); + return; + + case 'd': + if (x) + fputs (arm_condition_codes[get_arm_condition_code (x)], + stream); + return; + + case 'D': + if (x) + fputs (arm_condition_codes[ARM_INVERSE_CONDITION_CODE + (get_arm_condition_code (x))], + stream); + return; + + default: + if (x == 0) + abort (); + + if (GET_CODE (x) == REG) + { + fputs (REGISTER_PREFIX, stream); + fputs (reg_names[REGNO (x)], stream); + } + else if (GET_CODE (x) == MEM) + { + output_memory_reference_mode = GET_MODE (x); + output_address (XEXP (x, 0)); + } + else if (GET_CODE (x) == CONST_DOUBLE) + fprintf (stream, "#%s", fp_immediate_constant (x)); + else if (GET_CODE (x) == NEG) + abort (); /* This should never happen now. */ + else + { + fputc ('#', stream); + output_addr_const (stream, x); + } + } +} + +/* CYGNUS LOCAL unknown */ +/* Increase the `arm_text_location' by AMOUNT if we're in the text + segment. */ + +void +arm_increase_location (amount) + int amount; +{ + if (in_text_section ()) + arm_text_location += amount; +} + + +/* Output a label definition. If this label is within the .text segment, it + is stored in OFFSET_TABLE, to be used when building `llc' instructions. + Maybe GCC remembers names not starting with a `*' for a long time, but this + is a minority anyway, so we just make a copy. Do not store the leading `*' + if the name starts with one. */ + +void +arm_asm_output_label (stream, name) + FILE * stream; + char * name; +{ + char * real_name; + char * s; + struct label_offset *cur; + int hash = 0; + + assemble_name (stream, name); + fputs (":\n", stream); + + if (! in_text_section ()) + return; + + if (name[0] == '*') + { + real_name = xmalloc (1 + strlen (&name[1])); + strcpy (real_name, &name[1]); + } + else + { + real_name = xmalloc (2 + strlen (name)); + strcpy (real_name, user_label_prefix); + strcat (real_name, name); + } + for (s = real_name; *s; s++) + hash += *s; + + hash = hash % LABEL_HASH_SIZE; + cur = (struct label_offset *) xmalloc (sizeof (struct label_offset)); + cur->name = real_name; + cur->offset = arm_text_location; + cur->cdr = offset_table[hash]; + offset_table[hash] = cur; +} +/* END CYGNUS LOCAL */ + +/* A finite state machine takes care of noticing whether or not instructions + can be conditionally executed, and thus decrease execution time and code + size by deleting branch instructions. The fsm is controlled by + final_prescan_insn, and controls the actions of ASM_OUTPUT_OPCODE. */ + +/* The state of the fsm controlling condition codes are: + 0: normal, do nothing special + 1: make ASM_OUTPUT_OPCODE not output this instruction + 2: make ASM_OUTPUT_OPCODE not output this instruction + 3: make instructions conditional + 4: make instructions conditional + + State transitions (state->state by whom under condition): + 0 -> 1 final_prescan_insn if the `target' is a label + 0 -> 2 final_prescan_insn if the `target' is an unconditional branch + 1 -> 3 ASM_OUTPUT_OPCODE after not having output the conditional branch + 2 -> 4 ASM_OUTPUT_OPCODE after not having output the conditional branch + 3 -> 0 ASM_OUTPUT_INTERNAL_LABEL if the `target' label is reached + (the target label has CODE_LABEL_NUMBER equal to arm_target_label). + 4 -> 0 final_prescan_insn if the `target' unconditional branch is reached + (the target insn is arm_target_insn). + + If the jump clobbers the conditions then we use states 2 and 4. + + A similar thing can be done with conditional return insns. + + XXX In case the `target' is an unconditional branch, this conditionalising + of the instructions always reduces code size, but not always execution + time. But then, I want to reduce the code size to somewhere near what + /bin/cc produces. */ + +/* Returns the index of the ARM condition code string in + `arm_condition_codes'. COMPARISON should be an rtx like + `(eq (...) (...))'. */ + +static enum arm_cond_code +get_arm_condition_code (comparison) + rtx comparison; +{ + enum machine_mode mode = GET_MODE (XEXP (comparison, 0)); + register int code; + register enum rtx_code comp_code = GET_CODE (comparison); + + if (GET_MODE_CLASS (mode) != MODE_CC) + mode = SELECT_CC_MODE (comp_code, XEXP (comparison, 0), + XEXP (comparison, 1)); + + switch (mode) + { + case CC_DNEmode: code = ARM_NE; goto dominance; + case CC_DEQmode: code = ARM_EQ; goto dominance; + case CC_DGEmode: code = ARM_GE; goto dominance; + case CC_DGTmode: code = ARM_GT; goto dominance; + case CC_DLEmode: code = ARM_LE; goto dominance; + case CC_DLTmode: code = ARM_LT; goto dominance; + case CC_DGEUmode: code = ARM_CS; goto dominance; + case CC_DGTUmode: code = ARM_HI; goto dominance; + case CC_DLEUmode: code = ARM_LS; goto dominance; + case CC_DLTUmode: code = ARM_CC; + + dominance: + if (comp_code != EQ && comp_code != NE) + abort (); + + if (comp_code == EQ) + return ARM_INVERSE_CONDITION_CODE (code); + return code; + + case CC_NOOVmode: + switch (comp_code) + { + case NE: return ARM_NE; + case EQ: return ARM_EQ; + case GE: return ARM_PL; + case LT: return ARM_MI; + default: abort (); + } + + case CC_Zmode: + case CCFPmode: + switch (comp_code) + { + case NE: return ARM_NE; + case EQ: return ARM_EQ; + default: abort (); + } + + case CCFPEmode: + switch (comp_code) + { + case GE: return ARM_GE; + case GT: return ARM_GT; + case LE: return ARM_LS; + case LT: return ARM_MI; + default: abort (); + } + + case CC_SWPmode: + switch (comp_code) + { + case NE: return ARM_NE; + case EQ: return ARM_EQ; + case GE: return ARM_LE; + case GT: return ARM_LT; + case LE: return ARM_GE; + case LT: return ARM_GT; + case GEU: return ARM_LS; + case GTU: return ARM_CC; + case LEU: return ARM_CS; + case LTU: return ARM_HI; + default: abort (); + } + + case CC_Cmode: + switch (comp_code) + { + case LTU: return ARM_CS; + case GEU: return ARM_CC; + default: abort (); + } + + case CCmode: + switch (comp_code) + { + case NE: return ARM_NE; + case EQ: return ARM_EQ; + case GE: return ARM_GE; + case GT: return ARM_GT; + case LE: return ARM_LE; + case LT: return ARM_LT; + case GEU: return ARM_CS; + case GTU: return ARM_HI; + case LEU: return ARM_LS; + case LTU: return ARM_CC; + default: abort (); + } + + default: abort (); + } + + abort (); +} + + +void +final_prescan_insn (insn, opvec, noperands) + rtx insn; + rtx *opvec; + int noperands; +{ + /* BODY will hold the body of INSN. */ + register rtx body = PATTERN (insn); + + /* This will be 1 if trying to repeat the trick, and things need to be + reversed if it appears to fail. */ + int reverse = 0; + + /* JUMP_CLOBBERS will be one implies that the conditions if a branch is + taken are clobbered, even if the rtl suggests otherwise. It also + means that we have to grub around within the jump expression to find + out what the conditions are when the jump isn't taken. */ + int jump_clobbers = 0; + + /* If we start with a return insn, we only succeed if we find another one. */ + int seeking_return = 0; + + /* START_INSN will hold the insn from where we start looking. This is the + first insn after the following code_label if REVERSE is true. */ + rtx start_insn = insn; + + /* If in state 4, check if the target branch is reached, in order to + change back to state 0. */ + if (arm_ccfsm_state == 4) + { + if (insn == arm_target_insn) + { + arm_target_insn = NULL; + arm_ccfsm_state = 0; + } + return; + } + + /* If in state 3, it is possible to repeat the trick, if this insn is an + unconditional branch to a label, and immediately following this branch + is the previous target label which is only used once, and the label this + branch jumps to is not too far off. */ + if (arm_ccfsm_state == 3) + { + if (simplejump_p (insn)) + { + start_insn = next_nonnote_insn (start_insn); + if (GET_CODE (start_insn) == BARRIER) + { + /* XXX Isn't this always a barrier? */ + start_insn = next_nonnote_insn (start_insn); + } + if (GET_CODE (start_insn) == CODE_LABEL + && CODE_LABEL_NUMBER (start_insn) == arm_target_label + && LABEL_NUSES (start_insn) == 1) + reverse = TRUE; + else + return; + } + else if (GET_CODE (body) == RETURN) + { + start_insn = next_nonnote_insn (start_insn); + if (GET_CODE (start_insn) == BARRIER) + start_insn = next_nonnote_insn (start_insn); + if (GET_CODE (start_insn) == CODE_LABEL + && CODE_LABEL_NUMBER (start_insn) == arm_target_label + && LABEL_NUSES (start_insn) == 1) + { + reverse = TRUE; + seeking_return = 1; + } + else + return; + } + else + return; + } + + if (arm_ccfsm_state != 0 && !reverse) + abort (); + if (GET_CODE (insn) != JUMP_INSN) + return; + + /* This jump might be paralleled with a clobber of the condition codes + the jump should always come first */ + if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0) + body = XVECEXP (body, 0, 0); + +#if 0 + /* If this is a conditional return then we don't want to know */ + if (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC + && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE + && (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN + || GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN)) + return; +#endif + + if (reverse + || (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC + && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE)) + { + int insns_skipped; + int fail = FALSE, succeed = FALSE; + /* Flag which part of the IF_THEN_ELSE is the LABEL_REF. */ + int then_not_else = TRUE; + rtx this_insn = start_insn, label = 0; + + if (get_attr_conds (insn) == CONDS_JUMP_CLOB) + { + /* The code below is wrong for these, and I haven't time to + fix it now. So we just do the safe thing and return. This + whole function needs re-writing anyway. */ + jump_clobbers = 1; + return; + } + + /* Register the insn jumped to. */ + if (reverse) + { + if (!seeking_return) + label = XEXP (SET_SRC (body), 0); + } + else if (GET_CODE (XEXP (SET_SRC (body), 1)) == LABEL_REF) + label = XEXP (XEXP (SET_SRC (body), 1), 0); + else if (GET_CODE (XEXP (SET_SRC (body), 2)) == LABEL_REF) + { + label = XEXP (XEXP (SET_SRC (body), 2), 0); + then_not_else = FALSE; + } + else if (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN) + seeking_return = 1; + else if (GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN) + { + seeking_return = 1; + then_not_else = FALSE; + } + else + abort (); + + /* See how many insns this branch skips, and what kind of insns. If all + insns are okay, and the label or unconditional branch to the same + label is not too far away, succeed. */ + for (insns_skipped = 0; + !fail && !succeed && insns_skipped++ < max_insns_skipped;) + { + rtx scanbody; + + this_insn = next_nonnote_insn (this_insn); + if (!this_insn) + break; + + switch (GET_CODE (this_insn)) + { + case CODE_LABEL: + /* Succeed if it is the target label, otherwise fail since + control falls in from somewhere else. */ + if (this_insn == label) + { + if (jump_clobbers) + { + arm_ccfsm_state = 2; + this_insn = next_nonnote_insn (this_insn); + } + else + arm_ccfsm_state = 1; + succeed = TRUE; + } + else + fail = TRUE; + break; + + case BARRIER: + /* Succeed if the following insn is the target label. + Otherwise fail. + If return insns are used then the last insn in a function + will be a barrier. */ + this_insn = next_nonnote_insn (this_insn); + if (this_insn && this_insn == label) + { + if (jump_clobbers) + { + arm_ccfsm_state = 2; + this_insn = next_nonnote_insn (this_insn); + } + else + arm_ccfsm_state = 1; + succeed = TRUE; + } + else + fail = TRUE; + break; + + case CALL_INSN: + /* If using 32-bit addresses the cc is not preserved over + calls */ + if (TARGET_APCS_32) + { + /* Succeed if the following insn is the target label, + or if the following two insns are a barrier and + the target label. */ + this_insn = next_nonnote_insn (this_insn); + if (this_insn && GET_CODE (this_insn) == BARRIER) + this_insn = next_nonnote_insn (this_insn); + + if (this_insn && this_insn == label + && insns_skipped < max_insns_skipped) + { + if (jump_clobbers) + { + arm_ccfsm_state = 2; + this_insn = next_nonnote_insn (this_insn); + } + else + arm_ccfsm_state = 1; + succeed = TRUE; + } + else + fail = TRUE; + } + break; + + case JUMP_INSN: + /* If this is an unconditional branch to the same label, succeed. + If it is to another label, do nothing. If it is conditional, + fail. */ + /* XXX Probably, the tests for SET and the PC are unnecessary. */ + + scanbody = PATTERN (this_insn); + if (GET_CODE (scanbody) == SET + && GET_CODE (SET_DEST (scanbody)) == PC) + { + if (GET_CODE (SET_SRC (scanbody)) == LABEL_REF + && XEXP (SET_SRC (scanbody), 0) == label && !reverse) + { + arm_ccfsm_state = 2; + succeed = TRUE; + } + else if (GET_CODE (SET_SRC (scanbody)) == IF_THEN_ELSE) + fail = TRUE; + } + /* Fail if a conditional return is undesirable (eg on a + StrongARM), but still allow this if optimizing for size. */ + else if (GET_CODE (scanbody) == RETURN + && ! use_return_insn (TRUE) + && ! optimize_size) + fail = TRUE; + else if (GET_CODE (scanbody) == RETURN + && seeking_return) + { + arm_ccfsm_state = 2; + succeed = TRUE; + } + else if (GET_CODE (scanbody) == PARALLEL) + { + switch (get_attr_conds (this_insn)) + { + case CONDS_NOCOND: + break; + default: + fail = TRUE; + break; + } + } + break; + + case INSN: + /* Instructions using or affecting the condition codes make it + fail. */ + scanbody = PATTERN (this_insn); + if (! (GET_CODE (scanbody) == SET + || GET_CODE (scanbody) == PARALLEL) + || get_attr_conds (this_insn) != CONDS_NOCOND) + fail = TRUE; + break; + + default: + break; + } + } + if (succeed) + { + if ((!seeking_return) && (arm_ccfsm_state == 1 || reverse)) + arm_target_label = CODE_LABEL_NUMBER (label); + else if (seeking_return || arm_ccfsm_state == 2) + { + while (this_insn && GET_CODE (PATTERN (this_insn)) == USE) + { + this_insn = next_nonnote_insn (this_insn); + if (this_insn && (GET_CODE (this_insn) == BARRIER + || GET_CODE (this_insn) == CODE_LABEL)) + abort (); + } + if (!this_insn) + { + /* Oh, dear! we ran off the end.. give up */ + recog (PATTERN (insn), insn, NULL_PTR); + arm_ccfsm_state = 0; + arm_target_insn = NULL; + return; + } + arm_target_insn = this_insn; + } + else + abort (); + if (jump_clobbers) + { + if (reverse) + abort (); + arm_current_cc = + get_arm_condition_code (XEXP (XEXP (XEXP (SET_SRC (body), + 0), 0), 1)); + if (GET_CODE (XEXP (XEXP (SET_SRC (body), 0), 0)) == AND) + arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); + if (GET_CODE (XEXP (SET_SRC (body), 0)) == NE) + arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); + } + else + { + /* If REVERSE is true, ARM_CURRENT_CC needs to be inverted from + what it was. */ + if (!reverse) + arm_current_cc = get_arm_condition_code (XEXP (SET_SRC (body), + 0)); + } + + if (reverse || then_not_else) + arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); + } + /* restore recog_operand (getting the attributes of other insns can + destroy this array, but final.c assumes that it remains intact + across this call; since the insn has been recognized already we + call recog direct). */ + recog (PATTERN (insn), insn, NULL_PTR); + } +} + +#ifdef AOF_ASSEMBLER +/* Special functions only needed when producing AOF syntax assembler. */ + +rtx aof_pic_label = NULL_RTX; +struct pic_chain +{ + struct pic_chain *next; + char *symname; +}; + +static struct pic_chain *aof_pic_chain = NULL; + +rtx +aof_pic_entry (x) + rtx x; +{ + struct pic_chain **chainp; + int offset; + + if (aof_pic_label == NULL_RTX) + { + /* This needs to persist throughout the compilation. */ + end_temporary_allocation (); + aof_pic_label = gen_rtx (SYMBOL_REF, Pmode, "x$adcons"); + resume_temporary_allocation (); + } + + for (offset = 0, chainp = &aof_pic_chain; *chainp; + offset += 4, chainp = &(*chainp)->next) + if ((*chainp)->symname == XSTR (x, 0)) + return plus_constant (aof_pic_label, offset); + + *chainp = (struct pic_chain *) xmalloc (sizeof (struct pic_chain)); + (*chainp)->next = NULL; + (*chainp)->symname = XSTR (x, 0); + return plus_constant (aof_pic_label, offset); +} + +void +aof_dump_pic_table (f) + FILE *f; +{ + struct pic_chain *chain; + + if (aof_pic_chain == NULL) + return; + + fprintf (f, "\tAREA |%s$$adcons|, BASED %s%s\n", + reg_names[PIC_OFFSET_TABLE_REGNUM], REGISTER_PREFIX, + reg_names[PIC_OFFSET_TABLE_REGNUM]); + fputs ("|x$adcons|\n", f); + + for (chain = aof_pic_chain; chain; chain = chain->next) + { + fputs ("\tDCD\t", f); + assemble_name (f, chain->symname); + fputs ("\n", f); + } +} + +int arm_text_section_count = 1; + +char * +aof_text_section () +{ + static char buf[100]; + sprintf (buf, "\tAREA |C$$code%d|, CODE, READONLY", + arm_text_section_count++); + if (flag_pic) + strcat (buf, ", PIC, REENTRANT"); + return buf; +} + +static int arm_data_section_count = 1; + +char * +aof_data_section () +{ + static char buf[100]; + sprintf (buf, "\tAREA |C$$data%d|, DATA", arm_data_section_count++); + return buf; +} + +/* The AOF assembler is religiously strict about declarations of + imported and exported symbols, so that it is impossible to declare + a function as imported near the beginning of the file, and then to + export it later on. It is, however, possible to delay the decision + until all the functions in the file have been compiled. To get + around this, we maintain a list of the imports and exports, and + delete from it any that are subsequently defined. At the end of + compilation we spit the remainder of the list out before the END + directive. */ + +struct import +{ + struct import *next; + char *name; +}; + +static struct import *imports_list = NULL; + +void +aof_add_import (name) + char *name; +{ + struct import *new; + + for (new = imports_list; new; new = new->next) + if (new->name == name) + return; + + new = (struct import *) xmalloc (sizeof (struct import)); + new->next = imports_list; + imports_list = new; + new->name = name; +} + +void +aof_delete_import (name) + char *name; +{ + struct import **old; + + for (old = &imports_list; *old; old = & (*old)->next) + { + if ((*old)->name == name) + { + *old = (*old)->next; + return; + } + } +} + +int arm_main_function = 0; + +void +aof_dump_imports (f) + FILE *f; +{ + /* The AOF assembler needs this to cause the startup code to be extracted + from the library. Brining in __main causes the whole thing to work + automagically. */ + if (arm_main_function) + { + text_section (); + fputs ("\tIMPORT __main\n", f); + fputs ("\tDCD __main\n", f); + } + + /* Now dump the remaining imports. */ + while (imports_list) + { + fprintf (f, "\tIMPORT\t"); + assemble_name (f, imports_list->name); + fputc ('\n', f); + imports_list = imports_list->next; + } +} +#endif /* AOF_ASSEMBLER */ + +/* CYGNUS LOCAL */ + +/* Return non-zero if X is a symbolic operand (contains a SYMBOL_REF). */ +int +symbolic_operand (mode, x) + enum machine_mode mode; + rtx x; +{ + switch (GET_CODE (x)) + { + case CONST_DOUBLE: + case CONST: + case MEM: + case PLUS: + return symbolic_operand (mode, XEXP (x, 0)); + case SYMBOL_REF: + case LABEL_REF: + return 1; + default: + return 0; + } +} + +/* Handle a special case when computing the offset + of an argument from the frame pointer. */ +int +arm_debugger_arg_offset (value, addr) + int value; + struct rtx_def * addr; +{ + rtx insn; + + /* We are only interested if dbxout_parms() failed to compute the offset. */ + if (value != 0) + return 0; + + /* We can only cope with the case where the address is held in a register. */ + if (GET_CODE (addr) != REG) + return 0; + + /* If we are using the frame pointer to point at the argument, then an offset of 0 is correct. */ + if (REGNO (addr) == HARD_FRAME_POINTER_REGNUM) + return 0; + + /* Oh dear. The argument is pointed to by a register rather + than being held in a register, or being stored at a known + offset from the frame pointer. Since GDB only understands + those two kinds of argument we must translate the address + held in the register into an offset from the frame pointer. + We do this by searching through the insns for the function + looking to see where this register gets its value. If the + register is initialised from the frame pointer plus an offset + then we are in luck and we can continue, otherwise we give up. + + This code is exercised by producing debugging information + for a function with arguments like this: + + double func (double a, double b, int c, double d) {return d;} + + Without this code the stab for parameter 'd' will be set to + an offset of 0 from the frame pointer, rather than 8. */ + + /* The if() statement says: + + If the insn is a normal instruction + and if the insn is setting the value in a register + and if the register being set is the register holding the address of the argument + and if the address is computing by an addition + that involves adding to a register + which is the frame pointer + a constant integer + + then... */ + + for (insn = get_insns(); insn; insn = NEXT_INSN (insn)) + { + if ( GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == SET + && REGNO (XEXP (PATTERN (insn), 0)) == REGNO (addr) + && GET_CODE (XEXP (PATTERN (insn), 1)) == PLUS + && GET_CODE (XEXP (XEXP (PATTERN (insn), 1), 0)) == REG + && REGNO (XEXP (XEXP (PATTERN (insn), 1), 0)) == HARD_FRAME_POINTER_REGNUM + && GET_CODE (XEXP (XEXP (PATTERN (insn), 1), 1)) == CONST_INT + ) + { + value = INTVAL (XEXP (XEXP (PATTERN (insn), 1), 1)); + + break; + } + } + + if (value == 0) + { + warning ("Unable to compute real location of stacked parameter" ); + value = 8; /* XXX magic hack */ + } + + return value; +} + +/* Return nonzero if this insn is a call insn. */ + +static int +is_call_insn (insn) + rtx insn; +{ + if (GET_CODE (insn) == CALL_INSN) + return 1; + + if (GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == SEQUENCE + && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN) + return 1; + + return 0; +} + +/* Return nonzero if this insn, which is known to occur after a call insn, + will not stop the call from being interpreted as a tail call. */ + +static int +is_safe_after_call_insn (insn) + rtx insn; +{ + if (GET_CODE (insn) == NOTE) + return 1; + + if (GET_CODE (insn) == INSN) + { + rtx pattern = PATTERN (insn); + + if (GET_CODE (pattern) == USE) + return 1; + + /* Special case: Assignment of the result of the call that + has just been made to the return value for this function + will result in a move from the result register to itself. + Detect this case and rely upon the fact that a later pass + will eliminate this redundant move. */ + + if (GET_CODE (pattern) == SET + && GET_CODE (SET_SRC (pattern)) == REG + && GET_CODE (SET_DEST (pattern)) == REG + && REGNO (SET_SRC (pattern)) == REGNO (SET_DEST (pattern))) + return 1; + } + + return 0; +} + +/* Return nonzero if this function is suitable for a tail call optimisation. */ + +int +can_tail_call_optimise () +{ + rtx insn; + int found_call = 0; + + /* Functions that need frames cannot have tail call optimisations applied. */ + if (get_frame_size() > 0 + || current_function_anonymous_args) + return 0; + + /* Functions that perform more than one function call, + or that perform some computation after their only + function call cannot be optimised either. */ + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + if (is_call_insn (insn)) + { + if (found_call) + return 0; + else + found_call = 1; + } + else if (found_call) + { + if (! is_safe_after_call_insn (insn)) + return 0; + } + } + + /* Repeat the tests for the insns in the epilogue list. */ + for (insn = current_function_epilogue_delay_list; insn; insn = XEXP (insn, 1)) + { + if (is_call_insn (insn)) + { + if (found_call) + return 0; + else + found_call = 1; + } + else if (found_call) + { + if (! is_safe_after_call_insn (insn)) + return 0; + } + } + + return found_call; +} +/* END CYGNUS LOCAL */ + +/* CYGNUS LOCAL nickc */ +int +ok_integer_or_other (operand) + rtx operand; +{ + if (GET_CODE (operand) == CONST_INT) + { + if (const_ok_for_arm (INTVAL (operand)) + || const_ok_for_arm (~INTVAL (operand))) + return 1; + return 0; + } + + return 1; +} +/* END CYGNUS LOCAL */ diff --git a/gcc_arm/config/arm/arm_020422.h b/gcc_arm/config/arm/arm_020422.h new file mode 100755 index 0000000..ec12928 --- /dev/null +++ b/gcc_arm/config/arm/arm_020422.h @@ -0,0 +1,2309 @@ +/* Definitions of target machine for GNU compiler, for Acorn RISC Machine. + Copyright (C) 1991, 93, 94, 95, 96, 97, 98, 1999, 2002 Free Software Foundation, Inc. + Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl) + and Martin Simmons (@harleqn.co.uk). + More major hacks by Richard Earnshaw (rwe11@cl.cam.ac.uk) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Configuration triples for ARM ports work as follows: + (This is a bit of a mess and needs some thought) + arm-*-*: little endian + armel-*-*: little endian + armeb-*-*: big endian + If a non-embedded environment (ie: "real" OS) is specified, `arm' + should default to that used by the OS. +*/ + +#ifndef __ARM_H__ +#define __ARM_H__ + +#define TARGET_CPU_arm2 0x0000 +#define TARGET_CPU_arm250 0x0000 +#define TARGET_CPU_arm3 0x0000 +#define TARGET_CPU_arm6 0x0001 +#define TARGET_CPU_arm600 0x0001 +#define TARGET_CPU_arm610 0x0002 +#define TARGET_CPU_arm7 0x0001 +#define TARGET_CPU_arm7m 0x0004 +#define TARGET_CPU_arm7dm 0x0004 +#define TARGET_CPU_arm7dmi 0x0004 +#define TARGET_CPU_arm700 0x0001 +#define TARGET_CPU_arm710 0x0002 +#define TARGET_CPU_arm7100 0x0002 +#define TARGET_CPU_arm7500 0x0002 +#define TARGET_CPU_arm7500fe 0x1001 +#define TARGET_CPU_arm7tdmi 0x0008 +#define TARGET_CPU_arm8 0x0010 +#define TARGET_CPU_arm810 0x0020 +#define TARGET_CPU_strongarm 0x0040 +#define TARGET_CPU_strongarm110 0x0040 +#define TARGET_CPU_strongarm1100 0x0040 +#define TARGET_CPU_arm9 0x0080 +#define TARGET_CPU_arm9tdmi 0x0080 +/* Configure didn't specify */ +#define TARGET_CPU_generic 0x8000 + +enum arm_cond_code +{ + ARM_EQ = 0, ARM_NE, ARM_CS, ARM_CC, ARM_MI, ARM_PL, ARM_VS, ARM_VC, + ARM_HI, ARM_LS, ARM_GE, ARM_LT, ARM_GT, ARM_LE, ARM_AL, ARM_NV +}; +extern enum arm_cond_code arm_current_cc; +extern char *arm_condition_codes[]; + +#define ARM_INVERSE_CONDITION_CODE(X) ((enum arm_cond_code) (((int)X) ^ 1)) + +/* This is needed by the tail-calling peepholes */ +extern int frame_pointer_needed; + + +/* Just in case configure has failed to define anything. */ +#ifndef TARGET_CPU_DEFAULT +#define TARGET_CPU_DEFAULT TARGET_CPU_generic +#endif + +/* If the configuration file doesn't specify the cpu, the subtarget may + override it. If it doesn't, then default to an ARM6. */ +#if TARGET_CPU_DEFAULT == TARGET_CPU_generic +#undef TARGET_CPU_DEFAULT +#ifdef SUBTARGET_CPU_DEFAULT +#define TARGET_CPU_DEFAULT SUBTARGET_CPU_DEFAULT +#else +#define TARGET_CPU_DEFAULT TARGET_CPU_arm6 +#endif +#endif + +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm2 +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_2__" +#else +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm6 || TARGET_CPU_DEFAULT == TARGET_CPU_arm610 || TARGET_CPU_DEFAULT == TARGET_CPU_arm7500fe +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_3__" +#else +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm7m +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_3M__" +#else +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm7tdmi || TARGET_CPU_DEFAULT == TARGET_CPU_arm9 +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_4T__" +#else +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm8 || TARGET_CPU_DEFAULT == TARGET_CPU_arm810 || TARGET_CPU_DEFAULT == TARGET_CPU_strongarm +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_4__" +#else +Unrecognized value in TARGET_CPU_DEFAULT. +#endif +#endif +#endif +#endif +#endif + +#ifndef CPP_PREDEFINES +#define CPP_PREDEFINES "-Darm -Acpu(arm) -Amachine(arm)" +#endif + +#define CPP_SPEC "\ +%(cpp_cpu_arch) %(cpp_apcs_pc) %(cpp_float) \ +%(cpp_endian) %(subtarget_cpp_spec)" + +/* Set the architecture define -- if -march= is set, then it overrides + the -mcpu= setting. */ +#define CPP_CPU_ARCH_SPEC "\ +%{m2:-D__arm2__ -D__ARM_ARCH_2__} \ +%{m3:-D__arm2__ -D__ARM_ARCH_2__} \ +%{m6:-D__arm6__ -D__ARM_ARCH_3__} \ +%{march=arm2:-D__ARM_ARCH_2__} \ +%{march=arm250:-D__ARM_ARCH_2__} \ +%{march=arm3:-D__ARM_ARCH_2__} \ +%{march=arm6:-D__ARM_ARCH_3__} \ +%{march=arm600:-D__ARM_ARCH_3__} \ +%{march=arm610:-D__ARM_ARCH_3__} \ +%{march=arm7:-D__ARM_ARCH_3__} \ +%{march=arm700:-D__ARM_ARCH_3__} \ +%{march=arm710:-D__ARM_ARCH_3__} \ +%{march=arm7100:-D__ARM_ARCH_3__} \ +%{march=arm7500:-D__ARM_ARCH_3__} \ +%{march=arm7500fe:-D__ARM_ARCH_3__} \ +%{march=arm7m:-D__ARM_ARCH_3M__} \ +%{march=arm7dm:-D__ARM_ARCH_3M__} \ +%{march=arm7dmi:-D__ARM_ARCH_3M__} \ +%{march=arm7tdmi:-D__ARM_ARCH_4T__} \ +%{march=arm8:-D__ARM_ARCH_4__} \ +%{march=arm810:-D__ARM_ARCH_4__} \ +%{march=arm9:-D__ARM_ARCH_4T__} \ +%{march=arm920:-D__ARM_ARCH_4__} \ +%{march=arm920t:-D__ARM_ARCH_4T__} \ +%{march=arm9tdmi:-D__ARM_ARCH_4T__} \ +%{march=strongarm:-D__ARM_ARCH_4__} \ +%{march=strongarm110:-D__ARM_ARCH_4__} \ +%{march=strongarm1100:-D__ARM_ARCH_4__} \ +%{march=armv2:-D__ARM_ARCH_2__} \ +%{march=armv2a:-D__ARM_ARCH_2__} \ +%{march=armv3:-D__ARM_ARCH_3__} \ +%{march=armv3m:-D__ARM_ARCH_3M__} \ +%{march=armv4:-D__ARM_ARCH_4__} \ +%{march=armv4t:-D__ARM_ARCH_4T__} \ +%{!march=*: \ + %{mcpu=arm2:-D__ARM_ARCH_2__} \ + %{mcpu=arm250:-D__ARM_ARCH_2__} \ + %{mcpu=arm3:-D__ARM_ARCH_2__} \ + %{mcpu=arm6:-D__ARM_ARCH_3__} \ + %{mcpu=arm600:-D__ARM_ARCH_3__} \ + %{mcpu=arm610:-D__ARM_ARCH_3__} \ + %{mcpu=arm7:-D__ARM_ARCH_3__} \ + %{mcpu=arm700:-D__ARM_ARCH_3__} \ + %{mcpu=arm710:-D__ARM_ARCH_3__} \ + %{mcpu=arm7100:-D__ARM_ARCH_3__} \ + %{mcpu=arm7500:-D__ARM_ARCH_3__} \ + %{mcpu=arm7500fe:-D__ARM_ARCH_3__} \ + %{mcpu=arm7m:-D__ARM_ARCH_3M__} \ + %{mcpu=arm7dm:-D__ARM_ARCH_3M__} \ + %{mcpu=arm7dmi:-D__ARM_ARCH_3M__} \ + %{mcpu=arm7tdmi:-D__ARM_ARCH_4T__} \ + %{mcpu=arm8:-D__ARM_ARCH_4__} \ + %{mcpu=arm810:-D__ARM_ARCH_4__} \ + %{mcpu=arm9:-D__ARM_ARCH_4T__} \ + %{mcpu=arm920:-D__ARM_ARCH_4__} \ + %{mcpu=arm920t:-D__ARM_ARCH_4T__} \ + %{mcpu=arm9tdmi:-D__ARM_ARCH_4T__} \ + %{mcpu=strongarm:-D__ARM_ARCH_4__} \ + %{mcpu=strongarm110:-D__ARM_ARCH_4__} \ + %{mcpu=strongarm1100:-D__ARM_ARCH_4__} \ + %{!mcpu*:%{!m6:%{!m2:%{!m3:%(cpp_cpu_arch_default)}}}}} \ +" + +/* Define __APCS_26__ if the PC also contains the PSR */ +/* This also examines deprecated -m[236] if neither of -mapcs-{26,32} is set, + ??? Delete this for 2.9. */ +#define CPP_APCS_PC_SPEC "\ +%{mapcs-32:%{mapcs-26:%e-mapcs-26 and -mapcs-32 may not be used together} \ + -D__APCS_32__} \ +%{mapcs-26:-D__APCS_26__} \ +%{!mapcs-32: %{!mapcs-26:%{m6:-D__APCS_32__} %{m2:-D__APCS_26__} \ + %{m3:-D__APCS_26__} %{!m6:%{!m3:%{!m2:%(cpp_apcs_pc_default)}}}}} \ +" + +#ifndef CPP_APCS_PC_DEFAULT_SPEC +#define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_26__" +#endif + +#define CPP_FLOAT_SPEC "\ +%{msoft-float:\ + %{mhard-float:%e-msoft-float and -mhard_float may not be used together} \ + -D__SOFTFP__} \ +%{!mhard-float:%{!msoft-float:%(cpp_float_default)}} \ +" + +/* Default is hard float, which doesn't define anything */ +#define CPP_FLOAT_DEFAULT_SPEC "" + +#define CPP_ENDIAN_SPEC "\ +%{mbig-endian: \ + %{mlittle-endian: \ + %e-mbig-endian and -mlittle-endian may not be used together} \ + -D__ARMEB__ %{mwords-little-endian:-D__ARMWEL__}} \ +%{!mlittle-endian:%{!mbig-endian:%(cpp_endian_default)}} \ +" + +/* Default is little endian, which doesn't define anything. */ +#define CPP_ENDIAN_DEFAULT_SPEC "" + +/* Translate (for now) the old -m[236] option into the appropriate -mcpu=... + and -mapcs-xx equivalents. + ??? Remove support for this style in 2.9.*/ +#define CC1_SPEC "\ +%{m2:-mcpu=arm2 -mapcs-26} \ +%{m3:-mcpu=arm3 -mapcs-26} \ +%{m6:-mcpu=arm6 -mapcs-32} \ +" + +/* This macro defines names of additional specifications to put in the specs + that can be used in various specifications like CC1_SPEC. Its definition + is an initializer with a subgrouping for each command option. + + Each subgrouping contains a string constant, that defines the + specification name, and a string constant that used by the GNU CC driver + program. + + Do not define this macro if it does not need to do anything. */ +#define EXTRA_SPECS \ + { "cpp_cpu_arch", CPP_CPU_ARCH_SPEC }, \ + { "cpp_cpu_arch_default", CPP_ARCH_DEFAULT_SPEC }, \ + { "cpp_apcs_pc", CPP_APCS_PC_SPEC }, \ + { "cpp_apcs_pc_default", CPP_APCS_PC_DEFAULT_SPEC }, \ + { "cpp_float", CPP_FLOAT_SPEC }, \ + { "cpp_float_default", CPP_FLOAT_DEFAULT_SPEC }, \ + { "cpp_endian", CPP_ENDIAN_SPEC }, \ + { "cpp_endian_default", CPP_ENDIAN_DEFAULT_SPEC }, \ + { "subtarget_cpp_spec", SUBTARGET_CPP_SPEC }, \ + SUBTARGET_EXTRA_SPECS + +#define SUBTARGET_EXTRA_SPECS +#define SUBTARGET_CPP_SPEC "" + + +/* Run-time Target Specification. */ +#ifndef TARGET_VERSION +#define TARGET_VERSION \ + fputs (" (ARM/generic)", stderr); +#endif + +/* Run-time compilation parameters selecting different hardware subsets. */ +extern int target_flags; + +/* The floating point instruction architecture, can be 2 or 3 */ +/* CYGNUS LOCAL nickc/renamed from target_fp_name */ +extern char * target_fpe_name; +/* END CYGNUS LOCAL */ + +/* Nonzero if the function prologue (and epilogue) should obey + the ARM Procedure Call Standard. */ +#define ARM_FLAG_APCS_FRAME (0x0001) + +/* Nonzero if the function prologue should output the function name to enable + the post mortem debugger to print a backtrace (very useful on RISCOS, + unused on RISCiX). Specifying this flag also enables + -fno-omit-frame-pointer. + XXX Must still be implemented in the prologue. */ +#define ARM_FLAG_POKE (0x0002) + +/* Nonzero if floating point instructions are emulated by the FPE, in which + case instruction scheduling becomes very uninteresting. */ +#define ARM_FLAG_FPE (0x0004) + +/* Nonzero if destined for an ARM6xx. Takes out bits that assume restoration + of condition flags when returning from a branch & link (ie. a function) */ +/* ********* DEPRECATED ******** */ +#define ARM_FLAG_ARM6 (0x0008) + +/* ********* DEPRECATED ******** */ +#define ARM_FLAG_ARM3 (0x0010) + +/* Nonzero if destined for a processor in 32-bit program mode. Takes out bit + that assume restoration of the condition flags when returning from a + branch and link (ie a function). */ +#define ARM_FLAG_APCS_32 (0x0020) + +/* Nonzero if stack checking should be performed on entry to each function + which allocates temporary variables on the stack. */ +#define ARM_FLAG_APCS_STACK (0x0040) + +/* Nonzero if floating point parameters should be passed to functions in + floating point registers. */ +#define ARM_FLAG_APCS_FLOAT (0x0080) + +/* Nonzero if re-entrant, position independent code should be generated. + This is equivalent to -fpic. */ +#define ARM_FLAG_APCS_REENT (0x0100) + +/* Nonzero if the MMU will trap unaligned word accesses, so shorts must be + loaded byte-at-a-time. */ +#define ARM_FLAG_SHORT_BYTE (0x0200) + +/* Nonzero if all floating point instructions are missing (and there is no + emulator either). Generate function calls for all ops in this case. */ +#define ARM_FLAG_SOFT_FLOAT (0x0400) + +/* Nonzero if we should compile with BYTES_BIG_ENDIAN set to 1. */ +#define ARM_FLAG_BIG_END (0x0800) + +/* Nonzero if we should compile for Thumb interworking. */ +#define ARM_FLAG_THUMB (0x1000) + +/* Nonzero if we should have little-endian words even when compiling for + big-endian (for backwards compatibility with older versions of GCC). */ +#define ARM_FLAG_LITTLE_WORDS (0x2000) + +/* CYGNUS LOCAL */ +/* Nonzero if we need to protect the prolog from scheduling */ +#define ARM_FLAG_NO_SCHED_PRO (0x4000) +/* END CYGNUS LOCAL */ + +/* Nonzero if a call to abort should be generated if a noreturn +function tries to return. */ +#define ARM_FLAG_ABORT_NORETURN (0x8000) + +/* Nonzero if all call instructions should be indirect. */ +#define ARM_FLAG_LONG_CALLS (0x10000) + +#define TARGET_APCS (target_flags & ARM_FLAG_APCS_FRAME) +#define TARGET_POKE_FUNCTION_NAME (target_flags & ARM_FLAG_POKE) +#define TARGET_FPE (target_flags & ARM_FLAG_FPE) +#define TARGET_6 (target_flags & ARM_FLAG_ARM6) +#define TARGET_3 (target_flags & ARM_FLAG_ARM3) +#define TARGET_APCS_32 (target_flags & ARM_FLAG_APCS_32) +#define TARGET_APCS_STACK (target_flags & ARM_FLAG_APCS_STACK) +#define TARGET_APCS_FLOAT (target_flags & ARM_FLAG_APCS_FLOAT) +#define TARGET_APCS_REENT (target_flags & ARM_FLAG_APCS_REENT) +#define TARGET_SHORT_BY_BYTES (target_flags & ARM_FLAG_SHORT_BYTE) +#define TARGET_SOFT_FLOAT (target_flags & ARM_FLAG_SOFT_FLOAT) +#define TARGET_HARD_FLOAT (! TARGET_SOFT_FLOAT) +#define TARGET_BIG_END (target_flags & ARM_FLAG_BIG_END) +#define TARGET_THUMB_INTERWORK (target_flags & ARM_FLAG_THUMB) +#define TARGET_LITTLE_WORDS (target_flags & ARM_FLAG_LITTLE_WORDS) +/* CYGNUS LOCAL */ +#define TARGET_NO_SCHED_PRO (target_flags & ARM_FLAG_NO_SCHED_PRO) +/* END CYGNUS LOCAL */ +#define TARGET_ABORT_NORETURN (target_flags & ARM_FLAG_ABORT_NORETURN) +#define TARGET_LONG_CALLS (target_flags & ARM_FLAG_LONG_CALLS) + +/* SUBTARGET_SWITCHES is used to add flags on a per-config basis. + Bit 31 is reserved. See riscix.h. */ +#ifndef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES +#endif + +#define TARGET_SWITCHES \ +{ \ + {"apcs", ARM_FLAG_APCS_FRAME, "" }, \ + {"apcs-frame", ARM_FLAG_APCS_FRAME, \ + "Generate APCS conformant stack frames" }, \ + {"no-apcs-frame", -ARM_FLAG_APCS_FRAME, "" }, \ + {"poke-function-name", ARM_FLAG_POKE, \ + "Store function names in object code" }, \ + {"fpe", ARM_FLAG_FPE, "" }, \ + {"6", ARM_FLAG_ARM6, "" }, \ + {"2", ARM_FLAG_ARM3, "" }, \ + {"3", ARM_FLAG_ARM3, "" }, \ + {"apcs-32", ARM_FLAG_APCS_32, \ + "Use the 32bit version of the APCS" }, \ + {"apcs-26", -ARM_FLAG_APCS_32, \ + "Use the 26bit version of the APCS" }, \ + {"apcs-stack-check", ARM_FLAG_APCS_STACK, "" }, \ + {"no-apcs-stack-check", -ARM_FLAG_APCS_STACK, "" }, \ + {"apcs-float", ARM_FLAG_APCS_FLOAT, \ + "Pass FP arguments in FP registers" }, \ + {"no-apcs-float", -ARM_FLAG_APCS_FLOAT, "" }, \ + {"apcs-reentrant", ARM_FLAG_APCS_REENT, \ + "Generate re-entrant, PIC code" }, \ + {"no-apcs-reentrant", -ARM_FLAG_APCS_REENT, "" }, \ + {"short-load-bytes", ARM_FLAG_SHORT_BYTE, \ + "Load shorts a byte at a time" }, \ + {"no-short-load-bytes", -ARM_FLAG_SHORT_BYTE, "" }, \ + {"short-load-words", -ARM_FLAG_SHORT_BYTE, \ + "Load words a byte at a time" }, \ + {"no-short-load-words", ARM_FLAG_SHORT_BYTE, "" }, \ + {"soft-float", ARM_FLAG_SOFT_FLOAT, \ + "Use library calls to perform FP operations" }, \ + {"hard-float", -ARM_FLAG_SOFT_FLOAT, \ + "Use hardware floating point instructions" }, \ + {"big-endian", ARM_FLAG_BIG_END, \ + "Assume target CPU is configured as big endian" }, \ + {"little-endian", -ARM_FLAG_BIG_END, \ + "Assume target CPU is configured as little endian" }, \ + {"words-little-endian", ARM_FLAG_LITTLE_WORDS, \ + "Assume big endian bytes, little endian words" }, \ + {"thumb-interwork", ARM_FLAG_THUMB, \ + "Support calls between THUMB and ARM instructions sets" }, \ + {"no-thumb-interwork", -ARM_FLAG_THUMB, "" }, \ + {"abort-on-noreturn", ARM_FLAG_ABORT_NORETURN, \ + "Generate a call to abort if a noreturn function returns"}, \ + {"no-abort-on-noreturn", -ARM_FLAG_ABORT_NORETURN, ""}, \ + /* CYGNUS LOCAL */ \ + {"sched-prolog", -ARM_FLAG_NO_SCHED_PRO, \ + "Do not move instructions into a function's prologue" }, \ + {"no-sched-prolog", ARM_FLAG_NO_SCHED_PRO, "" }, \ + /* END CYGNUS LOCAL */ \ + {"long-calls", ARM_FLAG_LONG_CALLS, \ + "Generate all call instructions as indirect calls"}, \ + {"no-long-calls", -ARM_FLAG_LONG_CALLS, ""}, \ + SUBTARGET_SWITCHES \ + {"", TARGET_DEFAULT } \ +} + +#define TARGET_OPTIONS \ +{ \ + {"cpu=", & arm_select[0].string, \ + "Specify the name of the target CPU" }, \ + {"arch=", & arm_select[1].string, \ + "Specify the name of the target architecture" }, \ + {"tune=", & arm_select[2].string, "" }, \ + {"fpe=", & target_fpe_name, "" }, \ + {"fp=", & target_fpe_name, \ + "Specify the version of the floating point emulator" }, \ + { "structure-size-boundary=", & structure_size_string, \ + "Specify the minumum bit alignment of structures" } \ +} + +struct arm_cpu_select +{ + char * string; + char * name; + struct processors * processors; +}; + +/* This is a magic array. If the user specifies a command line switch + which matches one of the entries in TARGET_OPTIONS then the corresponding + string pointer will be set to the value specified by the user. */ +extern struct arm_cpu_select arm_select[]; + +enum prog_mode_type +{ + prog_mode26, + prog_mode32 +}; + +/* Recast the program mode class to be the prog_mode attribute */ +#define arm_prog_mode ((enum attr_prog_mode) arm_prgmode) + +extern enum prog_mode_type arm_prgmode; + +/* What sort of floating point unit do we have? Hardware or software. + If software, is it issue 2 or issue 3? */ +enum floating_point_type +{ + FP_HARD, + FP_SOFT2, + FP_SOFT3 +}; + +/* Recast the floating point class to be the floating point attribute. */ +#define arm_fpu_attr ((enum attr_fpu) arm_fpu) + +/* What type of floating point to tune for */ +extern enum floating_point_type arm_fpu; + +/* What type of floating point instructions are available */ +extern enum floating_point_type arm_fpu_arch; + +/* Default floating point architecture. Override in sub-target if + necessary. */ +#define FP_DEFAULT FP_SOFT2 + +/* Nonzero if the processor has a fast multiply insn, and one that does + a 64-bit multiply of two 32-bit values. */ +extern int arm_fast_multiply; + +/* Nonzero if this chip supports the ARM Architecture 4 extensions */ +extern int arm_arch4; + +/* CYGNUS LOCAL nickc/load scheduling */ +/* Nonzero if this chip can benefit from load scheduling. */ +extern int arm_ld_sched; +/* END CYGNUS LOCAL */ + +/* Nonzero if this chip is a StrongARM. */ +extern int arm_is_strong; + +/* Nonzero if this chip is a an ARM6 or an ARM7. */ +extern int arm_is_6_or_7; + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT 0 +#endif + +/* The frame pointer register used in gcc has nothing to do with debugging; + that is controlled by the APCS-FRAME option. */ +/* Not fully implemented yet */ +/* #define CAN_DEBUG_WITHOUT_FP 1 */ + +#define TARGET_MEM_FUNCTIONS 1 + +#define OVERRIDE_OPTIONS arm_override_options () + +/* Target machine storage Layout. */ + + +/* Define this macro if it is advisable to hold scalars in registers + in a wider mode than that declared by the program. In such cases, + the value is constrained to be within the bounds of the declared + type, but kept valid in the wider mode. The signedness of the + extension may differ from that of the type. */ + +/* It is far faster to zero extend chars than to sign extend them */ + +#define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \ + if (GET_MODE_CLASS (MODE) == MODE_INT \ + && GET_MODE_SIZE (MODE) < 4) \ + { \ + if (MODE == QImode) \ + UNSIGNEDP = 1; \ + else if (MODE == HImode) \ + UNSIGNEDP = TARGET_SHORT_BY_BYTES != 0; \ + (MODE) = SImode; \ + } + +/* Define this macro if the promotion described by `PROMOTE_MODE' + should also be done for outgoing function arguments. */ +/* This is required to ensure that push insns always push a word. */ +#define PROMOTE_FUNCTION_ARGS + +/* Define for XFmode extended real floating point support. + This will automatically cause REAL_ARITHMETIC to be defined. */ +/* For the ARM: + I think I have added all the code to make this work. Unfortunately, + early releases of the floating point emulation code on RISCiX used a + different format for extended precision numbers. On my RISCiX box there + is a bug somewhere which causes the machine to lock up when running enquire + with long doubles. There is the additional aspect that Norcroft C + treats long doubles as doubles and we ought to remain compatible. + Perhaps someone with an FPA coprocessor and not running RISCiX would like + to try this someday. */ +/* #define LONG_DOUBLE_TYPE_SIZE 96 */ + +/* Disable XFmode patterns in md file */ +#define ENABLE_XF_PATTERNS 0 + +/* Define if you don't want extended real, but do want to use the + software floating point emulator for REAL_ARITHMETIC and + decimal <-> binary conversion. */ +/* See comment above */ +#define REAL_ARITHMETIC + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. */ +#define BITS_BIG_ENDIAN 0 + +/* Define this if most significant byte of a word is the lowest numbered. + Most ARM processors are run in little endian mode, so that is the default. + If you want to have it run-time selectable, change the definition in a + cover file to be TARGET_BIG_ENDIAN. */ +#define BYTES_BIG_ENDIAN (TARGET_BIG_END != 0) + +/* Define this if most significant word of a multiword number is the lowest + numbered. + This is always false, even when in big-endian mode. */ +#define WORDS_BIG_ENDIAN (BYTES_BIG_ENDIAN && ! TARGET_LITTLE_WORDS) + +/* LIBGCC2_WORDS_BIG_ENDIAN has to be a constant, so we define this based + on processor pre-defineds when compiling libgcc2.c. */ +#if defined(__ARMEB__) && !defined(__ARMWEL__) +#define LIBGCC2_WORDS_BIG_ENDIAN 1 +#else +#define LIBGCC2_WORDS_BIG_ENDIAN 0 +#endif + +/* Define this if most significant word of doubles is the lowest numbered. + This is always true, even when in little-endian mode. */ +#define FLOAT_WORDS_BIG_ENDIAN 1 + +/* Number of bits in an addressable storage unit */ +#define BITS_PER_UNIT 8 + +#define BITS_PER_WORD 32 + +#define UNITS_PER_WORD 4 + +#define POINTER_SIZE 32 + +#define PARM_BOUNDARY 32 + +#define STACK_BOUNDARY 32 + +#define FUNCTION_BOUNDARY 32 + +#define EMPTY_FIELD_BOUNDARY 32 + +#define BIGGEST_ALIGNMENT 32 + +/* Make strings word-aligned so strcpy from constants will be faster. */ +#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ + (TREE_CODE (EXP) == STRING_CST \ + && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) + +/* Every structures size must be a multiple of 32 bits. */ +/* This is for compatibility with ARMCC. ARM SDT Reference Manual + (ARM DUI 0020D) page 2-20 says "Structures are aligned on word + boundaries". */ +#ifndef STRUCTURE_SIZE_BOUNDARY +#define STRUCTURE_SIZE_BOUNDARY 32 +#endif + +/* Used when parsing command line option -mstructure_size_boundary. */ +extern char * structure_size_string; + +/* Non-zero if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT 1 + +#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT + + +/* Standard register usage. */ + +/* Register allocation in ARM Procedure Call Standard (as used on RISCiX): + (S - saved over call). + + r0 * argument word/integer result + r1-r3 argument word + + r4-r8 S register variable + r9 S (rfp) register variable (real frame pointer) + CYGNUS LOCAL nickc/comment change + r10 F S (sl) stack limit (used by -mapcs-stack-check) + END CYGNUS LOCAL + r11 F S (fp) argument pointer + r12 (ip) temp workspace + r13 F S (sp) lower end of current stack frame + r14 (lr) link address/workspace + r15 F (pc) program counter + + f0 floating point result + f1-f3 floating point scratch + + f4-f7 S floating point variable + + cc This is NOT a real register, but is used internally + to represent things that use or set the condition + codes. + sfp This isn't either. It is used during rtl generation + since the offset between the frame pointer and the + auto's isn't known until after register allocation. + afp Nor this, we only need this because of non-local + goto. Without it fp appears to be used and the + elimination code won't get rid of sfp. It tracks + fp exactly at all times. + + *: See CONDITIONAL_REGISTER_USAGE */ + +/* The stack backtrace structure is as follows: + fp points to here: | save code pointer | [fp] + | return link value | [fp, #-4] + | return sp value | [fp, #-8] + | return fp value | [fp, #-12] + [| saved r10 value |] + [| saved r9 value |] + [| saved r8 value |] + [| saved r7 value |] + [| saved r6 value |] + [| saved r5 value |] + [| saved r4 value |] + [| saved r3 value |] + [| saved r2 value |] + [| saved r1 value |] + [| saved r0 value |] + [| saved f7 value |] three words + [| saved f6 value |] three words + [| saved f5 value |] three words + [| saved f4 value |] three words + r0-r3 are not normally saved in a C function. */ + +/* The number of hard registers is 16 ARM + 8 FPU + 1 CC + 1 SFP. */ +#define FIRST_PSEUDO_REGISTER 27 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. */ +#define FIXED_REGISTERS \ +{ \ + 0,0,0,0,0,0,0,0, \ + 0,0,1,1,0,1,0,1, \ + 0,0,0,0,0,0,0,0, \ + 1,1,1 \ +} + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. + The CC is not preserved over function calls on the ARM 6, so it is + easier to assume this for all. SFP is preserved, since FP is. */ +#define CALL_USED_REGISTERS \ +{ \ + 1,1,1,1,0,0,0,0, \ + 0,0,1,1,1,1,1,1, \ + 1,1,1,1,0,0,0,0, \ + 1,1,1 \ +} + +/* If doing stupid life analysis, avoid a bug causing a return value r0 to be + trampled. This effectively reduces the number of available registers by 1. + XXX It is a hack, I know. + XXX Is this still needed? */ +#define CONDITIONAL_REGISTER_USAGE \ +{ \ + if (obey_regdecls) \ + fixed_regs[0] = 1; \ + if (TARGET_SOFT_FLOAT) \ + { \ + int regno; \ + for (regno = 16; regno < 24; ++regno) \ + fixed_regs[regno] = call_used_regs[regno] = 1; \ + } \ + if (flag_pic) \ + { \ + fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ + call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 0; \ + } \ + /* CYGNUS LOCAL */ \ + else if (! TARGET_APCS_STACK) \ + { \ + fixed_regs[10] = 0; \ + call_used_regs[10] = 0; \ + } \ + /* END CYGNUS LOCAL */ \ +} + +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. + + On the ARM regs are UNITS_PER_WORD bits wide; FPU regs can hold any FP + mode. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + (((REGNO) >= 16 && REGNO != FRAME_POINTER_REGNUM \ + && (REGNO) != ARG_POINTER_REGNUM) ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + This is TRUE for ARM regs since they can hold anything, and TRUE for FPU + regs holding FP. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + ((GET_MODE_CLASS (MODE) == MODE_CC) ? (REGNO == CC_REGNUM) : \ + ((REGNO) < 16 || REGNO == FRAME_POINTER_REGNUM \ + || REGNO == ARG_POINTER_REGNUM \ + || GET_MODE_CLASS (MODE) == MODE_FLOAT)) + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + 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) \ + (GET_MODE_CLASS (MODE1) == GET_MODE_CLASS (MODE2)) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* Define this if the program counter is overloaded on a register. */ +#define PC_REGNUM 15 + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 13 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 25 + +/* Define this to be where the real frame pointer is if it is not possible to + work out the offset between the frame pointer and the automatic variables + until after register allocation has taken place. FRAME_POINTER_REGNUM + should point to a special register that we will make sure is eliminated. */ +#define HARD_FRAME_POINTER_REGNUM 11 + +/* 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. + If we have to have a frame pointer we might as well make use of it. + APCS says that the frame pointer does not need to be pushed in leaf + functions, or simple tail call functions. */ +/* CYGNUS LOCAL */ +#define FRAME_POINTER_REQUIRED \ + (current_function_has_nonlocal_label \ + || (TARGET_APCS && (! leaf_function_p () && ! can_tail_call_optimise ()))) + +extern int can_tail_call_optimise (); +/* END CYGNUS LOCAL */ + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 26 + +/* The native (Norcroft) Pascal compiler for the ARM passes the static chain + as an invisible last argument (possible since varargs don't exist in + Pascal), so the following is not true. */ +#define STATIC_CHAIN_REGNUM 8 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 0 + +/* Internal, so that we don't need to refer to a raw number */ +#define CC_REGNUM 24 + +/* The order in which register should be allocated. It is good to use ip + since no saving is required (though calls clobber it) and it never contains + function parameters. It is quite good to use lr since other calls may + clobber it anyway. Allocate r0 through r3 in reverse order since r3 is + least likely to contain a function parameter; in addition results are + returned in r0. + */ +#define REG_ALLOC_ORDER \ +{ \ + 3, 2, 1, 0, 12, 14, 4, 5, \ + 6, 7, 8, 10, 9, 11, 13, 15, \ + 16, 17, 18, 19, 20, 21, 22, 23, \ + 24, 25, 26 \ +} + +/* Register and constant classes. */ + +/* Register classes: all ARM regs or all FPU regs---simple! */ +enum reg_class +{ + NO_REGS, + FPU_REGS, + GENERAL_REGS, + ALL_REGS, + LIM_REG_CLASSES +}; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Give names of register classes as strings for dump file. */ +#define REG_CLASS_NAMES \ +{ \ + "NO_REGS", \ + "FPU_REGS", \ + "GENERAL_REGS", \ + "ALL_REGS", \ +} + +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ +#define REG_CLASS_CONTENTS \ +{ \ + 0x0000000, /* NO_REGS */ \ + 0x0FF0000, /* FPU_REGS */ \ + 0x200FFFF, /* GENERAL_REGS */ \ + 0x2FFFFFF /* ALL_REGS */ \ +} + +/* The same information, inverted: + Return the class number of the smallest class containing + reg number REGNO. This could be a conditional expression + or could index an array. */ +#define REGNO_REG_CLASS(REGNO) \ + (((REGNO) < 16 || REGNO == FRAME_POINTER_REGNUM \ + || REGNO == ARG_POINTER_REGNUM) \ + ? GENERAL_REGS : (REGNO) == CC_REGNUM \ + ? NO_REGS : FPU_REGS) + +/* The class value for index registers, and the one for base regs. */ +#define INDEX_REG_CLASS GENERAL_REGS +#define BASE_REG_CLASS GENERAL_REGS + +/* Get reg_class from a letter such as appears in the machine description. + We only need constraint `f' for FPU_REGS (`r' == GENERAL_REGS). */ +#define REG_CLASS_FROM_LETTER(C) \ + ((C)=='f' ? FPU_REGS : 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: immediate arithmetic operand (i.e. 8 bits shifted as required). + J: valid indexing constants. + K: ~value ok in rhs argument of data operand. + L: -value ok in rhs argument of data operand. + M: 0..32, or a power of 2 (for shifts, or mult done by shift). */ +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? const_ok_for_arm (VALUE) : \ + (C) == 'J' ? ((VALUE) < 4096 && (VALUE) > -4096) : \ + (C) == 'K' ? (const_ok_for_arm (~(VALUE))) : \ + (C) == 'L' ? (const_ok_for_arm (-(VALUE))) : \ + (C) == 'M' ? (((VALUE >= 0 && VALUE <= 32)) \ + || (((VALUE) & ((VALUE) - 1)) == 0)) \ + : 0) + +/* For the ARM, `Q' means that this is a memory operand that is just + an offset from a register. + `S' means any symbol that has the SYMBOL_REF_FLAG set or a CONSTANT_POOL + address. This means that the symbol is in the text segment and can be + accessed without using a load. */ + +#define EXTRA_CONSTRAINT(OP, C) \ + ((C) == 'Q' ? GET_CODE (OP) == MEM && GET_CODE (XEXP (OP, 0)) == REG \ + : (C) == 'R' ? (GET_CODE (OP) == MEM \ + && GET_CODE (XEXP (OP, 0)) == SYMBOL_REF \ + && CONSTANT_POOL_ADDRESS_P (XEXP (OP, 0))) \ + : (C) == 'S' ? (optimize > 0 && CONSTANT_ADDRESS_P (OP)) \ + : 0) + +/* Constant letter 'G' for the FPU immediate constants. + 'H' means the same constant negated. */ +#define CONST_DOUBLE_OK_FOR_LETTER_P(X,C) \ + ((C) == 'G' ? const_double_rtx_ok_for_fpu (X) \ + : (C) == 'H' ? neg_const_double_rtx_ok_for_fpu (X) : 0) + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. */ +#define PREFERRED_RELOAD_CLASS(X, CLASS) (CLASS) + +/* Return the register class of a scratch register needed to copy IN into + or out of a register in CLASS in MODE. If it can be done directly, + NO_REGS is returned. */ +#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS,MODE,X) \ + (((MODE) == HImode && ! arm_arch4 && true_regnum (X) == -1) \ + ? GENERAL_REGS : NO_REGS) + +/* If we need to load shorts byte-at-a-time, then we need a scratch. */ +#define SECONDARY_INPUT_RELOAD_CLASS(CLASS,MODE,X) \ + (((MODE) == HImode && ! arm_arch4 && TARGET_SHORT_BY_BYTES \ + && (GET_CODE (X) == MEM \ + || ((GET_CODE (X) == REG || GET_CODE (X) == SUBREG) \ + && true_regnum (X) == -1))) \ + ? GENERAL_REGS : NO_REGS) + +/* Try a machine-dependent way of reloading an illegitimate address + operand. If we find one, push the reload and jump to WIN. This + macro is used in only one place: `find_reloads_address' in reload.c. + + For the ARM, we wish to handle large displacements off a base + register by splitting the addend across a MOV and the mem insn. + This can cut the number of reloads needed. */ +#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \ +do { \ + if (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REGNO (XEXP (X, 0)) < FIRST_PSEUDO_REGISTER \ + && REG_MODE_OK_FOR_BASE_P (XEXP (X, 0), MODE) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT) \ + { \ + HOST_WIDE_INT val = INTVAL (XEXP (X, 1)); \ + HOST_WIDE_INT low, high; \ + \ + if (MODE == DImode || (TARGET_SOFT_FLOAT && MODE == DFmode)) \ + low = ((val & 0xf) ^ 0x8) - 0x8; \ + else if (MODE == SImode || MODE == QImode \ + || (MODE == SFmode && TARGET_SOFT_FLOAT) \ + || (MODE == HImode && ! arm_arch4)) \ + /* Need to be careful, -4096 is not a valid offset */ \ + low = val >= 0 ? (val & 0xfff) : -((-val) & 0xfff); \ + else if (MODE == HImode && arm_arch4) \ + /* Need to be careful, -256 is not a valid offset */ \ + low = val >= 0 ? (val & 0xff) : -((-val) & 0xff); \ + else if (GET_MODE_CLASS (MODE) == MODE_FLOAT \ + && TARGET_HARD_FLOAT) \ + /* Need to be careful, -1024 is not a valid offset */ \ + low = val >= 0 ? (val & 0x3ff) : -((-val) & 0x3ff); \ + else \ + break; \ + \ + high = ((((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000); \ + /* Check for overflow or zero */ \ + if (low == 0 || high == 0 || (high + low != val)) \ + break; \ + \ + /* Reload the high part into a base reg; leave the low part \ + in the mem. */ \ + X = gen_rtx_PLUS (GET_MODE (X), \ + gen_rtx_PLUS (GET_MODE (X), XEXP (X, 0), \ + GEN_INT (high)), \ + GEN_INT (low)); \ + push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL_PTR, \ + BASE_REG_CLASS, GET_MODE (X), VOIDmode, 0, 0, \ + OPNUM, TYPE); \ + goto WIN; \ + } \ +} while (0) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. + ARM regs are UNITS_PER_WORD bits while FPU regs can hold any FP mode */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((CLASS) == FPU_REGS ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Moves between FPU_REGS and GENERAL_REGS are two memory insns. */ +#define REGISTER_MOVE_COST(CLASS1, CLASS2) \ + ((((CLASS1) == FPU_REGS && (CLASS2) != FPU_REGS) \ + || ((CLASS2) == FPU_REGS && (CLASS1) != FPU_REGS)) \ + ? 20 : 2) + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD 1 + +/* 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 + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. */ +/* The push insns do not do this rounding implicitly. So don't define this. */ +/* #define PUSH_ROUNDING(NPUSHED) (((NPUSHED) + 3) & ~3) */ + +/* Define this if the maximum size of all the outgoing args is to be + accumulated and pushed during the prologue. The amount can be + found in the variable current_function_outgoing_args_size. */ +#define ACCUMULATE_OUTGOING_ARGS + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 4 + +/* Value is the number of byte of arguments automatically + popped when returning from a subroutine call. + FUNDECL is the declaration node of the function (as a tree), + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. + SIZE is the number of bytes of arguments passed on the stack. + + On the ARM, the caller does not pop any of its arguments that were passed + on the stack. */ +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 + +/* 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) \ + (GET_MODE_CLASS (TYPE_MODE (VALTYPE)) == MODE_FLOAT && TARGET_HARD_FLOAT \ + ? gen_rtx (REG, TYPE_MODE (VALTYPE), 16) \ + : gen_rtx (REG, TYPE_MODE (VALTYPE), 0)) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ +#define LIBCALL_VALUE(MODE) \ + (GET_MODE_CLASS (MODE) == MODE_FLOAT && TARGET_HARD_FLOAT \ + ? gen_rtx (REG, MODE, 16) \ + : gen_rtx (REG, MODE, 0)) + +/* 1 if N is a possible register number for a function value. + On the ARM, only r0 and f0 can return results. */ +#define FUNCTION_VALUE_REGNO_P(REGNO) \ + ((REGNO) == 0 || ((REGNO) == 16) && TARGET_HARD_FLOAT) + +/* How large values are returned */ +/* A C expression which can inhibit the returning of certain function values + in registers, based on the type of value. */ +/* CYGNUS LOCAL */ +#define RETURN_IN_MEMORY(TYPE) arm_return_in_memory (TYPE) +/* END CYGNUS LOCAL */ + +/* Define DEFAULT_PCC_STRUCT_RETURN to 1 if all structure and union return + values must be in memory. On the ARM, they need only do so if larger + than a word, or if they contain elements offset from zero in the struct. */ +#define DEFAULT_PCC_STRUCT_RETURN 0 + +/* Define where to put the arguments to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). + + On the ARM, normally the first 16 bytes are passed in registers r0-r3; all + other arguments are passed on the stack. If (NAMED == 0) (which happens + only in assign_parms, since SETUP_INCOMING_VARARGS is defined), say it is + passed in the stack (function_prologue will indeed make it pass in the + stack if necessary). */ +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + ((MODE) == VOIDmode \ + ? GEN_INT ((CUM).call_cookie) \ + : (NAMED) \ + ? ((CUM).nregs >= 16 ? 0 : gen_rtx (REG, MODE, (CUM).nregs / 4)) \ + : 0) + +/* 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) \ + ((CUM).nregs < 16 && 16 < (CUM).nregs + ((MODE) != BLKmode \ + ? GET_MODE_SIZE (MODE) \ + : int_size_in_bytes (TYPE)) \ + ? 4 - (CUM).nregs / 4 : 0) + +/* A C type for declaring a variable that is used as the first argument of + `FUNCTION_ARG' and other related values. For some target machines, the + type `int' suffices and can hold the number of bytes of argument so far. + + On the ARM, this is the number of bytes of arguments scanned so far. */ +typedef struct +{ + /* This is the number of registers of arguments scanned so far. */ + int nregs; + /* One of CALL_NORMAL, CALL_LONG or CALL_SHORT . */ + int call_cookie; +} CUMULATIVE_ARGS; + +/* 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. + On the ARM, the offset starts at 0. */ +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ + ((CUM).nregs = (((FNTYPE) && aggregate_value_p (TREE_TYPE ((FNTYPE)))) \ + ? 4 : 0), \ + (CUM).call_cookie = \ + (((FNTYPE) && lookup_attribute ("short_call", TYPE_ATTRIBUTES (FNTYPE))) \ + ? CALL_SHORT \ + : (((FNTYPE) && lookup_attribute ("long_call", \ + TYPE_ATTRIBUTES (FNTYPE)))\ + || TARGET_LONG_CALLS) \ + ? CALL_LONG \ + : CALL_NORMAL)) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + (CUM).nregs += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3) \ + +/* 1 if N is a possible register number for function argument passing. + On the ARM, r0-r3 are used to pass args. */ +#define FUNCTION_ARG_REGNO_P(REGNO) \ + ((REGNO) >= 0 && (REGNO) <= 3) + +/* Perform any 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. + + On the ARM, PRETEND_SIZE is set in order to have the prologue push the last + named arg and all anonymous args onto the stack. + XXX I know the prologue shouldn't be pushing registers, but it is faster + that way. */ +#define SETUP_INCOMING_VARARGS(CUM, MODE, TYPE, PRETEND_SIZE, NO_RTL) \ +{ \ + extern int current_function_anonymous_args; \ + current_function_anonymous_args = 1; \ + if ((CUM).nregs < 16) \ + (PRETEND_SIZE) = 16 - (CUM).nregs; \ +} + +/* Generate assembly output for the start of a function. */ +#define FUNCTION_PROLOGUE(STREAM, SIZE) \ + output_func_prologue ((STREAM), (SIZE)) + +/* Call the function profiler with a given profile label. The Acorn compiler + puts this BEFORE the prolog but gcc puts it afterwards. The ``mov ip,lr'' + seems like a good idea to stick with cc convention. ``prof'' doesn't seem + to mind about this! */ +#define FUNCTION_PROFILER(STREAM,LABELNO) \ +{ \ + fprintf(STREAM, "\tmov\t%sip, %slr\n", REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf(STREAM, "\tbl\tmcount\n"); \ + fprintf(STREAM, "\t.word\tLP%d\n", (LABELNO)); \ +} + +/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, + the stack pointer does not matter. The value is tested only in + functions that have frame pointers. + No definition is equivalent to always zero. + + On the ARM, the function epilogue recovers the stack pointer from the + frame. */ +#define EXIT_IGNORE_STACK 1 + +/* Generate the assembly code for function exit. */ +#define FUNCTION_EPILOGUE(STREAM, SIZE) \ + output_func_epilogue ((STREAM), (SIZE)) + +/* Determine if the epilogue should be output as RTL. + You should override this if you define FUNCTION_EXTRA_EPILOGUE. */ +#define USE_RETURN_INSN(ISCOND) use_return_insn (ISCOND) + +/* Definitions for register eliminations. + + This is an array of structures. Each structure initializes one pair + of eliminable registers. The "from" register number is given first, + followed by "to". Eliminations of the same "from" register are listed + in order of preference. + + We have two registers that can be eliminated on the ARM. First, the + arg pointer register can often be eliminated in favor of the stack + pointer register. Secondly, the pseudo frame pointer register can always + be eliminated; it is replaced with either the stack or the real frame + pointer. */ + +#define ELIMINABLE_REGS \ +{{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + {ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ + {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + {FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} + +/* Given FROM and TO register numbers, say whether this elimination is allowed. + Frame pointer elimination is automatically handled. + + All eliminations are permissible. Note that ARG_POINTER_REGNUM and + HARD_FRAME_POINTER_REGNUM are in fact the same thing. If we need a frame + pointer, we must eliminate FRAME_POINTER_REGNUM into + HARD_FRAME_POINTER_REGNUM and not into STACK_POINTER_REGNUM. */ +#define CAN_ELIMINATE(FROM, TO) \ + (((TO) == STACK_POINTER_REGNUM && frame_pointer_needed) ? 0 : 1) + +/* Define the offset between two registers, one to be eliminated, and the other + its replacement, at the start of a routine. */ +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ +{ \ + int volatile_func = arm_volatile_func (); \ + if ((FROM) == ARG_POINTER_REGNUM && (TO) == HARD_FRAME_POINTER_REGNUM)\ + (OFFSET) = 0; \ + else if ((FROM) == FRAME_POINTER_REGNUM \ + && (TO) == STACK_POINTER_REGNUM) \ + (OFFSET) = (current_function_outgoing_args_size \ + + (get_frame_size () + 3 & ~3)); \ + else \ + { \ + int regno; \ + int offset = 12; \ + int saved_hard_reg = 0; \ + \ + if (! volatile_func) \ + { \ + for (regno = 0; regno <= 10; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + saved_hard_reg = 1, offset += 4; \ + for (regno = 16; regno <=23; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 12; \ + } \ + if ((FROM) == FRAME_POINTER_REGNUM) \ + (OFFSET) = -offset; \ + else \ + { \ + if (! frame_pointer_needed) \ + offset -= 16; \ + if (! volatile_func \ + && (regs_ever_live[14] || saved_hard_reg)) \ + offset += 4; \ + offset += current_function_outgoing_args_size; \ + (OFFSET) = (get_frame_size () + 3 & ~3) + offset; \ + } \ + } \ +} + +/* CYGNUS LOCAL */ +/* Special case handling of the location of arguments passed on the stack. */ +#define DEBUGGER_ARG_OFFSET(value, addr) value ? value : arm_debugger_arg_offset (value, addr) +/* END CYGNUS LOCAL */ + +/* Output assembler code for a block containing the constant parts + of a trampoline, leaving space for the variable parts. + + On the ARM, (if r8 is the static chain regnum, and remembering that + referencing pc adds an offset of 8) the trampoline looks like: + ldr r8, [pc, #0] + ldr pc, [pc] + .word static chain value + .word function's address + ??? FIXME: When the trampoline returns, r8 will be clobbered. */ +#define TRAMPOLINE_TEMPLATE(FILE) \ +{ \ + fprintf ((FILE), "\tldr\t%sr8, [%spc, #0]\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\tldr\t%spc, [%spc, #0]\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\t.word\t0\n"); \ + fprintf ((FILE), "\t.word\t0\n"); \ +} + +/* Length in units of the trampoline for entering a nested function. */ +#define TRAMPOLINE_SIZE 16 + +/* Alignment required for a trampoline in units. */ +#define TRAMPOLINE_ALIGN 4 + +/* Emit RTL insns to initialize the variable parts of a trampoline. + FNADDR is an RTX for the address of the function's pure code. + CXT is an RTX for the static chain value for the function. */ +#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ +{ \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 8)), \ + (CXT)); \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 12)), \ + (FNADDR)); \ +} + + +/* Addressing modes, and classification of registers for them. */ + +#define HAVE_POST_INCREMENT 1 +#define HAVE_PRE_INCREMENT 1 +#define HAVE_POST_DECREMENT 1 +#define HAVE_PRE_DECREMENT 1 + +/* Macros to check register numbers against specific register classes. */ + +/* These assume that REGNO is a hard or pseudo reg number. + They give nonzero only if REGNO is a hard reg of the suitable class + or a pseudo reg currently allocated to a suitable hard reg. + Since they use reg_renumber, they are safe only once reg_renumber + has been allocated, which happens in local-alloc.c. + + On the ARM, don't allow the pc to be used. */ +#define REGNO_OK_FOR_BASE_P(REGNO) \ + ((REGNO) < 15 || (REGNO) == FRAME_POINTER_REGNUM \ + || (REGNO) == ARG_POINTER_REGNUM \ + || (unsigned) reg_renumber[(REGNO)] < 15 \ + || (unsigned) reg_renumber[(REGNO)] == FRAME_POINTER_REGNUM \ + || (unsigned) reg_renumber[(REGNO)] == ARG_POINTER_REGNUM) +#define REGNO_OK_FOR_INDEX_P(REGNO) \ + REGNO_OK_FOR_BASE_P(REGNO) + +/* Maximum number of registers that can appear in a valid memory address. + Shifts in addresses can't be by a register. */ + +#define MAX_REGS_PER_ADDRESS 2 + +/* Recognize any constant value that is a valid address. */ +/* XXX We can address any constant, eventually... */ + +#ifdef AOF_ASSEMBLER + +#define CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == SYMBOL_REF \ + && CONSTANT_POOL_ADDRESS_P (X)) + +#else + +#define CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == SYMBOL_REF \ + && (CONSTANT_POOL_ADDRESS_P (X) \ + || (optimize > 0 && SYMBOL_REF_FLAG (X)))) + +#endif /* AOF_ASSEMBLER */ + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. + + On the ARM, allow any integer (invalid ones are removed later by insn + patterns), nice doubles and symbol_refs which refer to the function's + constant pool XXX. */ +#define LEGITIMATE_CONSTANT_P(X) (! label_mentioned_p (X)) + +/* Flags for the call/call_value rtl operations set up by function_arg. */ +#define CALL_NORMAL 0x00000000 /* No special processing. */ +#define CALL_LONG 0x00000001 /* Always call indirect. */ +#define CALL_SHORT 0x00000002 /* Never call indirect. */ + +/* Symbols in the text segment can be accessed without indirecting via the + constant pool; it may take an extra binary operation, but this is still + faster than indirecting via memory. Don't do this when not optimizing, + since we won't be calculating al of the offsets necessary to do this + simplification. */ +/* This doesn't work with AOF syntax, since the string table may be in + a different AREA. */ +#ifndef AOF_ASSEMBLER +#define ENCODE_SECTION_INFO(decl) \ +{ \ + if (optimize > 0 && TREE_CONSTANT (decl) \ + && (!flag_writable_strings || TREE_CODE (decl) != STRING_CST)) \ + { \ + rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd' \ + ? TREE_CST_RTL (decl) : DECL_RTL (decl)); \ + SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1; \ + } \ + ARM_ENCODE_CALL_TYPE (decl) \ +} +#else +#define ENCODE_SECTION_INFO(decl) \ +{ \ + ARM_ENCODE_CALL_TYPE (decl) \ +} +#endif + +/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS + is a valid machine specific attribute for DECL. + The attributes in ATTRIBUTES have previously been assigned to DECL. */ +int arm_valid_machine_type_attribute (/* union tree_node *, union tree_node *, + union tree_node *, + union tree_node * */); +#define VALID_MACHINE_TYPE_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \ +arm_valid_machine_type_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS) + +/* If we are referencing a function that is weak then encode a long call + flag in the function name, otherwise if the function is static or + or known to be defined in this file then encode a short call flag. + This macro is used inside the ENCODE_SECTION macro. */ +#define ARM_ENCODE_CALL_TYPE(decl) \ + if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd') \ + { \ + if (TREE_CODE (decl) == FUNCTION_DECL && DECL_WEAK (decl)) \ + arm_encode_call_attribute (decl, LONG_CALL_FLAG_CHAR); \ + else if (! TREE_PUBLIC (decl)) \ + arm_encode_call_attribute (decl, SHORT_CALL_FLAG_CHAR); \ + } + +/* Special characters prefixed to function names + in order to encode attribute like information. + Note, '@' and '*' have already been taken. */ +#define SHORT_CALL_FLAG_CHAR '^' +#define LONG_CALL_FLAG_CHAR '#' + +#define ENCODED_SHORT_CALL_ATTR_P(SYMBOL_NAME) \ + (*(SYMBOL_NAME) == SHORT_CALL_FLAG_CHAR) + +#define ENCODED_LONG_CALL_ATTR_P(SYMBOL_NAME) \ + (*(SYMBOL_NAME) == LONG_CALL_FLAG_CHAR) + +#ifndef SUBTARGET_NAME_ENCODING_LENGTHS +#define SUBTARGET_NAME_ENCODING_LENGTHS +#endif + +/* This is a C fragement for the inside of a switch statement. + Each case label should return the number of characters to + be stripped from the start of a function's name, if that + name starts with the indicated character. */ +#define ARM_NAME_ENCODING_LENGTHS \ + case SHORT_CALL_FLAG_CHAR: return 1; \ + case LONG_CALL_FLAG_CHAR: return 1; \ + case '*': return 1; \ + SUBTARGET_NAME_ENCODING_LENGTHS + +/* This has to be handled by a function because more than part of the + ARM backend uses function name prefixes to encode attributes. */ +#undef STRIP_NAME_ENCODING +#define STRIP_NAME_ENCODING(VAR, SYMBOL_NAME) \ + (VAR) = arm_strip_name_encoding (SYMBOL_NAME) + +/* This is how to output a reference to a user-level label named NAME. + `assemble_name' uses this. */ +#undef ASM_OUTPUT_LABELREF +#define ASM_OUTPUT_LABELREF(FILE, NAME) \ + asm_fprintf (FILE, "%U%s", arm_strip_name_encoding (NAME)) + +/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx + and check its validity for a certain class. + We have two alternate definitions for each of them. + The usual definition accepts all pseudo regs; the other rejects + them unless they have been allocated suitable hard regs. + The symbol REG_OK_STRICT causes the latter definition to be used. */ +#ifndef REG_OK_STRICT + +/* Nonzero if X is a hard reg that can be used as a base reg + or if it is a pseudo reg. */ +#define REG_OK_FOR_BASE_P(X) \ + (REGNO (X) < 16 || REGNO (X) >= FIRST_PSEUDO_REGISTER \ + || REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM) + +/* Nonzero if X is a hard reg that can be used as an index + or if it is a pseudo reg. */ +#define REG_OK_FOR_INDEX_P(X) \ + REG_OK_FOR_BASE_P(X) + +#define REG_OK_FOR_PRE_POST_P(X) \ + (REGNO (X) < 16 || REGNO (X) >= FIRST_PSEUDO_REGISTER \ + || REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM) + +#else + +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + +/* Nonzero if X is a hard reg that can be used as an index. */ +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) + +#define REG_OK_FOR_PRE_POST_P(X) \ + (REGNO (X) < 16 || (unsigned) reg_renumber[REGNO (X)] < 16 \ + || REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO (X)] == FRAME_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO (X)] == ARG_POINTER_REGNUM) + +#endif + +/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression + that is a valid memory address for an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS. */ +#define BASE_REGISTER_RTX_P(X) \ + (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) + +#define INDEX_REGISTER_RTX_P(X) \ + (GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X)) + +/* A C statement (sans semicolon) to jump to LABEL for legitimate index RTXs + used by the macro GO_IF_LEGITIMATE_ADDRESS. Floating point indices can + only be small constants. */ +#define GO_IF_LEGITIMATE_INDEX(MODE, BASE_REGNO, INDEX, LABEL) \ +do \ +{ \ + HOST_WIDE_INT range; \ + enum rtx_code code = GET_CODE (INDEX); \ + \ + if (TARGET_HARD_FLOAT && GET_MODE_CLASS (MODE) == MODE_FLOAT) \ + { \ + if (code == CONST_INT && INTVAL (INDEX) < 1024 \ + && INTVAL (INDEX) > -1024 \ + && (INTVAL (INDEX) & 3) == 0) \ + goto LABEL; \ + } \ + else \ + { \ + if (INDEX_REGISTER_RTX_P (INDEX) && GET_MODE_SIZE (MODE) <= 4) \ + goto LABEL; \ + if (GET_MODE_SIZE (MODE) <= 4 && code == MULT \ + && (! arm_arch4 || (MODE) != HImode)) \ + { \ + rtx xiop0 = XEXP (INDEX, 0); \ + rtx xiop1 = XEXP (INDEX, 1); \ + if (INDEX_REGISTER_RTX_P (xiop0) \ + && power_of_two_operand (xiop1, SImode)) \ + goto LABEL; \ + if (INDEX_REGISTER_RTX_P (xiop1) \ + && power_of_two_operand (xiop0, SImode)) \ + goto LABEL; \ + } \ + if (GET_MODE_SIZE (MODE) <= 4 \ + && (code == LSHIFTRT || code == ASHIFTRT \ + || code == ASHIFT || code == ROTATERT) \ + && (! arm_arch4 || (MODE) != HImode)) \ + { \ + rtx op = XEXP (INDEX, 1); \ + if (INDEX_REGISTER_RTX_P (XEXP (INDEX, 0)) \ + && GET_CODE (op) == CONST_INT && INTVAL (op) > 0 \ + && INTVAL (op) <= 31) \ + goto LABEL; \ + } \ + /* NASTY: Since this limits the addressing of unsigned byte loads */ \ + range = ((MODE) == HImode || (MODE) == QImode) \ + ? (arm_arch4 ? 256 : 4095) : 4096; \ + if (code == CONST_INT && INTVAL (INDEX) < range \ + && INTVAL (INDEX) > -range) \ + goto LABEL; \ + } \ +} while (0) + +/* Jump to LABEL if X is a valid address RTX. This must also take + REG_OK_STRICT into account when deciding about valid registers, but it uses + the above macros so we are in luck. Allow REG, REG+REG, REG+INDEX, + INDEX+REG, REG-INDEX, and non floating SYMBOL_REF to the constant pool. + Allow REG-only and AUTINC-REG if handling TImode or HImode. Other symbol + refs must be forced though a static cell to ensure addressability. */ +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \ +{ \ + if (BASE_REGISTER_RTX_P (X)) \ + goto LABEL; \ + else if ((GET_CODE (X) == POST_INC || GET_CODE (X) == PRE_DEC) \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_PRE_POST_P (XEXP (X, 0))) \ + goto LABEL; \ + else if (GET_MODE_SIZE (MODE) >= 4 && reload_completed \ + && (GET_CODE (X) == LABEL_REF \ + || (GET_CODE (X) == CONST \ + && GET_CODE (XEXP ((X), 0)) == PLUS \ + && GET_CODE (XEXP (XEXP ((X), 0), 0)) == LABEL_REF \ + && GET_CODE (XEXP (XEXP ((X), 0), 1)) == CONST_INT)))\ + goto LABEL; \ + else if ((MODE) == TImode) \ + ; \ + else if ((MODE) == DImode || (TARGET_SOFT_FLOAT && (MODE) == DFmode)) \ + { \ + if (GET_CODE (X) == PLUS && BASE_REGISTER_RTX_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT) \ + { \ + HOST_WIDE_INT val = INTVAL (XEXP (X, 1)); \ + if (val == 4 || val == -4 || val == -8) \ + goto LABEL; \ + } \ + } \ + else if (GET_CODE (X) == PLUS) \ + { \ + rtx xop0 = XEXP(X,0); \ + rtx xop1 = XEXP(X,1); \ + \ + if (BASE_REGISTER_RTX_P (xop0)) \ + GO_IF_LEGITIMATE_INDEX (MODE, REGNO (xop0), xop1, LABEL); \ + else if (BASE_REGISTER_RTX_P (xop1)) \ + GO_IF_LEGITIMATE_INDEX (MODE, REGNO (xop1), xop0, LABEL); \ + } \ + /* Reload currently can't handle MINUS, so disable this for now */ \ + /* else if (GET_CODE (X) == MINUS) \ + { \ + rtx xop0 = XEXP (X,0); \ + rtx xop1 = XEXP (X,1); \ + \ + if (BASE_REGISTER_RTX_P (xop0)) \ + GO_IF_LEGITIMATE_INDEX (MODE, -1, xop1, LABEL); \ + } */ \ + else if (GET_MODE_CLASS (MODE) != MODE_FLOAT \ + && GET_CODE (X) == SYMBOL_REF \ + && CONSTANT_POOL_ADDRESS_P (X)) \ + goto LABEL; \ + else if ((GET_CODE (X) == PRE_INC || GET_CODE (X) == POST_DEC) \ + && (GET_MODE_SIZE (MODE) <= 4) \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_PRE_POST_P (XEXP (X, 0))) \ + goto LABEL; \ +} + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. + + On the ARM, try to convert [REG, #BIGCONST] + into ADD BASE, REG, #UPPERCONST and [BASE, #VALIDCONST], + where VALIDCONST == 0 in case of TImode. */ +extern struct rtx_def *legitimize_pic_address (); +#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ +{ \ + if (GET_CODE (X) == PLUS) \ + { \ + rtx xop0 = XEXP (X, 0); \ + rtx xop1 = XEXP (X, 1); \ + \ + if (CONSTANT_P (xop0) && ! symbol_mentioned_p (xop0)) \ + xop0 = force_reg (SImode, xop0); \ + if (CONSTANT_P (xop1) && ! symbol_mentioned_p (xop1)) \ + xop1 = force_reg (SImode, xop1); \ + if (BASE_REGISTER_RTX_P (xop0) && GET_CODE (xop1) == CONST_INT) \ + { \ + HOST_WIDE_INT n, low_n; \ + rtx base_reg, val; \ + n = INTVAL (xop1); \ + \ + if (MODE == DImode || (TARGET_SOFT_FLOAT && MODE == DFmode)) \ + { \ + low_n = n & 0x0f; \ + n &= ~0x0f; \ + if (low_n > 4) \ + { \ + n += 16; \ + low_n -= 16; \ + } \ + } \ + else \ + { \ + low_n = ((MODE) == TImode ? 0 \ + : n >= 0 ? (n & 0xfff) : -((-n) & 0xfff)); \ + n -= low_n; \ + } \ + base_reg = gen_reg_rtx (SImode); \ + val = force_operand (gen_rtx (PLUS, SImode, xop0, \ + GEN_INT (n)), NULL_RTX); \ + emit_move_insn (base_reg, val); \ + (X) = (low_n == 0 ? base_reg \ + : gen_rtx (PLUS, SImode, base_reg, GEN_INT (low_n))); \ + } \ + else if (xop0 != XEXP (X, 0) || xop1 != XEXP (x, 1)) \ + (X) = gen_rtx (PLUS, SImode, xop0, xop1); \ + } \ + else if (GET_CODE (X) == MINUS) \ + { \ + rtx xop0 = XEXP (X, 0); \ + rtx xop1 = XEXP (X, 1); \ + \ + if (CONSTANT_P (xop0)) \ + xop0 = force_reg (SImode, xop0); \ + if (CONSTANT_P (xop1) && ! symbol_mentioned_p (xop1)) \ + xop1 = force_reg (SImode, xop1); \ + if (xop0 != XEXP (X, 0) || xop1 != XEXP (X, 1)) \ + (X) = gen_rtx (MINUS, SImode, xop0, xop1); \ + } \ + if (flag_pic) \ + (X) = legitimize_pic_address (OLDX, MODE, NULL_RTX); \ + if (memory_address_p (MODE, X)) \ + goto WIN; \ +} + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. */ +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ +{ \ + if (GET_CODE(ADDR) == PRE_DEC || GET_CODE(ADDR) == POST_DEC \ + || GET_CODE(ADDR) == PRE_INC || GET_CODE(ADDR) == POST_INC) \ + goto LABEL; \ +} + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE SImode + +/* 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 */ + +/* Specify the tree operation to be used to convert reals to integers. */ +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* This is the kind of divide that is easiest to do in the general case. */ +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* signed 'char' is most compatible, but RISC OS wants it unsigned. + unsigned is probably best, but may break some code. */ +#ifndef DEFAULT_SIGNED_CHAR +#define DEFAULT_SIGNED_CHAR 0 +#endif + +/* Don't cse the address of the function being compiled. */ +#define NO_RECURSIVE_FUNCTION_CSE 1 + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 4 + +/* Define if operations between registers always perform the operation + on the full register even if a narrower mode is specified. */ +#define WORD_REGISTER_OPERATIONS + +/* Define if loading in MODE, an integral mode narrower than BITS_PER_WORD + will either zero-extend or sign-extend. The value of this macro should + be the code that says which one of the two operations is implicitly + done, NIL if none. */ +#define LOAD_EXTEND_OP(MODE) \ + ((arm_arch4 || (MODE) == QImode) ? ZERO_EXTEND \ + : ((BYTES_BIG_ENDIAN && (MODE) == HImode) ? SIGN_EXTEND : NIL)) + +/* Define this if zero-extension is slow (more than one real instruction). + On the ARM, it is more than one instruction only if not fetching from + memory. */ +/* #define SLOW_ZERO_EXTEND */ + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* Immediate shift counts are truncated by the output routines (or was it + the assembler?). Shift counts in a register are truncated by ARM. Note + that the native compiler puts too large (> 32) immediate shift counts + into a register and shifts by the register, letting the ARM decide what + to do instead of doing that itself. */ +/* This is all wrong. Defining SHIFT_COUNT_TRUNCATED tells combine that + code like (X << (Y % 32)) for register X, Y is equivalent to (X << Y). + On the arm, Y in a register is used modulo 256 for the shift. Only for + rotates is modulo 32 used. */ +/* #define SHIFT_COUNT_TRUNCATED 1 */ + +/* All integers have the same format so truncation is easy. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) 1 + +/* Calling from registers is a massive pain. */ +#define NO_FUNCTION_CSE 1 + +/* Chars and shorts should be passed as ints. */ +#define PROMOTE_PROTOTYPES 1 + +/* The machine modes of pointers and functions */ +#define Pmode SImode +#define FUNCTION_MODE Pmode + +/* The structure type of the machine dependent info field of insns + No uses for this yet. */ +/* #define INSN_MACHINE_INFO struct machine_info */ + +/* The relative costs of various types of constants. Note that cse.c defines + REG = 1, SUBREG = 2, any node = (2 + sum of subnodes). */ +#define CONST_COSTS(RTX, CODE, OUTER_CODE) \ + case CONST_INT: \ + if (const_ok_for_arm (INTVAL (RTX))) \ + return (OUTER_CODE) == SET ? 2 : -1; \ + else if (OUTER_CODE == AND \ + && const_ok_for_arm (~INTVAL (RTX))) \ + return -1; \ + else if ((OUTER_CODE == COMPARE \ + || OUTER_CODE == PLUS || OUTER_CODE == MINUS) \ + && const_ok_for_arm (-INTVAL (RTX))) \ + return -1; \ + else \ + return 5; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 6; \ + case CONST_DOUBLE: \ + if (const_double_rtx_ok_for_fpu (RTX)) \ + return (OUTER_CODE) == SET ? 2 : -1; \ + else if (((OUTER_CODE) == COMPARE || (OUTER_CODE) == PLUS) \ + && neg_const_double_rtx_ok_for_fpu (RTX)) \ + return -1; \ + return(7); + +#define ARM_FRAME_RTX(X) \ + ((X) == frame_pointer_rtx || (X) == stack_pointer_rtx \ + || (X) == arg_pointer_rtx) + +#define DEFAULT_RTX_COSTS(X,CODE,OUTER_CODE) \ + return arm_rtx_costs (X, CODE, OUTER_CODE); + +/* Moves to and from memory are quite expensive */ +#define MEMORY_MOVE_COST(MODE,CLASS,IN) 10 + +/* All address computations that can be done are free, but rtx cost returns + the same for practically all of them. So we weight the different types + of address here in the order (most pref first): + PRE/POST_INC/DEC, SHIFT or NON-INT sum, INT sum, REG, MEM or LABEL. */ +#define ADDRESS_COST(X) \ + (10 - ((GET_CODE (X) == MEM || GET_CODE (X) == LABEL_REF \ + || GET_CODE (X) == SYMBOL_REF) \ + ? 0 \ + : ((GET_CODE (X) == PRE_INC || GET_CODE (X) == PRE_DEC \ + || GET_CODE (X) == POST_INC || GET_CODE (X) == POST_DEC) \ + ? 10 \ + : (((GET_CODE (X) == PLUS || GET_CODE (X) == MINUS) \ + ? 6 + (GET_CODE (XEXP (X, 1)) == CONST_INT ? 2 \ + : ((GET_RTX_CLASS (GET_CODE (XEXP (X, 0))) == '2' \ + || GET_RTX_CLASS (GET_CODE (XEXP (X, 0))) == 'c' \ + || GET_RTX_CLASS (GET_CODE (XEXP (X, 1))) == '2' \ + || GET_RTX_CLASS (GET_CODE (XEXP (X, 1))) == 'c') \ + ? 1 : 0)) \ + : 4))))) + + + +/* Try to generate sequences that don't involve branches, we can then use + conditional instructions */ +#define BRANCH_COST 4 + +/* A C statement to update the variable COST based on the relationship + between INSN that is dependent on DEP through dependence LINK. */ +#define ADJUST_COST(INSN,LINK,DEP,COST) \ + (COST) = arm_adjust_cost ((INSN), (LINK), (DEP), (COST)) + +/* Position Independent Code. */ +/* We decide which register to use based on the compilation options and + the assembler in use; this is more general than the APCS restriction of + using sb (r9) all the time. */ +extern int arm_pic_register; + +/* The register number of the register used to address a table of static + data addresses in memory. */ +#define PIC_OFFSET_TABLE_REGNUM arm_pic_register + +#define FINALIZE_PIC arm_finalize_pic () + +#define LEGITIMATE_PIC_OPERAND_P(X) (! symbol_mentioned_p (X)) + + + +/* Condition code information. */ +/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, + return the mode to be used for the comparison. + CCFPEmode should be used with floating inequalities, + CCFPmode should be used with floating equalities. + CC_NOOVmode should be used with SImode integer equalities. + CC_Zmode should be used if only the Z flag is set correctly + CCmode should be used otherwise. */ + +#define EXTRA_CC_MODES CC_NOOVmode, CC_Zmode, CC_SWPmode, \ + CCFPmode, CCFPEmode, CC_DNEmode, CC_DEQmode, CC_DLEmode, \ + CC_DLTmode, CC_DGEmode, CC_DGTmode, CC_DLEUmode, CC_DLTUmode, \ + CC_DGEUmode, CC_DGTUmode, CC_Cmode + +#define EXTRA_CC_NAMES "CC_NOOV", "CC_Z", "CC_SWP", "CCFP", "CCFPE", \ + "CC_DNE", "CC_DEQ", "CC_DLE", "CC_DLT", "CC_DGE", "CC_DGT", "CC_DLEU", \ + "CC_DLTU", "CC_DGEU", "CC_DGTU", "CC_C" + +enum machine_mode arm_select_cc_mode (); +#define SELECT_CC_MODE(OP,X,Y) arm_select_cc_mode ((OP), (X), (Y)) + +#define REVERSIBLE_CC_MODE(MODE) ((MODE) != CCFPEmode) + +enum rtx_code arm_canonicalize_comparison (); +#define CANONICALIZE_COMPARISON(CODE,OP0,OP1) \ +do \ +{ \ + if (GET_CODE (OP1) == CONST_INT \ + && ! (const_ok_for_arm (INTVAL (OP1)) \ + || (const_ok_for_arm (- INTVAL (OP1))))) \ + { \ + rtx const_op = OP1; \ + CODE = arm_canonicalize_comparison ((CODE), &const_op); \ + OP1 = const_op; \ + } \ +} while (0) + +#define STORE_FLAG_VALUE 1 + +/* Define the information needed to generate branch insns. This is + stored from the compare operation. Note that we can't use "rtx" here + since it hasn't been defined! */ + +extern struct rtx_def *arm_compare_op0, *arm_compare_op1; +extern int arm_compare_fp; + +/* Define the codes that are matched by predicates in arm.c */ +#define PREDICATE_CODES \ + {"s_register_operand", {SUBREG, REG}}, \ + {"f_register_operand", {SUBREG, REG}}, \ + {"arm_add_operand", {SUBREG, REG, CONST_INT}}, \ + {"fpu_add_operand", {SUBREG, REG, CONST_DOUBLE}}, \ + {"arm_rhs_operand", {SUBREG, REG, CONST_INT}}, \ + {"fpu_rhs_operand", {SUBREG, REG, CONST_DOUBLE}}, \ + {"arm_not_operand", {SUBREG, REG, CONST_INT}}, \ + {"offsettable_memory_operand", {MEM}}, \ + {"bad_signed_byte_operand", {MEM}}, \ + {"alignable_memory_operand", {MEM}}, \ + {"shiftable_operator", {PLUS, MINUS, AND, IOR, XOR}}, \ + {"minmax_operator", {SMIN, SMAX, UMIN, UMAX}}, \ + {"shift_operator", {ASHIFT, ASHIFTRT, LSHIFTRT, ROTATERT, MULT}}, \ + {"di_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE, MEM}}, \ + {"soft_df_operand", {SUBREG, REG, CONST_DOUBLE, MEM}}, \ + {"load_multiple_operation", {PARALLEL}}, \ + {"store_multiple_operation", {PARALLEL}}, \ + {"equality_operator", {EQ, NE}}, \ + {"arm_rhsm_operand", {SUBREG, REG, CONST_INT, MEM}}, \ + {"const_shift_operand", {CONST_INT}}, \ + {"index_operand", {SUBREG, REG, CONST_INT}}, \ + {"reg_or_int_operand", {SUBREG, REG, CONST_INT}}, \ + {"multi_register_push", {PARALLEL}}, \ + {"cc_register", {REG}}, \ + {"dominant_cc_register", {REG}}, + + + +/* Gcc puts the pool in the wrong place for ARM, since we can only + load addresses a limited distance around the pc. We do some + special munging to move the constant pool values to the correct + point in the code. */ +#define MACHINE_DEPENDENT_REORG(INSN) arm_reorg ((INSN)) + +/* The pool is empty, since we have moved everything into the code. */ +#define ASM_OUTPUT_SPECIAL_POOL_ENTRY(FILE,X,MODE,ALIGN,LABELNO,JUMPTO) \ + goto JUMPTO + +/* Output an internal label definition. */ +#ifndef ASM_OUTPUT_INTERNAL_LABEL +#define ASM_OUTPUT_INTERNAL_LABEL(STREAM, PREFIX, NUM) \ + do \ + { \ + char * s = (char *) alloca (40 + strlen (PREFIX)); \ + extern int arm_target_label, arm_ccfsm_state; \ + extern rtx arm_target_insn; \ + \ + if (arm_ccfsm_state == 3 && arm_target_label == (NUM) \ + && !strcmp (PREFIX, "L")) \ + { \ + arm_ccfsm_state = 0; \ + arm_target_insn = NULL; \ + } \ + ASM_GENERATE_INTERNAL_LABEL (s, (PREFIX), (NUM)); \ + /* CYGNUS LOCAL variation */ \ + arm_asm_output_label (STREAM, s); \ + /* END CYGNUS LOCAL variation */ \ + } while (0) +#endif + +/* CYGNUS LOCAL */ +/* Output a label definition. */ +#undef ASM_OUTPUT_LABEL +#define ASM_OUTPUT_LABEL(STREAM,NAME) arm_asm_output_label ((STREAM), (NAME)) +/* END CYGNUS LOCAL */ + +/* Output a push or a pop instruction (only used when profiling). */ +#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ + fprintf (STREAM,"\tstmfd\t%ssp!,{%s%s}\n", \ + REGISTER_PREFIX, REGISTER_PREFIX, reg_names [REGNO]) + +#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \ + fprintf (STREAM,"\tldmfd\t%ssp!,{%s%s}\n", \ + REGISTER_PREFIX, REGISTER_PREFIX, reg_names [REGNO]) + +/* Target characters. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* Only perform branch elimination (by making instructions conditional) if + we're optimising. Otherwise it's of no use anyway. */ +#define FINAL_PRESCAN_INSN(INSN, OPVEC, NOPERANDS) \ + if (optimize) \ + final_prescan_insn (INSN, OPVEC, NOPERANDS) + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '?' || (CODE) == '|' || (CODE) == '@') +/* Output an operand of an instruction. */ +#define PRINT_OPERAND(STREAM, X, CODE) \ + arm_print_operand (STREAM, X, CODE) + +#define ARM_SIGN_EXTEND(x) ((HOST_WIDE_INT) \ + (HOST_BITS_PER_WIDE_INT <= 32 ? (x) \ + : (((x) & (unsigned HOST_WIDE_INT) 0xffffffff) | \ + (((x) & (unsigned HOST_WIDE_INT) 0x80000000) \ + ? ((~ (HOST_WIDE_INT) 0) \ + & ~ (unsigned HOST_WIDE_INT) 0xffffffff) \ + : 0)))) + +/* Output the address of an operand. */ +#define PRINT_OPERAND_ADDRESS(STREAM,X) \ +{ \ + int is_minus = GET_CODE (X) == MINUS; \ + \ + if (GET_CODE (X) == REG) \ + fprintf (STREAM, "[%s%s, #0]", REGISTER_PREFIX, \ + reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == PLUS || is_minus) \ + { \ + rtx base = XEXP (X, 0); \ + rtx index = XEXP (X, 1); \ + char * base_reg_name; \ + HOST_WIDE_INT offset = 0; \ + if (GET_CODE (base) != REG) \ + { \ + /* Ensure that BASE is a register (one of them must be). */ \ + rtx temp = base; \ + base = index; \ + index = temp; \ + } \ + base_reg_name = reg_names[REGNO (base)]; \ + switch (GET_CODE (index)) \ + { \ + case CONST_INT: \ + offset = INTVAL (index); \ + if (is_minus) \ + offset = -offset; \ + fprintf (STREAM, "[%s%s, #%d]", REGISTER_PREFIX, \ + base_reg_name, offset); \ + break; \ + \ + case REG: \ + fprintf (STREAM, "[%s%s, %s%s%s]", REGISTER_PREFIX, \ + base_reg_name, is_minus ? "-" : "", \ + REGISTER_PREFIX, reg_names[REGNO (index)] ); \ + break; \ + \ + case MULT: \ + case ASHIFTRT: \ + case LSHIFTRT: \ + case ASHIFT: \ + case ROTATERT: \ + { \ + fprintf (STREAM, "[%s%s, %s%s%s", REGISTER_PREFIX, \ + base_reg_name, is_minus ? "-" : "", REGISTER_PREFIX,\ + reg_names[REGNO (XEXP (index, 0))]); \ + arm_print_operand (STREAM, index, 'S'); \ + fputs ("]", STREAM); \ + break; \ + } \ + \ + default: \ + abort(); \ + } \ + } \ + else if (GET_CODE (X) == PRE_INC || GET_CODE (X) == POST_INC \ + || GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_DEC) \ + { \ + extern int output_memory_reference_mode; \ + \ + if (GET_CODE (XEXP (X, 0)) != REG) \ + abort (); \ + \ + if (GET_CODE (X) == PRE_DEC || GET_CODE (X) == PRE_INC) \ + fprintf (STREAM, "[%s%s, #%s%d]!", REGISTER_PREFIX, \ + reg_names[REGNO (XEXP (X, 0))], \ + GET_CODE (X) == PRE_DEC ? "-" : "", \ + GET_MODE_SIZE (output_memory_reference_mode)); \ + else \ + fprintf (STREAM, "[%s%s], #%s%d", REGISTER_PREFIX, \ + reg_names[REGNO (XEXP (X, 0))], \ + GET_CODE (X) == POST_DEC ? "-" : "", \ + GET_MODE_SIZE (output_memory_reference_mode)); \ + } \ + else output_addr_const(STREAM, X); \ +} + +/* Handles PIC addr specially */ +#define OUTPUT_INT_ADDR_CONST(STREAM,X) \ + { \ + if (flag_pic && GET_CODE(X) == CONST && is_pic(X)) \ + { \ + output_addr_const(STREAM, XEXP (XEXP (XEXP (X, 0), 0), 0)); \ + fputs(" - (", STREAM); \ + output_addr_const(STREAM, XEXP (XEXP (XEXP (X, 0), 1), 0)); \ + fputs(")", STREAM); \ + } \ + else output_addr_const(STREAM, X); \ + } + +/* Output code to add DELTA to the first argument, and then jump to FUNCTION. + Used for C++ multiple inheritance. */ +#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ +do { \ + int mi_delta = (DELTA); \ + char *mi_op = mi_delta < 0 ? "sub" : "add"; \ + int shift = 0; \ + int this_regno = (aggregate_value_p (TREE_TYPE (TREE_TYPE (FUNCTION))) \ + ? 1 : 0); \ + if (mi_delta < 0) mi_delta = -mi_delta; \ + while (mi_delta != 0) \ + { \ + if (mi_delta & (3 << shift) == 0) \ + shift += 2; \ + else \ + { \ + fprintf (FILE, "\t%s\t%s%s, %s%s, #%d\n", \ + mi_op, REGISTER_PREFIX, reg_names[this_regno], \ + REGISTER_PREFIX, reg_names[this_regno], \ + mi_delta & (0xff << shift)); \ + /* CYGNUS LOCAL */ \ + arm_increase_location (4); \ + /* END CYGNUS LOCAL */ \ + mi_delta &= ~(0xff << shift); \ + shift += 8; \ + } \ + } \ + fputs ("\tb\t", FILE); \ + assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ + fputc ('\n', FILE); \ + /* CYGNUS LOCAL */ \ + arm_increase_location (4); \ + /* END CYGNUS LOCAL */ \ +} while (0) + +/* A C expression whose value is RTL representing the value of the return + address for the frame COUNT steps up from the current frame. */ + +#define RETURN_ADDR_RTX(COUNT, FRAME) \ + ((COUNT == 0) \ + ? gen_rtx (MEM, Pmode, plus_constant (FRAME, -4)) \ + : NULL_RTX) + +/* Used to mask out junk bits from the return address, such as + processor state, interrupt status, condition codes and the like. */ +#define MASK_RETURN_ADDR \ + /* If we are generating code for an ARM2/ARM3 machine or for an ARM6 \ + in 26 bit mode, the condition codes must be masked out of the \ + return address. This does not apply to ARM6 and later processors \ + when running in 32 bit mode. */ \ + ((!TARGET_APCS_32) ? (GEN_INT (0x03fffffc)) : (GEN_INT (0xffffffff))) + +/* Prototypes for arm.c -- actually, they aren't since the types aren't + fully defined yet. */ + +char *arm_strip_name_encoding (/* const char * */); +int arm_is_longcall_p (/* rtx, int, int */); + +void arm_override_options (/* void */); +int use_return_insn (/* void */); +int const_ok_for_arm (/* HOST_WIDE_INT */); +int const_ok_for_op (/* HOST_WIDE_INT, enum rtx_code, + enum machine_mode */); +int arm_split_constant (/* enum rtx_code, enum machine_mode, + HOST_WIDE_INT, struct rtx_def *, + struct rtx_def *, int */); +enum rtx_code arm_canonicalize_comparison (/* enum rtx_code, + struct rtx_def ** */); +int arm_return_in_memory (/* union tree_node * */); +int legitimate_pic_operand_p (/* struct rtx_def * */); +struct rtx_def *legitimize_pic_address (/* struct rtx_def *, + enum machine_mode, + struct rtx_def * */); +int is_pic (/* struct rtx_def * */); +void arm_finalize_pic (/* void */); +int arm_rtx_costs (/* struct rtx_def *, enum rtx_code, enum rtx_code */); +int arm_adjust_cost (/* struct rtx_def *, struct rtx_def *, + struct rtx_def *, int */); +int const_double_rtx_ok_for_fpu (/* struct rtx_def * */); +int neg_const_double_rtx_ok_for_fpu (/* struct rtx_def * */); +int s_register_operand (/* struct rtx_def *, enum machine_mode */); +int f_register_operand (/* struct rtx_def *, enum machine_mode */); +int reg_or_int_operand (/* struct rtx_def *, enum machine_mode */); +int reload_memory_operand (/* struct rtx_def *, enum machine_mode */); +int arm_rhs_operand (/* struct rtx_def *, enum machine_mode */); +int arm_rhsm_operand (/* struct rtx_def *, enum machine_mode */); +int arm_add_operand (/* struct rtx_def *, enum machine_mode */); +int arm_not_operand (/* struct rtx_def *, enum machine_mode */); +int offsettable_memory_operand (/* struct rtx_def *, enum machine_mode */); +int alignable_memory_operand (/* struct rtx_def *, enum machine_mode */); +int bad_signed_byte_operand (/* struct rtx_def *, enum machine_mode */); +int fpu_rhs_operand (/* struct rtx_def *, enum machine_mode */); +int fpu_add_operand (/* struct rtx_def *, enum machine_mode */); +int power_of_two_operand (/* struct rtx_def *, enum machine_mode */); +int di_operand (/* struct rtx_def *, enum machine_mode */); +int soft_df_operand (/* struct rtx_def *, enum machine_mode */); +int index_operand (/* struct rtx_def *, enum machine_mode */); +int const_shift_operand (/* struct rtx_def *, enum machine_mode */); +int shiftable_operator (/* struct rtx_def *, enum machine_mode */); +int shift_operator (/* struct rtx_def *, enum machine_mode */); +int equality_operator (/* struct rtx_def *, enum machine_mode */); +int minmax_operator (/* struct rtx_def *, enum machine_mode */); +int cc_register (/* struct rtx_def *, enum machine_mode */); +int dominant_cc_register (/* struct rtx_def *, enum machine_mode */); +int symbol_mentioned_p (/* struct rtx_def * */); +int label_mentioned_p (/* struct rtx_def * */); +enum rtx_code minmax_code (/* struct rtx_def * */); +int adjacent_mem_locations (/* struct rtx_def *, struct rtx_def * */); +int load_multiple_operation (/* struct rtx_def *, enum machine_mode */); +int store_multiple_operation (/* struct rtx_def *, enum machine_mode */); +int load_multiple_sequence (/* struct rtx_def **, int, int *, int *, + HOST_WIDE_INT * */); +char *emit_ldm_seq (/* struct rtx_def **, int */); +int store_multiple_sequence (/* struct rtx_def **, int, int *, int *, + HOST_WIDE_INT * */); +char *emit_stm_seq (/* struct rtx_def **, int */); +int multi_register_push (/* struct rtx_def *, enum machine_mode */); +int arm_valid_machine_decl_attribute (/* union tree_node *, union tree_node *, + union tree_node *, + union tree_node * */); +struct rtx_def *arm_gen_load_multiple (/* int, int, struct rtx_def *, + int, int, int, int, int */); +struct rtx_def *arm_gen_store_multiple (/* int, int, struct rtx_def *, + int, int, int, int, int */); +int arm_gen_movstrqi (/* struct rtx_def ** */); +struct rtx_def *gen_rotated_half_load (/* struct rtx_def * */); +enum machine_mode arm_select_cc_mode (/* enum rtx_code, struct rtx_def *, + struct rtx_def * */); +struct rtx_def *gen_compare_reg (/* enum rtx_code, struct rtx_def *, + struct rtx_def * */); +void arm_reload_in_hi (/* struct rtx_def ** */); +void arm_reload_out_hi (/* struct rtx_def ** */); +void arm_reorg (/* struct rtx_def * */); +char *fp_immediate_constant (/* struct rtx_def * */); +void print_multi_reg (/* FILE *, char *, int, int */); +char *output_call (/* struct rtx_def ** */); +char *output_call_mem (/* struct rtx_def ** */); +char *output_mov_long_double_fpu_from_arm (/* struct rtx_def ** */); +char *output_mov_long_double_arm_from_fpu (/* struct rtx_def ** */); +char *output_mov_long_double_arm_from_arm (/* struct rtx_def ** */); +char *output_mov_double_fpu_from_arm (/* struct rtx_def ** */); +char *output_mov_double_arm_from_fpu (/* struct rtx_def ** */); +char *output_move_double (/* struct rtx_def ** */); +char *output_mov_immediate (/* struct rtx_def ** */); +char *output_add_immediate (/* struct rtx_def ** */); +char *arithmetic_instr (/* struct rtx_def *, int */); +void output_ascii_pseudo_op (/* FILE *, unsigned char *, int */); +char *output_return_instruction (/* struct rtx_def *, int, int */); +int arm_volatile_func (/* void */); +void output_func_prologue (/* FILE *, int */); +void output_func_epilogue (/* FILE *, int */); +void arm_expand_prologue (/* void */); +void arm_print_operand (/* FILE *, struct rtx_def *, int */); +void final_prescan_insn (/* struct rtx_def *, struct rtx_def **, int */); +#ifdef AOF_ASSEMBLER +struct rtx_def *aof_pic_entry (/* struct rtx_def * */); +void aof_dump_pic_table (/* FILE * */); +char *aof_text_section (/* void */); +char *aof_data_section (/* void */); +void aof_add_import (/* char * */); +void aof_delete_import (/* char * */); +void aof_dump_imports (/* FILE * */); +#endif +/* CYGNUS LOCAL nickc */ +int ok_integer_or_other (); +/* END CYGNUS LOCAL */ +int s_register_operand (/* register rtx op, enum machine_mode mode */); + +#endif /* __ARM_H__ */ diff --git a/gcc_arm/config/arm/arm_020422.md b/gcc_arm/config/arm/arm_020422.md new file mode 100755 index 0000000..c8f974f --- /dev/null +++ b/gcc_arm/config/arm/arm_020422.md @@ -0,0 +1,6508 @@ +;;- Machine description for Advanced RISC Machines' ARM for GNU compiler +;; Copyright (C) 1991, 93-98, 1999, 2002 Free Software Foundation, Inc. +;; Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl) +;; and Martin Simmons (@harleqn.co.uk). +;; More major hacks by Richard Earnshaw (rwe11@cl.cam.ac.uk) + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + +;; There are patterns in this file to support XFmode arithmetic. +;; Unfortunately RISC iX doesn't work well with these so they are disabled. +;; (See arm.h) + +;; UNSPEC Usage: +;; 0 `sin' operation: operand 0 is the result, operand 1 the parameter, +;; the mode is MODE_FLOAT +;; 1 `cos' operation: operand 0 is the result, operand 1 the parameter, +;; the mode is MODE_FLOAT +;; 2 `push multiple' operation: operand 0 is the first register. Subsequent +;; registers are in parallel (use...) expressions. +;; 3 A symbol that has been treated properly for pic usage, that is, we +;; will add the pic_register value to it before trying to dereference it. +;; Note: sin and cos are no-longer used. + +;; Attributes + +; PROG_MODE attribute is used to determine whether condition codes are +; clobbered by a call insn: they are if in prog32 mode. This is controlled +; by the -mapcs-{32,26} flag, and possibly the -mcpu=... option. +(define_attr "prog_mode" "prog26,prog32" (const (symbol_ref "arm_prog_mode"))) + +(define_attr "is_strongarm" "no,yes" (const (symbol_ref "arm_is_strong"))) + +; Floating Point Unit. If we only have floating point emulation, then there +; is no point in scheduling the floating point insns. (Well, for best +; performance we should try and group them together). + +(define_attr "fpu" "fpa,fpe2,fpe3" (const (symbol_ref "arm_fpu_attr"))) + +; LENGTH of an instruction (in bytes) +(define_attr "length" "" (const_int 4)) + +; An assembler sequence may clobber the condition codes without us knowing +(define_asm_attributes + [(set_attr "conds" "clob") + (set_attr "length" "4")]) + +; TYPE attribute is used to detect floating point instructions which, if +; running on a co-processor can run in parallel with other, basic instructions +; If write-buffer scheduling is enabled then it can also be used in the +; scheduling of writes. + +; Classification of each insn +; normal any data instruction that doesn't hit memory or fp regs +; mult a multiply instruction +; block blockage insn, this blocks all functional units +; float a floating point arithmetic operation (subject to expansion) +; fdivx XFmode floating point division +; fdivd DFmode floating point division +; fdivs SFmode floating point division +; fmul Floating point multiply +; ffmul Fast floating point multiply +; farith Floating point arithmetic (4 cycle) +; ffarith Fast floating point arithmetic (2 cycle) +; float_em a floating point arithmetic operation that is normally emulated +; even on a machine with an fpa. +; f_load a floating point load from memory +; f_store a floating point store to memory +; f_mem_r a transfer of a floating point register to a real reg via mem +; r_mem_f the reverse of f_mem_r +; f_2_r fast transfer float to arm (no memory needed) +; r_2_f fast transfer arm to float +; call a subroutine call +; load any load from memory +; store1 store 1 word to memory from arm registers +; store2 store 2 words +; store3 store 3 words +; store4 store 4 words +; +(define_attr "type" + "normal,mult,block,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith,float_em,f_load,f_store,f_mem_r,r_mem_f,f_2_r,r_2_f,call,load,store1,store2,store3,store4" + (const_string "normal")) + +;; CYGNUS LOCAL load scheduling +; Load scheduling, set from the arm_ld_sched variable +; initialised by arm_override_options() +(define_attr "ldsched" "no,yes" + (const (symbol_ref "arm_ld_sched"))) +;; END CYGNUS LOCAL + +; condition codes: this one is used by final_prescan_insn to speed up +; conditionalizing instructions. It saves having to scan the rtl to see if +; it uses or alters the condition codes. + +; USE means that the condition codes are used by the insn in the process of +; outputting code, this means (at present) that we can't use the insn in +; inlined branches + +; SET means that the purpose of the insn is to set the condition codes in a +; well defined manner. + +; CLOB means that the condition codes are altered in an undefined manner, if +; they are altered at all + +; JUMP_CLOB is used when the conditions are not defined if a branch is taken, +; but are if the branch wasn't taken; the effect is to limit the branch +; elimination scanning. + +; NOCOND means that the condition codes are neither altered nor affect the +; output of this insn + +(define_attr "conds" "use,set,clob,jump_clob,nocond" + (if_then_else (eq_attr "type" "call") + (if_then_else (eq_attr "prog_mode" "prog32") + (const_string "clob") (const_string "nocond")) + (const_string "nocond"))) + +; Only model the write buffer for ARM6 and ARM7. Earlier processors don't +; have one. Later ones, such as StrongARM, have write-back caches, so don't +; suffer blockages enough to warrent modelling this (and it can adversely +; affect the schedule). +(define_attr "model_wbuf" "no,yes" (const (symbol_ref "arm_is_6_or_7"))) + +(define_attr "write_conflict" "no,yes" + (if_then_else (eq_attr "type" + "block,float_em,f_load,f_store,f_mem_r,r_mem_f,call,load") + (const_string "yes") + (const_string "no"))) + +(define_attr "core_cycles" "single,multi" + (if_then_else (eq_attr "type" + "normal,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith") + (const_string "single") + (const_string "multi"))) + +; The write buffer on some of the arm6 processors is hard to model exactly. +; There is room in the buffer for up to two addresses and up to eight words +; of memory, but the two needn't be split evenly. When writing the two +; addresses are fully pipelined. However, a read from memory that is not +; currently in the cache will block until the writes have completed. +; It is normally the case that FCLK and MCLK will be in the ratio 2:1, so +; writes will take 2 FCLK cycles per word, if FCLK and MCLK are asynchronous +; (they aren't allowed to be at present) then there is a startup cost of 1MCLK +; cycle to add as well. + +;; (define_function_unit {name} {num-units} {n-users} {test} +;; {ready-delay} {issue-delay} [{conflict-list}]) +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "fdivx")) 71 69) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "fdivd")) 59 57) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "fdivs")) 31 29) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "fmul")) 9 7) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "ffmul")) 6 4) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "farith")) 4 2) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "ffarith")) 2 2) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "r_2_f")) 5 3) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "f_2_r")) 1 2) + +;; The fpa10 doesn't really have a memory read unit, but it can start to +;; speculatively execute the instruction in the pipeline, provided the data +;; is already loaded, so pretend reads have a delay of 2 (and that the +;; pipeline is infinite. + +(define_function_unit "fpa_mem" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "f_load")) 3 1) + +;;-------------------------------------------------------------------- +;; Write buffer +;;-------------------------------------------------------------------- +;; Strictly we should model a 4-deep write buffer for ARM7xx based chips +(define_function_unit "write_buf" 1 2 + (and (eq_attr "model_wbuf" "yes") + (eq_attr "type" "store1,r_mem_f")) 5 3) +(define_function_unit "write_buf" 1 2 + (and (eq_attr "model_wbuf" "yes") + (eq_attr "type" "store2")) 7 4) +(define_function_unit "write_buf" 1 2 + (and (eq_attr "model_wbuf" "yes") + (eq_attr "type" "store3")) 9 5) +(define_function_unit "write_buf" 1 2 + (and (eq_attr "model_wbuf" "yes") + (eq_attr "type" "store4")) 11 6) + +;;-------------------------------------------------------------------- +;; Write blockage unit +;;-------------------------------------------------------------------- +;; The write_blockage unit models (partially), the fact that reads will stall +;; until the write buffer empties. +;; The f_mem_r and r_mem_f could also block, but they are to the stack, +;; so we don't model them here +(define_function_unit "write_blockage" 1 0 (and (eq_attr "model_wbuf" "yes") + (eq_attr "type" "store1")) 5 5 + [(eq_attr "write_conflict" "yes")]) +(define_function_unit "write_blockage" 1 0 (and (eq_attr "model_wbuf" "yes") + (eq_attr "type" "store2")) 7 7 + [(eq_attr "write_conflict" "yes")]) +(define_function_unit "write_blockage" 1 0 (and (eq_attr "model_wbuf" "yes") + (eq_attr "type" "store3")) 9 9 + [(eq_attr "write_conflict" "yes")]) +(define_function_unit "write_blockage" 1 0 + (and (eq_attr "model_wbuf" "yes") (eq_attr "type" "store4")) 11 11 + [(eq_attr "write_conflict" "yes")]) +(define_function_unit "write_blockage" 1 0 + (and (eq_attr "model_wbuf" "yes") + (eq_attr "write_conflict" "yes")) 1 1) + +;;-------------------------------------------------------------------- +;; Core unit +;;-------------------------------------------------------------------- +;; Everything must spend at least one cycle in the core unit +(define_function_unit "core" 1 0 + (and (eq_attr "ldsched" "yes") (eq_attr "type" "store1")) 1 1) + +(define_function_unit "core" 1 0 + (and (eq_attr "ldsched" "yes") (eq_attr "type" "load")) 2 1) + +(define_function_unit "core" 1 0 + (and (eq_attr "ldsched" "!yes") (eq_attr "type" "load,store1")) 2 2) + +(define_function_unit "core" 1 0 + (and (eq_attr "fpu" "fpa") (eq_attr "type" "f_load")) 3 3) + +(define_function_unit "core" 1 0 + (and (eq_attr "fpu" "fpa") (eq_attr "type" "f_store")) 4 4) + +(define_function_unit "core" 1 0 + (and (eq_attr "fpu" "fpa") (eq_attr "type" "r_mem_f")) 6 6) + +(define_function_unit "core" 1 0 + (and (eq_attr "fpu" "fpa") (eq_attr "type" "f_mem_r")) 7 7) + +(define_function_unit "core" 1 0 + (and (eq_attr "ldsched" "no") (eq_attr "type" "mult")) 16 16) + +(define_function_unit "core" 1 0 + (and (and (eq_attr "ldsched" "yes") (eq_attr "is_strongarm" "no")) + (eq_attr "type" "mult")) 4 4) + +(define_function_unit "core" 1 0 + (and (and (eq_attr "ldsched" "yes") (eq_attr "is_strongarm" "yes")) + (eq_attr "type" "mult")) 3 2) + +(define_function_unit "core" 1 0 (eq_attr "type" "store2") 3 3) + +(define_function_unit "core" 1 0 (eq_attr "type" "store3") 4 4) + +(define_function_unit "core" 1 0 (eq_attr "type" "store4") 5 5) + +;; CYGNUS LOCAL +;; APCS support: When generating code for the software stack checking +;; model, we need to be able to perform calls to the special exception +;; handler routines. These routines are *NOT* APCS conforming, so we +;; do not need to mark any registers as clobbered over the call other +;; than the lr/r14 modified by the actual BL instruction. Rather than +;; trying to force the RTL for the existing comparison and call to +;; achieve this, we simply have a pattern that does the desired job. + +;; TODO: This is not ideal since it does not specify all of the +;; operators involved: +;; cmp %op0,%op1 cmpsi_insn (compare) +;; bl%op3 %op2 call_value_symbol (call) +;; Unfortunately since we do not go through the normal arm_ccfsm_state +;; processing we cannot use the %? operand replacment for the BL +;; condition. + +(define_insn "cond_call" + [(compare:CC (match_operand:SI 0 "s_register_operand" "r") + (match_operand:SI 1 "s_register_operand" "r")) + (match_operand:SI 2 "" "X") + (match_operator 3 "comparison_operator" [(reg:CC 24) (const_int 0)]) + (clobber (reg:CC 24)) + (clobber (reg:SI 14))] + "GET_CODE (operands[2]) == SYMBOL_REF && GET_CODE (operands[3]) == LTU" + "cmp\\t%0, %1\;bllt\\t%a2" +[(set_attr "conds" "clob") + (set_attr "type" "call") + (set_attr "length" "8")]) + +;; END CYGNUS LOCAL + +;; Note: For DImode insns, there is normally no reason why operands should +;; not be in the same register, what we don't want is for something being +;; written to partially overlap something that is an input. + +;; Addition insns. + +(define_insn "adddi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (plus:DI (match_operand:DI 1 "s_register_operand" "%0,0") + (match_operand:DI 2 "s_register_operand" "r,0"))) + (clobber (reg:CC 24))] + "" + "adds\\t%Q0, %Q1, %Q2\;adc\\t%R0, %R1, %R2" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*adddi_sesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (plus:DI (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "r,0"))) + (clobber (reg:CC 24))] + "" + "adds\\t%Q0, %Q1, %2\;adc\\t%R0, %R1, %2, asr #31" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*adddi_zesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (plus:DI (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "r,0"))) + (clobber (reg:CC 24))] + "" + "adds\\t%Q0, %Q1, %2\;adc\\t%R0, %R1, #0" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_expand "addsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (plus:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "reg_or_int_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT) + { + arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0], + operands[1], + (reload_in_progress || reload_completed ? 0 + : preserve_subexpressions_p ())); + DONE; + } +") + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (plus:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "const_int_operand" "")))] + "! (const_ok_for_arm (INTVAL (operands[2])) + || const_ok_for_arm (-INTVAL (operands[2])))" + [(clobber (const_int 0))] + " + arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0], + operands[1], 0); + DONE; +") + +(define_insn "*addsi3_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (plus:SI (match_operand:SI 1 "s_register_operand" "r,r,r") + (match_operand:SI 2 "reg_or_int_operand" "rI,L,?n")))] + "" + "@ + add%?\\t%0, %1, %2 + sub%?\\t%0, %1, #%n2 + #" +[(set_attr "length" "4,4,16")]) + +(define_insn "*addsi3_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (plus:SI (match_operand:SI 1 "s_register_operand" "r,r") + (match_operand:SI 2 "arm_add_operand" "rI,L")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") + (plus:SI (match_dup 1) (match_dup 2)))] + "" + "@ + add%?s\\t%0, %1, %2 + sub%?s\\t%0, %1, #%n2" +[(set_attr "conds" "set")]) + +(define_insn "*addsi3_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (plus:SI (match_operand:SI 0 "s_register_operand" "r,r") + (match_operand:SI 1 "arm_add_operand" "rI,L")) + (const_int 0)))] + "" + "@ + cmn%?\\t%0, %1 + cmp%?\\t%0, #%n1" +[(set_attr "conds" "set")]) + +;; The next four insns work because they compare the result with one of +;; the operands, and we know that the use of the condition code is +;; either GEU or LTU, so we can use the carry flag from the addition +;; instead of doing the compare a second time. +(define_insn "*addsi3_compare_op1" + [(set (reg:CC_C 24) + (compare:CC_C + (plus:SI (match_operand:SI 1 "s_register_operand" "r,r") + (match_operand:SI 2 "arm_add_operand" "rI,L")) + (match_dup 1))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") + (plus:SI (match_dup 1) (match_dup 2)))] + "" + "@ + add%?s\\t%0, %1, %2 + sub%?s\\t%0, %1, #%n2" +[(set_attr "conds" "set")]) + +(define_insn "*addsi3_compare_op2" + [(set (reg:CC_C 24) + (compare:CC_C + (plus:SI (match_operand:SI 1 "s_register_operand" "r,r") + (match_operand:SI 2 "arm_add_operand" "rI,L")) + (match_dup 2))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") + (plus:SI (match_dup 1) (match_dup 2)))] + "" + "@ + add%?s\\t%0, %1, %2 + sub%?s\\t%0, %1, #%n2" +[(set_attr "conds" "set")]) + +(define_insn "*compare_addsi2_op0" + [(set (reg:CC_C 24) + (compare:CC_C + (plus:SI (match_operand:SI 0 "s_register_operand" "r,r") + (match_operand:SI 1 "arm_add_operand" "rI,L")) + (match_dup 0)))] + "" + "@ + cmn%?\\t%0, %1 + cmp%?\\t%0, #%n1" +[(set_attr "conds" "set")]) + +(define_insn "*compare_addsi2_op1" + [(set (reg:CC_C 24) + (compare:CC_C + (plus:SI (match_operand:SI 0 "s_register_operand" "r,r") + (match_operand:SI 1 "arm_add_operand" "rI,L")) + (match_dup 1)))] + "" + "@ + cmn%?\\t%0, %1 + cmp%?\\t%0, #%n1" +[(set_attr "conds" "set")]) + +(define_insn "*addsi3_carryin" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (ltu:SI (reg:CC_C 24) (const_int 0)) + (plus:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rI"))))] + "" + "adc%?\\t%0, %1, %2" +[(set_attr "conds" "use")]) + +(define_insn "*addsi3_carryin_alt1" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (plus:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rI")) + (ltu:SI (reg:CC_C 24) (const_int 0))))] + "" + "adc%?\\t%0, %1, %2" +[(set_attr "conds" "use")]) + +(define_insn "*addsi3_carryin_alt2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (plus:SI (ltu:SI (reg:CC_C 24) (const_int 0)) + (match_operand:SI 1 "s_register_operand" "r")) + (match_operand:SI 2 "arm_rhs_operand" "rI")))] + "" + "adc%?\\t%0, %1, %2" +[(set_attr "conds" "use")]) + +(define_insn "*addsi3_carryin_alt3" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (plus:SI (ltu:SI (reg:CC_C 24) (const_int 0)) + (match_operand:SI 2 "arm_rhs_operand" "rI")) + (match_operand:SI 1 "s_register_operand" "r")))] + "" + "adc%?\\t%0, %1, %2" +[(set_attr "conds" "use")]) + +(define_insn "incscc" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (plus:SI (match_operator:SI 2 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "s_register_operand" "0,?r")))] + "" + "@ + add%d2\\t%0, %1, #1 + mov%D2\\t%0, %1\;add%d2\\t%0, %1, #1" +[(set_attr "conds" "use") + (set_attr "length" "4,8")]) + +; If a constant is too big to fit in a single instruction then the constant +; will be pre-loaded into a register taking at least two insns, we might be +; able to merge it with an add, but it depends on the exact value. + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "const_int_operand" "n")))] + "!(const_ok_for_arm (INTVAL (operands[2])) + || const_ok_for_arm (-INTVAL (operands[2])))" + [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2))) + (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 3)))] + " +{ + unsigned int val = (unsigned) INTVAL (operands[2]); + int i; + unsigned int temp; + + /* this code is similar to the approach followed in movsi, but it must + generate exactly two insns */ + + for (i = 30; i >= 0; i -= 2) + { + if (val & (3 << i)) + { + i -= 6; + if (i < 0) i = 0; + if (const_ok_for_arm (temp = (val & ~(255 << i)))) + { + val &= 255 << i; + break; + } + /* we might be able to do this as (larger number - small number) */ + temp = ((val >> i) & 255) + 1; + if (temp > 255 && i < 24) + { + i += 2; + temp = ((val >> i) & 255) + 1; + } + if (const_ok_for_arm ((temp << i) - val)) + { + i = temp << i; + temp = (unsigned) - (int) (i - val); + val = i; + break; + } + FAIL; + } + } + /* if we got here, we have found a way of doing it in two instructions. + the two constants are in val and temp */ + operands[2] = GEN_INT ((int)val); + operands[3] = GEN_INT ((int)temp); +} +") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "s_register_operand" "=f,f") + (plus:SF (match_operand:SF 1 "s_register_operand" "f,f") + (match_operand:SF 2 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + adf%?s\\t%0, %1, %2 + suf%?s\\t%0, %1, #%N2" +[(set_attr "type" "farith")]) + +(define_insn "adddf3" + [(set (match_operand:DF 0 "s_register_operand" "=f,f") + (plus:DF (match_operand:DF 1 "s_register_operand" "f,f") + (match_operand:DF 2 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + adf%?d\\t%0, %1, %2 + suf%?d\\t%0, %1, #%N2" +[(set_attr "type" "farith")]) + +(define_insn "*adddf_df_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f,f") + (plus:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f,f")) + (match_operand:DF 2 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + adf%?d\\t%0, %1, %2 + suf%?d\\t%0, %1, #%N2" +[(set_attr "type" "farith")]) + +(define_insn "*adddf_df_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (plus:DF (match_operand:DF 1 "s_register_operand" "f") + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "adf%?d\\t%0, %1, %2" +[(set_attr "type" "farith")]) + +(define_insn "*adddf_esfdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (plus:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "adf%?d\\t%0, %1, %2" +[(set_attr "type" "farith")]) + +(define_insn "addxf3" + [(set (match_operand:XF 0 "s_register_operand" "=f,f") + (plus:XF (match_operand:XF 1 "s_register_operand" "f,f") + (match_operand:XF 2 "fpu_add_operand" "fG,H")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "@ + adf%?e\\t%0, %1, %2 + suf%?e\\t%0, %1, #%N2" +[(set_attr "type" "farith")]) + +(define_insn "subdi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r,&r") + (minus:DI (match_operand:DI 1 "s_register_operand" "0,r,0") + (match_operand:DI 2 "s_register_operand" "r,0,0"))) + (clobber (reg:CC 24))] + "" + "subs\\t%Q0, %Q1, %Q2\;sbc\\t%R0, %R1, %R2" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*subdi_di_zesidi" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (minus:DI (match_operand:DI 1 "s_register_operand" "?r,0") + (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")))) + (clobber (reg:CC 24))] + "" + "subs\\t%Q0, %Q1, %2\;sbc\\t%R0, %R1, #0" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*subdi_di_sesidi" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (minus:DI (match_operand:DI 1 "s_register_operand" "r,0") + (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")))) + (clobber (reg:CC 24))] + "" + "subs\\t%Q0, %Q1, %2\;sbc\\t%R0, %R1, %2, asr #31" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*subdi_zesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (minus:DI (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "?r,0"))) + (clobber (reg:CC 24))] + "" + "rsbs\\t%Q0, %Q1, %2\;rsc\\t%R0, %R1, #0" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*subdi_sesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (minus:DI (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "?r,0"))) + (clobber (reg:CC 24))] + "" + "rsbs\\t%Q0, %Q1, %2\;rsc\\t%R0, %R1, %2, asr #31" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*subdi_zesidi_zesidi" + [(set (match_operand:DI 0 "s_register_operand" "=r") + (minus:DI (zero_extend:DI + (match_operand:SI 1 "s_register_operand" "r")) + (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r")))) + (clobber (reg:CC 24))] + "" + "subs\\t%Q0, %1, %2\;rsc\\t%R0, %1, %1" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_expand "subsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (minus:SI (match_operand:SI 1 "reg_or_int_operand" "") + (match_operand:SI 2 "s_register_operand" "")))] + "" + " + if (GET_CODE (operands[1]) == CONST_INT) + { + arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0], + operands[2], + (reload_in_progress || reload_completed ? 0 + : preserve_subexpressions_p ())); + DONE; + } +") + +(define_insn "*subsi3_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (minus:SI (match_operand:SI 1 "reg_or_int_operand" "rI,?n") + (match_operand:SI 2 "s_register_operand" "r,r")))] + "" + "@ + rsb%?\\t%0, %2, %1 + #" +[(set_attr "length" "4,16")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (minus:SI (match_operand:SI 1 "const_int_operand" "") + (match_operand:SI 2 "s_register_operand" "")))] + "! const_ok_for_arm (INTVAL (operands[1]))" + [(clobber (const_int 0))] + " + arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0], + operands[2], 0); + DONE; +") + +(define_insn "*subsi3_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (minus:SI (match_operand:SI 1 "arm_rhs_operand" "r,I") + (match_operand:SI 2 "arm_rhs_operand" "rI,r")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") + (minus:SI (match_dup 1) (match_dup 2)))] + "" + "@ + sub%?s\\t%0, %1, %2 + rsb%?s\\t%0, %2, %1" +[(set_attr "conds" "set")]) + +(define_insn "decscc" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (minus:SI (match_operand:SI 1 "s_register_operand" "0,?r") + (match_operator:SI 2 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)])))] + "" + "@ + sub%d2\\t%0, %1, #1 + mov%D2\\t%0, %1\;sub%d2\\t%0, %1, #1" +[(set_attr "conds" "use") + (set_attr "length" "*,8")]) + +(define_insn "subsf3" + [(set (match_operand:SF 0 "s_register_operand" "=f,f") + (minus:SF (match_operand:SF 1 "fpu_rhs_operand" "f,G") + (match_operand:SF 2 "fpu_rhs_operand" "fG,f")))] + "TARGET_HARD_FLOAT" + "@ + suf%?s\\t%0, %1, %2 + rsf%?s\\t%0, %2, %1" +[(set_attr "type" "farith")]) + +(define_insn "subdf3" + [(set (match_operand:DF 0 "s_register_operand" "=f,f") + (minus:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G") + (match_operand:DF 2 "fpu_rhs_operand" "fG,f")))] + "TARGET_HARD_FLOAT" + "@ + suf%?d\\t%0, %1, %2 + rsf%?d\\t%0, %2, %1" +[(set_attr "type" "farith")]) + +(define_insn "*subdf_esfdf_df" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (minus:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (match_operand:DF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "suf%?d\\t%0, %1, %2" +[(set_attr "type" "farith")]) + +(define_insn "*subdf_df_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f,f") + (minus:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G") + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f,f"))))] + "TARGET_HARD_FLOAT" + "@ + suf%?d\\t%0, %1, %2 + rsf%?d\\t%0, %2, %1" +[(set_attr "type" "farith")]) + +(define_insn "*subdf_esfdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (minus:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "suf%?d\\t%0, %1, %2" +[(set_attr "type" "farith")]) + +(define_insn "subxf3" + [(set (match_operand:XF 0 "s_register_operand" "=f,f") + (minus:XF (match_operand:XF 1 "fpu_rhs_operand" "f,G") + (match_operand:XF 2 "fpu_rhs_operand" "fG,f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "@ + suf%?e\\t%0, %1, %2 + rsf%?e\\t%0, %2, %1" +[(set_attr "type" "farith")]) + +;; Multiplication insns + +;; Use `&' and then `0' to prevent the operands 0 and 1 being the same +(define_insn "mulsi3" + [(set (match_operand:SI 0 "s_register_operand" "=&r,&r") + (mult:SI (match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 1 "s_register_operand" "%?r,0")))] + "" + "mul%?\\t%0, %2, %1" +[(set_attr "type" "mult")]) + +(define_insn "*mulsi3_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (mult:SI + (match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 1 "s_register_operand" "%?r,0")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=&r,&r") + (mult:SI (match_dup 2) (match_dup 1)))] + "" + "mul%?s\\t%0, %2, %1" +[(set_attr "conds" "set") + (set_attr "type" "mult")]) + +(define_insn "*mulsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (mult:SI + (match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 1 "s_register_operand" "%?r,0")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=&r,&r"))] + "" + "mul%?s\\t%0, %2, %1" +[(set_attr "conds" "set") + (set_attr "type" "mult")]) + +;; Unnamed templates to match MLA instruction. + +(define_insn "*mulsi3addsi" + [(set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r,&r") + (plus:SI + (mult:SI (match_operand:SI 2 "s_register_operand" "r,r,r,r") + (match_operand:SI 1 "s_register_operand" "%r,0,r,0")) + (match_operand:SI 3 "s_register_operand" "?r,r,0,0")))] + "" + "mla%?\\t%0, %2, %1, %3" +[(set_attr "type" "mult")]) + +(define_insn "*mulsi3addsi_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (plus:SI + (mult:SI + (match_operand:SI 2 "s_register_operand" "r,r,r,r") + (match_operand:SI 1 "s_register_operand" "%r,0,r,0")) + (match_operand:SI 3 "s_register_operand" "?r,r,0,0")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r,&r") + (plus:SI (mult:SI (match_dup 2) (match_dup 1)) + (match_dup 3)))] + "" + "mla%?s\\t%0, %2, %1, %3" +[(set_attr "conds" "set") + (set_attr "type" "mult")]) + +(define_insn "*mulsi3addsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (plus:SI + (mult:SI + (match_operand:SI 2 "s_register_operand" "r,r,r,r") + (match_operand:SI 1 "s_register_operand" "%r,0,r,0")) + (match_operand:SI 3 "s_register_operand" "?r,r,0,0")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=&r,&r,&r,&r"))] + "" + "mla%?s\\t%0, %2, %1, %3" +[(set_attr "conds" "set") + (set_attr "type" "mult")]) + +(define_insn "mulsidi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r") + (mult:DI (sign_extend:DI + (match_operand:SI 1 "s_register_operand" "%r")) + (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r"))))] + "arm_fast_multiply" + "smull%?\\t%Q0, %R0, %1, %2" +[(set_attr "type" "mult")]) + +(define_insn "umulsidi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r") + (mult:DI (zero_extend:DI + (match_operand:SI 1 "s_register_operand" "%r")) + (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r"))))] + "arm_fast_multiply" + "umull%?\\t%Q0, %R0, %1, %2" +[(set_attr "type" "mult")]) + +(define_insn "smulsi3_highpart" + [(set (match_operand:SI 0 "s_register_operand" "=&r,&r") + (truncate:SI + (lshiftrt:DI + (mult:DI (sign_extend:DI + (match_operand:SI 1 "s_register_operand" "%r,0")) + (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r"))) + (const_int 32)))) + (clobber (match_scratch:SI 3 "=&r,&r"))] + "arm_fast_multiply" + "smull%?\\t%3, %0, %2, %1" +[(set_attr "type" "mult")]) + +(define_insn "umulsi3_highpart" + [(set (match_operand:SI 0 "s_register_operand" "=&r,&r") + (truncate:SI + (lshiftrt:DI + (mult:DI (zero_extend:DI + (match_operand:SI 1 "s_register_operand" "%r,0")) + (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r"))) + (const_int 32)))) + (clobber (match_scratch:SI 3 "=&r,&r"))] + "arm_fast_multiply" + "umull%?\\t%3, %0, %2, %1" +[(set_attr "type" "mult")]) + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (mult:SF (match_operand:SF 1 "s_register_operand" "f") + (match_operand:SF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "fml%?s\\t%0, %1, %2" +[(set_attr "type" "ffmul")]) + +(define_insn "muldf3" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mult:DF (match_operand:DF 1 "s_register_operand" "f") + (match_operand:DF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "muf%?d\\t%0, %1, %2" +[(set_attr "type" "fmul")]) + +(define_insn "*muldf_esfdf_df" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mult:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (match_operand:DF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "muf%?d\\t%0, %1, %2" +[(set_attr "type" "fmul")]) + +(define_insn "*muldf_df_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mult:DF (match_operand:DF 1 "s_register_operand" "f") + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "muf%?d\\t%0, %1, %2" +[(set_attr "type" "fmul")]) + +(define_insn "*muldf_esfdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mult:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "muf%?d\\t%0, %1, %2" +[(set_attr "type" "fmul")]) + +(define_insn "mulxf3" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (mult:XF (match_operand:XF 1 "s_register_operand" "f") + (match_operand:XF 2 "fpu_rhs_operand" "fG")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "muf%?e\\t%0, %1, %2" +[(set_attr "type" "fmul")]) + +;; Division insns + +(define_insn "divsf3" + [(set (match_operand:SF 0 "s_register_operand" "=f,f") + (div:SF (match_operand:SF 1 "fpu_rhs_operand" "f,G") + (match_operand:SF 2 "fpu_rhs_operand" "fG,f")))] + "TARGET_HARD_FLOAT" + "@ + fdv%?s\\t%0, %1, %2 + frd%?s\\t%0, %2, %1" +[(set_attr "type" "fdivs")]) + +(define_insn "divdf3" + [(set (match_operand:DF 0 "s_register_operand" "=f,f") + (div:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G") + (match_operand:DF 2 "fpu_rhs_operand" "fG,f")))] + "TARGET_HARD_FLOAT" + "@ + dvf%?d\\t%0, %1, %2 + rdf%?d\\t%0, %2, %1" +[(set_attr "type" "fdivd")]) + +(define_insn "*divdf_esfdf_df" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (div:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (match_operand:DF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "dvf%?d\\t%0, %1, %2" +[(set_attr "type" "fdivd")]) + +(define_insn "*divdf_df_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (div:DF (match_operand:DF 1 "fpu_rhs_operand" "fG") + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "rdf%?d\\t%0, %2, %1" +[(set_attr "type" "fdivd")]) + +(define_insn "*divdf_esfdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (div:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "dvf%?d\\t%0, %1, %2" +[(set_attr "type" "fdivd")]) + +(define_insn "divxf3" + [(set (match_operand:XF 0 "s_register_operand" "=f,f") + (div:XF (match_operand:XF 1 "fpu_rhs_operand" "f,G") + (match_operand:XF 2 "fpu_rhs_operand" "fG,f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "@ + dvf%?e\\t%0, %1, %2 + rdf%?e\\t%0, %2, %1" +[(set_attr "type" "fdivx")]) + +;; Modulo insns + +(define_insn "modsf3" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (mod:SF (match_operand:SF 1 "s_register_operand" "f") + (match_operand:SF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "rmf%?s\\t%0, %1, %2" +[(set_attr "type" "fdivs")]) + +(define_insn "moddf3" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mod:DF (match_operand:DF 1 "s_register_operand" "f") + (match_operand:DF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "rmf%?d\\t%0, %1, %2" +[(set_attr "type" "fdivd")]) + +(define_insn "*moddf_esfdf_df" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mod:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (match_operand:DF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "rmf%?d\\t%0, %1, %2" +[(set_attr "type" "fdivd")]) + +(define_insn "*moddf_df_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mod:DF (match_operand:DF 1 "s_register_operand" "f") + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "rmf%?d\\t%0, %1, %2" +[(set_attr "type" "fdivd")]) + +(define_insn "*moddf_esfdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mod:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "rmf%?d\\t%0, %1, %2" +[(set_attr "type" "fdivd")]) + +(define_insn "modxf3" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (mod:XF (match_operand:XF 1 "s_register_operand" "f") + (match_operand:XF 2 "fpu_rhs_operand" "fG")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "rmf%?e\\t%0, %1, %2" +[(set_attr "type" "fdivx")]) + +;; Boolean and,ior,xor insns + +(define_insn "anddi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (and:DI (match_operand:DI 1 "s_register_operand" "%0,0") + (match_operand:DI 2 "s_register_operand" "r,0")))] + "" + "and%?\\t%Q0, %Q1, %Q2\;and%?\\t%R0, %R1, %R2" +[(set_attr "length" "8")]) + +(define_insn "*anddi_zesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (and:DI (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "?r,0")))] + "" + "and%?\\t%Q0, %Q1, %2\;mov%?\\t%R0, #0" +[(set_attr "length" "8")]) + +(define_insn "*anddi_sesdi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (and:DI (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "?r,0")))] + "" + "and%?\\t%Q0, %Q1, %2\;and%?\\t%R0, %R1, %2, asr #31" +[(set_attr "length" "8")]) + +(define_expand "andsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (and:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "reg_or_int_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT) + { + arm_split_constant (AND, SImode, INTVAL (operands[2]), operands[0], + operands[1], + (reload_in_progress || reload_completed + ? 0 : preserve_subexpressions_p ())); + DONE; + } +") + +(define_insn "*andsi3_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (and:SI (match_operand:SI 1 "s_register_operand" "r,r,r") + (match_operand:SI 2 "reg_or_int_operand" "rI,K,?n")))] + "" + "@ + and%?\\t%0, %1, %2 + bic%?\\t%0, %1, #%B2 + #" +[(set_attr "length" "4,4,16")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (and:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "const_int_operand" "")))] + "! (const_ok_for_arm (INTVAL (operands[2])) + || const_ok_for_arm (~ INTVAL (operands[2])))" + [(clobber (const_int 0))] + " + arm_split_constant (AND, SImode, INTVAL (operands[2]), operands[0], + operands[1], 0); + DONE; +") + +(define_insn "*andsi3_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (and:SI (match_operand:SI 1 "s_register_operand" "r,r") + (match_operand:SI 2 "arm_not_operand" "rI,K")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") + (and:SI (match_dup 1) (match_dup 2)))] + "" + "@ + and%?s\\t%0, %1, %2 + bic%?s\\t%0, %1, #%B2" +[(set_attr "conds" "set")]) + +(define_insn "*andsi3_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (and:SI (match_operand:SI 0 "s_register_operand" "r,r") + (match_operand:SI 1 "arm_not_operand" "rI,K")) + (const_int 0))) + (clobber (match_scratch:SI 3 "=X,r"))] + "" + "@ + tst%?\\t%0, %1 + bic%?s\\t%3, %0, #%B1" +[(set_attr "conds" "set")]) + +(define_insn "*zeroextractsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (zero_extract:SI + (match_operand:SI 0 "s_register_operand" "r") + (match_operand 1 "const_int_operand" "n") + (match_operand 2 "const_int_operand" "n")) + (const_int 0)))] + "INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) < 32 + && INTVAL (operands[1]) > 0 + && INTVAL (operands[1]) + (INTVAL (operands[2]) & 1) <= 8 + && INTVAL (operands[1]) + INTVAL (operands[2]) <= 32" + "* +{ + unsigned int mask = 0; + int cnt = INTVAL (operands[1]); + + while (cnt--) + mask = (mask << 1) | 1; + operands[1] = GEN_INT (mask << INTVAL (operands[2])); + output_asm_insn (\"tst%?\\t%0, %1\", operands); + return \"\"; +} +" +[(set_attr "conds" "set")]) + +;; ??? This pattern does not work because it does not check for start+length +;; less than or equal to 8. This is necessary for the bitfield to fit within +;; a single byte. This pattern was deleted Feb 25, 1999 in egcs, so we can +;; just disabled it for 99r1. + +(define_insn "*zeroextractqi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (zero_extract:SI + (match_operand:QI 0 "memory_operand" "m") + (match_operand 1 "const_int_operand" "n") + (match_operand 2 "const_int_operand" "n")) + (const_int 0))) + (clobber (match_scratch:QI 3 "=r"))] + "0 && INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) < 8 + && INTVAL (operands[1]) > 0 && INTVAL (operands[1]) <= 8" + "* +{ + unsigned int mask = 0; + int cnt = INTVAL (operands[1]); + + while (cnt--) + mask = (mask << 1) | 1; + operands[1] = GEN_INT (mask << INTVAL (operands[2])); + output_asm_insn (\"ldr%?b\\t%3, %0\", operands); + output_asm_insn (\"tst%?\\t%3, %1\", operands); + return \"\"; +} +" +[(set_attr "conds" "set") + (set_attr "length" "8")]) + +;;; ??? This pattern is bogus. If operand3 has bits outside the range +;;; represented by the bitfield, then this will produce incorrect results. +;;; Somewhere, the value needs to be truncated. On targets like the m68k, +;;; which have a real bitfield insert instruction, the truncation happens +;;; in the bitfield insert instruction itself. Since arm does not have a +;;; bitfield insert instruction, we would have to emit code here to truncate +;;; the value before we insert. This loses some of the advantage of having +;;; this insv pattern, so this pattern needs to be reevalutated. + +(define_expand "insv" + [(set (zero_extract:SI (match_operand:SI 0 "s_register_operand" "") + (match_operand:SI 1 "general_operand" "") + (match_operand:SI 2 "general_operand" "")) + (match_operand:SI 3 "nonmemory_operand" ""))] + "" + " +{ + int start_bit = INTVAL (operands[2]); + int width = INTVAL (operands[1]); + HOST_WIDE_INT mask = (((HOST_WIDE_INT)1) << width) - 1; + rtx target, subtarget; + + target = operands[0]; + /* Avoid using a subreg as a subtarget, and avoid writing a paradoxical + subreg as the final target. */ + if (GET_CODE (target) == SUBREG) + { + subtarget = gen_reg_rtx (SImode); + if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (target))) + < GET_MODE_SIZE (SImode)) + target = SUBREG_REG (target); + } + else + subtarget = target; + + if (GET_CODE (operands[3]) == CONST_INT) + { + /* Since we are inserting a known constant, we may be able to + reduce the number of bits that we have to clear so that + the mask becomes simple. */ + /* ??? This code does not check to see if the new mask is actually + simpler. It may not be. */ + rtx op1 = gen_reg_rtx (SImode); + /* ??? Truncate operand3 to fit in the bitfield. See comment before + start of this pattern. */ + HOST_WIDE_INT op3_value = mask & INTVAL (operands[3]); + HOST_WIDE_INT mask2 = ((mask & ~op3_value) << start_bit); + + emit_insn (gen_andsi3 (op1, operands[0], GEN_INT (~mask2))); + emit_insn (gen_iorsi3 (subtarget, op1, + GEN_INT (op3_value << start_bit))); + } + else if (start_bit == 0 + && ! (const_ok_for_arm (mask) + || const_ok_for_arm (~mask))) + { + /* A Trick, since we are setting the bottom bits in the word, + we can shift operand[3] up, operand[0] down, OR them together + and rotate the result back again. This takes 3 insns, and + the third might be mergable into another op. */ + /* The shift up copes with the possibility that operand[3] is + wider than the bitfield. */ + rtx op0 = gen_reg_rtx (SImode); + rtx op1 = gen_reg_rtx (SImode); + + emit_insn (gen_ashlsi3 (op0, operands[3], GEN_INT (32 - width))); + emit_insn (gen_iorsi3 (op1, gen_rtx (LSHIFTRT, SImode, operands[0], + operands[1]), + op0)); + emit_insn (gen_rotlsi3 (subtarget, op1, operands[1])); + } + else if ((width + start_bit == 32) + && ! (const_ok_for_arm (mask) + || const_ok_for_arm (~mask))) + { + /* Similar trick, but slightly less efficient. */ + + rtx op0 = gen_reg_rtx (SImode); + rtx op1 = gen_reg_rtx (SImode); + + emit_insn (gen_ashlsi3 (op0, operands[3], GEN_INT (32 - width))); + emit_insn (gen_ashlsi3 (op1, operands[0], operands[1])); + emit_insn (gen_iorsi3 (subtarget, + gen_rtx (LSHIFTRT, SImode, op1, + operands[1]), op0)); + } + else + { + rtx op0 = GEN_INT (mask); + rtx op1 = gen_reg_rtx (SImode); + rtx op2 = gen_reg_rtx (SImode); + + if (! (const_ok_for_arm (mask) || const_ok_for_arm (~mask))) + { + rtx tmp = gen_reg_rtx (SImode); + + emit_insn (gen_movsi (tmp, op0)); + op0 = tmp; + } + + /* Mask out any bits in operand[3] that are not needed. */ + emit_insn (gen_andsi3 (op1, operands[3], op0)); + + if (GET_CODE (op0) == CONST_INT + && (const_ok_for_arm (mask << start_bit) + || const_ok_for_arm (~ (mask << start_bit)))) + { + op0 = GEN_INT (~(mask << start_bit)); + emit_insn (gen_andsi3 (op2, operands[0], op0)); + } + else + { + if (GET_CODE (op0) == CONST_INT) + { + rtx tmp = gen_reg_rtx (SImode); + + emit_insn (gen_movsi (tmp, op0)); + op0 = tmp; + } + + if (start_bit != 0) + op0 = gen_rtx (ASHIFT, SImode, op0, operands[2]); + + emit_insn (gen_andsi_notsi_si (op2, operands[0], op0)); + } + + if (start_bit != 0) + op1 = gen_rtx (ASHIFT, SImode, op1, operands[2]); + + emit_insn (gen_iorsi3 (subtarget, op1, op2)); + } + + if (subtarget != target) + { + /* If TARGET is still a SUBREG, then it must be wider than a word, + so we must be careful only to set the subword we were asked to. */ + if (GET_CODE (target) == SUBREG) + emit_move_insn (target, subtarget); + else + emit_move_insn (target, gen_lowpart (GET_MODE (target), subtarget)); + } + + DONE; +} +") + +;; constants for op 2 will never be given to these patterns. +(define_insn "*anddi_notdi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (and:DI (not:DI (match_operand:DI 2 "s_register_operand" "r,0")) + (match_operand:DI 1 "s_register_operand" "0,r")))] + "" + "bic%?\\t%Q0, %Q1, %Q2\;bic%?\\t%R0, %R1, %R2" +[(set_attr "length" "8")]) + +(define_insn "*anddi_notzesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (and:DI (not:DI (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r"))) + (match_operand:DI 1 "s_register_operand" "0,?r")))] + "" + "@ + bic%?\\t%Q0, %Q1, %2 + bic%?\\t%Q0, %Q1, %2\;mov%?\\t%R0, %R1" +[(set_attr "length" "4,8")]) + +(define_insn "*anddi_notsesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (and:DI (not:DI (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r"))) + (match_operand:DI 1 "s_register_operand" "?r,0")))] + "" + "bic%?\\t%Q0, %Q1, %2\;bic%?\\t%R0, %R1, %2, asr #31" +[(set_attr "length" "8")]) + +(define_insn "andsi_notsi_si" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (and:SI (not:SI (match_operand:SI 2 "s_register_operand" "r")) + (match_operand:SI 1 "s_register_operand" "r")))] + "" + "bic%?\\t%0, %1, %2") + +(define_insn "andsi_not_shiftsi_si" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (and:SI (not:SI (match_operator:SI 4 "shift_operator" + [(match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 3 "arm_rhs_operand" "rM")])) + (match_operand:SI 1 "s_register_operand" "r")))] + "" + "bic%?\\t%0, %1, %2%S4") + +(define_insn "*andsi_notsi_si_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (and:SI (not:SI (match_operand:SI 2 "s_register_operand" "r")) + (match_operand:SI 1 "s_register_operand" "r")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (and:SI (not:SI (match_dup 2)) (match_dup 1)))] + "" + "bic%?s\\t%0, %1, %2" +[(set_attr "conds" "set")]) + +(define_insn "*andsi_notsi_si_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (and:SI (not:SI (match_operand:SI 2 "s_register_operand" "r")) + (match_operand:SI 1 "s_register_operand" "r")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "" + "bic%?s\\t%0, %1, %2" +[(set_attr "conds" "set")]) + +(define_insn "iordi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r") + (ior:DI (match_operand:DI 1 "s_register_operand" "%0") + (match_operand:DI 2 "s_register_operand" "r")))] + "" + "orr%?\\t%Q0, %Q1, %Q2\;orr%?\\t%R0, %R1, %R2" +[(set_attr "length" "8")]) + +(define_insn "*iordi_zesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (ior:DI (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "0,?r")))] + "" + "@ + orr%?\\t%Q0, %Q1, %2 + orr%?\\t%Q0, %Q1, %2\;mov%?\\t%R0, %R1" +[(set_attr "length" "4,8")]) + +(define_insn "*iordi_sesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (ior:DI (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "?r,0")))] + "" + "orr%?\\t%Q0, %Q1, %2\;orr%?\\t%R0, %R1, %2, asr #31" +[(set_attr "length" "8")]) + +(define_expand "iorsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (ior:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "reg_or_int_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT) + { + arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0], + operands[1], + (reload_in_progress || reload_completed + ? 0 : preserve_subexpressions_p ())); + DONE; + } +") + +(define_insn "*iorsi3_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (ior:SI (match_operand:SI 1 "s_register_operand" "r,r") + (match_operand:SI 2 "reg_or_int_operand" "rI,?n")))] + "" + "@ + orr%?\\t%0, %1, %2 + #" +[(set_attr "length" "4,16")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (ior:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "const_int_operand" "")))] + "! const_ok_for_arm (INTVAL (operands[2]))" + [(clobber (const_int 0))] + " + arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0], + operands[1], 0); + DONE; +") + +(define_insn "*iorsi3_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (ior:SI (match_operand:SI 1 "s_register_operand" "%r") + (match_operand:SI 2 "arm_rhs_operand" "rI")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (ior:SI (match_dup 1) (match_dup 2)))] + "" + "orr%?s\\t%0, %1, %2" +[(set_attr "conds" "set")]) + +(define_insn "*iorsi3_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (ior:SI (match_operand:SI 1 "s_register_operand" "%r") + (match_operand:SI 2 "arm_rhs_operand" "rI")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "" + "orr%?s\\t%0, %1, %2" +[(set_attr "conds" "set")]) + +(define_insn "xordi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (xor:DI (match_operand:DI 1 "s_register_operand" "%0,0") + (match_operand:DI 2 "s_register_operand" "r,0")))] + "" + "eor%?\\t%Q0, %Q1, %Q2\;eor%?\\t%R0, %R1, %R2" +[(set_attr "length" "8")]) + +(define_insn "*xordi_zesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (xor:DI (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "0,?r")))] + "" + "@ + eor%?\\t%Q0, %Q1, %2 + eor%?\\t%Q0, %Q1, %2\;mov%?\\t%R0, %R1" +[(set_attr "length" "4,8")]) + +(define_insn "*xordi_sesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (xor:DI (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "?r,0")))] + "" + "eor%?\\t%Q0, %Q1, %2\;eor%?\\t%R0, %R1, %2, asr #31" +[(set_attr "length" "8")]) + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (xor:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rI")))] + "" + "eor%?\\t%0, %1, %2") + +(define_insn "*xorsi3_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (xor:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rI")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (xor:SI (match_dup 1) (match_dup 2)))] + "" + "eor%?s\\t%0, %1, %2" +[(set_attr "conds" "set")]) + +(define_insn "*xorsi3_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (xor:SI (match_operand:SI 0 "s_register_operand" "r") + (match_operand:SI 1 "arm_rhs_operand" "rI")) + (const_int 0)))] + "" + "teq%?\\t%0, %1" +[(set_attr "conds" "set")]) + +;; by splitting (IOR (AND (NOT A) (NOT B)) C) as D = AND (IOR A B) (NOT C), +;; (NOT D) we can sometimes merge the final NOT into one of the following +;; insns + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "=r") + (ior:SI (and:SI (not:SI (match_operand:SI 1 "s_register_operand" "r")) + (not:SI (match_operand:SI 2 "arm_rhs_operand" "rI"))) + (match_operand:SI 3 "arm_rhs_operand" "rI"))) + (clobber (match_operand:SI 4 "s_register_operand" "=r"))] + "" + [(set (match_dup 4) (and:SI (ior:SI (match_dup 1) (match_dup 2)) + (not:SI (match_dup 3)))) + (set (match_dup 0) (not:SI (match_dup 4)))] + "" +) + +(define_insn "*andsi_iorsi3_notsi" + [(set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r") + (and:SI (ior:SI (match_operand:SI 1 "s_register_operand" "r,r,0") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")) + (not:SI (match_operand:SI 3 "arm_rhs_operand" "rI,rI,rI"))))] + "" + "orr%?\\t%0, %1, %2\;bic%?\\t%0, %0, %3" +[(set_attr "length" "8")]) + + + +;; Minimum and maximum insns + +(define_insn "smaxsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (smax:SI (match_operand:SI 1 "s_register_operand" "0,r,?r") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) + (clobber (reg:CC 24))] + "" + "@ + cmp\\t%1, %2\;movlt\\t%0, %2 + cmp\\t%1, %2\;movge\\t%0, %1 + cmp\\t%1, %2\;movge\\t%0, %1\;movlt\\t%0, %2" +[(set_attr "conds" "clob") + (set_attr "length" "8,8,12")]) + +(define_insn "sminsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (smin:SI (match_operand:SI 1 "s_register_operand" "0,r,?r") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) + (clobber (reg:CC 24))] + "" + "@ + cmp\\t%1, %2\;movge\\t%0, %2 + cmp\\t%1, %2\;movlt\\t%0, %1 + cmp\\t%1, %2\;movlt\\t%0, %1\;movge\\t%0, %2" +[(set_attr "conds" "clob") + (set_attr "length" "8,8,12")]) + +(define_insn "umaxsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (umax:SI (match_operand:SI 1 "s_register_operand" "0,r,?r") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) + (clobber (reg:CC 24))] + "" + "@ + cmp\\t%1, %2\;movcc\\t%0, %2 + cmp\\t%1, %2\;movcs\\t%0, %1 + cmp\\t%1, %2\;movcs\\t%0, %1\;movcc\\t%0, %2" +[(set_attr "conds" "clob") + (set_attr "length" "8,8,12")]) + +(define_insn "uminsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (umin:SI (match_operand:SI 1 "s_register_operand" "0,r,?r") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) + (clobber (reg:CC 24))] + "" + "@ + cmp\\t%1, %2\;movcs\\t%0, %2 + cmp\\t%1, %2\;movcc\\t%0, %1 + cmp\\t%1, %2\;movcc\\t%0, %1\;movcs\\t%0, %2" +[(set_attr "conds" "clob") + (set_attr "length" "8,8,12")]) + +(define_insn "*store_minmaxsi" + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operator:SI 3 "minmax_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "s_register_operand" "r")])) + (clobber (reg:CC 24))] + "" + "* + operands[3] = gen_rtx (minmax_code (operands[3]), SImode, operands[1], + operands[2]); + output_asm_insn (\"cmp\\t%1, %2\", operands); + output_asm_insn (\"str%d3\\t%1, %0\", operands); + output_asm_insn (\"str%D3\\t%2, %0\", operands); + return \"\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "12") + (set_attr "type" "store1")]) + +; Reject the frame pointer in operand[1], since reloading this after +; it has been eliminated can cause carnage. +(define_insn "*minmax_arithsi" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (match_operator:SI 4 "shiftable_operator" + [(match_operator:SI 5 "minmax_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_rhs_operand" "rI,rI")]) + (match_operand:SI 1 "s_register_operand" "0,?r")])) + (clobber (reg:CC 24))] + "GET_CODE (operands[1]) != REG + || (REGNO(operands[1]) != FRAME_POINTER_REGNUM + && REGNO(operands[1]) != ARG_POINTER_REGNUM)" + "* +{ + enum rtx_code code = GET_CODE (operands[4]); + + operands[5] = gen_rtx (minmax_code (operands[5]), SImode, operands[2], + operands[3]); + output_asm_insn (\"cmp\\t%2, %3\", operands); + output_asm_insn (\"%i4%d5\\t%0, %1, %2\", operands); + if (which_alternative != 0 || operands[3] != const0_rtx + || (code != PLUS && code != MINUS && code != IOR && code != XOR)) + output_asm_insn (\"%i4%D5\\t%0, %1, %3\", operands); + return \"\"; +} +" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + + +;; Shift and rotation insns + +(define_expand "ashlsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (ashift:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "arm_rhs_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT + && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31) + { + emit_insn (gen_movsi (operands[0], const0_rtx)); + DONE; + } +") + +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (ashiftrt:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "arm_rhs_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT + && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31) + operands[2] = GEN_INT (31); +") + +(define_expand "lshrsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (lshiftrt:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "arm_rhs_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT + && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31) + { + emit_insn (gen_movsi (operands[0], const0_rtx)); + DONE; + } +") + +(define_expand "rotlsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (rotatert:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "reg_or_int_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT) + operands[2] = GEN_INT ((32 - INTVAL (operands[2])) % 32); + else + { + rtx reg = gen_reg_rtx (SImode); + emit_insn (gen_subsi3 (reg, GEN_INT (32), operands[2])); + operands[2] = reg; + } +") + +(define_expand "rotrsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (rotatert:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "arm_rhs_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT + && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31) + operands[2] = GEN_INT (INTVAL (operands[2]) % 32); +") + +(define_insn "*shiftsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "reg_or_int_operand" "rM")]))] + "" + "mov%?\\t%0, %1%S3") + +(define_insn "*shiftsi3_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")]) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (match_op_dup 3 [(match_dup 1) (match_dup 2)]))] + "" + "mov%?s\\t%0, %1%S3" +[(set_attr "conds" "set")]) + +(define_insn "*shiftsi3_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")]) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "" + "mov%?s\\t%0, %1%S3" +[(set_attr "conds" "set")]) + +(define_insn "*notsi_shiftsi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (not:SI (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")])))] + "" + "mvn%?\\t%0, %1%S3") + +(define_insn "*notsi_shiftsi_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (not:SI (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")])) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (not:SI (match_op_dup 3 [(match_dup 1) (match_dup 2)])))] + "" + "mvn%?s\\t%0, %1%S3" +[(set_attr "conds" "set")]) + +(define_insn "*not_shiftsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (not:SI (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")])) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "" + "mvn%?s\\t%0, %1%S3" +[(set_attr "conds" "set")]) + + +;; Unary arithmetic insns + +(define_insn "negdi2" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (neg:DI (match_operand:DI 1 "s_register_operand" "?r,0")))] + "" + "rsbs\\t%Q0, %Q1, #0\;rsc\\t%R0, %R1, #0" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "negsi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (neg:SI (match_operand:SI 1 "s_register_operand" "r")))] + "" + "rsb%?\\t%0, %1, #0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (neg:SF (match_operand:SF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "mnf%?s\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "negdf2" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (neg:DF (match_operand:DF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "mnf%?d\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "*negdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (neg:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "mnf%?d\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "negxf2" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (neg:XF (match_operand:XF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "mnf%?e\\t%0, %1" +[(set_attr "type" "ffarith")]) + +;; abssi2 doesn't really clobber the condition codes if a different register +;; is being set. To keep things simple, assume during rtl manipulations that +;; it does, but tell the final scan operator the truth. Similarly for +;; (neg (abs...)) + +(define_insn "abssi2" + [(set (match_operand:SI 0 "s_register_operand" "=r,&r") + (abs:SI (match_operand:SI 1 "s_register_operand" "0,r"))) + (clobber (reg:CC 24))] + "" + "@ + cmp\\t%0, #0\;rsblt\\t%0, %0, #0 + eor%?\\t%0, %1, %1, asr #31\;sub%?\\t%0, %0, %1, asr #31" +[(set_attr "conds" "clob,*") + (set_attr "length" "8")]) + +(define_insn "*neg_abssi2" + [(set (match_operand:SI 0 "s_register_operand" "=r,&r") + (neg:SI (abs:SI (match_operand:SI 1 "s_register_operand" "0,r")))) + (clobber (reg:CC 24))] + "" + "@ + cmp\\t%0, #0\;rsbgt\\t%0, %0, #0 + eor%?\\t%0, %1, %1, asr #31\;rsb%?\\t%0, %0, %1, asr #31" +[(set_attr "conds" "clob,*") + (set_attr "length" "8")]) + +(define_insn "abssf2" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (abs:SF (match_operand:SF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "abs%?s\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "absdf2" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (abs:DF (match_operand:DF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "abs%?d\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "*absdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (abs:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "abs%?d\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "absxf2" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (abs:XF (match_operand:XF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "abs%?e\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "sqrtsf2" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (sqrt:SF (match_operand:SF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "sqt%?s\\t%0, %1" +[(set_attr "type" "float_em")]) + +(define_insn "sqrtdf2" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (sqrt:DF (match_operand:DF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "sqt%?d\\t%0, %1" +[(set_attr "type" "float_em")]) + +(define_insn "*sqrtdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (sqrt:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "sqt%?d\\t%0, %1" +[(set_attr "type" "float_em")]) + +(define_insn "sqrtxf2" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (sqrt:XF (match_operand:XF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "sqt%?e\\t%0, %1" +[(set_attr "type" "float_em")]) + +;; SIN COS TAN and family are always emulated, so it's probably better +;; to always call a library function. +;(define_insn "sinsf2" +; [(set (match_operand:SF 0 "s_register_operand" "=f") +; (unspec:SF [(match_operand:SF 1 "s_register_operand" "f")] 0))] +; "TARGET_HARD_FLOAT" +; "sin%?s\\t%0, %1" +;[(set_attr "type" "float_em")]) +; +;(define_insn "sindf2" +; [(set (match_operand:DF 0 "s_register_operand" "=f") +; (unspec:DF [(match_operand:DF 1 "s_register_operand" "f")] 0))] +; "TARGET_HARD_FLOAT" +; "sin%?d\\t%0, %1" +;[(set_attr "type" "float_em")]) +; +;(define_insn "*sindf_esfdf" +; [(set (match_operand:DF 0 "s_register_operand" "=f") +; (unspec:DF [(float_extend:DF +; (match_operand:SF 1 "s_register_operand" "f"))] 0))] +; "TARGET_HARD_FLOAT" +; "sin%?d\\t%0, %1" +;[(set_attr "type" "float_em")]) +; +;(define_insn "sinxf2" +; [(set (match_operand:XF 0 "s_register_operand" "=f") +; (unspec:XF [(match_operand:XF 1 "s_register_operand" "f")] 0))] +; "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" +; "sin%?e\\t%0, %1" +;[(set_attr "type" "float_em")]) +; +;(define_insn "cossf2" +; [(set (match_operand:SF 0 "s_register_operand" "=f") +; (unspec:SF [(match_operand:SF 1 "s_register_operand" "f")] 1))] +; "TARGET_HARD_FLOAT" +; "cos%?s\\t%0, %1" +;[(set_attr "type" "float_em")]) +; +;(define_insn "cosdf2" +; [(set (match_operand:DF 0 "s_register_operand" "=f") +; (unspec:DF [(match_operand:DF 1 "s_register_operand" "f")] 1))] +; "TARGET_HARD_FLOAT" +; "cos%?d\\t%0, %1" +;[(set_attr "type" "float_em")]) +; +;(define_insn "*cosdf_esfdf" +; [(set (match_operand:DF 0 "s_register_operand" "=f") +; (unspec:DF [(float_extend:DF +; (match_operand:SF 1 "s_register_operand" "f"))] 1))] +; "TARGET_HARD_FLOAT" +; "cos%?d\\t%0, %1" +;[(set_attr "type" "float_em")]) +; +;(define_insn "cosxf2" +; [(set (match_operand:XF 0 "s_register_operand" "=f") +; (unspec:XF [(match_operand:XF 1 "s_register_operand" "f")] 1))] +; "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" +; "cos%?e\\t%0, %1" +;[(set_attr "type" "float_em")]) + +(define_insn "one_cmpldi2" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (not:DI (match_operand:DI 1 "s_register_operand" "?r,0")))] + "" + "mvn%?\\t%Q0, %Q1\;mvn%?\\t%R0, %R1" +[(set_attr "length" "8")]) + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (not:SI (match_operand:SI 1 "s_register_operand" "r")))] + "" + "mvn%?\\t%0, %1") + +(define_insn "*notsi_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (not:SI (match_operand:SI 1 "s_register_operand" "r")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (not:SI (match_dup 1)))] + "" + "mvn%?s\\t%0, %1" +[(set_attr "conds" "set")]) + +(define_insn "*notsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (not:SI (match_operand:SI 1 "s_register_operand" "r")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "" + "mvn%?s\\t%0, %1" +[(set_attr "conds" "set")]) + +;; Fixed <--> Floating conversion insns + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (float:SF (match_operand:SI 1 "s_register_operand" "r")))] + "TARGET_HARD_FLOAT" + "flt%?s\\t%0, %1" +[(set_attr "type" "r_2_f")]) + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (float:DF (match_operand:SI 1 "s_register_operand" "r")))] + "TARGET_HARD_FLOAT" + "flt%?d\\t%0, %1" +[(set_attr "type" "r_2_f")]) + +(define_insn "floatsixf2" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (float:XF (match_operand:SI 1 "s_register_operand" "r")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "flt%?e\\t%0, %1" +[(set_attr "type" "r_2_f")]) + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (fix:SI (match_operand:SF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "fix%?z\\t%0, %1" +[(set_attr "type" "f_2_r")]) + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (fix:SI (match_operand:DF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "fix%?z\\t%0, %1" +[(set_attr "type" "f_2_r")]) + +(define_insn "fix_truncxfsi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (fix:SI (match_operand:XF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "fix%?z\\t%0, %1" +[(set_attr "type" "f_2_r")]) + +;; Truncation insns + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (float_truncate:SF + (match_operand:DF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "mvf%?s\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "truncxfsf2" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (float_truncate:SF + (match_operand:XF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "mvf%?s\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "truncxfdf2" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (float_truncate:DF + (match_operand:XF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "mvf%?d\\t%0, %1" +[(set_attr "type" "ffarith")]) + +;; Zero and sign extension instructions. + +(define_insn "zero_extendsidi2" + [(set (match_operand:DI 0 "s_register_operand" "=r") + (zero_extend:DI (match_operand:SI 1 "s_register_operand" "r")))] + "" + "* + if (REGNO (operands[1]) != REGNO (operands[0]) + (WORDS_BIG_ENDIAN ? 1 : 0)) + output_asm_insn (\"mov%?\\t%Q0, %1\", operands); + return \"mov%?\\t%R0, #0\"; +" +[(set_attr "length" "8")]) + +(define_insn "zero_extendqidi2" + [(set (match_operand:DI 0 "s_register_operand" "=r,r") + (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] + "" + "@ + and%?\\t%Q0, %1, #255\;mov%?\\t%R0, #0 + ldr%?b\\t%Q0, %1\;mov%?\\t%R0, #0" +[(set_attr "length" "8") + (set_attr "type" "*,load")]) + +(define_insn "extendsidi2" + [(set (match_operand:DI 0 "s_register_operand" "=r") + (sign_extend:DI (match_operand:SI 1 "s_register_operand" "r")))] + "" + "* + if (REGNO (operands[1]) != REGNO (operands[0]) + (WORDS_BIG_ENDIAN ? 1 : 0)) + output_asm_insn (\"mov%?\\t%Q0, %1\", operands); + return \"mov%?\\t%R0, %Q0, asr #31\"; +" +[(set_attr "length" "8")]) + +(define_expand "zero_extendhisi2" + [(set (match_dup 2) (ashift:SI (match_operand:HI 1 "nonimmediate_operand" "") + (const_int 16))) + (set (match_operand:SI 0 "s_register_operand" "") + (lshiftrt:SI (match_dup 2) (const_int 16)))] + "" + " +{ + if (arm_arch4 && GET_CODE (operands[1]) == MEM) + { + /* Note: We do not have to worry about TARGET_SHORT_BY_BYTES + here because the insn below will generate an LDRH instruction + rather than an LDR instruction, so we cannot get an unaligned + word access. */ + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_ZERO_EXTEND (SImode, operands[1]))); + DONE; + } + if (TARGET_SHORT_BY_BYTES && GET_CODE (operands[1]) == MEM) + { + emit_insn (gen_movhi_bytes (operands[0], operands[1])); + DONE; + } + if (! s_register_operand (operands[1], HImode)) + operands[1] = copy_to_mode_reg (HImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); +}") + +(define_insn "*zero_extendhisi_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + "arm_arch4" + "ldr%?h\\t%0, %1" +[(set_attr "type" "load")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (zero_extend:SI (match_operand:HI 1 "alignable_memory_operand" ""))) + (clobber (match_operand:SI 2 "s_register_operand" ""))] + "! arm_arch4" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (lshiftrt:SI (match_dup 2) (const_int 16)))] + " +{ + if ((operands[1] = gen_rotated_half_load (operands[1])) == NULL) + FAIL; +}") + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operator:SI 3 "shiftable_operator" + [(zero_extend:SI (match_operand:HI 1 "alignable_memory_operand" "")) + (match_operand:SI 4 "s_register_operand" "")])) + (clobber (match_operand:SI 2 "s_register_operand" ""))] + "! arm_arch4" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) + (match_op_dup 3 + [(lshiftrt:SI (match_dup 2) (const_int 16)) (match_dup 4)]))] + " +{ + if ((operands[1] = gen_rotated_half_load (operands[1])) == NULL) + FAIL; +}") + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (zero_extend:SI + (match_operand:QI 1 "nonimmediate_operand" "r,m")))] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + emit_insn (gen_andsi3 (operands[0], gen_lowpart (SImode, operands[1]), + GEN_INT (255))); + DONE; + } +") + +(define_insn "*load_extendqisi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + "" + "ldr%?b\\t%0, %1\\t%@ zero_extendqisi2" +[(set_attr "type" "load")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (zero_extend:SI (subreg:QI (match_operand:SI 1 "" "") 0))) + (clobber (match_operand:SI 2 "s_register_operand" ""))] + "GET_CODE (operands[1]) != MEM" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (and:SI (match_dup 2) (const_int 255)))] + "") + +(define_insn "*compareqi_eq0" + [(set (reg:CC_Z 24) + (compare:CC_Z (match_operand:QI 0 "s_register_operand" "r") + (const_int 0)))] + "" + "tst\\t%0, #255" +[(set_attr "conds" "set")]) + +(define_expand "extendhisi2" + [(set (match_dup 2) + (ashift:SI (match_operand:HI 1 "nonimmediate_operand" "") + (const_int 16))) + (set (match_operand:SI 0 "s_register_operand" "") + (ashiftrt:SI (match_dup 2) + (const_int 16)))] + "" + " +{ + if (arm_arch4 && GET_CODE (operands[1]) == MEM) + { + /* Note: We do not have to worry about TARGET_SHORT_BY_BYTES + here because the insn below will generate an LDRH instruction + rather than an LDR instruction, so we cannot get an unaligned + word access. */ + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_SIGN_EXTEND (SImode, operands[1]))); + DONE; + } + + if (TARGET_SHORT_BY_BYTES && GET_CODE (operands[1]) == MEM) + { + emit_insn (gen_extendhisi2_mem (operands[0], operands[1])); + DONE; + } + if (! s_register_operand (operands[1], HImode)) + operands[1] = copy_to_mode_reg (HImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); +}") + +(define_expand "extendhisi2_mem" + [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" ""))) + (set (match_dup 3) + (zero_extend:SI (match_dup 7))) + (set (match_dup 6) (ashift:SI (match_dup 4) (const_int 24))) + (set (match_operand:SI 0 "" "") + (ior:SI (ashiftrt:SI (match_dup 6) (const_int 16)) (match_dup 5)))] + "" + " +{ + rtx mem1, mem2; + rtx addr = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); + + mem1 = gen_rtx (MEM, QImode, addr); + MEM_COPY_ATTRIBUTES (mem1, operands[1]); + RTX_UNCHANGING_P (mem1) = RTX_UNCHANGING_P (operands[1]); + mem2 = gen_rtx (MEM, QImode, plus_constant (addr, 1)); + MEM_COPY_ATTRIBUTES (mem2, operands[1]); + RTX_UNCHANGING_P (mem2) = RTX_UNCHANGING_P (operands[1]); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = mem1; + operands[2] = gen_reg_rtx (SImode); + operands[3] = gen_reg_rtx (SImode); + operands[6] = gen_reg_rtx (SImode); + operands[7] = mem2; + + if (BYTES_BIG_ENDIAN) + { + operands[4] = operands[2]; + operands[5] = operands[3]; + } + else + { + operands[4] = operands[3]; + operands[5] = operands[2]; + } +} +") + +(define_insn "*extendhisi_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + "arm_arch4" + "ldr%?sh\\t%0, %1" +[(set_attr "type" "load")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (sign_extend:SI (match_operand:HI 1 "alignable_memory_operand" ""))) + (clobber (match_operand:SI 2 "s_register_operand" ""))] + "! arm_arch4" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (ashiftrt:SI (match_dup 2) (const_int 16)))] + " +{ + if ((operands[1] = gen_rotated_half_load (operands[1])) == NULL) + FAIL; +}") + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operator:SI 3 "shiftable_operator" + [(sign_extend:SI (match_operand:HI 1 "alignable_memory_operand" "")) + (match_operand:SI 4 "s_register_operand" "")])) + (clobber (match_operand:SI 2 "s_register_operand" ""))] + "! arm_arch4" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) + (match_op_dup 3 + [(ashiftrt:SI (match_dup 2) (const_int 16)) (match_dup 4)]))] + " +{ + if ((operands[1] = gen_rotated_half_load (operands[1])) == NULL) + FAIL; +}") + +(define_expand "extendqihi2" + [(set (match_dup 2) + (ashift:SI (match_operand:QI 1 "general_operand" "") + (const_int 24))) + (set (match_operand:HI 0 "s_register_operand" "") + (ashiftrt:SI (match_dup 2) + (const_int 24)))] + "" + " +{ + if (arm_arch4 && GET_CODE (operands[1]) == MEM) + { + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (SIGN_EXTEND, HImode, operands[1]))); + DONE; + } + if (! s_register_operand (operands[1], QImode)) + operands[1] = copy_to_mode_reg (QImode, operands[1]); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); +}") + +; Rather than restricting all byte accesses to memory addresses that ldrsb +; can handle, we fix up the ones that ldrsb can't grok with a split. +(define_insn "*extendqihi_insn" + [(set (match_operand:HI 0 "s_register_operand" "=r") + (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))] + "arm_arch4" + "* + /* If the address is invalid, this will split the instruction into two. */ + if (bad_signed_byte_operand(operands[1], QImode)) + return \"#\"; + return \"ldr%?sb\\t%0, %1\"; +" +[(set_attr "type" "load") + (set_attr "length" "8")]) + +(define_split + [(set (match_operand:HI 0 "s_register_operand" "") + (sign_extend:HI (match_operand:QI 1 "bad_signed_byte_operand" "")))] + "arm_arch4 && reload_completed" + [(set (match_dup 3) (match_dup 1)) + (set (match_dup 0) (sign_extend:HI (match_dup 2)))] + " + { + HOST_WIDE_INT offset; + + operands[3] = gen_rtx (REG, SImode, REGNO (operands[0])); + operands[2] = gen_rtx (MEM, QImode, operands[3]); + MEM_COPY_ATTRIBUTES (operands[2], operands[1]); + RTX_UNCHANGING_P (operands[2]) = RTX_UNCHANGING_P (operands[1]); + operands[1] = XEXP (operands[1], 0); + if (GET_CODE (operands[1]) == PLUS + && GET_CODE (XEXP (operands[1], 1)) == CONST_INT + && ! (const_ok_for_arm (offset = INTVAL (XEXP (operands[1], 1))) + || const_ok_for_arm (-offset))) + { + HOST_WIDE_INT low = (offset > 0 + ? (offset & 0xff) : -((-offset) & 0xff)); + XEXP (operands[2], 0) = plus_constant (operands[3], low); + operands[1] = plus_constant (XEXP (operands[1], 0), offset - low); + } + /* Ensure the sum is in correct canonical form */ + else if (GET_CODE (operands[1]) == PLUS + && GET_CODE (XEXP (operands[1], 1)) != CONST_INT + && ! s_register_operand (XEXP (operands[1], 1), VOIDmode)) + operands[1] = gen_rtx (PLUS, GET_MODE (operands[1]), + XEXP (operands[1], 1), XEXP (operands[1], 0)); + } +") + +(define_expand "extendqisi2" + [(set (match_dup 2) + (ashift:SI (match_operand:QI 1 "general_operand" "") + (const_int 24))) + (set (match_operand:SI 0 "s_register_operand" "") + (ashiftrt:SI (match_dup 2) + (const_int 24)))] + "" + " +{ + if (arm_arch4 && GET_CODE (operands[1]) == MEM) + { + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (SIGN_EXTEND, SImode, operands[1]))); + DONE; + } + if (! s_register_operand (operands[1], QImode)) + operands[1] = copy_to_mode_reg (QImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); +}") + +; Rather than restricting all byte accesses to memory addresses that ldrsb +; can handle, we fix up the ones that ldrsb can't grok with a split. +(define_insn "*extendqisi_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + "arm_arch4" + "* + /* If the address is invalid, this will split the instruction into two. */ + if (bad_signed_byte_operand(operands[1], QImode)) + return \"#\"; + return \"ldr%?sb\\t%0, %1\"; +" +[(set_attr "type" "load") + (set_attr "length" "8")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (sign_extend:SI (match_operand:QI 1 "bad_signed_byte_operand" "")))] + "arm_arch4 && reload_completed" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 0) (sign_extend:SI (match_dup 2)))] + " + { + HOST_WIDE_INT offset; + + operands[2] = gen_rtx (MEM, QImode, operands[0]); + MEM_COPY_ATTRIBUTES (operands[2], operands[1]); + RTX_UNCHANGING_P (operands[2]) = RTX_UNCHANGING_P (operands[1]); + operands[1] = XEXP (operands[1], 0); + if (GET_CODE (operands[1]) == PLUS + && GET_CODE (XEXP (operands[1], 1)) == CONST_INT + && ! (const_ok_for_arm (offset = INTVAL (XEXP (operands[1], 1))) + || const_ok_for_arm (-offset))) + { + HOST_WIDE_INT low = (offset > 0 + ? (offset & 0xff) : -((-offset) & 0xff)); + XEXP (operands[2], 0) = plus_constant (operands[0], low); + operands[1] = plus_constant (XEXP (operands[1], 0), offset - low); + } + /* Ensure the sum is in correct canonical form */ + else if (GET_CODE (operands[1]) == PLUS + && GET_CODE (XEXP (operands[1], 1)) != CONST_INT + && ! s_register_operand (XEXP (operands[1], 1), VOIDmode)) + operands[1] = gen_rtx (PLUS, GET_MODE (operands[1]), + XEXP (operands[1], 1), XEXP (operands[1], 0)); + } +") + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (float_extend:DF (match_operand:SF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "mvf%?d\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "extendsfxf2" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (float_extend:XF (match_operand:SF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "mvf%?e\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "extenddfxf2" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (float_extend:XF (match_operand:DF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "mvf%?e\\t%0, %1" +[(set_attr "type" "ffarith")]) + + +;; Move insns (including loads and stores) + +;; XXX Just some ideas about movti. +;; I don't think these are a good idea on the arm, there just aren't enough +;; registers +;;(define_expand "loadti" +;; [(set (match_operand:TI 0 "s_register_operand" "") +;; (mem:TI (match_operand:SI 1 "address_operand" "")))] +;; "" "") + +;;(define_expand "storeti" +;; [(set (mem:TI (match_operand:TI 0 "address_operand" "")) +;; (match_operand:TI 1 "s_register_operand" ""))] +;; "" "") + +;;(define_expand "movti" +;; [(set (match_operand:TI 0 "general_operand" "") +;; (match_operand:TI 1 "general_operand" ""))] +;; "" +;; " +;;{ +;; rtx insn; +;; +;; if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) +;; operands[1] = copy_to_reg (operands[1]); +;; if (GET_CODE (operands[0]) == MEM) +;; insn = gen_storeti (XEXP (operands[0], 0), operands[1]); +;; else if (GET_CODE (operands[1]) == MEM) +;; insn = gen_loadti (operands[0], XEXP (operands[1], 0)); +;; else +;; FAIL; +;; +;; emit_insn (insn); +;; DONE; +;;}") + +;; Recognise garbage generated above. + +;;(define_insn "" +;; [(set (match_operand:TI 0 "general_operand" "=r,r,r,<,>,m") +;; (match_operand:TI 1 "general_operand" "<,>,m,r,r,r"))] +;; "" +;; "* +;; { +;; register mem = (which_alternative < 3); +;; register char *template; +;; +;; operands[mem] = XEXP (operands[mem], 0); +;; switch (which_alternative) +;; { +;; case 0: template = \"ldmdb\\t%1!, %M0\"; break; +;; case 1: template = \"ldmia\\t%1!, %M0\"; break; +;; case 2: template = \"ldmia\\t%1, %M0\"; break; +;; case 3: template = \"stmdb\\t%0!, %M1\"; break; +;; case 4: template = \"stmia\\t%0!, %M1\"; break; +;; case 5: template = \"stmia\\t%0, %M1\"; break; +;; } +;; output_asm_insn (template, operands); +;; return \"\"; +;; }") + + +(define_insn "movdi" + [(set (match_operand:DI 0 "di_operand" "=r,r,o<>") + (match_operand:DI 1 "di_operand" "rIK,mi,r"))] + "" + "* + return (output_move_double (operands)); +" +[(set_attr "length" "8,8,8") + (set_attr "type" "*,load,store2")]) + +(define_expand "movsi" + [(set (match_operand:SI 0 "general_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "" + " + /* Everything except mem = const or mem = mem can be done easily */ + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (SImode, operands[1]); + /* CYGNUS LOCAL nickc */ + if (! ok_integer_or_other (operands[1])) + /* END CYGNUS LOCAL */ + { + arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0], + NULL_RTX, + (reload_in_progress || reload_completed ? 0 + : preserve_subexpressions_p ())); + DONE; + } + if (CONSTANT_P (operands[1]) && flag_pic) + operands[1] = legitimize_pic_address (operands[1], SImode, + ((reload_in_progress + || reload_completed) + ? operands[0] : 0)); +") + +(define_insn "*movsi_insn" + [(set (match_operand:SI 0 "general_operand" "=r,r,r,m") + (match_operand:SI 1 "general_operand" "rI,K,mi,r"))] + "register_operand (operands[0], SImode) + || register_operand (operands[1], SImode)" + "@ + mov%?\\t%0, %1 + mvn%?\\t%0, #%B1 + ldr%?\\t%0, %1 + str%?\\t%1, %0" +[(set_attr "type" "*,*,load,store1")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "! (const_ok_for_arm (INTVAL (operands[1])) + || const_ok_for_arm (~INTVAL (operands[1])))" + [(clobber (const_int 0))] + " + arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0], + NULL_RTX, 0); + DONE; +") + +(define_expand "movaddr" + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operand:DI 1 "address_operand" ""))] + "" + "") + +(define_insn "*movaddr_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operand:DI 1 "address_operand" "p"))] + "reload_completed + && (GET_CODE (operands[1]) == LABEL_REF + || (GET_CODE (operands[1]) == CONST + && GET_CODE (XEXP (operands[1], 0)) == PLUS + && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF + && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT))" + "adr%?\\t%0, %a1") + +/* When generating pic, we need to load the symbol offset into a register. + So that the optimizer does not confuse this with a normal symbol load + we use an unspec. The offset will be loaded from a constant pool entry, + since that is the only type of relocation we can use. */ + +(define_insn "pic_load_addr" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (unspec:SI [(match_operand 1 "" "")] 3))] + "flag_pic" + "ldr%?\\t%0, %a1" + [(set_attr "type" "load")]) + +;; This variant is used for AOF assembly, since it needs to mention the +;; pic register in the rtl. +(define_expand "pic_load_addr_based" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (unspec:SI [(match_operand 1 "" "") (match_dup 2)] 3))] + "flag_pic" + "operands[2] = pic_offset_table_rtx;") + +(define_insn "*pic_load_addr_based_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (unspec:SI [(match_operand 1 "" "") + (match_operand 2 "s_register_operand" "r")] 3))] + "flag_pic && operands[2] == pic_offset_table_rtx" + "* +#ifdef AOF_ASSEMBLER + operands[1] = aof_pic_entry (operands[1]); +#endif + output_asm_insn (\"ldr%?\\t%0, %a1\", operands); + return \"\"; +" [(set_attr "type" "load")]) + +(define_insn "pic_add_dot_plus_eight" + [(set (pc) (label_ref (match_operand 0 "" ""))) + (set (match_operand 1 "register_operand" "+r") + (plus:SI (match_dup 1) (const (plus:SI (pc) (const_int 8)))))] + "flag_pic" + "add%?\\t%1, %|pc, %1") + +;; If copying one reg to another we can set the condition codes according to +;; its value. Such a move is common after a return from subroutine and the +;; result is being tested against zero. + +(define_insn "*movsi_compare0" + [(set (reg:CC 24) (compare:CC (match_operand:SI 1 "s_register_operand" "0,r") + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") (match_dup 1))] + "" + "@ + cmp%?\\t%0, #0 + sub%?s\\t%0, %1, #0" +[(set_attr "conds" "set")]) + +;; Subroutine to store a half word from a register into memory. +;; Operand 0 is the source register (HImode) +;; Operand 1 is the destination address in a register (SImode) + +;; In both this routine and the next, we must be careful not to spill +;; a memory address of reg+large_const into a separate PLUS insn, since this +;; can generate unrecognizable rtl. + +(define_expand "storehi" + [;; store the low byte + (set (match_operand 1 "" "") (match_dup 3)) + ;; extract the high byte + (set (match_dup 2) + (ashiftrt:SI (match_operand 0 "" "") (const_int 8))) + ;; store the high byte + (set (match_dup 4) (subreg:QI (match_dup 2) 0))] ;explicit subreg safe + "" + " +{ + rtx addr = XEXP (operands[1], 0); + enum rtx_code code = GET_CODE (addr); + + if ((code == PLUS && GET_CODE (XEXP (addr, 1)) != CONST_INT) + || code == MINUS) + addr = force_reg (SImode, addr); + + operands[4] = change_address (operands[1], QImode, plus_constant (addr, 1)); + operands[1] = change_address (operands[1], QImode, NULL_RTX); + operands[3] = gen_lowpart (QImode, operands[0]); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[2] = gen_reg_rtx (SImode); +} +") + +(define_expand "storehi_bigend" + [(set (match_dup 4) (match_dup 3)) + (set (match_dup 2) + (ashiftrt:SI (match_operand 0 "" "") (const_int 8))) + (set (match_operand 1 "" "") (subreg:QI (match_dup 2) 0))] + "" + " +{ + rtx addr = XEXP (operands[1], 0); + enum rtx_code code = GET_CODE (addr); + + if ((code == PLUS && GET_CODE (XEXP (addr, 1)) != CONST_INT) + || code == MINUS) + addr = force_reg (SImode, addr); + + operands[4] = change_address (operands[1], QImode, plus_constant (addr, 1)); + operands[1] = change_address (operands[1], QImode, NULL_RTX); + operands[3] = gen_lowpart (QImode, operands[0]); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[2] = gen_reg_rtx (SImode); +} +") + +;; Subroutine to store a half word integer constant into memory. +(define_expand "storeinthi" + [(set (match_operand 0 "" "") + (subreg:QI (match_operand 1 "" "") 0)) + (set (match_dup 3) (subreg:QI (match_dup 2) 0))] + "" + " +{ + HOST_WIDE_INT value = INTVAL (operands[1]); + rtx addr = XEXP (operands[0], 0); + enum rtx_code code = GET_CODE (addr); + + if ((code == PLUS && GET_CODE (XEXP (addr, 1)) != CONST_INT) + || code == MINUS) + addr = force_reg (SImode, addr); + + operands[1] = gen_reg_rtx (SImode); + if (BYTES_BIG_ENDIAN) + { + emit_insn (gen_movsi (operands[1], GEN_INT ((value >> 8) & 255))); + if ((value & 255) == ((value >> 8) & 255)) + operands[2] = operands[1]; + else + { + operands[2] = gen_reg_rtx (SImode); + emit_insn (gen_movsi (operands[2], GEN_INT (value & 255))); + } + } + else + { + emit_insn (gen_movsi (operands[1], GEN_INT (value & 255))); + if ((value & 255) == ((value >> 8) & 255)) + operands[2] = operands[1]; + else + { + operands[2] = gen_reg_rtx (SImode); + emit_insn (gen_movsi (operands[2], GEN_INT ((value >> 8) & 255))); + } + } + + operands[3] = change_address (operands[0], QImode, plus_constant (addr, 1)); + operands[0] = change_address (operands[0], QImode, NULL_RTX); +} +") + +(define_expand "storehi_single_op" + [(set (match_operand:HI 0 "memory_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "arm_arch4" + " + if (! s_register_operand (operands[1], HImode)) + operands[1] = copy_to_mode_reg (HImode, operands[1]); +") + +(define_expand "movhi" + [(set (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + " +{ + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) == MEM) + { + if (arm_arch4) + { + emit_insn (gen_storehi_single_op (operands[0], operands[1])); + DONE; + } + if (GET_CODE (operands[1]) == CONST_INT) + emit_insn (gen_storeinthi (operands[0], operands[1])); + else + { + if (GET_CODE (operands[1]) == MEM) + operands[1] = force_reg (HImode, operands[1]); + if (BYTES_BIG_ENDIAN) + emit_insn (gen_storehi_bigend (operands[1], operands[0])); + else + emit_insn (gen_storehi (operands[1], operands[0])); + } + DONE; + } + /* Sign extend a constant, and keep it in an SImode reg. */ + else if (GET_CODE (operands[1]) == CONST_INT) + { + rtx reg = gen_reg_rtx (SImode); + HOST_WIDE_INT val = INTVAL (operands[1]) & 0xffff; + + /* If the constant is already valid, leave it alone. */ + if (! const_ok_for_arm (val)) + { + /* If setting all the top bits will make the constant + loadable in a single instruction, then set them. + Otherwise, sign extend the number. */ + + if (const_ok_for_arm (~ (val | ~0xffff))) + val |= ~0xffff; + else if (val & 0x8000) + val |= ~0xffff; + } + + emit_insn (gen_movsi (reg, GEN_INT (val))); + operands[1] = gen_rtx_SUBREG (HImode, reg, 0); + } + else if (! arm_arch4) + { + /* Note: We do not have to worry about TARGET_SHORT_BY_BYTES + for v4 and up architectures because LDRH instructions will + be used to access the HI values, and these cannot generate + unaligned word access faults in the MMU. */ + if (GET_CODE (operands[1]) == MEM) + { + if (TARGET_SHORT_BY_BYTES) + { + rtx base; + rtx offset = const0_rtx; + rtx reg = gen_reg_rtx (SImode); + + if ((GET_CODE (base = XEXP (operands[1], 0)) == REG + || (GET_CODE (base) == PLUS + && GET_CODE (offset = XEXP (base, 1)) == CONST_INT + && ((INTVAL(offset) & 1) != 1) + && GET_CODE (base = XEXP (base, 0)) == REG)) + && REGNO_POINTER_ALIGN (REGNO (base)) >= 4) + { + HOST_WIDE_INT new_offset = INTVAL (offset) & ~3; + rtx new; + + new = gen_rtx_MEM (SImode, + plus_constant (base, new_offset)); + MEM_COPY_ATTRIBUTES (new, operands[1]); + RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (operands[1]); + emit_insn (gen_movsi (reg, new)); + if (((INTVAL (offset) & 2) != 0) + ^ (BYTES_BIG_ENDIAN ? 1 : 0)) + { + rtx reg2 = gen_reg_rtx (SImode); + + emit_insn (gen_lshrsi3 (reg2, reg, GEN_INT (16))); + reg = reg2; + } + } + else + emit_insn (gen_movhi_bytes (reg, operands[1])); + + operands[1] = gen_lowpart (HImode, reg); + } + else if (BYTES_BIG_ENDIAN) + { + rtx base; + rtx offset = const0_rtx; + + if ((GET_CODE (base = XEXP (operands[1], 0)) == REG + || (GET_CODE (base) == PLUS + && GET_CODE (offset = XEXP (base, 1)) == CONST_INT + && GET_CODE (base = XEXP (base, 0)) == REG)) + && REGNO_POINTER_ALIGN (REGNO (base)) >= 4) + { + rtx reg = gen_reg_rtx (SImode); + rtx new; + + if ((INTVAL (offset) & 2) == 2) + { + HOST_WIDE_INT new_offset = INTVAL (offset) ^ 2; + new = gen_rtx_MEM (SImode, + plus_constant (base, new_offset)); + MEM_COPY_ATTRIBUTES (new, operands[1]); + RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (operands[1]); + emit_insn (gen_movsi (reg, new)); + } + else + { + new = gen_rtx_MEM (SImode, XEXP (operands[1], 0)); + MEM_COPY_ATTRIBUTES (new, operands[1]); + RTX_UNCHANGING_P (new) + = RTX_UNCHANGING_P (operands[1]); + emit_insn (gen_rotated_loadsi (reg, new)); + } + + operands[1] = gen_lowpart (HImode, reg); + } + else + { + emit_insn (gen_movhi_bigend (operands[0], operands[1])); + DONE; + } + } + } + } + } + /* Handle loading a large integer during reload */ + else if (GET_CODE (operands[1]) == CONST_INT + && ! const_ok_for_arm (INTVAL (operands[1])) + && ! const_ok_for_arm (~INTVAL (operands[1]))) + { + /* Writing a constant to memory needs a scratch, which should + be handled with SECONDARY_RELOADs. */ + if (GET_CODE (operands[0]) != REG) + abort (); + + operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0); + emit_insn (gen_movsi (operands[0], operands[1])); + DONE; + } +} +") + +(define_insn "rotated_loadsi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (rotate:SI (match_operand:SI 1 "offsettable_memory_operand" "o") + (const_int 16)))] + "! TARGET_SHORT_BY_BYTES" + "* +{ + rtx ops[2]; + + ops[0] = operands[0]; + ops[1] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 2)); + output_asm_insn (\"ldr%?\\t%0, %1\\t%@ load-rotate\", ops); + return \"\"; +}" +[(set_attr "type" "load")]) + +(define_expand "movhi_bytes" + [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" ""))) + (set (match_dup 3) + (zero_extend:SI (match_dup 6))) + (set (match_operand:SI 0 "" "") + (ior:SI (ashift:SI (match_dup 4) (const_int 8)) (match_dup 5)))] + "" + " +{ + rtx mem1, mem2; + rtx addr = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); + + mem1 = gen_rtx (MEM, QImode, addr); + MEM_COPY_ATTRIBUTES (mem1, operands[1]); + RTX_UNCHANGING_P (mem1) = RTX_UNCHANGING_P (operands[1]); + mem2 = gen_rtx (MEM, QImode, plus_constant (addr, 1)); + MEM_COPY_ATTRIBUTES (mem2, operands[1]); + RTX_UNCHANGING_P (mem2) = RTX_UNCHANGING_P (operands[1]); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = mem1; + operands[2] = gen_reg_rtx (SImode); + operands[3] = gen_reg_rtx (SImode); + operands[6] = mem2; + + if (BYTES_BIG_ENDIAN) + { + operands[4] = operands[2]; + operands[5] = operands[3]; + } + else + { + operands[4] = operands[3]; + operands[5] = operands[2]; + } +} +") + +(define_expand "movhi_bigend" + [(set (match_dup 2) + (rotate:SI (subreg:SI (match_operand:HI 1 "memory_operand" "") 0) + (const_int 16))) + (set (match_dup 3) + (ashiftrt:SI (match_dup 2) (const_int 16))) + (set (match_operand:HI 0 "s_register_operand" "") + (subreg:HI (match_dup 3) 0))] + "" + " + operands[2] = gen_reg_rtx (SImode); + operands[3] = gen_reg_rtx (SImode); +") + +;; Pattern to recognise insn generated default case above +;; CYGNUS LOCAL nickc: Store before load to avoid problem with reload. +(define_insn "*movhi_insn_arch4" + [(set (match_operand:HI 0 "general_operand" "=r,r,m,r") + (match_operand:HI 1 "general_operand" "rI,K,r,m"))] + "arm_arch4 + && ok_integer_or_other (operands[0]) + && ok_integer_or_other (operands[1])" ;; CYGNUS LOCAL nickc + "@ + mov%?\\t%0, %1\\t%@ movhi + mvn%?\\t%0, #%B1\\t%@ movhi + str%?h\\t%1, %0\\t%@ movhi ;; CYGNUS LOCAL nickc + ldr%?h\\t%0, %1\\t%@ movhi" ;; CYGNUS LOCAL nickc +[(set_attr "type" "*,*,store1,load")]) ;; CYGNUS LOCAL nickc +;; END CYGNUS LOCAL + +(define_insn "*movhi_insn_littleend" + [(set (match_operand:HI 0 "general_operand" "=r,r,r") + (match_operand:HI 1 "general_operand" "rI,K,m"))] + "! arm_arch4 + && ! BYTES_BIG_ENDIAN + && ! TARGET_SHORT_BY_BYTES + /* CYGNUS LOCAL nickc */ + && ok_integer_or_other (operands[1])" + ;; END CYGNUS LOCAL nickc + "@ + mov%?\\t%0, %1\\t%@ movhi + mvn%?\\t%0, #%B1\\t%@ movhi + ldr%?\\t%0, %1\\t%@ movhi" +[(set_attr "type" "*,*,load")]) + +(define_insn "*movhi_insn_bigend" + [(set (match_operand:HI 0 "s_register_operand" "=r,r,r") + (match_operand:HI 1 "general_operand" "rI,K,m"))] + "! arm_arch4 + && BYTES_BIG_ENDIAN + && ! TARGET_SHORT_BY_BYTES + /* CYGNUS LOCAL NICKC */ + && ok_integer_or_other (operands[1])" + ;; END CYGNUS LOCAL + "@ + mov%?\\t%0, %1\\t%@ movhi + mvn%?\\t%0, #%B1\\t%@ movhi + ldr%?\\t%0, %1\\t%@ movhi_bigend\;mov%?\\t%0, %0, asr #16" +[(set_attr "type" "*,*,load") + (set_attr "length" "4,4,8")]) + +(define_insn "*loadhi_si_bigend" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (rotate:SI (subreg:SI (match_operand:HI 1 "memory_operand" "m") 0) + (const_int 16)))] + "BYTES_BIG_ENDIAN + && ! TARGET_SHORT_BY_BYTES" + "ldr%?\\t%0, %1\\t%@ movhi_bigend" +[(set_attr "type" "load")]) + +(define_insn "*movhi_bytes" + [(set (match_operand:HI 0 "s_register_operand" "=r,r") + (match_operand:HI 1 "arm_rhs_operand" "rI,K"))] + "TARGET_SHORT_BY_BYTES" + "@ + mov%?\\t%0, %1\\t%@ movhi + mvn%?\\t%0, #%B1\\t%@ movhi") + + +(define_expand "reload_outhi" + [(parallel [(match_operand:HI 0 "reload_memory_operand" "=o") + (match_operand:HI 1 "s_register_operand" "r") + (match_operand:SI 2 "s_register_operand" "=&r")])] + "" + " + arm_reload_out_hi (operands); + DONE; +") + +(define_expand "reload_inhi" + [(parallel [(match_operand:HI 0 "s_register_operand" "=r") + (match_operand:HI 1 "reload_memory_operand" "o") + (match_operand:SI 2 "s_register_operand" "=&r")])] + "TARGET_SHORT_BY_BYTES" + " + arm_reload_in_hi (operands); + DONE; +") + +(define_expand "movqi" + [(set (match_operand:QI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" + " + /* Everything except mem = const or mem = mem can be done easily */ + + if (!(reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[1]) == CONST_INT) + { + rtx reg = gen_reg_rtx (SImode); + + emit_insn (gen_movsi (reg, operands[1])); + operands[1] = gen_rtx (SUBREG, QImode, reg, 0); + } + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (QImode, operands[1]); + } +") + + +(define_insn "*movqi_insn" + [(set (match_operand:QI 0 "general_operand" "=r,r,r,m") + (match_operand:QI 1 "general_operand" "rI,K,m,r"))] + "register_operand (operands[0], QImode) + || register_operand (operands[1], QImode)" + "@ + mov%?\\t%0, %1 + mvn%?\\t%0, #%B1 + ldr%?b\\t%0, %1 + str%?b\\t%1, %0" +[(set_attr "type" "*,*,load,store1")]) + +(define_expand "movsf" + [(set (match_operand:SF 0 "general_operand" "") + (match_operand:SF 1 "general_operand" ""))] + "" + " + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (SFmode, operands[1]); +") + +(define_insn "*movsf_hard_insn" + [(set (match_operand:SF 0 "general_operand" "=f,f,f,m,f,r,r,r,m") + (match_operand:SF 1 "general_operand" "fG,H,mE,f,r,f,r,mE,r"))] + "TARGET_HARD_FLOAT + && (GET_CODE (operands[0]) != MEM || register_operand (operands[1], SFmode))" + "@ + mvf%?s\\t%0, %1 + mnf%?s\\t%0, #%N1 + ldf%?s\\t%0, %1 + stf%?s\\t%1, %0 + str%?\\t%1, [%|sp, #-4]!\;ldf%?s\\t%0, [%|sp], #4 + stf%?s\\t%1, [%|sp, #-4]!\;ldr%?\\t%0, [%|sp], #4 + mov%?\\t%0, %1 + ldr%?\\t%0, %1\\t%@ float + str%?\\t%1, %0\\t%@ float" +[(set_attr "length" "4,4,4,4,8,8,4,4,4") + (set_attr "type" + "ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r,*,load,store1")]) + +;; Exactly the same as above, except that all `f' cases are deleted. +;; This is necessary to prevent reload from ever trying to use a `f' reg +;; when -msoft-float. + +(define_insn "*movsf_soft_insn" + [(set (match_operand:SF 0 "general_operand" "=r,r,m") + (match_operand:SF 1 "general_operand" "r,mE,r"))] + "TARGET_SOFT_FLOAT + && (GET_CODE (operands[0]) != MEM || register_operand (operands[1], SFmode))" + "@ + mov%?\\t%0, %1 + ldr%?\\t%0, %1\\t%@ float + str%?\\t%1, %0\\t%@ float" +[(set_attr "length" "4,4,4") + (set_attr "type" "*,load,store1")]) + +(define_expand "movdf" + [(set (match_operand:DF 0 "general_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "" + " + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (DFmode, operands[1]); +") + +;; Reloading a df mode value stored in integer regs to memory can require a +;; scratch reg. +(define_expand "reload_outdf" + [(match_operand:DF 0 "reload_memory_operand" "=o") + (match_operand:DF 1 "s_register_operand" "r") + (match_operand:SI 2 "s_register_operand" "=&r")] + "" + " +{ + enum rtx_code code = GET_CODE (XEXP (operands[0], 0)); + + if (code == REG) + operands[2] = XEXP (operands[0], 0); + else if (code == POST_INC || code == PRE_DEC) + { + operands[0] = gen_rtx (SUBREG, DImode, operands[0], 0); + operands[1] = gen_rtx (SUBREG, DImode, operands[1], 0); + emit_insn (gen_movdi (operands[0], operands[1])); + DONE; + } + else if (code == PRE_INC) + { + rtx reg = XEXP (XEXP (operands[0], 0), 0); + emit_insn (gen_addsi3 (reg, reg, GEN_INT (8))); + operands[2] = reg; + } + else if (code == POST_DEC) + operands[2] = XEXP (XEXP (operands[0], 0), 0); + else + emit_insn (gen_addsi3 (operands[2], XEXP (XEXP (operands[0], 0), 0), + XEXP (XEXP (operands[0], 0), 1))); + + emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (MEM, DFmode, operands[2]), + operands[1])); + + if (code == POST_DEC) + emit_insn (gen_addsi3 (operands[2], operands[2], GEN_INT (-8))); + + DONE; +} +") + +(define_insn "*movdf_hard_insn" + [(set (match_operand:DF 0 "general_operand" "=r,Q,r,m,r,f,f,f,m,!f,!r") + (match_operand:DF 1 "general_operand" "Q,r,r,r,mF,fG,H,mF,f,r,f"))] + "TARGET_HARD_FLOAT + && (GET_CODE (operands[0]) != MEM + || register_operand (operands[1], DFmode))" + "* +{ + rtx ops[3]; + + switch (which_alternative) + { + case 0: return \"ldm%?ia\\t%m1, %M0\\t%@ double\"; + case 1: return \"stm%?ia\\t%m0, %M1\\t%@ double\"; + case 2: case 3: case 4: return output_move_double (operands); + case 5: return \"mvf%?d\\t%0, %1\"; + case 6: return \"mnf%?d\\t%0, #%N1\"; + case 7: return \"ldf%?d\\t%0, %1\"; + case 8: return \"stf%?d\\t%1, %0\"; + case 9: return output_mov_double_fpu_from_arm (operands); + case 10: return output_mov_double_arm_from_fpu (operands); + } +} +" +[(set_attr "length" "4,4,8,8,8,4,4,4,4,8,8") + (set_attr "type" +"load,store2,*,store2,load,ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r")]) + +;; Software floating point version. This is essentially the same as movdi. +;; Do not use `f' as a constraint to prevent reload from ever trying to use +;; an `f' reg. + +(define_insn "*movdf_soft_insn" + [(set (match_operand:DF 0 "soft_df_operand" "=r,r,m") + (match_operand:DF 1 "soft_df_operand" "r,mF,r"))] + "TARGET_SOFT_FLOAT" + "* return output_move_double (operands);" +[(set_attr "length" "8,8,8") + (set_attr "type" "*,load,store2")]) + +(define_expand "movxf" + [(set (match_operand:XF 0 "general_operand" "") + (match_operand:XF 1 "general_operand" ""))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "") + +;; Even when the XFmode patterns aren't enabled, we enable this after +;; reloading so that we can push floating point registers in the prologue. + +(define_insn "*movxf_hard_insn" + [(set (match_operand:XF 0 "general_operand" "=f,f,f,m,f,r,r") + (match_operand:XF 1 "general_operand" "fG,H,m,f,r,f,r"))] + "TARGET_HARD_FLOAT && (ENABLE_XF_PATTERNS || reload_completed)" + "* + switch (which_alternative) + { + case 0: return \"mvf%?e\\t%0, %1\"; + case 1: return \"mnf%?e\\t%0, #%N1\"; + case 2: return \"ldf%?e\\t%0, %1\"; + case 3: return \"stf%?e\\t%1, %0\"; + case 4: return output_mov_long_double_fpu_from_arm (operands); + case 5: return output_mov_long_double_arm_from_fpu (operands); + case 6: return output_mov_long_double_arm_from_arm (operands); + } +" +[(set_attr "length" "4,4,4,4,8,8,12") + (set_attr "type" "ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r,*")]) + + +;; load- and store-multiple insns +;; The arm can load/store any set of registers, provided that they are in +;; ascending order; but that is beyond GCC so stick with what it knows. + +(define_expand "load_multiple" + [(match_par_dup 3 [(set (match_operand:SI 0 "" "") + (match_operand:SI 1 "" "")) + (use (match_operand:SI 2 "" ""))])] + "" + " + /* Support only fixed point registers */ + if (GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) > 14 + || INTVAL (operands[2]) < 2 + || GET_CODE (operands[1]) != MEM + || GET_CODE (operands[0]) != REG + || REGNO (operands[0]) > 14 + || REGNO (operands[0]) + INTVAL (operands[2]) > 15) + FAIL; + + operands[3] + = arm_gen_load_multiple (REGNO (operands[0]), INTVAL (operands[2]), + force_reg (SImode, XEXP (operands[1], 0)), + TRUE, FALSE, RTX_UNCHANGING_P(operands[1]), + MEM_IN_STRUCT_P(operands[1]), + MEM_SCALAR_P (operands[1])); +") + +;; Load multiple with write-back + +(define_insn "*ldmsi_postinc" + [(match_parallel 0 "load_multiple_operation" + [(set (match_operand:SI 1 "s_register_operand" "+r") + (plus:SI (match_dup 1) + (match_operand:SI 2 "const_int_operand" "n"))) + (set (match_operand:SI 3 "s_register_operand" "=r") + (mem:SI (match_dup 1)))])] + "(INTVAL (operands[2]) == 4 * (XVECLEN (operands[0], 0) - 2))" + "* +{ + rtx ops[3]; + int count = XVECLEN (operands[0], 0); + + ops[0] = XEXP (SET_SRC (XVECEXP (operands[0], 0, 0)), 0); + ops[1] = SET_DEST (XVECEXP (operands[0], 0, 1)); + ops[2] = SET_DEST (XVECEXP (operands[0], 0, count - 2)); + + output_asm_insn (\"ldm%?ia\\t%0!, {%1-%2}\\t%@ load multiple\", ops); + return \"\"; +} +" +[(set_attr "type" "load")]) + +;; Ordinary load multiple + +(define_insn "*ldmsi" + [(match_parallel 0 "load_multiple_operation" + [(set (match_operand:SI 1 "s_register_operand" "=r") + (mem:SI (match_operand:SI 2 "s_register_operand" "r")))])] + "" + "* +{ + rtx ops[3]; + int count = XVECLEN (operands[0], 0); + + ops[0] = XEXP (SET_SRC (XVECEXP (operands[0], 0, 0)), 0); + ops[1] = SET_DEST (XVECEXP (operands[0], 0, 0)); + ops[2] = SET_DEST (XVECEXP (operands[0], 0, count - 1)); + + output_asm_insn (\"ldm%?ia\\t%0, {%1-%2}\\t%@ load multiple\", ops); + return \"\"; +} +" +[(set_attr "type" "load")]) + +(define_expand "store_multiple" + [(match_par_dup 3 [(set (match_operand:SI 0 "" "") + (match_operand:SI 1 "" "")) + (use (match_operand:SI 2 "" ""))])] + "" + " + /* Support only fixed point registers */ + if (GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) > 14 + || INTVAL (operands[2]) < 2 + || GET_CODE (operands[1]) != REG + || GET_CODE (operands[0]) != MEM + || REGNO (operands[1]) > 14 + || REGNO (operands[1]) + INTVAL (operands[2]) > 15) + FAIL; + + operands[3] + = arm_gen_store_multiple (REGNO (operands[1]), INTVAL (operands[2]), + force_reg (SImode, XEXP (operands[0], 0)), + TRUE, FALSE, RTX_UNCHANGING_P (operands[0]), + MEM_IN_STRUCT_P(operands[0]), + MEM_SCALAR_P (operands[0])); +") + +;; Store multiple with write-back + +(define_insn "*stmsi_postinc" + [(match_parallel 0 "store_multiple_operation" + [(set (match_operand:SI 1 "s_register_operand" "+r") + (plus:SI (match_dup 1) + (match_operand:SI 2 "const_int_operand" "n"))) + (set (mem:SI (match_dup 1)) + (match_operand:SI 3 "s_register_operand" "r"))])] + "(INTVAL (operands[2]) == 4 * (XVECLEN (operands[0], 0) - 2))" + "* +{ + rtx ops[3]; + int count = XVECLEN (operands[0], 0); + + ops[0] = XEXP (SET_SRC (XVECEXP (operands[0], 0, 0)), 0); + ops[1] = SET_SRC (XVECEXP (operands[0], 0, 1)); + ops[2] = SET_SRC (XVECEXP (operands[0], 0, count - 2)); + + output_asm_insn (\"stm%?ia\\t%0!, {%1-%2}\\t%@ str multiple\", ops); + return \"\"; +} +" +[(set (attr "type") + (cond [(eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 4)) + (const_string "store2") + (eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 5)) + (const_string "store3")] + (const_string "store4")))]) + +;; Ordinary store multiple + +(define_insn "*stmsi" + [(match_parallel 0 "store_multiple_operation" + [(set (mem:SI (match_operand:SI 2 "s_register_operand" "r")) + (match_operand:SI 1 "s_register_operand" "r"))])] + "" + "* +{ + rtx ops[3]; + int count = XVECLEN (operands[0], 0); + + ops[0] = XEXP (SET_DEST (XVECEXP (operands[0], 0, 0)), 0); + ops[1] = SET_SRC (XVECEXP (operands[0], 0, 0)); + ops[2] = SET_SRC (XVECEXP (operands[0], 0, count - 1)); + + output_asm_insn (\"stm%?ia\\t%0, {%1-%2}\\t%@ str multiple\", ops); + return \"\"; +} +" +[(set (attr "type") + (cond [(eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 3)) + (const_string "store2") + (eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 4)) + (const_string "store3")] + (const_string "store4")))]) + +;; Move a block of memory if it is word aligned and MORE than 2 words long. +;; We could let this apply for blocks of less than this, but it clobbers so +;; many registers that there is then probably a better way. + +(define_expand "movstrqi" + [(match_operand:BLK 0 "general_operand" "") + (match_operand:BLK 1 "general_operand" "") + (match_operand:SI 2 "const_int_operand" "") + (match_operand:SI 3 "const_int_operand" "")] + "" + " + if (arm_gen_movstrqi (operands)) + DONE; + FAIL; +") + + +;; Comparison and test insns + +(define_expand "cmpsi" + [(match_operand:SI 0 "s_register_operand" "") + (match_operand:SI 1 "arm_add_operand" "")] + "" + " +{ + arm_compare_op0 = operands[0]; + arm_compare_op1 = operands[1]; + arm_compare_fp = 0; + DONE; +} +") + +(define_expand "cmpsf" + [(match_operand:SF 0 "s_register_operand" "") + (match_operand:SF 1 "fpu_rhs_operand" "")] + "TARGET_HARD_FLOAT" + " +{ + arm_compare_op0 = operands[0]; + arm_compare_op1 = operands[1]; + arm_compare_fp = 1; + DONE; +} +") + +(define_expand "cmpdf" + [(match_operand:DF 0 "s_register_operand" "") + (match_operand:DF 1 "fpu_rhs_operand" "")] + "TARGET_HARD_FLOAT" + " +{ + arm_compare_op0 = operands[0]; + arm_compare_op1 = operands[1]; + arm_compare_fp = 1; + DONE; +} +") + +(define_expand "cmpxf" + [(match_operand:XF 0 "s_register_operand" "") + (match_operand:XF 1 "fpu_rhs_operand" "")] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + " +{ + arm_compare_op0 = operands[0]; + arm_compare_op1 = operands[1]; + arm_compare_fp = 1; + DONE; +} +") + +(define_insn "*cmpsi_insn" + [(set (reg:CC 24) + (compare:CC (match_operand:SI 0 "s_register_operand" "r,r") + (match_operand:SI 1 "arm_add_operand" "rI,L")))] + "" + "@ + cmp%?\\t%0, %1 + cmn%?\\t%0, #%n1" +[(set_attr "conds" "set")]) + +(define_insn "*cmpsi_shiftsi" + [(set (reg:CC 24) + (compare:CC (match_operand:SI 0 "s_register_operand" "r") + (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")])))] + "" + "cmp%?\\t%0, %1%S3" +[(set_attr "conds" "set")]) + +(define_insn "*cmpsi_shiftsi_swp" + [(set (reg:CC_SWP 24) + (compare:CC_SWP (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "reg_or_int_operand" "rM")]) + (match_operand:SI 0 "s_register_operand" "r")))] + "" + "cmp%?\\t%0, %1%S3" +[(set_attr "conds" "set")]) + +(define_insn "*cmpsi_neg_shiftsi" + [(set (reg:CC 24) + (compare:CC (match_operand:SI 0 "s_register_operand" "r") + (neg:SI (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")]))))] + "" + "cmn%?\\t%0, %1%S3" +[(set_attr "conds" "set")]) + +(define_insn "*cmpsf_insn" + [(set (reg:CCFP 24) + (compare:CCFP (match_operand:SF 0 "s_register_operand" "f,f") + (match_operand:SF 1 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + cmf%?\\t%0, %1 + cnf%?\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmpdf_insn" + [(set (reg:CCFP 24) + (compare:CCFP (match_operand:DF 0 "s_register_operand" "f,f") + (match_operand:DF 1 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + cmf%?\\t%0, %1 + cnf%?\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmpesfdf_df" + [(set (reg:CCFP 24) + (compare:CCFP (float_extend:DF + (match_operand:SF 0 "s_register_operand" "f,f")) + (match_operand:DF 1 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + cmf%?\\t%0, %1 + cnf%?\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmpdf_esfdf" + [(set (reg:CCFP 24) + (compare:CCFP (match_operand:DF 0 "s_register_operand" "f") + (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "cmf%?\\t%0, %1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmpxf_insn" + [(set (reg:CCFP 24) + (compare:CCFP (match_operand:XF 0 "s_register_operand" "f,f") + (match_operand:XF 1 "fpu_add_operand" "fG,H")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "@ + cmf%?\\t%0, %1 + cnf%?\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmpsf_trap" + [(set (reg:CCFPE 24) + (compare:CCFPE (match_operand:SF 0 "s_register_operand" "f,f") + (match_operand:SF 1 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + cmf%?e\\t%0, %1 + cnf%?e\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmpdf_trap" + [(set (reg:CCFPE 24) + (compare:CCFPE (match_operand:DF 0 "s_register_operand" "f,f") + (match_operand:DF 1 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + cmf%?e\\t%0, %1 + cnf%?e\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmp_esfdf_df_trap" + [(set (reg:CCFPE 24) + (compare:CCFPE (float_extend:DF + (match_operand:SF 0 "s_register_operand" "f,f")) + (match_operand:DF 1 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + cmf%?e\\t%0, %1 + cnf%?e\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmp_df_esfdf_trap" + [(set (reg:CCFPE 24) + (compare:CCFPE (match_operand:DF 0 "s_register_operand" "f") + (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "cmf%?e\\t%0, %1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmpxf_trap" + [(set (reg:CCFPE 24) + (compare:CCFPE (match_operand:XF 0 "s_register_operand" "f,f") + (match_operand:XF 1 "fpu_add_operand" "fG,H")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "@ + cmf%?e\\t%0, %1 + cnf%?e\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +; This insn allows redundant compares to be removed by cse, nothing should +; ever appear in the output file since (set (reg x) (reg x)) is a no-op that +; is deleted later on. The match_dup will match the mode here, so that +; mode changes of the condition codes aren't lost by this even though we don't +; specify what they are. + +(define_insn "*deleted_compare" + [(set (match_operand 0 "cc_register" "") (match_dup 0))] + "" + "\\t%@ deleted compare" +[(set_attr "conds" "set") + (set_attr "length" "0")]) + + +;; Conditional branch insns + +(define_expand "beq" + [(set (pc) + (if_then_else (eq (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (EQ, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "bne" + [(set (pc) + (if_then_else (ne (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (NE, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "bgt" + [(set (pc) + (if_then_else (gt (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (GT, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "ble" + [(set (pc) + (if_then_else (le (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (LE, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "bge" + [(set (pc) + (if_then_else (ge (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (GE, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "blt" + [(set (pc) + (if_then_else (lt (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (LT, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "bgtu" + [(set (pc) + (if_then_else (gtu (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (GTU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "bleu" + [(set (pc) + (if_then_else (leu (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (LEU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "bgeu" + [(set (pc) + (if_then_else (geu (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (GEU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "bltu" + [(set (pc) + (if_then_else (ltu (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (LTU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +;; patterns to match conditional branch insns + +(define_insn "*condbranch" + [(set (pc) + (if_then_else (match_operator 1 "comparison_operator" + [(match_operand 2 "cc_register" "") (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + extern int arm_ccfsm_state; + + if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2) + { + arm_ccfsm_state += 2; + return \"\"; + } + return \"b%d1\\t%l0\"; +}" +[(set_attr "conds" "use")]) + +(define_insn "*condbranch_reversed" + [(set (pc) + (if_then_else (match_operator 1 "comparison_operator" + [(match_operand 2 "cc_register" "") (const_int 0)]) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + extern int arm_ccfsm_state; + + if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2) + { + arm_ccfsm_state += 2; + return \"\"; + } + return \"b%D1\\t%l0\"; +}" +[(set_attr "conds" "use")]) + + +; scc insns + +(define_expand "seq" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (eq:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (EQ, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sne" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (ne:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (NE, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sgt" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (gt:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (GT, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sle" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (le:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (LE, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sge" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (ge:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (GE, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "slt" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (lt:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (LT, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sgtu" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (gtu:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (GTU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sleu" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (leu:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (LEU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sgeu" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (geu:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (GEU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sltu" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (ltu:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (LTU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_insn "*mov_scc" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operator:SI 1 "comparison_operator" + [(match_operand 2 "cc_register" "") (const_int 0)]))] + "" + "mov%D1\\t%0, #0\;mov%d1\\t%0, #1" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + +(define_insn "*mov_negscc" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (neg:SI (match_operator:SI 1 "comparison_operator" + [(match_operand 2 "cc_register" "") (const_int 0)])))] + "" + "mov%D1\\t%0, #0\;mvn%d1\\t%0, #0" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + +(define_insn "*mov_notscc" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (not:SI (match_operator:SI 1 "comparison_operator" + [(match_operand 2 "cc_register" "") (const_int 0)])))] + "" + "mov%D1\\t%0, #0\;mvn%d1\\t%0, #1" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + + +;; Conditional move insns + +(define_expand "movsicc" + [(set (match_operand:SI 0 "s_register_operand" "") + (if_then_else:SI (match_operand 1 "comparison_operator" "") + (match_operand:SI 2 "arm_not_operand" "") + (match_operand:SI 3 "arm_not_operand" "")))] + "" + " +{ + enum rtx_code code = GET_CODE (operands[1]); + rtx ccreg = gen_compare_reg (code, arm_compare_op0, arm_compare_op1, + arm_compare_fp); + + operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); +}") + +(define_expand "movsfcc" + [(set (match_operand:SF 0 "s_register_operand" "") + (if_then_else:SF (match_operand 1 "comparison_operator" "") + (match_operand:SF 2 "s_register_operand" "") + (match_operand:SF 3 "nonmemory_operand" "")))] + "" + " +{ + enum rtx_code code = GET_CODE (operands[1]); + rtx ccreg; + + /* When compiling for SOFT_FLOAT, ensure both arms are in registers. + Otherwise, ensure it is a valid FP add operand */ + if ((! TARGET_HARD_FLOAT) + || (! fpu_add_operand (operands[3], SFmode))) + operands[3] = force_reg (SFmode, operands[3]); + + ccreg = gen_compare_reg (code, arm_compare_op0, arm_compare_op1, + arm_compare_fp); + + operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); +}") + +(define_expand "movdfcc" + [(set (match_operand:DF 0 "s_register_operand" "") + (if_then_else:DF (match_operand 1 "comparison_operator" "") + (match_operand:DF 2 "s_register_operand" "") + (match_operand:DF 3 "fpu_add_operand" "")))] + "TARGET_HARD_FLOAT" + " +{ + enum rtx_code code = GET_CODE (operands[1]); + rtx ccreg = gen_compare_reg (code, arm_compare_op0, arm_compare_op1, + arm_compare_fp); + + operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); +}") + +(define_insn "*movsicc_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r,r,r,r,r") + (if_then_else:SI + (match_operator 3 "comparison_operator" + [(match_operand 4 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_not_operand" "0,0,rI,K,rI,rI,K,K") + (match_operand:SI 2 "arm_not_operand" "rI,K,0,0,rI,K,rI,K")))] + "" + "@ + mov%D3\\t%0, %2 + mvn%D3\\t%0, #%B2 + mov%d3\\t%0, %1 + mvn%d3\\t%0, #%B1 + mov%d3\\t%0, %1\;mov%D3\\t%0, %2 + mov%d3\\t%0, %1\;mvn%D3\\t%0, #%B2 + mvn%d3\\t%0, #%B1\;mov%D3\\t%0, %2 + mvn%d3\\t%0, #%B1\;mvn%D3\\t%0, #%B2" + [(set_attr "length" "4,4,4,4,8,8,8,8") + (set_attr "conds" "use")]) + +(define_insn "*movsfcc_hard_insn" + [(set (match_operand:SF 0 "s_register_operand" "=f,f,f,f,f,f,f,f") + (if_then_else:SF + (match_operator 3 "comparison_operator" + [(match_operand 4 "cc_register" "") (const_int 0)]) + (match_operand:SF 1 "fpu_add_operand" "0,0,fG,H,fG,fG,H,H") + (match_operand:SF 2 "fpu_add_operand" "fG,H,0,0,fG,H,fG,H")))] + "TARGET_HARD_FLOAT" + "@ + mvf%D3s\\t%0, %2 + mnf%D3s\\t%0, #%N2 + mvf%d3s\\t%0, %1 + mnf%d3s\\t%0, #%N1 + mvf%d3s\\t%0, %1\;mvf%D3s\\t%0, %2 + mvf%d3s\\t%0, %1\;mnf%D3s\\t%0, #%N2 + mnf%d3s\\t%0, #%N1\;mvf%D3s\\t%0, %2 + mnf%d3s\\t%0, #%N1\;mnf%D3s\\t%0, #%N2" + [(set_attr "length" "4,4,4,4,8,8,8,8") + (set_attr "type" "ffarith") + (set_attr "conds" "use")]) + +(define_insn "*movsfcc_soft_insn" + [(set (match_operand:SF 0 "s_register_operand" "=r,r") + (if_then_else:SF (match_operator 3 "comparison_operator" + [(match_operand 4 "cc_register" "") (const_int 0)]) + (match_operand:SF 1 "s_register_operand" "0,r") + (match_operand:SF 2 "s_register_operand" "r,0")))] + "TARGET_SOFT_FLOAT" + "@ + mov%D3\\t%0, %2 + mov%d3\\t%0, %1" + [(set_attr "conds" "use")]) + +(define_insn "*movdfcc_insn" + [(set (match_operand:DF 0 "s_register_operand" "=f,f,f,f,f,f,f,f") + (if_then_else:DF + (match_operator 3 "comparison_operator" + [(match_operand 4 "cc_register" "") (const_int 0)]) + (match_operand:DF 1 "fpu_add_operand" "0,0,fG,H,fG,fG,H,H") + (match_operand:DF 2 "fpu_add_operand" "fG,H,0,0,fG,H,fG,H")))] + "TARGET_HARD_FLOAT" + "@ + mvf%D3d\\t%0, %2 + mnf%D3d\\t%0, #%N2 + mvf%d3d\\t%0, %1 + mnf%d3d\\t%0, #%N1 + mvf%d3d\\t%0, %1\;mvf%D3d\\t%0, %2 + mvf%d3d\\t%0, %1\;mnf%D3d\\t%0, #%N2 + mnf%d3d\\t%0, #%N1\;mvf%D3d\\t%0, %2 + mnf%d3d\\t%0, #%N1\;mnf%D3d\\t%0, #%N2" + [(set_attr "length" "4,4,4,4,8,8,8,8") + (set_attr "type" "ffarith") + (set_attr "conds" "use")]) + +;; Jump and linkage insns + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "* +{ + extern int arm_ccfsm_state; + + if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2) + { + arm_ccfsm_state += 2; + return \"\"; + } + return \"b%?\\t%l0\"; +}") + +(define_expand "call" + [(parallel [(call (match_operand 0 "memory_operand" "") + (match_operand 1 "general_operand" "")) + (use (match_operand 2 "" "")) + (clobber (reg:SI 14))])] + "" + " +{ + if (GET_CODE (XEXP (operands[0], 0)) != REG + && arm_is_longcall_p (operands[0], INTVAL (operands[2]), 0)) + XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0)); +}") + +(define_insn "*call_reg" + [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r")) + (match_operand 1 "" "g")) + (use (match_operand 2 "" "")) + (clobber (reg:SI 14))] + "" + "* + return output_call (operands); +" +;; length is worst case, normally it is only two +[(set_attr "length" "12") + (set_attr "type" "call")]) + +(define_insn "*call_mem" + [(call (mem:SI (match_operand 0 "memory_operand" "m")) + (match_operand 1 "general_operand" "g")) + (use (match_operand 2 "" "")) + (clobber (reg:SI 14))] + "" + "* + return output_call_mem (operands); +" +[(set_attr "length" "12") + (set_attr "type" "call")]) + +(define_expand "call_value" + [(parallel [(set (match_operand 0 "" "=rf") + (call (match_operand 1 "memory_operand" "m") + (match_operand 2 "general_operand" "g"))) + (use (match_operand 3 "" "")) + (clobber (reg:SI 14))])] + "" + " +{ + if (GET_CODE (XEXP (operands[1], 0)) != REG + && arm_is_longcall_p (operands[1], INTVAL (operands[3]), 0)) + XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0)); +}") + +(define_insn "*call_value_reg" + [(set (match_operand 0 "" "=rf") + (call (mem:SI (match_operand:SI 1 "s_register_operand" "r")) + (match_operand 2 "general_operand" "g"))) + (use (match_operand 3 "" "")) + (clobber (reg:SI 14))] + "" + "* + return output_call (&operands[1]); +" +[(set_attr "length" "12") + (set_attr "type" "call")]) + +(define_insn "*call_value_mem" + [(set (match_operand 0 "" "=rf") + (call (mem:SI (match_operand 1 "memory_operand" "m")) + (match_operand 2 "general_operand" "g"))) + (use (match_operand 3 "" "")) + (clobber (reg:SI 14))] + "! CONSTANT_ADDRESS_P (XEXP (operands[1], 0))" + "* + return output_call_mem (&operands[1]); +" +[(set_attr "length" "12") + (set_attr "type" "call")]) + +;; Allow calls to SYMBOL_REFs specially as they are not valid general addresses +;; The 'a' causes the operand to be treated as an address, i.e. no '#' output. + +(define_insn "*call_symbol" + [(call (mem:SI (match_operand:SI 0 "" "X")) + (match_operand:SI 1 "general_operand" "g")) + (use (match_operand 2 "" "")) + (clobber (reg:SI 14))] + "GET_CODE (operands[0]) == SYMBOL_REF + && ! arm_is_longcall_p (operands[0], INTVAL (operands[2]), 1)" + "bl%?\\t%a0" +[(set_attr "type" "call")]) + +(define_insn "*call_value_symbol" + [(set (match_operand 0 "s_register_operand" "=rf") + (call (mem:SI (match_operand:SI 1 "" "X")) + (match_operand:SI 2 "general_operand" "g"))) + (use (match_operand 3 "" "")) + (clobber (reg:SI 14))] + "GET_CODE(operands[1]) == SYMBOL_REF + && ! arm_is_longcall_p (operands[1], INTVAL (operands[3]), 1)" + "bl%?\\t%a1" +[(set_attr "type" "call")]) + +;; Often the return insn will be the same as loading from memory, so set attr +(define_insn "return" + [(return)] + "USE_RETURN_INSN (FALSE)" + "* +{ + extern int arm_ccfsm_state; + + if (arm_ccfsm_state == 2) + { + arm_ccfsm_state += 2; + return \"\"; + } + return output_return_instruction (NULL, TRUE, FALSE); +}" +[(set_attr "type" "load")]) + +(define_insn "*cond_return" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand 1 "cc_register" "") (const_int 0)]) + (return) + (pc)))] + "USE_RETURN_INSN (TRUE)" + "* +{ + extern int arm_ccfsm_state; + + if (arm_ccfsm_state == 2) + { + arm_ccfsm_state += 2; + return \"\"; + } + return output_return_instruction (operands[0], TRUE, FALSE); +}" +[(set_attr "conds" "use") + (set_attr "type" "load")]) + +(define_insn "*cond_return_inverted" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand 1 "cc_register" "") (const_int 0)]) + (pc) + (return)))] + "USE_RETURN_INSN (TRUE)" + "* +{ + extern int arm_ccfsm_state; + + if (arm_ccfsm_state == 2) + { + arm_ccfsm_state += 2; + return \"\"; + } + return output_return_instruction (operands[0], TRUE, TRUE); +}" +[(set_attr "conds" "use") + (set_attr "type" "load")]) + +;; Call subroutine returning any type. + +(define_expand "untyped_call" + [(parallel [(call (match_operand 0 "" "") + (const_int 0)) + (match_operand 1 "" "") + (match_operand 2 "" "")])] + "" + " +{ + int i; + + emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx)); + + for (i = 0; i < XVECLEN (operands[2], 0); i++) + { + rtx set = XVECEXP (operands[2], 0, i); + emit_move_insn (SET_DEST (set), SET_SRC (set)); + } + + /* The optimizer does not know that the call sets the function value + registers we stored in the result block. We avoid problems by + claiming that all hard registers are used and clobbered at this + point. */ + emit_insn (gen_blockage ()); + + DONE; +}") + +;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and +;; all of memory. This blocks insns from being moved across this point. + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] 0)] + "" + "" +[(set_attr "length" "0") + (set_attr "type" "block")]) + +(define_expand "casesi" + [(match_operand:SI 0 "s_register_operand" "") ; index to jump on + (match_operand:SI 1 "const_int_operand" "") ; lower bound + (match_operand:SI 2 "const_int_operand" "") ; total range + (match_operand:SI 3 "" "") ; table label + (match_operand:SI 4 "" "")] ; Out of range label + "" + " +{ + rtx reg; + if (operands[1] != const0_rtx) + { + reg = gen_reg_rtx (SImode); + emit_insn (gen_addsi3 (reg, operands[0], + GEN_INT (-INTVAL (operands[1])))); + operands[0] = reg; + } + + if (! const_ok_for_arm (INTVAL (operands[2]))) + operands[2] = force_reg (SImode, operands[2]); + + emit_jump_insn (gen_casesi_internal (operands[0], operands[2], operands[3], + operands[4])); + DONE; +}") + +;; The USE in this pattern is needed to tell flow analysis that this is +;; a CASESI insn. It has no other purpose. +(define_insn "casesi_internal" + [(parallel [(set (pc) + (if_then_else + (leu (match_operand:SI 0 "s_register_operand" "r") + (match_operand:SI 1 "arm_rhs_operand" "rI")) + (mem:SI (plus:SI (mult:SI (match_dup 0) (const_int 4)) + (label_ref (match_operand 2 "" "")))) + (label_ref (match_operand 3 "" "")))) + (use (label_ref (match_dup 2)))])] + "" + "* + if (flag_pic) + return \"cmp\\t%0, %1\;addls\\t%|pc, %|pc, %0, asl #2\;b\\t%l3\"; + return \"cmp\\t%0, %1\;ldrls\\t%|pc, [%|pc, %0, asl #2]\;b\\t%l3\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "indirect_jump" + [(set (pc) + (match_operand:SI 0 "s_register_operand" "r"))] + "" + "mov%?\\t%|pc, %0\\t%@ indirect jump") + +(define_insn "*load_indirect_jump" + [(set (pc) + (match_operand:SI 0 "memory_operand" "m"))] + "" + "ldr%?\\t%|pc, %0\\t%@ indirect jump" +[(set_attr "type" "load")]) + +;; Misc insns + +(define_insn "nop" + [(const_int 0)] + "" + "mov%?\\tr0, r0\\t%@ nop") + +;; Patterns to allow combination of arithmetic, cond code and shifts + +(define_insn "*arith_shiftsi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operator:SI 1 "shiftable_operator" + [(match_operator:SI 3 "shift_operator" + [(match_operand:SI 4 "s_register_operand" "r") + (match_operand:SI 5 "reg_or_int_operand" "rI")]) + (match_operand:SI 2 "s_register_operand" "r")]))] + "" + "%i1%?\\t%0, %2, %4%S3") + +(define_insn "*arith_shiftsi_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (match_operator:SI 1 "shiftable_operator" + [(match_operator:SI 3 "shift_operator" + [(match_operand:SI 4 "s_register_operand" "r") + (match_operand:SI 5 "reg_or_int_operand" "rI")]) + (match_operand:SI 2 "s_register_operand" "r")]) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (match_op_dup 1 [(match_op_dup 3 [(match_dup 4) (match_dup 5)]) + (match_dup 2)]))] + "" + "%i1%?s\\t%0, %2, %4%S3" +[(set_attr "conds" "set")]) + +(define_insn "*arith_shiftsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (match_operator:SI 1 "shiftable_operator" + [(match_operator:SI 3 "shift_operator" + [(match_operand:SI 4 "s_register_operand" "r") + (match_operand:SI 5 "reg_or_int_operand" "rI")]) + (match_operand:SI 2 "s_register_operand" "r")]) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "" + "%i1%?s\\t%0, %2, %4%S3" +[(set_attr "conds" "set")]) + +(define_insn "*sub_shiftsi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "reg_or_int_operand" "rM")])))] + "" + "sub%?\\t%0, %1, %3%S2") + +(define_insn "*sub_shiftsi_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (minus:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "reg_or_int_operand" "rM")])) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) + (match_dup 4)])))] + "" + "sub%?s\\t%0, %1, %3%S2" +[(set_attr "conds" "set")]) + +(define_insn "*sub_shiftsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (minus:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "reg_or_int_operand" "rM")])) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "" + "sub%?s\\t%0, %1, %3%S2" +[(set_attr "conds" "set")]) + +;; These variants of the above insns can occur if the first operand is the +;; frame pointer and we eliminate that. This is a kludge, but there doesn't +;; seem to be a way around it. Most of the predicates have to be null +;; because the format can be generated part way through reload, so +;; if we don't match it as soon as it becomes available, reload doesn't know +;; how to reload pseudos that haven't got hard registers; the constraints will +;; sort everything out. + +(define_insn "*reload_mulsi3" + [(set (match_operand:SI 0 "" "=&r") + (plus:SI (plus:SI (match_operator:SI 5 "shift_operator" + [(match_operand:SI 3 "" "r") + (match_operand:SI 4 "" "rM")]) + (match_operand:SI 2 "" "r")) + (match_operand:SI 1 "const_int_operand" "n")))] + "reload_in_progress" + "* + output_asm_insn (\"add%?\\t%0, %2, %3%S5\", operands); + operands[2] = operands[1]; + operands[1] = operands[0]; + return output_add_immediate (operands); +" +; we have no idea how long the add_immediate is, it could be up to 4. +[(set_attr "length" "20")]) + +(define_insn "*reload_mulsi_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (plus:SI + (plus:SI + (match_operator:SI 5 "shift_operator" + [(match_operand:SI 3 "" "r") + (match_operand:SI 4 "" "rM")]) + (match_operand:SI 1 "" "r")) + (match_operand:SI 2 "const_int_operand" "n")) + (const_int 0))) + (set (match_operand:SI 0 "" "=&r") + (plus:SI (plus:SI (match_op_dup 5 [(match_dup 3) (match_dup 4)]) + (match_dup 1)) + (match_dup 2)))] + "reload_in_progress" + "* + output_add_immediate (operands); + return \"add%?s\\t%0, %0, %3%S5\"; +" +[(set_attr "conds" "set") + (set_attr "length" "20")]) + +(define_insn "*reload_mulsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (plus:SI + (plus:SI + (match_operator:SI 5 "shift_operator" + [(match_operand:SI 3 "" "r") + (match_operand:SI 4 "" "rM")]) + (match_operand:SI 1 "" "r")) + (match_operand:SI 2 "const_int_operand" "n")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=&r"))] + "reload_in_progress" + "* + output_add_immediate (operands); + return \"add%?s\\t%0, %0, %3%S5\"; +" +[(set_attr "conds" "set") + (set_attr "length" "20")]) + +;; These are similar, but are needed when the mla pattern contains the +;; eliminated register as operand 3. + +(define_insn "*reload_muladdsi" + [(set (match_operand:SI 0 "" "=&r,&r") + (plus:SI (plus:SI (mult:SI (match_operand:SI 1 "" "%0,r") + (match_operand:SI 2 "" "r,r")) + (match_operand:SI 3 "" "r,r")) + (match_operand:SI 4 "const_int_operand" "n,n")))] + "reload_in_progress" + "* + output_asm_insn (\"mla%?\\t%0, %2, %1, %3\", operands); + operands[2] = operands[4]; + operands[1] = operands[0]; + return output_add_immediate (operands); +" +[(set_attr "length" "20") + (set_attr "type" "mult")]) + +(define_insn "*reload_muladdsi_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (plus:SI (plus:SI (mult:SI + (match_operand:SI 3 "" "r") + (match_operand:SI 4 "" "r")) + (match_operand:SI 1 "" "r")) + (match_operand:SI 2 "const_int_operand" "n")) + (const_int 0))) + (set (match_operand:SI 0 "" "=&r") + (plus:SI (plus:SI (mult:SI (match_dup 3) (match_dup 4)) (match_dup 1)) + (match_dup 2)))] + "reload_in_progress" + "* + output_add_immediate (operands); + output_asm_insn (\"mla%?s\\t%0, %3, %4, %0\", operands); + return \"\"; +" +[(set_attr "length" "20") + (set_attr "conds" "set") + (set_attr "type" "mult")]) + +(define_insn "*reload_muladdsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (plus:SI (plus:SI (mult:SI + (match_operand:SI 3 "" "r") + (match_operand:SI 4 "" "r")) + (match_operand:SI 1 "" "r")) + (match_operand:SI 2 "const_int_operand" "n")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=&r"))] + "reload_in_progress" + "* + output_add_immediate (operands); + return \"mla%?s\\t%0, %3, %4, %0\"; +" +[(set_attr "length" "20") + (set_attr "conds" "set") + (set_attr "type" "mult")]) + + + +(define_insn "*and_scc" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (and:SI (match_operator 1 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (match_operand:SI 2 "s_register_operand" "r")))] + "" + "mov%D1\\t%0, #0\;and%d1\\t%0, %2, #1" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + +(define_insn "*ior_scc" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (ior:SI (match_operator 2 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "s_register_operand" "0,?r")))] + "" + "@ + orr%d2\\t%0, %1, #1 + mov%D2\\t%0, %1\;orr%d2\\t%0, %1, #1" +[(set_attr "conds" "use") + (set_attr "length" "4,8")]) + +(define_insn "*compare_scc" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (match_operator 1 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_add_operand" "rI,L")])) + (clobber (reg:CC 24))] + "" + "* + if (GET_CODE (operands[1]) == LT && operands[3] == const0_rtx) + return \"mov\\t%0, %2, lsr #31\"; + + if (GET_CODE (operands[1]) == GE && operands[3] == const0_rtx) + return \"mvn\\t%0, %2\;mov\\t%0, %0, lsr #31\"; + + if (GET_CODE (operands[1]) == NE) + { + if (which_alternative == 1) + return \"adds\\t%0, %2, #%n3\;movne\\t%0, #1\"; + return \"subs\\t%0, %2, %3\;movne\\t%0, #1\"; + } + if (which_alternative == 1) + output_asm_insn (\"cmn\\t%2, #%n3\", operands); + else + output_asm_insn (\"cmp\\t%2, %3\", operands); + return \"mov%D1\\t%0, #0\;mov%d1\\t%0, #1\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "*cond_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI (match_operator 3 "equality_operator" + [(match_operator 4 "comparison_operator" + [(match_operand 5 "cc_register" "") (const_int 0)]) + (const_int 0)]) + (match_operand:SI 1 "arm_rhs_operand" "0,rI,?rI") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))] + "" + "* + if (GET_CODE (operands[3]) == NE) + { + if (which_alternative != 1) + output_asm_insn (\"mov%D4\\t%0, %2\", operands); + if (which_alternative != 0) + output_asm_insn (\"mov%d4\\t%0, %1\", operands); + return \"\"; + } + if (which_alternative != 0) + output_asm_insn (\"mov%D4\\t%0, %1\", operands); + if (which_alternative != 1) + output_asm_insn (\"mov%d4\\t%0, %2\", operands); + return \"\"; +" +[(set_attr "conds" "use") + (set_attr "length" "4,4,8")]) + +(define_insn "*cond_arith" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (match_operator:SI 5 "shiftable_operator" + [(match_operator:SI 4 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_rhs_operand" "rI,rI")]) + (match_operand:SI 1 "s_register_operand" "0,?r")])) + (clobber (reg:CC 24))] + "" + "* + if (GET_CODE (operands[4]) == LT && operands[3] == const0_rtx) + return \"%i5\\t%0, %1, %2, lsr #31\"; + + output_asm_insn (\"cmp\\t%2, %3\", operands); + if (GET_CODE (operands[5]) == AND) + output_asm_insn (\"mov%D4\\t%0, #0\", operands); + else if (GET_CODE (operands[5]) == MINUS) + output_asm_insn (\"rsb%D4\\t%0, %1, #0\", operands); + else if (which_alternative != 0) + output_asm_insn (\"mov%D4\\t%0, %1\", operands); + return \"%i5%d4\\t%0, %1, #1\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "*cond_sub" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (minus:SI (match_operand:SI 1 "s_register_operand" "0,?r") + (match_operator:SI 4 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_rhs_operand" "rI,rI")]))) + (clobber (reg:CC 24))] + "" + "* + output_asm_insn (\"cmp\\t%2, %3\", operands); + if (which_alternative != 0) + output_asm_insn (\"mov%D4\\t%0, %1\", operands); + return \"sub%d4\\t%0, %1, #1\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*cmp_ite0" + [(set (match_operand 6 "dominant_cc_register" "") + (compare + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand:SI 0 "s_register_operand" "r,r,r,r") + (match_operand:SI 1 "arm_add_operand" "rI,L,rI,L")]) + (match_operator:SI 5 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "r,r,r,r") + (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")]) + (const_int 0)) + (const_int 0)))] + "" + "* +{ + char* opcodes[4][2] = + { + {\"cmp\\t%2, %3\;cmp%d5\\t%0, %1\",\"cmp\\t%0, %1\;cmp%d4\\t%2, %3\"}, + {\"cmp\\t%2, %3\;cmn%d5\\t%0, #%n1\", \"cmn\\t%0, #%n1\;cmp%d4\\t%2, %3\"}, + {\"cmn\\t%2, #%n3\;cmp%d5\\t%0, %1\", \"cmp\\t%0, %1\;cmn%d4\\t%2, #%n3\"}, + {\"cmn\\t%2, #%n3\;cmn%d5\\t%0, #%n1\", + \"cmn\\t%0, #%n1\;cmn%d4\\t%2, #%n3\"} + }; + int swap = + comparison_dominates_p (GET_CODE (operands[5]), GET_CODE (operands[4])); + + return opcodes[which_alternative][swap]; +} +" +[(set_attr "conds" "set") + (set_attr "length" "8")]) + +(define_insn "*cmp_ite1" + [(set (match_operand 6 "dominant_cc_register" "") + (compare + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand:SI 0 "s_register_operand" "r,r,r,r") + (match_operand:SI 1 "arm_add_operand" "rI,L,rI,L")]) + (match_operator:SI 5 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "r,r,r,r") + (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")]) + (const_int 1)) + (const_int 0)))] + "" + "* +{ + char* opcodes[4][2] = + { + {\"cmp\\t%0, %1\;cmp%d4\\t%2, %3\", \"cmp\\t%2, %3\;cmp%D5\\t%0, %1\"}, + {\"cmn\\t%0, #%n1\;cmp%d4\\t%2, %3\", \"cmp\\t%2, %3\;cmn%D5\\t%0, #%n1\"}, + {\"cmp\\t%0, %1\;cmn%d4\\t%2, #%n3\", \"cmn\\t%2, #%n3\;cmp%D5\\t%0, %1\"}, + {\"cmn\\t%0, #%n1\;cmn%d4\\t%2, #%n3\", + \"cmn\\t%2, #%n3\;cmn%D5\\t%0, #%n1\"} + }; + int swap = + comparison_dominates_p (GET_CODE (operands[5]), + reverse_condition (GET_CODE (operands[4]))); + + return opcodes[which_alternative][swap]; +} +" +[(set_attr "conds" "set") + (set_attr "length" "8")]) + +(define_insn "*negscc" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (neg:SI (match_operator 3 "comparison_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rI")]))) + (clobber (reg:CC 24))] + "" + "* + if (GET_CODE (operands[3]) == LT && operands[3] == const0_rtx) + return \"mov\\t%0, %1, asr #31\"; + + if (GET_CODE (operands[3]) == NE) + return \"subs\\t%0, %1, %2\;mvnne\\t%0, #0\"; + + if (GET_CODE (operands[3]) == GT) + return \"subs\\t%0, %1, %2\;mvnne\\t%0, %0, asr #31\"; + + output_asm_insn (\"cmp\\t%1, %2\", operands); + output_asm_insn (\"mov%D3\\t%0, #0\", operands); + return \"mvn%d3\\t%0, #0\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "movcond" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand:SI 3 "s_register_operand" "r,r,r") + (match_operand:SI 4 "arm_add_operand" "rIL,rIL,rIL")]) + (match_operand:SI 1 "arm_rhs_operand" "0,rI,?rI") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) + (clobber (reg:CC 24))] + "" + "* + if (GET_CODE (operands[5]) == LT + && (operands[4] == const0_rtx)) + { + if (which_alternative != 1 && GET_CODE (operands[1]) == REG) + { + if (operands[2] == const0_rtx) + return \"and\\t%0, %1, %3, asr #31\"; + return \"ands\\t%0, %1, %3, asr #32\;movcc\\t%0, %2\"; + } + else if (which_alternative != 0 && GET_CODE (operands[2]) == REG) + { + if (operands[1] == const0_rtx) + return \"bic\\t%0, %2, %3, asr #31\"; + return \"bics\\t%0, %2, %3, asr #32\;movcs\\t%0, %1\"; + } + /* The only case that falls through to here is when both ops 1 & 2 + are constants */ + } + + if (GET_CODE (operands[5]) == GE + && (operands[4] == const0_rtx)) + { + if (which_alternative != 1 && GET_CODE (operands[1]) == REG) + { + if (operands[2] == const0_rtx) + return \"bic\\t%0, %1, %3, asr #31\"; + return \"bics\\t%0, %1, %3, asr #32\;movcs\\t%0, %2\"; + } + else if (which_alternative != 0 && GET_CODE (operands[2]) == REG) + { + if (operands[1] == const0_rtx) + return \"and\\t%0, %2, %3, asr #31\"; + return \"ands\\t%0, %2, %3, asr #32\;movcc\\t%0, %1\"; + } + /* The only case that falls through to here is when both ops 1 & 2 + are constants */ + } + if (GET_CODE (operands[4]) == CONST_INT + && !const_ok_for_arm (INTVAL (operands[4]))) + output_asm_insn (\"cmn\\t%3, #%n4\", operands); + else + output_asm_insn (\"cmp\\t%3, %4\", operands); + if (which_alternative != 0) + output_asm_insn (\"mov%d5\\t%0, %1\", operands); + if (which_alternative != 1) + output_asm_insn (\"mov%D5\\t%0, %2\", operands); + return \"\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "8,8,12")]) + +(define_insn "*ifcompare_plus_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI (match_operator 6 "comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r,r") + (match_operand:SI 5 "arm_add_operand" "rIL,rIL")]) + (plus:SI + (match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_add_operand" "rIL,rIL")) + (match_operand:SI 1 "arm_rhsm_operand" "0,?rIm"))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_plus_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r,r,r") + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand 5 "cc_register" "") (const_int 0)]) + (plus:SI + (match_operand:SI 2 "s_register_operand" "r,r,r,r,r,r") + (match_operand:SI 3 "arm_add_operand" "rI,L,rI,L,rI,L")) + (match_operand:SI 1 "arm_rhsm_operand" "0,0,?rI,?rI,m,m")))] + "" + "@ + add%d4\\t%0, %2, %3 + sub%d4\\t%0, %2, #%n3 + add%d4\\t%0, %2, %3\;mov%D4\\t%0, %1 + sub%d4\\t%0, %2, #%n3\;mov%D4\\t%0, %1 + add%d4\\t%0, %2, %3\;ldr%D4\\t%0, %1 + sub%d4\\t%0, %2, #%n3\;ldr%D4\\t%0, %1" +[(set_attr "conds" "use") + (set_attr "length" "4,4,8,8,8,8") + (set_attr "type" "*,*,*,*,load,load")]) + +(define_insn "*ifcompare_move_plus" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI (match_operator 6 "comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r,r") + (match_operand:SI 5 "arm_add_operand" "rIL,rIL")]) + (match_operand:SI 1 "arm_rhsm_operand" "0,?rIm") + (plus:SI + (match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_add_operand" "rIL,rIL")))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_move_plus" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r,r,r") + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand 5 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_rhsm_operand" "0,0,?rI,?rI,m,m") + (plus:SI + (match_operand:SI 2 "s_register_operand" "r,r,r,r,r,r") + (match_operand:SI 3 "arm_add_operand" "rI,L,rI,L,rI,L"))))] + "" + "@ + add%D4\\t%0, %2, %3 + sub%D4\\t%0, %2, #%n3 + add%D4\\t%0, %2, %3\;mov%d4\\t%0, %1 + sub%D4\\t%0, %2, #%n3\;mov%d4\\t%0, %1 + add%D4\\t%0, %2, %3\;ldr%d4\\t%0, %1 + sub%D4\\t%0, %2, #%n3\;ldr%d4\\t%0, %1" +[(set_attr "conds" "use") + (set_attr "length" "4,4,8,8,8,8") + (set_attr "type" "*,*,*,*,load,load")]) + +(define_insn "*ifcompare_arith_arith" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI (match_operator 9 "comparison_operator" + [(match_operand:SI 5 "s_register_operand" "r") + (match_operand:SI 6 "arm_add_operand" "rIL")]) + (match_operator:SI 8 "shiftable_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rI")]) + (match_operator:SI 7 "shiftable_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "arm_rhs_operand" "rI")]))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "*if_arith_arith" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI (match_operator 5 "comparison_operator" + [(match_operand 8 "cc_register" "") (const_int 0)]) + (match_operator:SI 6 "shiftable_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rI")]) + (match_operator:SI 7 "shiftable_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "arm_rhs_operand" "rI")])))] + "" + "%I6%d5\\t%0, %1, %2\;%I7%D5\\t%0, %3, %4" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + +(define_insn "*ifcompare_arith_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI (match_operator 6 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_add_operand" "rIL,rIL")]) + (match_operator:SI 7 "shiftable_operator" + [(match_operand:SI 4 "s_register_operand" "r,r") + (match_operand:SI 5 "arm_rhs_operand" "rI,rI")]) + (match_operand:SI 1 "arm_rhsm_operand" "0,?rIm"))) + (clobber (reg:CC 24))] + "" + "* + /* If we have an operation where (op x 0) is the identity operation and + the conditional operator is LT or GE and we are comparing against zero and + everything is in registers then we can do this in two instructions */ + if (operands[3] == const0_rtx + && GET_CODE (operands[7]) != AND + && GET_CODE (operands[5]) == REG + && GET_CODE (operands[1]) == REG + && REGNO (operands[1]) == REGNO (operands[4]) + && REGNO (operands[4]) != REGNO (operands[0])) + { + if (GET_CODE (operands[6]) == LT) + return \"and\\t%0, %5, %2, asr #31\;%I7\\t%0, %4, %0\"; + else if (GET_CODE (operands[6]) == GE) + return \"bic\\t%0, %5, %2, asr #31\;%I7\\t%0, %4, %0\"; + } + if (GET_CODE (operands[3]) == CONST_INT + && !const_ok_for_arm (INTVAL (operands[3]))) + output_asm_insn (\"cmn\\t%2, #%n3\", operands); + else + output_asm_insn (\"cmp\\t%2, %3\", operands); + output_asm_insn (\"%I7%d6\\t%0, %4, %5\", operands); + if (which_alternative != 0) + { + if (GET_CODE (operands[1]) == MEM) + return \"ldr%D6\\t%0, %1\"; + else + return \"mov%D6\\t%0, %1\"; + } + return \"\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_arith_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI (match_operator 4 "comparison_operator" + [(match_operand 6 "cc_register" "") (const_int 0)]) + (match_operator:SI 5 "shiftable_operator" + [(match_operand:SI 2 "s_register_operand" "r,r,r") + (match_operand:SI 3 "arm_rhs_operand" "rI,rI,rI")]) + (match_operand:SI 1 "arm_rhsm_operand" "0,?rI,m")))] + "" + "@ + %I5%d4\\t%0, %2, %3 + %I5%d4\\t%0, %2, %3\;mov%D4\\t%0, %1 + %I5%d4\\t%0, %2, %3\;ldr%D4\\t%0, %1" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8") + (set_attr "type" "*,*,load")]) + +(define_insn "*ifcompare_move_arith" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI (match_operator 6 "comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r,r") + (match_operand:SI 5 "arm_add_operand" "rIL,rIL")]) + (match_operand:SI 1 "arm_rhsm_operand" "0,?rIm") + (match_operator:SI 7 "shiftable_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_rhs_operand" "rI,rI")]))) + (clobber (reg:CC 24))] + "" + "* + /* If we have an operation where (op x 0) is the identity operation and + the conditional operator is LT or GE and we are comparing against zero and + everything is in registers then we can do this in two instructions */ + if (operands[5] == const0_rtx + && GET_CODE (operands[7]) != AND + && GET_CODE (operands[3]) == REG + && GET_CODE (operands[1]) == REG + && REGNO (operands[1]) == REGNO (operands[2]) + && REGNO (operands[2]) != REGNO (operands[0])) + { + if (GET_CODE (operands[6]) == GE) + return \"and\\t%0, %3, %4, asr #31\;%I7\\t%0, %2, %0\"; + else if (GET_CODE (operands[6]) == LT) + return \"bic\\t%0, %3, %4, asr #31\;%I7\\t%0, %2, %0\"; + } + + if (GET_CODE (operands[5]) == CONST_INT + && !const_ok_for_arm (INTVAL (operands[5]))) + output_asm_insn (\"cmn\\t%4, #%n5\", operands); + else + output_asm_insn (\"cmp\\t%4, %5\", operands); + + if (which_alternative != 0) + { + if (GET_CODE (operands[1]) == MEM) + output_asm_insn (\"ldr%d6\\t%0, %1\", operands); + else + output_asm_insn (\"mov%d6\\t%0, %1\", operands); + } + return \"%I7%D6\\t%0, %2, %3\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_move_arith" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand 6 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_rhsm_operand" "0,?rI,m") + (match_operator:SI 5 "shiftable_operator" + [(match_operand:SI 2 "s_register_operand" "r,r,r") + (match_operand:SI 3 "arm_rhs_operand" "rI,rI,rI")])))] + "" + "@ + %I5%D4\\t%0, %2, %3 + %I5%D4\\t%0, %2, %3\;mov%d4\\t%0, %1 + %I5%D4\\t%0, %2, %3\;ldr%d4\\t%0, %1" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8") + (set_attr "type" "*,*,load")]) + +(define_insn "*ifcompare_move_not" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand:SI 3 "s_register_operand" "r,r") + (match_operand:SI 4 "arm_add_operand" "rIL,rIL")]) + (match_operand:SI 1 "arm_not_operand" "0,?rIK") + (not:SI + (match_operand:SI 2 "s_register_operand" "r,r")))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_move_not" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_not_operand" "0,?rI,K") + (not:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))))] + "" + "@ + mvn%D4\\t%0, %2 + mov%d4\\t%0, %1\;mvn%D4\\t%0, %2 + mvn%d4\\t%0, #%B1\;mvn%D4\\t%0, %2" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8")]) + +(define_insn "*ifcompare_not_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand:SI 3 "s_register_operand" "r,r") + (match_operand:SI 4 "arm_add_operand" "rIL,rIL")]) + (not:SI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:SI 1 "arm_not_operand" "0,?rIK"))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_not_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (not:SI (match_operand:SI 2 "s_register_operand" "r,r,r")) + (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))] + "" + "@ + mvn%d4\\t%0, %2 + mov%D4\\t%0, %1\;mvn%d4\\t%0, %2 + mvn%D4\\t%0, #%B1\;mvn%d4\\t%0, %2" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8")]) + +(define_insn "*ifcompare_shift_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI + (match_operator 6 "comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r,r") + (match_operand:SI 5 "arm_add_operand" "rIL,rIL")]) + (match_operator:SI 7 "shift_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_rhs_operand" "rM,rM")]) + (match_operand:SI 1 "arm_not_operand" "0,?rIK"))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_shift_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand 6 "cc_register" "") (const_int 0)]) + (match_operator:SI 4 "shift_operator" + [(match_operand:SI 2 "s_register_operand" "r,r,r") + (match_operand:SI 3 "arm_rhs_operand" "rM,rM,rM")]) + (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))] + "" + "@ + mov%d5\\t%0, %2%S4 + mov%D5\\t%0, %1\;mov%d5\\t%0, %2%S4 + mvn%D5\\t%0, #%B1\;mov%d5\\t%0, %2%S4" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8")]) + +(define_insn "*ifcompare_move_shift" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI + (match_operator 6 "comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r,r") + (match_operand:SI 5 "arm_add_operand" "rIL,rIL")]) + (match_operand:SI 1 "arm_not_operand" "0,?rIK") + (match_operator:SI 7 "shift_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_rhs_operand" "rM,rM")]))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_move_shift" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand 6 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_not_operand" "0,?rI,K") + (match_operator:SI 4 "shift_operator" + [(match_operand:SI 2 "s_register_operand" "r,r,r") + (match_operand:SI 3 "arm_rhs_operand" "rM,rM,rM")])))] + "" + "@ + mov%D5\\t%0, %2%S4 + mov%d5\\t%0, %1\;mov%D5\\t%0, %2%S4 + mvn%d5\\t%0, #%B1\;mov%D5\\t%0, %2%S4" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8")]) + +(define_insn "*ifcompare_shift_shift" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI + (match_operator 7 "comparison_operator" + [(match_operand:SI 5 "s_register_operand" "r") + (match_operand:SI 6 "arm_add_operand" "rIL")]) + (match_operator:SI 8 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")]) + (match_operator:SI 9 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "arm_rhs_operand" "rM")]))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "*if_shift_shift" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand 8 "cc_register" "") (const_int 0)]) + (match_operator:SI 6 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")]) + (match_operator:SI 7 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "arm_rhs_operand" "rM")])))] + "" + "mov%d5\\t%0, %1%S6\;mov%D5\\t%0, %3%S7" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + +(define_insn "*ifcompare_not_arith" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI + (match_operator 6 "comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r") + (match_operand:SI 5 "arm_add_operand" "rIL")]) + (not:SI (match_operand:SI 1 "s_register_operand" "r")) + (match_operator:SI 7 "shiftable_operator" + [(match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 3 "arm_rhs_operand" "rI")]))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "*if_not_arith" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand 4 "cc_register" "") (const_int 0)]) + (not:SI (match_operand:SI 1 "s_register_operand" "r")) + (match_operator:SI 6 "shiftable_operator" + [(match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 3 "arm_rhs_operand" "rI")])))] + "" + "mvn%d5\\t%0, %1\;%I6%D5\\t%0, %2, %3" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + +(define_insn "*ifcompare_arith_not" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI + (match_operator 6 "comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r") + (match_operand:SI 5 "arm_add_operand" "rIL")]) + (match_operator:SI 7 "shiftable_operator" + [(match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 3 "arm_rhs_operand" "rI")]) + (not:SI (match_operand:SI 1 "s_register_operand" "r")))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "*if_arith_not" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand 4 "cc_register" "") (const_int 0)]) + (match_operator:SI 6 "shiftable_operator" + [(match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 3 "arm_rhs_operand" "rI")]) + (not:SI (match_operand:SI 1 "s_register_operand" "r"))))] + "" + "mvn%D5\\t%0, %1\;%I6%d5\\t%0, %2, %3" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + +(define_insn "*ifcompare_neg_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand:SI 3 "s_register_operand" "r,r") + (match_operand:SI 4 "arm_add_operand" "rIL,rIL")]) + (neg:SI (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:SI 1 "arm_not_operand" "0,?rIK"))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_neg_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (neg:SI (match_operand:SI 2 "s_register_operand" "r,r,r")) + (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))] + "" + "@ + rsb%d4\\t%0, %2, #0 + mov%D4\\t%0, %1\;rsb%d4\\t%0, %2, #0 + mvn%D4\\t%0, #%B1\;rsb%d4\\t%0, %2, #0" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8")]) + +(define_insn "*ifcompare_move_neg" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand:SI 3 "s_register_operand" "r,r") + (match_operand:SI 4 "arm_add_operand" "rIL,rIL")]) + (match_operand:SI 1 "arm_not_operand" "0,?rIK") + (neg:SI (match_operand:SI 2 "s_register_operand" "r,r")))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_move_neg" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_not_operand" "0,?rI,K") + (neg:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))))] + "" + "@ + rsb%D4\\t%0, %2, #0 + mov%d4\\t%0, %1\;rsb%D4\\t%0, %2, #0 + mvn%d4\\t%0, #%B1\;rsb%D4\\t%0, %2, #0" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8")]) + +(define_insn "*arith_adjacentmem" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operator:SI 1 "shiftable_operator" + [(match_operand:SI 2 "memory_operand" "m") + (match_operand:SI 3 "memory_operand" "m")])) + (clobber (match_scratch:SI 4 "=r"))] + "adjacent_mem_locations (operands[2], operands[3])" + "* +{ + rtx ldm[3]; + rtx arith[4]; + int val1 = 0, val2 = 0; + + if (REGNO (operands[0]) > REGNO (operands[4])) + { + ldm[1] = operands[4]; + ldm[2] = operands[0]; + } + else + { + ldm[1] = operands[0]; + ldm[2] = operands[4]; + } + if (GET_CODE (XEXP (operands[2], 0)) != REG) + val1 = INTVAL (XEXP (XEXP (operands[2], 0), 1)); + if (GET_CODE (XEXP (operands[3], 0)) != REG) + val2 = INTVAL (XEXP (XEXP (operands[3], 0), 1)); + arith[0] = operands[0]; + arith[3] = operands[1]; + if (val1 < val2) + { + arith[1] = ldm[1]; + arith[2] = ldm[2]; + } + else + { + arith[1] = ldm[2]; + arith[2] = ldm[1]; + } + if (val1 && val2) + { + rtx ops[3]; + ldm[0] = ops[0] = operands[4]; + ops[1] = XEXP (XEXP (operands[2], 0), 0); + ops[2] = XEXP (XEXP (operands[2], 0), 1); + output_add_immediate (ops); + if (val1 < val2) + output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm); + else + output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm); + } + else if (val1) + { + ldm[0] = XEXP (operands[3], 0); + if (val1 < val2) + output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm); + else + output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm); + } + else + { + ldm[0] = XEXP (operands[2], 0); + if (val1 < val2) + output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm); + else + output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm); + } + output_asm_insn (\"%I3%?\\t%0, %1, %2\", arith); + return \"\"; +} +" +[(set_attr "length" "12") + (set_attr "type" "load")]) + +;; the arm can support extended pre-inc instructions + +;; In all these cases, we use operands 0 and 1 for the register being +;; incremented because those are the operands that local-alloc will +;; tie and these are the pair most likely to be tieable (and the ones +;; that will benefit the most). + +;; We reject the frame pointer if it occurs anywhere in these patterns since +;; elimination will cause too many headaches. + +(define_insn "*strqi_preinc" + [(set (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "index_operand" "rJ"))) + (match_operand:QI 3 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "str%?b\\t%3, [%0, %2]!" +[(set_attr "type" "store1")]) + +(define_insn "*strqi_predec" + [(set (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "r"))) + (match_operand:QI 3 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "str%?b\\t%3, [%0, -%2]!" +[(set_attr "type" "store1")]) + +(define_insn "*loadqi_preinc" + [(set (match_operand:QI 3 "s_register_operand" "=r") + (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "index_operand" "rJ")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?b\\t%3, [%0, %2]!" +[(set_attr "type" "load")]) + +(define_insn "*loadqi_predec" + [(set (match_operand:QI 3 "s_register_operand" "=r") + (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "r")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?b\\t%3, [%0, -%2]!" +[(set_attr "type" "load")]) + +(define_insn "*loadqisi_preinc" + [(set (match_operand:SI 3 "s_register_operand" "=r") + (zero_extend:SI + (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "index_operand" "rJ"))))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?b\\t%3, [%0, %2]!\\t%@ z_extendqisi" +[(set_attr "type" "load")]) + +(define_insn "*loadqisi_predec" + [(set (match_operand:SI 3 "s_register_operand" "=r") + (zero_extend:SI + (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "r"))))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?b\\t%3, [%0, -%2]!\\t%@ z_extendqisi" +[(set_attr "type" "load")]) + +(define_insn "*strsi_preinc" + [(set (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "index_operand" "rJ"))) + (match_operand:SI 3 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "str%?\\t%3, [%0, %2]!" +[(set_attr "type" "store1")]) + +(define_insn "*strqi_predec" + [(set (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "r"))) + (match_operand:SI 3 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "str%?\\t%3, [%0, -%2]!" +[(set_attr "type" "store1")]) + +(define_insn "*loadsi_preinc" + [(set (match_operand:SI 3 "s_register_operand" "=r") + (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "index_operand" "rJ")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?\\t%3, [%0, %2]!" +[(set_attr "type" "load")]) + +(define_insn "*loadsi_predec" + [(set (match_operand:SI 3 "s_register_operand" "=r") + (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "r")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?\\t%3, [%0, -%2]!" +[(set_attr "type" "load")]) + +(define_insn "*loadhi_preinc" + [(set (match_operand:HI 3 "s_register_operand" "=r") + (mem:HI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "index_operand" "rJ")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_dup 1) (match_dup 2)))] + "(! BYTES_BIG_ENDIAN) + && ! TARGET_SHORT_BY_BYTES + && REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?\\t%3, [%0, %2]!\\t%@ loadhi" +[(set_attr "type" "load")]) + +(define_insn "*loadhi_predec" + [(set (match_operand:HI 3 "s_register_operand" "=r") + (mem:HI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "r")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_dup 2)))] + "(!BYTES_BIG_ENDIAN) + && ! TARGET_SHORT_BY_BYTES + && REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?\\t%3, [%0, -%2]!\\t%@ loadhi" +[(set_attr "type" "load")]) + +(define_insn "*strqi_shiftpreinc" + [(set (mem:QI (plus:SI (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")]) + (match_operand:SI 1 "s_register_operand" "0"))) + (match_operand:QI 5 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) + (match_dup 1)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "str%?b\\t%5, [%0, %3%S2]!" +[(set_attr "type" "store1")]) + +(define_insn "*strqi_shiftpredec" + [(set (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")]))) + (match_operand:QI 5 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) + (match_dup 4)])))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "str%?b\\t%5, [%0, -%3%S2]!" +[(set_attr "type" "store1")]) + +(define_insn "*loadqi_shiftpreinc" + [(set (match_operand:QI 5 "s_register_operand" "=r") + (mem:QI (plus:SI (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")]) + (match_operand:SI 1 "s_register_operand" "0")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) + (match_dup 1)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "ldr%?b\\t%5, [%0, %3%S2]!" +[(set_attr "type" "load")]) + +(define_insn "*loadqi_shiftpredec" + [(set (match_operand:QI 5 "s_register_operand" "=r") + (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")])))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) + (match_dup 4)])))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "ldr%?b\\t%5, [%0, -%3%S2]!" +[(set_attr "type" "load")]) + +(define_insn "*strsi_shiftpreinc" + [(set (mem:SI (plus:SI (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")]) + (match_operand:SI 1 "s_register_operand" "0"))) + (match_operand:SI 5 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) + (match_dup 1)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "str%?\\t%5, [%0, %3%S2]!" +[(set_attr "type" "store1")]) + +(define_insn "*strsi_shiftpredec" + [(set (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")]))) + (match_operand:SI 5 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) + (match_dup 4)])))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "str%?\\t%5, [%0, -%3%S2]!" +[(set_attr "type" "store1")]) + +(define_insn "*loadqi_shiftpreinc" + [(set (match_operand:SI 5 "s_register_operand" "=r") + (mem:SI (plus:SI (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")]) + (match_operand:SI 1 "s_register_operand" "0")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) + (match_dup 1)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "ldr%?\\t%5, [%0, %3%S2]!" +[(set_attr "type" "load")]) + +(define_insn "*loadqi_shiftpredec" + [(set (match_operand:SI 5 "s_register_operand" "=r") + (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")])))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) + (match_dup 4)])))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "ldr%?\\t%5, [%0, -%3%S2]!" +[(set_attr "type" "load")]) + +(define_insn "*loadhi_shiftpreinc" + [(set (match_operand:HI 5 "s_register_operand" "=r") + (mem:HI (plus:SI (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")]) + (match_operand:SI 1 "s_register_operand" "0")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) + (match_dup 1)))] + "(! BYTES_BIG_ENDIAN) + && ! TARGET_SHORT_BY_BYTES + && REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "ldr%?\\t%5, [%0, %3%S2]!\\t%@ loadhi" +[(set_attr "type" "load")]) + +(define_insn "*loadhi_shiftpredec" + [(set (match_operand:HI 5 "s_register_operand" "=r") + (mem:HI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")])))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) + (match_dup 4)])))] + "(! BYTES_BIG_ENDIAN) + && ! TARGET_SHORT_BY_BYTES + && REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "ldr%?\\t%5, [%0, -%3%S2]!\\t%@ loadhi" +[(set_attr "type" "load")]) + +; It can also support extended post-inc expressions, but combine doesn't +; try these.... +; It doesn't seem worth adding peepholes for anything but the most common +; cases since, unlike combine, the increment must immediately follow the load +; for this pattern to match. +; When loading we must watch to see that the base register isn't trampled by +; the load. In such cases this isn't a post-inc expression. + +(define_peephole + [(set (mem:QI (match_operand:SI 0 "s_register_operand" "+r")) + (match_operand:QI 2 "s_register_operand" "r")) + (set (match_dup 0) + (plus:SI (match_dup 0) (match_operand:SI 1 "index_operand" "rJ")))] + "" + "str%?b\\t%2, [%0], %1") + +(define_peephole + [(set (match_operand:QI 0 "s_register_operand" "=r") + (mem:QI (match_operand:SI 1 "s_register_operand" "+r"))) + (set (match_dup 1) + (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))] + "REGNO(operands[0]) != REGNO(operands[1]) + && (GET_CODE (operands[2]) != REG + || REGNO(operands[0]) != REGNO (operands[2]))" + "ldr%?b\\t%0, [%1], %2") + +(define_peephole + [(set (mem:SI (match_operand:SI 0 "s_register_operand" "+r")) + (match_operand:SI 2 "s_register_operand" "r")) + (set (match_dup 0) + (plus:SI (match_dup 0) (match_operand:SI 1 "index_operand" "rJ")))] + "" + "str%?\\t%2, [%0], %1") + +(define_peephole + [(set (match_operand:HI 0 "s_register_operand" "=r") + (mem:HI (match_operand:SI 1 "s_register_operand" "+r"))) + (set (match_dup 1) + (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))] + "(! BYTES_BIG_ENDIAN) + && ! TARGET_SHORT_BY_BYTES + && REGNO(operands[0]) != REGNO(operands[1]) + && (GET_CODE (operands[2]) != REG + || REGNO(operands[0]) != REGNO (operands[2]))" + "ldr%?\\t%0, [%1], %2\\t%@ loadhi") + +(define_peephole + [(set (match_operand:SI 0 "s_register_operand" "=r") + (mem:SI (match_operand:SI 1 "s_register_operand" "+r"))) + (set (match_dup 1) + (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))] + "REGNO(operands[0]) != REGNO(operands[1]) + && (GET_CODE (operands[2]) != REG + || REGNO(operands[0]) != REGNO (operands[2]))" + "ldr%?\\t%0, [%1], %2") + +(define_peephole + [(set (mem:QI (plus:SI (match_operand:SI 0 "s_register_operand" "+r") + (match_operand:SI 1 "index_operand" "rJ"))) + (match_operand:QI 2 "s_register_operand" "r")) + (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))] + "" + "str%?b\\t%2, [%0, %1]!") + +(define_peephole + [(set (mem:QI (plus:SI (match_operator:SI 4 "shift_operator" + [(match_operand:SI 0 "s_register_operand" "r") + (match_operand:SI 1 "const_int_operand" "n")]) + (match_operand:SI 2 "s_register_operand" "+r"))) + (match_operand:QI 3 "s_register_operand" "r")) + (set (match_dup 2) (plus:SI (match_op_dup 4 [(match_dup 0) (match_dup 1)]) + (match_dup 2)))] + "" + "str%?b\\t%3, [%2, %0%S4]!") + +; This pattern is never tried by combine, so do it as a peephole + +(define_peephole + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operand:SI 1 "s_register_operand" "r")) + (set (reg:CC 24) + (compare:CC (match_dup 1) (const_int 0)))] + "" + "sub%?s\\t%0, %1, #0" +[(set_attr "conds" "set")]) + +; Peepholes to spot possible load- and store-multiples, if the ordering is +; reversed, check that the memory references aren't volatile. + +(define_peephole + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operand:SI 4 "memory_operand" "m")) + (set (match_operand:SI 1 "s_register_operand" "=r") + (match_operand:SI 5 "memory_operand" "m")) + (set (match_operand:SI 2 "s_register_operand" "=r") + (match_operand:SI 6 "memory_operand" "m")) + (set (match_operand:SI 3 "s_register_operand" "=r") + (match_operand:SI 7 "memory_operand" "m"))] + "load_multiple_sequence (operands, 4, NULL, NULL, NULL)" + "* + return emit_ldm_seq (operands, 4); +") + +(define_peephole + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operand:SI 3 "memory_operand" "m")) + (set (match_operand:SI 1 "s_register_operand" "=r") + (match_operand:SI 4 "memory_operand" "m")) + (set (match_operand:SI 2 "s_register_operand" "=r") + (match_operand:SI 5 "memory_operand" "m"))] + "load_multiple_sequence (operands, 3, NULL, NULL, NULL)" + "* + return emit_ldm_seq (operands, 3); +") + +(define_peephole + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operand:SI 2 "memory_operand" "m")) + (set (match_operand:SI 1 "s_register_operand" "=r") + (match_operand:SI 3 "memory_operand" "m"))] + "load_multiple_sequence (operands, 2, NULL, NULL, NULL)" + "* + return emit_ldm_seq (operands, 2); +") + +(define_peephole + [(set (match_operand:SI 4 "memory_operand" "=m") + (match_operand:SI 0 "s_register_operand" "r")) + (set (match_operand:SI 5 "memory_operand" "=m") + (match_operand:SI 1 "s_register_operand" "r")) + (set (match_operand:SI 6 "memory_operand" "=m") + (match_operand:SI 2 "s_register_operand" "r")) + (set (match_operand:SI 7 "memory_operand" "=m") + (match_operand:SI 3 "s_register_operand" "r"))] + "store_multiple_sequence (operands, 4, NULL, NULL, NULL)" + "* + return emit_stm_seq (operands, 4); +") + +(define_peephole + [(set (match_operand:SI 3 "memory_operand" "=m") + (match_operand:SI 0 "s_register_operand" "r")) + (set (match_operand:SI 4 "memory_operand" "=m") + (match_operand:SI 1 "s_register_operand" "r")) + (set (match_operand:SI 5 "memory_operand" "=m") + (match_operand:SI 2 "s_register_operand" "r"))] + "store_multiple_sequence (operands, 3, NULL, NULL, NULL)" + "* + return emit_stm_seq (operands, 3); +") + +(define_peephole + [(set (match_operand:SI 2 "memory_operand" "=m") + (match_operand:SI 0 "s_register_operand" "r")) + (set (match_operand:SI 3 "memory_operand" "=m") + (match_operand:SI 1 "s_register_operand" "r"))] + "store_multiple_sequence (operands, 2, NULL, NULL, NULL)" + "* + return emit_stm_seq (operands, 2); +") + +;; A call followed by return can be replaced by restoring the regs and +;; jumping to the subroutine, provided we aren't passing the address of +;; any of our local variables. If we call alloca then this is unsafe +;; since restoring the frame frees the memory, which is not what we want. +;; Sometimes the return might have been targeted by the final prescan: +;; if so then emit a proper return insn as well. +;; Unfortunately, if the frame pointer is required, we don't know if the +;; current function has any implicit stack pointer adjustments that will +;; be restored by the return: we can't therefore do a tail call. +;; Another unfortunate that we can't handle is if current_function_args_size +;; is non-zero: in this case elimination of the argument pointer assumed +;; that lr was pushed onto the stack, so eliminating upsets the offset +;; calculations. + +(define_peephole + [(parallel [(call (mem:SI (match_operand:SI 0 "" "X")) + (match_operand:SI 1 "general_operand" "g")) + (clobber (reg:SI 14))]) + (return)] + "(GET_CODE (operands[0]) == SYMBOL_REF && USE_RETURN_INSN (FALSE) + && !get_frame_size () && !current_function_calls_alloca + && !frame_pointer_needed && !current_function_args_size)" + "* +{ + extern rtx arm_target_insn; + extern int arm_ccfsm_state; + + if (arm_ccfsm_state && arm_target_insn && INSN_DELETED_P (arm_target_insn)) + { + arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); + output_return_instruction (NULL, TRUE, FALSE); + arm_ccfsm_state = 0; + arm_target_insn = NULL; + } + + output_return_instruction (NULL, FALSE, FALSE); + return \"b%?\\t%a0\"; +}" +[(set_attr "type" "call") + (set_attr "length" "8")]) + +(define_peephole + [(parallel [(set (match_operand 0 "s_register_operand" "=rf") + (call (mem:SI (match_operand:SI 1 "" "X")) + (match_operand:SI 2 "general_operand" "g"))) + (clobber (reg:SI 14))]) + (return)] + "(GET_CODE (operands[1]) == SYMBOL_REF && USE_RETURN_INSN (FALSE) + && !get_frame_size () && !current_function_calls_alloca + && !frame_pointer_needed && !current_function_args_size)" + "* +{ + extern rtx arm_target_insn; + extern int arm_ccfsm_state; + + if (arm_ccfsm_state && arm_target_insn && INSN_DELETED_P (arm_target_insn)) + { + arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); + output_return_instruction (NULL, TRUE, FALSE); + arm_ccfsm_state = 0; + arm_target_insn = NULL; + } + + output_return_instruction (NULL, FALSE, FALSE); + return \"b%?\\t%a1\"; +}" +[(set_attr "type" "call") + (set_attr "length" "8")]) + +;; As above but when this function is not void, we must be returning the +;; result of the called subroutine. + +(define_peephole + [(parallel [(set (match_operand 0 "s_register_operand" "=rf") + (call (mem:SI (match_operand:SI 1 "" "X")) + (match_operand:SI 2 "general_operand" "g"))) + (clobber (reg:SI 14))]) + (use (match_dup 0)) + (return)] + "(GET_CODE (operands[1]) == SYMBOL_REF && USE_RETURN_INSN (FALSE) + && !get_frame_size () && !current_function_calls_alloca + && !frame_pointer_needed && !current_function_args_size)" + "* +{ + extern rtx arm_target_insn; + extern int arm_ccfsm_state; + + if (arm_ccfsm_state && arm_target_insn && INSN_DELETED_P (arm_target_insn)) + { + arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); + output_return_instruction (NULL, TRUE, FALSE); + arm_ccfsm_state = 0; + arm_target_insn = NULL; + } + + output_return_instruction (NULL, FALSE, FALSE); + return \"b%?\\t%a1\"; +}" +[(set_attr "type" "call") + (set_attr "length" "8")]) + +;; CYGNUS LOCAL +;; If calling a subroutine and then jumping back to somewhere else, but not +;; too far away, then we can set the link register with the branch address +;; and jump direct to the subroutine. On return from the subroutine +;; execution continues at the branch; this avoids a prefetch stall. +;; We use the length attribute (via short_branch ()) to establish whether or +;; not this is possible, this is the same as the sparc does. + +(define_peephole + [(parallel[(call (mem:SI (match_operand:SI 0 "" "X")) + (match_operand:SI 1 "general_operand" "g")) + (clobber (reg:SI 14))]) + (set (pc) + (label_ref (match_operand 2 "" "")))] + "0 && GET_CODE (operands[0]) == SYMBOL_REF + && short_branch (INSN_UID (insn), INSN_UID (operands[2])) + && arm_insn_not_targeted (insn)" + "* +{ + int backward = arm_backwards_branch (INSN_UID (insn), + INSN_UID (operands[2])); + +#if 0 + /* Putting this in means that TARGET_6 code will ONLY run on an arm6 or + * above, leaving it out means that the code will still run on an arm 2 or 3 + */ + if (TARGET_6) + { + if (backward) + output_asm_insn (\"sub%?\\t%|lr, %|pc, #(8 + . -%l2)\", operands); + else + output_asm_insn (\"add%?\\t%|lr, %|pc, #(%l2 - . -8)\", operands); + } + else +#endif + { + output_asm_insn (\"mov%?\\t%|lr, %|pc\\t%@ protect cc\", operands); + if (backward) + output_asm_insn (\"sub%?\\t%|lr, %|lr, #(4 + . -%l2)\", operands); + else + output_asm_insn (\"add%?\\t%|lr, %|lr, #(%l2 - . -4)\", operands); + } + return \"b%?\\t%a0\"; +}" +[(set_attr "type" "call") + (set (attr "length") + (if_then_else (eq_attr "prog_mode" "prog32") + (const_int 8) + (const_int 12)))]) + +(define_peephole + [(parallel[(set (match_operand:SI 0 "s_register_operand" "=r") + (call (mem:SI (match_operand:SI 1 "" "X")) + (match_operand:SI 2 "general_operand" "g"))) + (clobber (reg:SI 14))]) + (set (pc) + (label_ref (match_operand 3 "" "")))] + "0 && GET_CODE (operands[0]) == SYMBOL_REF + && short_branch (INSN_UID (insn), INSN_UID (operands[3])) + && arm_insn_not_targeted (insn)" + "* +{ + int backward = arm_backwards_branch (INSN_UID (insn), + INSN_UID (operands[3])); + +#if 0 + /* Putting this in means that TARGET_6 code will ONLY run on an arm6 or + * above, leaving it out means that the code will still run on an arm 2 or 3 + */ + if (TARGET_6) + { + if (backward) + output_asm_insn (\"sub%?\\t%|lr, %|pc, #(8 + . -%l3)\", operands); + else + output_asm_insn (\"add%?\\t%|lr, %|pc, #(%l3 - . -8)\", operands); + } + else +#endif + { + output_asm_insn (\"mov%?\\t%|lr, %|pc\\t%@ protect cc\", operands); + if (backward) + output_asm_insn (\"sub%?\\t%|lr, %|lr, #(4 + . -%l3)\", operands); + else + output_asm_insn (\"add%?\\t%|lr, %|lr, #(%l3 - . -4)\", operands); + } + return \"b%?\\t%a1\"; +}" +[(set_attr "type" "call") + (set (attr "length") + (if_then_else (eq_attr "prog_mode" "prog32") + (const_int 8) + (const_int 12)))]) +;; END CYGNUS LOCAL + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (and:SI (ge:SI (match_operand:SI 1 "s_register_operand" "") + (const_int 0)) + (neg:SI (match_operator:SI 2 "comparison_operator" + [(match_operand:SI 3 "s_register_operand" "") + (match_operand:SI 4 "arm_rhs_operand" "")])))) + (clobber (match_operand:SI 5 "s_register_operand" ""))] + "" + [(set (match_dup 5) (not:SI (ashiftrt:SI (match_dup 1) (const_int 31)))) + (set (match_dup 0) (and:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) + (match_dup 5)))] + "") + +;; This split can be used because CC_Z mode implies that the following +;; branch will be an equality, or an unsigned inequality, so the sign +;; extension is not needed. + +(define_split + [(set (reg:CC_Z 24) + (compare:CC_Z + (ashift:SI (subreg:SI (match_operand:QI 0 "memory_operand" "") 0) + (const_int 24)) + (match_operand 1 "const_int_operand" ""))) + (clobber (match_scratch:SI 2 ""))] + "((unsigned HOST_WIDE_INT) INTVAL (operands[1])) + == (((unsigned HOST_WIDE_INT) INTVAL (operands[1])) >> 24) << 24" + [(set (match_dup 2) (zero_extend:SI (match_dup 0))) + (set (reg:CC 24) (compare:CC (match_dup 2) (match_dup 1)))] + " + operands[1] = GEN_INT (((unsigned long) INTVAL (operands[1])) >> 24); +") + +(define_expand "prologue" + [(clobber (const_int 0))] + "" + " + arm_expand_prologue (); + DONE; +") + +;; This split is only used during output to reduce the number of patterns +;; that need assembler instructions adding to them. We allowed the setting +;; of the conditions to be implicit during rtl generation so that +;; the conditional compare patterns would work. However this conflicts to +;; some extent with the conditional data operations, so we have to split them +;; up again here. + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(match_operand 2 "" "") (match_operand 3 "" "")]) + (match_operand 4 "" "") + (match_operand 5 "" ""))) + (clobber (reg:CC 24))] + "reload_completed" + [(set (match_dup 6) (match_dup 7)) + (set (match_dup 0) + (if_then_else:SI (match_op_dup 1 [(match_dup 6) (const_int 0)]) + (match_dup 4) + (match_dup 5)))] + " +{ + enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]), operands[2], + operands[3]); + + operands[6] = gen_rtx (REG, mode, 24); + operands[7] = gen_rtx (COMPARE, mode, operands[2], operands[3]); +} +") + +;; CYGNUS LOCAL +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "") + (match_operand:SI 3 "arm_add_operand" "")]) + (match_operand:SI 4 "arm_rhs_operand" "") + (not:SI + (match_operand:SI 5 "s_register_operand" "")))) + (clobber (reg:CC 24))] + "reload_completed" + [(set (match_dup 6) (match_dup 7)) + (set (match_dup 0) + (if_then_else:SI (match_op_dup 1 [(match_dup 6) (const_int 0)]) + (match_dup 4) + (not:SI (match_dup 5))))] + " +{ + enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]), operands[2], + operands[3]); + + operands[6] = gen_rtx (REG, mode, 24); + operands[7] = gen_rtx (COMPARE, mode, operands[2], operands[3]); +} +") + +(define_insn "*cond_move_not" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI (match_operator 4 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_rhs_operand" "0,?rI") + (not:SI + (match_operand:SI 2 "s_register_operand" "r,r"))))] + "" + "@ + mvn%D4\\t%0, %2 + mov%d4\\t%0, %1\;mvn%D4\\t%0, %2" +[(set_attr "conds" "use") + (set_attr "length" "4,8")]) +;; END CYGNUS LOCAL + +;; The next two patterns occur when an AND operation is followed by a +;; scc insn sequence + +(define_insn "*sign_extract_onebit" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (sign_extract:SI (match_operand:SI 1 "s_register_operand" "r") + (const_int 1) + (match_operand:SI 2 "const_int_operand" "n")))] + "" + "* + operands[2] = GEN_INT (1 << INTVAL (operands[2])); + output_asm_insn (\"ands\\t%0, %1, %2\", operands); + return \"mvnne\\t%0, #0\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*not_signextract_onebit" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (not:SI + (sign_extract:SI (match_operand:SI 1 "s_register_operand" "r") + (const_int 1) + (match_operand:SI 2 "const_int_operand" "n"))))] + "" + "* + operands[2] = GEN_INT (1 << INTVAL (operands[2])); + output_asm_insn (\"tst\\t%1, %2\", operands); + output_asm_insn (\"mvneq\\t%0, #0\", operands); + return \"movne\\t%0, #0\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +;; Push multiple registers to the stack. The first register is in the +;; unspec part of the insn; subsequent registers are in parallel (use ...) +;; expressions. +(define_insn "*push_multi" + [(match_parallel 2 "multi_register_push" + [(set (match_operand:BLK 0 "memory_operand" "=m") + (unspec:BLK [(match_operand:SI 1 "s_register_operand" "r")] 2))])] + "" + "* +{ + char pattern[100]; + int i; + extern int lr_save_eliminated; + + if (lr_save_eliminated) + { + if (XVECLEN (operands[2], 0) > 1) + abort (); + return \"\"; + } + strcpy (pattern, \"stmfd\\t%m0!, {%1\"); + for (i = 1; i < XVECLEN (operands[2], 0); i++) + { + strcat (pattern, \", %|\"); + strcat (pattern, reg_names[REGNO (XEXP (XVECEXP (operands[2], 0, i), + 0))]); + } + strcat (pattern, \"}\"); + output_asm_insn (pattern, operands); + return \"\"; +}" +[(set_attr "type" "store4")]) + +;; Similarly for the floating point registers +(define_insn "*push_fp_multi" + [(match_parallel 2 "multi_register_push" + [(set (match_operand:BLK 0 "memory_operand" "=m") + (unspec:BLK [(match_operand:XF 1 "f_register_operand" "f")] 2))])] + "" + "* +{ + char pattern[100]; + int i; + + sprintf (pattern, \"sfmfd\\t%%1, %d, [%%m0]!\", XVECLEN (operands[2], 0)); + output_asm_insn (pattern, operands); + return \"\"; +}" +[(set_attr "type" "f_store")]) + +;; Special patterns for dealing with the constant pool + +(define_insn "consttable_4" + [(unspec_volatile [(match_operand 0 "" "")] 2)] + "" + "* +{ + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) + { + case MODE_FLOAT: + { + union real_extract u; + bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); + assemble_real (u.d, GET_MODE (operands[0])); + break; + } + default: + assemble_integer (operands[0], 4, 1); + break; + } + return \"\"; +}" +[(set_attr "length" "4")]) + +(define_insn "consttable_8" + [(unspec_volatile [(match_operand 0 "" "")] 3)] + "" + "* +{ + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) + { + case MODE_FLOAT: + { + union real_extract u; + bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); + assemble_real (u.d, GET_MODE (operands[0])); + break; + } + default: + assemble_integer (operands[0], 8, 1); + break; + } + return \"\"; +}" +[(set_attr "length" "8")]) + +(define_insn "consttable_end" + [(unspec_volatile [(const_int 0)] 4)] + "" + "* + /* Nothing to do (currently). */ + return \"\"; +") + +(define_insn "align_4" + [(unspec_volatile [(const_int 0)] 5)] + "" + "* + assemble_align (32); + return \"\"; +") diff --git a/gcc_arm/config/arm/arm_020428.h b/gcc_arm/config/arm/arm_020428.h new file mode 100755 index 0000000..2e98c66 --- /dev/null +++ b/gcc_arm/config/arm/arm_020428.h @@ -0,0 +1,2309 @@ +/* Definitions of target machine for GNU compiler, for Acorn RISC Machine. + Copyright (C) 1991, 93, 94, 95, 96, 97, 98, 1999, 2002 Free Software Foundation, Inc. + Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl) + and Martin Simmons (@harleqn.co.uk). + More major hacks by Richard Earnshaw (rwe11@cl.cam.ac.uk) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Configuration triples for ARM ports work as follows: + (This is a bit of a mess and needs some thought) + arm-*-*: little endian + armel-*-*: little endian + armeb-*-*: big endian + If a non-embedded environment (ie: "real" OS) is specified, `arm' + should default to that used by the OS. +*/ + +#ifndef __ARM_H__ +#define __ARM_H__ + +#define TARGET_CPU_arm2 0x0000 +#define TARGET_CPU_arm250 0x0000 +#define TARGET_CPU_arm3 0x0000 +#define TARGET_CPU_arm6 0x0001 +#define TARGET_CPU_arm600 0x0001 +#define TARGET_CPU_arm610 0x0002 +#define TARGET_CPU_arm7 0x0001 +#define TARGET_CPU_arm7m 0x0004 +#define TARGET_CPU_arm7dm 0x0004 +#define TARGET_CPU_arm7dmi 0x0004 +#define TARGET_CPU_arm700 0x0001 +#define TARGET_CPU_arm710 0x0002 +#define TARGET_CPU_arm7100 0x0002 +#define TARGET_CPU_arm7500 0x0002 +#define TARGET_CPU_arm7500fe 0x1001 +#define TARGET_CPU_arm7tdmi 0x0008 +#define TARGET_CPU_arm8 0x0010 +#define TARGET_CPU_arm810 0x0020 +#define TARGET_CPU_strongarm 0x0040 +#define TARGET_CPU_strongarm110 0x0040 +#define TARGET_CPU_strongarm1100 0x0040 +#define TARGET_CPU_arm9 0x0080 +#define TARGET_CPU_arm9tdmi 0x0080 +/* Configure didn't specify */ +#define TARGET_CPU_generic 0x8000 + +enum arm_cond_code +{ + ARM_EQ = 0, ARM_NE, ARM_CS, ARM_CC, ARM_MI, ARM_PL, ARM_VS, ARM_VC, + ARM_HI, ARM_LS, ARM_GE, ARM_LT, ARM_GT, ARM_LE, ARM_AL, ARM_NV +}; +extern enum arm_cond_code arm_current_cc; +extern char *arm_condition_codes[]; + +#define ARM_INVERSE_CONDITION_CODE(X) ((enum arm_cond_code) (((int)X) ^ 1)) + +/* This is needed by the tail-calling peepholes */ +extern int frame_pointer_needed; + + +/* Just in case configure has failed to define anything. */ +#ifndef TARGET_CPU_DEFAULT +#define TARGET_CPU_DEFAULT TARGET_CPU_generic +#endif + +/* If the configuration file doesn't specify the cpu, the subtarget may + override it. If it doesn't, then default to an ARM6. */ +#if TARGET_CPU_DEFAULT == TARGET_CPU_generic +#undef TARGET_CPU_DEFAULT +#ifdef SUBTARGET_CPU_DEFAULT +#define TARGET_CPU_DEFAULT SUBTARGET_CPU_DEFAULT +#else +#define TARGET_CPU_DEFAULT TARGET_CPU_arm6 +#endif +#endif + +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm2 +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_2__" +#else +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm6 || TARGET_CPU_DEFAULT == TARGET_CPU_arm610 || TARGET_CPU_DEFAULT == TARGET_CPU_arm7500fe +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_3__" +#else +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm7m +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_3M__" +#else +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm7tdmi || TARGET_CPU_DEFAULT == TARGET_CPU_arm9 +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_4T__" +#else +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm8 || TARGET_CPU_DEFAULT == TARGET_CPU_arm810 || TARGET_CPU_DEFAULT == TARGET_CPU_strongarm +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_4__" +#else +Unrecognized value in TARGET_CPU_DEFAULT. +#endif +#endif +#endif +#endif +#endif + +#ifndef CPP_PREDEFINES +#define CPP_PREDEFINES "-Darm -Acpu(arm) -Amachine(arm)" +#endif + +#define CPP_SPEC "\ +%(cpp_cpu_arch) %(cpp_apcs_pc) %(cpp_float) \ +%(cpp_endian) %(subtarget_cpp_spec)" + +/* Set the architecture define -- if -march= is set, then it overrides + the -mcpu= setting. */ +#define CPP_CPU_ARCH_SPEC "\ +%{m2:-D__arm2__ -D__ARM_ARCH_2__} \ +%{m3:-D__arm2__ -D__ARM_ARCH_2__} \ +%{m6:-D__arm6__ -D__ARM_ARCH_3__} \ +%{march=arm2:-D__ARM_ARCH_2__} \ +%{march=arm250:-D__ARM_ARCH_2__} \ +%{march=arm3:-D__ARM_ARCH_2__} \ +%{march=arm6:-D__ARM_ARCH_3__} \ +%{march=arm600:-D__ARM_ARCH_3__} \ +%{march=arm610:-D__ARM_ARCH_3__} \ +%{march=arm7:-D__ARM_ARCH_3__} \ +%{march=arm700:-D__ARM_ARCH_3__} \ +%{march=arm710:-D__ARM_ARCH_3__} \ +%{march=arm7100:-D__ARM_ARCH_3__} \ +%{march=arm7500:-D__ARM_ARCH_3__} \ +%{march=arm7500fe:-D__ARM_ARCH_3__} \ +%{march=arm7m:-D__ARM_ARCH_3M__} \ +%{march=arm7dm:-D__ARM_ARCH_3M__} \ +%{march=arm7dmi:-D__ARM_ARCH_3M__} \ +%{march=arm7tdmi:-D__ARM_ARCH_4T__} \ +%{march=arm8:-D__ARM_ARCH_4__} \ +%{march=arm810:-D__ARM_ARCH_4__} \ +%{march=arm9:-D__ARM_ARCH_4T__} \ +%{march=arm920:-D__ARM_ARCH_4__} \ +%{march=arm920t:-D__ARM_ARCH_4T__} \ +%{march=arm9tdmi:-D__ARM_ARCH_4T__} \ +%{march=strongarm:-D__ARM_ARCH_4__} \ +%{march=strongarm110:-D__ARM_ARCH_4__} \ +%{march=strongarm1100:-D__ARM_ARCH_4__} \ +%{march=armv2:-D__ARM_ARCH_2__} \ +%{march=armv2a:-D__ARM_ARCH_2__} \ +%{march=armv3:-D__ARM_ARCH_3__} \ +%{march=armv3m:-D__ARM_ARCH_3M__} \ +%{march=armv4:-D__ARM_ARCH_4__} \ +%{march=armv4t:-D__ARM_ARCH_4T__} \ +%{!march=*: \ + %{mcpu=arm2:-D__ARM_ARCH_2__} \ + %{mcpu=arm250:-D__ARM_ARCH_2__} \ + %{mcpu=arm3:-D__ARM_ARCH_2__} \ + %{mcpu=arm6:-D__ARM_ARCH_3__} \ + %{mcpu=arm600:-D__ARM_ARCH_3__} \ + %{mcpu=arm610:-D__ARM_ARCH_3__} \ + %{mcpu=arm7:-D__ARM_ARCH_3__} \ + %{mcpu=arm700:-D__ARM_ARCH_3__} \ + %{mcpu=arm710:-D__ARM_ARCH_3__} \ + %{mcpu=arm7100:-D__ARM_ARCH_3__} \ + %{mcpu=arm7500:-D__ARM_ARCH_3__} \ + %{mcpu=arm7500fe:-D__ARM_ARCH_3__} \ + %{mcpu=arm7m:-D__ARM_ARCH_3M__} \ + %{mcpu=arm7dm:-D__ARM_ARCH_3M__} \ + %{mcpu=arm7dmi:-D__ARM_ARCH_3M__} \ + %{mcpu=arm7tdmi:-D__ARM_ARCH_4T__} \ + %{mcpu=arm8:-D__ARM_ARCH_4__} \ + %{mcpu=arm810:-D__ARM_ARCH_4__} \ + %{mcpu=arm9:-D__ARM_ARCH_4T__} \ + %{mcpu=arm920:-D__ARM_ARCH_4__} \ + %{mcpu=arm920t:-D__ARM_ARCH_4T__} \ + %{mcpu=arm9tdmi:-D__ARM_ARCH_4T__} \ + %{mcpu=strongarm:-D__ARM_ARCH_4__} \ + %{mcpu=strongarm110:-D__ARM_ARCH_4__} \ + %{mcpu=strongarm1100:-D__ARM_ARCH_4__} \ + %{!mcpu*:%{!m6:%{!m2:%{!m3:%(cpp_cpu_arch_default)}}}}} \ +" + +/* Define __APCS_26__ if the PC also contains the PSR */ +/* This also examines deprecated -m[236] if neither of -mapcs-{26,32} is set, + ??? Delete this for 2.9. */ +#define CPP_APCS_PC_SPEC "\ +%{mapcs-32:%{mapcs-26:%e-mapcs-26 and -mapcs-32 may not be used together} \ + -D__APCS_32__} \ +%{mapcs-26:-D__APCS_26__} \ +%{!mapcs-32: %{!mapcs-26:%{m6:-D__APCS_32__} %{m2:-D__APCS_26__} \ + %{m3:-D__APCS_26__} %{!m6:%{!m3:%{!m2:%(cpp_apcs_pc_default)}}}}} \ +" + +#ifndef CPP_APCS_PC_DEFAULT_SPEC +#define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_26__" +#endif + +#define CPP_FLOAT_SPEC "\ +%{msoft-float:\ + %{mhard-float:%e-msoft-float and -mhard_float may not be used together} \ + -D__SOFTFP__} \ +%{!mhard-float:%{!msoft-float:%(cpp_float_default)}} \ +" + +/* Default is hard float, which doesn't define anything */ +#define CPP_FLOAT_DEFAULT_SPEC "" + +#define CPP_ENDIAN_SPEC "\ +%{mbig-endian: \ + %{mlittle-endian: \ + %e-mbig-endian and -mlittle-endian may not be used together} \ + -D__ARMEB__ %{mwords-little-endian:-D__ARMWEL__}} \ +%{!mlittle-endian:%{!mbig-endian:%(cpp_endian_default)}} \ +" + +/* Default is little endian, which doesn't define anything. */ +#define CPP_ENDIAN_DEFAULT_SPEC "" + +/* Translate (for now) the old -m[236] option into the appropriate -mcpu=... + and -mapcs-xx equivalents. + ??? Remove support for this style in 2.9.*/ +#define CC1_SPEC "\ +%{m2:-mcpu=arm2 -mapcs-26} \ +%{m3:-mcpu=arm3 -mapcs-26} \ +%{m6:-mcpu=arm6 -mapcs-32} \ +" + +/* This macro defines names of additional specifications to put in the specs + that can be used in various specifications like CC1_SPEC. Its definition + is an initializer with a subgrouping for each command option. + + Each subgrouping contains a string constant, that defines the + specification name, and a string constant that used by the GNU CC driver + program. + + Do not define this macro if it does not need to do anything. */ +#define EXTRA_SPECS \ + { "cpp_cpu_arch", CPP_CPU_ARCH_SPEC }, \ + { "cpp_cpu_arch_default", CPP_ARCH_DEFAULT_SPEC }, \ + { "cpp_apcs_pc", CPP_APCS_PC_SPEC }, \ + { "cpp_apcs_pc_default", CPP_APCS_PC_DEFAULT_SPEC }, \ + { "cpp_float", CPP_FLOAT_SPEC }, \ + { "cpp_float_default", CPP_FLOAT_DEFAULT_SPEC }, \ + { "cpp_endian", CPP_ENDIAN_SPEC }, \ + { "cpp_endian_default", CPP_ENDIAN_DEFAULT_SPEC }, \ + { "subtarget_cpp_spec", SUBTARGET_CPP_SPEC }, \ + SUBTARGET_EXTRA_SPECS + +#define SUBTARGET_EXTRA_SPECS +#define SUBTARGET_CPP_SPEC "" + + +/* Run-time Target Specification. */ +#ifndef TARGET_VERSION +#define TARGET_VERSION \ + fputs (" (ARM/generic)", stderr); +#endif + +/* Run-time compilation parameters selecting different hardware subsets. */ +extern int target_flags; + +/* The floating point instruction architecture, can be 2 or 3 */ +/* CYGNUS LOCAL nickc/renamed from target_fp_name */ +extern char * target_fpe_name; +/* END CYGNUS LOCAL */ + +/* Nonzero if the function prologue (and epilogue) should obey + the ARM Procedure Call Standard. */ +#define ARM_FLAG_APCS_FRAME (0x0001) + +/* Nonzero if the function prologue should output the function name to enable + the post mortem debugger to print a backtrace (very useful on RISCOS, + unused on RISCiX). Specifying this flag also enables + -fno-omit-frame-pointer. + XXX Must still be implemented in the prologue. */ +#define ARM_FLAG_POKE (0x0002) + +/* Nonzero if floating point instructions are emulated by the FPE, in which + case instruction scheduling becomes very uninteresting. */ +#define ARM_FLAG_FPE (0x0004) + +/* Nonzero if destined for an ARM6xx. Takes out bits that assume restoration + of condition flags when returning from a branch & link (ie. a function) */ +/* ********* DEPRECATED ******** */ +#define ARM_FLAG_ARM6 (0x0008) + +/* ********* DEPRECATED ******** */ +#define ARM_FLAG_ARM3 (0x0010) + +/* Nonzero if destined for a processor in 32-bit program mode. Takes out bit + that assume restoration of the condition flags when returning from a + branch and link (ie a function). */ +#define ARM_FLAG_APCS_32 (0x0020) + +/* Nonzero if stack checking should be performed on entry to each function + which allocates temporary variables on the stack. */ +#define ARM_FLAG_APCS_STACK (0x0040) + +/* Nonzero if floating point parameters should be passed to functions in + floating point registers. */ +#define ARM_FLAG_APCS_FLOAT (0x0080) + +/* Nonzero if re-entrant, position independent code should be generated. + This is equivalent to -fpic. */ +#define ARM_FLAG_APCS_REENT (0x0100) + +/* Nonzero if the MMU will trap unaligned word accesses, so shorts must be + loaded byte-at-a-time. */ +#define ARM_FLAG_SHORT_BYTE (0x0200) + +/* Nonzero if all floating point instructions are missing (and there is no + emulator either). Generate function calls for all ops in this case. */ +#define ARM_FLAG_SOFT_FLOAT (0x0400) + +/* Nonzero if we should compile with BYTES_BIG_ENDIAN set to 1. */ +#define ARM_FLAG_BIG_END (0x0800) + +/* Nonzero if we should compile for Thumb interworking. */ +#define ARM_FLAG_THUMB (0x1000) + +/* Nonzero if we should have little-endian words even when compiling for + big-endian (for backwards compatibility with older versions of GCC). */ +#define ARM_FLAG_LITTLE_WORDS (0x2000) + +/* CYGNUS LOCAL */ +/* Nonzero if we need to protect the prolog from scheduling */ +#define ARM_FLAG_NO_SCHED_PRO (0x4000) +/* END CYGNUS LOCAL */ + +/* Nonzero if a call to abort should be generated if a noreturn +function tries to return. */ +#define ARM_FLAG_ABORT_NORETURN (0x8000) + +/* Nonzero if all call instructions should be indirect. */ +#define ARM_FLAG_LONG_CALLS (0x10000) + +#define TARGET_APCS (target_flags & ARM_FLAG_APCS_FRAME) +#define TARGET_POKE_FUNCTION_NAME (target_flags & ARM_FLAG_POKE) +#define TARGET_FPE (target_flags & ARM_FLAG_FPE) +#define TARGET_6 (target_flags & ARM_FLAG_ARM6) +#define TARGET_3 (target_flags & ARM_FLAG_ARM3) +#define TARGET_APCS_32 (target_flags & ARM_FLAG_APCS_32) +#define TARGET_APCS_STACK (target_flags & ARM_FLAG_APCS_STACK) +#define TARGET_APCS_FLOAT (target_flags & ARM_FLAG_APCS_FLOAT) +#define TARGET_APCS_REENT (target_flags & ARM_FLAG_APCS_REENT) +#define TARGET_SHORT_BY_BYTES (target_flags & ARM_FLAG_SHORT_BYTE) +#define TARGET_SOFT_FLOAT (target_flags & ARM_FLAG_SOFT_FLOAT) +#define TARGET_HARD_FLOAT (! TARGET_SOFT_FLOAT) +#define TARGET_BIG_END (target_flags & ARM_FLAG_BIG_END) +#define TARGET_THUMB_INTERWORK (target_flags & ARM_FLAG_THUMB) +#define TARGET_LITTLE_WORDS (target_flags & ARM_FLAG_LITTLE_WORDS) +/* CYGNUS LOCAL */ +#define TARGET_NO_SCHED_PRO (target_flags & ARM_FLAG_NO_SCHED_PRO) +/* END CYGNUS LOCAL */ +#define TARGET_ABORT_NORETURN (target_flags & ARM_FLAG_ABORT_NORETURN) +#define TARGET_LONG_CALLS (target_flags & ARM_FLAG_LONG_CALLS) + +/* SUBTARGET_SWITCHES is used to add flags on a per-config basis. + Bit 31 is reserved. See riscix.h. */ +#ifndef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES +#endif + +#define TARGET_SWITCHES \ +{ \ + {"apcs", ARM_FLAG_APCS_FRAME, "" }, \ + {"apcs-frame", ARM_FLAG_APCS_FRAME, \ + "Generate APCS conformant stack frames" }, \ + {"no-apcs-frame", -ARM_FLAG_APCS_FRAME, "" }, \ + {"poke-function-name", ARM_FLAG_POKE, \ + "Store function names in object code" }, \ + {"fpe", ARM_FLAG_FPE, "" }, \ + {"6", ARM_FLAG_ARM6, "" }, \ + {"2", ARM_FLAG_ARM3, "" }, \ + {"3", ARM_FLAG_ARM3, "" }, \ + {"apcs-32", ARM_FLAG_APCS_32, \ + "Use the 32bit version of the APCS" }, \ + {"apcs-26", -ARM_FLAG_APCS_32, \ + "Use the 26bit version of the APCS" }, \ + {"apcs-stack-check", ARM_FLAG_APCS_STACK, "" }, \ + {"no-apcs-stack-check", -ARM_FLAG_APCS_STACK, "" }, \ + {"apcs-float", ARM_FLAG_APCS_FLOAT, \ + "Pass FP arguments in FP registers" }, \ + {"no-apcs-float", -ARM_FLAG_APCS_FLOAT, "" }, \ + {"apcs-reentrant", ARM_FLAG_APCS_REENT, \ + "Generate re-entrant, PIC code" }, \ + {"no-apcs-reentrant", -ARM_FLAG_APCS_REENT, "" }, \ + {"short-load-bytes", ARM_FLAG_SHORT_BYTE, \ + "Load shorts a byte at a time" }, \ + {"no-short-load-bytes", -ARM_FLAG_SHORT_BYTE, "" }, \ + {"short-load-words", -ARM_FLAG_SHORT_BYTE, \ + "Load words a byte at a time" }, \ + {"no-short-load-words", ARM_FLAG_SHORT_BYTE, "" }, \ + {"soft-float", ARM_FLAG_SOFT_FLOAT, \ + "Use library calls to perform FP operations" }, \ + {"hard-float", -ARM_FLAG_SOFT_FLOAT, \ + "Use hardware floating point instructions" }, \ + {"big-endian", ARM_FLAG_BIG_END, \ + "Assume target CPU is configured as big endian" }, \ + {"little-endian", -ARM_FLAG_BIG_END, \ + "Assume target CPU is configured as little endian" }, \ + {"words-little-endian", ARM_FLAG_LITTLE_WORDS, \ + "Assume big endian bytes, little endian words" }, \ + {"thumb-interwork", ARM_FLAG_THUMB, \ + "Support calls between THUMB and ARM instructions sets" }, \ + {"no-thumb-interwork", -ARM_FLAG_THUMB, "" }, \ + {"abort-on-noreturn", ARM_FLAG_ABORT_NORETURN, \ + "Generate a call to abort if a noreturn function returns"}, \ + {"no-abort-on-noreturn", -ARM_FLAG_ABORT_NORETURN, ""}, \ + /* CYGNUS LOCAL */ \ + {"sched-prolog", -ARM_FLAG_NO_SCHED_PRO, \ + "Do not move instructions into a function's prologue" }, \ + {"no-sched-prolog", ARM_FLAG_NO_SCHED_PRO, "" }, \ + /* END CYGNUS LOCAL */ \ + {"long-calls", ARM_FLAG_LONG_CALLS, \ + "Generate all call instructions as indirect calls"}, \ + {"no-long-calls", -ARM_FLAG_LONG_CALLS, ""}, \ + SUBTARGET_SWITCHES \ + {"", TARGET_DEFAULT } \ +} + +#define TARGET_OPTIONS \ +{ \ + {"cpu=", & arm_select[0].string, \ + "Specify the name of the target CPU" }, \ + {"arch=", & arm_select[1].string, \ + "Specify the name of the target architecture" }, \ + {"tune=", & arm_select[2].string, "" }, \ + {"fpe=", & target_fpe_name, "" }, \ + {"fp=", & target_fpe_name, \ + "Specify the version of the floating point emulator" }, \ + { "structure-size-boundary=", & structure_size_string, \ + "Specify the minumum bit alignment of structures" } \ +} + +struct arm_cpu_select +{ + char * string; + char * name; + struct processors * processors; +}; + +/* This is a magic array. If the user specifies a command line switch + which matches one of the entries in TARGET_OPTIONS then the corresponding + string pointer will be set to the value specified by the user. */ +extern struct arm_cpu_select arm_select[]; + +enum prog_mode_type +{ + prog_mode26, + prog_mode32 +}; + +/* Recast the program mode class to be the prog_mode attribute */ +#define arm_prog_mode ((enum attr_prog_mode) arm_prgmode) + +extern enum prog_mode_type arm_prgmode; + +/* What sort of floating point unit do we have? Hardware or software. + If software, is it issue 2 or issue 3? */ +enum floating_point_type +{ + FP_HARD, + FP_SOFT2, + FP_SOFT3 +}; + +/* Recast the floating point class to be the floating point attribute. */ +#define arm_fpu_attr ((enum attr_fpu) arm_fpu) + +/* What type of floating point to tune for */ +extern enum floating_point_type arm_fpu; + +/* What type of floating point instructions are available */ +extern enum floating_point_type arm_fpu_arch; + +/* Default floating point architecture. Override in sub-target if + necessary. */ +#define FP_DEFAULT FP_SOFT2 + +/* Nonzero if the processor has a fast multiply insn, and one that does + a 64-bit multiply of two 32-bit values. */ +extern int arm_fast_multiply; + +/* Nonzero if this chip supports the ARM Architecture 4 extensions */ +extern int arm_arch4; + +/* CYGNUS LOCAL nickc/load scheduling */ +/* Nonzero if this chip can benefit from load scheduling. */ +extern int arm_ld_sched; +/* END CYGNUS LOCAL */ + +/* Nonzero if this chip is a StrongARM. */ +extern int arm_is_strong; + +/* Nonzero if this chip is a an ARM6 or an ARM7. */ +extern int arm_is_6_or_7; + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT 0 +#endif + +/* The frame pointer register used in gcc has nothing to do with debugging; + that is controlled by the APCS-FRAME option. */ +/* Not fully implemented yet */ +/* #define CAN_DEBUG_WITHOUT_FP 1 */ + +#define TARGET_MEM_FUNCTIONS 1 + +#define OVERRIDE_OPTIONS arm_override_options () + +/* Target machine storage Layout. */ + + +/* Define this macro if it is advisable to hold scalars in registers + in a wider mode than that declared by the program. In such cases, + the value is constrained to be within the bounds of the declared + type, but kept valid in the wider mode. The signedness of the + extension may differ from that of the type. */ + +/* It is far faster to zero extend chars than to sign extend them */ + +#define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \ + if (GET_MODE_CLASS (MODE) == MODE_INT \ + && GET_MODE_SIZE (MODE) < 4) \ + { \ + if (MODE == QImode) \ + UNSIGNEDP = 1; \ + else if (MODE == HImode) \ + UNSIGNEDP = TARGET_SHORT_BY_BYTES != 0; \ + (MODE) = SImode; \ + } + +/* Define this macro if the promotion described by `PROMOTE_MODE' + should also be done for outgoing function arguments. */ +/* This is required to ensure that push insns always push a word. */ +#define PROMOTE_FUNCTION_ARGS + +/* Define for XFmode extended real floating point support. + This will automatically cause REAL_ARITHMETIC to be defined. */ +/* For the ARM: + I think I have added all the code to make this work. Unfortunately, + early releases of the floating point emulation code on RISCiX used a + different format for extended precision numbers. On my RISCiX box there + is a bug somewhere which causes the machine to lock up when running enquire + with long doubles. There is the additional aspect that Norcroft C + treats long doubles as doubles and we ought to remain compatible. + Perhaps someone with an FPA coprocessor and not running RISCiX would like + to try this someday. */ +/* #define LONG_DOUBLE_TYPE_SIZE 96 */ + +/* Disable XFmode patterns in md file */ +#define ENABLE_XF_PATTERNS 0 + +/* Define if you don't want extended real, but do want to use the + software floating point emulator for REAL_ARITHMETIC and + decimal <-> binary conversion. */ +/* See comment above */ +#define REAL_ARITHMETIC + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. */ +#define BITS_BIG_ENDIAN 0 + +/* Define this if most significant byte of a word is the lowest numbered. + Most ARM processors are run in little endian mode, so that is the default. + If you want to have it run-time selectable, change the definition in a + cover file to be TARGET_BIG_ENDIAN. */ +#define BYTES_BIG_ENDIAN (TARGET_BIG_END != 0) + +/* Define this if most significant word of a multiword number is the lowest + numbered. + This is always false, even when in big-endian mode. */ +#define WORDS_BIG_ENDIAN (BYTES_BIG_ENDIAN && ! TARGET_LITTLE_WORDS) + +/* LIBGCC2_WORDS_BIG_ENDIAN has to be a constant, so we define this based + on processor pre-defineds when compiling libgcc2.c. */ +#if defined(__ARMEB__) && !defined(__ARMWEL__) +#define LIBGCC2_WORDS_BIG_ENDIAN 1 +#else +#define LIBGCC2_WORDS_BIG_ENDIAN 0 +#endif + +/* Define this if most significant word of doubles is the lowest numbered. + This is always true, even when in little-endian mode. */ +#define FLOAT_WORDS_BIG_ENDIAN 1 + +/* Number of bits in an addressable storage unit */ +#define BITS_PER_UNIT 8 + +#define BITS_PER_WORD 32 + +#define UNITS_PER_WORD 4 + +#define POINTER_SIZE 32 + +#define PARM_BOUNDARY 32 + +#define STACK_BOUNDARY 32 + +#define FUNCTION_BOUNDARY 32 + +#define EMPTY_FIELD_BOUNDARY 32 + +#define BIGGEST_ALIGNMENT 32 + +/* Make strings word-aligned so strcpy from constants will be faster. */ +#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ + (TREE_CODE (EXP) == STRING_CST \ + && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) + +/* Every structures size must be a multiple of 32 bits. */ +/* This is for compatibility with ARMCC. ARM SDT Reference Manual + (ARM DUI 0020D) page 2-20 says "Structures are aligned on word + boundaries". */ +#ifndef STRUCTURE_SIZE_BOUNDARY +#define STRUCTURE_SIZE_BOUNDARY 32 +#endif + +/* Used when parsing command line option -mstructure_size_boundary. */ +extern char * structure_size_string; + +/* Non-zero if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT 1 + +#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT + + +/* Standard register usage. */ + +/* Register allocation in ARM Procedure Call Standard (as used on RISCiX): + (S - saved over call). + + r0 * argument word/integer result + r1-r3 argument word + + r4-r8 S register variable + r9 S (rfp) register variable (real frame pointer) + CYGNUS LOCAL nickc/comment change + r10 F S (sl) stack limit (used by -mapcs-stack-check) + END CYGNUS LOCAL + r11 F S (fp) argument pointer + r12 (ip) temp workspace + r13 F S (sp) lower end of current stack frame + r14 (lr) link address/workspace + r15 F (pc) program counter + + f0 floating point result + f1-f3 floating point scratch + + f4-f7 S floating point variable + + cc This is NOT a real register, but is used internally + to represent things that use or set the condition + codes. + sfp This isn't either. It is used during rtl generation + since the offset between the frame pointer and the + auto's isn't known until after register allocation. + afp Nor this, we only need this because of non-local + goto. Without it fp appears to be used and the + elimination code won't get rid of sfp. It tracks + fp exactly at all times. + + *: See CONDITIONAL_REGISTER_USAGE */ + +/* The stack backtrace structure is as follows: + fp points to here: | save code pointer | [fp] + | return link value | [fp, #-4] + | return sp value | [fp, #-8] + | return fp value | [fp, #-12] + [| saved r10 value |] + [| saved r9 value |] + [| saved r8 value |] + [| saved r7 value |] + [| saved r6 value |] + [| saved r5 value |] + [| saved r4 value |] + [| saved r3 value |] + [| saved r2 value |] + [| saved r1 value |] + [| saved r0 value |] + [| saved f7 value |] three words + [| saved f6 value |] three words + [| saved f5 value |] three words + [| saved f4 value |] three words + r0-r3 are not normally saved in a C function. */ + +/* The number of hard registers is 16 ARM + 8 FPU + 1 CC + 1 SFP. */ +#define FIRST_PSEUDO_REGISTER 27 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. */ +#define FIXED_REGISTERS \ +{ \ + 0,0,0,0,0,0,0,0, \ + 0,0,1,1,0,1,0,1, \ + 0,0,0,0,0,0,0,0, \ + 1,1,1 \ +} + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. + The CC is not preserved over function calls on the ARM 6, so it is + easier to assume this for all. SFP is preserved, since FP is. */ +#define CALL_USED_REGISTERS \ +{ \ + 1,1,1,1,0,0,0,0, \ + 0,0,1,1,1,1,1,1, \ + 1,1,1,1,0,0,0,0, \ + 1,1,1 \ +} + +/* If doing stupid life analysis, avoid a bug causing a return value r0 to be + trampled. This effectively reduces the number of available registers by 1. + XXX It is a hack, I know. + XXX Is this still needed? */ +#define CONDITIONAL_REGISTER_USAGE \ +{ \ + if (obey_regdecls) \ + fixed_regs[0] = 1; \ + if (TARGET_SOFT_FLOAT) \ + { \ + int regno; \ + for (regno = 16; regno < 24; ++regno) \ + fixed_regs[regno] = call_used_regs[regno] = 1; \ + } \ + if (flag_pic) \ + { \ + fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ + call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 0; \ + } \ + /* CYGNUS LOCAL */ \ + else if (! TARGET_APCS_STACK) \ + { \ + fixed_regs[10] = 0; \ + call_used_regs[10] = 0; \ + } \ + /* END CYGNUS LOCAL */ \ +} + +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. + + On the ARM regs are UNITS_PER_WORD bits wide; FPU regs can hold any FP + mode. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + (((REGNO) >= 16 && REGNO != FRAME_POINTER_REGNUM \ + && (REGNO) != ARG_POINTER_REGNUM) ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + This is TRUE for ARM regs since they can hold anything, and TRUE for FPU + regs holding FP. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + ((GET_MODE_CLASS (MODE) == MODE_CC) ? (REGNO == CC_REGNUM) : \ + ((REGNO) < 16 || REGNO == FRAME_POINTER_REGNUM \ + || REGNO == ARG_POINTER_REGNUM \ + || GET_MODE_CLASS (MODE) == MODE_FLOAT)) + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + 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) \ + (GET_MODE_CLASS (MODE1) == GET_MODE_CLASS (MODE2)) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* Define this if the program counter is overloaded on a register. */ +#define PC_REGNUM 15 + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 13 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 25 + +/* Define this to be where the real frame pointer is if it is not possible to + work out the offset between the frame pointer and the automatic variables + until after register allocation has taken place. FRAME_POINTER_REGNUM + should point to a special register that we will make sure is eliminated. */ +#define HARD_FRAME_POINTER_REGNUM 11 + +/* 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. + If we have to have a frame pointer we might as well make use of it. + APCS says that the frame pointer does not need to be pushed in leaf + functions, or simple tail call functions. */ +/* CYGNUS LOCAL */ +#define FRAME_POINTER_REQUIRED \ + (current_function_has_nonlocal_label \ + || (TARGET_APCS && (! leaf_function_p () && ! can_tail_call_optimise ()))) + +extern int can_tail_call_optimise (); +/* END CYGNUS LOCAL */ + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 26 + +/* The native (Norcroft) Pascal compiler for the ARM passes the static chain + as an invisible last argument (possible since varargs don't exist in + Pascal), so the following is not true. */ +#define STATIC_CHAIN_REGNUM 8 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 0 + +/* Internal, so that we don't need to refer to a raw number */ +#define CC_REGNUM 24 + +/* The order in which register should be allocated. It is good to use ip + since no saving is required (though calls clobber it) and it never contains + function parameters. It is quite good to use lr since other calls may + clobber it anyway. Allocate r0 through r3 in reverse order since r3 is + least likely to contain a function parameter; in addition results are + returned in r0. + */ +#define REG_ALLOC_ORDER \ +{ \ + 3, 2, 1, 0, 12, 14, 4, 5, \ + 6, 7, 8, 10, 9, 11, 13, 15, \ + 16, 17, 18, 19, 20, 21, 22, 23, \ + 24, 25, 26 \ +} + +/* Register and constant classes. */ + +/* Register classes: all ARM regs or all FPU regs---simple! */ +enum reg_class +{ + NO_REGS, + FPU_REGS, + GENERAL_REGS, + ALL_REGS, + LIM_REG_CLASSES +}; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Give names of register classes as strings for dump file. */ +#define REG_CLASS_NAMES \ +{ \ + "NO_REGS", \ + "FPU_REGS", \ + "GENERAL_REGS", \ + "ALL_REGS", \ +} + +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ +#define REG_CLASS_CONTENTS \ +{ \ + 0x0000000, /* NO_REGS */ \ + 0x0FF0000, /* FPU_REGS */ \ + 0x200FFFF, /* GENERAL_REGS */ \ + 0x2FFFFFF /* ALL_REGS */ \ +} + +/* The same information, inverted: + Return the class number of the smallest class containing + reg number REGNO. This could be a conditional expression + or could index an array. */ +#define REGNO_REG_CLASS(REGNO) \ + (((REGNO) < 16 || REGNO == FRAME_POINTER_REGNUM \ + || REGNO == ARG_POINTER_REGNUM) \ + ? GENERAL_REGS : (REGNO) == CC_REGNUM \ + ? NO_REGS : FPU_REGS) + +/* The class value for index registers, and the one for base regs. */ +#define INDEX_REG_CLASS GENERAL_REGS +#define BASE_REG_CLASS GENERAL_REGS + +/* Get reg_class from a letter such as appears in the machine description. + We only need constraint `f' for FPU_REGS (`r' == GENERAL_REGS). */ +#define REG_CLASS_FROM_LETTER(C) \ + ((C)=='f' ? FPU_REGS : 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: immediate arithmetic operand (i.e. 8 bits shifted as required). + J: valid indexing constants. + K: ~value ok in rhs argument of data operand. + L: -value ok in rhs argument of data operand. + M: 0..32, or a power of 2 (for shifts, or mult done by shift). */ +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? const_ok_for_arm (VALUE) : \ + (C) == 'J' ? ((VALUE) < 4096 && (VALUE) > -4096) : \ + (C) == 'K' ? (const_ok_for_arm (~(VALUE))) : \ + (C) == 'L' ? (const_ok_for_arm (-(VALUE))) : \ + (C) == 'M' ? (((VALUE >= 0 && VALUE <= 32)) \ + || (((VALUE) & ((VALUE) - 1)) == 0)) \ + : 0) + +/* For the ARM, `Q' means that this is a memory operand that is just + an offset from a register. + `S' means any symbol that has the SYMBOL_REF_FLAG set or a CONSTANT_POOL + address. This means that the symbol is in the text segment and can be + accessed without using a load. */ + +#define EXTRA_CONSTRAINT(OP, C) \ + ((C) == 'Q' ? GET_CODE (OP) == MEM && GET_CODE (XEXP (OP, 0)) == REG \ + : (C) == 'R' ? (GET_CODE (OP) == MEM \ + && GET_CODE (XEXP (OP, 0)) == SYMBOL_REF \ + && CONSTANT_POOL_ADDRESS_P (XEXP (OP, 0))) \ + : (C) == 'S' ? (optimize > 0 && CONSTANT_ADDRESS_P (OP)) \ + : 0) + +/* Constant letter 'G' for the FPU immediate constants. + 'H' means the same constant negated. */ +#define CONST_DOUBLE_OK_FOR_LETTER_P(X,C) \ + ((C) == 'G' ? const_double_rtx_ok_for_fpu (X) \ + : (C) == 'H' ? neg_const_double_rtx_ok_for_fpu (X) : 0) + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. */ +#define PREFERRED_RELOAD_CLASS(X, CLASS) (CLASS) + +/* Return the register class of a scratch register needed to copy IN into + or out of a register in CLASS in MODE. If it can be done directly, + NO_REGS is returned. */ +#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS,MODE,X) \ + (((MODE) == HImode && ! arm_arch4 && true_regnum (X) == -1) \ + ? GENERAL_REGS : NO_REGS) + +/* If we need to load shorts byte-at-a-time, then we need a scratch. */ +#define SECONDARY_INPUT_RELOAD_CLASS(CLASS,MODE,X) \ + (((MODE) == HImode && ! arm_arch4 && TARGET_SHORT_BY_BYTES \ + && (GET_CODE (X) == MEM \ + || ((GET_CODE (X) == REG || GET_CODE (X) == SUBREG) \ + && true_regnum (X) == -1))) \ + ? GENERAL_REGS : NO_REGS) + +/* Try a machine-dependent way of reloading an illegitimate address + operand. If we find one, push the reload and jump to WIN. This + macro is used in only one place: `find_reloads_address' in reload.c. + + For the ARM, we wish to handle large displacements off a base + register by splitting the addend across a MOV and the mem insn. + This can cut the number of reloads needed. */ +#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \ +do { \ + if (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REGNO (XEXP (X, 0)) < FIRST_PSEUDO_REGISTER \ + && REG_MODE_OK_FOR_BASE_P (XEXP (X, 0), MODE) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT) \ + { \ + HOST_WIDE_INT val = INTVAL (XEXP (X, 1)); \ + HOST_WIDE_INT low, high; \ + \ + if (MODE == DImode || (TARGET_SOFT_FLOAT && MODE == DFmode)) \ + low = ((val & 0xf) ^ 0x8) - 0x8; \ + else if (MODE == SImode || MODE == QImode \ + || (MODE == SFmode && TARGET_SOFT_FLOAT) \ + || (MODE == HImode && ! arm_arch4)) \ + /* Need to be careful, -4096 is not a valid offset */ \ + low = val >= 0 ? (val & 0xfff) : -((-val) & 0xfff); \ + else if (MODE == HImode && arm_arch4) \ + /* Need to be careful, -256 is not a valid offset */ \ + low = val >= 0 ? (val & 0xff) : -((-val) & 0xff); \ + else if (GET_MODE_CLASS (MODE) == MODE_FLOAT \ + && TARGET_HARD_FLOAT) \ + /* Need to be careful, -1024 is not a valid offset */ \ + low = val >= 0 ? (val & 0x3ff) : -((-val) & 0x3ff); \ + else \ + break; \ + \ + high = ((((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000); \ + /* Check for overflow or zero */ \ + if (low == 0 || high == 0 || (high + low != val)) \ + break; \ + \ + /* Reload the high part into a base reg; leave the low part \ + in the mem. */ \ + X = gen_rtx_PLUS (GET_MODE (X), \ + gen_rtx_PLUS (GET_MODE (X), XEXP (X, 0), \ + GEN_INT (high)), \ + GEN_INT (low)); \ + push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL_PTR, \ + BASE_REG_CLASS, GET_MODE (X), VOIDmode, 0, 0, \ + OPNUM, TYPE); \ + goto WIN; \ + } \ +} while (0) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. + ARM regs are UNITS_PER_WORD bits while FPU regs can hold any FP mode */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((CLASS) == FPU_REGS ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Moves between FPU_REGS and GENERAL_REGS are two memory insns. */ +#define REGISTER_MOVE_COST(CLASS1, CLASS2) \ + ((((CLASS1) == FPU_REGS && (CLASS2) != FPU_REGS) \ + || ((CLASS2) == FPU_REGS && (CLASS1) != FPU_REGS)) \ + ? 20 : 2) + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD 1 + +/* 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 + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. */ +/* The push insns do not do this rounding implicitly. So don't define this. */ +/* #define PUSH_ROUNDING(NPUSHED) (((NPUSHED) + 3) & ~3) */ + +/* Define this if the maximum size of all the outgoing args is to be + accumulated and pushed during the prologue. The amount can be + found in the variable current_function_outgoing_args_size. */ +#define ACCUMULATE_OUTGOING_ARGS + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 4 + +/* Value is the number of byte of arguments automatically + popped when returning from a subroutine call. + FUNDECL is the declaration node of the function (as a tree), + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. + SIZE is the number of bytes of arguments passed on the stack. + + On the ARM, the caller does not pop any of its arguments that were passed + on the stack. */ +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 + +/* 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) \ + (GET_MODE_CLASS (TYPE_MODE (VALTYPE)) == MODE_FLOAT && TARGET_HARD_FLOAT \ + ? gen_rtx (REG, TYPE_MODE (VALTYPE), 16) \ + : gen_rtx (REG, TYPE_MODE (VALTYPE), 0)) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ +#define LIBCALL_VALUE(MODE) \ + (GET_MODE_CLASS (MODE) == MODE_FLOAT && TARGET_HARD_FLOAT \ + ? gen_rtx (REG, MODE, 16) \ + : gen_rtx (REG, MODE, 0)) + +/* 1 if N is a possible register number for a function value. + On the ARM, only r0 and f0 can return results. */ +#define FUNCTION_VALUE_REGNO_P(REGNO) \ + ((REGNO) == 0 || ((REGNO) == 16) && TARGET_HARD_FLOAT) + +/* How large values are returned */ +/* A C expression which can inhibit the returning of certain function values + in registers, based on the type of value. */ +/* CYGNUS LOCAL */ +#define RETURN_IN_MEMORY(TYPE) arm_return_in_memory (TYPE) +/* END CYGNUS LOCAL */ + +/* Define DEFAULT_PCC_STRUCT_RETURN to 1 if all structure and union return + values must be in memory. On the ARM, they need only do so if larger + than a word, or if they contain elements offset from zero in the struct. */ +#define DEFAULT_PCC_STRUCT_RETURN 0 + +/* Define where to put the arguments to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). + + On the ARM, normally the first 16 bytes are passed in registers r0-r3; all + other arguments are passed on the stack. If (NAMED == 0) (which happens + only in assign_parms, since SETUP_INCOMING_VARARGS is defined), say it is + passed in the stack (function_prologue will indeed make it pass in the + stack if necessary). */ +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + ((MODE) == VOIDmode \ + ? GEN_INT ((CUM).call_cookie) \ + : (NAMED) \ + ? ((CUM).nregs >= 16 ? 0 : gen_rtx (REG, MODE, (CUM).nregs / 4)) \ + : 0) + +/* 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) \ + ((CUM).nregs < 16 && 16 < (CUM).nregs + ((MODE) != BLKmode \ + ? GET_MODE_SIZE (MODE) \ + : int_size_in_bytes (TYPE)) \ + ? 4 - (CUM).nregs / 4 : 0) + +/* A C type for declaring a variable that is used as the first argument of + `FUNCTION_ARG' and other related values. For some target machines, the + type `int' suffices and can hold the number of bytes of argument so far. + + On the ARM, this is the number of bytes of arguments scanned so far. */ +typedef struct +{ + /* This is the number of registers of arguments scanned so far. */ + int nregs; + /* One of CALL_NORMAL, CALL_LONG or CALL_SHORT . */ + int call_cookie; +} CUMULATIVE_ARGS; + +/* 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. + On the ARM, the offset starts at 0. */ +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ + ((CUM).nregs = (((FNTYPE) && aggregate_value_p (TREE_TYPE ((FNTYPE)))) \ + ? 4 : 0), \ + (CUM).call_cookie = \ + (((FNTYPE) && lookup_attribute ("short_call", TYPE_ATTRIBUTES (FNTYPE))) \ + ? CALL_SHORT \ + : (((FNTYPE) && lookup_attribute ("long_call", \ + TYPE_ATTRIBUTES (FNTYPE)))\ + || TARGET_LONG_CALLS) \ + ? CALL_LONG \ + : CALL_NORMAL)) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + (CUM).nregs += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3) \ + +/* 1 if N is a possible register number for function argument passing. + On the ARM, r0-r3 are used to pass args. */ +#define FUNCTION_ARG_REGNO_P(REGNO) \ + ((REGNO) >= 0 && (REGNO) <= 3) + +/* Perform any 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. + + On the ARM, PRETEND_SIZE is set in order to have the prologue push the last + named arg and all anonymous args onto the stack. + XXX I know the prologue shouldn't be pushing registers, but it is faster + that way. */ +#define SETUP_INCOMING_VARARGS(CUM, MODE, TYPE, PRETEND_SIZE, NO_RTL) \ +{ \ + extern int current_function_anonymous_args; \ + current_function_anonymous_args = 1; \ + if ((CUM).nregs < 16) \ + (PRETEND_SIZE) = 16 - (CUM).nregs; \ +} + +/* Generate assembly output for the start of a function. */ +#define FUNCTION_PROLOGUE(STREAM, SIZE) \ + output_func_prologue ((STREAM), (SIZE)) + +/* Call the function profiler with a given profile label. The Acorn compiler + puts this BEFORE the prolog but gcc puts it afterwards. The ``mov ip,lr'' + seems like a good idea to stick with cc convention. ``prof'' doesn't seem + to mind about this! */ +#define FUNCTION_PROFILER(STREAM,LABELNO) \ +{ \ + fprintf(STREAM, "\tmov\t%sip, %slr\n", REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf(STREAM, "\tbl\tmcount\n"); \ + fprintf(STREAM, "\t.word\tLP%d\n", (LABELNO)); \ +} + +/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, + the stack pointer does not matter. The value is tested only in + functions that have frame pointers. + No definition is equivalent to always zero. + + On the ARM, the function epilogue recovers the stack pointer from the + frame. */ +#define EXIT_IGNORE_STACK 1 + +/* Generate the assembly code for function exit. */ +#define FUNCTION_EPILOGUE(STREAM, SIZE) \ + output_func_epilogue ((STREAM), (SIZE)) + +/* Determine if the epilogue should be output as RTL. + You should override this if you define FUNCTION_EXTRA_EPILOGUE. */ +#define USE_RETURN_INSN(ISCOND) use_return_insn (ISCOND) + +/* Definitions for register eliminations. + + This is an array of structures. Each structure initializes one pair + of eliminable registers. The "from" register number is given first, + followed by "to". Eliminations of the same "from" register are listed + in order of preference. + + We have two registers that can be eliminated on the ARM. First, the + arg pointer register can often be eliminated in favor of the stack + pointer register. Secondly, the pseudo frame pointer register can always + be eliminated; it is replaced with either the stack or the real frame + pointer. */ + +#define ELIMINABLE_REGS \ +{{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + {ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ + {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + {FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} + +/* Given FROM and TO register numbers, say whether this elimination is allowed. + Frame pointer elimination is automatically handled. + + All eliminations are permissible. Note that ARG_POINTER_REGNUM and + HARD_FRAME_POINTER_REGNUM are in fact the same thing. If we need a frame + pointer, we must eliminate FRAME_POINTER_REGNUM into + HARD_FRAME_POINTER_REGNUM and not into STACK_POINTER_REGNUM. */ +#define CAN_ELIMINATE(FROM, TO) \ + (((TO) == STACK_POINTER_REGNUM && frame_pointer_needed) ? 0 : 1) + +/* Define the offset between two registers, one to be eliminated, and the other + its replacement, at the start of a routine. */ +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ +{ \ + int volatile_func = arm_volatile_func (); \ + if ((FROM) == ARG_POINTER_REGNUM && (TO) == HARD_FRAME_POINTER_REGNUM)\ + (OFFSET) = 0; \ + else if ((FROM) == FRAME_POINTER_REGNUM \ + && (TO) == STACK_POINTER_REGNUM) \ + (OFFSET) = (current_function_outgoing_args_size \ + + (get_frame_size () + 3 & ~3)); \ + else \ + { \ + int regno; \ + int offset = 12; \ + int saved_hard_reg = 0; \ + \ + if (! volatile_func) \ + { \ + for (regno = 0; regno <= 10; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + saved_hard_reg = 1, offset += 4; \ + for (regno = 16; regno <=23; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 12; \ + } \ + if ((FROM) == FRAME_POINTER_REGNUM) \ + (OFFSET) = -offset; \ + else \ + { \ + if (! frame_pointer_needed) \ + offset -= 16; \ + if (! volatile_func \ + && (regs_ever_live[14] || saved_hard_reg)) \ + offset += 4; \ + offset += current_function_outgoing_args_size; \ + (OFFSET) = (get_frame_size () + 3 & ~3) + offset; \ + } \ + } \ +} + +/* CYGNUS LOCAL */ +/* Special case handling of the location of arguments passed on the stack. */ +#define DEBUGGER_ARG_OFFSET(value, addr) value ? value : arm_debugger_arg_offset (value, addr) +/* END CYGNUS LOCAL */ + +/* Output assembler code for a block containing the constant parts + of a trampoline, leaving space for the variable parts. + + On the ARM, (if r8 is the static chain regnum, and remembering that + referencing pc adds an offset of 8) the trampoline looks like: + ldr r8, [pc, #0] + ldr pc, [pc] + .word static chain value + .word function's address + ??? FIXME: When the trampoline returns, r8 will be clobbered. */ +#define TRAMPOLINE_TEMPLATE(FILE) \ +{ \ + fprintf ((FILE), "\tldr\t%sr8, [%spc, #0]\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\tldr\t%spc, [%spc, #0]\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\t.word\t0\n"); \ + fprintf ((FILE), "\t.word\t0\n"); \ +} + +/* Length in units of the trampoline for entering a nested function. */ +#define TRAMPOLINE_SIZE 16 + +/* Alignment required for a trampoline in units. */ +#define TRAMPOLINE_ALIGN 4 + +/* Emit RTL insns to initialize the variable parts of a trampoline. + FNADDR is an RTX for the address of the function's pure code. + CXT is an RTX for the static chain value for the function. */ +#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ +{ \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 8)), \ + (CXT)); \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 12)), \ + (FNADDR)); \ +} + + +/* Addressing modes, and classification of registers for them. */ + +#define HAVE_POST_INCREMENT 1 +#define HAVE_PRE_INCREMENT 1 +#define HAVE_POST_DECREMENT 1 +#define HAVE_PRE_DECREMENT 1 + +/* Macros to check register numbers against specific register classes. */ + +/* These assume that REGNO is a hard or pseudo reg number. + They give nonzero only if REGNO is a hard reg of the suitable class + or a pseudo reg currently allocated to a suitable hard reg. + Since they use reg_renumber, they are safe only once reg_renumber + has been allocated, which happens in local-alloc.c. + + On the ARM, don't allow the pc to be used. */ +#define REGNO_OK_FOR_BASE_P(REGNO) \ + ((REGNO) < 15 || (REGNO) == FRAME_POINTER_REGNUM \ + || (REGNO) == ARG_POINTER_REGNUM \ + || (unsigned) reg_renumber[(REGNO)] < 15 \ + || (unsigned) reg_renumber[(REGNO)] == FRAME_POINTER_REGNUM \ + || (unsigned) reg_renumber[(REGNO)] == ARG_POINTER_REGNUM) +#define REGNO_OK_FOR_INDEX_P(REGNO) \ + REGNO_OK_FOR_BASE_P(REGNO) + +/* Maximum number of registers that can appear in a valid memory address. + Shifts in addresses can't be by a register. */ + +#define MAX_REGS_PER_ADDRESS 2 + +/* Recognize any constant value that is a valid address. */ +/* XXX We can address any constant, eventually... */ + +#ifdef AOF_ASSEMBLER + +#define CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == SYMBOL_REF \ + && CONSTANT_POOL_ADDRESS_P (X)) + +#else + +#define CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == SYMBOL_REF \ + && (CONSTANT_POOL_ADDRESS_P (X) \ + || (optimize > 0 && SYMBOL_REF_FLAG (X)))) + +#endif /* AOF_ASSEMBLER */ + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. + + On the ARM, allow any integer (invalid ones are removed later by insn + patterns), nice doubles and symbol_refs which refer to the function's + constant pool XXX. */ +#define LEGITIMATE_CONSTANT_P(X) (! label_mentioned_p (X)) + +/* Flags for the call/call_value rtl operations set up by function_arg. */ +#define CALL_NORMAL 0x00000000 /* No special processing. */ +#define CALL_LONG 0x00000001 /* Always call indirect. */ +#define CALL_SHORT 0x00000002 /* Never call indirect. */ + +/* Symbols in the text segment can be accessed without indirecting via the + constant pool; it may take an extra binary operation, but this is still + faster than indirecting via memory. Don't do this when not optimizing, + since we won't be calculating al of the offsets necessary to do this + simplification. */ +/* This doesn't work with AOF syntax, since the string table may be in + a different AREA. */ +#ifndef AOF_ASSEMBLER +#define ENCODE_SECTION_INFO(decl) \ +{ \ + if (optimize > 0 && TREE_CONSTANT (decl) \ + && (!flag_writable_strings || TREE_CODE (decl) != STRING_CST)) \ + { \ + rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd' \ + ? TREE_CST_RTL (decl) : DECL_RTL (decl)); \ + SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1; \ + } \ + ARM_ENCODE_CALL_TYPE (decl) \ +} +#else +#define ENCODE_SECTION_INFO(decl) \ +{ \ + ARM_ENCODE_CALL_TYPE (decl) \ +} +#endif + +/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS + is a valid machine specific attribute for DECL. + The attributes in ATTRIBUTES have previously been assigned to DECL. */ +int arm_valid_machine_type_attribute (/* union tree_node *, union tree_node *, + union tree_node *, + union tree_node * */); +#define VALID_MACHINE_TYPE_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \ +arm_valid_machine_type_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS) + +/* If we are referencing a function that is weak then encode a long call + flag in the function name, otherwise if the function is static or + or known to be defined in this file then encode a short call flag. + This macro is used inside the ENCODE_SECTION macro. */ +#define ARM_ENCODE_CALL_TYPE(decl) \ + if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd') \ + { \ + if (TREE_CODE (decl) == FUNCTION_DECL && DECL_WEAK (decl)) \ + arm_encode_call_attribute (decl, LONG_CALL_FLAG_CHAR); \ + else if (! TREE_PUBLIC (decl)) \ + arm_encode_call_attribute (decl, SHORT_CALL_FLAG_CHAR); \ + } + +/* Special characters prefixed to function names + in order to encode attribute like information. + Note, '@' and '*' have already been taken. */ +#define SHORT_CALL_FLAG_CHAR '^' +#define LONG_CALL_FLAG_CHAR '#' + +#define ENCODED_SHORT_CALL_ATTR_P(SYMBOL_NAME) \ + (*(SYMBOL_NAME) == SHORT_CALL_FLAG_CHAR) + +#define ENCODED_LONG_CALL_ATTR_P(SYMBOL_NAME) \ + (*(SYMBOL_NAME) == LONG_CALL_FLAG_CHAR) + +#ifndef SUBTARGET_NAME_ENCODING_LENGTHS +#define SUBTARGET_NAME_ENCODING_LENGTHS +#endif + +/* This is a C fragement for the inside of a switch statement. + Each case label should return the number of characters to + be stripped from the start of a function's name, if that + name starts with the indicated character. */ +#define ARM_NAME_ENCODING_LENGTHS \ + case SHORT_CALL_FLAG_CHAR: return 1; \ + case LONG_CALL_FLAG_CHAR: return 1; \ + case '*': return 1; \ + SUBTARGET_NAME_ENCODING_LENGTHS + +/* This has to be handled by a function because more than part of the + ARM backend uses function name prefixes to encode attributes. */ +#undef STRIP_NAME_ENCODING +#define STRIP_NAME_ENCODING(VAR, SYMBOL_NAME) \ + (VAR) = arm_strip_name_encoding (SYMBOL_NAME) + +/* This is how to output a reference to a user-level label named NAME. + `assemble_name' uses this. */ +#undef ASM_OUTPUT_LABELREF +#define ASM_OUTPUT_LABELREF(FILE, NAME) \ + asm_fprintf (FILE, "%U%s", arm_strip_name_encoding (NAME)) + +/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx + and check its validity for a certain class. + We have two alternate definitions for each of them. + The usual definition accepts all pseudo regs; the other rejects + them unless they have been allocated suitable hard regs. + The symbol REG_OK_STRICT causes the latter definition to be used. */ +#ifndef REG_OK_STRICT + +/* Nonzero if X is a hard reg that can be used as a base reg + or if it is a pseudo reg. */ +#define REG_OK_FOR_BASE_P(X) \ + (REGNO (X) < 16 || REGNO (X) >= FIRST_PSEUDO_REGISTER \ + || REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM) + +/* Nonzero if X is a hard reg that can be used as an index + or if it is a pseudo reg. */ +#define REG_OK_FOR_INDEX_P(X) \ + REG_OK_FOR_BASE_P(X) + +#define REG_OK_FOR_PRE_POST_P(X) \ + (REGNO (X) < 16 || REGNO (X) >= FIRST_PSEUDO_REGISTER \ + || REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM) + +#else + +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + +/* Nonzero if X is a hard reg that can be used as an index. */ +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) + +#define REG_OK_FOR_PRE_POST_P(X) \ + (REGNO (X) < 16 || (unsigned) reg_renumber[REGNO (X)] < 16 \ + || REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO (X)] == FRAME_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO (X)] == ARG_POINTER_REGNUM) + +#endif + +/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression + that is a valid memory address for an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS. */ +#define BASE_REGISTER_RTX_P(X) \ + (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) + +#define INDEX_REGISTER_RTX_P(X) \ + (GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X)) + +/* A C statement (sans semicolon) to jump to LABEL for legitimate index RTXs + used by the macro GO_IF_LEGITIMATE_ADDRESS. Floating point indices can + only be small constants. */ +#define GO_IF_LEGITIMATE_INDEX(MODE, BASE_REGNO, INDEX, LABEL) \ +do \ +{ \ + HOST_WIDE_INT range; \ + enum rtx_code code = GET_CODE (INDEX); \ + \ + if (TARGET_HARD_FLOAT && GET_MODE_CLASS (MODE) == MODE_FLOAT) \ + { \ + if (code == CONST_INT && INTVAL (INDEX) < 1024 \ + && INTVAL (INDEX) > -1024 \ + && (INTVAL (INDEX) & 3) == 0) \ + goto LABEL; \ + } \ + else \ + { \ + if (INDEX_REGISTER_RTX_P (INDEX) && GET_MODE_SIZE (MODE) <= 4) \ + goto LABEL; \ + if (GET_MODE_SIZE (MODE) <= 4 && code == MULT \ + && (! arm_arch4 || (MODE) != HImode)) \ + { \ + rtx xiop0 = XEXP (INDEX, 0); \ + rtx xiop1 = XEXP (INDEX, 1); \ + if (INDEX_REGISTER_RTX_P (xiop0) \ + && power_of_two_operand (xiop1, SImode)) \ + goto LABEL; \ + if (INDEX_REGISTER_RTX_P (xiop1) \ + && power_of_two_operand (xiop0, SImode)) \ + goto LABEL; \ + } \ + if (GET_MODE_SIZE (MODE) <= 4 \ + && (code == LSHIFTRT || code == ASHIFTRT \ + || code == ASHIFT || code == ROTATERT) \ + && (! arm_arch4 || (MODE) != HImode)) \ + { \ + rtx op = XEXP (INDEX, 1); \ + if (INDEX_REGISTER_RTX_P (XEXP (INDEX, 0)) \ + && GET_CODE (op) == CONST_INT && INTVAL (op) > 0 \ + && INTVAL (op) <= 31) \ + goto LABEL; \ + } \ + /* NASTY: Since this limits the addressing of unsigned byte loads */ \ + range = ((MODE) == HImode || (MODE) == QImode) \ + ? (arm_arch4 ? 256 : 4095) : 4096; \ + if (code == CONST_INT && INTVAL (INDEX) < range \ + && INTVAL (INDEX) > -range) \ + goto LABEL; \ + } \ +} while (0) + +/* Jump to LABEL if X is a valid address RTX. This must also take + REG_OK_STRICT into account when deciding about valid registers, but it uses + the above macros so we are in luck. Allow REG, REG+REG, REG+INDEX, + INDEX+REG, REG-INDEX, and non floating SYMBOL_REF to the constant pool. + Allow REG-only and AUTINC-REG if handling TImode or HImode. Other symbol + refs must be forced though a static cell to ensure addressability. */ +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \ +{ \ + if (BASE_REGISTER_RTX_P (X)) \ + goto LABEL; \ + else if ((GET_CODE (X) == POST_INC || GET_CODE (X) == PRE_DEC) \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_PRE_POST_P (XEXP (X, 0))) \ + goto LABEL; \ + else if (GET_MODE_SIZE (MODE) >= 4 && reload_completed \ + && (GET_CODE (X) == LABEL_REF \ + || (GET_CODE (X) == CONST \ + && GET_CODE (XEXP ((X), 0)) == PLUS \ + && GET_CODE (XEXP (XEXP ((X), 0), 0)) == LABEL_REF \ + && GET_CODE (XEXP (XEXP ((X), 0), 1)) == CONST_INT)))\ + goto LABEL; \ + else if ((MODE) == TImode) \ + ; \ + else if ((MODE) == DImode || (TARGET_SOFT_FLOAT && (MODE) == DFmode)) \ + { \ + if (GET_CODE (X) == PLUS && BASE_REGISTER_RTX_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT) \ + { \ + HOST_WIDE_INT val = INTVAL (XEXP (X, 1)); \ + if (val == 4 || val == -4 || val == -8) \ + goto LABEL; \ + } \ + } \ + else if (GET_CODE (X) == PLUS) \ + { \ + rtx xop0 = XEXP(X,0); \ + rtx xop1 = XEXP(X,1); \ + \ + if (BASE_REGISTER_RTX_P (xop0)) \ + GO_IF_LEGITIMATE_INDEX (MODE, REGNO (xop0), xop1, LABEL); \ + else if (BASE_REGISTER_RTX_P (xop1)) \ + GO_IF_LEGITIMATE_INDEX (MODE, REGNO (xop1), xop0, LABEL); \ + } \ + /* Reload currently can't handle MINUS, so disable this for now */ \ + /* else if (GET_CODE (X) == MINUS) \ + { \ + rtx xop0 = XEXP (X,0); \ + rtx xop1 = XEXP (X,1); \ + \ + if (BASE_REGISTER_RTX_P (xop0)) \ + GO_IF_LEGITIMATE_INDEX (MODE, -1, xop1, LABEL); \ + } */ \ + else if (GET_MODE_CLASS (MODE) != MODE_FLOAT \ + && GET_CODE (X) == SYMBOL_REF \ + && CONSTANT_POOL_ADDRESS_P (X)) \ + goto LABEL; \ + else if ((GET_CODE (X) == PRE_INC || GET_CODE (X) == POST_DEC) \ + && (GET_MODE_SIZE (MODE) <= 4) \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_PRE_POST_P (XEXP (X, 0))) \ + goto LABEL; \ +} + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. + + On the ARM, try to convert [REG, #BIGCONST] + into ADD BASE, REG, #UPPERCONST and [BASE, #VALIDCONST], + where VALIDCONST == 0 in case of TImode. */ +extern struct rtx_def *legitimize_pic_address (); +#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ +{ \ + if (GET_CODE (X) == PLUS) \ + { \ + rtx xop0 = XEXP (X, 0); \ + rtx xop1 = XEXP (X, 1); \ + \ + if (CONSTANT_P (xop0) && ! symbol_mentioned_p (xop0)) \ + xop0 = force_reg (SImode, xop0); \ + if (CONSTANT_P (xop1) && ! symbol_mentioned_p (xop1)) \ + xop1 = force_reg (SImode, xop1); \ + if (BASE_REGISTER_RTX_P (xop0) && GET_CODE (xop1) == CONST_INT) \ + { \ + HOST_WIDE_INT n, low_n; \ + rtx base_reg, val; \ + n = INTVAL (xop1); \ + \ + if (MODE == DImode || (TARGET_SOFT_FLOAT && MODE == DFmode)) \ + { \ + low_n = n & 0x0f; \ + n &= ~0x0f; \ + if (low_n > 4) \ + { \ + n += 16; \ + low_n -= 16; \ + } \ + } \ + else \ + { \ + low_n = ((MODE) == TImode ? 0 \ + : n >= 0 ? (n & 0xfff) : -((-n) & 0xfff)); \ + n -= low_n; \ + } \ + base_reg = gen_reg_rtx (SImode); \ + val = force_operand (gen_rtx (PLUS, SImode, xop0, \ + GEN_INT (n)), NULL_RTX); \ + emit_move_insn (base_reg, val); \ + (X) = (low_n == 0 ? base_reg \ + : gen_rtx (PLUS, SImode, base_reg, GEN_INT (low_n))); \ + } \ + else if (xop0 != XEXP (X, 0) || xop1 != XEXP (x, 1)) \ + (X) = gen_rtx (PLUS, SImode, xop0, xop1); \ + } \ + else if (GET_CODE (X) == MINUS) \ + { \ + rtx xop0 = XEXP (X, 0); \ + rtx xop1 = XEXP (X, 1); \ + \ + if (CONSTANT_P (xop0)) \ + xop0 = force_reg (SImode, xop0); \ + if (CONSTANT_P (xop1) && ! symbol_mentioned_p (xop1)) \ + xop1 = force_reg (SImode, xop1); \ + if (xop0 != XEXP (X, 0) || xop1 != XEXP (X, 1)) \ + (X) = gen_rtx (MINUS, SImode, xop0, xop1); \ + } \ + if (flag_pic) \ + (X) = legitimize_pic_address (OLDX, MODE, NULL_RTX); \ + if (memory_address_p (MODE, X)) \ + goto WIN; \ +} + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. */ +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ +{ \ + if (GET_CODE(ADDR) == PRE_DEC || GET_CODE(ADDR) == POST_DEC \ + || GET_CODE(ADDR) == PRE_INC || GET_CODE(ADDR) == POST_INC) \ + goto LABEL; \ +} + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE SImode + +/* 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 */ + +/* Specify the tree operation to be used to convert reals to integers. */ +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* This is the kind of divide that is easiest to do in the general case. */ +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* signed 'char' is most compatible, but RISC OS wants it unsigned. + unsigned is probably best, but may break some code. */ +#ifndef DEFAULT_SIGNED_CHAR +#define DEFAULT_SIGNED_CHAR 0 +#endif + +/* Don't cse the address of the function being compiled. */ +#define NO_RECURSIVE_FUNCTION_CSE 1 + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 4 + +/* Define if operations between registers always perform the operation + on the full register even if a narrower mode is specified. */ +#define WORD_REGISTER_OPERATIONS + +/* Define if loading in MODE, an integral mode narrower than BITS_PER_WORD + will either zero-extend or sign-extend. The value of this macro should + be the code that says which one of the two operations is implicitly + done, NIL if none. */ +#define LOAD_EXTEND_OP(MODE) \ + ((arm_arch4 || (MODE) == QImode) ? ZERO_EXTEND \ + : ((BYTES_BIG_ENDIAN && (MODE) == HImode) ? SIGN_EXTEND : NIL)) + +/* Define this if zero-extension is slow (more than one real instruction). + On the ARM, it is more than one instruction only if not fetching from + memory. */ +/* #define SLOW_ZERO_EXTEND */ + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* Immediate shift counts are truncated by the output routines (or was it + the assembler?). Shift counts in a register are truncated by ARM. Note + that the native compiler puts too large (> 32) immediate shift counts + into a register and shifts by the register, letting the ARM decide what + to do instead of doing that itself. */ +/* This is all wrong. Defining SHIFT_COUNT_TRUNCATED tells combine that + code like (X << (Y % 32)) for register X, Y is equivalent to (X << Y). + On the arm, Y in a register is used modulo 256 for the shift. Only for + rotates is modulo 32 used. */ +/* #define SHIFT_COUNT_TRUNCATED 1 */ + +/* All integers have the same format so truncation is easy. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) 1 + +/* Calling from registers is a massive pain. */ +#define NO_FUNCTION_CSE 1 + +/* Chars and shorts should be passed as ints. */ +#define PROMOTE_PROTOTYPES 1 + +/* The machine modes of pointers and functions */ +#define Pmode SImode +#define FUNCTION_MODE Pmode + +/* The structure type of the machine dependent info field of insns + No uses for this yet. */ +/* #define INSN_MACHINE_INFO struct machine_info */ + +/* The relative costs of various types of constants. Note that cse.c defines + REG = 1, SUBREG = 2, any node = (2 + sum of subnodes). */ +#define CONST_COSTS(RTX, CODE, OUTER_CODE) \ + case CONST_INT: \ + if (const_ok_for_arm (INTVAL (RTX))) \ + return (OUTER_CODE) == SET ? 2 : -1; \ + else if (OUTER_CODE == AND \ + && const_ok_for_arm (~INTVAL (RTX))) \ + return -1; \ + else if ((OUTER_CODE == COMPARE \ + || OUTER_CODE == PLUS || OUTER_CODE == MINUS) \ + && const_ok_for_arm (-INTVAL (RTX))) \ + return -1; \ + else \ + return 5; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 6; \ + case CONST_DOUBLE: \ + if (const_double_rtx_ok_for_fpu (RTX)) \ + return (OUTER_CODE) == SET ? 2 : -1; \ + else if (((OUTER_CODE) == COMPARE || (OUTER_CODE) == PLUS) \ + && neg_const_double_rtx_ok_for_fpu (RTX)) \ + return -1; \ + return(7); + +#define ARM_FRAME_RTX(X) \ + ((X) == frame_pointer_rtx || (X) == stack_pointer_rtx \ + || (X) == arg_pointer_rtx) + +#define DEFAULT_RTX_COSTS(X,CODE,OUTER_CODE) \ + return arm_rtx_costs (X, CODE, OUTER_CODE); + +/* Moves to and from memory are quite expensive */ +#define MEMORY_MOVE_COST(MODE,CLASS,IN) 10 + +/* All address computations that can be done are free, but rtx cost returns + the same for practically all of them. So we weight the different types + of address here in the order (most pref first): + PRE/POST_INC/DEC, SHIFT or NON-INT sum, INT sum, REG, MEM or LABEL. */ +#define ADDRESS_COST(X) \ + (10 - ((GET_CODE (X) == MEM || GET_CODE (X) == LABEL_REF \ + || GET_CODE (X) == SYMBOL_REF) \ + ? 0 \ + : ((GET_CODE (X) == PRE_INC || GET_CODE (X) == PRE_DEC \ + || GET_CODE (X) == POST_INC || GET_CODE (X) == POST_DEC) \ + ? 10 \ + : (((GET_CODE (X) == PLUS || GET_CODE (X) == MINUS) \ + ? 6 + (GET_CODE (XEXP (X, 1)) == CONST_INT ? 2 \ + : ((GET_RTX_CLASS (GET_CODE (XEXP (X, 0))) == '2' \ + || GET_RTX_CLASS (GET_CODE (XEXP (X, 0))) == 'c' \ + || GET_RTX_CLASS (GET_CODE (XEXP (X, 1))) == '2' \ + || GET_RTX_CLASS (GET_CODE (XEXP (X, 1))) == 'c') \ + ? 1 : 0)) \ + : 4))))) + + + +/* Try to generate sequences that don't involve branches, we can then use + conditional instructions */ +#define BRANCH_COST 4 + +/* A C statement to update the variable COST based on the relationship + between INSN that is dependent on DEP through dependence LINK. */ +#define ADJUST_COST(INSN,LINK,DEP,COST) \ + (COST) = arm_adjust_cost ((INSN), (LINK), (DEP), (COST)) + +/* Position Independent Code. */ +/* We decide which register to use based on the compilation options and + the assembler in use; this is more general than the APCS restriction of + using sb (r9) all the time. */ +extern int arm_pic_register; + +/* The register number of the register used to address a table of static + data addresses in memory. */ +#define PIC_OFFSET_TABLE_REGNUM arm_pic_register + +#define FINALIZE_PIC arm_finalize_pic () + +#define LEGITIMATE_PIC_OPERAND_P(X) (! symbol_mentioned_p (X)) + + + +/* Condition code information. */ +/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, + return the mode to be used for the comparison. + CCFPEmode should be used with floating inequalities, + CCFPmode should be used with floating equalities. + CC_NOOVmode should be used with SImode integer equalities. + CC_Zmode should be used if only the Z flag is set correctly + CCmode should be used otherwise. */ + +#define EXTRA_CC_MODES CC_NOOVmode, CC_Zmode, CC_SWPmode, \ + CCFPmode, CCFPEmode, CC_DNEmode, CC_DEQmode, CC_DLEmode, \ + CC_DLTmode, CC_DGEmode, CC_DGTmode, CC_DLEUmode, CC_DLTUmode, \ + CC_DGEUmode, CC_DGTUmode, CC_Cmode + +#define EXTRA_CC_NAMES "CC_NOOV", "CC_Z", "CC_SWP", "CCFP", "CCFPE", \ + "CC_DNE", "CC_DEQ", "CC_DLE", "CC_DLT", "CC_DGE", "CC_DGT", "CC_DLEU", \ + "CC_DLTU", "CC_DGEU", "CC_DGTU", "CC_C" + +enum machine_mode arm_select_cc_mode (); +#define SELECT_CC_MODE(OP,X,Y) arm_select_cc_mode ((OP), (X), (Y)) + +#define REVERSIBLE_CC_MODE(MODE) ((MODE) != CCFPEmode) + +enum rtx_code arm_canonicalize_comparison (); +#define CANONICALIZE_COMPARISON(CODE,OP0,OP1) \ +do \ +{ \ + if (GET_CODE (OP1) == CONST_INT \ + && ! (const_ok_for_arm (INTVAL (OP1)) \ + || (const_ok_for_arm (- INTVAL (OP1))))) \ + { \ + rtx const_op = OP1; \ + CODE = arm_canonicalize_comparison ((CODE), &const_op); \ + OP1 = const_op; \ + } \ +} while (0) + +#define STORE_FLAG_VALUE 1 + +/* Define the information needed to generate branch insns. This is + stored from the compare operation. Note that we can't use "rtx" here + since it hasn't been defined! */ + +extern struct rtx_def *arm_compare_op0, *arm_compare_op1; +extern int arm_compare_fp; + +/* Define the codes that are matched by predicates in arm.c */ +#define PREDICATE_CODES \ + {"s_register_operand", {SUBREG, REG}}, \ + {"f_register_operand", {SUBREG, REG}}, \ + {"arm_add_operand", {SUBREG, REG, CONST_INT}}, \ + {"fpu_add_operand", {SUBREG, REG, CONST_DOUBLE}}, \ + {"arm_rhs_operand", {SUBREG, REG, CONST_INT}}, \ + {"fpu_rhs_operand", {SUBREG, REG, CONST_DOUBLE}}, \ + {"arm_not_operand", {SUBREG, REG, CONST_INT}}, \ + {"offsettable_memory_operand", {MEM}}, \ + {"bad_signed_byte_operand", {MEM}}, \ + {"alignable_memory_operand", {MEM}}, \ + {"shiftable_operator", {PLUS, MINUS, AND, IOR, XOR}}, \ + {"minmax_operator", {SMIN, SMAX, UMIN, UMAX}}, \ + {"shift_operator", {ASHIFT, ASHIFTRT, LSHIFTRT, ROTATERT, MULT}}, \ + {"di_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE, MEM}}, \ + {"soft_df_operand", {SUBREG, REG, CONST_DOUBLE, MEM}}, \ + {"load_multiple_operation", {PARALLEL}}, \ + {"store_multiple_operation", {PARALLEL}}, \ + {"equality_operator", {EQ, NE}}, \ + {"arm_rhsm_operand", {SUBREG, REG, CONST_INT, MEM}}, \ + {"const_shift_operand", {CONST_INT}}, \ + {"index_operand", {SUBREG, REG, CONST_INT}}, \ + {"reg_or_int_operand", {SUBREG, REG, CONST_INT}}, \ + {"multi_register_push", {PARALLEL}}, \ + {"cc_register", {REG}}, \ + {"dominant_cc_register", {REG}}, + + + +/* Gcc puts the pool in the wrong place for ARM, since we can only + load addresses a limited distance around the pc. We do some + special munging to move the constant pool values to the correct + point in the code. */ +#define MACHINE_DEPENDENT_REORG(INSN) arm_reorg ((INSN)) + +/* The pool is empty, since we have moved everything into the code. */ +#define ASM_OUTPUT_SPECIAL_POOL_ENTRY(FILE,X,MODE,ALIGN,LABELNO,JUMPTO) \ + goto JUMPTO + +/* Output an internal label definition. */ +#ifndef ASM_OUTPUT_INTERNAL_LABEL +#define ASM_OUTPUT_INTERNAL_LABEL(STREAM, PREFIX, NUM) \ + do \ + { \ + char * s = (char *) alloca (40 + strlen (PREFIX)); \ + extern int arm_target_label, arm_ccfsm_state; \ + extern rtx arm_target_insn; \ + \ + if (arm_ccfsm_state == 3 && arm_target_label == (NUM) \ + && !strcmp (PREFIX, "L")) \ + { \ + arm_ccfsm_state = 0; \ + arm_target_insn = NULL; \ + } \ + ASM_GENERATE_INTERNAL_LABEL (s, (PREFIX), (NUM)); \ + /* CYGNUS LOCAL variation */ \ + arm_asm_output_label (STREAM, s); \ + /* END CYGNUS LOCAL variation */ \ + } while (0) +#endif + +/* CYGNUS LOCAL */ +/* Output a label definition. */ +#undef ASM_OUTPUT_LABEL +#define ASM_OUTPUT_LABEL(STREAM,NAME) arm_asm_output_label ((STREAM), (NAME)) +/* END CYGNUS LOCAL */ + +/* Output a push or a pop instruction (only used when profiling). */ +#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ + fprintf (STREAM,"\tstmfd\t%ssp!,{%s%s}\n", \ + REGISTER_PREFIX, REGISTER_PREFIX, reg_names [REGNO]) + +#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \ + fprintf (STREAM,"\tldmfd\t%ssp!,{%s%s}\n", \ + REGISTER_PREFIX, REGISTER_PREFIX, reg_names [REGNO]) + +/* Target characters. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* Only perform branch elimination (by making instructions conditional) if + we're optimising. Otherwise it's of no use anyway. */ +#define FINAL_PRESCAN_INSN(INSN, OPVEC, NOPERANDS) \ + if (optimize) \ + final_prescan_insn (INSN, OPVEC, NOPERANDS) + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '?' || (CODE) == '|' || (CODE) == '@') +/* Output an operand of an instruction. */ +#define PRINT_OPERAND(STREAM, X, CODE) \ + arm_print_operand (STREAM, X, CODE) + +#define ARM_SIGN_EXTEND(x) ((HOST_WIDE_INT) \ + (HOST_BITS_PER_WIDE_INT <= 32 ? (x) \ + : (((x) & (unsigned HOST_WIDE_INT) 0xffffffff) | \ + (((x) & (unsigned HOST_WIDE_INT) 0x80000000) \ + ? ((~ (HOST_WIDE_INT) 0) \ + & ~ (unsigned HOST_WIDE_INT) 0xffffffff) \ + : 0)))) + +/* Output the address of an operand. */ +#define PRINT_OPERAND_ADDRESS(STREAM,X) \ +{ \ + int is_minus = GET_CODE (X) == MINUS; \ + \ + if (GET_CODE (X) == REG) \ + fprintf (STREAM, "[%s%s, #0]", REGISTER_PREFIX, \ + reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == PLUS || is_minus) \ + { \ + rtx base = XEXP (X, 0); \ + rtx index = XEXP (X, 1); \ + char * base_reg_name; \ + HOST_WIDE_INT offset = 0; \ + if (GET_CODE (base) != REG) \ + { \ + /* Ensure that BASE is a register (one of them must be). */ \ + rtx temp = base; \ + base = index; \ + index = temp; \ + } \ + base_reg_name = reg_names[REGNO (base)]; \ + switch (GET_CODE (index)) \ + { \ + case CONST_INT: \ + offset = INTVAL (index); \ + if (is_minus) \ + offset = -offset; \ + fprintf (STREAM, "[%s%s, #%d]", REGISTER_PREFIX, \ + base_reg_name, offset); \ + break; \ + \ + case REG: \ + fprintf (STREAM, "[%s%s, %s%s%s]", REGISTER_PREFIX, \ + base_reg_name, is_minus ? "-" : "", \ + REGISTER_PREFIX, reg_names[REGNO (index)] ); \ + break; \ + \ + case MULT: \ + case ASHIFTRT: \ + case LSHIFTRT: \ + case ASHIFT: \ + case ROTATERT: \ + { \ + fprintf (STREAM, "[%s%s, %s%s%s", REGISTER_PREFIX, \ + base_reg_name, is_minus ? "-" : "", REGISTER_PREFIX,\ + reg_names[REGNO (XEXP (index, 0))]); \ + arm_print_operand (STREAM, index, 'S'); \ + fputs ("]", STREAM); \ + break; \ + } \ + \ + default: \ + abort(); \ + } \ + } \ + else if (GET_CODE (X) == PRE_INC || GET_CODE (X) == POST_INC \ + || GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_DEC) \ + { \ + extern int output_memory_reference_mode; \ + \ + if (GET_CODE (XEXP (X, 0)) != REG) \ + abort (); \ + \ + if (GET_CODE (X) == PRE_DEC || GET_CODE (X) == PRE_INC) \ + fprintf (STREAM, "[%s%s, #%s%d]!", REGISTER_PREFIX, \ + reg_names[REGNO (XEXP (X, 0))], \ + GET_CODE (X) == PRE_DEC ? "-" : "", \ + GET_MODE_SIZE (output_memory_reference_mode)); \ + else \ + fprintf (STREAM, "[%s%s], #%s%d", REGISTER_PREFIX, \ + reg_names[REGNO (XEXP (X, 0))], \ + GET_CODE (X) == POST_DEC ? "-" : "", \ + GET_MODE_SIZE (output_memory_reference_mode)); \ + } \ + else output_addr_const(STREAM, X); \ +} + +/* Handles PIC addr specially */ +#define OUTPUT_INT_ADDR_CONST(STREAM,X) \ + { \ + if (flag_pic && GET_CODE(X) == CONST && is_pic(X)) \ + { \ + output_addr_const(STREAM, XEXP (XEXP (XEXP (X, 0), 0), 0)); \ + fputs(" - (", STREAM); \ + output_addr_const(STREAM, XEXP (XEXP (XEXP (X, 0), 1), 0)); \ + fputs(")", STREAM); \ + } \ + else output_addr_const(STREAM, X); \ + } + +/* Output code to add DELTA to the first argument, and then jump to FUNCTION. + Used for C++ multiple inheritance. */ +#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ +do { \ + int mi_delta = (DELTA); \ + char *mi_op = mi_delta < 0 ? "sub" : "add"; \ + int shift = 0; \ + int this_regno = (aggregate_value_p (TREE_TYPE (TREE_TYPE (FUNCTION))) \ + ? 1 : 0); \ + if (mi_delta < 0) mi_delta = -mi_delta; \ + while (mi_delta != 0) \ + { \ + if (mi_delta & (3 << shift) == 0) \ + shift += 2; \ + else \ + { \ + fprintf (FILE, "\t%s\t%s%s, %s%s, #%d\n", \ + mi_op, REGISTER_PREFIX, reg_names[this_regno], \ + REGISTER_PREFIX, reg_names[this_regno], \ + mi_delta & (0xff << shift)); \ + /* CYGNUS LOCAL */ \ + arm_increase_location (4); \ + /* END CYGNUS LOCAL */ \ + mi_delta &= ~(0xff << shift); \ + shift += 8; \ + } \ + } \ + fputs ("\tb\t", FILE); \ + assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ + fputc ('\n', FILE); \ + /* CYGNUS LOCAL */ \ + arm_increase_location (4); \ + /* END CYGNUS LOCAL */ \ +} while (0) + +/* A C expression whose value is RTL representing the value of the return + address for the frame COUNT steps up from the current frame. */ + +#define RETURN_ADDR_RTX(COUNT, FRAME) \ + ((COUNT == 0) \ + ? gen_rtx (MEM, Pmode, plus_constant (FRAME, -4)) \ + : NULL_RTX) + +/* Used to mask out junk bits from the return address, such as + processor state, interrupt status, condition codes and the like. */ +#define MASK_RETURN_ADDR \ + /* If we are generating code for an ARM2/ARM3 machine or for an ARM6 \ + in 26 bit mode, the condition codes must be masked out of the \ + return address. This does not apply to ARM6 and later processors \ + when running in 32 bit mode. */ \ + ((!TARGET_APCS_32) ? (GEN_INT (0x03fffffc)) : (GEN_INT (0xffffffff))) + +/* Prototypes for arm.c -- actually, they aren't since the types aren't + fully defined yet. */ + +char *arm_strip_name_encoding (/* const char * */); +int arm_is_longcall_p (/* rtx, int, int */); + +void arm_override_options (/* void */); +int use_return_insn (/* void */); +int const_ok_for_arm (/* HOST_WIDE_INT */); +int const_ok_for_op (/* HOST_WIDE_INT, enum rtx_code, + enum machine_mode */); +int arm_split_constant (/* enum rtx_code, enum machine_mode, + HOST_WIDE_INT, struct rtx_def *, + struct rtx_def *, int */); +enum rtx_code arm_canonicalize_comparison (/* enum rtx_code, + struct rtx_def ** */); +int arm_return_in_memory (/* union tree_node * */); +int legitimate_pic_operand_p (/* struct rtx_def * */); +struct rtx_def *legitimize_pic_address (/* struct rtx_def *, + enum machine_mode, + struct rtx_def * */); +int is_pic (/* struct rtx_def * */); +void arm_finalize_pic (/* void */); +int arm_rtx_costs (/* struct rtx_def *, enum rtx_code, enum rtx_code */); +int arm_adjust_cost (/* struct rtx_def *, struct rtx_def *, + struct rtx_def *, int */); +int const_double_rtx_ok_for_fpu (/* struct rtx_def * */); +int neg_const_double_rtx_ok_for_fpu (/* struct rtx_def * */); +int s_register_operand (/* struct rtx_def *, enum machine_mode */); +int f_register_operand (/* struct rtx_def *, enum machine_mode */); +int reg_or_int_operand (/* struct rtx_def *, enum machine_mode */); +int reload_memory_operand (/* struct rtx_def *, enum machine_mode */); +int arm_rhs_operand (/* struct rtx_def *, enum machine_mode */); +int arm_rhsm_operand (/* struct rtx_def *, enum machine_mode */); +int arm_add_operand (/* struct rtx_def *, enum machine_mode */); +int arm_not_operand (/* struct rtx_def *, enum machine_mode */); +int offsettable_memory_operand (/* struct rtx_def *, enum machine_mode */); +int alignable_memory_operand (/* struct rtx_def *, enum machine_mode */); +int bad_signed_byte_operand (/* struct rtx_def *, enum machine_mode */); +int fpu_rhs_operand (/* struct rtx_def *, enum machine_mode */); +int fpu_add_operand (/* struct rtx_def *, enum machine_mode */); +int power_of_two_operand (/* struct rtx_def *, enum machine_mode */); +int di_operand (/* struct rtx_def *, enum machine_mode */); +int soft_df_operand (/* struct rtx_def *, enum machine_mode */); +int index_operand (/* struct rtx_def *, enum machine_mode */); +int const_shift_operand (/* struct rtx_def *, enum machine_mode */); +int shiftable_operator (/* struct rtx_def *, enum machine_mode */); +int shift_operator (/* struct rtx_def *, enum machine_mode */); +int equality_operator (/* struct rtx_def *, enum machine_mode */); +int minmax_operator (/* struct rtx_def *, enum machine_mode */); +int cc_register (/* struct rtx_def *, enum machine_mode */); +int dominant_cc_register (/* struct rtx_def *, enum machine_mode */); +int symbol_mentioned_p (/* struct rtx_def * */); +int label_mentioned_p (/* struct rtx_def * */); +enum rtx_code minmax_code (/* struct rtx_def * */); +int adjacent_mem_locations (/* struct rtx_def *, struct rtx_def * */); +int load_multiple_operation (/* struct rtx_def *, enum machine_mode */); +int store_multiple_operation (/* struct rtx_def *, enum machine_mode */); +int load_multiple_sequence (/* struct rtx_def **, int, int *, int *, + HOST_WIDE_INT * */); +char *emit_ldm_seq (/* struct rtx_def **, int */); +int store_multiple_sequence (/* struct rtx_def **, int, int *, int *, + HOST_WIDE_INT * */); +char *emit_stm_seq (/* struct rtx_def **, int */); +int multi_register_push (/* struct rtx_def *, enum machine_mode */); +int arm_valid_machine_decl_attribute (/* union tree_node *, union tree_node *, + union tree_node *, + union tree_node * */); +struct rtx_def *arm_gen_load_multiple (/* int, int, struct rtx_def *, + int, int, int, int, int */); +struct rtx_def *arm_gen_store_multiple (/* int, int, struct rtx_def *, + int, int, int, int, int */); +int arm_gen_movstrqi (/* struct rtx_def ** */); +struct rtx_def *gen_rotated_half_load (/* struct rtx_def * */); +enum machine_mode arm_select_cc_mode (/* enum rtx_code, struct rtx_def *, + struct rtx_def * */); +struct rtx_def *gen_compare_reg (/* enum rtx_code, struct rtx_def *, + struct rtx_def * */); +void arm_reload_in_hi (/* struct rtx_def ** */); +void arm_reload_out_hi (/* struct rtx_def ** */); +void arm_reorg (/* struct rtx_def * */); +char *fp_immediate_constant (/* struct rtx_def * */); +void print_multi_reg (/* FILE *, char *, int, int */); +char *output_call (/* struct rtx_def ** */); +char *output_call_mem (/* struct rtx_def ** */); +char *output_mov_long_double_fpu_from_arm (/* struct rtx_def ** */); +char *output_mov_long_double_arm_from_fpu (/* struct rtx_def ** */); +char *output_mov_long_double_arm_from_arm (/* struct rtx_def ** */); +char *output_mov_double_fpu_from_arm (/* struct rtx_def ** */); +char *output_mov_double_arm_from_fpu (/* struct rtx_def ** */); +char *output_move_double (/* struct rtx_def ** */); +char *output_mov_immediate (/* struct rtx_def ** */); +char *output_add_immediate (/* struct rtx_def ** */); +char *arithmetic_instr (/* struct rtx_def *, int */); +void output_ascii_pseudo_op (/* FILE *, unsigned char *, int */); +char *output_return_instruction (/* struct rtx_def *, int, int */); +int arm_volatile_func (/* void */); +void output_func_prologue (/* FILE *, int */); +void output_func_epilogue (/* FILE *, int */); +void arm_expand_prologue (/* void */); +void arm_print_operand (/* FILE *, struct rtx_def *, int */); +void final_prescan_insn (/* struct rtx_def *, struct rtx_def **, int */); +#ifdef AOF_ASSEMBLER +struct rtx_def *aof_pic_entry (/* struct rtx_def * */); +void aof_dump_pic_table (/* FILE * */); +char *aof_text_section (/* void */); +char *aof_data_section (/* void */); +void aof_add_import (/* char * */); +void aof_delete_import (/* char * */); +void aof_dump_imports (/* FILE * */); +#endif +/* CYGNUS LOCAL nickc */ +int ok_integer_or_other (); +/* END CYGNUS LOCAL */ +//int s_register_operand (/* register rtx op, enum machine_mode mode */); + +#endif /* __ARM_H__ */ diff --git a/gcc_arm/config/arm/arm_990720.h b/gcc_arm/config/arm/arm_990720.h new file mode 100755 index 0000000..6e4a300 --- /dev/null +++ b/gcc_arm/config/arm/arm_990720.h @@ -0,0 +1,2210 @@ +/* Definitions of target machine for GNU compiler, for Acorn RISC Machine. + Copyright (C) 1991, 93, 94, 95, 96, 97, 98, 1999 Free Software Foundation, Inc. + Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl) + and Martin Simmons (@harleqn.co.uk). + More major hacks by Richard Earnshaw (rwe11@cl.cam.ac.uk) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Configuration triples for ARM ports work as follows: + (This is a bit of a mess and needs some thought) + arm-*-*: little endian + armel-*-*: little endian + armeb-*-*: big endian + If a non-embedded environment (ie: "real" OS) is specified, `arm' + should default to that used by the OS. +*/ + +#ifndef __ARM_H__ +#define __ARM_H__ + +#define TARGET_CPU_arm2 0x0000 +#define TARGET_CPU_arm250 0x0000 +#define TARGET_CPU_arm3 0x0000 +#define TARGET_CPU_arm6 0x0001 +#define TARGET_CPU_arm600 0x0001 +#define TARGET_CPU_arm610 0x0002 +#define TARGET_CPU_arm7 0x0001 +#define TARGET_CPU_arm7m 0x0004 +#define TARGET_CPU_arm7dm 0x0004 +#define TARGET_CPU_arm7dmi 0x0004 +#define TARGET_CPU_arm700 0x0001 +#define TARGET_CPU_arm710 0x0002 +#define TARGET_CPU_arm7100 0x0002 +#define TARGET_CPU_arm7500 0x0002 +#define TARGET_CPU_arm7500fe 0x1001 +#define TARGET_CPU_arm7tdmi 0x0008 +#define TARGET_CPU_arm8 0x0010 +#define TARGET_CPU_arm810 0x0020 +#define TARGET_CPU_strongarm 0x0040 +#define TARGET_CPU_strongarm110 0x0040 +#define TARGET_CPU_strongarm1100 0x0040 +#define TARGET_CPU_arm9 0x0080 +#define TARGET_CPU_arm9tdmi 0x0080 +/* Configure didn't specify */ +#define TARGET_CPU_generic 0x8000 + +enum arm_cond_code +{ + ARM_EQ = 0, ARM_NE, ARM_CS, ARM_CC, ARM_MI, ARM_PL, ARM_VS, ARM_VC, + ARM_HI, ARM_LS, ARM_GE, ARM_LT, ARM_GT, ARM_LE, ARM_AL, ARM_NV +}; +extern enum arm_cond_code arm_current_cc; +extern char *arm_condition_codes[]; + +#define ARM_INVERSE_CONDITION_CODE(X) ((enum arm_cond_code) (((int)X) ^ 1)) + +/* This is needed by the tail-calling peepholes */ +extern int frame_pointer_needed; + + +/* Just in case configure has failed to define anything. */ +#ifndef TARGET_CPU_DEFAULT +#define TARGET_CPU_DEFAULT TARGET_CPU_generic +#endif + +/* If the configuration file doesn't specify the cpu, the subtarget may + override it. If it doesn't, then default to an ARM6. */ +#if TARGET_CPU_DEFAULT == TARGET_CPU_generic +#undef TARGET_CPU_DEFAULT +#ifdef SUBTARGET_CPU_DEFAULT +#define TARGET_CPU_DEFAULT SUBTARGET_CPU_DEFAULT +#else +#define TARGET_CPU_DEFAULT TARGET_CPU_arm6 +#endif +#endif + +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm2 +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_2__" +#else +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm6 || TARGET_CPU_DEFAULT == TARGET_CPU_arm610 || TARGET_CPU_DEFAULT == TARGET_CPU_arm7500fe +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_3__" +#else +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm7m +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_3M__" +#else +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm7tdmi || TARGET_CPU_DEFAULT == TARGET_CPU_arm9 +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_4T__" +#else +#if TARGET_CPU_DEFAULT == TARGET_CPU_arm8 || TARGET_CPU_DEFAULT == TARGET_CPU_arm810 || TARGET_CPU_DEFAULT == TARGET_CPU_strongarm +#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_4__" +#else +Unrecognized value in TARGET_CPU_DEFAULT. +#endif +#endif +#endif +#endif +#endif + +#ifndef CPP_PREDEFINES +#define CPP_PREDEFINES "-Darm -Acpu(arm) -Amachine(arm)" +#endif + +#define CPP_SPEC "\ +%(cpp_cpu_arch) %(cpp_apcs_pc) %(cpp_float) \ +%(cpp_endian) %(subtarget_cpp_spec)" + +/* Set the architecture define -- if -march= is set, then it overrides + the -mcpu= setting. */ +#define CPP_CPU_ARCH_SPEC "\ +%{m2:-D__arm2__ -D__ARM_ARCH_2__} \ +%{m3:-D__arm2__ -D__ARM_ARCH_2__} \ +%{m6:-D__arm6__ -D__ARM_ARCH_3__} \ +%{march=arm2:-D__ARM_ARCH_2__} \ +%{march=arm250:-D__ARM_ARCH_2__} \ +%{march=arm3:-D__ARM_ARCH_2__} \ +%{march=arm6:-D__ARM_ARCH_3__} \ +%{march=arm600:-D__ARM_ARCH_3__} \ +%{march=arm610:-D__ARM_ARCH_3__} \ +%{march=arm7:-D__ARM_ARCH_3__} \ +%{march=arm700:-D__ARM_ARCH_3__} \ +%{march=arm710:-D__ARM_ARCH_3__} \ +%{march=arm7100:-D__ARM_ARCH_3__} \ +%{march=arm7500:-D__ARM_ARCH_3__} \ +%{march=arm7500fe:-D__ARM_ARCH_3__} \ +%{march=arm7m:-D__ARM_ARCH_3M__} \ +%{march=arm7dm:-D__ARM_ARCH_3M__} \ +%{march=arm7dmi:-D__ARM_ARCH_3M__} \ +%{march=arm7tdmi:-D__ARM_ARCH_4T__} \ +%{march=arm8:-D__ARM_ARCH_4__} \ +%{march=arm810:-D__ARM_ARCH_4__} \ +%{march=arm9:-D__ARM_ARCH_4T__} \ +%{march=arm920:-D__ARM_ARCH_4__} \ +%{march=arm920t:-D__ARM_ARCH_4T__} \ +%{march=arm9tdmi:-D__ARM_ARCH_4T__} \ +%{march=strongarm:-D__ARM_ARCH_4__} \ +%{march=strongarm110:-D__ARM_ARCH_4__} \ +%{march=strongarm1100:-D__ARM_ARCH_4__} \ +%{march=armv2:-D__ARM_ARCH_2__} \ +%{march=armv2a:-D__ARM_ARCH_2__} \ +%{march=armv3:-D__ARM_ARCH_3__} \ +%{march=armv3m:-D__ARM_ARCH_3M__} \ +%{march=armv4:-D__ARM_ARCH_4__} \ +%{march=armv4t:-D__ARM_ARCH_4T__} \ +%{!march=*: \ + %{mcpu=arm2:-D__ARM_ARCH_2__} \ + %{mcpu=arm250:-D__ARM_ARCH_2__} \ + %{mcpu=arm3:-D__ARM_ARCH_2__} \ + %{mcpu=arm6:-D__ARM_ARCH_3__} \ + %{mcpu=arm600:-D__ARM_ARCH_3__} \ + %{mcpu=arm610:-D__ARM_ARCH_3__} \ + %{mcpu=arm7:-D__ARM_ARCH_3__} \ + %{mcpu=arm700:-D__ARM_ARCH_3__} \ + %{mcpu=arm710:-D__ARM_ARCH_3__} \ + %{mcpu=arm7100:-D__ARM_ARCH_3__} \ + %{mcpu=arm7500:-D__ARM_ARCH_3__} \ + %{mcpu=arm7500fe:-D__ARM_ARCH_3__} \ + %{mcpu=arm7m:-D__ARM_ARCH_3M__} \ + %{mcpu=arm7dm:-D__ARM_ARCH_3M__} \ + %{mcpu=arm7dmi:-D__ARM_ARCH_3M__} \ + %{mcpu=arm7tdmi:-D__ARM_ARCH_4T__} \ + %{mcpu=arm8:-D__ARM_ARCH_4__} \ + %{mcpu=arm810:-D__ARM_ARCH_4__} \ + %{mcpu=arm9:-D__ARM_ARCH_4T__} \ + %{mcpu=arm920:-D__ARM_ARCH_4__} \ + %{mcpu=arm920t:-D__ARM_ARCH_4T__} \ + %{mcpu=arm9tdmi:-D__ARM_ARCH_4T__} \ + %{mcpu=strongarm:-D__ARM_ARCH_4__} \ + %{mcpu=strongarm110:-D__ARM_ARCH_4__} \ + %{mcpu=strongarm1100:-D__ARM_ARCH_4__} \ + %{!mcpu*:%{!m6:%{!m2:%{!m3:%(cpp_cpu_arch_default)}}}}} \ +" + +/* Define __APCS_26__ if the PC also contains the PSR */ +/* This also examines deprecated -m[236] if neither of -mapcs-{26,32} is set, + ??? Delete this for 2.9. */ +#define CPP_APCS_PC_SPEC "\ +%{mapcs-32:%{mapcs-26:%e-mapcs-26 and -mapcs-32 may not be used together} \ + -D__APCS_32__} \ +%{mapcs-26:-D__APCS_26__} \ +%{!mapcs-32: %{!mapcs-26:%{m6:-D__APCS_32__} %{m2:-D__APCS_26__} \ + %{m3:-D__APCS_26__} %{!m6:%{!m3:%{!m2:%(cpp_apcs_pc_default)}}}}} \ +" + +#ifndef CPP_APCS_PC_DEFAULT_SPEC +#define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_26__" +#endif + +#define CPP_FLOAT_SPEC "\ +%{msoft-float:\ + %{mhard-float:%e-msoft-float and -mhard_float may not be used together} \ + -D__SOFTFP__} \ +%{!mhard-float:%{!msoft-float:%(cpp_float_default)}} \ +" + +/* Default is hard float, which doesn't define anything */ +#define CPP_FLOAT_DEFAULT_SPEC "" + +#define CPP_ENDIAN_SPEC "\ +%{mbig-endian: \ + %{mlittle-endian: \ + %e-mbig-endian and -mlittle-endian may not be used together} \ + -D__ARMEB__ %{mwords-little-endian:-D__ARMWEL__}} \ +%{!mlittle-endian:%{!mbig-endian:%(cpp_endian_default)}} \ +" + +/* Default is little endian, which doesn't define anything. */ +#define CPP_ENDIAN_DEFAULT_SPEC "" + +/* Translate (for now) the old -m[236] option into the appropriate -mcpu=... + and -mapcs-xx equivalents. + ??? Remove support for this style in 2.9.*/ +#define CC1_SPEC "\ +%{m2:-mcpu=arm2 -mapcs-26} \ +%{m3:-mcpu=arm3 -mapcs-26} \ +%{m6:-mcpu=arm6 -mapcs-32} \ +" + +/* This macro defines names of additional specifications to put in the specs + that can be used in various specifications like CC1_SPEC. Its definition + is an initializer with a subgrouping for each command option. + + Each subgrouping contains a string constant, that defines the + specification name, and a string constant that used by the GNU CC driver + program. + + Do not define this macro if it does not need to do anything. */ +#define EXTRA_SPECS \ + { "cpp_cpu_arch", CPP_CPU_ARCH_SPEC }, \ + { "cpp_cpu_arch_default", CPP_ARCH_DEFAULT_SPEC }, \ + { "cpp_apcs_pc", CPP_APCS_PC_SPEC }, \ + { "cpp_apcs_pc_default", CPP_APCS_PC_DEFAULT_SPEC }, \ + { "cpp_float", CPP_FLOAT_SPEC }, \ + { "cpp_float_default", CPP_FLOAT_DEFAULT_SPEC }, \ + { "cpp_endian", CPP_ENDIAN_SPEC }, \ + { "cpp_endian_default", CPP_ENDIAN_DEFAULT_SPEC }, \ + { "subtarget_cpp_spec", SUBTARGET_CPP_SPEC }, \ + SUBTARGET_EXTRA_SPECS + +#define SUBTARGET_EXTRA_SPECS +#define SUBTARGET_CPP_SPEC "" + + +/* Run-time Target Specification. */ +#ifndef TARGET_VERSION +#define TARGET_VERSION \ + fputs (" (ARM/generic)", stderr); +#endif + +/* Run-time compilation parameters selecting different hardware subsets. */ +extern int target_flags; + +/* The floating point instruction architecture, can be 2 or 3 */ +/* CYGNUS LOCAL nickc/renamed from target_fp_name */ +extern char * target_fpe_name; +/* END CYGNUS LOCAL */ + +/* Nonzero if the function prologue (and epilogue) should obey + the ARM Procedure Call Standard. */ +#define ARM_FLAG_APCS_FRAME (0x0001) + +/* Nonzero if the function prologue should output the function name to enable + the post mortem debugger to print a backtrace (very useful on RISCOS, + unused on RISCiX). Specifying this flag also enables + -fno-omit-frame-pointer. + XXX Must still be implemented in the prologue. */ +#define ARM_FLAG_POKE (0x0002) + +/* Nonzero if floating point instructions are emulated by the FPE, in which + case instruction scheduling becomes very uninteresting. */ +#define ARM_FLAG_FPE (0x0004) + +/* Nonzero if destined for an ARM6xx. Takes out bits that assume restoration + of condition flags when returning from a branch & link (ie. a function) */ +/* ********* DEPRECATED ******** */ +#define ARM_FLAG_ARM6 (0x0008) + +/* ********* DEPRECATED ******** */ +#define ARM_FLAG_ARM3 (0x0010) + +/* Nonzero if destined for a processor in 32-bit program mode. Takes out bit + that assume restoration of the condition flags when returning from a + branch and link (ie a function). */ +#define ARM_FLAG_APCS_32 (0x0020) + +/* Nonzero if stack checking should be performed on entry to each function + which allocates temporary variables on the stack. */ +#define ARM_FLAG_APCS_STACK (0x0040) + +/* Nonzero if floating point parameters should be passed to functions in + floating point registers. */ +#define ARM_FLAG_APCS_FLOAT (0x0080) + +/* Nonzero if re-entrant, position independent code should be generated. + This is equivalent to -fpic. */ +#define ARM_FLAG_APCS_REENT (0x0100) + +/* Nonzero if the MMU will trap unaligned word accesses, so shorts must be + loaded byte-at-a-time. */ +#define ARM_FLAG_SHORT_BYTE (0x0200) + +/* Nonzero if all floating point instructions are missing (and there is no + emulator either). Generate function calls for all ops in this case. */ +#define ARM_FLAG_SOFT_FLOAT (0x0400) + +/* Nonzero if we should compile with BYTES_BIG_ENDIAN set to 1. */ +#define ARM_FLAG_BIG_END (0x0800) + +/* Nonzero if we should compile for Thumb interworking. */ +#define ARM_FLAG_THUMB (0x1000) + +/* Nonzero if we should have little-endian words even when compiling for + big-endian (for backwards compatibility with older versions of GCC). */ +#define ARM_FLAG_LITTLE_WORDS (0x2000) + +/* CYGNUS LOCAL */ +/* Nonzero if we need to protect the prolog from scheduling */ +#define ARM_FLAG_NO_SCHED_PRO (0x4000) +/* END CYGNUS LOCAL */ + +/* Nonzero if a call to abort should be generated if a noreturn +function tries to return. */ +#define ARM_FLAG_ABORT_NORETURN (0x8000) + +#define TARGET_APCS (target_flags & ARM_FLAG_APCS_FRAME) +#define TARGET_POKE_FUNCTION_NAME (target_flags & ARM_FLAG_POKE) +#define TARGET_FPE (target_flags & ARM_FLAG_FPE) +#define TARGET_6 (target_flags & ARM_FLAG_ARM6) +#define TARGET_3 (target_flags & ARM_FLAG_ARM3) +#define TARGET_APCS_32 (target_flags & ARM_FLAG_APCS_32) +#define TARGET_APCS_STACK (target_flags & ARM_FLAG_APCS_STACK) +#define TARGET_APCS_FLOAT (target_flags & ARM_FLAG_APCS_FLOAT) +#define TARGET_APCS_REENT (target_flags & ARM_FLAG_APCS_REENT) +#define TARGET_SHORT_BY_BYTES (target_flags & ARM_FLAG_SHORT_BYTE) +#define TARGET_SOFT_FLOAT (target_flags & ARM_FLAG_SOFT_FLOAT) +#define TARGET_HARD_FLOAT (! TARGET_SOFT_FLOAT) +#define TARGET_BIG_END (target_flags & ARM_FLAG_BIG_END) +#define TARGET_THUMB_INTERWORK (target_flags & ARM_FLAG_THUMB) +#define TARGET_LITTLE_WORDS (target_flags & ARM_FLAG_LITTLE_WORDS) +/* CYGNUS LOCAL */ +#define TARGET_NO_SCHED_PRO (target_flags & ARM_FLAG_NO_SCHED_PRO) +/* END CYGNUS LOCAL */ +#define TARGET_ABORT_NORETURN (target_flags & ARM_FLAG_ABORT_NORETURN) + +/* SUBTARGET_SWITCHES is used to add flags on a per-config basis. + Bit 31 is reserved. See riscix.h. */ +#ifndef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES +#endif + +#define TARGET_SWITCHES \ +{ \ + {"apcs", ARM_FLAG_APCS_FRAME, "" }, \ + {"apcs-frame", ARM_FLAG_APCS_FRAME, \ + "Generate APCS conformant stack frames" }, \ + {"no-apcs-frame", -ARM_FLAG_APCS_FRAME, "" }, \ + {"poke-function-name", ARM_FLAG_POKE, \ + "Store function names in object code" }, \ + {"fpe", ARM_FLAG_FPE, "" }, \ + {"6", ARM_FLAG_ARM6, "" }, \ + {"2", ARM_FLAG_ARM3, "" }, \ + {"3", ARM_FLAG_ARM3, "" }, \ + {"apcs-32", ARM_FLAG_APCS_32, \ + "Use the 32bit version of the APCS" }, \ + {"apcs-26", -ARM_FLAG_APCS_32, \ + "Use the 26bit version of the APCS" }, \ + {"apcs-stack-check", ARM_FLAG_APCS_STACK, "" }, \ + {"no-apcs-stack-check", -ARM_FLAG_APCS_STACK, "" }, \ + {"apcs-float", ARM_FLAG_APCS_FLOAT, \ + "Pass FP arguments in FP registers" }, \ + {"no-apcs-float", -ARM_FLAG_APCS_FLOAT, "" }, \ + {"apcs-reentrant", ARM_FLAG_APCS_REENT, \ + "Generate re-entrant, PIC code" }, \ + {"no-apcs-reentrant", -ARM_FLAG_APCS_REENT, "" }, \ + {"short-load-bytes", ARM_FLAG_SHORT_BYTE, \ + "Load shorts a byte at a time" }, \ + {"no-short-load-bytes", -ARM_FLAG_SHORT_BYTE, "" }, \ + {"short-load-words", -ARM_FLAG_SHORT_BYTE, \ + "Load words a byte at a time" }, \ + {"no-short-load-words", ARM_FLAG_SHORT_BYTE, "" }, \ + {"soft-float", ARM_FLAG_SOFT_FLOAT, \ + "Use library calls to perform FP operations" }, \ + {"hard-float", -ARM_FLAG_SOFT_FLOAT, \ + "Use hardware floating point instructions" }, \ + {"big-endian", ARM_FLAG_BIG_END, \ + "Assume target CPU is configured as big endian" }, \ + {"little-endian", -ARM_FLAG_BIG_END, \ + "Assume target CPU is configured as little endian" }, \ + {"words-little-endian", ARM_FLAG_LITTLE_WORDS, \ + "Assume big endian bytes, little endian words" }, \ + {"thumb-interwork", ARM_FLAG_THUMB, \ + "Support calls between THUMB and ARM instructions sets" }, \ + {"no-thumb-interwork", -ARM_FLAG_THUMB, "" }, \ + {"abort-on-noreturn", ARM_FLAG_ABORT_NORETURN, \ + "Generate a call to abort if a noreturn function returns"}, \ + {"no-abort-on-noreturn", -ARM_FLAG_ABORT_NORETURN, ""}, \ + /* CYGNUS LOCAL */ \ + {"sched-prolog", -ARM_FLAG_NO_SCHED_PRO, \ + "Do not move instructions into a function's prologue" }, \ + {"no-sched-prolog", ARM_FLAG_NO_SCHED_PRO, "" }, \ + /* END CYGNUS LOCAL */ \ + SUBTARGET_SWITCHES \ + {"", TARGET_DEFAULT } \ +} + +#define TARGET_OPTIONS \ +{ \ + {"cpu=", & arm_select[0].string, \ + "Specify the name of the target CPU" }, \ + {"arch=", & arm_select[1].string, \ + "Specify the name of the target architecture" }, \ + {"tune=", & arm_select[2].string, "" }, \ + {"fpe=", & target_fpe_name, "" }, \ + {"fp=", & target_fpe_name, \ + "Specify the version of the floating point emulator" }, \ + { "structure-size-boundary=", & structure_size_string, \ + "Specify the minumum bit alignment of structures" } \ +} + +struct arm_cpu_select +{ + char * string; + char * name; + struct processors * processors; +}; + +/* This is a magic array. If the user specifies a command line switch + which matches one of the entries in TARGET_OPTIONS then the corresponding + string pointer will be set to the value specified by the user. */ +extern struct arm_cpu_select arm_select[]; + +enum prog_mode_type +{ + prog_mode26, + prog_mode32 +}; + +/* Recast the program mode class to be the prog_mode attribute */ +#define arm_prog_mode ((enum attr_prog_mode) arm_prgmode) + +extern enum prog_mode_type arm_prgmode; + +/* What sort of floating point unit do we have? Hardware or software. + If software, is it issue 2 or issue 3? */ +enum floating_point_type +{ + FP_HARD, + FP_SOFT2, + FP_SOFT3 +}; + +/* Recast the floating point class to be the floating point attribute. */ +#define arm_fpu_attr ((enum attr_fpu) arm_fpu) + +/* What type of floating point to tune for */ +extern enum floating_point_type arm_fpu; + +/* What type of floating point instructions are available */ +extern enum floating_point_type arm_fpu_arch; + +/* Default floating point architecture. Override in sub-target if + necessary. */ +#define FP_DEFAULT FP_SOFT2 + +/* Nonzero if the processor has a fast multiply insn, and one that does + a 64-bit multiply of two 32-bit values. */ +extern int arm_fast_multiply; + +/* Nonzero if this chip supports the ARM Architecture 4 extensions */ +extern int arm_arch4; + +/* CYGNUS LOCAL nickc/load scheduling */ +/* Nonzero if this chip can benefit from load scheduling. */ +extern int arm_ld_sched; +/* END CYGNUS LOCAL */ + +/* Nonzero if this chip is a StrongARM. */ +extern int arm_is_strong; + +/* Nonzero if this chip is a an ARM6 or an ARM7. */ +extern int arm_is_6_or_7; + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT 0 +#endif + +/* The frame pointer register used in gcc has nothing to do with debugging; + that is controlled by the APCS-FRAME option. */ +/* Not fully implemented yet */ +/* #define CAN_DEBUG_WITHOUT_FP 1 */ + +#define TARGET_MEM_FUNCTIONS 1 + +#define OVERRIDE_OPTIONS arm_override_options () + +/* Target machine storage Layout. */ + + +/* Define this macro if it is advisable to hold scalars in registers + in a wider mode than that declared by the program. In such cases, + the value is constrained to be within the bounds of the declared + type, but kept valid in the wider mode. The signedness of the + extension may differ from that of the type. */ + +/* It is far faster to zero extend chars than to sign extend them */ + +#define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \ + if (GET_MODE_CLASS (MODE) == MODE_INT \ + && GET_MODE_SIZE (MODE) < 4) \ + { \ + if (MODE == QImode) \ + UNSIGNEDP = 1; \ + else if (MODE == HImode) \ + UNSIGNEDP = TARGET_SHORT_BY_BYTES != 0; \ + (MODE) = SImode; \ + } + +/* Define this macro if the promotion described by `PROMOTE_MODE' + should also be done for outgoing function arguments. */ +/* This is required to ensure that push insns always push a word. */ +#define PROMOTE_FUNCTION_ARGS + +/* Define for XFmode extended real floating point support. + This will automatically cause REAL_ARITHMETIC to be defined. */ +/* For the ARM: + I think I have added all the code to make this work. Unfortunately, + early releases of the floating point emulation code on RISCiX used a + different format for extended precision numbers. On my RISCiX box there + is a bug somewhere which causes the machine to lock up when running enquire + with long doubles. There is the additional aspect that Norcroft C + treats long doubles as doubles and we ought to remain compatible. + Perhaps someone with an FPA coprocessor and not running RISCiX would like + to try this someday. */ +/* #define LONG_DOUBLE_TYPE_SIZE 96 */ + +/* Disable XFmode patterns in md file */ +#define ENABLE_XF_PATTERNS 0 + +/* Define if you don't want extended real, but do want to use the + software floating point emulator for REAL_ARITHMETIC and + decimal <-> binary conversion. */ +/* See comment above */ +#define REAL_ARITHMETIC + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. */ +#define BITS_BIG_ENDIAN 0 + +/* Define this if most significant byte of a word is the lowest numbered. + Most ARM processors are run in little endian mode, so that is the default. + If you want to have it run-time selectable, change the definition in a + cover file to be TARGET_BIG_ENDIAN. */ +#define BYTES_BIG_ENDIAN (TARGET_BIG_END != 0) + +/* Define this if most significant word of a multiword number is the lowest + numbered. + This is always false, even when in big-endian mode. */ +#define WORDS_BIG_ENDIAN (BYTES_BIG_ENDIAN && ! TARGET_LITTLE_WORDS) + +/* LIBGCC2_WORDS_BIG_ENDIAN has to be a constant, so we define this based + on processor pre-defineds when compiling libgcc2.c. */ +#if defined(__ARMEB__) && !defined(__ARMWEL__) +#define LIBGCC2_WORDS_BIG_ENDIAN 1 +#else +#define LIBGCC2_WORDS_BIG_ENDIAN 0 +#endif + +/* Define this if most significant word of doubles is the lowest numbered. + This is always true, even when in little-endian mode. */ +#define FLOAT_WORDS_BIG_ENDIAN 1 + +/* Number of bits in an addressable storage unit */ +#define BITS_PER_UNIT 8 + +#define BITS_PER_WORD 32 + +#define UNITS_PER_WORD 4 + +#define POINTER_SIZE 32 + +#define PARM_BOUNDARY 32 + +#define STACK_BOUNDARY 32 + +#define FUNCTION_BOUNDARY 32 + +#define EMPTY_FIELD_BOUNDARY 32 + +#define BIGGEST_ALIGNMENT 32 + +/* Make strings word-aligned so strcpy from constants will be faster. */ +#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ + (TREE_CODE (EXP) == STRING_CST \ + && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) + +/* Every structures size must be a multiple of 32 bits. */ +/* This is for compatibility with ARMCC. ARM SDT Reference Manual + (ARM DUI 0020D) page 2-20 says "Structures are aligned on word + boundaries". */ +#ifndef STRUCTURE_SIZE_BOUNDARY +#define STRUCTURE_SIZE_BOUNDARY 32 +#endif + +/* Used when parsing command line option -mstructure_size_boundary. */ +extern char * structure_size_string; + +/* Non-zero if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT 1 + +#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT + + +/* Standard register usage. */ + +/* Register allocation in ARM Procedure Call Standard (as used on RISCiX): + (S - saved over call). + + r0 * argument word/integer result + r1-r3 argument word + + r4-r8 S register variable + r9 S (rfp) register variable (real frame pointer) + CYGNUS LOCAL nickc/comment change + r10 F S (sl) stack limit (used by -mapcs-stack-check) + END CYGNUS LOCAL + r11 F S (fp) argument pointer + r12 (ip) temp workspace + r13 F S (sp) lower end of current stack frame + r14 (lr) link address/workspace + r15 F (pc) program counter + + f0 floating point result + f1-f3 floating point scratch + + f4-f7 S floating point variable + + cc This is NOT a real register, but is used internally + to represent things that use or set the condition + codes. + sfp This isn't either. It is used during rtl generation + since the offset between the frame pointer and the + auto's isn't known until after register allocation. + afp Nor this, we only need this because of non-local + goto. Without it fp appears to be used and the + elimination code won't get rid of sfp. It tracks + fp exactly at all times. + + *: See CONDITIONAL_REGISTER_USAGE */ + +/* The stack backtrace structure is as follows: + fp points to here: | save code pointer | [fp] + | return link value | [fp, #-4] + | return sp value | [fp, #-8] + | return fp value | [fp, #-12] + [| saved r10 value |] + [| saved r9 value |] + [| saved r8 value |] + [| saved r7 value |] + [| saved r6 value |] + [| saved r5 value |] + [| saved r4 value |] + [| saved r3 value |] + [| saved r2 value |] + [| saved r1 value |] + [| saved r0 value |] + [| saved f7 value |] three words + [| saved f6 value |] three words + [| saved f5 value |] three words + [| saved f4 value |] three words + r0-r3 are not normally saved in a C function. */ + +/* The number of hard registers is 16 ARM + 8 FPU + 1 CC + 1 SFP. */ +#define FIRST_PSEUDO_REGISTER 27 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. */ +#define FIXED_REGISTERS \ +{ \ + 0,0,0,0,0,0,0,0, \ + 0,0,1,1,0,1,0,1, \ + 0,0,0,0,0,0,0,0, \ + 1,1,1 \ +} + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. + The CC is not preserved over function calls on the ARM 6, so it is + easier to assume this for all. SFP is preserved, since FP is. */ +#define CALL_USED_REGISTERS \ +{ \ + 1,1,1,1,0,0,0,0, \ + 0,0,1,1,1,1,1,1, \ + 1,1,1,1,0,0,0,0, \ + 1,1,1 \ +} + +/* If doing stupid life analysis, avoid a bug causing a return value r0 to be + trampled. This effectively reduces the number of available registers by 1. + XXX It is a hack, I know. + XXX Is this still needed? */ +#define CONDITIONAL_REGISTER_USAGE \ +{ \ + if (obey_regdecls) \ + fixed_regs[0] = 1; \ + if (TARGET_SOFT_FLOAT) \ + { \ + int regno; \ + for (regno = 16; regno < 24; ++regno) \ + fixed_regs[regno] = call_used_regs[regno] = 1; \ + } \ + if (flag_pic) \ + { \ + fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ + call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 0; \ + } \ + /* CYGNUS LOCAL */ \ + else if (! TARGET_APCS_STACK) \ + { \ + fixed_regs[10] = 0; \ + call_used_regs[10] = 0; \ + } \ + /* END CYGNUS LOCAL */ \ +} + +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. + + On the ARM regs are UNITS_PER_WORD bits wide; FPU regs can hold any FP + mode. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + (((REGNO) >= 16 && REGNO != FRAME_POINTER_REGNUM \ + && (REGNO) != ARG_POINTER_REGNUM) ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + This is TRUE for ARM regs since they can hold anything, and TRUE for FPU + regs holding FP. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + ((GET_MODE_CLASS (MODE) == MODE_CC) ? (REGNO == CC_REGNUM) : \ + ((REGNO) < 16 || REGNO == FRAME_POINTER_REGNUM \ + || REGNO == ARG_POINTER_REGNUM \ + || GET_MODE_CLASS (MODE) == MODE_FLOAT)) + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + 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) \ + (GET_MODE_CLASS (MODE1) == GET_MODE_CLASS (MODE2)) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* Define this if the program counter is overloaded on a register. */ +#define PC_REGNUM 15 + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 13 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 25 + +/* Define this to be where the real frame pointer is if it is not possible to + work out the offset between the frame pointer and the automatic variables + until after register allocation has taken place. FRAME_POINTER_REGNUM + should point to a special register that we will make sure is eliminated. */ +#define HARD_FRAME_POINTER_REGNUM 11 + +/* 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. + If we have to have a frame pointer we might as well make use of it. + APCS says that the frame pointer does not need to be pushed in leaf + functions, or simple tail call functions. */ +/* CYGNUS LOCAL */ +#define FRAME_POINTER_REQUIRED \ + (current_function_has_nonlocal_label \ + || (TARGET_APCS && (! leaf_function_p () && ! can_tail_call_optimise ()))) + +extern int can_tail_call_optimise (); +/* END CYGNUS LOCAL */ + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 26 + +/* The native (Norcroft) Pascal compiler for the ARM passes the static chain + as an invisible last argument (possible since varargs don't exist in + Pascal), so the following is not true. */ +#define STATIC_CHAIN_REGNUM 8 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 0 + +/* Internal, so that we don't need to refer to a raw number */ +#define CC_REGNUM 24 + +/* The order in which register should be allocated. It is good to use ip + since no saving is required (though calls clobber it) and it never contains + function parameters. It is quite good to use lr since other calls may + clobber it anyway. Allocate r0 through r3 in reverse order since r3 is + least likely to contain a function parameter; in addition results are + returned in r0. + */ +#define REG_ALLOC_ORDER \ +{ \ + 3, 2, 1, 0, 12, 14, 4, 5, \ + 6, 7, 8, 10, 9, 11, 13, 15, \ + 16, 17, 18, 19, 20, 21, 22, 23, \ + 24, 25, 26 \ +} + +/* Register and constant classes. */ + +/* Register classes: all ARM regs or all FPU regs---simple! */ +enum reg_class +{ + NO_REGS, + FPU_REGS, + GENERAL_REGS, + ALL_REGS, + LIM_REG_CLASSES +}; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Give names of register classes as strings for dump file. */ +#define REG_CLASS_NAMES \ +{ \ + "NO_REGS", \ + "FPU_REGS", \ + "GENERAL_REGS", \ + "ALL_REGS", \ +} + +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ +#define REG_CLASS_CONTENTS \ +{ \ + 0x0000000, /* NO_REGS */ \ + 0x0FF0000, /* FPU_REGS */ \ + 0x200FFFF, /* GENERAL_REGS */ \ + 0x2FFFFFF /* ALL_REGS */ \ +} + +/* The same information, inverted: + Return the class number of the smallest class containing + reg number REGNO. This could be a conditional expression + or could index an array. */ +#define REGNO_REG_CLASS(REGNO) \ + (((REGNO) < 16 || REGNO == FRAME_POINTER_REGNUM \ + || REGNO == ARG_POINTER_REGNUM) \ + ? GENERAL_REGS : (REGNO) == CC_REGNUM \ + ? NO_REGS : FPU_REGS) + +/* The class value for index registers, and the one for base regs. */ +#define INDEX_REG_CLASS GENERAL_REGS +#define BASE_REG_CLASS GENERAL_REGS + +/* Get reg_class from a letter such as appears in the machine description. + We only need constraint `f' for FPU_REGS (`r' == GENERAL_REGS). */ +#define REG_CLASS_FROM_LETTER(C) \ + ((C)=='f' ? FPU_REGS : 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: immediate arithmetic operand (i.e. 8 bits shifted as required). + J: valid indexing constants. + K: ~value ok in rhs argument of data operand. + L: -value ok in rhs argument of data operand. + M: 0..32, or a power of 2 (for shifts, or mult done by shift). */ +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? const_ok_for_arm (VALUE) : \ + (C) == 'J' ? ((VALUE) < 4096 && (VALUE) > -4096) : \ + (C) == 'K' ? (const_ok_for_arm (~(VALUE))) : \ + (C) == 'L' ? (const_ok_for_arm (-(VALUE))) : \ + (C) == 'M' ? (((VALUE >= 0 && VALUE <= 32)) \ + || (((VALUE) & ((VALUE) - 1)) == 0)) \ + : 0) + +/* For the ARM, `Q' means that this is a memory operand that is just + an offset from a register. + `S' means any symbol that has the SYMBOL_REF_FLAG set or a CONSTANT_POOL + address. This means that the symbol is in the text segment and can be + accessed without using a load. */ + +#define EXTRA_CONSTRAINT(OP, C) \ + ((C) == 'Q' ? GET_CODE (OP) == MEM && GET_CODE (XEXP (OP, 0)) == REG \ + : (C) == 'R' ? (GET_CODE (OP) == MEM \ + && GET_CODE (XEXP (OP, 0)) == SYMBOL_REF \ + && CONSTANT_POOL_ADDRESS_P (XEXP (OP, 0))) \ + : (C) == 'S' ? (optimize > 0 && CONSTANT_ADDRESS_P (OP)) \ + : 0) + +/* Constant letter 'G' for the FPU immediate constants. + 'H' means the same constant negated. */ +#define CONST_DOUBLE_OK_FOR_LETTER_P(X,C) \ + ((C) == 'G' ? const_double_rtx_ok_for_fpu (X) \ + : (C) == 'H' ? neg_const_double_rtx_ok_for_fpu (X) : 0) + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. */ +#define PREFERRED_RELOAD_CLASS(X, CLASS) (CLASS) + +/* Return the register class of a scratch register needed to copy IN into + or out of a register in CLASS in MODE. If it can be done directly, + NO_REGS is returned. */ +#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS,MODE,X) \ + (((MODE) == HImode && ! arm_arch4 && true_regnum (X) == -1) \ + ? GENERAL_REGS : NO_REGS) + +/* If we need to load shorts byte-at-a-time, then we need a scratch. */ +#define SECONDARY_INPUT_RELOAD_CLASS(CLASS,MODE,X) \ + (((MODE) == HImode && ! arm_arch4 && TARGET_SHORT_BY_BYTES \ + && (GET_CODE (X) == MEM \ + || ((GET_CODE (X) == REG || GET_CODE (X) == SUBREG) \ + && true_regnum (X) == -1))) \ + ? GENERAL_REGS : NO_REGS) + +/* Try a machine-dependent way of reloading an illegitimate address + operand. If we find one, push the reload and jump to WIN. This + macro is used in only one place: `find_reloads_address' in reload.c. + + For the ARM, we wish to handle large displacements off a base + register by splitting the addend across a MOV and the mem insn. + This can cut the number of reloads needed. */ +#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \ +do { \ + if (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REGNO (XEXP (X, 0)) < FIRST_PSEUDO_REGISTER \ + && REG_MODE_OK_FOR_BASE_P (XEXP (X, 0), MODE) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT) \ + { \ + HOST_WIDE_INT val = INTVAL (XEXP (X, 1)); \ + HOST_WIDE_INT low, high; \ + \ + if (MODE == DImode || (TARGET_SOFT_FLOAT && MODE == DFmode)) \ + low = ((val & 0xf) ^ 0x8) - 0x8; \ + else if (MODE == SImode || MODE == QImode \ + || (MODE == SFmode && TARGET_SOFT_FLOAT) \ + || (MODE == HImode && ! arm_arch4)) \ + /* Need to be careful, -4096 is not a valid offset */ \ + low = val >= 0 ? (val & 0xfff) : -((-val) & 0xfff); \ + else if (MODE == HImode && arm_arch4) \ + /* Need to be careful, -256 is not a valid offset */ \ + low = val >= 0 ? (val & 0xff) : -((-val) & 0xff); \ + else if (GET_MODE_CLASS (MODE) == MODE_FLOAT \ + && TARGET_HARD_FLOAT) \ + /* Need to be careful, -1024 is not a valid offset */ \ + low = val >= 0 ? (val & 0x3ff) : -((-val) & 0x3ff); \ + else \ + break; \ + \ + high = ((((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000); \ + /* Check for overflow or zero */ \ + if (low == 0 || high == 0 || (high + low != val)) \ + break; \ + \ + /* Reload the high part into a base reg; leave the low part \ + in the mem. */ \ + X = gen_rtx_PLUS (GET_MODE (X), \ + gen_rtx_PLUS (GET_MODE (X), XEXP (X, 0), \ + GEN_INT (high)), \ + GEN_INT (low)); \ + push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL_PTR, \ + BASE_REG_CLASS, GET_MODE (X), VOIDmode, 0, 0, \ + OPNUM, TYPE); \ + goto WIN; \ + } \ +} while (0) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. + ARM regs are UNITS_PER_WORD bits while FPU regs can hold any FP mode */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((CLASS) == FPU_REGS ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Moves between FPU_REGS and GENERAL_REGS are two memory insns. */ +#define REGISTER_MOVE_COST(CLASS1, CLASS2) \ + ((((CLASS1) == FPU_REGS && (CLASS2) != FPU_REGS) \ + || ((CLASS2) == FPU_REGS && (CLASS1) != FPU_REGS)) \ + ? 20 : 2) + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD 1 + +/* 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 + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. */ +/* The push insns do not do this rounding implicitly. So don't define this. */ +/* #define PUSH_ROUNDING(NPUSHED) (((NPUSHED) + 3) & ~3) */ + +/* Define this if the maximum size of all the outgoing args is to be + accumulated and pushed during the prologue. The amount can be + found in the variable current_function_outgoing_args_size. */ +#define ACCUMULATE_OUTGOING_ARGS + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 4 + +/* Value is the number of byte of arguments automatically + popped when returning from a subroutine call. + FUNDECL is the declaration node of the function (as a tree), + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. + SIZE is the number of bytes of arguments passed on the stack. + + On the ARM, the caller does not pop any of its arguments that were passed + on the stack. */ +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 + +/* 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) \ + (GET_MODE_CLASS (TYPE_MODE (VALTYPE)) == MODE_FLOAT && TARGET_HARD_FLOAT \ + ? gen_rtx (REG, TYPE_MODE (VALTYPE), 16) \ + : gen_rtx (REG, TYPE_MODE (VALTYPE), 0)) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ +#define LIBCALL_VALUE(MODE) \ + (GET_MODE_CLASS (MODE) == MODE_FLOAT && TARGET_HARD_FLOAT \ + ? gen_rtx (REG, MODE, 16) \ + : gen_rtx (REG, MODE, 0)) + +/* 1 if N is a possible register number for a function value. + On the ARM, only r0 and f0 can return results. */ +#define FUNCTION_VALUE_REGNO_P(REGNO) \ + ((REGNO) == 0 || ((REGNO) == 16) && TARGET_HARD_FLOAT) + +/* How large values are returned */ +/* A C expression which can inhibit the returning of certain function values + in registers, based on the type of value. */ +/* CYGNUS LOCAL */ +#define RETURN_IN_MEMORY(TYPE) arm_return_in_memory (TYPE) +/* END CYGNUS LOCAL */ + +/* Define DEFAULT_PCC_STRUCT_RETURN to 1 if all structure and union return + values must be in memory. On the ARM, they need only do so if larger + than a word, or if they contain elements offset from zero in the struct. */ +#define DEFAULT_PCC_STRUCT_RETURN 0 + +/* Define where to put the arguments to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). + + On the ARM, normally the first 16 bytes are passed in registers r0-r3; all + other arguments are passed on the stack. If (NAMED == 0) (which happens + only in assign_parms, since SETUP_INCOMING_VARARGS is defined), say it is + passed in the stack (function_prologue will indeed make it pass in the + stack if necessary). */ +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + ((NAMED) \ + ? ((CUM) >= 16 ? 0 : gen_rtx (REG, MODE, (CUM) / 4)) \ + : 0) + +/* 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) \ + ((CUM) < 16 && 16 < (CUM) + ((MODE) != BLKmode \ + ? GET_MODE_SIZE (MODE) \ + : int_size_in_bytes (TYPE)) \ + ? 4 - (CUM) / 4 : 0) + +/* A C type for declaring a variable that is used as the first argument of + `FUNCTION_ARG' and other related values. For some target machines, the + type `int' suffices and can hold the number of bytes of argument so far. + + On the ARM, this is the number of bytes of arguments scanned so far. */ +#define CUMULATIVE_ARGS int + +/* 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. + On the ARM, the offset starts at 0. */ +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ + ((CUM) = (((FNTYPE) && aggregate_value_p (TREE_TYPE ((FNTYPE)))) ? 4 : 0)) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + (CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3) \ + +/* 1 if N is a possible register number for function argument passing. + On the ARM, r0-r3 are used to pass args. */ +#define FUNCTION_ARG_REGNO_P(REGNO) \ + ((REGNO) >= 0 && (REGNO) <= 3) + +/* Perform any 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. + + On the ARM, PRETEND_SIZE is set in order to have the prologue push the last + named arg and all anonymous args onto the stack. + XXX I know the prologue shouldn't be pushing registers, but it is faster + that way. */ +#define SETUP_INCOMING_VARARGS(CUM, MODE, TYPE, PRETEND_SIZE, NO_RTL) \ +{ \ + extern int current_function_anonymous_args; \ + current_function_anonymous_args = 1; \ + if ((CUM) < 16) \ + (PRETEND_SIZE) = 16 - (CUM); \ +} + +/* Generate assembly output for the start of a function. */ +#define FUNCTION_PROLOGUE(STREAM, SIZE) \ + output_func_prologue ((STREAM), (SIZE)) + +/* Call the function profiler with a given profile label. The Acorn compiler + puts this BEFORE the prolog but gcc puts it afterwards. The ``mov ip,lr'' + seems like a good idea to stick with cc convention. ``prof'' doesn't seem + to mind about this! */ +#define FUNCTION_PROFILER(STREAM,LABELNO) \ +{ \ + fprintf(STREAM, "\tmov\t%sip, %slr\n", REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf(STREAM, "\tbl\tmcount\n"); \ + fprintf(STREAM, "\t.word\tLP%d\n", (LABELNO)); \ +} + +/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, + the stack pointer does not matter. The value is tested only in + functions that have frame pointers. + No definition is equivalent to always zero. + + On the ARM, the function epilogue recovers the stack pointer from the + frame. */ +#define EXIT_IGNORE_STACK 1 + +/* Generate the assembly code for function exit. */ +#define FUNCTION_EPILOGUE(STREAM, SIZE) \ + output_func_epilogue ((STREAM), (SIZE)) + +/* Determine if the epilogue should be output as RTL. + You should override this if you define FUNCTION_EXTRA_EPILOGUE. */ +#define USE_RETURN_INSN(ISCOND) use_return_insn (ISCOND) + +/* Definitions for register eliminations. + + This is an array of structures. Each structure initializes one pair + of eliminable registers. The "from" register number is given first, + followed by "to". Eliminations of the same "from" register are listed + in order of preference. + + We have two registers that can be eliminated on the ARM. First, the + arg pointer register can often be eliminated in favor of the stack + pointer register. Secondly, the pseudo frame pointer register can always + be eliminated; it is replaced with either the stack or the real frame + pointer. */ + +#define ELIMINABLE_REGS \ +{{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + {ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ + {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + {FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} + +/* Given FROM and TO register numbers, say whether this elimination is allowed. + Frame pointer elimination is automatically handled. + + All eliminations are permissible. Note that ARG_POINTER_REGNUM and + HARD_FRAME_POINTER_REGNUM are in fact the same thing. If we need a frame + pointer, we must eliminate FRAME_POINTER_REGNUM into + HARD_FRAME_POINTER_REGNUM and not into STACK_POINTER_REGNUM. */ +#define CAN_ELIMINATE(FROM, TO) \ + (((TO) == STACK_POINTER_REGNUM && frame_pointer_needed) ? 0 : 1) + +/* Define the offset between two registers, one to be eliminated, and the other + its replacement, at the start of a routine. */ +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ +{ \ + int volatile_func = arm_volatile_func (); \ + if ((FROM) == ARG_POINTER_REGNUM && (TO) == HARD_FRAME_POINTER_REGNUM)\ + (OFFSET) = 0; \ + else if ((FROM) == FRAME_POINTER_REGNUM \ + && (TO) == STACK_POINTER_REGNUM) \ + (OFFSET) = (current_function_outgoing_args_size \ + + (get_frame_size () + 3 & ~3)); \ + else \ + { \ + int regno; \ + int offset = 12; \ + int saved_hard_reg = 0; \ + \ + if (! volatile_func) \ + { \ + for (regno = 0; regno <= 10; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + saved_hard_reg = 1, offset += 4; \ + for (regno = 16; regno <=23; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 12; \ + } \ + if ((FROM) == FRAME_POINTER_REGNUM) \ + (OFFSET) = -offset; \ + else \ + { \ + if (! frame_pointer_needed) \ + offset -= 16; \ + if (! volatile_func \ + && (regs_ever_live[14] || saved_hard_reg)) \ + offset += 4; \ + offset += current_function_outgoing_args_size; \ + (OFFSET) = (get_frame_size () + 3 & ~3) + offset; \ + } \ + } \ +} + +/* CYGNUS LOCAL */ +/* Special case handling of the location of arguments passed on the stack. */ +#define DEBUGGER_ARG_OFFSET(value, addr) value ? value : arm_debugger_arg_offset (value, addr) +/* END CYGNUS LOCAL */ + +/* Output assembler code for a block containing the constant parts + of a trampoline, leaving space for the variable parts. + + On the ARM, (if r8 is the static chain regnum, and remembering that + referencing pc adds an offset of 8) the trampoline looks like: + ldr r8, [pc, #0] + ldr pc, [pc] + .word static chain value + .word function's address + ??? FIXME: When the trampoline returns, r8 will be clobbered. */ +#define TRAMPOLINE_TEMPLATE(FILE) \ +{ \ + fprintf ((FILE), "\tldr\t%sr8, [%spc, #0]\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\tldr\t%spc, [%spc, #0]\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\t.word\t0\n"); \ + fprintf ((FILE), "\t.word\t0\n"); \ +} + +/* Length in units of the trampoline for entering a nested function. */ +#define TRAMPOLINE_SIZE 16 + +/* Alignment required for a trampoline in units. */ +#define TRAMPOLINE_ALIGN 4 + +/* Emit RTL insns to initialize the variable parts of a trampoline. + FNADDR is an RTX for the address of the function's pure code. + CXT is an RTX for the static chain value for the function. */ +#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ +{ \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 8)), \ + (CXT)); \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 12)), \ + (FNADDR)); \ +} + + +/* Addressing modes, and classification of registers for them. */ + +#define HAVE_POST_INCREMENT 1 +#define HAVE_PRE_INCREMENT 1 +#define HAVE_POST_DECREMENT 1 +#define HAVE_PRE_DECREMENT 1 + +/* Macros to check register numbers against specific register classes. */ + +/* These assume that REGNO is a hard or pseudo reg number. + They give nonzero only if REGNO is a hard reg of the suitable class + or a pseudo reg currently allocated to a suitable hard reg. + Since they use reg_renumber, they are safe only once reg_renumber + has been allocated, which happens in local-alloc.c. + + On the ARM, don't allow the pc to be used. */ +#define REGNO_OK_FOR_BASE_P(REGNO) \ + ((REGNO) < 15 || (REGNO) == FRAME_POINTER_REGNUM \ + || (REGNO) == ARG_POINTER_REGNUM \ + || (unsigned) reg_renumber[(REGNO)] < 15 \ + || (unsigned) reg_renumber[(REGNO)] == FRAME_POINTER_REGNUM \ + || (unsigned) reg_renumber[(REGNO)] == ARG_POINTER_REGNUM) +#define REGNO_OK_FOR_INDEX_P(REGNO) \ + REGNO_OK_FOR_BASE_P(REGNO) + +/* Maximum number of registers that can appear in a valid memory address. + Shifts in addresses can't be by a register. */ + +#define MAX_REGS_PER_ADDRESS 2 + +/* Recognize any constant value that is a valid address. */ +/* XXX We can address any constant, eventually... */ + +#ifdef AOF_ASSEMBLER + +#define CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == SYMBOL_REF \ + && CONSTANT_POOL_ADDRESS_P (X)) + +#else + +#define CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == SYMBOL_REF \ + && (CONSTANT_POOL_ADDRESS_P (X) \ + || (optimize > 0 && SYMBOL_REF_FLAG (X)))) + +#endif /* AOF_ASSEMBLER */ + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. + + On the ARM, allow any integer (invalid ones are removed later by insn + patterns), nice doubles and symbol_refs which refer to the function's + constant pool XXX. */ +#define LEGITIMATE_CONSTANT_P(X) (! label_mentioned_p (X)) + +/* Symbols in the text segment can be accessed without indirecting via the + constant pool; it may take an extra binary operation, but this is still + faster than indirecting via memory. Don't do this when not optimizing, + since we won't be calculating al of the offsets necessary to do this + simplification. */ +/* This doesn't work with AOF syntax, since the string table may be in + a different AREA. */ +#ifndef AOF_ASSEMBLER +#define ENCODE_SECTION_INFO(decl) \ +{ \ + if (optimize > 0 && TREE_CONSTANT (decl) \ + && (!flag_writable_strings || TREE_CODE (decl) != STRING_CST)) \ + { \ + rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd' \ + ? TREE_CST_RTL (decl) : DECL_RTL (decl)); \ + SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1; \ + } \ +} +#endif + +/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx + and check its validity for a certain class. + We have two alternate definitions for each of them. + The usual definition accepts all pseudo regs; the other rejects + them unless they have been allocated suitable hard regs. + The symbol REG_OK_STRICT causes the latter definition to be used. */ +#ifndef REG_OK_STRICT + +/* Nonzero if X is a hard reg that can be used as a base reg + or if it is a pseudo reg. */ +#define REG_OK_FOR_BASE_P(X) \ + (REGNO (X) < 16 || REGNO (X) >= FIRST_PSEUDO_REGISTER \ + || REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM) + +/* Nonzero if X is a hard reg that can be used as an index + or if it is a pseudo reg. */ +#define REG_OK_FOR_INDEX_P(X) \ + REG_OK_FOR_BASE_P(X) + +#define REG_OK_FOR_PRE_POST_P(X) \ + (REGNO (X) < 16 || REGNO (X) >= FIRST_PSEUDO_REGISTER \ + || REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM) + +#else + +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + +/* Nonzero if X is a hard reg that can be used as an index. */ +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) + +#define REG_OK_FOR_PRE_POST_P(X) \ + (REGNO (X) < 16 || (unsigned) reg_renumber[REGNO (X)] < 16 \ + || REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO (X)] == FRAME_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO (X)] == ARG_POINTER_REGNUM) + +#endif + +/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression + that is a valid memory address for an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS. */ +#define BASE_REGISTER_RTX_P(X) \ + (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) + +#define INDEX_REGISTER_RTX_P(X) \ + (GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X)) + +/* A C statement (sans semicolon) to jump to LABEL for legitimate index RTXs + used by the macro GO_IF_LEGITIMATE_ADDRESS. Floating point indices can + only be small constants. */ +#define GO_IF_LEGITIMATE_INDEX(MODE, BASE_REGNO, INDEX, LABEL) \ +do \ +{ \ + HOST_WIDE_INT range; \ + enum rtx_code code = GET_CODE (INDEX); \ + \ + if (TARGET_HARD_FLOAT && GET_MODE_CLASS (MODE) == MODE_FLOAT) \ + { \ + if (code == CONST_INT && INTVAL (INDEX) < 1024 \ + && INTVAL (INDEX) > -1024 \ + && (INTVAL (INDEX) & 3) == 0) \ + goto LABEL; \ + } \ + else \ + { \ + if (INDEX_REGISTER_RTX_P (INDEX) && GET_MODE_SIZE (MODE) <= 4) \ + goto LABEL; \ + if (GET_MODE_SIZE (MODE) <= 4 && code == MULT \ + && (! arm_arch4 || (MODE) != HImode)) \ + { \ + rtx xiop0 = XEXP (INDEX, 0); \ + rtx xiop1 = XEXP (INDEX, 1); \ + if (INDEX_REGISTER_RTX_P (xiop0) \ + && power_of_two_operand (xiop1, SImode)) \ + goto LABEL; \ + if (INDEX_REGISTER_RTX_P (xiop1) \ + && power_of_two_operand (xiop0, SImode)) \ + goto LABEL; \ + } \ + if (GET_MODE_SIZE (MODE) <= 4 \ + && (code == LSHIFTRT || code == ASHIFTRT \ + || code == ASHIFT || code == ROTATERT) \ + && (! arm_arch4 || (MODE) != HImode)) \ + { \ + rtx op = XEXP (INDEX, 1); \ + if (INDEX_REGISTER_RTX_P (XEXP (INDEX, 0)) \ + && GET_CODE (op) == CONST_INT && INTVAL (op) > 0 \ + && INTVAL (op) <= 31) \ + goto LABEL; \ + } \ + /* NASTY: Since this limits the addressing of unsigned byte loads */ \ + range = ((MODE) == HImode || (MODE) == QImode) \ + ? (arm_arch4 ? 256 : 4095) : 4096; \ + if (code == CONST_INT && INTVAL (INDEX) < range \ + && INTVAL (INDEX) > -range) \ + goto LABEL; \ + } \ +} while (0) + +/* Jump to LABEL if X is a valid address RTX. This must also take + REG_OK_STRICT into account when deciding about valid registers, but it uses + the above macros so we are in luck. Allow REG, REG+REG, REG+INDEX, + INDEX+REG, REG-INDEX, and non floating SYMBOL_REF to the constant pool. + Allow REG-only and AUTINC-REG if handling TImode or HImode. Other symbol + refs must be forced though a static cell to ensure addressability. */ +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \ +{ \ + if (BASE_REGISTER_RTX_P (X)) \ + goto LABEL; \ + else if ((GET_CODE (X) == POST_INC || GET_CODE (X) == PRE_DEC) \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_PRE_POST_P (XEXP (X, 0))) \ + goto LABEL; \ + else if (GET_MODE_SIZE (MODE) >= 4 && reload_completed \ + && (GET_CODE (X) == LABEL_REF \ + || (GET_CODE (X) == CONST \ + && GET_CODE (XEXP ((X), 0)) == PLUS \ + && GET_CODE (XEXP (XEXP ((X), 0), 0)) == LABEL_REF \ + && GET_CODE (XEXP (XEXP ((X), 0), 1)) == CONST_INT)))\ + goto LABEL; \ + else if ((MODE) == TImode) \ + ; \ + else if ((MODE) == DImode || (TARGET_SOFT_FLOAT && (MODE) == DFmode)) \ + { \ + if (GET_CODE (X) == PLUS && BASE_REGISTER_RTX_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT) \ + { \ + HOST_WIDE_INT val = INTVAL (XEXP (X, 1)); \ + if (val == 4 || val == -4 || val == -8) \ + goto LABEL; \ + } \ + } \ + else if (GET_CODE (X) == PLUS) \ + { \ + rtx xop0 = XEXP(X,0); \ + rtx xop1 = XEXP(X,1); \ + \ + if (BASE_REGISTER_RTX_P (xop0)) \ + GO_IF_LEGITIMATE_INDEX (MODE, REGNO (xop0), xop1, LABEL); \ + else if (BASE_REGISTER_RTX_P (xop1)) \ + GO_IF_LEGITIMATE_INDEX (MODE, REGNO (xop1), xop0, LABEL); \ + } \ + /* Reload currently can't handle MINUS, so disable this for now */ \ + /* else if (GET_CODE (X) == MINUS) \ + { \ + rtx xop0 = XEXP (X,0); \ + rtx xop1 = XEXP (X,1); \ + \ + if (BASE_REGISTER_RTX_P (xop0)) \ + GO_IF_LEGITIMATE_INDEX (MODE, -1, xop1, LABEL); \ + } */ \ + else if (GET_MODE_CLASS (MODE) != MODE_FLOAT \ + && GET_CODE (X) == SYMBOL_REF \ + && CONSTANT_POOL_ADDRESS_P (X)) \ + goto LABEL; \ + else if ((GET_CODE (X) == PRE_INC || GET_CODE (X) == POST_DEC) \ + && (GET_MODE_SIZE (MODE) <= 4) \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_PRE_POST_P (XEXP (X, 0))) \ + goto LABEL; \ +} + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. + + On the ARM, try to convert [REG, #BIGCONST] + into ADD BASE, REG, #UPPERCONST and [BASE, #VALIDCONST], + where VALIDCONST == 0 in case of TImode. */ +extern struct rtx_def *legitimize_pic_address (); +#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ +{ \ + if (GET_CODE (X) == PLUS) \ + { \ + rtx xop0 = XEXP (X, 0); \ + rtx xop1 = XEXP (X, 1); \ + \ + if (CONSTANT_P (xop0) && ! symbol_mentioned_p (xop0)) \ + xop0 = force_reg (SImode, xop0); \ + if (CONSTANT_P (xop1) && ! symbol_mentioned_p (xop1)) \ + xop1 = force_reg (SImode, xop1); \ + if (BASE_REGISTER_RTX_P (xop0) && GET_CODE (xop1) == CONST_INT) \ + { \ + HOST_WIDE_INT n, low_n; \ + rtx base_reg, val; \ + n = INTVAL (xop1); \ + \ + if (MODE == DImode || (TARGET_SOFT_FLOAT && MODE == DFmode)) \ + { \ + low_n = n & 0x0f; \ + n &= ~0x0f; \ + if (low_n > 4) \ + { \ + n += 16; \ + low_n -= 16; \ + } \ + } \ + else \ + { \ + low_n = ((MODE) == TImode ? 0 \ + : n >= 0 ? (n & 0xfff) : -((-n) & 0xfff)); \ + n -= low_n; \ + } \ + base_reg = gen_reg_rtx (SImode); \ + val = force_operand (gen_rtx (PLUS, SImode, xop0, \ + GEN_INT (n)), NULL_RTX); \ + emit_move_insn (base_reg, val); \ + (X) = (low_n == 0 ? base_reg \ + : gen_rtx (PLUS, SImode, base_reg, GEN_INT (low_n))); \ + } \ + else if (xop0 != XEXP (X, 0) || xop1 != XEXP (x, 1)) \ + (X) = gen_rtx (PLUS, SImode, xop0, xop1); \ + } \ + else if (GET_CODE (X) == MINUS) \ + { \ + rtx xop0 = XEXP (X, 0); \ + rtx xop1 = XEXP (X, 1); \ + \ + if (CONSTANT_P (xop0)) \ + xop0 = force_reg (SImode, xop0); \ + if (CONSTANT_P (xop1) && ! symbol_mentioned_p (xop1)) \ + xop1 = force_reg (SImode, xop1); \ + if (xop0 != XEXP (X, 0) || xop1 != XEXP (X, 1)) \ + (X) = gen_rtx (MINUS, SImode, xop0, xop1); \ + } \ + if (flag_pic) \ + (X) = legitimize_pic_address (OLDX, MODE, NULL_RTX); \ + if (memory_address_p (MODE, X)) \ + goto WIN; \ +} + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. */ +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ +{ \ + if (GET_CODE(ADDR) == PRE_DEC || GET_CODE(ADDR) == POST_DEC \ + || GET_CODE(ADDR) == PRE_INC || GET_CODE(ADDR) == POST_INC) \ + goto LABEL; \ +} + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE SImode + +/* 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 */ + +/* Specify the tree operation to be used to convert reals to integers. */ +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* This is the kind of divide that is easiest to do in the general case. */ +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* signed 'char' is most compatible, but RISC OS wants it unsigned. + unsigned is probably best, but may break some code. */ +#ifndef DEFAULT_SIGNED_CHAR +#define DEFAULT_SIGNED_CHAR 0 +#endif + +/* Don't cse the address of the function being compiled. */ +#define NO_RECURSIVE_FUNCTION_CSE 1 + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 4 + +/* Define if operations between registers always perform the operation + on the full register even if a narrower mode is specified. */ +#define WORD_REGISTER_OPERATIONS + +/* Define if loading in MODE, an integral mode narrower than BITS_PER_WORD + will either zero-extend or sign-extend. The value of this macro should + be the code that says which one of the two operations is implicitly + done, NIL if none. */ +#define LOAD_EXTEND_OP(MODE) \ + ((arm_arch4 || (MODE) == QImode) ? ZERO_EXTEND \ + : ((BYTES_BIG_ENDIAN && (MODE) == HImode) ? SIGN_EXTEND : NIL)) + +/* Define this if zero-extension is slow (more than one real instruction). + On the ARM, it is more than one instruction only if not fetching from + memory. */ +/* #define SLOW_ZERO_EXTEND */ + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* Immediate shift counts are truncated by the output routines (or was it + the assembler?). Shift counts in a register are truncated by ARM. Note + that the native compiler puts too large (> 32) immediate shift counts + into a register and shifts by the register, letting the ARM decide what + to do instead of doing that itself. */ +/* This is all wrong. Defining SHIFT_COUNT_TRUNCATED tells combine that + code like (X << (Y % 32)) for register X, Y is equivalent to (X << Y). + On the arm, Y in a register is used modulo 256 for the shift. Only for + rotates is modulo 32 used. */ +/* #define SHIFT_COUNT_TRUNCATED 1 */ + +/* All integers have the same format so truncation is easy. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) 1 + +/* Calling from registers is a massive pain. */ +#define NO_FUNCTION_CSE 1 + +/* Chars and shorts should be passed as ints. */ +#define PROMOTE_PROTOTYPES 1 + +/* The machine modes of pointers and functions */ +#define Pmode SImode +#define FUNCTION_MODE Pmode + +/* The structure type of the machine dependent info field of insns + No uses for this yet. */ +/* #define INSN_MACHINE_INFO struct machine_info */ + +/* The relative costs of various types of constants. Note that cse.c defines + REG = 1, SUBREG = 2, any node = (2 + sum of subnodes). */ +#define CONST_COSTS(RTX, CODE, OUTER_CODE) \ + case CONST_INT: \ + if (const_ok_for_arm (INTVAL (RTX))) \ + return (OUTER_CODE) == SET ? 2 : -1; \ + else if (OUTER_CODE == AND \ + && const_ok_for_arm (~INTVAL (RTX))) \ + return -1; \ + else if ((OUTER_CODE == COMPARE \ + || OUTER_CODE == PLUS || OUTER_CODE == MINUS) \ + && const_ok_for_arm (-INTVAL (RTX))) \ + return -1; \ + else \ + return 5; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 6; \ + case CONST_DOUBLE: \ + if (const_double_rtx_ok_for_fpu (RTX)) \ + return (OUTER_CODE) == SET ? 2 : -1; \ + else if (((OUTER_CODE) == COMPARE || (OUTER_CODE) == PLUS) \ + && neg_const_double_rtx_ok_for_fpu (RTX)) \ + return -1; \ + return(7); + +#define ARM_FRAME_RTX(X) \ + ((X) == frame_pointer_rtx || (X) == stack_pointer_rtx \ + || (X) == arg_pointer_rtx) + +#define DEFAULT_RTX_COSTS(X,CODE,OUTER_CODE) \ + return arm_rtx_costs (X, CODE, OUTER_CODE); + +/* Moves to and from memory are quite expensive */ +#define MEMORY_MOVE_COST(MODE,CLASS,IN) 10 + +/* All address computations that can be done are free, but rtx cost returns + the same for practically all of them. So we weight the different types + of address here in the order (most pref first): + PRE/POST_INC/DEC, SHIFT or NON-INT sum, INT sum, REG, MEM or LABEL. */ +#define ADDRESS_COST(X) \ + (10 - ((GET_CODE (X) == MEM || GET_CODE (X) == LABEL_REF \ + || GET_CODE (X) == SYMBOL_REF) \ + ? 0 \ + : ((GET_CODE (X) == PRE_INC || GET_CODE (X) == PRE_DEC \ + || GET_CODE (X) == POST_INC || GET_CODE (X) == POST_DEC) \ + ? 10 \ + : (((GET_CODE (X) == PLUS || GET_CODE (X) == MINUS) \ + ? 6 + (GET_CODE (XEXP (X, 1)) == CONST_INT ? 2 \ + : ((GET_RTX_CLASS (GET_CODE (XEXP (X, 0))) == '2' \ + || GET_RTX_CLASS (GET_CODE (XEXP (X, 0))) == 'c' \ + || GET_RTX_CLASS (GET_CODE (XEXP (X, 1))) == '2' \ + || GET_RTX_CLASS (GET_CODE (XEXP (X, 1))) == 'c') \ + ? 1 : 0)) \ + : 4))))) + + + +/* Try to generate sequences that don't involve branches, we can then use + conditional instructions */ +#define BRANCH_COST 4 + +/* A C statement to update the variable COST based on the relationship + between INSN that is dependent on DEP through dependence LINK. */ +#define ADJUST_COST(INSN,LINK,DEP,COST) \ + (COST) = arm_adjust_cost ((INSN), (LINK), (DEP), (COST)) + +/* Position Independent Code. */ +/* We decide which register to use based on the compilation options and + the assembler in use; this is more general than the APCS restriction of + using sb (r9) all the time. */ +extern int arm_pic_register; + +/* The register number of the register used to address a table of static + data addresses in memory. */ +#define PIC_OFFSET_TABLE_REGNUM arm_pic_register + +#define FINALIZE_PIC arm_finalize_pic () + +#define LEGITIMATE_PIC_OPERAND_P(X) (! symbol_mentioned_p (X)) + + + +/* Condition code information. */ +/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, + return the mode to be used for the comparison. + CCFPEmode should be used with floating inequalities, + CCFPmode should be used with floating equalities. + CC_NOOVmode should be used with SImode integer equalities. + CC_Zmode should be used if only the Z flag is set correctly + CCmode should be used otherwise. */ + +#define EXTRA_CC_MODES CC_NOOVmode, CC_Zmode, CC_SWPmode, \ + CCFPmode, CCFPEmode, CC_DNEmode, CC_DEQmode, CC_DLEmode, \ + CC_DLTmode, CC_DGEmode, CC_DGTmode, CC_DLEUmode, CC_DLTUmode, \ + CC_DGEUmode, CC_DGTUmode, CC_Cmode + +#define EXTRA_CC_NAMES "CC_NOOV", "CC_Z", "CC_SWP", "CCFP", "CCFPE", \ + "CC_DNE", "CC_DEQ", "CC_DLE", "CC_DLT", "CC_DGE", "CC_DGT", "CC_DLEU", \ + "CC_DLTU", "CC_DGEU", "CC_DGTU", "CC_C" + +enum machine_mode arm_select_cc_mode (); +#define SELECT_CC_MODE(OP,X,Y) arm_select_cc_mode ((OP), (X), (Y)) + +#define REVERSIBLE_CC_MODE(MODE) ((MODE) != CCFPEmode) + +enum rtx_code arm_canonicalize_comparison (); +#define CANONICALIZE_COMPARISON(CODE,OP0,OP1) \ +do \ +{ \ + if (GET_CODE (OP1) == CONST_INT \ + && ! (const_ok_for_arm (INTVAL (OP1)) \ + || (const_ok_for_arm (- INTVAL (OP1))))) \ + { \ + rtx const_op = OP1; \ + CODE = arm_canonicalize_comparison ((CODE), &const_op); \ + OP1 = const_op; \ + } \ +} while (0) + +#define STORE_FLAG_VALUE 1 + +/* Define the information needed to generate branch insns. This is + stored from the compare operation. Note that we can't use "rtx" here + since it hasn't been defined! */ + +extern struct rtx_def *arm_compare_op0, *arm_compare_op1; +extern int arm_compare_fp; + +/* Define the codes that are matched by predicates in arm.c */ +#define PREDICATE_CODES \ + {"s_register_operand", {SUBREG, REG}}, \ + {"f_register_operand", {SUBREG, REG}}, \ + {"arm_add_operand", {SUBREG, REG, CONST_INT}}, \ + {"fpu_add_operand", {SUBREG, REG, CONST_DOUBLE}}, \ + {"arm_rhs_operand", {SUBREG, REG, CONST_INT}}, \ + {"fpu_rhs_operand", {SUBREG, REG, CONST_DOUBLE}}, \ + {"arm_not_operand", {SUBREG, REG, CONST_INT}}, \ + {"offsettable_memory_operand", {MEM}}, \ + {"bad_signed_byte_operand", {MEM}}, \ + {"alignable_memory_operand", {MEM}}, \ + {"shiftable_operator", {PLUS, MINUS, AND, IOR, XOR}}, \ + {"minmax_operator", {SMIN, SMAX, UMIN, UMAX}}, \ + {"shift_operator", {ASHIFT, ASHIFTRT, LSHIFTRT, ROTATERT, MULT}}, \ + {"di_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE, MEM}}, \ + {"soft_df_operand", {SUBREG, REG, CONST_DOUBLE, MEM}}, \ + {"load_multiple_operation", {PARALLEL}}, \ + {"store_multiple_operation", {PARALLEL}}, \ + {"equality_operator", {EQ, NE}}, \ + {"arm_rhsm_operand", {SUBREG, REG, CONST_INT, MEM}}, \ + {"const_shift_operand", {CONST_INT}}, \ + {"index_operand", {SUBREG, REG, CONST_INT}}, \ + {"reg_or_int_operand", {SUBREG, REG, CONST_INT}}, \ + {"multi_register_push", {PARALLEL}}, \ + {"cc_register", {REG}}, \ + {"dominant_cc_register", {REG}}, + + + +/* Gcc puts the pool in the wrong place for ARM, since we can only + load addresses a limited distance around the pc. We do some + special munging to move the constant pool values to the correct + point in the code. */ +#define MACHINE_DEPENDENT_REORG(INSN) arm_reorg ((INSN)) + +/* The pool is empty, since we have moved everything into the code. */ +#define ASM_OUTPUT_SPECIAL_POOL_ENTRY(FILE,X,MODE,ALIGN,LABELNO,JUMPTO) \ + goto JUMPTO + +/* Output an internal label definition. */ +#ifndef ASM_OUTPUT_INTERNAL_LABEL +#define ASM_OUTPUT_INTERNAL_LABEL(STREAM, PREFIX, NUM) \ + do \ + { \ + char * s = (char *) alloca (40 + strlen (PREFIX)); \ + extern int arm_target_label, arm_ccfsm_state; \ + extern rtx arm_target_insn; \ + \ + if (arm_ccfsm_state == 3 && arm_target_label == (NUM) \ + && !strcmp (PREFIX, "L")) \ + { \ + arm_ccfsm_state = 0; \ + arm_target_insn = NULL; \ + } \ + ASM_GENERATE_INTERNAL_LABEL (s, (PREFIX), (NUM)); \ + /* CYGNUS LOCAL variation */ \ + arm_asm_output_label (STREAM, s); \ + /* END CYGNUS LOCAL variation */ \ + } while (0) +#endif + +/* CYGNUS LOCAL */ +/* Output a label definition. */ +#undef ASM_OUTPUT_LABEL +#define ASM_OUTPUT_LABEL(STREAM,NAME) arm_asm_output_label ((STREAM), (NAME)) +/* END CYGNUS LOCAL */ + +/* Output a push or a pop instruction (only used when profiling). */ +#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ + fprintf (STREAM,"\tstmfd\t%ssp!,{%s%s}\n", \ + REGISTER_PREFIX, REGISTER_PREFIX, reg_names [REGNO]) + +#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \ + fprintf (STREAM,"\tldmfd\t%ssp!,{%s%s}\n", \ + REGISTER_PREFIX, REGISTER_PREFIX, reg_names [REGNO]) + +/* Target characters. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* Only perform branch elimination (by making instructions conditional) if + we're optimising. Otherwise it's of no use anyway. */ +#define FINAL_PRESCAN_INSN(INSN, OPVEC, NOPERANDS) \ + if (optimize) \ + final_prescan_insn (INSN, OPVEC, NOPERANDS) + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '?' || (CODE) == '|' || (CODE) == '@') +/* Output an operand of an instruction. */ +#define PRINT_OPERAND(STREAM, X, CODE) \ + arm_print_operand (STREAM, X, CODE) + +#define ARM_SIGN_EXTEND(x) ((HOST_WIDE_INT) \ + (HOST_BITS_PER_WIDE_INT <= 32 ? (x) \ + : (((x) & (unsigned HOST_WIDE_INT) 0xffffffff) | \ + (((x) & (unsigned HOST_WIDE_INT) 0x80000000) \ + ? ((~ (HOST_WIDE_INT) 0) \ + & ~ (unsigned HOST_WIDE_INT) 0xffffffff) \ + : 0)))) + +/* Output the address of an operand. */ +#define PRINT_OPERAND_ADDRESS(STREAM,X) \ +{ \ + int is_minus = GET_CODE (X) == MINUS; \ + \ + if (GET_CODE (X) == REG) \ + fprintf (STREAM, "[%s%s, #0]", REGISTER_PREFIX, \ + reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == PLUS || is_minus) \ + { \ + rtx base = XEXP (X, 0); \ + rtx index = XEXP (X, 1); \ + char * base_reg_name; \ + HOST_WIDE_INT offset = 0; \ + if (GET_CODE (base) != REG) \ + { \ + /* Ensure that BASE is a register (one of them must be). */ \ + rtx temp = base; \ + base = index; \ + index = temp; \ + } \ + base_reg_name = reg_names[REGNO (base)]; \ + switch (GET_CODE (index)) \ + { \ + case CONST_INT: \ + offset = INTVAL (index); \ + if (is_minus) \ + offset = -offset; \ + fprintf (STREAM, "[%s%s, #%d]", REGISTER_PREFIX, \ + base_reg_name, offset); \ + break; \ + \ + case REG: \ + fprintf (STREAM, "[%s%s, %s%s%s]", REGISTER_PREFIX, \ + base_reg_name, is_minus ? "-" : "", \ + REGISTER_PREFIX, reg_names[REGNO (index)] ); \ + break; \ + \ + case MULT: \ + case ASHIFTRT: \ + case LSHIFTRT: \ + case ASHIFT: \ + case ROTATERT: \ + { \ + fprintf (STREAM, "[%s%s, %s%s%s", REGISTER_PREFIX, \ + base_reg_name, is_minus ? "-" : "", REGISTER_PREFIX,\ + reg_names[REGNO (XEXP (index, 0))]); \ + arm_print_operand (STREAM, index, 'S'); \ + fputs ("]", STREAM); \ + break; \ + } \ + \ + default: \ + abort(); \ + } \ + } \ + else if (GET_CODE (X) == PRE_INC || GET_CODE (X) == POST_INC \ + || GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_DEC) \ + { \ + extern int output_memory_reference_mode; \ + \ + if (GET_CODE (XEXP (X, 0)) != REG) \ + abort (); \ + \ + if (GET_CODE (X) == PRE_DEC || GET_CODE (X) == PRE_INC) \ + fprintf (STREAM, "[%s%s, #%s%d]!", REGISTER_PREFIX, \ + reg_names[REGNO (XEXP (X, 0))], \ + GET_CODE (X) == PRE_DEC ? "-" : "", \ + GET_MODE_SIZE (output_memory_reference_mode)); \ + else \ + fprintf (STREAM, "[%s%s], #%s%d", REGISTER_PREFIX, \ + reg_names[REGNO (XEXP (X, 0))], \ + GET_CODE (X) == POST_DEC ? "-" : "", \ + GET_MODE_SIZE (output_memory_reference_mode)); \ + } \ + else output_addr_const(STREAM, X); \ +} + +/* Handles PIC addr specially */ +#define OUTPUT_INT_ADDR_CONST(STREAM,X) \ + { \ + if (flag_pic && GET_CODE(X) == CONST && is_pic(X)) \ + { \ + output_addr_const(STREAM, XEXP (XEXP (XEXP (X, 0), 0), 0)); \ + fputs(" - (", STREAM); \ + output_addr_const(STREAM, XEXP (XEXP (XEXP (X, 0), 1), 0)); \ + fputs(")", STREAM); \ + } \ + else output_addr_const(STREAM, X); \ + } + +/* Output code to add DELTA to the first argument, and then jump to FUNCTION. + Used for C++ multiple inheritance. */ +#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ +do { \ + int mi_delta = (DELTA); \ + char *mi_op = mi_delta < 0 ? "sub" : "add"; \ + int shift = 0; \ + int this_regno = (aggregate_value_p (TREE_TYPE (TREE_TYPE (FUNCTION))) \ + ? 1 : 0); \ + if (mi_delta < 0) mi_delta = -mi_delta; \ + while (mi_delta != 0) \ + { \ + if (mi_delta & (3 << shift) == 0) \ + shift += 2; \ + else \ + { \ + fprintf (FILE, "\t%s\t%s%s, %s%s, #%d\n", \ + mi_op, REGISTER_PREFIX, reg_names[this_regno], \ + REGISTER_PREFIX, reg_names[this_regno], \ + mi_delta & (0xff << shift)); \ + /* CYGNUS LOCAL */ \ + arm_increase_location (4); \ + /* END CYGNUS LOCAL */ \ + mi_delta &= ~(0xff << shift); \ + shift += 8; \ + } \ + } \ + fputs ("\tb\t", FILE); \ + assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ + fputc ('\n', FILE); \ + /* CYGNUS LOCAL */ \ + arm_increase_location (4); \ + /* END CYGNUS LOCAL */ \ +} while (0) + +/* A C expression whose value is RTL representing the value of the return + address for the frame COUNT steps up from the current frame. */ + +#define RETURN_ADDR_RTX(COUNT, FRAME) \ + ((COUNT == 0) \ + ? gen_rtx (MEM, Pmode, plus_constant (FRAME, -4)) \ + : NULL_RTX) + +/* Used to mask out junk bits from the return address, such as + processor state, interrupt status, condition codes and the like. */ +#define MASK_RETURN_ADDR \ + /* If we are generating code for an ARM2/ARM3 machine or for an ARM6 \ + in 26 bit mode, the condition codes must be masked out of the \ + return address. This does not apply to ARM6 and later processors \ + when running in 32 bit mode. */ \ + ((!TARGET_APCS_32) ? (GEN_INT (0x03fffffc)) : (GEN_INT (0xffffffff))) + +/* Prototypes for arm.c -- actually, they aren't since the types aren't + fully defined yet. */ + +void arm_override_options (/* void */); +int use_return_insn (/* void */); +int const_ok_for_arm (/* HOST_WIDE_INT */); +int const_ok_for_op (/* HOST_WIDE_INT, enum rtx_code, + enum machine_mode */); +int arm_split_constant (/* enum rtx_code, enum machine_mode, + HOST_WIDE_INT, struct rtx_def *, + struct rtx_def *, int */); +enum rtx_code arm_canonicalize_comparison (/* enum rtx_code, + struct rtx_def ** */); +int arm_return_in_memory (/* union tree_node * */); +int legitimate_pic_operand_p (/* struct rtx_def * */); +struct rtx_def *legitimize_pic_address (/* struct rtx_def *, + enum machine_mode, + struct rtx_def * */); +int is_pic (/* struct rtx_def * */); +void arm_finalize_pic (/* void */); +int arm_rtx_costs (/* struct rtx_def *, enum rtx_code, enum rtx_code */); +int arm_adjust_cost (/* struct rtx_def *, struct rtx_def *, + struct rtx_def *, int */); +int const_double_rtx_ok_for_fpu (/* struct rtx_def * */); +int neg_const_double_rtx_ok_for_fpu (/* struct rtx_def * */); +int s_register_operand (/* struct rtx_def *, enum machine_mode */); +int f_register_operand (/* struct rtx_def *, enum machine_mode */); +int reg_or_int_operand (/* struct rtx_def *, enum machine_mode */); +int reload_memory_operand (/* struct rtx_def *, enum machine_mode */); +int arm_rhs_operand (/* struct rtx_def *, enum machine_mode */); +int arm_rhsm_operand (/* struct rtx_def *, enum machine_mode */); +int arm_add_operand (/* struct rtx_def *, enum machine_mode */); +int arm_not_operand (/* struct rtx_def *, enum machine_mode */); +int offsettable_memory_operand (/* struct rtx_def *, enum machine_mode */); +int alignable_memory_operand (/* struct rtx_def *, enum machine_mode */); +int bad_signed_byte_operand (/* struct rtx_def *, enum machine_mode */); +int fpu_rhs_operand (/* struct rtx_def *, enum machine_mode */); +int fpu_add_operand (/* struct rtx_def *, enum machine_mode */); +int power_of_two_operand (/* struct rtx_def *, enum machine_mode */); +int di_operand (/* struct rtx_def *, enum machine_mode */); +int soft_df_operand (/* struct rtx_def *, enum machine_mode */); +int index_operand (/* struct rtx_def *, enum machine_mode */); +int const_shift_operand (/* struct rtx_def *, enum machine_mode */); +int shiftable_operator (/* struct rtx_def *, enum machine_mode */); +int shift_operator (/* struct rtx_def *, enum machine_mode */); +int equality_operator (/* struct rtx_def *, enum machine_mode */); +int minmax_operator (/* struct rtx_def *, enum machine_mode */); +int cc_register (/* struct rtx_def *, enum machine_mode */); +int dominant_cc_register (/* struct rtx_def *, enum machine_mode */); +int symbol_mentioned_p (/* struct rtx_def * */); +int label_mentioned_p (/* struct rtx_def * */); +enum rtx_code minmax_code (/* struct rtx_def * */); +int adjacent_mem_locations (/* struct rtx_def *, struct rtx_def * */); +int load_multiple_operation (/* struct rtx_def *, enum machine_mode */); +int store_multiple_operation (/* struct rtx_def *, enum machine_mode */); +int load_multiple_sequence (/* struct rtx_def **, int, int *, int *, + HOST_WIDE_INT * */); +char *emit_ldm_seq (/* struct rtx_def **, int */); +int store_multiple_sequence (/* struct rtx_def **, int, int *, int *, + HOST_WIDE_INT * */); +char *emit_stm_seq (/* struct rtx_def **, int */); +int multi_register_push (/* struct rtx_def *, enum machine_mode */); +int arm_valid_machine_decl_attribute (/* union tree_node *, union tree_node *, + union tree_node *, + union tree_node * */); +struct rtx_def *arm_gen_load_multiple (/* int, int, struct rtx_def *, + int, int, int, int, int */); +struct rtx_def *arm_gen_store_multiple (/* int, int, struct rtx_def *, + int, int, int, int, int */); +int arm_gen_movstrqi (/* struct rtx_def ** */); +struct rtx_def *gen_rotated_half_load (/* struct rtx_def * */); +enum machine_mode arm_select_cc_mode (/* enum rtx_code, struct rtx_def *, + struct rtx_def * */); +struct rtx_def *gen_compare_reg (/* enum rtx_code, struct rtx_def *, + struct rtx_def * */); +void arm_reload_in_hi (/* struct rtx_def ** */); +void arm_reload_out_hi (/* struct rtx_def ** */); +void arm_reorg (/* struct rtx_def * */); +char *fp_immediate_constant (/* struct rtx_def * */); +void print_multi_reg (/* FILE *, char *, int, int */); +char *output_call (/* struct rtx_def ** */); +char *output_call_mem (/* struct rtx_def ** */); +char *output_mov_long_double_fpu_from_arm (/* struct rtx_def ** */); +char *output_mov_long_double_arm_from_fpu (/* struct rtx_def ** */); +char *output_mov_long_double_arm_from_arm (/* struct rtx_def ** */); +char *output_mov_double_fpu_from_arm (/* struct rtx_def ** */); +char *output_mov_double_arm_from_fpu (/* struct rtx_def ** */); +char *output_move_double (/* struct rtx_def ** */); +char *output_mov_immediate (/* struct rtx_def ** */); +char *output_add_immediate (/* struct rtx_def ** */); +char *arithmetic_instr (/* struct rtx_def *, int */); +void output_ascii_pseudo_op (/* FILE *, unsigned char *, int */); +char *output_return_instruction (/* struct rtx_def *, int, int */); +int arm_volatile_func (/* void */); +void output_func_prologue (/* FILE *, int */); +void output_func_epilogue (/* FILE *, int */); +void arm_expand_prologue (/* void */); +void arm_print_operand (/* FILE *, struct rtx_def *, int */); +void final_prescan_insn (/* struct rtx_def *, struct rtx_def **, int */); +#ifdef AOF_ASSEMBLER +struct rtx_def *aof_pic_entry (/* struct rtx_def * */); +void aof_dump_pic_table (/* FILE * */); +char *aof_text_section (/* void */); +char *aof_data_section (/* void */); +void aof_add_import (/* char * */); +void aof_delete_import (/* char * */); +void aof_dump_imports (/* FILE * */); +#endif +/* CYGNUS LOCAL nickc */ +int ok_integer_or_other (); +/* END CYGNUS LOCAL */ + +#endif /* __ARM_H__ */ diff --git a/gcc_arm/config/arm/arm_990720.md b/gcc_arm/config/arm/arm_990720.md new file mode 100755 index 0000000..807d4cb --- /dev/null +++ b/gcc_arm/config/arm/arm_990720.md @@ -0,0 +1,6488 @@ +;;- Machine description for Advanced RISC Machines' ARM for GNU compiler +;; Copyright (C) 1991, 93-98, 1999 Free Software Foundation, Inc. +;; Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl) +;; and Martin Simmons (@harleqn.co.uk). +;; More major hacks by Richard Earnshaw (rwe11@cl.cam.ac.uk) + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + +;; There are patterns in this file to support XFmode arithmetic. +;; Unfortunately RISC iX doesn't work well with these so they are disabled. +;; (See arm.h) + +;; UNSPEC Usage: +;; 0 `sin' operation: operand 0 is the result, operand 1 the parameter, +;; the mode is MODE_FLOAT +;; 1 `cos' operation: operand 0 is the result, operand 1 the parameter, +;; the mode is MODE_FLOAT +;; 2 `push multiple' operation: operand 0 is the first register. Subsequent +;; registers are in parallel (use...) expressions. +;; 3 A symbol that has been treated properly for pic usage, that is, we +;; will add the pic_register value to it before trying to dereference it. +;; Note: sin and cos are no-longer used. + +;; Attributes + +; PROG_MODE attribute is used to determine whether condition codes are +; clobbered by a call insn: they are if in prog32 mode. This is controlled +; by the -mapcs-{32,26} flag, and possibly the -mcpu=... option. +(define_attr "prog_mode" "prog26,prog32" (const (symbol_ref "arm_prog_mode"))) + +(define_attr "is_strongarm" "no,yes" (const (symbol_ref "arm_is_strong"))) + +; Floating Point Unit. If we only have floating point emulation, then there +; is no point in scheduling the floating point insns. (Well, for best +; performance we should try and group them together). + +(define_attr "fpu" "fpa,fpe2,fpe3" (const (symbol_ref "arm_fpu_attr"))) + +; LENGTH of an instruction (in bytes) +(define_attr "length" "" (const_int 4)) + +; An assembler sequence may clobber the condition codes without us knowing +(define_asm_attributes + [(set_attr "conds" "clob") + (set_attr "length" "4")]) + +; TYPE attribute is used to detect floating point instructions which, if +; running on a co-processor can run in parallel with other, basic instructions +; If write-buffer scheduling is enabled then it can also be used in the +; scheduling of writes. + +; Classification of each insn +; normal any data instruction that doesn't hit memory or fp regs +; mult a multiply instruction +; block blockage insn, this blocks all functional units +; float a floating point arithmetic operation (subject to expansion) +; fdivx XFmode floating point division +; fdivd DFmode floating point division +; fdivs SFmode floating point division +; fmul Floating point multiply +; ffmul Fast floating point multiply +; farith Floating point arithmetic (4 cycle) +; ffarith Fast floating point arithmetic (2 cycle) +; float_em a floating point arithmetic operation that is normally emulated +; even on a machine with an fpa. +; f_load a floating point load from memory +; f_store a floating point store to memory +; f_mem_r a transfer of a floating point register to a real reg via mem +; r_mem_f the reverse of f_mem_r +; f_2_r fast transfer float to arm (no memory needed) +; r_2_f fast transfer arm to float +; call a subroutine call +; load any load from memory +; store1 store 1 word to memory from arm registers +; store2 store 2 words +; store3 store 3 words +; store4 store 4 words +; +(define_attr "type" + "normal,mult,block,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith,float_em,f_load,f_store,f_mem_r,r_mem_f,f_2_r,r_2_f,call,load,store1,store2,store3,store4" + (const_string "normal")) + +;; CYGNUS LOCAL load scheduling +; Load scheduling, set from the arm_ld_sched variable +; initialised by arm_override_options() +(define_attr "ldsched" "no,yes" + (const (symbol_ref "arm_ld_sched"))) +;; END CYGNUS LOCAL + +; condition codes: this one is used by final_prescan_insn to speed up +; conditionalizing instructions. It saves having to scan the rtl to see if +; it uses or alters the condition codes. + +; USE means that the condition codes are used by the insn in the process of +; outputting code, this means (at present) that we can't use the insn in +; inlined branches + +; SET means that the purpose of the insn is to set the condition codes in a +; well defined manner. + +; CLOB means that the condition codes are altered in an undefined manner, if +; they are altered at all + +; JUMP_CLOB is used when the conditions are not defined if a branch is taken, +; but are if the branch wasn't taken; the effect is to limit the branch +; elimination scanning. + +; NOCOND means that the condition codes are neither altered nor affect the +; output of this insn + +(define_attr "conds" "use,set,clob,jump_clob,nocond" + (if_then_else (eq_attr "type" "call") + (if_then_else (eq_attr "prog_mode" "prog32") + (const_string "clob") (const_string "nocond")) + (const_string "nocond"))) + +; Only model the write buffer for ARM6 and ARM7. Earlier processors don't +; have one. Later ones, such as StrongARM, have write-back caches, so don't +; suffer blockages enough to warrent modelling this (and it can adversely +; affect the schedule). +(define_attr "model_wbuf" "no,yes" (const (symbol_ref "arm_is_6_or_7"))) + +(define_attr "write_conflict" "no,yes" + (if_then_else (eq_attr "type" + "block,float_em,f_load,f_store,f_mem_r,r_mem_f,call,load") + (const_string "yes") + (const_string "no"))) + +(define_attr "core_cycles" "single,multi" + (if_then_else (eq_attr "type" + "normal,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith") + (const_string "single") + (const_string "multi"))) + +; The write buffer on some of the arm6 processors is hard to model exactly. +; There is room in the buffer for up to two addresses and up to eight words +; of memory, but the two needn't be split evenly. When writing the two +; addresses are fully pipelined. However, a read from memory that is not +; currently in the cache will block until the writes have completed. +; It is normally the case that FCLK and MCLK will be in the ratio 2:1, so +; writes will take 2 FCLK cycles per word, if FCLK and MCLK are asynchronous +; (they aren't allowed to be at present) then there is a startup cost of 1MCLK +; cycle to add as well. + +;; (define_function_unit {name} {num-units} {n-users} {test} +;; {ready-delay} {issue-delay} [{conflict-list}]) +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "fdivx")) 71 69) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "fdivd")) 59 57) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "fdivs")) 31 29) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "fmul")) 9 7) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "ffmul")) 6 4) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "farith")) 4 2) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "ffarith")) 2 2) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "r_2_f")) 5 3) + +(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "f_2_r")) 1 2) + +;; The fpa10 doesn't really have a memory read unit, but it can start to +;; speculatively execute the instruction in the pipeline, provided the data +;; is already loaded, so pretend reads have a delay of 2 (and that the +;; pipeline is infinite. + +(define_function_unit "fpa_mem" 1 0 (and (eq_attr "fpu" "fpa") + (eq_attr "type" "f_load")) 3 1) + +;;-------------------------------------------------------------------- +;; Write buffer +;;-------------------------------------------------------------------- +;; Strictly we should model a 4-deep write buffer for ARM7xx based chips +(define_function_unit "write_buf" 1 2 + (and (eq_attr "model_wbuf" "yes") + (eq_attr "type" "store1,r_mem_f")) 5 3) +(define_function_unit "write_buf" 1 2 + (and (eq_attr "model_wbuf" "yes") + (eq_attr "type" "store2")) 7 4) +(define_function_unit "write_buf" 1 2 + (and (eq_attr "model_wbuf" "yes") + (eq_attr "type" "store3")) 9 5) +(define_function_unit "write_buf" 1 2 + (and (eq_attr "model_wbuf" "yes") + (eq_attr "type" "store4")) 11 6) + +;;-------------------------------------------------------------------- +;; Write blockage unit +;;-------------------------------------------------------------------- +;; The write_blockage unit models (partially), the fact that reads will stall +;; until the write buffer empties. +;; The f_mem_r and r_mem_f could also block, but they are to the stack, +;; so we don't model them here +(define_function_unit "write_blockage" 1 0 (and (eq_attr "model_wbuf" "yes") + (eq_attr "type" "store1")) 5 5 + [(eq_attr "write_conflict" "yes")]) +(define_function_unit "write_blockage" 1 0 (and (eq_attr "model_wbuf" "yes") + (eq_attr "type" "store2")) 7 7 + [(eq_attr "write_conflict" "yes")]) +(define_function_unit "write_blockage" 1 0 (and (eq_attr "model_wbuf" "yes") + (eq_attr "type" "store3")) 9 9 + [(eq_attr "write_conflict" "yes")]) +(define_function_unit "write_blockage" 1 0 + (and (eq_attr "model_wbuf" "yes") (eq_attr "type" "store4")) 11 11 + [(eq_attr "write_conflict" "yes")]) +(define_function_unit "write_blockage" 1 0 + (and (eq_attr "model_wbuf" "yes") + (eq_attr "write_conflict" "yes")) 1 1) + +;;-------------------------------------------------------------------- +;; Core unit +;;-------------------------------------------------------------------- +;; Everything must spend at least one cycle in the core unit +(define_function_unit "core" 1 0 + (and (eq_attr "ldsched" "yes") (eq_attr "type" "store1")) 1 1) + +(define_function_unit "core" 1 0 + (and (eq_attr "ldsched" "yes") (eq_attr "type" "load")) 2 1) + +(define_function_unit "core" 1 0 + (and (eq_attr "ldsched" "!yes") (eq_attr "type" "load,store1")) 2 2) + +(define_function_unit "core" 1 0 + (and (eq_attr "fpu" "fpa") (eq_attr "type" "f_load")) 3 3) + +(define_function_unit "core" 1 0 + (and (eq_attr "fpu" "fpa") (eq_attr "type" "f_store")) 4 4) + +(define_function_unit "core" 1 0 + (and (eq_attr "fpu" "fpa") (eq_attr "type" "r_mem_f")) 6 6) + +(define_function_unit "core" 1 0 + (and (eq_attr "fpu" "fpa") (eq_attr "type" "f_mem_r")) 7 7) + +(define_function_unit "core" 1 0 + (and (eq_attr "ldsched" "no") (eq_attr "type" "mult")) 16 16) + +(define_function_unit "core" 1 0 + (and (and (eq_attr "ldsched" "yes") (eq_attr "is_strongarm" "no")) + (eq_attr "type" "mult")) 4 4) + +(define_function_unit "core" 1 0 + (and (and (eq_attr "ldsched" "yes") (eq_attr "is_strongarm" "yes")) + (eq_attr "type" "mult")) 3 2) + +(define_function_unit "core" 1 0 (eq_attr "type" "store2") 3 3) + +(define_function_unit "core" 1 0 (eq_attr "type" "store3") 4 4) + +(define_function_unit "core" 1 0 (eq_attr "type" "store4") 5 5) + +;; CYGNUS LOCAL +;; APCS support: When generating code for the software stack checking +;; model, we need to be able to perform calls to the special exception +;; handler routines. These routines are *NOT* APCS conforming, so we +;; do not need to mark any registers as clobbered over the call other +;; than the lr/r14 modified by the actual BL instruction. Rather than +;; trying to force the RTL for the existing comparison and call to +;; achieve this, we simply have a pattern that does the desired job. + +;; TODO: This is not ideal since it does not specify all of the +;; operators involved: +;; cmp %op0,%op1 cmpsi_insn (compare) +;; bl%op3 %op2 call_value_symbol (call) +;; Unfortunately since we do not go through the normal arm_ccfsm_state +;; processing we cannot use the %? operand replacment for the BL +;; condition. + +(define_insn "cond_call" + [(compare:CC (match_operand:SI 0 "s_register_operand" "r") + (match_operand:SI 1 "s_register_operand" "r")) + (match_operand:SI 2 "" "X") + (match_operator 3 "comparison_operator" [(reg:CC 24) (const_int 0)]) + (clobber (reg:CC 24)) + (clobber (reg:SI 14))] + "GET_CODE (operands[2]) == SYMBOL_REF && GET_CODE (operands[3]) == LTU" + "cmp\\t%0, %1\;bllt\\t%a2" +[(set_attr "conds" "clob") + (set_attr "type" "call") + (set_attr "length" "8")]) + +;; END CYGNUS LOCAL + +;; Note: For DImode insns, there is normally no reason why operands should +;; not be in the same register, what we don't want is for something being +;; written to partially overlap something that is an input. + +;; Addition insns. + +(define_insn "adddi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (plus:DI (match_operand:DI 1 "s_register_operand" "%0,0") + (match_operand:DI 2 "s_register_operand" "r,0"))) + (clobber (reg:CC 24))] + "" + "adds\\t%Q0, %Q1, %Q2\;adc\\t%R0, %R1, %R2" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*adddi_sesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (plus:DI (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "r,0"))) + (clobber (reg:CC 24))] + "" + "adds\\t%Q0, %Q1, %2\;adc\\t%R0, %R1, %2, asr #31" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*adddi_zesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (plus:DI (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "r,0"))) + (clobber (reg:CC 24))] + "" + "adds\\t%Q0, %Q1, %2\;adc\\t%R0, %R1, #0" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_expand "addsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (plus:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "reg_or_int_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT) + { + arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0], + operands[1], + (reload_in_progress || reload_completed ? 0 + : preserve_subexpressions_p ())); + DONE; + } +") + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (plus:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "const_int_operand" "")))] + "! (const_ok_for_arm (INTVAL (operands[2])) + || const_ok_for_arm (-INTVAL (operands[2])))" + [(clobber (const_int 0))] + " + arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0], + operands[1], 0); + DONE; +") + +(define_insn "*addsi3_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (plus:SI (match_operand:SI 1 "s_register_operand" "r,r,r") + (match_operand:SI 2 "reg_or_int_operand" "rI,L,?n")))] + "" + "@ + add%?\\t%0, %1, %2 + sub%?\\t%0, %1, #%n2 + #" +[(set_attr "length" "4,4,16")]) + +(define_insn "*addsi3_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (plus:SI (match_operand:SI 1 "s_register_operand" "r,r") + (match_operand:SI 2 "arm_add_operand" "rI,L")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") + (plus:SI (match_dup 1) (match_dup 2)))] + "" + "@ + add%?s\\t%0, %1, %2 + sub%?s\\t%0, %1, #%n2" +[(set_attr "conds" "set")]) + +(define_insn "*addsi3_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (plus:SI (match_operand:SI 0 "s_register_operand" "r,r") + (match_operand:SI 1 "arm_add_operand" "rI,L")) + (const_int 0)))] + "" + "@ + cmn%?\\t%0, %1 + cmp%?\\t%0, #%n1" +[(set_attr "conds" "set")]) + +;; The next four insns work because they compare the result with one of +;; the operands, and we know that the use of the condition code is +;; either GEU or LTU, so we can use the carry flag from the addition +;; instead of doing the compare a second time. +(define_insn "*addsi3_compare_op1" + [(set (reg:CC_C 24) + (compare:CC_C + (plus:SI (match_operand:SI 1 "s_register_operand" "r,r") + (match_operand:SI 2 "arm_add_operand" "rI,L")) + (match_dup 1))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") + (plus:SI (match_dup 1) (match_dup 2)))] + "" + "@ + add%?s\\t%0, %1, %2 + sub%?s\\t%0, %1, #%n2" +[(set_attr "conds" "set")]) + +(define_insn "*addsi3_compare_op2" + [(set (reg:CC_C 24) + (compare:CC_C + (plus:SI (match_operand:SI 1 "s_register_operand" "r,r") + (match_operand:SI 2 "arm_add_operand" "rI,L")) + (match_dup 2))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") + (plus:SI (match_dup 1) (match_dup 2)))] + "" + "@ + add%?s\\t%0, %1, %2 + sub%?s\\t%0, %1, #%n2" +[(set_attr "conds" "set")]) + +(define_insn "*compare_addsi2_op0" + [(set (reg:CC_C 24) + (compare:CC_C + (plus:SI (match_operand:SI 0 "s_register_operand" "r,r") + (match_operand:SI 1 "arm_add_operand" "rI,L")) + (match_dup 0)))] + "" + "@ + cmn%?\\t%0, %1 + cmp%?\\t%0, #%n1" +[(set_attr "conds" "set")]) + +(define_insn "*compare_addsi2_op1" + [(set (reg:CC_C 24) + (compare:CC_C + (plus:SI (match_operand:SI 0 "s_register_operand" "r,r") + (match_operand:SI 1 "arm_add_operand" "rI,L")) + (match_dup 1)))] + "" + "@ + cmn%?\\t%0, %1 + cmp%?\\t%0, #%n1" +[(set_attr "conds" "set")]) + +(define_insn "*addsi3_carryin" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (ltu:SI (reg:CC_C 24) (const_int 0)) + (plus:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rI"))))] + "" + "adc%?\\t%0, %1, %2" +[(set_attr "conds" "use")]) + +(define_insn "*addsi3_carryin_alt1" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (plus:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rI")) + (ltu:SI (reg:CC_C 24) (const_int 0))))] + "" + "adc%?\\t%0, %1, %2" +[(set_attr "conds" "use")]) + +(define_insn "*addsi3_carryin_alt2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (plus:SI (ltu:SI (reg:CC_C 24) (const_int 0)) + (match_operand:SI 1 "s_register_operand" "r")) + (match_operand:SI 2 "arm_rhs_operand" "rI")))] + "" + "adc%?\\t%0, %1, %2" +[(set_attr "conds" "use")]) + +(define_insn "*addsi3_carryin_alt3" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (plus:SI (ltu:SI (reg:CC_C 24) (const_int 0)) + (match_operand:SI 2 "arm_rhs_operand" "rI")) + (match_operand:SI 1 "s_register_operand" "r")))] + "" + "adc%?\\t%0, %1, %2" +[(set_attr "conds" "use")]) + +(define_insn "incscc" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (plus:SI (match_operator:SI 2 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "s_register_operand" "0,?r")))] + "" + "@ + add%d2\\t%0, %1, #1 + mov%D2\\t%0, %1\;add%d2\\t%0, %1, #1" +[(set_attr "conds" "use") + (set_attr "length" "4,8")]) + +; If a constant is too big to fit in a single instruction then the constant +; will be pre-loaded into a register taking at least two insns, we might be +; able to merge it with an add, but it depends on the exact value. + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "const_int_operand" "n")))] + "!(const_ok_for_arm (INTVAL (operands[2])) + || const_ok_for_arm (-INTVAL (operands[2])))" + [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2))) + (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 3)))] + " +{ + unsigned int val = (unsigned) INTVAL (operands[2]); + int i; + unsigned int temp; + + /* this code is similar to the approach followed in movsi, but it must + generate exactly two insns */ + + for (i = 30; i >= 0; i -= 2) + { + if (val & (3 << i)) + { + i -= 6; + if (i < 0) i = 0; + if (const_ok_for_arm (temp = (val & ~(255 << i)))) + { + val &= 255 << i; + break; + } + /* we might be able to do this as (larger number - small number) */ + temp = ((val >> i) & 255) + 1; + if (temp > 255 && i < 24) + { + i += 2; + temp = ((val >> i) & 255) + 1; + } + if (const_ok_for_arm ((temp << i) - val)) + { + i = temp << i; + temp = (unsigned) - (int) (i - val); + val = i; + break; + } + FAIL; + } + } + /* if we got here, we have found a way of doing it in two instructions. + the two constants are in val and temp */ + operands[2] = GEN_INT ((int)val); + operands[3] = GEN_INT ((int)temp); +} +") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "s_register_operand" "=f,f") + (plus:SF (match_operand:SF 1 "s_register_operand" "f,f") + (match_operand:SF 2 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + adf%?s\\t%0, %1, %2 + suf%?s\\t%0, %1, #%N2" +[(set_attr "type" "farith")]) + +(define_insn "adddf3" + [(set (match_operand:DF 0 "s_register_operand" "=f,f") + (plus:DF (match_operand:DF 1 "s_register_operand" "f,f") + (match_operand:DF 2 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + adf%?d\\t%0, %1, %2 + suf%?d\\t%0, %1, #%N2" +[(set_attr "type" "farith")]) + +(define_insn "*adddf_df_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f,f") + (plus:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f,f")) + (match_operand:DF 2 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + adf%?d\\t%0, %1, %2 + suf%?d\\t%0, %1, #%N2" +[(set_attr "type" "farith")]) + +(define_insn "*adddf_df_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (plus:DF (match_operand:DF 1 "s_register_operand" "f") + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "adf%?d\\t%0, %1, %2" +[(set_attr "type" "farith")]) + +(define_insn "*adddf_esfdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (plus:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "adf%?d\\t%0, %1, %2" +[(set_attr "type" "farith")]) + +(define_insn "addxf3" + [(set (match_operand:XF 0 "s_register_operand" "=f,f") + (plus:XF (match_operand:XF 1 "s_register_operand" "f,f") + (match_operand:XF 2 "fpu_add_operand" "fG,H")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "@ + adf%?e\\t%0, %1, %2 + suf%?e\\t%0, %1, #%N2" +[(set_attr "type" "farith")]) + +(define_insn "subdi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r,&r") + (minus:DI (match_operand:DI 1 "s_register_operand" "0,r,0") + (match_operand:DI 2 "s_register_operand" "r,0,0"))) + (clobber (reg:CC 24))] + "" + "subs\\t%Q0, %Q1, %Q2\;sbc\\t%R0, %R1, %R2" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*subdi_di_zesidi" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (minus:DI (match_operand:DI 1 "s_register_operand" "?r,0") + (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")))) + (clobber (reg:CC 24))] + "" + "subs\\t%Q0, %Q1, %2\;sbc\\t%R0, %R1, #0" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*subdi_di_sesidi" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (minus:DI (match_operand:DI 1 "s_register_operand" "r,0") + (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")))) + (clobber (reg:CC 24))] + "" + "subs\\t%Q0, %Q1, %2\;sbc\\t%R0, %R1, %2, asr #31" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*subdi_zesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (minus:DI (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "?r,0"))) + (clobber (reg:CC 24))] + "" + "rsbs\\t%Q0, %Q1, %2\;rsc\\t%R0, %R1, #0" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*subdi_sesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (minus:DI (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "?r,0"))) + (clobber (reg:CC 24))] + "" + "rsbs\\t%Q0, %Q1, %2\;rsc\\t%R0, %R1, %2, asr #31" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*subdi_zesidi_zesidi" + [(set (match_operand:DI 0 "s_register_operand" "=r") + (minus:DI (zero_extend:DI + (match_operand:SI 1 "s_register_operand" "r")) + (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r")))) + (clobber (reg:CC 24))] + "" + "subs\\t%Q0, %1, %2\;rsc\\t%R0, %1, %1" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_expand "subsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (minus:SI (match_operand:SI 1 "reg_or_int_operand" "") + (match_operand:SI 2 "s_register_operand" "")))] + "" + " + if (GET_CODE (operands[1]) == CONST_INT) + { + arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0], + operands[2], + (reload_in_progress || reload_completed ? 0 + : preserve_subexpressions_p ())); + DONE; + } +") + +(define_insn "*subsi3_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (minus:SI (match_operand:SI 1 "reg_or_int_operand" "rI,?n") + (match_operand:SI 2 "s_register_operand" "r,r")))] + "" + "@ + rsb%?\\t%0, %2, %1 + #" +[(set_attr "length" "4,16")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (minus:SI (match_operand:SI 1 "const_int_operand" "") + (match_operand:SI 2 "s_register_operand" "")))] + "! const_ok_for_arm (INTVAL (operands[1]))" + [(clobber (const_int 0))] + " + arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0], + operands[2], 0); + DONE; +") + +(define_insn "*subsi3_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (minus:SI (match_operand:SI 1 "arm_rhs_operand" "r,I") + (match_operand:SI 2 "arm_rhs_operand" "rI,r")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") + (minus:SI (match_dup 1) (match_dup 2)))] + "" + "@ + sub%?s\\t%0, %1, %2 + rsb%?s\\t%0, %2, %1" +[(set_attr "conds" "set")]) + +(define_insn "decscc" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (minus:SI (match_operand:SI 1 "s_register_operand" "0,?r") + (match_operator:SI 2 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)])))] + "" + "@ + sub%d2\\t%0, %1, #1 + mov%D2\\t%0, %1\;sub%d2\\t%0, %1, #1" +[(set_attr "conds" "use") + (set_attr "length" "*,8")]) + +(define_insn "subsf3" + [(set (match_operand:SF 0 "s_register_operand" "=f,f") + (minus:SF (match_operand:SF 1 "fpu_rhs_operand" "f,G") + (match_operand:SF 2 "fpu_rhs_operand" "fG,f")))] + "TARGET_HARD_FLOAT" + "@ + suf%?s\\t%0, %1, %2 + rsf%?s\\t%0, %2, %1" +[(set_attr "type" "farith")]) + +(define_insn "subdf3" + [(set (match_operand:DF 0 "s_register_operand" "=f,f") + (minus:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G") + (match_operand:DF 2 "fpu_rhs_operand" "fG,f")))] + "TARGET_HARD_FLOAT" + "@ + suf%?d\\t%0, %1, %2 + rsf%?d\\t%0, %2, %1" +[(set_attr "type" "farith")]) + +(define_insn "*subdf_esfdf_df" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (minus:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (match_operand:DF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "suf%?d\\t%0, %1, %2" +[(set_attr "type" "farith")]) + +(define_insn "*subdf_df_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f,f") + (minus:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G") + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f,f"))))] + "TARGET_HARD_FLOAT" + "@ + suf%?d\\t%0, %1, %2 + rsf%?d\\t%0, %2, %1" +[(set_attr "type" "farith")]) + +(define_insn "*subdf_esfdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (minus:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "suf%?d\\t%0, %1, %2" +[(set_attr "type" "farith")]) + +(define_insn "subxf3" + [(set (match_operand:XF 0 "s_register_operand" "=f,f") + (minus:XF (match_operand:XF 1 "fpu_rhs_operand" "f,G") + (match_operand:XF 2 "fpu_rhs_operand" "fG,f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "@ + suf%?e\\t%0, %1, %2 + rsf%?e\\t%0, %2, %1" +[(set_attr "type" "farith")]) + +;; Multiplication insns + +;; Use `&' and then `0' to prevent the operands 0 and 1 being the same +(define_insn "mulsi3" + [(set (match_operand:SI 0 "s_register_operand" "=&r,&r") + (mult:SI (match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 1 "s_register_operand" "%?r,0")))] + "" + "mul%?\\t%0, %2, %1" +[(set_attr "type" "mult")]) + +(define_insn "*mulsi3_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (mult:SI + (match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 1 "s_register_operand" "%?r,0")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=&r,&r") + (mult:SI (match_dup 2) (match_dup 1)))] + "" + "mul%?s\\t%0, %2, %1" +[(set_attr "conds" "set") + (set_attr "type" "mult")]) + +(define_insn "*mulsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (mult:SI + (match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 1 "s_register_operand" "%?r,0")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=&r,&r"))] + "" + "mul%?s\\t%0, %2, %1" +[(set_attr "conds" "set") + (set_attr "type" "mult")]) + +;; Unnamed templates to match MLA instruction. + +(define_insn "*mulsi3addsi" + [(set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r,&r") + (plus:SI + (mult:SI (match_operand:SI 2 "s_register_operand" "r,r,r,r") + (match_operand:SI 1 "s_register_operand" "%r,0,r,0")) + (match_operand:SI 3 "s_register_operand" "?r,r,0,0")))] + "" + "mla%?\\t%0, %2, %1, %3" +[(set_attr "type" "mult")]) + +(define_insn "*mulsi3addsi_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (plus:SI + (mult:SI + (match_operand:SI 2 "s_register_operand" "r,r,r,r") + (match_operand:SI 1 "s_register_operand" "%r,0,r,0")) + (match_operand:SI 3 "s_register_operand" "?r,r,0,0")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r,&r") + (plus:SI (mult:SI (match_dup 2) (match_dup 1)) + (match_dup 3)))] + "" + "mla%?s\\t%0, %2, %1, %3" +[(set_attr "conds" "set") + (set_attr "type" "mult")]) + +(define_insn "*mulsi3addsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (plus:SI + (mult:SI + (match_operand:SI 2 "s_register_operand" "r,r,r,r") + (match_operand:SI 1 "s_register_operand" "%r,0,r,0")) + (match_operand:SI 3 "s_register_operand" "?r,r,0,0")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=&r,&r,&r,&r"))] + "" + "mla%?s\\t%0, %2, %1, %3" +[(set_attr "conds" "set") + (set_attr "type" "mult")]) + +(define_insn "mulsidi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r") + (mult:DI (sign_extend:DI + (match_operand:SI 1 "s_register_operand" "%r")) + (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r"))))] + "arm_fast_multiply" + "smull%?\\t%Q0, %R0, %1, %2" +[(set_attr "type" "mult")]) + +(define_insn "umulsidi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r") + (mult:DI (zero_extend:DI + (match_operand:SI 1 "s_register_operand" "%r")) + (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r"))))] + "arm_fast_multiply" + "umull%?\\t%Q0, %R0, %1, %2" +[(set_attr "type" "mult")]) + +(define_insn "smulsi3_highpart" + [(set (match_operand:SI 0 "s_register_operand" "=&r,&r") + (truncate:SI + (lshiftrt:DI + (mult:DI (sign_extend:DI + (match_operand:SI 1 "s_register_operand" "%r,0")) + (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r"))) + (const_int 32)))) + (clobber (match_scratch:SI 3 "=&r,&r"))] + "arm_fast_multiply" + "smull%?\\t%3, %0, %2, %1" +[(set_attr "type" "mult")]) + +(define_insn "umulsi3_highpart" + [(set (match_operand:SI 0 "s_register_operand" "=&r,&r") + (truncate:SI + (lshiftrt:DI + (mult:DI (zero_extend:DI + (match_operand:SI 1 "s_register_operand" "%r,0")) + (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r"))) + (const_int 32)))) + (clobber (match_scratch:SI 3 "=&r,&r"))] + "arm_fast_multiply" + "umull%?\\t%3, %0, %2, %1" +[(set_attr "type" "mult")]) + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (mult:SF (match_operand:SF 1 "s_register_operand" "f") + (match_operand:SF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "fml%?s\\t%0, %1, %2" +[(set_attr "type" "ffmul")]) + +(define_insn "muldf3" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mult:DF (match_operand:DF 1 "s_register_operand" "f") + (match_operand:DF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "muf%?d\\t%0, %1, %2" +[(set_attr "type" "fmul")]) + +(define_insn "*muldf_esfdf_df" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mult:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (match_operand:DF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "muf%?d\\t%0, %1, %2" +[(set_attr "type" "fmul")]) + +(define_insn "*muldf_df_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mult:DF (match_operand:DF 1 "s_register_operand" "f") + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "muf%?d\\t%0, %1, %2" +[(set_attr "type" "fmul")]) + +(define_insn "*muldf_esfdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mult:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "muf%?d\\t%0, %1, %2" +[(set_attr "type" "fmul")]) + +(define_insn "mulxf3" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (mult:XF (match_operand:XF 1 "s_register_operand" "f") + (match_operand:XF 2 "fpu_rhs_operand" "fG")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "muf%?e\\t%0, %1, %2" +[(set_attr "type" "fmul")]) + +;; Division insns + +(define_insn "divsf3" + [(set (match_operand:SF 0 "s_register_operand" "=f,f") + (div:SF (match_operand:SF 1 "fpu_rhs_operand" "f,G") + (match_operand:SF 2 "fpu_rhs_operand" "fG,f")))] + "TARGET_HARD_FLOAT" + "@ + fdv%?s\\t%0, %1, %2 + frd%?s\\t%0, %2, %1" +[(set_attr "type" "fdivs")]) + +(define_insn "divdf3" + [(set (match_operand:DF 0 "s_register_operand" "=f,f") + (div:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G") + (match_operand:DF 2 "fpu_rhs_operand" "fG,f")))] + "TARGET_HARD_FLOAT" + "@ + dvf%?d\\t%0, %1, %2 + rdf%?d\\t%0, %2, %1" +[(set_attr "type" "fdivd")]) + +(define_insn "*divdf_esfdf_df" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (div:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (match_operand:DF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "dvf%?d\\t%0, %1, %2" +[(set_attr "type" "fdivd")]) + +(define_insn "*divdf_df_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (div:DF (match_operand:DF 1 "fpu_rhs_operand" "fG") + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "rdf%?d\\t%0, %2, %1" +[(set_attr "type" "fdivd")]) + +(define_insn "*divdf_esfdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (div:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "dvf%?d\\t%0, %1, %2" +[(set_attr "type" "fdivd")]) + +(define_insn "divxf3" + [(set (match_operand:XF 0 "s_register_operand" "=f,f") + (div:XF (match_operand:XF 1 "fpu_rhs_operand" "f,G") + (match_operand:XF 2 "fpu_rhs_operand" "fG,f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "@ + dvf%?e\\t%0, %1, %2 + rdf%?e\\t%0, %2, %1" +[(set_attr "type" "fdivx")]) + +;; Modulo insns + +(define_insn "modsf3" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (mod:SF (match_operand:SF 1 "s_register_operand" "f") + (match_operand:SF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "rmf%?s\\t%0, %1, %2" +[(set_attr "type" "fdivs")]) + +(define_insn "moddf3" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mod:DF (match_operand:DF 1 "s_register_operand" "f") + (match_operand:DF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "rmf%?d\\t%0, %1, %2" +[(set_attr "type" "fdivd")]) + +(define_insn "*moddf_esfdf_df" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mod:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (match_operand:DF 2 "fpu_rhs_operand" "fG")))] + "TARGET_HARD_FLOAT" + "rmf%?d\\t%0, %1, %2" +[(set_attr "type" "fdivd")]) + +(define_insn "*moddf_df_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mod:DF (match_operand:DF 1 "s_register_operand" "f") + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "rmf%?d\\t%0, %1, %2" +[(set_attr "type" "fdivd")]) + +(define_insn "*moddf_esfdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (mod:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f")) + (float_extend:DF + (match_operand:SF 2 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "rmf%?d\\t%0, %1, %2" +[(set_attr "type" "fdivd")]) + +(define_insn "modxf3" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (mod:XF (match_operand:XF 1 "s_register_operand" "f") + (match_operand:XF 2 "fpu_rhs_operand" "fG")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "rmf%?e\\t%0, %1, %2" +[(set_attr "type" "fdivx")]) + +;; Boolean and,ior,xor insns + +(define_insn "anddi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (and:DI (match_operand:DI 1 "s_register_operand" "%0,0") + (match_operand:DI 2 "s_register_operand" "r,0")))] + "" + "and%?\\t%Q0, %Q1, %Q2\;and%?\\t%R0, %R1, %R2" +[(set_attr "length" "8")]) + +(define_insn "*anddi_zesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (and:DI (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "?r,0")))] + "" + "and%?\\t%Q0, %Q1, %2\;mov%?\\t%R0, #0" +[(set_attr "length" "8")]) + +(define_insn "*anddi_sesdi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (and:DI (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "?r,0")))] + "" + "and%?\\t%Q0, %Q1, %2\;and%?\\t%R0, %R1, %2, asr #31" +[(set_attr "length" "8")]) + +(define_expand "andsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (and:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "reg_or_int_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT) + { + arm_split_constant (AND, SImode, INTVAL (operands[2]), operands[0], + operands[1], + (reload_in_progress || reload_completed + ? 0 : preserve_subexpressions_p ())); + DONE; + } +") + +(define_insn "*andsi3_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (and:SI (match_operand:SI 1 "s_register_operand" "r,r,r") + (match_operand:SI 2 "reg_or_int_operand" "rI,K,?n")))] + "" + "@ + and%?\\t%0, %1, %2 + bic%?\\t%0, %1, #%B2 + #" +[(set_attr "length" "4,4,16")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (and:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "const_int_operand" "")))] + "! (const_ok_for_arm (INTVAL (operands[2])) + || const_ok_for_arm (~ INTVAL (operands[2])))" + [(clobber (const_int 0))] + " + arm_split_constant (AND, SImode, INTVAL (operands[2]), operands[0], + operands[1], 0); + DONE; +") + +(define_insn "*andsi3_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (and:SI (match_operand:SI 1 "s_register_operand" "r,r") + (match_operand:SI 2 "arm_not_operand" "rI,K")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") + (and:SI (match_dup 1) (match_dup 2)))] + "" + "@ + and%?s\\t%0, %1, %2 + bic%?s\\t%0, %1, #%B2" +[(set_attr "conds" "set")]) + +(define_insn "*andsi3_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (and:SI (match_operand:SI 0 "s_register_operand" "r,r") + (match_operand:SI 1 "arm_not_operand" "rI,K")) + (const_int 0))) + (clobber (match_scratch:SI 3 "=X,r"))] + "" + "@ + tst%?\\t%0, %1 + bic%?s\\t%3, %0, #%B1" +[(set_attr "conds" "set")]) + +(define_insn "*zeroextractsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (zero_extract:SI + (match_operand:SI 0 "s_register_operand" "r") + (match_operand 1 "const_int_operand" "n") + (match_operand 2 "const_int_operand" "n")) + (const_int 0)))] + "INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) < 32 + && INTVAL (operands[1]) > 0 + && INTVAL (operands[1]) + (INTVAL (operands[2]) & 1) <= 8 + && INTVAL (operands[1]) + INTVAL (operands[2]) <= 32" + "* +{ + unsigned int mask = 0; + int cnt = INTVAL (operands[1]); + + while (cnt--) + mask = (mask << 1) | 1; + operands[1] = GEN_INT (mask << INTVAL (operands[2])); + output_asm_insn (\"tst%?\\t%0, %1\", operands); + return \"\"; +} +" +[(set_attr "conds" "set")]) + +;; ??? This pattern does not work because it does not check for start+length +;; less than or equal to 8. This is necessary for the bitfield to fit within +;; a single byte. This pattern was deleted Feb 25, 1999 in egcs, so we can +;; just disabled it for 99r1. + +(define_insn "*zeroextractqi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (zero_extract:SI + (match_operand:QI 0 "memory_operand" "m") + (match_operand 1 "const_int_operand" "n") + (match_operand 2 "const_int_operand" "n")) + (const_int 0))) + (clobber (match_scratch:QI 3 "=r"))] + "0 && INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) < 8 + && INTVAL (operands[1]) > 0 && INTVAL (operands[1]) <= 8" + "* +{ + unsigned int mask = 0; + int cnt = INTVAL (operands[1]); + + while (cnt--) + mask = (mask << 1) | 1; + operands[1] = GEN_INT (mask << INTVAL (operands[2])); + output_asm_insn (\"ldr%?b\\t%3, %0\", operands); + output_asm_insn (\"tst%?\\t%3, %1\", operands); + return \"\"; +} +" +[(set_attr "conds" "set") + (set_attr "length" "8")]) + +;;; ??? This pattern is bogus. If operand3 has bits outside the range +;;; represented by the bitfield, then this will produce incorrect results. +;;; Somewhere, the value needs to be truncated. On targets like the m68k, +;;; which have a real bitfield insert instruction, the truncation happens +;;; in the bitfield insert instruction itself. Since arm does not have a +;;; bitfield insert instruction, we would have to emit code here to truncate +;;; the value before we insert. This loses some of the advantage of having +;;; this insv pattern, so this pattern needs to be reevalutated. + +(define_expand "insv" + [(set (zero_extract:SI (match_operand:SI 0 "s_register_operand" "") + (match_operand:SI 1 "general_operand" "") + (match_operand:SI 2 "general_operand" "")) + (match_operand:SI 3 "nonmemory_operand" ""))] + "" + " +{ + int start_bit = INTVAL (operands[2]); + int width = INTVAL (operands[1]); + HOST_WIDE_INT mask = (((HOST_WIDE_INT)1) << width) - 1; + rtx target, subtarget; + + target = operands[0]; + /* Avoid using a subreg as a subtarget, and avoid writing a paradoxical + subreg as the final target. */ + if (GET_CODE (target) == SUBREG) + { + subtarget = gen_reg_rtx (SImode); + if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (target))) + < GET_MODE_SIZE (SImode)) + target = SUBREG_REG (target); + } + else + subtarget = target; + + if (GET_CODE (operands[3]) == CONST_INT) + { + /* Since we are inserting a known constant, we may be able to + reduce the number of bits that we have to clear so that + the mask becomes simple. */ + /* ??? This code does not check to see if the new mask is actually + simpler. It may not be. */ + rtx op1 = gen_reg_rtx (SImode); + /* ??? Truncate operand3 to fit in the bitfield. See comment before + start of this pattern. */ + HOST_WIDE_INT op3_value = mask & INTVAL (operands[3]); + HOST_WIDE_INT mask2 = ((mask & ~op3_value) << start_bit); + + emit_insn (gen_andsi3 (op1, operands[0], GEN_INT (~mask2))); + emit_insn (gen_iorsi3 (subtarget, op1, + GEN_INT (op3_value << start_bit))); + } + else if (start_bit == 0 + && ! (const_ok_for_arm (mask) + || const_ok_for_arm (~mask))) + { + /* A Trick, since we are setting the bottom bits in the word, + we can shift operand[3] up, operand[0] down, OR them together + and rotate the result back again. This takes 3 insns, and + the third might be mergable into another op. */ + /* The shift up copes with the possibility that operand[3] is + wider than the bitfield. */ + rtx op0 = gen_reg_rtx (SImode); + rtx op1 = gen_reg_rtx (SImode); + + emit_insn (gen_ashlsi3 (op0, operands[3], GEN_INT (32 - width))); + emit_insn (gen_iorsi3 (op1, gen_rtx (LSHIFTRT, SImode, operands[0], + operands[1]), + op0)); + emit_insn (gen_rotlsi3 (subtarget, op1, operands[1])); + } + else if ((width + start_bit == 32) + && ! (const_ok_for_arm (mask) + || const_ok_for_arm (~mask))) + { + /* Similar trick, but slightly less efficient. */ + + rtx op0 = gen_reg_rtx (SImode); + rtx op1 = gen_reg_rtx (SImode); + + emit_insn (gen_ashlsi3 (op0, operands[3], GEN_INT (32 - width))); + emit_insn (gen_ashlsi3 (op1, operands[0], operands[1])); + emit_insn (gen_iorsi3 (subtarget, + gen_rtx (LSHIFTRT, SImode, op1, + operands[1]), op0)); + } + else + { + rtx op0 = GEN_INT (mask); + rtx op1 = gen_reg_rtx (SImode); + rtx op2 = gen_reg_rtx (SImode); + + if (! (const_ok_for_arm (mask) || const_ok_for_arm (~mask))) + { + rtx tmp = gen_reg_rtx (SImode); + + emit_insn (gen_movsi (tmp, op0)); + op0 = tmp; + } + + /* Mask out any bits in operand[3] that are not needed. */ + emit_insn (gen_andsi3 (op1, operands[3], op0)); + + if (GET_CODE (op0) == CONST_INT + && (const_ok_for_arm (mask << start_bit) + || const_ok_for_arm (~ (mask << start_bit)))) + { + op0 = GEN_INT (~(mask << start_bit)); + emit_insn (gen_andsi3 (op2, operands[0], op0)); + } + else + { + if (GET_CODE (op0) == CONST_INT) + { + rtx tmp = gen_reg_rtx (SImode); + + emit_insn (gen_movsi (tmp, op0)); + op0 = tmp; + } + + if (start_bit != 0) + op0 = gen_rtx (ASHIFT, SImode, op0, operands[2]); + + emit_insn (gen_andsi_notsi_si (op2, operands[0], op0)); + } + + if (start_bit != 0) + op1 = gen_rtx (ASHIFT, SImode, op1, operands[2]); + + emit_insn (gen_iorsi3 (subtarget, op1, op2)); + } + + if (subtarget != target) + { + /* If TARGET is still a SUBREG, then it must be wider than a word, + so we must be careful only to set the subword we were asked to. */ + if (GET_CODE (target) == SUBREG) + emit_move_insn (target, subtarget); + else + emit_move_insn (target, gen_lowpart (GET_MODE (target), subtarget)); + } + + DONE; +} +") + +;; constants for op 2 will never be given to these patterns. +(define_insn "*anddi_notdi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (and:DI (not:DI (match_operand:DI 2 "s_register_operand" "r,0")) + (match_operand:DI 1 "s_register_operand" "0,r")))] + "" + "bic%?\\t%Q0, %Q1, %Q2\;bic%?\\t%R0, %R1, %R2" +[(set_attr "length" "8")]) + +(define_insn "*anddi_notzesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (and:DI (not:DI (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r"))) + (match_operand:DI 1 "s_register_operand" "0,?r")))] + "" + "@ + bic%?\\t%Q0, %Q1, %2 + bic%?\\t%Q0, %Q1, %2\;mov%?\\t%R0, %R1" +[(set_attr "length" "4,8")]) + +(define_insn "*anddi_notsesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (and:DI (not:DI (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r"))) + (match_operand:DI 1 "s_register_operand" "?r,0")))] + "" + "bic%?\\t%Q0, %Q1, %2\;bic%?\\t%R0, %R1, %2, asr #31" +[(set_attr "length" "8")]) + +(define_insn "andsi_notsi_si" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (and:SI (not:SI (match_operand:SI 2 "s_register_operand" "r")) + (match_operand:SI 1 "s_register_operand" "r")))] + "" + "bic%?\\t%0, %1, %2") + +(define_insn "andsi_not_shiftsi_si" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (and:SI (not:SI (match_operator:SI 4 "shift_operator" + [(match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 3 "arm_rhs_operand" "rM")])) + (match_operand:SI 1 "s_register_operand" "r")))] + "" + "bic%?\\t%0, %1, %2%S4") + +(define_insn "*andsi_notsi_si_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (and:SI (not:SI (match_operand:SI 2 "s_register_operand" "r")) + (match_operand:SI 1 "s_register_operand" "r")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (and:SI (not:SI (match_dup 2)) (match_dup 1)))] + "" + "bic%?s\\t%0, %1, %2" +[(set_attr "conds" "set")]) + +(define_insn "*andsi_notsi_si_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (and:SI (not:SI (match_operand:SI 2 "s_register_operand" "r")) + (match_operand:SI 1 "s_register_operand" "r")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "" + "bic%?s\\t%0, %1, %2" +[(set_attr "conds" "set")]) + +(define_insn "iordi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r") + (ior:DI (match_operand:DI 1 "s_register_operand" "%0") + (match_operand:DI 2 "s_register_operand" "r")))] + "" + "orr%?\\t%Q0, %Q1, %Q2\;orr%?\\t%R0, %R1, %R2" +[(set_attr "length" "8")]) + +(define_insn "*iordi_zesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (ior:DI (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "0,?r")))] + "" + "@ + orr%?\\t%Q0, %Q1, %2 + orr%?\\t%Q0, %Q1, %2\;mov%?\\t%R0, %R1" +[(set_attr "length" "4,8")]) + +(define_insn "*iordi_sesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (ior:DI (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "?r,0")))] + "" + "orr%?\\t%Q0, %Q1, %2\;orr%?\\t%R0, %R1, %2, asr #31" +[(set_attr "length" "8")]) + +(define_expand "iorsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (ior:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "reg_or_int_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT) + { + arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0], + operands[1], + (reload_in_progress || reload_completed + ? 0 : preserve_subexpressions_p ())); + DONE; + } +") + +(define_insn "*iorsi3_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (ior:SI (match_operand:SI 1 "s_register_operand" "r,r") + (match_operand:SI 2 "reg_or_int_operand" "rI,?n")))] + "" + "@ + orr%?\\t%0, %1, %2 + #" +[(set_attr "length" "4,16")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (ior:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "const_int_operand" "")))] + "! const_ok_for_arm (INTVAL (operands[2]))" + [(clobber (const_int 0))] + " + arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0], + operands[1], 0); + DONE; +") + +(define_insn "*iorsi3_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (ior:SI (match_operand:SI 1 "s_register_operand" "%r") + (match_operand:SI 2 "arm_rhs_operand" "rI")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (ior:SI (match_dup 1) (match_dup 2)))] + "" + "orr%?s\\t%0, %1, %2" +[(set_attr "conds" "set")]) + +(define_insn "*iorsi3_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (ior:SI (match_operand:SI 1 "s_register_operand" "%r") + (match_operand:SI 2 "arm_rhs_operand" "rI")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "" + "orr%?s\\t%0, %1, %2" +[(set_attr "conds" "set")]) + +(define_insn "xordi3" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (xor:DI (match_operand:DI 1 "s_register_operand" "%0,0") + (match_operand:DI 2 "s_register_operand" "r,0")))] + "" + "eor%?\\t%Q0, %Q1, %Q2\;eor%?\\t%R0, %R1, %R2" +[(set_attr "length" "8")]) + +(define_insn "*xordi_zesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (xor:DI (zero_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "0,?r")))] + "" + "@ + eor%?\\t%Q0, %Q1, %2 + eor%?\\t%Q0, %Q1, %2\;mov%?\\t%R0, %R1" +[(set_attr "length" "4,8")]) + +(define_insn "*xordi_sesidi_di" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (xor:DI (sign_extend:DI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:DI 1 "s_register_operand" "?r,0")))] + "" + "eor%?\\t%Q0, %Q1, %2\;eor%?\\t%R0, %R1, %2, asr #31" +[(set_attr "length" "8")]) + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (xor:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rI")))] + "" + "eor%?\\t%0, %1, %2") + +(define_insn "*xorsi3_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (xor:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rI")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (xor:SI (match_dup 1) (match_dup 2)))] + "" + "eor%?s\\t%0, %1, %2" +[(set_attr "conds" "set")]) + +(define_insn "*xorsi3_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (xor:SI (match_operand:SI 0 "s_register_operand" "r") + (match_operand:SI 1 "arm_rhs_operand" "rI")) + (const_int 0)))] + "" + "teq%?\\t%0, %1" +[(set_attr "conds" "set")]) + +;; by splitting (IOR (AND (NOT A) (NOT B)) C) as D = AND (IOR A B) (NOT C), +;; (NOT D) we can sometimes merge the final NOT into one of the following +;; insns + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "=r") + (ior:SI (and:SI (not:SI (match_operand:SI 1 "s_register_operand" "r")) + (not:SI (match_operand:SI 2 "arm_rhs_operand" "rI"))) + (match_operand:SI 3 "arm_rhs_operand" "rI"))) + (clobber (match_operand:SI 4 "s_register_operand" "=r"))] + "" + [(set (match_dup 4) (and:SI (ior:SI (match_dup 1) (match_dup 2)) + (not:SI (match_dup 3)))) + (set (match_dup 0) (not:SI (match_dup 4)))] + "" +) + +(define_insn "*andsi_iorsi3_notsi" + [(set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r") + (and:SI (ior:SI (match_operand:SI 1 "s_register_operand" "r,r,0") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")) + (not:SI (match_operand:SI 3 "arm_rhs_operand" "rI,rI,rI"))))] + "" + "orr%?\\t%0, %1, %2\;bic%?\\t%0, %0, %3" +[(set_attr "length" "8")]) + + + +;; Minimum and maximum insns + +(define_insn "smaxsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (smax:SI (match_operand:SI 1 "s_register_operand" "0,r,?r") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) + (clobber (reg:CC 24))] + "" + "@ + cmp\\t%1, %2\;movlt\\t%0, %2 + cmp\\t%1, %2\;movge\\t%0, %1 + cmp\\t%1, %2\;movge\\t%0, %1\;movlt\\t%0, %2" +[(set_attr "conds" "clob") + (set_attr "length" "8,8,12")]) + +(define_insn "sminsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (smin:SI (match_operand:SI 1 "s_register_operand" "0,r,?r") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) + (clobber (reg:CC 24))] + "" + "@ + cmp\\t%1, %2\;movge\\t%0, %2 + cmp\\t%1, %2\;movlt\\t%0, %1 + cmp\\t%1, %2\;movlt\\t%0, %1\;movge\\t%0, %2" +[(set_attr "conds" "clob") + (set_attr "length" "8,8,12")]) + +(define_insn "umaxsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (umax:SI (match_operand:SI 1 "s_register_operand" "0,r,?r") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) + (clobber (reg:CC 24))] + "" + "@ + cmp\\t%1, %2\;movcc\\t%0, %2 + cmp\\t%1, %2\;movcs\\t%0, %1 + cmp\\t%1, %2\;movcs\\t%0, %1\;movcc\\t%0, %2" +[(set_attr "conds" "clob") + (set_attr "length" "8,8,12")]) + +(define_insn "uminsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (umin:SI (match_operand:SI 1 "s_register_operand" "0,r,?r") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) + (clobber (reg:CC 24))] + "" + "@ + cmp\\t%1, %2\;movcs\\t%0, %2 + cmp\\t%1, %2\;movcc\\t%0, %1 + cmp\\t%1, %2\;movcc\\t%0, %1\;movcs\\t%0, %2" +[(set_attr "conds" "clob") + (set_attr "length" "8,8,12")]) + +(define_insn "*store_minmaxsi" + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operator:SI 3 "minmax_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "s_register_operand" "r")])) + (clobber (reg:CC 24))] + "" + "* + operands[3] = gen_rtx (minmax_code (operands[3]), SImode, operands[1], + operands[2]); + output_asm_insn (\"cmp\\t%1, %2\", operands); + output_asm_insn (\"str%d3\\t%1, %0\", operands); + output_asm_insn (\"str%D3\\t%2, %0\", operands); + return \"\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "12") + (set_attr "type" "store1")]) + +; Reject the frame pointer in operand[1], since reloading this after +; it has been eliminated can cause carnage. +(define_insn "*minmax_arithsi" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (match_operator:SI 4 "shiftable_operator" + [(match_operator:SI 5 "minmax_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_rhs_operand" "rI,rI")]) + (match_operand:SI 1 "s_register_operand" "0,?r")])) + (clobber (reg:CC 24))] + "GET_CODE (operands[1]) != REG + || (REGNO(operands[1]) != FRAME_POINTER_REGNUM + && REGNO(operands[1]) != ARG_POINTER_REGNUM)" + "* +{ + enum rtx_code code = GET_CODE (operands[4]); + + operands[5] = gen_rtx (minmax_code (operands[5]), SImode, operands[2], + operands[3]); + output_asm_insn (\"cmp\\t%2, %3\", operands); + output_asm_insn (\"%i4%d5\\t%0, %1, %2\", operands); + if (which_alternative != 0 || operands[3] != const0_rtx + || (code != PLUS && code != MINUS && code != IOR && code != XOR)) + output_asm_insn (\"%i4%D5\\t%0, %1, %3\", operands); + return \"\"; +} +" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + + +;; Shift and rotation insns + +(define_expand "ashlsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (ashift:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "arm_rhs_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT + && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31) + { + emit_insn (gen_movsi (operands[0], const0_rtx)); + DONE; + } +") + +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (ashiftrt:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "arm_rhs_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT + && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31) + operands[2] = GEN_INT (31); +") + +(define_expand "lshrsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (lshiftrt:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "arm_rhs_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT + && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31) + { + emit_insn (gen_movsi (operands[0], const0_rtx)); + DONE; + } +") + +(define_expand "rotlsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (rotatert:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "reg_or_int_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT) + operands[2] = GEN_INT ((32 - INTVAL (operands[2])) % 32); + else + { + rtx reg = gen_reg_rtx (SImode); + emit_insn (gen_subsi3 (reg, GEN_INT (32), operands[2])); + operands[2] = reg; + } +") + +(define_expand "rotrsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (rotatert:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "arm_rhs_operand" "")))] + "" + " + if (GET_CODE (operands[2]) == CONST_INT + && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31) + operands[2] = GEN_INT (INTVAL (operands[2]) % 32); +") + +(define_insn "*shiftsi3" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "reg_or_int_operand" "rM")]))] + "" + "mov%?\\t%0, %1%S3") + +(define_insn "*shiftsi3_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")]) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (match_op_dup 3 [(match_dup 1) (match_dup 2)]))] + "" + "mov%?s\\t%0, %1%S3" +[(set_attr "conds" "set")]) + +(define_insn "*shiftsi3_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")]) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "" + "mov%?s\\t%0, %1%S3" +[(set_attr "conds" "set")]) + +(define_insn "*notsi_shiftsi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (not:SI (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")])))] + "" + "mvn%?\\t%0, %1%S3") + +(define_insn "*notsi_shiftsi_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (not:SI (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")])) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (not:SI (match_op_dup 3 [(match_dup 1) (match_dup 2)])))] + "" + "mvn%?s\\t%0, %1%S3" +[(set_attr "conds" "set")]) + +(define_insn "*not_shiftsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (not:SI (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")])) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "" + "mvn%?s\\t%0, %1%S3" +[(set_attr "conds" "set")]) + + +;; Unary arithmetic insns + +(define_insn "negdi2" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (neg:DI (match_operand:DI 1 "s_register_operand" "?r,0")))] + "" + "rsbs\\t%Q0, %Q1, #0\;rsc\\t%R0, %R1, #0" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "negsi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (neg:SI (match_operand:SI 1 "s_register_operand" "r")))] + "" + "rsb%?\\t%0, %1, #0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (neg:SF (match_operand:SF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "mnf%?s\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "negdf2" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (neg:DF (match_operand:DF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "mnf%?d\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "*negdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (neg:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "mnf%?d\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "negxf2" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (neg:XF (match_operand:XF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "mnf%?e\\t%0, %1" +[(set_attr "type" "ffarith")]) + +;; abssi2 doesn't really clobber the condition codes if a different register +;; is being set. To keep things simple, assume during rtl manipulations that +;; it does, but tell the final scan operator the truth. Similarly for +;; (neg (abs...)) + +(define_insn "abssi2" + [(set (match_operand:SI 0 "s_register_operand" "=r,&r") + (abs:SI (match_operand:SI 1 "s_register_operand" "0,r"))) + (clobber (reg:CC 24))] + "" + "@ + cmp\\t%0, #0\;rsblt\\t%0, %0, #0 + eor%?\\t%0, %1, %1, asr #31\;sub%?\\t%0, %0, %1, asr #31" +[(set_attr "conds" "clob,*") + (set_attr "length" "8")]) + +(define_insn "*neg_abssi2" + [(set (match_operand:SI 0 "s_register_operand" "=r,&r") + (neg:SI (abs:SI (match_operand:SI 1 "s_register_operand" "0,r")))) + (clobber (reg:CC 24))] + "" + "@ + cmp\\t%0, #0\;rsbgt\\t%0, %0, #0 + eor%?\\t%0, %1, %1, asr #31\;rsb%?\\t%0, %0, %1, asr #31" +[(set_attr "conds" "clob,*") + (set_attr "length" "8")]) + +(define_insn "abssf2" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (abs:SF (match_operand:SF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "abs%?s\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "absdf2" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (abs:DF (match_operand:DF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "abs%?d\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "*absdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (abs:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "abs%?d\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "absxf2" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (abs:XF (match_operand:XF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "abs%?e\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "sqrtsf2" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (sqrt:SF (match_operand:SF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "sqt%?s\\t%0, %1" +[(set_attr "type" "float_em")]) + +(define_insn "sqrtdf2" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (sqrt:DF (match_operand:DF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "sqt%?d\\t%0, %1" +[(set_attr "type" "float_em")]) + +(define_insn "*sqrtdf_esfdf" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (sqrt:DF (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "sqt%?d\\t%0, %1" +[(set_attr "type" "float_em")]) + +(define_insn "sqrtxf2" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (sqrt:XF (match_operand:XF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "sqt%?e\\t%0, %1" +[(set_attr "type" "float_em")]) + +;; SIN COS TAN and family are always emulated, so it's probably better +;; to always call a library function. +;(define_insn "sinsf2" +; [(set (match_operand:SF 0 "s_register_operand" "=f") +; (unspec:SF [(match_operand:SF 1 "s_register_operand" "f")] 0))] +; "TARGET_HARD_FLOAT" +; "sin%?s\\t%0, %1" +;[(set_attr "type" "float_em")]) +; +;(define_insn "sindf2" +; [(set (match_operand:DF 0 "s_register_operand" "=f") +; (unspec:DF [(match_operand:DF 1 "s_register_operand" "f")] 0))] +; "TARGET_HARD_FLOAT" +; "sin%?d\\t%0, %1" +;[(set_attr "type" "float_em")]) +; +;(define_insn "*sindf_esfdf" +; [(set (match_operand:DF 0 "s_register_operand" "=f") +; (unspec:DF [(float_extend:DF +; (match_operand:SF 1 "s_register_operand" "f"))] 0))] +; "TARGET_HARD_FLOAT" +; "sin%?d\\t%0, %1" +;[(set_attr "type" "float_em")]) +; +;(define_insn "sinxf2" +; [(set (match_operand:XF 0 "s_register_operand" "=f") +; (unspec:XF [(match_operand:XF 1 "s_register_operand" "f")] 0))] +; "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" +; "sin%?e\\t%0, %1" +;[(set_attr "type" "float_em")]) +; +;(define_insn "cossf2" +; [(set (match_operand:SF 0 "s_register_operand" "=f") +; (unspec:SF [(match_operand:SF 1 "s_register_operand" "f")] 1))] +; "TARGET_HARD_FLOAT" +; "cos%?s\\t%0, %1" +;[(set_attr "type" "float_em")]) +; +;(define_insn "cosdf2" +; [(set (match_operand:DF 0 "s_register_operand" "=f") +; (unspec:DF [(match_operand:DF 1 "s_register_operand" "f")] 1))] +; "TARGET_HARD_FLOAT" +; "cos%?d\\t%0, %1" +;[(set_attr "type" "float_em")]) +; +;(define_insn "*cosdf_esfdf" +; [(set (match_operand:DF 0 "s_register_operand" "=f") +; (unspec:DF [(float_extend:DF +; (match_operand:SF 1 "s_register_operand" "f"))] 1))] +; "TARGET_HARD_FLOAT" +; "cos%?d\\t%0, %1" +;[(set_attr "type" "float_em")]) +; +;(define_insn "cosxf2" +; [(set (match_operand:XF 0 "s_register_operand" "=f") +; (unspec:XF [(match_operand:XF 1 "s_register_operand" "f")] 1))] +; "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" +; "cos%?e\\t%0, %1" +;[(set_attr "type" "float_em")]) + +(define_insn "one_cmpldi2" + [(set (match_operand:DI 0 "s_register_operand" "=&r,&r") + (not:DI (match_operand:DI 1 "s_register_operand" "?r,0")))] + "" + "mvn%?\\t%Q0, %Q1\;mvn%?\\t%R0, %R1" +[(set_attr "length" "8")]) + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (not:SI (match_operand:SI 1 "s_register_operand" "r")))] + "" + "mvn%?\\t%0, %1") + +(define_insn "*notsi_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (not:SI (match_operand:SI 1 "s_register_operand" "r")) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (not:SI (match_dup 1)))] + "" + "mvn%?s\\t%0, %1" +[(set_attr "conds" "set")]) + +(define_insn "*notsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (not:SI (match_operand:SI 1 "s_register_operand" "r")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "" + "mvn%?s\\t%0, %1" +[(set_attr "conds" "set")]) + +;; Fixed <--> Floating conversion insns + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (float:SF (match_operand:SI 1 "s_register_operand" "r")))] + "TARGET_HARD_FLOAT" + "flt%?s\\t%0, %1" +[(set_attr "type" "r_2_f")]) + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (float:DF (match_operand:SI 1 "s_register_operand" "r")))] + "TARGET_HARD_FLOAT" + "flt%?d\\t%0, %1" +[(set_attr "type" "r_2_f")]) + +(define_insn "floatsixf2" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (float:XF (match_operand:SI 1 "s_register_operand" "r")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "flt%?e\\t%0, %1" +[(set_attr "type" "r_2_f")]) + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (fix:SI (match_operand:SF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "fix%?z\\t%0, %1" +[(set_attr "type" "f_2_r")]) + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (fix:SI (match_operand:DF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "fix%?z\\t%0, %1" +[(set_attr "type" "f_2_r")]) + +(define_insn "fix_truncxfsi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (fix:SI (match_operand:XF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "fix%?z\\t%0, %1" +[(set_attr "type" "f_2_r")]) + +;; Truncation insns + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (float_truncate:SF + (match_operand:DF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "mvf%?s\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "truncxfsf2" + [(set (match_operand:SF 0 "s_register_operand" "=f") + (float_truncate:SF + (match_operand:XF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "mvf%?s\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "truncxfdf2" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (float_truncate:DF + (match_operand:XF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "mvf%?d\\t%0, %1" +[(set_attr "type" "ffarith")]) + +;; Zero and sign extension instructions. + +(define_insn "zero_extendsidi2" + [(set (match_operand:DI 0 "s_register_operand" "=r") + (zero_extend:DI (match_operand:SI 1 "s_register_operand" "r")))] + "" + "* + if (REGNO (operands[1]) != REGNO (operands[0]) + (WORDS_BIG_ENDIAN ? 1 : 0)) + output_asm_insn (\"mov%?\\t%Q0, %1\", operands); + return \"mov%?\\t%R0, #0\"; +" +[(set_attr "length" "8")]) + +(define_insn "zero_extendqidi2" + [(set (match_operand:DI 0 "s_register_operand" "=r,r") + (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] + "" + "@ + and%?\\t%Q0, %1, #255\;mov%?\\t%R0, #0 + ldr%?b\\t%Q0, %1\;mov%?\\t%R0, #0" +[(set_attr "length" "8") + (set_attr "type" "*,load")]) + +(define_insn "extendsidi2" + [(set (match_operand:DI 0 "s_register_operand" "=r") + (sign_extend:DI (match_operand:SI 1 "s_register_operand" "r")))] + "" + "* + if (REGNO (operands[1]) != REGNO (operands[0]) + (WORDS_BIG_ENDIAN ? 1 : 0)) + output_asm_insn (\"mov%?\\t%Q0, %1\", operands); + return \"mov%?\\t%R0, %Q0, asr #31\"; +" +[(set_attr "length" "8")]) + +(define_expand "zero_extendhisi2" + [(set (match_dup 2) (ashift:SI (match_operand:HI 1 "nonimmediate_operand" "") + (const_int 16))) + (set (match_operand:SI 0 "s_register_operand" "") + (lshiftrt:SI (match_dup 2) (const_int 16)))] + "" + " +{ + if (arm_arch4 && GET_CODE (operands[1]) == MEM) + { + /* Note: We do not have to worry about TARGET_SHORT_BY_BYTES + here because the insn below will generate an LDRH instruction + rather than an LDR instruction, so we cannot get an unaligned + word access. */ + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_ZERO_EXTEND (SImode, operands[1]))); + DONE; + } + if (TARGET_SHORT_BY_BYTES && GET_CODE (operands[1]) == MEM) + { + emit_insn (gen_movhi_bytes (operands[0], operands[1])); + DONE; + } + if (! s_register_operand (operands[1], HImode)) + operands[1] = copy_to_mode_reg (HImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); +}") + +(define_insn "*zero_extendhisi_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + "arm_arch4" + "ldr%?h\\t%0, %1" +[(set_attr "type" "load")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (zero_extend:SI (match_operand:HI 1 "alignable_memory_operand" ""))) + (clobber (match_operand:SI 2 "s_register_operand" ""))] + "! arm_arch4" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (lshiftrt:SI (match_dup 2) (const_int 16)))] + " +{ + if ((operands[1] = gen_rotated_half_load (operands[1])) == NULL) + FAIL; +}") + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operator:SI 3 "shiftable_operator" + [(zero_extend:SI (match_operand:HI 1 "alignable_memory_operand" "")) + (match_operand:SI 4 "s_register_operand" "")])) + (clobber (match_operand:SI 2 "s_register_operand" ""))] + "! arm_arch4" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) + (match_op_dup 3 + [(lshiftrt:SI (match_dup 2) (const_int 16)) (match_dup 4)]))] + " +{ + if ((operands[1] = gen_rotated_half_load (operands[1])) == NULL) + FAIL; +}") + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (zero_extend:SI + (match_operand:QI 1 "nonimmediate_operand" "r,m")))] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + emit_insn (gen_andsi3 (operands[0], gen_lowpart (SImode, operands[1]), + GEN_INT (255))); + DONE; + } +") + +(define_insn "*load_extendqisi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + "" + "ldr%?b\\t%0, %1\\t%@ zero_extendqisi2" +[(set_attr "type" "load")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (zero_extend:SI (subreg:QI (match_operand:SI 1 "" "") 0))) + (clobber (match_operand:SI 2 "s_register_operand" ""))] + "GET_CODE (operands[1]) != MEM" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (and:SI (match_dup 2) (const_int 255)))] + "") + +(define_insn "*compareqi_eq0" + [(set (reg:CC_Z 24) + (compare:CC_Z (match_operand:QI 0 "s_register_operand" "r") + (const_int 0)))] + "" + "tst\\t%0, #255" +[(set_attr "conds" "set")]) + +(define_expand "extendhisi2" + [(set (match_dup 2) + (ashift:SI (match_operand:HI 1 "nonimmediate_operand" "") + (const_int 16))) + (set (match_operand:SI 0 "s_register_operand" "") + (ashiftrt:SI (match_dup 2) + (const_int 16)))] + "" + " +{ + if (arm_arch4 && GET_CODE (operands[1]) == MEM) + { + /* Note: We do not have to worry about TARGET_SHORT_BY_BYTES + here because the insn below will generate an LDRH instruction + rather than an LDR instruction, so we cannot get an unaligned + word access. */ + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_SIGN_EXTEND (SImode, operands[1]))); + DONE; + } + + if (TARGET_SHORT_BY_BYTES && GET_CODE (operands[1]) == MEM) + { + emit_insn (gen_extendhisi2_mem (operands[0], operands[1])); + DONE; + } + if (! s_register_operand (operands[1], HImode)) + operands[1] = copy_to_mode_reg (HImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); +}") + +(define_expand "extendhisi2_mem" + [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" ""))) + (set (match_dup 3) + (zero_extend:SI (match_dup 7))) + (set (match_dup 6) (ashift:SI (match_dup 4) (const_int 24))) + (set (match_operand:SI 0 "" "") + (ior:SI (ashiftrt:SI (match_dup 6) (const_int 16)) (match_dup 5)))] + "" + " +{ + rtx mem1, mem2; + rtx addr = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); + + mem1 = gen_rtx (MEM, QImode, addr); + MEM_COPY_ATTRIBUTES (mem1, operands[1]); + RTX_UNCHANGING_P (mem1) = RTX_UNCHANGING_P (operands[1]); + mem2 = gen_rtx (MEM, QImode, plus_constant (addr, 1)); + MEM_COPY_ATTRIBUTES (mem2, operands[1]); + RTX_UNCHANGING_P (mem2) = RTX_UNCHANGING_P (operands[1]); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = mem1; + operands[2] = gen_reg_rtx (SImode); + operands[3] = gen_reg_rtx (SImode); + operands[6] = gen_reg_rtx (SImode); + operands[7] = mem2; + + if (BYTES_BIG_ENDIAN) + { + operands[4] = operands[2]; + operands[5] = operands[3]; + } + else + { + operands[4] = operands[3]; + operands[5] = operands[2]; + } +} +") + +(define_insn "*extendhisi_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + "arm_arch4" + "ldr%?sh\\t%0, %1" +[(set_attr "type" "load")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (sign_extend:SI (match_operand:HI 1 "alignable_memory_operand" ""))) + (clobber (match_operand:SI 2 "s_register_operand" ""))] + "! arm_arch4" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (ashiftrt:SI (match_dup 2) (const_int 16)))] + " +{ + if ((operands[1] = gen_rotated_half_load (operands[1])) == NULL) + FAIL; +}") + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operator:SI 3 "shiftable_operator" + [(sign_extend:SI (match_operand:HI 1 "alignable_memory_operand" "")) + (match_operand:SI 4 "s_register_operand" "")])) + (clobber (match_operand:SI 2 "s_register_operand" ""))] + "! arm_arch4" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) + (match_op_dup 3 + [(ashiftrt:SI (match_dup 2) (const_int 16)) (match_dup 4)]))] + " +{ + if ((operands[1] = gen_rotated_half_load (operands[1])) == NULL) + FAIL; +}") + +(define_expand "extendqihi2" + [(set (match_dup 2) + (ashift:SI (match_operand:QI 1 "general_operand" "") + (const_int 24))) + (set (match_operand:HI 0 "s_register_operand" "") + (ashiftrt:SI (match_dup 2) + (const_int 24)))] + "" + " +{ + if (arm_arch4 && GET_CODE (operands[1]) == MEM) + { + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (SIGN_EXTEND, HImode, operands[1]))); + DONE; + } + if (! s_register_operand (operands[1], QImode)) + operands[1] = copy_to_mode_reg (QImode, operands[1]); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); +}") + +; Rather than restricting all byte accesses to memory addresses that ldrsb +; can handle, we fix up the ones that ldrsb can't grok with a split. +(define_insn "*extendqihi_insn" + [(set (match_operand:HI 0 "s_register_operand" "=r") + (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))] + "arm_arch4" + "* + /* If the address is invalid, this will split the instruction into two. */ + if (bad_signed_byte_operand(operands[1], QImode)) + return \"#\"; + return \"ldr%?sb\\t%0, %1\"; +" +[(set_attr "type" "load") + (set_attr "length" "8")]) + +(define_split + [(set (match_operand:HI 0 "s_register_operand" "") + (sign_extend:HI (match_operand:QI 1 "bad_signed_byte_operand" "")))] + "arm_arch4 && reload_completed" + [(set (match_dup 3) (match_dup 1)) + (set (match_dup 0) (sign_extend:HI (match_dup 2)))] + " + { + HOST_WIDE_INT offset; + + operands[3] = gen_rtx (REG, SImode, REGNO (operands[0])); + operands[2] = gen_rtx (MEM, QImode, operands[3]); + MEM_COPY_ATTRIBUTES (operands[2], operands[1]); + RTX_UNCHANGING_P (operands[2]) = RTX_UNCHANGING_P (operands[1]); + operands[1] = XEXP (operands[1], 0); + if (GET_CODE (operands[1]) == PLUS + && GET_CODE (XEXP (operands[1], 1)) == CONST_INT + && ! (const_ok_for_arm (offset = INTVAL (XEXP (operands[1], 1))) + || const_ok_for_arm (-offset))) + { + HOST_WIDE_INT low = (offset > 0 + ? (offset & 0xff) : -((-offset) & 0xff)); + XEXP (operands[2], 0) = plus_constant (operands[3], low); + operands[1] = plus_constant (XEXP (operands[1], 0), offset - low); + } + /* Ensure the sum is in correct canonical form */ + else if (GET_CODE (operands[1]) == PLUS + && GET_CODE (XEXP (operands[1], 1)) != CONST_INT + && ! s_register_operand (XEXP (operands[1], 1), VOIDmode)) + operands[1] = gen_rtx (PLUS, GET_MODE (operands[1]), + XEXP (operands[1], 1), XEXP (operands[1], 0)); + } +") + +(define_expand "extendqisi2" + [(set (match_dup 2) + (ashift:SI (match_operand:QI 1 "general_operand" "") + (const_int 24))) + (set (match_operand:SI 0 "s_register_operand" "") + (ashiftrt:SI (match_dup 2) + (const_int 24)))] + "" + " +{ + if (arm_arch4 && GET_CODE (operands[1]) == MEM) + { + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (SIGN_EXTEND, SImode, operands[1]))); + DONE; + } + if (! s_register_operand (operands[1], QImode)) + operands[1] = copy_to_mode_reg (QImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); +}") + +; Rather than restricting all byte accesses to memory addresses that ldrsb +; can handle, we fix up the ones that ldrsb can't grok with a split. +(define_insn "*extendqisi_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + "arm_arch4" + "* + /* If the address is invalid, this will split the instruction into two. */ + if (bad_signed_byte_operand(operands[1], QImode)) + return \"#\"; + return \"ldr%?sb\\t%0, %1\"; +" +[(set_attr "type" "load") + (set_attr "length" "8")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (sign_extend:SI (match_operand:QI 1 "bad_signed_byte_operand" "")))] + "arm_arch4 && reload_completed" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 0) (sign_extend:SI (match_dup 2)))] + " + { + HOST_WIDE_INT offset; + + operands[2] = gen_rtx (MEM, QImode, operands[0]); + MEM_COPY_ATTRIBUTES (operands[2], operands[1]); + RTX_UNCHANGING_P (operands[2]) = RTX_UNCHANGING_P (operands[1]); + operands[1] = XEXP (operands[1], 0); + if (GET_CODE (operands[1]) == PLUS + && GET_CODE (XEXP (operands[1], 1)) == CONST_INT + && ! (const_ok_for_arm (offset = INTVAL (XEXP (operands[1], 1))) + || const_ok_for_arm (-offset))) + { + HOST_WIDE_INT low = (offset > 0 + ? (offset & 0xff) : -((-offset) & 0xff)); + XEXP (operands[2], 0) = plus_constant (operands[0], low); + operands[1] = plus_constant (XEXP (operands[1], 0), offset - low); + } + /* Ensure the sum is in correct canonical form */ + else if (GET_CODE (operands[1]) == PLUS + && GET_CODE (XEXP (operands[1], 1)) != CONST_INT + && ! s_register_operand (XEXP (operands[1], 1), VOIDmode)) + operands[1] = gen_rtx (PLUS, GET_MODE (operands[1]), + XEXP (operands[1], 1), XEXP (operands[1], 0)); + } +") + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "s_register_operand" "=f") + (float_extend:DF (match_operand:SF 1 "s_register_operand" "f")))] + "TARGET_HARD_FLOAT" + "mvf%?d\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "extendsfxf2" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (float_extend:XF (match_operand:SF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "mvf%?e\\t%0, %1" +[(set_attr "type" "ffarith")]) + +(define_insn "extenddfxf2" + [(set (match_operand:XF 0 "s_register_operand" "=f") + (float_extend:XF (match_operand:DF 1 "s_register_operand" "f")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "mvf%?e\\t%0, %1" +[(set_attr "type" "ffarith")]) + + +;; Move insns (including loads and stores) + +;; XXX Just some ideas about movti. +;; I don't think these are a good idea on the arm, there just aren't enough +;; registers +;;(define_expand "loadti" +;; [(set (match_operand:TI 0 "s_register_operand" "") +;; (mem:TI (match_operand:SI 1 "address_operand" "")))] +;; "" "") + +;;(define_expand "storeti" +;; [(set (mem:TI (match_operand:TI 0 "address_operand" "")) +;; (match_operand:TI 1 "s_register_operand" ""))] +;; "" "") + +;;(define_expand "movti" +;; [(set (match_operand:TI 0 "general_operand" "") +;; (match_operand:TI 1 "general_operand" ""))] +;; "" +;; " +;;{ +;; rtx insn; +;; +;; if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) +;; operands[1] = copy_to_reg (operands[1]); +;; if (GET_CODE (operands[0]) == MEM) +;; insn = gen_storeti (XEXP (operands[0], 0), operands[1]); +;; else if (GET_CODE (operands[1]) == MEM) +;; insn = gen_loadti (operands[0], XEXP (operands[1], 0)); +;; else +;; FAIL; +;; +;; emit_insn (insn); +;; DONE; +;;}") + +;; Recognise garbage generated above. + +;;(define_insn "" +;; [(set (match_operand:TI 0 "general_operand" "=r,r,r,<,>,m") +;; (match_operand:TI 1 "general_operand" "<,>,m,r,r,r"))] +;; "" +;; "* +;; { +;; register mem = (which_alternative < 3); +;; register char *template; +;; +;; operands[mem] = XEXP (operands[mem], 0); +;; switch (which_alternative) +;; { +;; case 0: template = \"ldmdb\\t%1!, %M0\"; break; +;; case 1: template = \"ldmia\\t%1!, %M0\"; break; +;; case 2: template = \"ldmia\\t%1, %M0\"; break; +;; case 3: template = \"stmdb\\t%0!, %M1\"; break; +;; case 4: template = \"stmia\\t%0!, %M1\"; break; +;; case 5: template = \"stmia\\t%0, %M1\"; break; +;; } +;; output_asm_insn (template, operands); +;; return \"\"; +;; }") + + +(define_insn "movdi" + [(set (match_operand:DI 0 "di_operand" "=r,r,o<>") + (match_operand:DI 1 "di_operand" "rIK,mi,r"))] + "" + "* + return (output_move_double (operands)); +" +[(set_attr "length" "8,8,8") + (set_attr "type" "*,load,store2")]) + +(define_expand "movsi" + [(set (match_operand:SI 0 "general_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "" + " + /* Everything except mem = const or mem = mem can be done easily */ + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (SImode, operands[1]); + /* CYGNUS LOCAL nickc */ + if (! ok_integer_or_other (operands[1])) + /* END CYGNUS LOCAL */ + { + arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0], + NULL_RTX, + (reload_in_progress || reload_completed ? 0 + : preserve_subexpressions_p ())); + DONE; + } + if (CONSTANT_P (operands[1]) && flag_pic) + operands[1] = legitimize_pic_address (operands[1], SImode, + ((reload_in_progress + || reload_completed) + ? operands[0] : 0)); +") + +(define_insn "*movsi_insn" + [(set (match_operand:SI 0 "general_operand" "=r,r,r,m") + (match_operand:SI 1 "general_operand" "rI,K,mi,r"))] + "register_operand (operands[0], SImode) + || register_operand (operands[1], SImode)" + "@ + mov%?\\t%0, %1 + mvn%?\\t%0, #%B1 + ldr%?\\t%0, %1 + str%?\\t%1, %0" +[(set_attr "type" "*,*,load,store1")]) + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "! (const_ok_for_arm (INTVAL (operands[1])) + || const_ok_for_arm (~INTVAL (operands[1])))" + [(clobber (const_int 0))] + " + arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0], + NULL_RTX, 0); + DONE; +") + +(define_expand "movaddr" + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operand:DI 1 "address_operand" ""))] + "" + "") + +(define_insn "*movaddr_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operand:DI 1 "address_operand" "p"))] + "reload_completed + && (GET_CODE (operands[1]) == LABEL_REF + || (GET_CODE (operands[1]) == CONST + && GET_CODE (XEXP (operands[1], 0)) == PLUS + && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF + && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT))" + "adr%?\\t%0, %a1") + +/* When generating pic, we need to load the symbol offset into a register. + So that the optimizer does not confuse this with a normal symbol load + we use an unspec. The offset will be loaded from a constant pool entry, + since that is the only type of relocation we can use. */ + +(define_insn "pic_load_addr" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (unspec:SI [(match_operand 1 "" "")] 3))] + "flag_pic" + "ldr%?\\t%0, %a1" + [(set_attr "type" "load")]) + +;; This variant is used for AOF assembly, since it needs to mention the +;; pic register in the rtl. +(define_expand "pic_load_addr_based" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (unspec:SI [(match_operand 1 "" "") (match_dup 2)] 3))] + "flag_pic" + "operands[2] = pic_offset_table_rtx;") + +(define_insn "*pic_load_addr_based_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (unspec:SI [(match_operand 1 "" "") + (match_operand 2 "s_register_operand" "r")] 3))] + "flag_pic && operands[2] == pic_offset_table_rtx" + "* +#ifdef AOF_ASSEMBLER + operands[1] = aof_pic_entry (operands[1]); +#endif + output_asm_insn (\"ldr%?\\t%0, %a1\", operands); + return \"\"; +" [(set_attr "type" "load")]) + +(define_insn "pic_add_dot_plus_eight" + [(set (pc) (label_ref (match_operand 0 "" ""))) + (set (match_operand 1 "register_operand" "+r") + (plus:SI (match_dup 1) (const (plus:SI (pc) (const_int 8)))))] + "flag_pic" + "add%?\\t%1, %|pc, %1") + +;; If copying one reg to another we can set the condition codes according to +;; its value. Such a move is common after a return from subroutine and the +;; result is being tested against zero. + +(define_insn "*movsi_compare0" + [(set (reg:CC 24) (compare:CC (match_operand:SI 1 "s_register_operand" "0,r") + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") (match_dup 1))] + "" + "@ + cmp%?\\t%0, #0 + sub%?s\\t%0, %1, #0" +[(set_attr "conds" "set")]) + +;; Subroutine to store a half word from a register into memory. +;; Operand 0 is the source register (HImode) +;; Operand 1 is the destination address in a register (SImode) + +;; In both this routine and the next, we must be careful not to spill +;; a memory address of reg+large_const into a separate PLUS insn, since this +;; can generate unrecognizable rtl. + +(define_expand "storehi" + [;; store the low byte + (set (match_operand 1 "" "") (match_dup 3)) + ;; extract the high byte + (set (match_dup 2) + (ashiftrt:SI (match_operand 0 "" "") (const_int 8))) + ;; store the high byte + (set (match_dup 4) (subreg:QI (match_dup 2) 0))] ;explicit subreg safe + "" + " +{ + rtx addr = XEXP (operands[1], 0); + enum rtx_code code = GET_CODE (addr); + + if ((code == PLUS && GET_CODE (XEXP (addr, 1)) != CONST_INT) + || code == MINUS) + addr = force_reg (SImode, addr); + + operands[4] = change_address (operands[1], QImode, plus_constant (addr, 1)); + operands[1] = change_address (operands[1], QImode, NULL_RTX); + operands[3] = gen_lowpart (QImode, operands[0]); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[2] = gen_reg_rtx (SImode); +} +") + +(define_expand "storehi_bigend" + [(set (match_dup 4) (match_dup 3)) + (set (match_dup 2) + (ashiftrt:SI (match_operand 0 "" "") (const_int 8))) + (set (match_operand 1 "" "") (subreg:QI (match_dup 2) 0))] + "" + " +{ + rtx addr = XEXP (operands[1], 0); + enum rtx_code code = GET_CODE (addr); + + if ((code == PLUS && GET_CODE (XEXP (addr, 1)) != CONST_INT) + || code == MINUS) + addr = force_reg (SImode, addr); + + operands[4] = change_address (operands[1], QImode, plus_constant (addr, 1)); + operands[1] = change_address (operands[1], QImode, NULL_RTX); + operands[3] = gen_lowpart (QImode, operands[0]); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[2] = gen_reg_rtx (SImode); +} +") + +;; Subroutine to store a half word integer constant into memory. +(define_expand "storeinthi" + [(set (match_operand 0 "" "") + (subreg:QI (match_operand 1 "" "") 0)) + (set (match_dup 3) (subreg:QI (match_dup 2) 0))] + "" + " +{ + HOST_WIDE_INT value = INTVAL (operands[1]); + rtx addr = XEXP (operands[0], 0); + enum rtx_code code = GET_CODE (addr); + + if ((code == PLUS && GET_CODE (XEXP (addr, 1)) != CONST_INT) + || code == MINUS) + addr = force_reg (SImode, addr); + + operands[1] = gen_reg_rtx (SImode); + if (BYTES_BIG_ENDIAN) + { + emit_insn (gen_movsi (operands[1], GEN_INT ((value >> 8) & 255))); + if ((value & 255) == ((value >> 8) & 255)) + operands[2] = operands[1]; + else + { + operands[2] = gen_reg_rtx (SImode); + emit_insn (gen_movsi (operands[2], GEN_INT (value & 255))); + } + } + else + { + emit_insn (gen_movsi (operands[1], GEN_INT (value & 255))); + if ((value & 255) == ((value >> 8) & 255)) + operands[2] = operands[1]; + else + { + operands[2] = gen_reg_rtx (SImode); + emit_insn (gen_movsi (operands[2], GEN_INT ((value >> 8) & 255))); + } + } + + operands[3] = change_address (operands[0], QImode, plus_constant (addr, 1)); + operands[0] = change_address (operands[0], QImode, NULL_RTX); +} +") + +(define_expand "storehi_single_op" + [(set (match_operand:HI 0 "memory_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "arm_arch4" + " + if (! s_register_operand (operands[1], HImode)) + operands[1] = copy_to_mode_reg (HImode, operands[1]); +") + +(define_expand "movhi" + [(set (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + " +{ + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) == MEM) + { + if (arm_arch4) + { + emit_insn (gen_storehi_single_op (operands[0], operands[1])); + DONE; + } + if (GET_CODE (operands[1]) == CONST_INT) + emit_insn (gen_storeinthi (operands[0], operands[1])); + else + { + if (GET_CODE (operands[1]) == MEM) + operands[1] = force_reg (HImode, operands[1]); + if (BYTES_BIG_ENDIAN) + emit_insn (gen_storehi_bigend (operands[1], operands[0])); + else + emit_insn (gen_storehi (operands[1], operands[0])); + } + DONE; + } + /* Sign extend a constant, and keep it in an SImode reg. */ + else if (GET_CODE (operands[1]) == CONST_INT) + { + rtx reg = gen_reg_rtx (SImode); + HOST_WIDE_INT val = INTVAL (operands[1]) & 0xffff; + + /* If the constant is already valid, leave it alone. */ + if (! const_ok_for_arm (val)) + { + /* If setting all the top bits will make the constant + loadable in a single instruction, then set them. + Otherwise, sign extend the number. */ + + if (const_ok_for_arm (~ (val | ~0xffff))) + val |= ~0xffff; + else if (val & 0x8000) + val |= ~0xffff; + } + + emit_insn (gen_movsi (reg, GEN_INT (val))); + operands[1] = gen_rtx_SUBREG (HImode, reg, 0); + } + else if (! arm_arch4) + { + /* Note: We do not have to worry about TARGET_SHORT_BY_BYTES + for v4 and up architectures because LDRH instructions will + be used to access the HI values, and these cannot generate + unaligned word access faults in the MMU. */ + if (GET_CODE (operands[1]) == MEM) + { + if (TARGET_SHORT_BY_BYTES) + { + rtx base; + rtx offset = const0_rtx; + rtx reg = gen_reg_rtx (SImode); + + if ((GET_CODE (base = XEXP (operands[1], 0)) == REG + || (GET_CODE (base) == PLUS + && GET_CODE (offset = XEXP (base, 1)) == CONST_INT + && ((INTVAL(offset) & 1) != 1) + && GET_CODE (base = XEXP (base, 0)) == REG)) + && REGNO_POINTER_ALIGN (REGNO (base)) >= 4) + { + HOST_WIDE_INT new_offset = INTVAL (offset) & ~3; + rtx new; + + new = gen_rtx_MEM (SImode, + plus_constant (base, new_offset)); + MEM_COPY_ATTRIBUTES (new, operands[1]); + RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (operands[1]); + emit_insn (gen_movsi (reg, new)); + if (((INTVAL (offset) & 2) != 0) + ^ (BYTES_BIG_ENDIAN ? 1 : 0)) + { + rtx reg2 = gen_reg_rtx (SImode); + + emit_insn (gen_lshrsi3 (reg2, reg, GEN_INT (16))); + reg = reg2; + } + } + else + emit_insn (gen_movhi_bytes (reg, operands[1])); + + operands[1] = gen_lowpart (HImode, reg); + } + else if (BYTES_BIG_ENDIAN) + { + rtx base; + rtx offset = const0_rtx; + + if ((GET_CODE (base = XEXP (operands[1], 0)) == REG + || (GET_CODE (base) == PLUS + && GET_CODE (offset = XEXP (base, 1)) == CONST_INT + && GET_CODE (base = XEXP (base, 0)) == REG)) + && REGNO_POINTER_ALIGN (REGNO (base)) >= 4) + { + rtx reg = gen_reg_rtx (SImode); + rtx new; + + if ((INTVAL (offset) & 2) == 2) + { + HOST_WIDE_INT new_offset = INTVAL (offset) ^ 2; + new = gen_rtx_MEM (SImode, + plus_constant (base, new_offset)); + MEM_COPY_ATTRIBUTES (new, operands[1]); + RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (operands[1]); + emit_insn (gen_movsi (reg, new)); + } + else + { + new = gen_rtx_MEM (SImode, XEXP (operands[1], 0)); + MEM_COPY_ATTRIBUTES (new, operands[1]); + RTX_UNCHANGING_P (new) + = RTX_UNCHANGING_P (operands[1]); + emit_insn (gen_rotated_loadsi (reg, new)); + } + + operands[1] = gen_lowpart (HImode, reg); + } + else + { + emit_insn (gen_movhi_bigend (operands[0], operands[1])); + DONE; + } + } + } + } + } + /* Handle loading a large integer during reload */ + else if (GET_CODE (operands[1]) == CONST_INT + && ! const_ok_for_arm (INTVAL (operands[1])) + && ! const_ok_for_arm (~INTVAL (operands[1]))) + { + /* Writing a constant to memory needs a scratch, which should + be handled with SECONDARY_RELOADs. */ + if (GET_CODE (operands[0]) != REG) + abort (); + + operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0); + emit_insn (gen_movsi (operands[0], operands[1])); + DONE; + } +} +") + +(define_insn "rotated_loadsi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (rotate:SI (match_operand:SI 1 "offsettable_memory_operand" "o") + (const_int 16)))] + "! TARGET_SHORT_BY_BYTES" + "* +{ + rtx ops[2]; + + ops[0] = operands[0]; + ops[1] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 2)); + output_asm_insn (\"ldr%?\\t%0, %1\\t%@ load-rotate\", ops); + return \"\"; +}" +[(set_attr "type" "load")]) + +(define_expand "movhi_bytes" + [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" ""))) + (set (match_dup 3) + (zero_extend:SI (match_dup 6))) + (set (match_operand:SI 0 "" "") + (ior:SI (ashift:SI (match_dup 4) (const_int 8)) (match_dup 5)))] + "" + " +{ + rtx mem1, mem2; + rtx addr = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); + + mem1 = gen_rtx (MEM, QImode, addr); + MEM_COPY_ATTRIBUTES (mem1, operands[1]); + RTX_UNCHANGING_P (mem1) = RTX_UNCHANGING_P (operands[1]); + mem2 = gen_rtx (MEM, QImode, plus_constant (addr, 1)); + MEM_COPY_ATTRIBUTES (mem2, operands[1]); + RTX_UNCHANGING_P (mem2) = RTX_UNCHANGING_P (operands[1]); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = mem1; + operands[2] = gen_reg_rtx (SImode); + operands[3] = gen_reg_rtx (SImode); + operands[6] = mem2; + + if (BYTES_BIG_ENDIAN) + { + operands[4] = operands[2]; + operands[5] = operands[3]; + } + else + { + operands[4] = operands[3]; + operands[5] = operands[2]; + } +} +") + +(define_expand "movhi_bigend" + [(set (match_dup 2) + (rotate:SI (subreg:SI (match_operand:HI 1 "memory_operand" "") 0) + (const_int 16))) + (set (match_dup 3) + (ashiftrt:SI (match_dup 2) (const_int 16))) + (set (match_operand:HI 0 "s_register_operand" "") + (subreg:HI (match_dup 3) 0))] + "" + " + operands[2] = gen_reg_rtx (SImode); + operands[3] = gen_reg_rtx (SImode); +") + +;; Pattern to recognise insn generated default case above +;; CYGNUS LOCAL nickc: Store before load to avoid problem with reload. +(define_insn "*movhi_insn_arch4" + [(set (match_operand:HI 0 "general_operand" "=r,r,m,r") + (match_operand:HI 1 "general_operand" "rI,K,r,m"))] + "arm_arch4 + && ok_integer_or_other (operands[0]) + && ok_integer_or_other (operands[1])" ;; CYGNUS LOCAL nickc + "@ + mov%?\\t%0, %1\\t%@ movhi + mvn%?\\t%0, #%B1\\t%@ movhi + str%?h\\t%1, %0\\t%@ movhi ;; CYGNUS LOCAL nickc + ldr%?h\\t%0, %1\\t%@ movhi" ;; CYGNUS LOCAL nickc +[(set_attr "type" "*,*,store1,load")]) ;; CYGNUS LOCAL nickc +;; END CYGNUS LOCAL + +(define_insn "*movhi_insn_littleend" + [(set (match_operand:HI 0 "general_operand" "=r,r,r") + (match_operand:HI 1 "general_operand" "rI,K,m"))] + "! arm_arch4 + && ! BYTES_BIG_ENDIAN + && ! TARGET_SHORT_BY_BYTES + /* CYGNUS LOCAL nickc */ + && ok_integer_or_other (operands[1])" + ;; END CYGNUS LOCAL nickc + "@ + mov%?\\t%0, %1\\t%@ movhi + mvn%?\\t%0, #%B1\\t%@ movhi + ldr%?\\t%0, %1\\t%@ movhi" +[(set_attr "type" "*,*,load")]) + +(define_insn "*movhi_insn_bigend" + [(set (match_operand:HI 0 "s_register_operand" "=r,r,r") + (match_operand:HI 1 "general_operand" "rI,K,m"))] + "! arm_arch4 + && BYTES_BIG_ENDIAN + && ! TARGET_SHORT_BY_BYTES + /* CYGNUS LOCAL NICKC */ + && ok_integer_or_other (operands[1])" + ;; END CYGNUS LOCAL + "@ + mov%?\\t%0, %1\\t%@ movhi + mvn%?\\t%0, #%B1\\t%@ movhi + ldr%?\\t%0, %1\\t%@ movhi_bigend\;mov%?\\t%0, %0, asr #16" +[(set_attr "type" "*,*,load") + (set_attr "length" "4,4,8")]) + +(define_insn "*loadhi_si_bigend" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (rotate:SI (subreg:SI (match_operand:HI 1 "memory_operand" "m") 0) + (const_int 16)))] + "BYTES_BIG_ENDIAN + && ! TARGET_SHORT_BY_BYTES" + "ldr%?\\t%0, %1\\t%@ movhi_bigend" +[(set_attr "type" "load")]) + +(define_insn "*movhi_bytes" + [(set (match_operand:HI 0 "s_register_operand" "=r,r") + (match_operand:HI 1 "arm_rhs_operand" "rI,K"))] + "TARGET_SHORT_BY_BYTES" + "@ + mov%?\\t%0, %1\\t%@ movhi + mvn%?\\t%0, #%B1\\t%@ movhi") + + +(define_expand "reload_outhi" + [(parallel [(match_operand:HI 0 "reload_memory_operand" "=o") + (match_operand:HI 1 "s_register_operand" "r") + (match_operand:SI 2 "s_register_operand" "=&r")])] + "" + " + arm_reload_out_hi (operands); + DONE; +") + +(define_expand "reload_inhi" + [(parallel [(match_operand:HI 0 "s_register_operand" "=r") + (match_operand:HI 1 "reload_memory_operand" "o") + (match_operand:SI 2 "s_register_operand" "=&r")])] + "TARGET_SHORT_BY_BYTES" + " + arm_reload_in_hi (operands); + DONE; +") + +(define_expand "movqi" + [(set (match_operand:QI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" + " + /* Everything except mem = const or mem = mem can be done easily */ + + if (!(reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[1]) == CONST_INT) + { + rtx reg = gen_reg_rtx (SImode); + + emit_insn (gen_movsi (reg, operands[1])); + operands[1] = gen_rtx (SUBREG, QImode, reg, 0); + } + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (QImode, operands[1]); + } +") + + +(define_insn "*movqi_insn" + [(set (match_operand:QI 0 "general_operand" "=r,r,r,m") + (match_operand:QI 1 "general_operand" "rI,K,m,r"))] + "register_operand (operands[0], QImode) + || register_operand (operands[1], QImode)" + "@ + mov%?\\t%0, %1 + mvn%?\\t%0, #%B1 + ldr%?b\\t%0, %1 + str%?b\\t%1, %0" +[(set_attr "type" "*,*,load,store1")]) + +(define_expand "movsf" + [(set (match_operand:SF 0 "general_operand" "") + (match_operand:SF 1 "general_operand" ""))] + "" + " + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (SFmode, operands[1]); +") + +(define_insn "*movsf_hard_insn" + [(set (match_operand:SF 0 "general_operand" "=f,f,f,m,f,r,r,r,m") + (match_operand:SF 1 "general_operand" "fG,H,mE,f,r,f,r,mE,r"))] + "TARGET_HARD_FLOAT + && (GET_CODE (operands[0]) != MEM || register_operand (operands[1], SFmode))" + "@ + mvf%?s\\t%0, %1 + mnf%?s\\t%0, #%N1 + ldf%?s\\t%0, %1 + stf%?s\\t%1, %0 + str%?\\t%1, [%|sp, #-4]!\;ldf%?s\\t%0, [%|sp], #4 + stf%?s\\t%1, [%|sp, #-4]!\;ldr%?\\t%0, [%|sp], #4 + mov%?\\t%0, %1 + ldr%?\\t%0, %1\\t%@ float + str%?\\t%1, %0\\t%@ float" +[(set_attr "length" "4,4,4,4,8,8,4,4,4") + (set_attr "type" + "ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r,*,load,store1")]) + +;; Exactly the same as above, except that all `f' cases are deleted. +;; This is necessary to prevent reload from ever trying to use a `f' reg +;; when -msoft-float. + +(define_insn "*movsf_soft_insn" + [(set (match_operand:SF 0 "general_operand" "=r,r,m") + (match_operand:SF 1 "general_operand" "r,mE,r"))] + "TARGET_SOFT_FLOAT + && (GET_CODE (operands[0]) != MEM || register_operand (operands[1], SFmode))" + "@ + mov%?\\t%0, %1 + ldr%?\\t%0, %1\\t%@ float + str%?\\t%1, %0\\t%@ float" +[(set_attr "length" "4,4,4") + (set_attr "type" "*,load,store1")]) + +(define_expand "movdf" + [(set (match_operand:DF 0 "general_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "" + " + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (DFmode, operands[1]); +") + +;; Reloading a df mode value stored in integer regs to memory can require a +;; scratch reg. +(define_expand "reload_outdf" + [(match_operand:DF 0 "reload_memory_operand" "=o") + (match_operand:DF 1 "s_register_operand" "r") + (match_operand:SI 2 "s_register_operand" "=&r")] + "" + " +{ + enum rtx_code code = GET_CODE (XEXP (operands[0], 0)); + + if (code == REG) + operands[2] = XEXP (operands[0], 0); + else if (code == POST_INC || code == PRE_DEC) + { + operands[0] = gen_rtx (SUBREG, DImode, operands[0], 0); + operands[1] = gen_rtx (SUBREG, DImode, operands[1], 0); + emit_insn (gen_movdi (operands[0], operands[1])); + DONE; + } + else if (code == PRE_INC) + { + rtx reg = XEXP (XEXP (operands[0], 0), 0); + emit_insn (gen_addsi3 (reg, reg, GEN_INT (8))); + operands[2] = reg; + } + else if (code == POST_DEC) + operands[2] = XEXP (XEXP (operands[0], 0), 0); + else + emit_insn (gen_addsi3 (operands[2], XEXP (XEXP (operands[0], 0), 0), + XEXP (XEXP (operands[0], 0), 1))); + + emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (MEM, DFmode, operands[2]), + operands[1])); + + if (code == POST_DEC) + emit_insn (gen_addsi3 (operands[2], operands[2], GEN_INT (-8))); + + DONE; +} +") + +(define_insn "*movdf_hard_insn" + [(set (match_operand:DF 0 "general_operand" "=r,Q,r,m,r,f,f,f,m,!f,!r") + (match_operand:DF 1 "general_operand" "Q,r,r,r,mF,fG,H,mF,f,r,f"))] + "TARGET_HARD_FLOAT + && (GET_CODE (operands[0]) != MEM + || register_operand (operands[1], DFmode))" + "* +{ + rtx ops[3]; + + switch (which_alternative) + { + case 0: return \"ldm%?ia\\t%m1, %M0\\t%@ double\"; + case 1: return \"stm%?ia\\t%m0, %M1\\t%@ double\"; + case 2: case 3: case 4: return output_move_double (operands); + case 5: return \"mvf%?d\\t%0, %1\"; + case 6: return \"mnf%?d\\t%0, #%N1\"; + case 7: return \"ldf%?d\\t%0, %1\"; + case 8: return \"stf%?d\\t%1, %0\"; + case 9: return output_mov_double_fpu_from_arm (operands); + case 10: return output_mov_double_arm_from_fpu (operands); + } +} +" +[(set_attr "length" "4,4,8,8,8,4,4,4,4,8,8") + (set_attr "type" +"load,store2,*,store2,load,ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r")]) + +;; Software floating point version. This is essentially the same as movdi. +;; Do not use `f' as a constraint to prevent reload from ever trying to use +;; an `f' reg. + +(define_insn "*movdf_soft_insn" + [(set (match_operand:DF 0 "soft_df_operand" "=r,r,m") + (match_operand:DF 1 "soft_df_operand" "r,mF,r"))] + "TARGET_SOFT_FLOAT" + "* return output_move_double (operands);" +[(set_attr "length" "8,8,8") + (set_attr "type" "*,load,store2")]) + +(define_expand "movxf" + [(set (match_operand:XF 0 "general_operand" "") + (match_operand:XF 1 "general_operand" ""))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "") + +;; Even when the XFmode patterns aren't enabled, we enable this after +;; reloading so that we can push floating point registers in the prologue. + +(define_insn "*movxf_hard_insn" + [(set (match_operand:XF 0 "general_operand" "=f,f,f,m,f,r,r") + (match_operand:XF 1 "general_operand" "fG,H,m,f,r,f,r"))] + "TARGET_HARD_FLOAT && (ENABLE_XF_PATTERNS || reload_completed)" + "* + switch (which_alternative) + { + case 0: return \"mvf%?e\\t%0, %1\"; + case 1: return \"mnf%?e\\t%0, #%N1\"; + case 2: return \"ldf%?e\\t%0, %1\"; + case 3: return \"stf%?e\\t%1, %0\"; + case 4: return output_mov_long_double_fpu_from_arm (operands); + case 5: return output_mov_long_double_arm_from_fpu (operands); + case 6: return output_mov_long_double_arm_from_arm (operands); + } +" +[(set_attr "length" "4,4,4,4,8,8,12") + (set_attr "type" "ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r,*")]) + + +;; load- and store-multiple insns +;; The arm can load/store any set of registers, provided that they are in +;; ascending order; but that is beyond GCC so stick with what it knows. + +(define_expand "load_multiple" + [(match_par_dup 3 [(set (match_operand:SI 0 "" "") + (match_operand:SI 1 "" "")) + (use (match_operand:SI 2 "" ""))])] + "" + " + /* Support only fixed point registers */ + if (GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) > 14 + || INTVAL (operands[2]) < 2 + || GET_CODE (operands[1]) != MEM + || GET_CODE (operands[0]) != REG + || REGNO (operands[0]) > 14 + || REGNO (operands[0]) + INTVAL (operands[2]) > 15) + FAIL; + + operands[3] + = arm_gen_load_multiple (REGNO (operands[0]), INTVAL (operands[2]), + force_reg (SImode, XEXP (operands[1], 0)), + TRUE, FALSE, RTX_UNCHANGING_P(operands[1]), + MEM_IN_STRUCT_P(operands[1]), + MEM_SCALAR_P (operands[1])); +") + +;; Load multiple with write-back + +(define_insn "*ldmsi_postinc" + [(match_parallel 0 "load_multiple_operation" + [(set (match_operand:SI 1 "s_register_operand" "+r") + (plus:SI (match_dup 1) + (match_operand:SI 2 "const_int_operand" "n"))) + (set (match_operand:SI 3 "s_register_operand" "=r") + (mem:SI (match_dup 1)))])] + "(INTVAL (operands[2]) == 4 * (XVECLEN (operands[0], 0) - 2))" + "* +{ + rtx ops[3]; + int count = XVECLEN (operands[0], 0); + + ops[0] = XEXP (SET_SRC (XVECEXP (operands[0], 0, 0)), 0); + ops[1] = SET_DEST (XVECEXP (operands[0], 0, 1)); + ops[2] = SET_DEST (XVECEXP (operands[0], 0, count - 2)); + + output_asm_insn (\"ldm%?ia\\t%0!, {%1-%2}\\t%@ load multiple\", ops); + return \"\"; +} +" +[(set_attr "type" "load")]) + +;; Ordinary load multiple + +(define_insn "*ldmsi" + [(match_parallel 0 "load_multiple_operation" + [(set (match_operand:SI 1 "s_register_operand" "=r") + (mem:SI (match_operand:SI 2 "s_register_operand" "r")))])] + "" + "* +{ + rtx ops[3]; + int count = XVECLEN (operands[0], 0); + + ops[0] = XEXP (SET_SRC (XVECEXP (operands[0], 0, 0)), 0); + ops[1] = SET_DEST (XVECEXP (operands[0], 0, 0)); + ops[2] = SET_DEST (XVECEXP (operands[0], 0, count - 1)); + + output_asm_insn (\"ldm%?ia\\t%0, {%1-%2}\\t%@ load multiple\", ops); + return \"\"; +} +" +[(set_attr "type" "load")]) + +(define_expand "store_multiple" + [(match_par_dup 3 [(set (match_operand:SI 0 "" "") + (match_operand:SI 1 "" "")) + (use (match_operand:SI 2 "" ""))])] + "" + " + /* Support only fixed point registers */ + if (GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) > 14 + || INTVAL (operands[2]) < 2 + || GET_CODE (operands[1]) != REG + || GET_CODE (operands[0]) != MEM + || REGNO (operands[1]) > 14 + || REGNO (operands[1]) + INTVAL (operands[2]) > 15) + FAIL; + + operands[3] + = arm_gen_store_multiple (REGNO (operands[1]), INTVAL (operands[2]), + force_reg (SImode, XEXP (operands[0], 0)), + TRUE, FALSE, RTX_UNCHANGING_P (operands[0]), + MEM_IN_STRUCT_P(operands[0]), + MEM_SCALAR_P (operands[0])); +") + +;; Store multiple with write-back + +(define_insn "*stmsi_postinc" + [(match_parallel 0 "store_multiple_operation" + [(set (match_operand:SI 1 "s_register_operand" "+r") + (plus:SI (match_dup 1) + (match_operand:SI 2 "const_int_operand" "n"))) + (set (mem:SI (match_dup 1)) + (match_operand:SI 3 "s_register_operand" "r"))])] + "(INTVAL (operands[2]) == 4 * (XVECLEN (operands[0], 0) - 2))" + "* +{ + rtx ops[3]; + int count = XVECLEN (operands[0], 0); + + ops[0] = XEXP (SET_SRC (XVECEXP (operands[0], 0, 0)), 0); + ops[1] = SET_SRC (XVECEXP (operands[0], 0, 1)); + ops[2] = SET_SRC (XVECEXP (operands[0], 0, count - 2)); + + output_asm_insn (\"stm%?ia\\t%0!, {%1-%2}\\t%@ str multiple\", ops); + return \"\"; +} +" +[(set (attr "type") + (cond [(eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 4)) + (const_string "store2") + (eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 5)) + (const_string "store3")] + (const_string "store4")))]) + +;; Ordinary store multiple + +(define_insn "*stmsi" + [(match_parallel 0 "store_multiple_operation" + [(set (mem:SI (match_operand:SI 2 "s_register_operand" "r")) + (match_operand:SI 1 "s_register_operand" "r"))])] + "" + "* +{ + rtx ops[3]; + int count = XVECLEN (operands[0], 0); + + ops[0] = XEXP (SET_DEST (XVECEXP (operands[0], 0, 0)), 0); + ops[1] = SET_SRC (XVECEXP (operands[0], 0, 0)); + ops[2] = SET_SRC (XVECEXP (operands[0], 0, count - 1)); + + output_asm_insn (\"stm%?ia\\t%0, {%1-%2}\\t%@ str multiple\", ops); + return \"\"; +} +" +[(set (attr "type") + (cond [(eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 3)) + (const_string "store2") + (eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 4)) + (const_string "store3")] + (const_string "store4")))]) + +;; Move a block of memory if it is word aligned and MORE than 2 words long. +;; We could let this apply for blocks of less than this, but it clobbers so +;; many registers that there is then probably a better way. + +(define_expand "movstrqi" + [(match_operand:BLK 0 "general_operand" "") + (match_operand:BLK 1 "general_operand" "") + (match_operand:SI 2 "const_int_operand" "") + (match_operand:SI 3 "const_int_operand" "")] + "" + " + if (arm_gen_movstrqi (operands)) + DONE; + FAIL; +") + + +;; Comparison and test insns + +(define_expand "cmpsi" + [(match_operand:SI 0 "s_register_operand" "") + (match_operand:SI 1 "arm_add_operand" "")] + "" + " +{ + arm_compare_op0 = operands[0]; + arm_compare_op1 = operands[1]; + arm_compare_fp = 0; + DONE; +} +") + +(define_expand "cmpsf" + [(match_operand:SF 0 "s_register_operand" "") + (match_operand:SF 1 "fpu_rhs_operand" "")] + "TARGET_HARD_FLOAT" + " +{ + arm_compare_op0 = operands[0]; + arm_compare_op1 = operands[1]; + arm_compare_fp = 1; + DONE; +} +") + +(define_expand "cmpdf" + [(match_operand:DF 0 "s_register_operand" "") + (match_operand:DF 1 "fpu_rhs_operand" "")] + "TARGET_HARD_FLOAT" + " +{ + arm_compare_op0 = operands[0]; + arm_compare_op1 = operands[1]; + arm_compare_fp = 1; + DONE; +} +") + +(define_expand "cmpxf" + [(match_operand:XF 0 "s_register_operand" "") + (match_operand:XF 1 "fpu_rhs_operand" "")] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + " +{ + arm_compare_op0 = operands[0]; + arm_compare_op1 = operands[1]; + arm_compare_fp = 1; + DONE; +} +") + +(define_insn "*cmpsi_insn" + [(set (reg:CC 24) + (compare:CC (match_operand:SI 0 "s_register_operand" "r,r") + (match_operand:SI 1 "arm_add_operand" "rI,L")))] + "" + "@ + cmp%?\\t%0, %1 + cmn%?\\t%0, #%n1" +[(set_attr "conds" "set")]) + +(define_insn "*cmpsi_shiftsi" + [(set (reg:CC 24) + (compare:CC (match_operand:SI 0 "s_register_operand" "r") + (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")])))] + "" + "cmp%?\\t%0, %1%S3" +[(set_attr "conds" "set")]) + +(define_insn "*cmpsi_shiftsi_swp" + [(set (reg:CC_SWP 24) + (compare:CC_SWP (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "reg_or_int_operand" "rM")]) + (match_operand:SI 0 "s_register_operand" "r")))] + "" + "cmp%?\\t%0, %1%S3" +[(set_attr "conds" "set")]) + +(define_insn "*cmpsi_neg_shiftsi" + [(set (reg:CC 24) + (compare:CC (match_operand:SI 0 "s_register_operand" "r") + (neg:SI (match_operator:SI 3 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")]))))] + "" + "cmn%?\\t%0, %1%S3" +[(set_attr "conds" "set")]) + +(define_insn "*cmpsf_insn" + [(set (reg:CCFP 24) + (compare:CCFP (match_operand:SF 0 "s_register_operand" "f,f") + (match_operand:SF 1 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + cmf%?\\t%0, %1 + cnf%?\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmpdf_insn" + [(set (reg:CCFP 24) + (compare:CCFP (match_operand:DF 0 "s_register_operand" "f,f") + (match_operand:DF 1 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + cmf%?\\t%0, %1 + cnf%?\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmpesfdf_df" + [(set (reg:CCFP 24) + (compare:CCFP (float_extend:DF + (match_operand:SF 0 "s_register_operand" "f,f")) + (match_operand:DF 1 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + cmf%?\\t%0, %1 + cnf%?\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmpdf_esfdf" + [(set (reg:CCFP 24) + (compare:CCFP (match_operand:DF 0 "s_register_operand" "f") + (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "cmf%?\\t%0, %1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmpxf_insn" + [(set (reg:CCFP 24) + (compare:CCFP (match_operand:XF 0 "s_register_operand" "f,f") + (match_operand:XF 1 "fpu_add_operand" "fG,H")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "@ + cmf%?\\t%0, %1 + cnf%?\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmpsf_trap" + [(set (reg:CCFPE 24) + (compare:CCFPE (match_operand:SF 0 "s_register_operand" "f,f") + (match_operand:SF 1 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + cmf%?e\\t%0, %1 + cnf%?e\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmpdf_trap" + [(set (reg:CCFPE 24) + (compare:CCFPE (match_operand:DF 0 "s_register_operand" "f,f") + (match_operand:DF 1 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + cmf%?e\\t%0, %1 + cnf%?e\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmp_esfdf_df_trap" + [(set (reg:CCFPE 24) + (compare:CCFPE (float_extend:DF + (match_operand:SF 0 "s_register_operand" "f,f")) + (match_operand:DF 1 "fpu_add_operand" "fG,H")))] + "TARGET_HARD_FLOAT" + "@ + cmf%?e\\t%0, %1 + cnf%?e\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmp_df_esfdf_trap" + [(set (reg:CCFPE 24) + (compare:CCFPE (match_operand:DF 0 "s_register_operand" "f") + (float_extend:DF + (match_operand:SF 1 "s_register_operand" "f"))))] + "TARGET_HARD_FLOAT" + "cmf%?e\\t%0, %1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +(define_insn "*cmpxf_trap" + [(set (reg:CCFPE 24) + (compare:CCFPE (match_operand:XF 0 "s_register_operand" "f,f") + (match_operand:XF 1 "fpu_add_operand" "fG,H")))] + "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT" + "@ + cmf%?e\\t%0, %1 + cnf%?e\\t%0, #%N1" +[(set_attr "conds" "set") + (set_attr "type" "f_2_r")]) + +; This insn allows redundant compares to be removed by cse, nothing should +; ever appear in the output file since (set (reg x) (reg x)) is a no-op that +; is deleted later on. The match_dup will match the mode here, so that +; mode changes of the condition codes aren't lost by this even though we don't +; specify what they are. + +(define_insn "*deleted_compare" + [(set (match_operand 0 "cc_register" "") (match_dup 0))] + "" + "\\t%@ deleted compare" +[(set_attr "conds" "set") + (set_attr "length" "0")]) + + +;; Conditional branch insns + +(define_expand "beq" + [(set (pc) + (if_then_else (eq (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (EQ, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "bne" + [(set (pc) + (if_then_else (ne (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (NE, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "bgt" + [(set (pc) + (if_then_else (gt (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (GT, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "ble" + [(set (pc) + (if_then_else (le (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (LE, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "bge" + [(set (pc) + (if_then_else (ge (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (GE, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "blt" + [(set (pc) + (if_then_else (lt (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (LT, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "bgtu" + [(set (pc) + (if_then_else (gtu (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (GTU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "bleu" + [(set (pc) + (if_then_else (leu (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (LEU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "bgeu" + [(set (pc) + (if_then_else (geu (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (GEU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "bltu" + [(set (pc) + (if_then_else (ltu (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + operands[1] = gen_compare_reg (LTU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +;; patterns to match conditional branch insns + +(define_insn "*condbranch" + [(set (pc) + (if_then_else (match_operator 1 "comparison_operator" + [(match_operand 2 "cc_register" "") (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + extern int arm_ccfsm_state; + + if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2) + { + arm_ccfsm_state += 2; + return \"\"; + } + return \"b%d1\\t%l0\"; +}" +[(set_attr "conds" "use")]) + +(define_insn "*condbranch_reversed" + [(set (pc) + (if_then_else (match_operator 1 "comparison_operator" + [(match_operand 2 "cc_register" "") (const_int 0)]) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + extern int arm_ccfsm_state; + + if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2) + { + arm_ccfsm_state += 2; + return \"\"; + } + return \"b%D1\\t%l0\"; +}" +[(set_attr "conds" "use")]) + + +; scc insns + +(define_expand "seq" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (eq:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (EQ, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sne" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (ne:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (NE, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sgt" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (gt:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (GT, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sle" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (le:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (LE, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sge" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (ge:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (GE, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "slt" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (lt:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (LT, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sgtu" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (gtu:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (GTU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sleu" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (leu:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (LEU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sgeu" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (geu:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (GEU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_expand "sltu" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (ltu:SI (match_dup 1) (const_int 0)))] + "" + " +{ + operands[1] = gen_compare_reg (LTU, arm_compare_op0, arm_compare_op1, + arm_compare_fp); +} +") + +(define_insn "*mov_scc" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operator:SI 1 "comparison_operator" + [(match_operand 2 "cc_register" "") (const_int 0)]))] + "" + "mov%D1\\t%0, #0\;mov%d1\\t%0, #1" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + +(define_insn "*mov_negscc" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (neg:SI (match_operator:SI 1 "comparison_operator" + [(match_operand 2 "cc_register" "") (const_int 0)])))] + "" + "mov%D1\\t%0, #0\;mvn%d1\\t%0, #0" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + +(define_insn "*mov_notscc" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (not:SI (match_operator:SI 1 "comparison_operator" + [(match_operand 2 "cc_register" "") (const_int 0)])))] + "" + "mov%D1\\t%0, #0\;mvn%d1\\t%0, #1" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + + +;; Conditional move insns + +(define_expand "movsicc" + [(set (match_operand:SI 0 "s_register_operand" "") + (if_then_else:SI (match_operand 1 "comparison_operator" "") + (match_operand:SI 2 "arm_not_operand" "") + (match_operand:SI 3 "arm_not_operand" "")))] + "" + " +{ + enum rtx_code code = GET_CODE (operands[1]); + rtx ccreg = gen_compare_reg (code, arm_compare_op0, arm_compare_op1, + arm_compare_fp); + + operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); +}") + +(define_expand "movsfcc" + [(set (match_operand:SF 0 "s_register_operand" "") + (if_then_else:SF (match_operand 1 "comparison_operator" "") + (match_operand:SF 2 "s_register_operand" "") + (match_operand:SF 3 "nonmemory_operand" "")))] + "" + " +{ + enum rtx_code code = GET_CODE (operands[1]); + rtx ccreg; + + /* When compiling for SOFT_FLOAT, ensure both arms are in registers. + Otherwise, ensure it is a valid FP add operand */ + if ((! TARGET_HARD_FLOAT) + || (! fpu_add_operand (operands[3], SFmode))) + operands[3] = force_reg (SFmode, operands[3]); + + ccreg = gen_compare_reg (code, arm_compare_op0, arm_compare_op1, + arm_compare_fp); + + operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); +}") + +(define_expand "movdfcc" + [(set (match_operand:DF 0 "s_register_operand" "") + (if_then_else:DF (match_operand 1 "comparison_operator" "") + (match_operand:DF 2 "s_register_operand" "") + (match_operand:DF 3 "fpu_add_operand" "")))] + "TARGET_HARD_FLOAT" + " +{ + enum rtx_code code = GET_CODE (operands[1]); + rtx ccreg = gen_compare_reg (code, arm_compare_op0, arm_compare_op1, + arm_compare_fp); + + operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); +}") + +(define_insn "*movsicc_insn" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r,r,r,r,r") + (if_then_else:SI + (match_operator 3 "comparison_operator" + [(match_operand 4 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_not_operand" "0,0,rI,K,rI,rI,K,K") + (match_operand:SI 2 "arm_not_operand" "rI,K,0,0,rI,K,rI,K")))] + "" + "@ + mov%D3\\t%0, %2 + mvn%D3\\t%0, #%B2 + mov%d3\\t%0, %1 + mvn%d3\\t%0, #%B1 + mov%d3\\t%0, %1\;mov%D3\\t%0, %2 + mov%d3\\t%0, %1\;mvn%D3\\t%0, #%B2 + mvn%d3\\t%0, #%B1\;mov%D3\\t%0, %2 + mvn%d3\\t%0, #%B1\;mvn%D3\\t%0, #%B2" + [(set_attr "length" "4,4,4,4,8,8,8,8") + (set_attr "conds" "use")]) + +(define_insn "*movsfcc_hard_insn" + [(set (match_operand:SF 0 "s_register_operand" "=f,f,f,f,f,f,f,f") + (if_then_else:SF + (match_operator 3 "comparison_operator" + [(match_operand 4 "cc_register" "") (const_int 0)]) + (match_operand:SF 1 "fpu_add_operand" "0,0,fG,H,fG,fG,H,H") + (match_operand:SF 2 "fpu_add_operand" "fG,H,0,0,fG,H,fG,H")))] + "TARGET_HARD_FLOAT" + "@ + mvf%D3s\\t%0, %2 + mnf%D3s\\t%0, #%N2 + mvf%d3s\\t%0, %1 + mnf%d3s\\t%0, #%N1 + mvf%d3s\\t%0, %1\;mvf%D3s\\t%0, %2 + mvf%d3s\\t%0, %1\;mnf%D3s\\t%0, #%N2 + mnf%d3s\\t%0, #%N1\;mvf%D3s\\t%0, %2 + mnf%d3s\\t%0, #%N1\;mnf%D3s\\t%0, #%N2" + [(set_attr "length" "4,4,4,4,8,8,8,8") + (set_attr "type" "ffarith") + (set_attr "conds" "use")]) + +(define_insn "*movsfcc_soft_insn" + [(set (match_operand:SF 0 "s_register_operand" "=r,r") + (if_then_else:SF (match_operator 3 "comparison_operator" + [(match_operand 4 "cc_register" "") (const_int 0)]) + (match_operand:SF 1 "s_register_operand" "0,r") + (match_operand:SF 2 "s_register_operand" "r,0")))] + "TARGET_SOFT_FLOAT" + "@ + mov%D3\\t%0, %2 + mov%d3\\t%0, %1" + [(set_attr "conds" "use")]) + +(define_insn "*movdfcc_insn" + [(set (match_operand:DF 0 "s_register_operand" "=f,f,f,f,f,f,f,f") + (if_then_else:DF + (match_operator 3 "comparison_operator" + [(match_operand 4 "cc_register" "") (const_int 0)]) + (match_operand:DF 1 "fpu_add_operand" "0,0,fG,H,fG,fG,H,H") + (match_operand:DF 2 "fpu_add_operand" "fG,H,0,0,fG,H,fG,H")))] + "TARGET_HARD_FLOAT" + "@ + mvf%D3d\\t%0, %2 + mnf%D3d\\t%0, #%N2 + mvf%d3d\\t%0, %1 + mnf%d3d\\t%0, #%N1 + mvf%d3d\\t%0, %1\;mvf%D3d\\t%0, %2 + mvf%d3d\\t%0, %1\;mnf%D3d\\t%0, #%N2 + mnf%d3d\\t%0, #%N1\;mvf%D3d\\t%0, %2 + mnf%d3d\\t%0, #%N1\;mnf%D3d\\t%0, #%N2" + [(set_attr "length" "4,4,4,4,8,8,8,8") + (set_attr "type" "ffarith") + (set_attr "conds" "use")]) + +;; Jump and linkage insns + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "* +{ + extern int arm_ccfsm_state; + + if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2) + { + arm_ccfsm_state += 2; + return \"\"; + } + return \"b%?\\t%l0\"; +}") + +(define_expand "call" + [(parallel [(call (match_operand 0 "memory_operand" "") + (match_operand 1 "general_operand" "")) + (clobber (reg:SI 14))])] + "" + "") + +(define_insn "*call_reg" + [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r")) + (match_operand 1 "" "g")) + (clobber (reg:SI 14))] + "" + "* + return output_call (operands); +" +;; length is worst case, normally it is only two +[(set_attr "length" "12") + (set_attr "type" "call")]) + +(define_insn "*call_mem" + [(call (mem:SI (match_operand 0 "memory_operand" "m")) + (match_operand 1 "general_operand" "g")) + (clobber (reg:SI 14))] + "" + "* + return output_call_mem (operands); +" +[(set_attr "length" "12") + (set_attr "type" "call")]) + +(define_expand "call_value" + [(parallel [(set (match_operand 0 "" "=rf") + (call (match_operand 1 "memory_operand" "m") + (match_operand 2 "general_operand" "g"))) + (clobber (reg:SI 14))])] + "" + "") + +(define_insn "*call_value_reg" + [(set (match_operand 0 "" "=rf") + (call (mem:SI (match_operand:SI 1 "s_register_operand" "r")) + (match_operand 2 "general_operand" "g"))) + (clobber (reg:SI 14))] + "" + "* + return output_call (&operands[1]); +" +[(set_attr "length" "12") + (set_attr "type" "call")]) + +(define_insn "*call_value_mem" + [(set (match_operand 0 "" "=rf") + (call (mem:SI (match_operand 1 "memory_operand" "m")) + (match_operand 2 "general_operand" "g"))) + (clobber (reg:SI 14))] + "! CONSTANT_ADDRESS_P (XEXP (operands[1], 0))" + "* + return output_call_mem (&operands[1]); +" +[(set_attr "length" "12") + (set_attr "type" "call")]) + +;; Allow calls to SYMBOL_REFs specially as they are not valid general addresses +;; The 'a' causes the operand to be treated as an address, i.e. no '#' output. + +(define_insn "*call_symbol" + [(call (mem:SI (match_operand:SI 0 "" "X")) + (match_operand:SI 1 "general_operand" "g")) + (clobber (reg:SI 14))] + "GET_CODE (operands[0]) == SYMBOL_REF" + "bl%?\\t%a0" +[(set_attr "type" "call")]) + +(define_insn "*call_value_symbol" + [(set (match_operand 0 "s_register_operand" "=rf") + (call (mem:SI (match_operand:SI 1 "" "X")) + (match_operand:SI 2 "general_operand" "g"))) + (clobber (reg:SI 14))] + "GET_CODE(operands[1]) == SYMBOL_REF" + "bl%?\\t%a1" +[(set_attr "type" "call")]) + +;; Often the return insn will be the same as loading from memory, so set attr +(define_insn "return" + [(return)] + "USE_RETURN_INSN (FALSE)" + "* +{ + extern int arm_ccfsm_state; + + if (arm_ccfsm_state == 2) + { + arm_ccfsm_state += 2; + return \"\"; + } + return output_return_instruction (NULL, TRUE, FALSE); +}" +[(set_attr "type" "load")]) + +(define_insn "*cond_return" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand 1 "cc_register" "") (const_int 0)]) + (return) + (pc)))] + "USE_RETURN_INSN (TRUE)" + "* +{ + extern int arm_ccfsm_state; + + if (arm_ccfsm_state == 2) + { + arm_ccfsm_state += 2; + return \"\"; + } + return output_return_instruction (operands[0], TRUE, FALSE); +}" +[(set_attr "conds" "use") + (set_attr "type" "load")]) + +(define_insn "*cond_return_inverted" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand 1 "cc_register" "") (const_int 0)]) + (pc) + (return)))] + "USE_RETURN_INSN (TRUE)" + "* +{ + extern int arm_ccfsm_state; + + if (arm_ccfsm_state == 2) + { + arm_ccfsm_state += 2; + return \"\"; + } + return output_return_instruction (operands[0], TRUE, TRUE); +}" +[(set_attr "conds" "use") + (set_attr "type" "load")]) + +;; Call subroutine returning any type. + +(define_expand "untyped_call" + [(parallel [(call (match_operand 0 "" "") + (const_int 0)) + (match_operand 1 "" "") + (match_operand 2 "" "")])] + "" + " +{ + int i; + + emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx)); + + for (i = 0; i < XVECLEN (operands[2], 0); i++) + { + rtx set = XVECEXP (operands[2], 0, i); + emit_move_insn (SET_DEST (set), SET_SRC (set)); + } + + /* The optimizer does not know that the call sets the function value + registers we stored in the result block. We avoid problems by + claiming that all hard registers are used and clobbered at this + point. */ + emit_insn (gen_blockage ()); + + DONE; +}") + +;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and +;; all of memory. This blocks insns from being moved across this point. + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] 0)] + "" + "" +[(set_attr "length" "0") + (set_attr "type" "block")]) + +(define_expand "casesi" + [(match_operand:SI 0 "s_register_operand" "") ; index to jump on + (match_operand:SI 1 "const_int_operand" "") ; lower bound + (match_operand:SI 2 "const_int_operand" "") ; total range + (match_operand:SI 3 "" "") ; table label + (match_operand:SI 4 "" "")] ; Out of range label + "" + " +{ + rtx reg; + if (operands[1] != const0_rtx) + { + reg = gen_reg_rtx (SImode); + emit_insn (gen_addsi3 (reg, operands[0], + GEN_INT (-INTVAL (operands[1])))); + operands[0] = reg; + } + + if (! const_ok_for_arm (INTVAL (operands[2]))) + operands[2] = force_reg (SImode, operands[2]); + + emit_jump_insn (gen_casesi_internal (operands[0], operands[2], operands[3], + operands[4])); + DONE; +}") + +;; The USE in this pattern is needed to tell flow analysis that this is +;; a CASESI insn. It has no other purpose. +(define_insn "casesi_internal" + [(parallel [(set (pc) + (if_then_else + (leu (match_operand:SI 0 "s_register_operand" "r") + (match_operand:SI 1 "arm_rhs_operand" "rI")) + (mem:SI (plus:SI (mult:SI (match_dup 0) (const_int 4)) + (label_ref (match_operand 2 "" "")))) + (label_ref (match_operand 3 "" "")))) + (use (label_ref (match_dup 2)))])] + "" + "* + if (flag_pic) + return \"cmp\\t%0, %1\;addls\\t%|pc, %|pc, %0, asl #2\;b\\t%l3\"; + return \"cmp\\t%0, %1\;ldrls\\t%|pc, [%|pc, %0, asl #2]\;b\\t%l3\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "indirect_jump" + [(set (pc) + (match_operand:SI 0 "s_register_operand" "r"))] + "" + "mov%?\\t%|pc, %0\\t%@ indirect jump") + +(define_insn "*load_indirect_jump" + [(set (pc) + (match_operand:SI 0 "memory_operand" "m"))] + "" + "ldr%?\\t%|pc, %0\\t%@ indirect jump" +[(set_attr "type" "load")]) + +;; Misc insns + +(define_insn "nop" + [(const_int 0)] + "" + "mov%?\\tr0, r0\\t%@ nop") + +;; Patterns to allow combination of arithmetic, cond code and shifts + +(define_insn "*arith_shiftsi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operator:SI 1 "shiftable_operator" + [(match_operator:SI 3 "shift_operator" + [(match_operand:SI 4 "s_register_operand" "r") + (match_operand:SI 5 "reg_or_int_operand" "rI")]) + (match_operand:SI 2 "s_register_operand" "r")]))] + "" + "%i1%?\\t%0, %2, %4%S3") + +(define_insn "*arith_shiftsi_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (match_operator:SI 1 "shiftable_operator" + [(match_operator:SI 3 "shift_operator" + [(match_operand:SI 4 "s_register_operand" "r") + (match_operand:SI 5 "reg_or_int_operand" "rI")]) + (match_operand:SI 2 "s_register_operand" "r")]) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (match_op_dup 1 [(match_op_dup 3 [(match_dup 4) (match_dup 5)]) + (match_dup 2)]))] + "" + "%i1%?s\\t%0, %2, %4%S3" +[(set_attr "conds" "set")]) + +(define_insn "*arith_shiftsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (match_operator:SI 1 "shiftable_operator" + [(match_operator:SI 3 "shift_operator" + [(match_operand:SI 4 "s_register_operand" "r") + (match_operand:SI 5 "reg_or_int_operand" "rI")]) + (match_operand:SI 2 "s_register_operand" "r")]) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "" + "%i1%?s\\t%0, %2, %4%S3" +[(set_attr "conds" "set")]) + +(define_insn "*sub_shiftsi" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "reg_or_int_operand" "rM")])))] + "" + "sub%?\\t%0, %1, %3%S2") + +(define_insn "*sub_shiftsi_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (minus:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "reg_or_int_operand" "rM")])) + (const_int 0))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) + (match_dup 4)])))] + "" + "sub%?s\\t%0, %1, %3%S2" +[(set_attr "conds" "set")]) + +(define_insn "*sub_shiftsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV + (minus:SI (match_operand:SI 1 "s_register_operand" "r") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "reg_or_int_operand" "rM")])) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "" + "sub%?s\\t%0, %1, %3%S2" +[(set_attr "conds" "set")]) + +;; These variants of the above insns can occur if the first operand is the +;; frame pointer and we eliminate that. This is a kludge, but there doesn't +;; seem to be a way around it. Most of the predicates have to be null +;; because the format can be generated part way through reload, so +;; if we don't match it as soon as it becomes available, reload doesn't know +;; how to reload pseudos that haven't got hard registers; the constraints will +;; sort everything out. + +(define_insn "*reload_mulsi3" + [(set (match_operand:SI 0 "" "=&r") + (plus:SI (plus:SI (match_operator:SI 5 "shift_operator" + [(match_operand:SI 3 "" "r") + (match_operand:SI 4 "" "rM")]) + (match_operand:SI 2 "" "r")) + (match_operand:SI 1 "const_int_operand" "n")))] + "reload_in_progress" + "* + output_asm_insn (\"add%?\\t%0, %2, %3%S5\", operands); + operands[2] = operands[1]; + operands[1] = operands[0]; + return output_add_immediate (operands); +" +; we have no idea how long the add_immediate is, it could be up to 4. +[(set_attr "length" "20")]) + +(define_insn "*reload_mulsi_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (plus:SI + (plus:SI + (match_operator:SI 5 "shift_operator" + [(match_operand:SI 3 "" "r") + (match_operand:SI 4 "" "rM")]) + (match_operand:SI 1 "" "r")) + (match_operand:SI 2 "const_int_operand" "n")) + (const_int 0))) + (set (match_operand:SI 0 "" "=&r") + (plus:SI (plus:SI (match_op_dup 5 [(match_dup 3) (match_dup 4)]) + (match_dup 1)) + (match_dup 2)))] + "reload_in_progress" + "* + output_add_immediate (operands); + return \"add%?s\\t%0, %0, %3%S5\"; +" +[(set_attr "conds" "set") + (set_attr "length" "20")]) + +(define_insn "*reload_mulsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (plus:SI + (plus:SI + (match_operator:SI 5 "shift_operator" + [(match_operand:SI 3 "" "r") + (match_operand:SI 4 "" "rM")]) + (match_operand:SI 1 "" "r")) + (match_operand:SI 2 "const_int_operand" "n")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=&r"))] + "reload_in_progress" + "* + output_add_immediate (operands); + return \"add%?s\\t%0, %0, %3%S5\"; +" +[(set_attr "conds" "set") + (set_attr "length" "20")]) + +;; These are similar, but are needed when the mla pattern contains the +;; eliminated register as operand 3. + +(define_insn "*reload_muladdsi" + [(set (match_operand:SI 0 "" "=&r,&r") + (plus:SI (plus:SI (mult:SI (match_operand:SI 1 "" "%0,r") + (match_operand:SI 2 "" "r,r")) + (match_operand:SI 3 "" "r,r")) + (match_operand:SI 4 "const_int_operand" "n,n")))] + "reload_in_progress" + "* + output_asm_insn (\"mla%?\\t%0, %2, %1, %3\", operands); + operands[2] = operands[4]; + operands[1] = operands[0]; + return output_add_immediate (operands); +" +[(set_attr "length" "20") + (set_attr "type" "mult")]) + +(define_insn "*reload_muladdsi_compare0" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (plus:SI (plus:SI (mult:SI + (match_operand:SI 3 "" "r") + (match_operand:SI 4 "" "r")) + (match_operand:SI 1 "" "r")) + (match_operand:SI 2 "const_int_operand" "n")) + (const_int 0))) + (set (match_operand:SI 0 "" "=&r") + (plus:SI (plus:SI (mult:SI (match_dup 3) (match_dup 4)) (match_dup 1)) + (match_dup 2)))] + "reload_in_progress" + "* + output_add_immediate (operands); + output_asm_insn (\"mla%?s\\t%0, %3, %4, %0\", operands); + return \"\"; +" +[(set_attr "length" "20") + (set_attr "conds" "set") + (set_attr "type" "mult")]) + +(define_insn "*reload_muladdsi_compare0_scratch" + [(set (reg:CC_NOOV 24) + (compare:CC_NOOV (plus:SI (plus:SI (mult:SI + (match_operand:SI 3 "" "r") + (match_operand:SI 4 "" "r")) + (match_operand:SI 1 "" "r")) + (match_operand:SI 2 "const_int_operand" "n")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=&r"))] + "reload_in_progress" + "* + output_add_immediate (operands); + return \"mla%?s\\t%0, %3, %4, %0\"; +" +[(set_attr "length" "20") + (set_attr "conds" "set") + (set_attr "type" "mult")]) + + + +(define_insn "*and_scc" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (and:SI (match_operator 1 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (match_operand:SI 2 "s_register_operand" "r")))] + "" + "mov%D1\\t%0, #0\;and%d1\\t%0, %2, #1" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + +(define_insn "*ior_scc" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (ior:SI (match_operator 2 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "s_register_operand" "0,?r")))] + "" + "@ + orr%d2\\t%0, %1, #1 + mov%D2\\t%0, %1\;orr%d2\\t%0, %1, #1" +[(set_attr "conds" "use") + (set_attr "length" "4,8")]) + +(define_insn "*compare_scc" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (match_operator 1 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_add_operand" "rI,L")])) + (clobber (reg:CC 24))] + "" + "* + if (GET_CODE (operands[1]) == LT && operands[3] == const0_rtx) + return \"mov\\t%0, %2, lsr #31\"; + + if (GET_CODE (operands[1]) == GE && operands[3] == const0_rtx) + return \"mvn\\t%0, %2\;mov\\t%0, %0, lsr #31\"; + + if (GET_CODE (operands[1]) == NE) + { + if (which_alternative == 1) + return \"adds\\t%0, %2, #%n3\;movne\\t%0, #1\"; + return \"subs\\t%0, %2, %3\;movne\\t%0, #1\"; + } + if (which_alternative == 1) + output_asm_insn (\"cmn\\t%2, #%n3\", operands); + else + output_asm_insn (\"cmp\\t%2, %3\", operands); + return \"mov%D1\\t%0, #0\;mov%d1\\t%0, #1\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "*cond_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI (match_operator 3 "equality_operator" + [(match_operator 4 "comparison_operator" + [(match_operand 5 "cc_register" "") (const_int 0)]) + (const_int 0)]) + (match_operand:SI 1 "arm_rhs_operand" "0,rI,?rI") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))] + "" + "* + if (GET_CODE (operands[3]) == NE) + { + if (which_alternative != 1) + output_asm_insn (\"mov%D4\\t%0, %2\", operands); + if (which_alternative != 0) + output_asm_insn (\"mov%d4\\t%0, %1\", operands); + return \"\"; + } + if (which_alternative != 0) + output_asm_insn (\"mov%D4\\t%0, %1\", operands); + if (which_alternative != 1) + output_asm_insn (\"mov%d4\\t%0, %2\", operands); + return \"\"; +" +[(set_attr "conds" "use") + (set_attr "length" "4,4,8")]) + +(define_insn "*cond_arith" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (match_operator:SI 5 "shiftable_operator" + [(match_operator:SI 4 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_rhs_operand" "rI,rI")]) + (match_operand:SI 1 "s_register_operand" "0,?r")])) + (clobber (reg:CC 24))] + "" + "* + if (GET_CODE (operands[4]) == LT && operands[3] == const0_rtx) + return \"%i5\\t%0, %1, %2, lsr #31\"; + + output_asm_insn (\"cmp\\t%2, %3\", operands); + if (GET_CODE (operands[5]) == AND) + output_asm_insn (\"mov%D4\\t%0, #0\", operands); + else if (GET_CODE (operands[5]) == MINUS) + output_asm_insn (\"rsb%D4\\t%0, %1, #0\", operands); + else if (which_alternative != 0) + output_asm_insn (\"mov%D4\\t%0, %1\", operands); + return \"%i5%d4\\t%0, %1, #1\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "*cond_sub" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (minus:SI (match_operand:SI 1 "s_register_operand" "0,?r") + (match_operator:SI 4 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_rhs_operand" "rI,rI")]))) + (clobber (reg:CC 24))] + "" + "* + output_asm_insn (\"cmp\\t%2, %3\", operands); + if (which_alternative != 0) + output_asm_insn (\"mov%D4\\t%0, %1\", operands); + return \"sub%d4\\t%0, %1, #1\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*cmp_ite0" + [(set (match_operand 6 "dominant_cc_register" "") + (compare + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand:SI 0 "s_register_operand" "r,r,r,r") + (match_operand:SI 1 "arm_add_operand" "rI,L,rI,L")]) + (match_operator:SI 5 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "r,r,r,r") + (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")]) + (const_int 0)) + (const_int 0)))] + "" + "* +{ + char* opcodes[4][2] = + { + {\"cmp\\t%2, %3\;cmp%d5\\t%0, %1\",\"cmp\\t%0, %1\;cmp%d4\\t%2, %3\"}, + {\"cmp\\t%2, %3\;cmn%d5\\t%0, #%n1\", \"cmn\\t%0, #%n1\;cmp%d4\\t%2, %3\"}, + {\"cmn\\t%2, #%n3\;cmp%d5\\t%0, %1\", \"cmp\\t%0, %1\;cmn%d4\\t%2, #%n3\"}, + {\"cmn\\t%2, #%n3\;cmn%d5\\t%0, #%n1\", + \"cmn\\t%0, #%n1\;cmn%d4\\t%2, #%n3\"} + }; + int swap = + comparison_dominates_p (GET_CODE (operands[5]), GET_CODE (operands[4])); + + return opcodes[which_alternative][swap]; +} +" +[(set_attr "conds" "set") + (set_attr "length" "8")]) + +(define_insn "*cmp_ite1" + [(set (match_operand 6 "dominant_cc_register" "") + (compare + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand:SI 0 "s_register_operand" "r,r,r,r") + (match_operand:SI 1 "arm_add_operand" "rI,L,rI,L")]) + (match_operator:SI 5 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "r,r,r,r") + (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")]) + (const_int 1)) + (const_int 0)))] + "" + "* +{ + char* opcodes[4][2] = + { + {\"cmp\\t%0, %1\;cmp%d4\\t%2, %3\", \"cmp\\t%2, %3\;cmp%D5\\t%0, %1\"}, + {\"cmn\\t%0, #%n1\;cmp%d4\\t%2, %3\", \"cmp\\t%2, %3\;cmn%D5\\t%0, #%n1\"}, + {\"cmp\\t%0, %1\;cmn%d4\\t%2, #%n3\", \"cmn\\t%2, #%n3\;cmp%D5\\t%0, %1\"}, + {\"cmn\\t%0, #%n1\;cmn%d4\\t%2, #%n3\", + \"cmn\\t%2, #%n3\;cmn%D5\\t%0, #%n1\"} + }; + int swap = + comparison_dominates_p (GET_CODE (operands[5]), + reverse_condition (GET_CODE (operands[4]))); + + return opcodes[which_alternative][swap]; +} +" +[(set_attr "conds" "set") + (set_attr "length" "8")]) + +(define_insn "*negscc" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (neg:SI (match_operator 3 "comparison_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rI")]))) + (clobber (reg:CC 24))] + "" + "* + if (GET_CODE (operands[3]) == LT && operands[3] == const0_rtx) + return \"mov\\t%0, %1, asr #31\"; + + if (GET_CODE (operands[3]) == NE) + return \"subs\\t%0, %1, %2\;mvnne\\t%0, #0\"; + + if (GET_CODE (operands[3]) == GT) + return \"subs\\t%0, %1, %2\;mvnne\\t%0, %0, asr #31\"; + + output_asm_insn (\"cmp\\t%1, %2\", operands); + output_asm_insn (\"mov%D3\\t%0, #0\", operands); + return \"mvn%d3\\t%0, #0\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "movcond" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand:SI 3 "s_register_operand" "r,r,r") + (match_operand:SI 4 "arm_add_operand" "rIL,rIL,rIL")]) + (match_operand:SI 1 "arm_rhs_operand" "0,rI,?rI") + (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))) + (clobber (reg:CC 24))] + "" + "* + if (GET_CODE (operands[5]) == LT + && (operands[4] == const0_rtx)) + { + if (which_alternative != 1 && GET_CODE (operands[1]) == REG) + { + if (operands[2] == const0_rtx) + return \"and\\t%0, %1, %3, asr #31\"; + return \"ands\\t%0, %1, %3, asr #32\;movcc\\t%0, %2\"; + } + else if (which_alternative != 0 && GET_CODE (operands[2]) == REG) + { + if (operands[1] == const0_rtx) + return \"bic\\t%0, %2, %3, asr #31\"; + return \"bics\\t%0, %2, %3, asr #32\;movcs\\t%0, %1\"; + } + /* The only case that falls through to here is when both ops 1 & 2 + are constants */ + } + + if (GET_CODE (operands[5]) == GE + && (operands[4] == const0_rtx)) + { + if (which_alternative != 1 && GET_CODE (operands[1]) == REG) + { + if (operands[2] == const0_rtx) + return \"bic\\t%0, %1, %3, asr #31\"; + return \"bics\\t%0, %1, %3, asr #32\;movcs\\t%0, %2\"; + } + else if (which_alternative != 0 && GET_CODE (operands[2]) == REG) + { + if (operands[1] == const0_rtx) + return \"and\\t%0, %2, %3, asr #31\"; + return \"ands\\t%0, %2, %3, asr #32\;movcc\\t%0, %1\"; + } + /* The only case that falls through to here is when both ops 1 & 2 + are constants */ + } + if (GET_CODE (operands[4]) == CONST_INT + && !const_ok_for_arm (INTVAL (operands[4]))) + output_asm_insn (\"cmn\\t%3, #%n4\", operands); + else + output_asm_insn (\"cmp\\t%3, %4\", operands); + if (which_alternative != 0) + output_asm_insn (\"mov%d5\\t%0, %1\", operands); + if (which_alternative != 1) + output_asm_insn (\"mov%D5\\t%0, %2\", operands); + return \"\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "8,8,12")]) + +(define_insn "*ifcompare_plus_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI (match_operator 6 "comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r,r") + (match_operand:SI 5 "arm_add_operand" "rIL,rIL")]) + (plus:SI + (match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_add_operand" "rIL,rIL")) + (match_operand:SI 1 "arm_rhsm_operand" "0,?rIm"))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_plus_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r,r,r") + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand 5 "cc_register" "") (const_int 0)]) + (plus:SI + (match_operand:SI 2 "s_register_operand" "r,r,r,r,r,r") + (match_operand:SI 3 "arm_add_operand" "rI,L,rI,L,rI,L")) + (match_operand:SI 1 "arm_rhsm_operand" "0,0,?rI,?rI,m,m")))] + "" + "@ + add%d4\\t%0, %2, %3 + sub%d4\\t%0, %2, #%n3 + add%d4\\t%0, %2, %3\;mov%D4\\t%0, %1 + sub%d4\\t%0, %2, #%n3\;mov%D4\\t%0, %1 + add%d4\\t%0, %2, %3\;ldr%D4\\t%0, %1 + sub%d4\\t%0, %2, #%n3\;ldr%D4\\t%0, %1" +[(set_attr "conds" "use") + (set_attr "length" "4,4,8,8,8,8") + (set_attr "type" "*,*,*,*,load,load")]) + +(define_insn "*ifcompare_move_plus" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI (match_operator 6 "comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r,r") + (match_operand:SI 5 "arm_add_operand" "rIL,rIL")]) + (match_operand:SI 1 "arm_rhsm_operand" "0,?rIm") + (plus:SI + (match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_add_operand" "rIL,rIL")))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_move_plus" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r,r,r") + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand 5 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_rhsm_operand" "0,0,?rI,?rI,m,m") + (plus:SI + (match_operand:SI 2 "s_register_operand" "r,r,r,r,r,r") + (match_operand:SI 3 "arm_add_operand" "rI,L,rI,L,rI,L"))))] + "" + "@ + add%D4\\t%0, %2, %3 + sub%D4\\t%0, %2, #%n3 + add%D4\\t%0, %2, %3\;mov%d4\\t%0, %1 + sub%D4\\t%0, %2, #%n3\;mov%d4\\t%0, %1 + add%D4\\t%0, %2, %3\;ldr%d4\\t%0, %1 + sub%D4\\t%0, %2, #%n3\;ldr%d4\\t%0, %1" +[(set_attr "conds" "use") + (set_attr "length" "4,4,8,8,8,8") + (set_attr "type" "*,*,*,*,load,load")]) + +(define_insn "*ifcompare_arith_arith" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI (match_operator 9 "comparison_operator" + [(match_operand:SI 5 "s_register_operand" "r") + (match_operand:SI 6 "arm_add_operand" "rIL")]) + (match_operator:SI 8 "shiftable_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rI")]) + (match_operator:SI 7 "shiftable_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "arm_rhs_operand" "rI")]))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "*if_arith_arith" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI (match_operator 5 "comparison_operator" + [(match_operand 8 "cc_register" "") (const_int 0)]) + (match_operator:SI 6 "shiftable_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rI")]) + (match_operator:SI 7 "shiftable_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "arm_rhs_operand" "rI")])))] + "" + "%I6%d5\\t%0, %1, %2\;%I7%D5\\t%0, %3, %4" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + +(define_insn "*ifcompare_arith_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI (match_operator 6 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_add_operand" "rIL,rIL")]) + (match_operator:SI 7 "shiftable_operator" + [(match_operand:SI 4 "s_register_operand" "r,r") + (match_operand:SI 5 "arm_rhs_operand" "rI,rI")]) + (match_operand:SI 1 "arm_rhsm_operand" "0,?rIm"))) + (clobber (reg:CC 24))] + "" + "* + /* If we have an operation where (op x 0) is the identity operation and + the conditional operator is LT or GE and we are comparing against zero and + everything is in registers then we can do this in two instructions */ + if (operands[3] == const0_rtx + && GET_CODE (operands[7]) != AND + && GET_CODE (operands[5]) == REG + && GET_CODE (operands[1]) == REG + && REGNO (operands[1]) == REGNO (operands[4]) + && REGNO (operands[4]) != REGNO (operands[0])) + { + if (GET_CODE (operands[6]) == LT) + return \"and\\t%0, %5, %2, asr #31\;%I7\\t%0, %4, %0\"; + else if (GET_CODE (operands[6]) == GE) + return \"bic\\t%0, %5, %2, asr #31\;%I7\\t%0, %4, %0\"; + } + if (GET_CODE (operands[3]) == CONST_INT + && !const_ok_for_arm (INTVAL (operands[3]))) + output_asm_insn (\"cmn\\t%2, #%n3\", operands); + else + output_asm_insn (\"cmp\\t%2, %3\", operands); + output_asm_insn (\"%I7%d6\\t%0, %4, %5\", operands); + if (which_alternative != 0) + { + if (GET_CODE (operands[1]) == MEM) + return \"ldr%D6\\t%0, %1\"; + else + return \"mov%D6\\t%0, %1\"; + } + return \"\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_arith_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI (match_operator 4 "comparison_operator" + [(match_operand 6 "cc_register" "") (const_int 0)]) + (match_operator:SI 5 "shiftable_operator" + [(match_operand:SI 2 "s_register_operand" "r,r,r") + (match_operand:SI 3 "arm_rhs_operand" "rI,rI,rI")]) + (match_operand:SI 1 "arm_rhsm_operand" "0,?rI,m")))] + "" + "@ + %I5%d4\\t%0, %2, %3 + %I5%d4\\t%0, %2, %3\;mov%D4\\t%0, %1 + %I5%d4\\t%0, %2, %3\;ldr%D4\\t%0, %1" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8") + (set_attr "type" "*,*,load")]) + +(define_insn "*ifcompare_move_arith" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI (match_operator 6 "comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r,r") + (match_operand:SI 5 "arm_add_operand" "rIL,rIL")]) + (match_operand:SI 1 "arm_rhsm_operand" "0,?rIm") + (match_operator:SI 7 "shiftable_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_rhs_operand" "rI,rI")]))) + (clobber (reg:CC 24))] + "" + "* + /* If we have an operation where (op x 0) is the identity operation and + the conditional operator is LT or GE and we are comparing against zero and + everything is in registers then we can do this in two instructions */ + if (operands[5] == const0_rtx + && GET_CODE (operands[7]) != AND + && GET_CODE (operands[3]) == REG + && GET_CODE (operands[1]) == REG + && REGNO (operands[1]) == REGNO (operands[2]) + && REGNO (operands[2]) != REGNO (operands[0])) + { + if (GET_CODE (operands[6]) == GE) + return \"and\\t%0, %3, %4, asr #31\;%I7\\t%0, %2, %0\"; + else if (GET_CODE (operands[6]) == LT) + return \"bic\\t%0, %3, %4, asr #31\;%I7\\t%0, %2, %0\"; + } + + if (GET_CODE (operands[5]) == CONST_INT + && !const_ok_for_arm (INTVAL (operands[5]))) + output_asm_insn (\"cmn\\t%4, #%n5\", operands); + else + output_asm_insn (\"cmp\\t%4, %5\", operands); + + if (which_alternative != 0) + { + if (GET_CODE (operands[1]) == MEM) + output_asm_insn (\"ldr%d6\\t%0, %1\", operands); + else + output_asm_insn (\"mov%d6\\t%0, %1\", operands); + } + return \"%I7%D6\\t%0, %2, %3\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_move_arith" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand 6 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_rhsm_operand" "0,?rI,m") + (match_operator:SI 5 "shiftable_operator" + [(match_operand:SI 2 "s_register_operand" "r,r,r") + (match_operand:SI 3 "arm_rhs_operand" "rI,rI,rI")])))] + "" + "@ + %I5%D4\\t%0, %2, %3 + %I5%D4\\t%0, %2, %3\;mov%d4\\t%0, %1 + %I5%D4\\t%0, %2, %3\;ldr%d4\\t%0, %1" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8") + (set_attr "type" "*,*,load")]) + +(define_insn "*ifcompare_move_not" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand:SI 3 "s_register_operand" "r,r") + (match_operand:SI 4 "arm_add_operand" "rIL,rIL")]) + (match_operand:SI 1 "arm_not_operand" "0,?rIK") + (not:SI + (match_operand:SI 2 "s_register_operand" "r,r")))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_move_not" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_not_operand" "0,?rI,K") + (not:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))))] + "" + "@ + mvn%D4\\t%0, %2 + mov%d4\\t%0, %1\;mvn%D4\\t%0, %2 + mvn%d4\\t%0, #%B1\;mvn%D4\\t%0, %2" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8")]) + +(define_insn "*ifcompare_not_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand:SI 3 "s_register_operand" "r,r") + (match_operand:SI 4 "arm_add_operand" "rIL,rIL")]) + (not:SI + (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:SI 1 "arm_not_operand" "0,?rIK"))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_not_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (not:SI (match_operand:SI 2 "s_register_operand" "r,r,r")) + (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))] + "" + "@ + mvn%d4\\t%0, %2 + mov%D4\\t%0, %1\;mvn%d4\\t%0, %2 + mvn%D4\\t%0, #%B1\;mvn%d4\\t%0, %2" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8")]) + +(define_insn "*ifcompare_shift_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI + (match_operator 6 "comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r,r") + (match_operand:SI 5 "arm_add_operand" "rIL,rIL")]) + (match_operator:SI 7 "shift_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_rhs_operand" "rM,rM")]) + (match_operand:SI 1 "arm_not_operand" "0,?rIK"))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_shift_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand 6 "cc_register" "") (const_int 0)]) + (match_operator:SI 4 "shift_operator" + [(match_operand:SI 2 "s_register_operand" "r,r,r") + (match_operand:SI 3 "arm_rhs_operand" "rM,rM,rM")]) + (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))] + "" + "@ + mov%d5\\t%0, %2%S4 + mov%D5\\t%0, %1\;mov%d5\\t%0, %2%S4 + mvn%D5\\t%0, #%B1\;mov%d5\\t%0, %2%S4" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8")]) + +(define_insn "*ifcompare_move_shift" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI + (match_operator 6 "comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r,r") + (match_operand:SI 5 "arm_add_operand" "rIL,rIL")]) + (match_operand:SI 1 "arm_not_operand" "0,?rIK") + (match_operator:SI 7 "shift_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_rhs_operand" "rM,rM")]))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_move_shift" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand 6 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_not_operand" "0,?rI,K") + (match_operator:SI 4 "shift_operator" + [(match_operand:SI 2 "s_register_operand" "r,r,r") + (match_operand:SI 3 "arm_rhs_operand" "rM,rM,rM")])))] + "" + "@ + mov%D5\\t%0, %2%S4 + mov%d5\\t%0, %1\;mov%D5\\t%0, %2%S4 + mvn%d5\\t%0, #%B1\;mov%D5\\t%0, %2%S4" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8")]) + +(define_insn "*ifcompare_shift_shift" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI + (match_operator 7 "comparison_operator" + [(match_operand:SI 5 "s_register_operand" "r") + (match_operand:SI 6 "arm_add_operand" "rIL")]) + (match_operator:SI 8 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")]) + (match_operator:SI 9 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "arm_rhs_operand" "rM")]))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "*if_shift_shift" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand 8 "cc_register" "") (const_int 0)]) + (match_operator:SI 6 "shift_operator" + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "arm_rhs_operand" "rM")]) + (match_operator:SI 7 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "arm_rhs_operand" "rM")])))] + "" + "mov%d5\\t%0, %1%S6\;mov%D5\\t%0, %3%S7" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + +(define_insn "*ifcompare_not_arith" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI + (match_operator 6 "comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r") + (match_operand:SI 5 "arm_add_operand" "rIL")]) + (not:SI (match_operand:SI 1 "s_register_operand" "r")) + (match_operator:SI 7 "shiftable_operator" + [(match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 3 "arm_rhs_operand" "rI")]))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "*if_not_arith" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand 4 "cc_register" "") (const_int 0)]) + (not:SI (match_operand:SI 1 "s_register_operand" "r")) + (match_operator:SI 6 "shiftable_operator" + [(match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 3 "arm_rhs_operand" "rI")])))] + "" + "mvn%d5\\t%0, %1\;%I6%D5\\t%0, %2, %3" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + +(define_insn "*ifcompare_arith_not" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI + (match_operator 6 "comparison_operator" + [(match_operand:SI 4 "s_register_operand" "r") + (match_operand:SI 5 "arm_add_operand" "rIL")]) + (match_operator:SI 7 "shiftable_operator" + [(match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 3 "arm_rhs_operand" "rI")]) + (not:SI (match_operand:SI 1 "s_register_operand" "r")))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +(define_insn "*if_arith_not" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand 4 "cc_register" "") (const_int 0)]) + (match_operator:SI 6 "shiftable_operator" + [(match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 3 "arm_rhs_operand" "rI")]) + (not:SI (match_operand:SI 1 "s_register_operand" "r"))))] + "" + "mvn%D5\\t%0, %1\;%I6%d5\\t%0, %2, %3" +[(set_attr "conds" "use") + (set_attr "length" "8")]) + +(define_insn "*ifcompare_neg_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand:SI 3 "s_register_operand" "r,r") + (match_operand:SI 4 "arm_add_operand" "rIL,rIL")]) + (neg:SI (match_operand:SI 2 "s_register_operand" "r,r")) + (match_operand:SI 1 "arm_not_operand" "0,?rIK"))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_neg_move" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (neg:SI (match_operand:SI 2 "s_register_operand" "r,r,r")) + (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))] + "" + "@ + rsb%d4\\t%0, %2, #0 + mov%D4\\t%0, %1\;rsb%d4\\t%0, %2, #0 + mvn%D4\\t%0, #%B1\;rsb%d4\\t%0, %2, #0" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8")]) + +(define_insn "*ifcompare_move_neg" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI + (match_operator 5 "comparison_operator" + [(match_operand:SI 3 "s_register_operand" "r,r") + (match_operand:SI 4 "arm_add_operand" "rIL,rIL")]) + (match_operand:SI 1 "arm_not_operand" "0,?rIK") + (neg:SI (match_operand:SI 2 "s_register_operand" "r,r")))) + (clobber (reg:CC 24))] + "" + "#" +[(set_attr "conds" "clob") + (set_attr "length" "8,12")]) + +(define_insn "*if_move_neg" + [(set (match_operand:SI 0 "s_register_operand" "=r,r,r") + (if_then_else:SI + (match_operator 4 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_not_operand" "0,?rI,K") + (neg:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))))] + "" + "@ + rsb%D4\\t%0, %2, #0 + mov%d4\\t%0, %1\;rsb%D4\\t%0, %2, #0 + mvn%d4\\t%0, #%B1\;rsb%D4\\t%0, %2, #0" +[(set_attr "conds" "use") + (set_attr "length" "4,8,8")]) + +(define_insn "*arith_adjacentmem" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operator:SI 1 "shiftable_operator" + [(match_operand:SI 2 "memory_operand" "m") + (match_operand:SI 3 "memory_operand" "m")])) + (clobber (match_scratch:SI 4 "=r"))] + "adjacent_mem_locations (operands[2], operands[3])" + "* +{ + rtx ldm[3]; + rtx arith[4]; + int val1 = 0, val2 = 0; + + if (REGNO (operands[0]) > REGNO (operands[4])) + { + ldm[1] = operands[4]; + ldm[2] = operands[0]; + } + else + { + ldm[1] = operands[0]; + ldm[2] = operands[4]; + } + if (GET_CODE (XEXP (operands[2], 0)) != REG) + val1 = INTVAL (XEXP (XEXP (operands[2], 0), 1)); + if (GET_CODE (XEXP (operands[3], 0)) != REG) + val2 = INTVAL (XEXP (XEXP (operands[3], 0), 1)); + arith[0] = operands[0]; + arith[3] = operands[1]; + if (val1 < val2) + { + arith[1] = ldm[1]; + arith[2] = ldm[2]; + } + else + { + arith[1] = ldm[2]; + arith[2] = ldm[1]; + } + if (val1 && val2) + { + rtx ops[3]; + ldm[0] = ops[0] = operands[4]; + ops[1] = XEXP (XEXP (operands[2], 0), 0); + ops[2] = XEXP (XEXP (operands[2], 0), 1); + output_add_immediate (ops); + if (val1 < val2) + output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm); + else + output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm); + } + else if (val1) + { + ldm[0] = XEXP (operands[3], 0); + if (val1 < val2) + output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm); + else + output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm); + } + else + { + ldm[0] = XEXP (operands[2], 0); + if (val1 < val2) + output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm); + else + output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm); + } + output_asm_insn (\"%I3%?\\t%0, %1, %2\", arith); + return \"\"; +} +" +[(set_attr "length" "12") + (set_attr "type" "load")]) + +;; the arm can support extended pre-inc instructions + +;; In all these cases, we use operands 0 and 1 for the register being +;; incremented because those are the operands that local-alloc will +;; tie and these are the pair most likely to be tieable (and the ones +;; that will benefit the most). + +;; We reject the frame pointer if it occurs anywhere in these patterns since +;; elimination will cause too many headaches. + +(define_insn "*strqi_preinc" + [(set (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "index_operand" "rJ"))) + (match_operand:QI 3 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "str%?b\\t%3, [%0, %2]!" +[(set_attr "type" "store1")]) + +(define_insn "*strqi_predec" + [(set (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "r"))) + (match_operand:QI 3 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "str%?b\\t%3, [%0, -%2]!" +[(set_attr "type" "store1")]) + +(define_insn "*loadqi_preinc" + [(set (match_operand:QI 3 "s_register_operand" "=r") + (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "index_operand" "rJ")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?b\\t%3, [%0, %2]!" +[(set_attr "type" "load")]) + +(define_insn "*loadqi_predec" + [(set (match_operand:QI 3 "s_register_operand" "=r") + (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "r")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?b\\t%3, [%0, -%2]!" +[(set_attr "type" "load")]) + +(define_insn "*loadqisi_preinc" + [(set (match_operand:SI 3 "s_register_operand" "=r") + (zero_extend:SI + (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "index_operand" "rJ"))))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?b\\t%3, [%0, %2]!\\t%@ z_extendqisi" +[(set_attr "type" "load")]) + +(define_insn "*loadqisi_predec" + [(set (match_operand:SI 3 "s_register_operand" "=r") + (zero_extend:SI + (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "r"))))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?b\\t%3, [%0, -%2]!\\t%@ z_extendqisi" +[(set_attr "type" "load")]) + +(define_insn "*strsi_preinc" + [(set (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "index_operand" "rJ"))) + (match_operand:SI 3 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "str%?\\t%3, [%0, %2]!" +[(set_attr "type" "store1")]) + +(define_insn "*strqi_predec" + [(set (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "r"))) + (match_operand:SI 3 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "str%?\\t%3, [%0, -%2]!" +[(set_attr "type" "store1")]) + +(define_insn "*loadsi_preinc" + [(set (match_operand:SI 3 "s_register_operand" "=r") + (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "index_operand" "rJ")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?\\t%3, [%0, %2]!" +[(set_attr "type" "load")]) + +(define_insn "*loadsi_predec" + [(set (match_operand:SI 3 "s_register_operand" "=r") + (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "r")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_dup 2)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?\\t%3, [%0, -%2]!" +[(set_attr "type" "load")]) + +(define_insn "*loadhi_preinc" + [(set (match_operand:HI 3 "s_register_operand" "=r") + (mem:HI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "index_operand" "rJ")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_dup 1) (match_dup 2)))] + "(! BYTES_BIG_ENDIAN) + && ! TARGET_SHORT_BY_BYTES + && REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?\\t%3, [%0, %2]!\\t%@ loadhi" +[(set_attr "type" "load")]) + +(define_insn "*loadhi_predec" + [(set (match_operand:HI 3 "s_register_operand" "=r") + (mem:HI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "r")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_dup 2)))] + "(!BYTES_BIG_ENDIAN) + && ! TARGET_SHORT_BY_BYTES + && REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != FRAME_POINTER_REGNUM)" + "ldr%?\\t%3, [%0, -%2]!\\t%@ loadhi" +[(set_attr "type" "load")]) + +(define_insn "*strqi_shiftpreinc" + [(set (mem:QI (plus:SI (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")]) + (match_operand:SI 1 "s_register_operand" "0"))) + (match_operand:QI 5 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) + (match_dup 1)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "str%?b\\t%5, [%0, %3%S2]!" +[(set_attr "type" "store1")]) + +(define_insn "*strqi_shiftpredec" + [(set (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")]))) + (match_operand:QI 5 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) + (match_dup 4)])))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "str%?b\\t%5, [%0, -%3%S2]!" +[(set_attr "type" "store1")]) + +(define_insn "*loadqi_shiftpreinc" + [(set (match_operand:QI 5 "s_register_operand" "=r") + (mem:QI (plus:SI (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")]) + (match_operand:SI 1 "s_register_operand" "0")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) + (match_dup 1)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "ldr%?b\\t%5, [%0, %3%S2]!" +[(set_attr "type" "load")]) + +(define_insn "*loadqi_shiftpredec" + [(set (match_operand:QI 5 "s_register_operand" "=r") + (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")])))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) + (match_dup 4)])))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "ldr%?b\\t%5, [%0, -%3%S2]!" +[(set_attr "type" "load")]) + +(define_insn "*strsi_shiftpreinc" + [(set (mem:SI (plus:SI (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")]) + (match_operand:SI 1 "s_register_operand" "0"))) + (match_operand:SI 5 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) + (match_dup 1)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "str%?\\t%5, [%0, %3%S2]!" +[(set_attr "type" "store1")]) + +(define_insn "*strsi_shiftpredec" + [(set (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")]))) + (match_operand:SI 5 "s_register_operand" "r")) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) + (match_dup 4)])))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "str%?\\t%5, [%0, -%3%S2]!" +[(set_attr "type" "store1")]) + +(define_insn "*loadqi_shiftpreinc" + [(set (match_operand:SI 5 "s_register_operand" "=r") + (mem:SI (plus:SI (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")]) + (match_operand:SI 1 "s_register_operand" "0")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) + (match_dup 1)))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "ldr%?\\t%5, [%0, %3%S2]!" +[(set_attr "type" "load")]) + +(define_insn "*loadqi_shiftpredec" + [(set (match_operand:SI 5 "s_register_operand" "=r") + (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")])))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) + (match_dup 4)])))] + "REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "ldr%?\\t%5, [%0, -%3%S2]!" +[(set_attr "type" "load")]) + +(define_insn "*loadhi_shiftpreinc" + [(set (match_operand:HI 5 "s_register_operand" "=r") + (mem:HI (plus:SI (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")]) + (match_operand:SI 1 "s_register_operand" "0")))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) + (match_dup 1)))] + "(! BYTES_BIG_ENDIAN) + && ! TARGET_SHORT_BY_BYTES + && REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "ldr%?\\t%5, [%0, %3%S2]!\\t%@ loadhi" +[(set_attr "type" "load")]) + +(define_insn "*loadhi_shiftpredec" + [(set (match_operand:HI 5 "s_register_operand" "=r") + (mem:HI (minus:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operator:SI 2 "shift_operator" + [(match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 4 "const_shift_operand" "n")])))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3) + (match_dup 4)])))] + "(! BYTES_BIG_ENDIAN) + && ! TARGET_SHORT_BY_BYTES + && REGNO (operands[0]) != FRAME_POINTER_REGNUM + && REGNO (operands[1]) != FRAME_POINTER_REGNUM + && REGNO (operands[3]) != FRAME_POINTER_REGNUM" + "ldr%?\\t%5, [%0, -%3%S2]!\\t%@ loadhi" +[(set_attr "type" "load")]) + +; It can also support extended post-inc expressions, but combine doesn't +; try these.... +; It doesn't seem worth adding peepholes for anything but the most common +; cases since, unlike combine, the increment must immediately follow the load +; for this pattern to match. +; When loading we must watch to see that the base register isn't trampled by +; the load. In such cases this isn't a post-inc expression. + +(define_peephole + [(set (mem:QI (match_operand:SI 0 "s_register_operand" "+r")) + (match_operand:QI 2 "s_register_operand" "r")) + (set (match_dup 0) + (plus:SI (match_dup 0) (match_operand:SI 1 "index_operand" "rJ")))] + "" + "str%?b\\t%2, [%0], %1") + +(define_peephole + [(set (match_operand:QI 0 "s_register_operand" "=r") + (mem:QI (match_operand:SI 1 "s_register_operand" "+r"))) + (set (match_dup 1) + (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))] + "REGNO(operands[0]) != REGNO(operands[1]) + && (GET_CODE (operands[2]) != REG + || REGNO(operands[0]) != REGNO (operands[2]))" + "ldr%?b\\t%0, [%1], %2") + +(define_peephole + [(set (mem:SI (match_operand:SI 0 "s_register_operand" "+r")) + (match_operand:SI 2 "s_register_operand" "r")) + (set (match_dup 0) + (plus:SI (match_dup 0) (match_operand:SI 1 "index_operand" "rJ")))] + "" + "str%?\\t%2, [%0], %1") + +(define_peephole + [(set (match_operand:HI 0 "s_register_operand" "=r") + (mem:HI (match_operand:SI 1 "s_register_operand" "+r"))) + (set (match_dup 1) + (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))] + "(! BYTES_BIG_ENDIAN) + && ! TARGET_SHORT_BY_BYTES + && REGNO(operands[0]) != REGNO(operands[1]) + && (GET_CODE (operands[2]) != REG + || REGNO(operands[0]) != REGNO (operands[2]))" + "ldr%?\\t%0, [%1], %2\\t%@ loadhi") + +(define_peephole + [(set (match_operand:SI 0 "s_register_operand" "=r") + (mem:SI (match_operand:SI 1 "s_register_operand" "+r"))) + (set (match_dup 1) + (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))] + "REGNO(operands[0]) != REGNO(operands[1]) + && (GET_CODE (operands[2]) != REG + || REGNO(operands[0]) != REGNO (operands[2]))" + "ldr%?\\t%0, [%1], %2") + +(define_peephole + [(set (mem:QI (plus:SI (match_operand:SI 0 "s_register_operand" "+r") + (match_operand:SI 1 "index_operand" "rJ"))) + (match_operand:QI 2 "s_register_operand" "r")) + (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))] + "" + "str%?b\\t%2, [%0, %1]!") + +(define_peephole + [(set (mem:QI (plus:SI (match_operator:SI 4 "shift_operator" + [(match_operand:SI 0 "s_register_operand" "r") + (match_operand:SI 1 "const_int_operand" "n")]) + (match_operand:SI 2 "s_register_operand" "+r"))) + (match_operand:QI 3 "s_register_operand" "r")) + (set (match_dup 2) (plus:SI (match_op_dup 4 [(match_dup 0) (match_dup 1)]) + (match_dup 2)))] + "" + "str%?b\\t%3, [%2, %0%S4]!") + +; This pattern is never tried by combine, so do it as a peephole + +(define_peephole + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operand:SI 1 "s_register_operand" "r")) + (set (reg:CC 24) + (compare:CC (match_dup 1) (const_int 0)))] + "" + "sub%?s\\t%0, %1, #0" +[(set_attr "conds" "set")]) + +; Peepholes to spot possible load- and store-multiples, if the ordering is +; reversed, check that the memory references aren't volatile. + +(define_peephole + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operand:SI 4 "memory_operand" "m")) + (set (match_operand:SI 1 "s_register_operand" "=r") + (match_operand:SI 5 "memory_operand" "m")) + (set (match_operand:SI 2 "s_register_operand" "=r") + (match_operand:SI 6 "memory_operand" "m")) + (set (match_operand:SI 3 "s_register_operand" "=r") + (match_operand:SI 7 "memory_operand" "m"))] + "load_multiple_sequence (operands, 4, NULL, NULL, NULL)" + "* + return emit_ldm_seq (operands, 4); +") + +(define_peephole + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operand:SI 3 "memory_operand" "m")) + (set (match_operand:SI 1 "s_register_operand" "=r") + (match_operand:SI 4 "memory_operand" "m")) + (set (match_operand:SI 2 "s_register_operand" "=r") + (match_operand:SI 5 "memory_operand" "m"))] + "load_multiple_sequence (operands, 3, NULL, NULL, NULL)" + "* + return emit_ldm_seq (operands, 3); +") + +(define_peephole + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operand:SI 2 "memory_operand" "m")) + (set (match_operand:SI 1 "s_register_operand" "=r") + (match_operand:SI 3 "memory_operand" "m"))] + "load_multiple_sequence (operands, 2, NULL, NULL, NULL)" + "* + return emit_ldm_seq (operands, 2); +") + +(define_peephole + [(set (match_operand:SI 4 "memory_operand" "=m") + (match_operand:SI 0 "s_register_operand" "r")) + (set (match_operand:SI 5 "memory_operand" "=m") + (match_operand:SI 1 "s_register_operand" "r")) + (set (match_operand:SI 6 "memory_operand" "=m") + (match_operand:SI 2 "s_register_operand" "r")) + (set (match_operand:SI 7 "memory_operand" "=m") + (match_operand:SI 3 "s_register_operand" "r"))] + "store_multiple_sequence (operands, 4, NULL, NULL, NULL)" + "* + return emit_stm_seq (operands, 4); +") + +(define_peephole + [(set (match_operand:SI 3 "memory_operand" "=m") + (match_operand:SI 0 "s_register_operand" "r")) + (set (match_operand:SI 4 "memory_operand" "=m") + (match_operand:SI 1 "s_register_operand" "r")) + (set (match_operand:SI 5 "memory_operand" "=m") + (match_operand:SI 2 "s_register_operand" "r"))] + "store_multiple_sequence (operands, 3, NULL, NULL, NULL)" + "* + return emit_stm_seq (operands, 3); +") + +(define_peephole + [(set (match_operand:SI 2 "memory_operand" "=m") + (match_operand:SI 0 "s_register_operand" "r")) + (set (match_operand:SI 3 "memory_operand" "=m") + (match_operand:SI 1 "s_register_operand" "r"))] + "store_multiple_sequence (operands, 2, NULL, NULL, NULL)" + "* + return emit_stm_seq (operands, 2); +") + +;; A call followed by return can be replaced by restoring the regs and +;; jumping to the subroutine, provided we aren't passing the address of +;; any of our local variables. If we call alloca then this is unsafe +;; since restoring the frame frees the memory, which is not what we want. +;; Sometimes the return might have been targeted by the final prescan: +;; if so then emit a proper return insn as well. +;; Unfortunately, if the frame pointer is required, we don't know if the +;; current function has any implicit stack pointer adjustments that will +;; be restored by the return: we can't therefore do a tail call. +;; Another unfortunate that we can't handle is if current_function_args_size +;; is non-zero: in this case elimination of the argument pointer assumed +;; that lr was pushed onto the stack, so eliminating upsets the offset +;; calculations. + +(define_peephole + [(parallel [(call (mem:SI (match_operand:SI 0 "" "X")) + (match_operand:SI 1 "general_operand" "g")) + (clobber (reg:SI 14))]) + (return)] + "(GET_CODE (operands[0]) == SYMBOL_REF && USE_RETURN_INSN (FALSE) + && !get_frame_size () && !current_function_calls_alloca + && !frame_pointer_needed && !current_function_args_size)" + "* +{ + extern rtx arm_target_insn; + extern int arm_ccfsm_state; + + if (arm_ccfsm_state && arm_target_insn && INSN_DELETED_P (arm_target_insn)) + { + arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); + output_return_instruction (NULL, TRUE, FALSE); + arm_ccfsm_state = 0; + arm_target_insn = NULL; + } + + output_return_instruction (NULL, FALSE, FALSE); + return \"b%?\\t%a0\"; +}" +[(set_attr "type" "call") + (set_attr "length" "8")]) + +(define_peephole + [(parallel [(set (match_operand 0 "s_register_operand" "=rf") + (call (mem:SI (match_operand:SI 1 "" "X")) + (match_operand:SI 2 "general_operand" "g"))) + (clobber (reg:SI 14))]) + (return)] + "(GET_CODE (operands[1]) == SYMBOL_REF && USE_RETURN_INSN (FALSE) + && !get_frame_size () && !current_function_calls_alloca + && !frame_pointer_needed && !current_function_args_size)" + "* +{ + extern rtx arm_target_insn; + extern int arm_ccfsm_state; + + if (arm_ccfsm_state && arm_target_insn && INSN_DELETED_P (arm_target_insn)) + { + arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); + output_return_instruction (NULL, TRUE, FALSE); + arm_ccfsm_state = 0; + arm_target_insn = NULL; + } + + output_return_instruction (NULL, FALSE, FALSE); + return \"b%?\\t%a1\"; +}" +[(set_attr "type" "call") + (set_attr "length" "8")]) + +;; As above but when this function is not void, we must be returning the +;; result of the called subroutine. + +(define_peephole + [(parallel [(set (match_operand 0 "s_register_operand" "=rf") + (call (mem:SI (match_operand:SI 1 "" "X")) + (match_operand:SI 2 "general_operand" "g"))) + (clobber (reg:SI 14))]) + (use (match_dup 0)) + (return)] + "(GET_CODE (operands[1]) == SYMBOL_REF && USE_RETURN_INSN (FALSE) + && !get_frame_size () && !current_function_calls_alloca + && !frame_pointer_needed && !current_function_args_size)" + "* +{ + extern rtx arm_target_insn; + extern int arm_ccfsm_state; + + if (arm_ccfsm_state && arm_target_insn && INSN_DELETED_P (arm_target_insn)) + { + arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); + output_return_instruction (NULL, TRUE, FALSE); + arm_ccfsm_state = 0; + arm_target_insn = NULL; + } + + output_return_instruction (NULL, FALSE, FALSE); + return \"b%?\\t%a1\"; +}" +[(set_attr "type" "call") + (set_attr "length" "8")]) + +;; CYGNUS LOCAL +;; If calling a subroutine and then jumping back to somewhere else, but not +;; too far away, then we can set the link register with the branch address +;; and jump direct to the subroutine. On return from the subroutine +;; execution continues at the branch; this avoids a prefetch stall. +;; We use the length attribute (via short_branch ()) to establish whether or +;; not this is possible, this is the same as the sparc does. + +(define_peephole + [(parallel[(call (mem:SI (match_operand:SI 0 "" "X")) + (match_operand:SI 1 "general_operand" "g")) + (clobber (reg:SI 14))]) + (set (pc) + (label_ref (match_operand 2 "" "")))] + "0 && GET_CODE (operands[0]) == SYMBOL_REF + && short_branch (INSN_UID (insn), INSN_UID (operands[2])) + && arm_insn_not_targeted (insn)" + "* +{ + int backward = arm_backwards_branch (INSN_UID (insn), + INSN_UID (operands[2])); + +#if 0 + /* Putting this in means that TARGET_6 code will ONLY run on an arm6 or + * above, leaving it out means that the code will still run on an arm 2 or 3 + */ + if (TARGET_6) + { + if (backward) + output_asm_insn (\"sub%?\\t%|lr, %|pc, #(8 + . -%l2)\", operands); + else + output_asm_insn (\"add%?\\t%|lr, %|pc, #(%l2 - . -8)\", operands); + } + else +#endif + { + output_asm_insn (\"mov%?\\t%|lr, %|pc\\t%@ protect cc\", operands); + if (backward) + output_asm_insn (\"sub%?\\t%|lr, %|lr, #(4 + . -%l2)\", operands); + else + output_asm_insn (\"add%?\\t%|lr, %|lr, #(%l2 - . -4)\", operands); + } + return \"b%?\\t%a0\"; +}" +[(set_attr "type" "call") + (set (attr "length") + (if_then_else (eq_attr "prog_mode" "prog32") + (const_int 8) + (const_int 12)))]) + +(define_peephole + [(parallel[(set (match_operand:SI 0 "s_register_operand" "=r") + (call (mem:SI (match_operand:SI 1 "" "X")) + (match_operand:SI 2 "general_operand" "g"))) + (clobber (reg:SI 14))]) + (set (pc) + (label_ref (match_operand 3 "" "")))] + "0 && GET_CODE (operands[0]) == SYMBOL_REF + && short_branch (INSN_UID (insn), INSN_UID (operands[3])) + && arm_insn_not_targeted (insn)" + "* +{ + int backward = arm_backwards_branch (INSN_UID (insn), + INSN_UID (operands[3])); + +#if 0 + /* Putting this in means that TARGET_6 code will ONLY run on an arm6 or + * above, leaving it out means that the code will still run on an arm 2 or 3 + */ + if (TARGET_6) + { + if (backward) + output_asm_insn (\"sub%?\\t%|lr, %|pc, #(8 + . -%l3)\", operands); + else + output_asm_insn (\"add%?\\t%|lr, %|pc, #(%l3 - . -8)\", operands); + } + else +#endif + { + output_asm_insn (\"mov%?\\t%|lr, %|pc\\t%@ protect cc\", operands); + if (backward) + output_asm_insn (\"sub%?\\t%|lr, %|lr, #(4 + . -%l3)\", operands); + else + output_asm_insn (\"add%?\\t%|lr, %|lr, #(%l3 - . -4)\", operands); + } + return \"b%?\\t%a1\"; +}" +[(set_attr "type" "call") + (set (attr "length") + (if_then_else (eq_attr "prog_mode" "prog32") + (const_int 8) + (const_int 12)))]) +;; END CYGNUS LOCAL + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (and:SI (ge:SI (match_operand:SI 1 "s_register_operand" "") + (const_int 0)) + (neg:SI (match_operator:SI 2 "comparison_operator" + [(match_operand:SI 3 "s_register_operand" "") + (match_operand:SI 4 "arm_rhs_operand" "")])))) + (clobber (match_operand:SI 5 "s_register_operand" ""))] + "" + [(set (match_dup 5) (not:SI (ashiftrt:SI (match_dup 1) (const_int 31)))) + (set (match_dup 0) (and:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)]) + (match_dup 5)))] + "") + +;; This split can be used because CC_Z mode implies that the following +;; branch will be an equality, or an unsigned inequality, so the sign +;; extension is not needed. + +(define_split + [(set (reg:CC_Z 24) + (compare:CC_Z + (ashift:SI (subreg:SI (match_operand:QI 0 "memory_operand" "") 0) + (const_int 24)) + (match_operand 1 "const_int_operand" ""))) + (clobber (match_scratch:SI 2 ""))] + "((unsigned HOST_WIDE_INT) INTVAL (operands[1])) + == (((unsigned HOST_WIDE_INT) INTVAL (operands[1])) >> 24) << 24" + [(set (match_dup 2) (zero_extend:SI (match_dup 0))) + (set (reg:CC 24) (compare:CC (match_dup 2) (match_dup 1)))] + " + operands[1] = GEN_INT (((unsigned long) INTVAL (operands[1])) >> 24); +") + +(define_expand "prologue" + [(clobber (const_int 0))] + "" + " + arm_expand_prologue (); + DONE; +") + +;; This split is only used during output to reduce the number of patterns +;; that need assembler instructions adding to them. We allowed the setting +;; of the conditions to be implicit during rtl generation so that +;; the conditional compare patterns would work. However this conflicts to +;; some extent with the conditional data operations, so we have to split them +;; up again here. + +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(match_operand 2 "" "") (match_operand 3 "" "")]) + (match_operand 4 "" "") + (match_operand 5 "" ""))) + (clobber (reg:CC 24))] + "reload_completed" + [(set (match_dup 6) (match_dup 7)) + (set (match_dup 0) + (if_then_else:SI (match_op_dup 1 [(match_dup 6) (const_int 0)]) + (match_dup 4) + (match_dup 5)))] + " +{ + enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]), operands[2], + operands[3]); + + operands[6] = gen_rtx (REG, mode, 24); + operands[7] = gen_rtx (COMPARE, mode, operands[2], operands[3]); +} +") + +;; CYGNUS LOCAL +(define_split + [(set (match_operand:SI 0 "s_register_operand" "") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(match_operand:SI 2 "s_register_operand" "") + (match_operand:SI 3 "arm_add_operand" "")]) + (match_operand:SI 4 "arm_rhs_operand" "") + (not:SI + (match_operand:SI 5 "s_register_operand" "")))) + (clobber (reg:CC 24))] + "reload_completed" + [(set (match_dup 6) (match_dup 7)) + (set (match_dup 0) + (if_then_else:SI (match_op_dup 1 [(match_dup 6) (const_int 0)]) + (match_dup 4) + (not:SI (match_dup 5))))] + " +{ + enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]), operands[2], + operands[3]); + + operands[6] = gen_rtx (REG, mode, 24); + operands[7] = gen_rtx (COMPARE, mode, operands[2], operands[3]); +} +") + +(define_insn "*cond_move_not" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (if_then_else:SI (match_operator 4 "comparison_operator" + [(match_operand 3 "cc_register" "") (const_int 0)]) + (match_operand:SI 1 "arm_rhs_operand" "0,?rI") + (not:SI + (match_operand:SI 2 "s_register_operand" "r,r"))))] + "" + "@ + mvn%D4\\t%0, %2 + mov%d4\\t%0, %1\;mvn%D4\\t%0, %2" +[(set_attr "conds" "use") + (set_attr "length" "4,8")]) +;; END CYGNUS LOCAL + +;; The next two patterns occur when an AND operation is followed by a +;; scc insn sequence + +(define_insn "*sign_extract_onebit" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (sign_extract:SI (match_operand:SI 1 "s_register_operand" "r") + (const_int 1) + (match_operand:SI 2 "const_int_operand" "n")))] + "" + "* + operands[2] = GEN_INT (1 << INTVAL (operands[2])); + output_asm_insn (\"ands\\t%0, %1, %2\", operands); + return \"mvnne\\t%0, #0\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "8")]) + +(define_insn "*not_signextract_onebit" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (not:SI + (sign_extract:SI (match_operand:SI 1 "s_register_operand" "r") + (const_int 1) + (match_operand:SI 2 "const_int_operand" "n"))))] + "" + "* + operands[2] = GEN_INT (1 << INTVAL (operands[2])); + output_asm_insn (\"tst\\t%1, %2\", operands); + output_asm_insn (\"mvneq\\t%0, #0\", operands); + return \"movne\\t%0, #0\"; +" +[(set_attr "conds" "clob") + (set_attr "length" "12")]) + +;; Push multiple registers to the stack. The first register is in the +;; unspec part of the insn; subsequent registers are in parallel (use ...) +;; expressions. +(define_insn "*push_multi" + [(match_parallel 2 "multi_register_push" + [(set (match_operand:BLK 0 "memory_operand" "=m") + (unspec:BLK [(match_operand:SI 1 "s_register_operand" "r")] 2))])] + "" + "* +{ + char pattern[100]; + int i; + extern int lr_save_eliminated; + + if (lr_save_eliminated) + { + if (XVECLEN (operands[2], 0) > 1) + abort (); + return \"\"; + } + strcpy (pattern, \"stmfd\\t%m0!, {%1\"); + for (i = 1; i < XVECLEN (operands[2], 0); i++) + { + strcat (pattern, \", %|\"); + strcat (pattern, reg_names[REGNO (XEXP (XVECEXP (operands[2], 0, i), + 0))]); + } + strcat (pattern, \"}\"); + output_asm_insn (pattern, operands); + return \"\"; +}" +[(set_attr "type" "store4")]) + +;; Similarly for the floating point registers +(define_insn "*push_fp_multi" + [(match_parallel 2 "multi_register_push" + [(set (match_operand:BLK 0 "memory_operand" "=m") + (unspec:BLK [(match_operand:XF 1 "f_register_operand" "f")] 2))])] + "" + "* +{ + char pattern[100]; + int i; + + sprintf (pattern, \"sfmfd\\t%%1, %d, [%%m0]!\", XVECLEN (operands[2], 0)); + output_asm_insn (pattern, operands); + return \"\"; +}" +[(set_attr "type" "f_store")]) + +;; Special patterns for dealing with the constant pool + +(define_insn "consttable_4" + [(unspec_volatile [(match_operand 0 "" "")] 2)] + "" + "* +{ + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) + { + case MODE_FLOAT: + { + union real_extract u; + bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); + assemble_real (u.d, GET_MODE (operands[0])); + break; + } + default: + assemble_integer (operands[0], 4, 1); + break; + } + return \"\"; +}" +[(set_attr "length" "4")]) + +(define_insn "consttable_8" + [(unspec_volatile [(match_operand 0 "" "")] 3)] + "" + "* +{ + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) + { + case MODE_FLOAT: + { + union real_extract u; + bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); + assemble_real (u.d, GET_MODE (operands[0])); + break; + } + default: + assemble_integer (operands[0], 8, 1); + break; + } + return \"\"; +}" +[(set_attr "length" "8")]) + +(define_insn "consttable_end" + [(unspec_volatile [(const_int 0)] 4)] + "" + "* + /* Nothing to do (currently). */ + return \"\"; +") + +(define_insn "align_4" + [(unspec_volatile [(const_int 0)] 5)] + "" + "* + assemble_align (32); + return \"\"; +") diff --git a/gcc_arm/config/arm/coff.h b/gcc_arm/config/arm/coff.h new file mode 100755 index 0000000..13703ca --- /dev/null +++ b/gcc_arm/config/arm/coff.h @@ -0,0 +1,211 @@ +/* Definitions of target machine for GNU compiler, + for ARM with COFF obj format. + Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + Contributed by Doug Evans (dje@cygnus.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "arm/semi.h" +#include "arm/aout.h" + +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "_" + + +/* Run-time Target Specification. */ +#undef TARGET_VERSION +#define TARGET_VERSION fputs (" (ARM/coff)", stderr) + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32) + +/* CYGNUS LOCAL nickc/interworking */ +#define MULTILIB_DEFAULTS { "mlittle-endian", "msoft-float", "mapcs-32", "mno-thumb-interwork" } +/* END CYGNUS LOCAL nickc */ + +/* Setting this to 32 produces more efficient code, but the value set in previous + versions of this toolchain was 8, which produces more compact structures. The + command line option -mstructure_size_boundary= can be used to change this + value. */ +#undef STRUCTURE_SIZE_BOUNDARY +#define STRUCTURE_SIZE_BOUNDARY arm_structure_size_boundary + +extern int arm_structure_size_boundary; + +/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS + is a valid machine specific attribute for DECL. + The attributes in ATTRIBUTES have previously been assigned to DECL. */ +extern int arm_valid_machine_decl_attribute (); +#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \ +arm_valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS) + +/* This is COFF, but prefer stabs. */ +#define SDB_DEBUGGING_INFO + +#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG + +#include "dbxcoff.h" + +/* A C statement to output assembler commands which will identify the + object file as having been compiled with GNU CC (or another GNU + compiler). */ +/* Define this to NULL so we don't get anything. + We have ASM_IDENTIFY_LANGUAGE. + Also, when using stabs, gcc2_compiled must be a stabs entry, not an + ordinary symbol, or gdb won't see it. The stabs entry must be + before the N_SO in order for gdb to find it. */ +#define ASM_IDENTIFY_GCC(STREAM) \ + fprintf (STREAM, "%sgcc2_compiled.:\n", LOCAL_LABEL_PREFIX ) + +/* This outputs a lot of .req's to define alias for various registers. + Let's try to avoid this. */ +#undef ASM_FILE_START +#define ASM_FILE_START(STREAM) \ +do { \ + extern char *version_string; \ + fprintf (STREAM, "%s Generated by gcc %s for ARM/coff\n", \ + ASM_COMMENT_START, version_string); \ +} while (0) + +/* A C statement to output something to the assembler file to switch to section + NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or + NULL_TREE. Some target formats do not support arbitrary sections. Do not + define this macro in such cases. */ +#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ +do { \ + if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ + fprintf (STREAM, "\t.section %s,\"x\"\n", (NAME)); \ + else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ + fprintf (STREAM, "\t.section %s,\"\"\n", (NAME)); \ + else \ + fprintf (STREAM, "\t.section %s,\"w\"\n", (NAME)); \ +} while (0) + +/* Support the ctors/dtors and other sections. */ + +#undef INIT_SECTION_ASM_OP + +/* Define this macro if jump tables (for `tablejump' insns) should be + output in the text section, along with the assembler instructions. + Otherwise, the readonly data section is used. */ +#define JUMP_TABLES_IN_TEXT_SECTION 1 + +#undef READONLY_DATA_SECTION +#define READONLY_DATA_SECTION rdata_section +#undef RDATA_SECTION_ASM_OP +#define RDATA_SECTION_ASM_OP "\t.section .rdata" +#undef CTORS_SECTION_ASM_OP +#define CTORS_SECTION_ASM_OP "\t.section .ctors,\"x\"" +#undef DTORS_SECTION_ASM_OP +#define DTORS_SECTION_ASM_OP "\t.section .dtors,\"x\"" + +/* A list of other sections which the compiler might be "in" at any + given time. */ + +#undef EXTRA_SECTIONS +#define EXTRA_SECTIONS SUBTARGET_EXTRA_SECTIONS in_rdata, in_ctors, in_dtors + +#define SUBTARGET_EXTRA_SECTIONS + +/* A list of extra section function definitions. */ + +#undef EXTRA_SECTION_FUNCTIONS +#define EXTRA_SECTION_FUNCTIONS \ + RDATA_SECTION_FUNCTION \ + CTORS_SECTION_FUNCTION \ + DTORS_SECTION_FUNCTION \ + SUBTARGET_EXTRA_SECTION_FUNCTIONS + +#define SUBTARGET_EXTRA_SECTION_FUNCTIONS + +#define RDATA_SECTION_FUNCTION \ +void \ +rdata_section () \ +{ \ + if (in_section != in_rdata) \ + { \ + fprintf (asm_out_file, "%s\n", RDATA_SECTION_ASM_OP); \ + in_section = in_rdata; \ + } \ +} + +#define CTORS_SECTION_FUNCTION \ +void \ +ctors_section () \ +{ \ + if (in_section != in_ctors) \ + { \ + fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \ + in_section = in_ctors; \ + } \ +} + +#define DTORS_SECTION_FUNCTION \ +void \ +dtors_section () \ +{ \ + if (in_section != in_dtors) \ + { \ + fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \ + in_section = in_dtors; \ + } \ +} + +/* Support the ctors/dtors sections for g++. */ + +#define INT_ASM_OP ".word" + +/* A C statement (sans semicolon) to output an element in the table of + global constructors. */ +#undef ASM_OUTPUT_CONSTRUCTOR +#define ASM_OUTPUT_CONSTRUCTOR(STREAM,NAME) \ +do { \ + ctors_section (); \ + fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} while (0) + +/* A C statement (sans semicolon) to output an element in the table of + global destructors. */ +#undef ASM_OUTPUT_DESTRUCTOR +#define ASM_OUTPUT_DESTRUCTOR(STREAM,NAME) \ +do { \ + dtors_section (); \ + fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} while (0) + +/* __CTOR_LIST__ and __DTOR_LIST__ must be defined by the linker script. */ +#define CTOR_LISTS_DEFINED_EXTERNALLY + +#undef DO_GLOBAL_CTORS_BODY +#undef DO_GLOBAL_DTORS_BODY + +/* If you don't define HAVE_ATEXIT, and the object file format/OS/whatever + does not support constructors/destructors, then gcc implements destructors + by defining its own exit function, which calls the destructors. This gcc + exit function overrides the C library's exit function, and this can cause + all kinds of havoc if the C library has a non-trivial exit function. You + really don't want to use the exit function in libgcc2.c. */ +#define HAVE_ATEXIT + +/* The ARM development system defines __main. */ +#define NAME__MAIN "__gccmain" +#define SYMBOL__MAIN __gccmain diff --git a/gcc_arm/config/arm/ecos-elf.h b/gcc_arm/config/arm/ecos-elf.h new file mode 100755 index 0000000..9fdc64a --- /dev/null +++ b/gcc_arm/config/arm/ecos-elf.h @@ -0,0 +1,29 @@ +/* Definitions for ecos based ARM systems using ELF + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Run-time Target Specification. */ +#define TARGET_VERSION fputs (" (ARM/ELF Ecos)", stderr); + +#define HAS_INIT_SECTION + +#include "unknown-elf.h" + +#undef INVOKE_main + diff --git a/gcc_arm/config/arm/elf.h b/gcc_arm/config/arm/elf.h new file mode 100755 index 0000000..c78b68a --- /dev/null +++ b/gcc_arm/config/arm/elf.h @@ -0,0 +1,374 @@ +/* Definitions of target machine for GNU compiler, + for ARM with ELF obj format. + Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + Contributed by Philip Blundell and + Catherine Moore + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#define OBJECT_FORMAT_ELF + +#ifndef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "." +#endif + +#ifndef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "" +#endif + +#ifndef CPP_PREDEFINES +#define CPP_PREDEFINES "-Darm -Darm_elf -Acpu(arm) -Amachine(arm) -D__ELF__" +#endif + +/* The following macro defines the format used to output the second + operand of the .type assembler directive. Different svr4 assemblers + expect various different forms for this operand. The one given here + is just a default. You may need to override it in your machine- + specific tm.h file (depending upon the particulars of your assembler). */ +#define TYPE_OPERAND_FMT "%s" + +/* Write the extra assembler code needed to declare a function's result. + Most svr4 assemblers don't require any special declaration of the + result value, but there are exceptions. */ +#ifndef ASM_DECLARE_RESULT +#define ASM_DECLARE_RESULT(FILE, RESULT) +#endif + +/* These macros generate the special .type and .size directives which + are used to set the corresponding fields of the linker symbol table + entries in an ELF object file under SVR4. These macros also output + the starting labels for the relevant functions/objects. */ +#define TYPE_ASM_OP ".type" +#define SIZE_ASM_OP ".size" + +/* Write the extra assembler code needed to declare a function properly. + Some svr4 assemblers need to also have something extra said about the + function's return value. We allow for that here. */ +#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ + do { \ + fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \ + assemble_name (FILE, NAME); \ + putc (',', FILE); \ + fprintf (FILE, TYPE_OPERAND_FMT, "function"); \ + putc ('\n', FILE); \ + ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \ + ASM_OUTPUT_LABEL(FILE, NAME); \ + } while (0) + +/* Write the extra assembler code needed to declare an object properly. */ +#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \ + do { \ + fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \ + assemble_name (FILE, NAME); \ + putc (',', FILE); \ + fprintf (FILE, TYPE_OPERAND_FMT, "object"); \ + putc ('\n', FILE); \ + size_directive_output = 0; \ + if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \ + { \ + size_directive_output = 1; \ + fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ + assemble_name (FILE, NAME); \ + putc (',', FILE); \ + fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, \ + int_size_in_bytes (TREE_TYPE (DECL))); \ + fputc ('\n', FILE); \ + } \ + ASM_OUTPUT_LABEL(FILE, NAME); \ + } while (0) + +/* Output the size directive for a decl in rest_of_decl_compilation + in the case where we did not do so before the initializer. + Once we find the error_mark_node, we know that the value of + size_directive_output was set + by ASM_DECLARE_OBJECT_NAME when it was run for the same decl. */ +#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \ +do { \ + char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \ + if (!flag_inhibit_size_directive && DECL_SIZE (DECL) \ + && ! AT_END && TOP_LEVEL \ + && DECL_INITIAL (DECL) == error_mark_node \ + && !size_directive_output) \ + { \ + size_directive_output = 1; \ + fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ + assemble_name (FILE, name); \ + putc (',', FILE); \ + fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, \ + int_size_in_bytes (TREE_TYPE (DECL))); \ + fputc ('\n', FILE); \ + } \ + } while (0) + +/* This is how to declare the size of a function. */ +#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \ + do { \ + if (!flag_inhibit_size_directive) \ + { \ + char label[256]; \ + static int labelno; \ + labelno ++; \ + ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno); \ + ASM_OUTPUT_INTERNAL_LABEL (FILE, "Lfe", labelno); \ + fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ + assemble_name (FILE, (FNAME)); \ + fprintf (FILE, ","); \ + assemble_name (FILE, label); \ + fprintf (FILE, "-"); \ + assemble_name (FILE, (FNAME)); \ + putc ('\n', FILE); \ + } \ + } while (0) + +/* Define this macro if jump tables (for `tablejump' insns) should be + output in the text section, along with the assembler instructions. + Otherwise, the readonly data section is used. */ +#define JUMP_TABLES_IN_TEXT_SECTION 1 + +#ifndef ASM_SPEC +#define ASM_SPEC "%{mbig-endian:-EB} %{mcpu=*:-m%*} %{march=*:-m%*} \ + %{mapcs-*:-mapcs-%*} %{mthumb-interwork:-mthumb-interwork}" +#endif + +#ifndef LINK_SPEC +#define LINK_SPEC "%{mbig-endian:-EB} -X" +#endif + +/* Run-time Target Specification. */ +#ifndef TARGET_VERSION +#define TARGET_VERSION fputs (" (ARM/elf)", stderr) +#endif + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32) +#endif + +#ifndef MULTILIB_DEFAULTS +#define MULTILIB_DEFAULTS { "mlittle-endian", "msoft-float", "mapcs-32", "mno-thumb-interwork", "fno-leading-underscore" } +#endif + +/* Setting this to 32 produces more efficient code, but the value set in previous + versions of this toolchain was 8, which produces more compact structures. The + command line option -mstructure_size_boundary= can be used to change this + value. */ +#undef STRUCTURE_SIZE_BOUNDARY +#define STRUCTURE_SIZE_BOUNDARY arm_structure_size_boundary + +extern int arm_structure_size_boundary; + +/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS + is a valid machine specific attribute for DECL. + The attributes in ATTRIBUTES have previously been assigned to DECL. */ +extern int arm_valid_machine_decl_attribute (); +#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \ +arm_valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS) + + +/* A C statement to output assembler commands which will identify the + object file as having been compiled with GNU CC (or another GNU + compiler). */ +/* Define this to NULL so we don't get anything. + We have ASM_IDENTIFY_LANGUAGE. + Also, when using stabs, gcc2_compiled must be a stabs entry, not an + ordinary symbol, or gdb won't see it. The stabs entry must be + before the N_SO in order for gdb to find it. */ +#ifndef ASM_IDENTIFY_GCC +#define ASM_IDENTIFY_GCC(STREAM) \ + fprintf (STREAM, "%sgcc2_compiled.:\n", LOCAL_LABEL_PREFIX ) +#endif + +/* This outputs a lot of .req's to define alias for various registers. + Let's try to avoid this. */ +#ifndef ASM_FILE_START +#define ASM_FILE_START(STREAM) \ +do { \ + extern char *version_string; \ + fprintf (STREAM, "%s Generated by gcc %s for ARM/elf\n", \ + ASM_COMMENT_START, version_string); \ +} while (0) +#endif + +/* Output an internal label definition. */ +#ifndef ASM_OUTPUT_INTERNAL_LABEL +#define ASM_OUTPUT_INTERNAL_LABEL(STREAM, PREFIX, NUM) \ + do \ + { \ + char *s = (char *) alloca (40 + strlen (PREFIX)); \ + extern int arm_target_label, arm_ccfsm_state; \ + extern rtx arm_target_insn; \ + \ + if (arm_ccfsm_state == 3 && arm_target_label == (NUM) \ + && !strcmp (PREFIX, "L")) \ + { \ + arm_ccfsm_state = 0; \ + arm_target_insn = NULL; \ + } \ + ASM_GENERATE_INTERNAL_LABEL (s, (PREFIX), (NUM)); \ + /* CYGNUS LOCAL nickc */ \ + arm_asm_output_label (STREAM, s); \ + /* END CYGNUS LOCAL */ \ + } while (0) +#endif + +/* Support the ctors/dtors and other sections. */ + +/* Define the pseudo-ops used to switch to the .ctors and .dtors sections. + + Note that we want to give these sections the SHF_WRITE attribute + because these sections will actually contain data (i.e. tables of + addresses of functions in the current root executable or shared library + file) and, in the case of a shared library, the relocatable addresses + will have to be properly resolved/relocated (and then written into) by + the dynamic linker when it actually attaches the given shared library + to the executing process. (Note that on SVR4, you may wish to use the + `-z text' option to the ELF linker, when building a shared library, as + an additional check that you are doing everything right. But if you do + use the `-z text' option when building a shared library, you will get + errors unless the .ctors and .dtors sections are marked as writable + via the SHF_WRITE attribute.) */ +#ifndef CTORS_SECTION_ASM_OP +#define CTORS_SECTION_ASM_OP "\t.section\t.ctors,\"aw\"" +#endif + +#ifndef DTORS_SECTION_ASM_OP +#define DTORS_SECTION_ASM_OP "\t.section\t.dtors,\"aw\"" +#endif + +/* A list of other sections which the compiler might be "in" at any + given time. */ +#ifndef SUBTARGET_EXTRA_SECTIONS +#define SUBTARGET_EXTRA_SECTIONS +#endif + +#ifndef EXTRA_SECTIONS +#define EXTRA_SECTIONS SUBTARGET_EXTRA_SECTIONS in_ctors, in_dtors +#endif + +/* A list of extra section function definitions. */ +#ifndef SUBTARGET_EXTRA_SECTION_FUNCTIONS +#define SUBTARGET_EXTRA_SECTION_FUNCTIONS +#endif + +#ifndef EXTRA_SECTION_FUNCTIONS +#define EXTRA_SECTION_FUNCTIONS \ + SUBTARGET_EXTRA_SECTION_FUNCTIONS \ + CTORS_SECTION_FUNCTION \ + DTORS_SECTION_FUNCTION +#endif + +#ifndef CTORS_SECTION_FUNCTION +#define CTORS_SECTION_FUNCTION \ +void \ +ctors_section () \ +{ \ + if (in_section != in_ctors) \ + { \ + fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \ + in_section = in_ctors; \ + } \ +} +#endif + +#ifndef DTORS_SECTION_FUNCTION +#define DTORS_SECTION_FUNCTION \ +void \ +dtors_section () \ +{ \ + if (in_section != in_dtors) \ + { \ + fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \ + in_section = in_dtors; \ + } \ +} +#endif + +/* Support the ctors/dtors sections for g++. */ +#ifndef INT_ASM_OP +#define INT_ASM_OP ".word" +#endif + +/* A C statement (sans semicolon) to output an element in the table of + global constructors. */ +#ifndef ASM_OUTPUT_CONSTRUCTOR +#define ASM_OUTPUT_CONSTRUCTOR(STREAM,NAME) \ +do { \ + ctors_section (); \ + fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} while (0) +#endif + +/* A C statement (sans semicolon) to output an element in the table of + global destructors. */ +#ifndef ASM_OUTPUT_DESTRUCTOR +#define ASM_OUTPUT_DESTRUCTOR(STREAM,NAME) \ +do { \ + dtors_section (); \ + fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} while (0) +#endif + +/* This is how we tell the assembler that a symbol is weak. */ + +#define ASM_WEAKEN_LABEL(FILE,NAME) \ + do { fputs ("\t.weak\t", FILE); assemble_name (FILE, NAME); \ + fputc ('\n', FILE); } while (0) + +#include "arm/aout.h" + +#define ASM_OUTPUT_UNIQUE_BSS(file, decl, name, size) \ + { \ + int len = strlen (name) + 5; \ + char * string; \ + \ + string = alloca (len + 1); \ + sprintf (string, ".bss.%s", name); \ + \ + named_section (NULL, string, 0); \ + \ + ASM_GLOBALIZE_LABEL (file, name); \ + \ + ASM_OUTPUT_ALIGN (file, \ + floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT)); \ + \ + last_assemble_variable_decl = decl; \ + ASM_DECLARE_OBJECT_NAME (file, name, decl); \ + ASM_OUTPUT_SKIP (file, size ? size : 1); \ + } + +#define ASM_OUTPUT_UNIQUE_LOCAL(file, decl, name, size) \ + do \ + { \ + int len = strlen (name) + 5; \ + char * string; \ + \ + string = alloca (len + 1); \ + sprintf (string, ".bss.%s", name); \ + \ + named_section (NULL, string, 0); \ + \ + ASM_OUTPUT_ALIGN (file, \ + floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT)); \ + ASM_OUTPUT_LABEL (file, name); \ + fprintf (file, "\t.space\t%d\n", size); \ + } \ + while (0) diff --git a/gcc_arm/config/arm/lib1funcs.asm b/gcc_arm/config/arm/lib1funcs.asm new file mode 100755 index 0000000..2b1ac8c --- /dev/null +++ b/gcc_arm/config/arm/lib1funcs.asm @@ -0,0 +1,580 @@ +@ libgcc1 routines for ARM cpu. +@ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk) + +/* Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc. + +This file 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. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file with other programs, and to distribute +those programs without any restriction coming from the use of this +file. (The General Public License restrictions do apply in other +respects; for example, they cover modification of the file, and +distribution when not linked into another program.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with other files, + some of which are compiled with GCC, to produce an executable, + this library does not by itself cause the resulting executable + to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#ifdef __APCS_26__ +#define RET movs +#define RETc(x) mov##x##s +#define RETCOND ^ +#else +#define RET mov +#define RETc(x) mov##x +#define RETCOND +#endif + +#ifndef __USER_LABEL_PREFIX__ +#error __USER_LABEL_PREFIX__ not defined +#endif + +/* ANSI concatenation macros. */ + +#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +/* Use the right prefix for global labels. */ + +#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) + +#ifdef __elf__ +#define __PLT__ (PLT) +#define TYPE(x) .type SYM(x),function +#define SIZE(x) .size SYM(x), . - SYM(x) +#else +#define __PLT__ +#define TYPE(x) +#define SIZE(x) +#endif + +#ifdef L_udivsi3 + +dividend .req r0 +divisor .req r1 +result .req r2 +curbit .req r3 +ip .req r12 +sp .req r13 +lr .req r14 +pc .req r15 + + .text + .globl SYM (__udivsi3) + TYPE (__udivsi3) + .align 0 + +SYM (__udivsi3): + cmp divisor, #0 + beq Ldiv0 + mov curbit, #1 + mov result, #0 + cmp dividend, divisor + bcc Lgot_result +Loop1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, #0x10000000 + cmpcc divisor, dividend + movcc divisor, divisor, lsl #4 + movcc curbit, curbit, lsl #4 + bcc Loop1 + +Lbignum: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + cmp divisor, #0x80000000 + cmpcc divisor, dividend + movcc divisor, divisor, lsl #1 + movcc curbit, curbit, lsl #1 + bcc Lbignum + +Loop3: + @ Test for possible subtractions, and note which bits + @ are done in the result. On the final pass, this may subtract + @ too much from the dividend, but the result will be ok, since the + @ "bit" will have been shifted out at the bottom. + cmp dividend, divisor + subcs dividend, dividend, divisor + orrcs result, result, curbit + cmp dividend, divisor, lsr #1 + subcs dividend, dividend, divisor, lsr #1 + orrcs result, result, curbit, lsr #1 + cmp dividend, divisor, lsr #2 + subcs dividend, dividend, divisor, lsr #2 + orrcs result, result, curbit, lsr #2 + cmp dividend, divisor, lsr #3 + subcs dividend, dividend, divisor, lsr #3 + orrcs result, result, curbit, lsr #3 + cmp dividend, #0 @ Early termination? + movnes curbit, curbit, lsr #4 @ No, any more bits to do? + movne divisor, divisor, lsr #4 + bne Loop3 +Lgot_result: + mov r0, result + RET pc, lr + +Ldiv0: + str lr, [sp, #-4]! + bl SYM (__div0) __PLT__ + mov r0, #0 @ about as wrong as it could be + ldmia sp!, {pc}RETCOND + + SIZE (__udivsi3) + +#endif /* L_udivsi3 */ + +#ifdef L_umodsi3 + +dividend .req r0 +divisor .req r1 +overdone .req r2 +curbit .req r3 +ip .req r12 +sp .req r13 +lr .req r14 +pc .req r15 + + .text + .globl SYM (__umodsi3) + TYPE (__umodsi3) + .align 0 + +SYM (__umodsi3): + cmp divisor, #0 + beq Ldiv0 + mov curbit, #1 + cmp dividend, divisor + RETc(cc) pc, lr +Loop1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, #0x10000000 + cmpcc divisor, dividend + movcc divisor, divisor, lsl #4 + movcc curbit, curbit, lsl #4 + bcc Loop1 + +Lbignum: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + cmp divisor, #0x80000000 + cmpcc divisor, dividend + movcc divisor, divisor, lsl #1 + movcc curbit, curbit, lsl #1 + bcc Lbignum + +Loop3: + @ Test for possible subtractions. On the final pass, this may + @ subtract too much from the dividend, so keep track of which + @ subtractions are done, we can fix them up afterwards... + mov overdone, #0 + cmp dividend, divisor + subcs dividend, dividend, divisor + cmp dividend, divisor, lsr #1 + subcs dividend, dividend, divisor, lsr #1 + orrcs overdone, overdone, curbit, ror #1 + cmp dividend, divisor, lsr #2 + subcs dividend, dividend, divisor, lsr #2 + orrcs overdone, overdone, curbit, ror #2 + cmp dividend, divisor, lsr #3 + subcs dividend, dividend, divisor, lsr #3 + orrcs overdone, overdone, curbit, ror #3 + mov ip, curbit + cmp dividend, #0 @ Early termination? + movnes curbit, curbit, lsr #4 @ No, any more bits to do? + movne divisor, divisor, lsr #4 + bne Loop3 + + @ Any subtractions that we should not have done will be recorded in + @ the top three bits of "overdone". Exactly which were not needed + @ are governed by the position of the bit, stored in ip. + @ If we terminated early, because dividend became zero, + @ then none of the below will match, since the bit in ip will not be + @ in the bottom nibble. + ands overdone, overdone, #0xe0000000 + RETc(eq) pc, lr @ No fixups needed + tst overdone, ip, ror #3 + addne dividend, dividend, divisor, lsr #3 + tst overdone, ip, ror #2 + addne dividend, dividend, divisor, lsr #2 + tst overdone, ip, ror #1 + addne dividend, dividend, divisor, lsr #1 + RET pc, lr + +Ldiv0: + str lr, [sp, #-4]! + bl SYM (__div0) __PLT__ + mov r0, #0 @ about as wrong as it could be + ldmia sp!, {pc}RETCOND + + SIZE (__umodsi3) + +#endif /* L_umodsi3 */ + +#ifdef L_divsi3 + +dividend .req r0 +divisor .req r1 +result .req r2 +curbit .req r3 +ip .req r12 +sp .req r13 +lr .req r14 +pc .req r15 + + .text + .globl SYM (__divsi3) + TYPE (__divsi3) + .align 0 + +SYM (__divsi3): + eor ip, dividend, divisor @ Save the sign of the result. + mov curbit, #1 + mov result, #0 + cmp divisor, #0 + rsbmi divisor, divisor, #0 @ Loops below use unsigned. + beq Ldiv0 + cmp dividend, #0 + rsbmi dividend, dividend, #0 + cmp dividend, divisor + bcc Lgot_result + +Loop1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, #0x10000000 + cmpcc divisor, dividend + movcc divisor, divisor, lsl #4 + movcc curbit, curbit, lsl #4 + bcc Loop1 + +Lbignum: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + cmp divisor, #0x80000000 + cmpcc divisor, dividend + movcc divisor, divisor, lsl #1 + movcc curbit, curbit, lsl #1 + bcc Lbignum + +Loop3: + @ Test for possible subtractions, and note which bits + @ are done in the result. On the final pass, this may subtract + @ too much from the dividend, but the result will be ok, since the + @ "bit" will have been shifted out at the bottom. + cmp dividend, divisor + subcs dividend, dividend, divisor + orrcs result, result, curbit + cmp dividend, divisor, lsr #1 + subcs dividend, dividend, divisor, lsr #1 + orrcs result, result, curbit, lsr #1 + cmp dividend, divisor, lsr #2 + subcs dividend, dividend, divisor, lsr #2 + orrcs result, result, curbit, lsr #2 + cmp dividend, divisor, lsr #3 + subcs dividend, dividend, divisor, lsr #3 + orrcs result, result, curbit, lsr #3 + cmp dividend, #0 @ Early termination? + movnes curbit, curbit, lsr #4 @ No, any more bits to do? + movne divisor, divisor, lsr #4 + bne Loop3 +Lgot_result: + mov r0, result + cmp ip, #0 + rsbmi r0, r0, #0 + RET pc, lr + +Ldiv0: + str lr, [sp, #-4]! + bl SYM (__div0) __PLT__ + mov r0, #0 @ about as wrong as it could be + ldmia sp!, {pc}RETCOND + + SIZE (__divsi3) + +#endif /* L_divsi3 */ + +#ifdef L_modsi3 + +dividend .req r0 +divisor .req r1 +overdone .req r2 +curbit .req r3 +ip .req r12 +sp .req r13 +lr .req r14 +pc .req r15 + + .text + .globl SYM (__modsi3) + TYPE (__modsi3) + .align 0 + +SYM (__modsi3): + mov curbit, #1 + cmp divisor, #0 + rsbmi divisor, divisor, #0 @ Loops below use unsigned. + beq Ldiv0 + @ Need to save the sign of the dividend, unfortunately, we need + @ ip later on; this is faster than pushing lr and using that. + str dividend, [sp, #-4]! + cmp dividend, #0 + rsbmi dividend, dividend, #0 + cmp dividend, divisor + bcc Lgot_result + +Loop1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, #0x10000000 + cmpcc divisor, dividend + movcc divisor, divisor, lsl #4 + movcc curbit, curbit, lsl #4 + bcc Loop1 + +Lbignum: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + cmp divisor, #0x80000000 + cmpcc divisor, dividend + movcc divisor, divisor, lsl #1 + movcc curbit, curbit, lsl #1 + bcc Lbignum + +Loop3: + @ Test for possible subtractions. On the final pass, this may + @ subtract too much from the dividend, so keep track of which + @ subtractions are done, we can fix them up afterwards... + mov overdone, #0 + cmp dividend, divisor + subcs dividend, dividend, divisor + cmp dividend, divisor, lsr #1 + subcs dividend, dividend, divisor, lsr #1 + orrcs overdone, overdone, curbit, ror #1 + cmp dividend, divisor, lsr #2 + subcs dividend, dividend, divisor, lsr #2 + orrcs overdone, overdone, curbit, ror #2 + cmp dividend, divisor, lsr #3 + subcs dividend, dividend, divisor, lsr #3 + orrcs overdone, overdone, curbit, ror #3 + mov ip, curbit + cmp dividend, #0 @ Early termination? + movnes curbit, curbit, lsr #4 @ No, any more bits to do? + movne divisor, divisor, lsr #4 + bne Loop3 + + @ Any subtractions that we should not have done will be recorded in + @ the top three bits of "overdone". Exactly which were not needed + @ are governed by the position of the bit, stored in ip. + @ If we terminated early, because dividend became zero, + @ then none of the below will match, since the bit in ip will not be + @ in the bottom nibble. + ands overdone, overdone, #0xe0000000 + beq Lgot_result + tst overdone, ip, ror #3 + addne dividend, dividend, divisor, lsr #3 + tst overdone, ip, ror #2 + addne dividend, dividend, divisor, lsr #2 + tst overdone, ip, ror #1 + addne dividend, dividend, divisor, lsr #1 +Lgot_result: + ldr ip, [sp], #4 + cmp ip, #0 + rsbmi dividend, dividend, #0 + RET pc, lr + +Ldiv0: + str lr, [sp, #-4]! + bl SYM (__div0) __PLT__ + mov r0, #0 @ about as wrong as it could be + ldmia sp!, {pc}RETCOND + + SIZE (__modsi3) + +#endif /* L_modsi3 */ + +#ifdef L_dvmd_tls + + .globl SYM (__div0) + TYPE (__div0) + .align 0 +SYM (__div0): + RET pc, lr + + SIZE (__div0) + +#endif /* L_divmodsi_tools */ + +#ifdef L_dvmd_lnx +@ GNU/Linux division-by zero handler. Used in place of L_dvmd_tls + +#include + +#define SIGFPE 8 @ cant use as it + @ contains too much C rubbish + .globl SYM (__div0) + TYPE (__div0) + .align 0 +SYM (__div0): + stmfd sp!, {r1, lr} + swi __NR_getpid + cmn r0, #1000 + ldmhsfd sp!, {r1, pc}RETCOND @ not much we can do + mov r1, #SIGFPE + swi __NR_kill + ldmfd sp!, {r1, pc}RETCOND + + SIZE (__div0) + +#endif /* L_dvmd_lnx */ + +/* These next two sections are here despite the fact that they contain Thumb + assembler because their presence allows interworked code to be linked even + when the GCC library is this one. */ + +#ifdef L_call_via_rX + +/* These labels & instructions are used by the Arm/Thumb interworking code. + The address of function to be called is loaded into a register and then + one of these labels is called via a BL instruction. This puts the + return address into the link register with the bottom bit set, and the + code here switches to the correct mode before executing the function. */ + + .text + .align 0 + .force_thumb +.macro call_via register + .globl SYM (_call_via_\register) + TYPE (_call_via_\register) + .thumb_func +SYM (_call_via_\register): + bx \register + nop + + SIZE (_call_via_\register) +.endm + + call_via r0 + call_via r1 + call_via r2 + call_via r3 + call_via r4 + call_via r5 + call_via r6 + call_via r7 + call_via r8 + call_via r9 + call_via sl + call_via fp + call_via ip + call_via sp + call_via lr + +#endif /* L_call_via_rX */ + +#ifdef L_interwork_call_via_rX + +/* These labels & instructions are used by the Arm/Thumb interworking code, + when the target address is in an unknown instruction set. The address + of function to be called is loaded into a register and then one of these + labels is called via a BL instruction. This puts the return address + into the link register with the bottom bit set, and the code here + switches to the correct mode before executing the function. Unfortunately + the target code cannot be relied upon to return via a BX instruction, so + instead we have to store the resturn address on the stack and allow the + called function to return here instead. Upon return we recover the real + return address and use a BX to get back to Thumb mode. */ + + .text + .align 0 + + .code 32 + .globl _arm_return +_arm_return: + ldmia r13!, {r12} + bx r12 + .code 16 + +.macro interwork register + .code 16 + .globl SYM (_interwork_call_via_\register) + TYPE (_interwork_call_via_\register) + .thumb_func +SYM (_interwork_call_via_\register): + bx pc + nop + + .code 32 + .globl .Lchange_\register +.Lchange_\register: + tst \register, #1 + stmeqdb r13!, {lr} + adreq lr, _arm_return + bx \register + + SIZE (_interwork_call_via_\register) +.endm + + interwork r0 + interwork r1 + interwork r2 + interwork r3 + interwork r4 + interwork r5 + interwork r6 + interwork r7 + interwork r8 + interwork r9 + interwork sl + interwork fp + interwork ip + interwork sp + + /* The lr case has to be handled a little differently...*/ + .code 16 + .globl SYM (_interwork_call_via_lr) + TYPE (_interwork_call_via_lr) + .thumb_func +SYM (_interwork_call_via_lr): + bx pc + nop + + .code 32 + .globl .Lchange_lr +.Lchange_lr: + tst lr, #1 + stmeqdb r13!, {lr} + mov ip, lr + adreq lr, _arm_return + bx ip + + SIZE (_interwork_call_via_lr) + +#endif /* L_interwork_call_via_rX */ diff --git a/gcc_arm/config/arm/lib1thumb.asm b/gcc_arm/config/arm/lib1thumb.asm new file mode 100755 index 0000000..1789356 --- /dev/null +++ b/gcc_arm/config/arm/lib1thumb.asm @@ -0,0 +1,572 @@ +@ libgcc1 routines for ARM cpu. +@ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk) + +/* Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc. + +This file 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. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file with other programs, and to distribute +those programs without any restriction coming from the use of this +file. (The General Public License restrictions do apply in other +respects; for example, they cover modification of the file, and +distribution when not linked into another program.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with other files, + some of which are compiled with GCC, to produce an executable, + this library does not by itself cause the resulting executable + to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + + .code 16 + +#ifndef __USER_LABEL_PREFIX__ +#error __USER_LABEL_PREFIX__ not defined +#endif + +/* ANSI concatenation macros. */ + +#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +/* Use the right prefix for global labels. */ + +#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) + +#define __PLT__ + +#ifdef __ELF__ +#define TYPE(x) .type SYM(x),function +#define SIZE(x) .size SYM(x), . - SYM(x) +#else +#define TYPE(x) +#define SIZE(x) +#endif + +/* Function end macros. Variants for interworking. */ + +# define __THUMB_INTERWORK__ +# ifdef __THUMB_INTERWORK__ +# define RET bx lr +# define RETc(x) bx##x lr +.macro THUMB_LDIV0 +.Ldiv0: + push { lr } + bl SYM (__div0) + mov r0, #0 @ About as wrong as it could be. + pop { r1 } + bx r1 +.endm +# else +# define RET mov pc, lr +# define RETc(x) mov##x pc, lr +.macro THUMB_LDIV0 +.Ldiv0: + push { lr } + bl SYM (__div0) + mov r0, #0 @ About as wrong as it could be. + pop { pc } +.endm +# endif +# define RETCOND + +.macro FUNC_END name +.Ldiv0: + THUMB_LDIV0 + SIZE (__\name) +.endm + +.macro THUMB_FUNC_START name + .globl SYM (\name) + TYPE (\name) + .thumb_func +SYM (\name): +.endm + +/* Function start macros. */ + +#define THUMB_FUNC .thumb_func +#define THUMB_CODE .force_thumb + +.macro FUNC_START name + .text + .globl SYM (__\name) + TYPE (__\name) + .align 0 + THUMB_CODE + THUMB_FUNC +SYM (__\name): +.endm + +/* Register aliases. */ + +work .req r4 @ XXXX is this safe ? +dividend .req r0 +divisor .req r1 +overdone .req r2 +result .req r2 +curbit .req r3 +ip .req r12 +sp .req r13 +lr .req r14 +pc .req r15 + +/* ------------------------------------------------------------------------ */ +/* Bodies of the divsion and modulo routines. */ +/* ------------------------------------------------------------------------ */ +.macro THUMB_DIV_MOD_BODY modulo + @ Load the constant 0x10000000 into our work register. + mov work, #1 + lsl work, #28 +.Loop1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, work + bhs .Lbignum + cmp divisor, dividend + bhs .Lbignum + lsl divisor, #4 + lsl curbit, #4 + b .Loop1 +.Lbignum: + @ Set work to 0x80000000 + lsl work, #3 +.Loop2: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + cmp divisor, work + bhs .Loop3 + cmp divisor, dividend + bhs .Loop3 + lsl divisor, #1 + lsl curbit, #1 + b .Loop2 +.Loop3: + @ Test for possible subtractions ... + .if \modulo + @ ... On the final pass, this may subtract too much from the dividend, + @ so keep track of which subtractions are done, we can fix them up + @ afterwards. + mov overdone, #0 + cmp dividend, divisor + blo .Lover1 + sub dividend, dividend, divisor +.Lover1: + lsr work, divisor, #1 + cmp dividend, work + blo .Lover2 + sub dividend, dividend, work + mov ip, curbit + mov work, #1 + ror curbit, work + orr overdone, curbit + mov curbit, ip +.Lover2: + lsr work, divisor, #2 + cmp dividend, work + blo .Lover3 + sub dividend, dividend, work + mov ip, curbit + mov work, #2 + ror curbit, work + orr overdone, curbit + mov curbit, ip +.Lover3: + lsr work, divisor, #3 + cmp dividend, work + blo .Lover4 + sub dividend, dividend, work + mov ip, curbit + mov work, #3 + ror curbit, work + orr overdone, curbit + mov curbit, ip +.Lover4: + mov ip, curbit + .else + @ ... and note which bits are done in the result. On the final pass, + @ this may subtract too much from the dividend, but the result will be ok, + @ since the "bit" will have been shifted out at the bottom. + cmp dividend, divisor + blo .Lover1 + sub dividend, dividend, divisor + orr result, result, curbit +.Lover1: + lsr work, divisor, #1 + cmp dividend, work + blo .Lover2 + sub dividend, dividend, work + lsr work, curbit, #1 + orr result, work +.Lover2: + lsr work, divisor, #2 + cmp dividend, work + blo .Lover3 + sub dividend, dividend, work + lsr work, curbit, #2 + orr result, work +.Lover3: + lsr work, divisor, #3 + cmp dividend, work + blo .Lover4 + sub dividend, dividend, work + lsr work, curbit, #3 + orr result, work +.Lover4: + .endif + + cmp dividend, #0 @ Early termination? + beq .Lover5 + lsr curbit, #4 @ No, any more bits to do? + beq .Lover5 + lsr divisor, #4 + b .Loop3 +.Lover5: + .if \modulo + @ Any subtractions that we should not have done will be recorded in + @ the top three bits of "overdone". Exactly which were not needed + @ are governed by the position of the bit, stored in ip. + mov work, #0xe + lsl work, #28 + and overdone, work + beq .Lgot_result + + @ If we terminated early, because dividend became zero, then the + @ bit in ip will not be in the bottom nibble, and we should not + @ perform the additions below. We must test for this though + @ (rather relying upon the TSTs to prevent the additions) since + @ the bit in ip could be in the top two bits which might then match + @ with one of the smaller RORs. + mov curbit, ip + mov work, #0x7 + tst curbit, work + beq .Lgot_result + + mov curbit, ip + mov work, #3 + ror curbit, work + tst overdone, curbit + beq .Lover6 + lsr work, divisor, #3 + add dividend, work +.Lover6: + mov curbit, ip + mov work, #2 + ror curbit, work + tst overdone, curbit + beq .Lover7 + lsr work, divisor, #2 + add dividend, work +.Lover7: + mov curbit, ip + mov work, #1 + ror curbit, work + tst overdone, curbit + beq .Lgot_result + lsr work, divisor, #1 + add dividend, work + .endif +.Lgot_result: +.endm +/* ------------------------------------------------------------------------ */ +/* Start of the Real Functions */ +/* ------------------------------------------------------------------------ */ +#ifdef L_udivsi3 + + FUNC_START udivsi3 + + cmp divisor, #0 + beq .Ldiv0 + mov curbit, #1 + mov result, #0 + + push { work } + cmp dividend, divisor + blo .Lgot_result + + THUMB_DIV_MOD_BODY 0 + + mov r0, result + pop { work } + RET + + FUNC_END udivsi3 + +#endif /* L_udivsi3 */ +/* ------------------------------------------------------------------------ */ +#ifdef L_umodsi3 + + FUNC_START umodsi3 + + cmp divisor, #0 + beq .Ldiv0 + mov curbit, #1 + cmp dividend, divisor + bhs ..Lover10 + RET + +..Lover10: + push { work } + + THUMB_DIV_MOD_BODY 1 + + pop { work } + RET + + FUNC_END umodsi3 + +#endif /* L_umodsi3 */ +/* ------------------------------------------------------------------------ */ +#ifdef L_divsi3 + + FUNC_START divsi3 + + cmp divisor, #0 + beq .Ldiv0 + + push { work } + mov work, dividend + eor work, divisor @ Save the sign of the result. + mov ip, work + mov curbit, #1 + mov result, #0 + cmp divisor, #0 + bpl .Lover10 + neg divisor, divisor @ Loops below use unsigned. +.Lover10: + cmp dividend, #0 + bpl .Lover11 + neg dividend, dividend +.Lover11: + cmp dividend, divisor + blo .Lgot_result + + THUMB_DIV_MOD_BODY 0 + + mov r0, result + mov work, ip + cmp work, #0 + bpl .Lover12 + neg r0, r0 +.Lover12: + pop { work } + RET + + FUNC_END divsi3 + +#endif /* L_divsi3 */ +/* ------------------------------------------------------------------------ */ +#ifdef L_modsi3 + + FUNC_START modsi3 + + mov curbit, #1 + cmp divisor, #0 + beq .Ldiv0 + bpl .Lover10 + neg divisor, divisor @ Loops below use unsigned. + +.Lover10: + push { work } + @ Need to save the sign of the dividend, unfortunately, we need + @ work later on. Must do this after saving the original value of + @ the work register, because we will pop this value off first. + push { dividend } + cmp dividend, #0 + bpl .Lover11 + neg dividend, dividend +.Lover11: + cmp dividend, divisor + blo .Lgot_result + + THUMB_DIV_MOD_BODY 1 + + pop { work } + cmp work, #0 + bpl .Lover12 + neg dividend, dividend +.Lover12: + pop { work } + RET + + FUNC_END modsi3 + +#endif /* L_modsi3 */ +/* ------------------------------------------------------------------------ */ +#ifdef L_dvmd_tls + + FUNC_START div0 + + RET + + SIZE (__div0) + +#endif /* L_divmodsi_tools */ +/* ------------------------------------------------------------------------ */ +#ifdef L_dvmd_lnx +@ GNU/Linux division-by zero handler. Used in place of L_dvmd_tls + +#include + +#define SIGFPE 8 @ cant use as it + @ contains too much C rubbish + FUNC_START div0 + + stmfd sp!, {r1, lr} + swi __NR_getpid + cmn r0, #1000 + ldmhsfd sp!, {r1, pc}RETCOND @ not much we can do + mov r1, #SIGFPE + swi __NR_kill +#ifdef __THUMB_INTERWORK__ + ldmfd sp!, {r1, lr} + bx lr +#else + ldmfd sp!, {r1, pc}RETCOND +#endif + + SIZE (__div0) + +#endif /* L_dvmd_lnx */ +/* ------------------------------------------------------------------------ */ +/* These next two sections are here despite the fact that they contain Thumb + assembler because their presence allows interworked code to be linked even + when the GCC library is this one. */ + +/* Do not build the interworking functions when the target architecture does + not support Thumb instructions. (This can be a multilib option). */ +#if defined L_call_via_rX + +/* These labels & instructions are used by the Arm/Thumb interworking code. + The address of function to be called is loaded into a register and then + one of these labels is called via a BL instruction. This puts the + return address into the link register with the bottom bit set, and the + code here switches to the correct mode before executing the function. */ + + .text + .align 0 + .force_thumb + +.macro call_via register + THUMB_FUNC_START _call_via_\register + + bx \register + nop + + SIZE (_call_via_\register) +.endm + + call_via r0 + call_via r1 + call_via r2 + call_via r3 + call_via r4 + call_via r5 + call_via r6 + call_via r7 + call_via r8 + call_via r9 + call_via sl + call_via fp + call_via ip + call_via sp + call_via lr + +#endif /* L_call_via_rX */ +/* ------------------------------------------------------------------------ */ +/* Do not build the interworking functions when the target architecture does + not support Thumb instructions. (This can be a multilib option). */ +#if defined L_interwork_call_via_rX + +/* These labels & instructions are used by the Arm/Thumb interworking code, + when the target address is in an unknown instruction set. The address + of function to be called is loaded into a register and then one of these + labels is called via a BL instruction. This puts the return address + into the link register with the bottom bit set, and the code here + switches to the correct mode before executing the function. Unfortunately + the target code cannot be relied upon to return via a BX instruction, so + instead we have to store the resturn address on the stack and allow the + called function to return here instead. Upon return we recover the real + return address and use a BX to get back to Thumb mode. */ + + .text + .align 0 + + .code 32 + .globl _arm_return +_arm_return: + ldmia r13!, {r12} + bx r12 + .code 16 + +.macro interwork register + .code 16 + + THUMB_FUNC_START _interwork_call_via_\register + + bx pc + nop + + .code 32 + .globl .Lchange_\register +.Lchange_\register: + tst \register, #1 + stmeqdb r13!, {lr} + adreq lr, _arm_return + bx \register + + SIZE (_interwork_call_via_\register) +.endm + + interwork r0 + interwork r1 + interwork r2 + interwork r3 + interwork r4 + interwork r5 + interwork r6 + interwork r7 + interwork r8 + interwork r9 + interwork sl + interwork fp + interwork ip + interwork sp + + /* The LR case has to be handled a little differently... */ + .code 16 + + THUMB_FUNC_START _interwork_call_via_lr + + bx pc + nop + + .code 32 + .globl .Lchange_lr +.Lchange_lr: + tst lr, #1 + stmeqdb r13!, {lr} + mov ip, lr + adreq lr, _arm_return + bx ip + + SIZE (_interwork_call_via_lr) + +#endif /* L_interwork_call_via_rX */ diff --git a/gcc_arm/config/arm/lib1thumb_981111.asm b/gcc_arm/config/arm/lib1thumb_981111.asm new file mode 100755 index 0000000..dcabcf4 --- /dev/null +++ b/gcc_arm/config/arm/lib1thumb_981111.asm @@ -0,0 +1,747 @@ +@ libgcc1 routines for ARM cpu. +@ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk) + +/* Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc. + +This file 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. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file with other programs, and to distribute +those programs without any restriction coming from the use of this +file. (The General Public License restrictions do apply in other +respects; for example, they cover modification of the file, and +distribution when not linked into another program.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with other files, + some of which are compiled with GCC, to produce an executable, + this library does not by itself cause the resulting executable + to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + + .code 16 + +#ifndef __USER_LABEL_PREFIX__ +#error __USER_LABEL_PREFIX__ not defined +#endif + +#ifdef __elf__ +#define __PLT__ (PLT) +#define TYPE(x) .type SYM(x),function +#define SIZE(x) .size SYM(x), . - SYM(x) +#else +#define __PLT__ +#define TYPE(x) +#define SIZE(x) +#endif + +#define RET mov pc, lr + +/* ANSI concatenation macros. */ + +#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +/* Use the right prefix for global labels. */ + +#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) + +work .req r4 @ XXXX is this safe ? + +#ifdef L_udivsi3 + +dividend .req r0 +divisor .req r1 +result .req r2 +curbit .req r3 +ip .req r12 +sp .req r13 +lr .req r14 +pc .req r15 + + .text + .globl SYM (__udivsi3) + TYPE (__udivsi3) + .align 0 + .thumb_func +SYM (__udivsi3): + cmp divisor, #0 + beq Ldiv0 + mov curbit, #1 + mov result, #0 + + push { work } + cmp dividend, divisor + bcc Lgot_result + + @ Load the constant 0x10000000 into our work register + mov work, #1 + lsl work, #28 +Loop1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, work + bcs Lbignum + cmp divisor, dividend + bcs Lbignum + lsl divisor, #4 + lsl curbit, #4 + b Loop1 + +Lbignum: + @ Set work to 0x80000000 + lsl work, #3 +Loop2: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + cmp divisor, work + bcs Loop3 + cmp divisor, dividend + bcs Loop3 + lsl divisor, #1 + lsl curbit, #1 + b Loop2 + +Loop3: + @ Test for possible subtractions, and note which bits + @ are done in the result. On the final pass, this may subtract + @ too much from the dividend, but the result will be ok, since the + @ "bit" will have been shifted out at the bottom. + cmp dividend, divisor + bcc Over1 + sub dividend, dividend, divisor + orr result, result, curbit +Over1: + lsr work, divisor, #1 + cmp dividend, work + bcc Over2 + sub dividend, dividend, work + lsr work, curbit, #1 + orr result, work +Over2: + lsr work, divisor, #2 + cmp dividend, work + bcc Over3 + sub dividend, dividend, work + lsr work, curbit, #2 + orr result, work +Over3: + lsr work, divisor, #3 + cmp dividend, work + bcc Over4 + sub dividend, dividend, work + lsr work, curbit, #3 + orr result, work +Over4: + cmp dividend, #0 @ Early termination? + beq Lgot_result + lsr curbit, #4 @ No, any more bits to do? + beq Lgot_result + lsr divisor, #4 + b Loop3 +Lgot_result: + mov r0, result + pop { work } + RET + +Ldiv0: + push { lr } + bl SYM (__div0) __PLT__ + mov r0, #0 @ about as wrong as it could be + pop { pc } + + SIZE (__udivsi3) + +#endif /* L_udivsi3 */ + +#ifdef L_umodsi3 + +dividend .req r0 +divisor .req r1 +overdone .req r2 +curbit .req r3 +ip .req r12 +sp .req r13 +lr .req r14 +pc .req r15 + + .text + .globl SYM (__umodsi3) + TYPE (__umodsi3) + .align 0 + .thumb_func +SYM (__umodsi3): + cmp divisor, #0 + beq Ldiv0 + mov curbit, #1 + cmp dividend, divisor + bcs Over1 + RET + +Over1: + @ Load the constant 0x10000000 into our work register + push { work } + mov work, #1 + lsl work, #28 +Loop1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, work + bcs Lbignum + cmp divisor, dividend + bcs Lbignum + lsl divisor, #4 + lsl curbit, #4 + b Loop1 + +Lbignum: + @ Set work to 0x80000000 + lsl work, #3 +Loop2: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + cmp divisor, work + bcs Loop3 + cmp divisor, dividend + bcs Loop3 + lsl divisor, #1 + lsl curbit, #1 + b Loop2 + +Loop3: + @ Test for possible subtractions. On the final pass, this may + @ subtract too much from the dividend, so keep track of which + @ subtractions are done, we can fix them up afterwards... + mov overdone, #0 + cmp dividend, divisor + bcc Over2 + sub dividend, dividend, divisor +Over2: + lsr work, divisor, #1 + cmp dividend, work + bcc Over3 + sub dividend, dividend, work + mov ip, curbit + mov work, #1 + ror curbit, work + orr overdone, curbit + mov curbit, ip +Over3: + lsr work, divisor, #2 + cmp dividend, work + bcc Over4 + sub dividend, dividend, work + mov ip, curbit + mov work, #2 + ror curbit, work + orr overdone, curbit + mov curbit, ip +Over4: + lsr work, divisor, #3 + cmp dividend, work + bcc Over5 + sub dividend, dividend, work + mov ip, curbit + mov work, #3 + ror curbit, work + orr overdone, curbit + mov curbit, ip +Over5: + mov ip, curbit + cmp dividend, #0 @ Early termination? + beq Over6 + lsr curbit, #4 @ No, any more bits to do? + beq Over6 + lsr divisor, #4 + b Loop3 + +Over6: + @ Any subtractions that we should not have done will be recorded in + @ the top three bits of "overdone". Exactly which were not needed + @ are governed by the position of the bit, stored in ip. + @ If we terminated early, because dividend became zero, + @ then none of the below will match, since the bit in ip will not be + @ in the bottom nibble. + + mov work, #0xe + lsl work, #28 + and overdone, work + bne Over7 + pop { work } + RET @ No fixups needed +Over7: + mov curbit, ip + mov work, #3 + ror curbit, work + tst overdone, curbit + beq Over8 + lsr work, divisor, #3 + add dividend, dividend, work +Over8: + mov curbit, ip + mov work, #2 + ror curbit, work + tst overdone, curbit + beq Over9 + lsr work, divisor, #2 + add dividend, dividend, work +Over9: + mov curbit, ip + mov work, #1 + ror curbit, work + tst overdone, curbit + beq Over10 + lsr work, divisor, #1 + add dividend, dividend, work +Over10: + pop { work } + RET + +Ldiv0: + push { lr } + bl SYM (__div0) __PLT__ + mov r0, #0 @ about as wrong as it could be + pop { pc } + + SIZE (__umodsi3) + +#endif /* L_umodsi3 */ + +#ifdef L_divsi3 + +dividend .req r0 +divisor .req r1 +result .req r2 +curbit .req r3 +ip .req r12 +sp .req r13 +lr .req r14 +pc .req r15 + + .text + .globl SYM (__divsi3) + TYPE (__divsi3) + .align 0 + .thumb_func +SYM (__divsi3): + cmp divisor, #0 + beq Ldiv0 + + push { work } + mov work, dividend + eor work, divisor @ Save the sign of the result. + mov ip, work + mov curbit, #1 + mov result, #0 + cmp divisor, #0 + bpl Over1 + neg divisor, divisor @ Loops below use unsigned. +Over1: + cmp dividend, #0 + bpl Over2 + neg dividend, dividend +Over2: + cmp dividend, divisor + bcc Lgot_result + + mov work, #1 + lsl work, #28 +Loop1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, work + Bcs Lbignum + cmp divisor, dividend + Bcs Lbignum + lsl divisor, #4 + lsl curbit, #4 + b Loop1 + +Lbignum: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + lsl work, #3 +Loop2: + cmp divisor, work + Bcs Loop3 + cmp divisor, dividend + Bcs Loop3 + lsl divisor, #1 + lsl curbit, #1 + b Loop2 + +Loop3: + @ Test for possible subtractions, and note which bits + @ are done in the result. On the final pass, this may subtract + @ too much from the dividend, but the result will be ok, since the + @ "bit" will have been shifted out at the bottom. + cmp dividend, divisor + Bcc Over3 + sub dividend, dividend, divisor + orr result, result, curbit +Over3: + lsr work, divisor, #1 + cmp dividend, work + Bcc Over4 + sub dividend, dividend, work + lsr work, curbit, #1 + orr result, work +Over4: + lsr work, divisor, #2 + cmp dividend, work + Bcc Over5 + sub dividend, dividend, work + lsr work, curbit, #2 + orr result, result, work +Over5: + lsr work, divisor, #3 + cmp dividend, work + Bcc Over6 + sub dividend, dividend, work + lsr work, curbit, #3 + orr result, result, work +Over6: + cmp dividend, #0 @ Early termination? + Beq Lgot_result + lsr curbit, #4 @ No, any more bits to do? + Beq Lgot_result + lsr divisor, #4 + b Loop3 + +Lgot_result: + mov r0, result + mov work, ip + cmp work, #0 + Bpl Over7 + neg r0, r0 +Over7: + pop { work } + RET + +Ldiv0: + push { lr } + bl SYM (__div0) __PLT__ + mov r0, #0 @ about as wrong as it could be + pop { pc } + + SIZE (__divsi3) + +#endif /* L_divsi3 */ + +#ifdef L_modsi3 + +dividend .req r0 +divisor .req r1 +overdone .req r2 +curbit .req r3 +ip .req r12 +sp .req r13 +lr .req r14 +pc .req r15 + + .text + .globl SYM (__modsi3) + TYPE (__modsi3) + .align 0 + .thumb_func +SYM (__modsi3): + mov curbit, #1 + cmp divisor, #0 + beq Ldiv0 + Bpl Over1 + neg divisor, divisor @ Loops below use unsigned. +Over1: + push { work } + @ Need to save the sign of the dividend, unfortunately, we need + @ ip later on. Must do this after saving the original value of + @ the work register, because we will pop this value off first. + push { dividend } + cmp dividend, #0 + Bpl Over2 + neg dividend, dividend +Over2: + cmp dividend, divisor + bcc Lgot_result + mov work, #1 + lsl work, #28 +Loop1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, work + bcs Lbignum + cmp divisor, dividend + bcs Lbignum + lsl divisor, #4 + lsl curbit, #4 + b Loop1 + +Lbignum: + @ Set work to 0x80000000 + lsl work, #3 +Loop2: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + cmp divisor, work + bcs Loop3 + cmp divisor, dividend + bcs Loop3 + lsl divisor, #1 + lsl curbit, #1 + b Loop2 + +Loop3: + @ Test for possible subtractions. On the final pass, this may + @ subtract too much from the dividend, so keep track of which + @ subtractions are done, we can fix them up afterwards... + mov overdone, #0 + cmp dividend, divisor + bcc Over3 + sub dividend, dividend, divisor +Over3: + lsr work, divisor, #1 + cmp dividend, work + bcc Over4 + sub dividend, dividend, work + mov ip, curbit + mov work, #1 + ror curbit, work + orr overdone, curbit + mov curbit, ip +Over4: + lsr work, divisor, #2 + cmp dividend, work + bcc Over5 + sub dividend, dividend, work + mov ip, curbit + mov work, #2 + ror curbit, work + orr overdone, curbit + mov curbit, ip +Over5: + lsr work, divisor, #3 + cmp dividend, work + bcc Over6 + sub dividend, dividend, work + mov ip, curbit + mov work, #3 + ror curbit, work + orr overdone, curbit + mov curbit, ip +Over6: + mov ip, curbit + cmp dividend, #0 @ Early termination? + beq Over7 + lsr curbit, #4 @ No, any more bits to do? + beq Over7 + lsr divisor, #4 + b Loop3 + +Over7: + @ Any subtractions that we should not have done will be recorded in + @ the top three bits of "overdone". Exactly which were not needed + @ are governed by the position of the bit, stored in ip. + @ If we terminated early, because dividend became zero, + @ then none of the below will match, since the bit in ip will not be + @ in the bottom nibble. + mov work, #0xe + lsl work, #28 + and overdone, work + beq Lgot_result + + mov curbit, ip + mov work, #3 + ror curbit, work + tst overdone, curbit + beq Over8 + lsr work, divisor, #3 + add dividend, dividend, work +Over8: + mov curbit, ip + mov work, #2 + ror curbit, work + tst overdone, curbit + beq Over9 + lsr work, divisor, #2 + add dividend, dividend, work +Over9: + mov curbit, ip + mov work, #1 + ror curbit, work + tst overdone, curbit + beq Lgot_result + lsr work, divisor, #1 + add dividend, dividend, work +Lgot_result: + pop { work } + cmp work, #0 + bpl Over10 + neg dividend, dividend +Over10: + pop { work } + RET + +Ldiv0: + push { lr } + bl SYM (__div0) __PLT__ + mov r0, #0 @ about as wrong as it could be + pop { pc } + + SIZE (__modsi3) + +#endif /* L_modsi3 */ + +#ifdef L_dvmd_tls + + .globl SYM (__div0) + TYPE (__div0) + .align 0 + .thumb_func +SYM (__div0): + RET + + SIZE (__div0) + +#endif /* L_divmodsi_tools */ + + +#ifdef L_call_via_rX + +/* These labels & instructions are used by the Arm/Thumb interworking code. + The address of function to be called is loaded into a register and then + one of these labels is called via a BL instruction. This puts the + return address into the link register with the bottom bit set, and the + code here switches to the correct mode before executing the function. */ + + .text + .align 0 + +.macro call_via register + .globl SYM (_call_via_\register) + TYPE (_call_via_\register) + .thumb_func +SYM (_call_via_\register): + bx \register + nop + + SIZE (_call_via_\register) +.endm + + call_via r0 + call_via r1 + call_via r2 + call_via r3 + call_via r4 + call_via r5 + call_via r6 + call_via r7 + call_via r8 + call_via r9 + call_via sl + call_via fp + call_via ip + call_via sp + call_via lr + +#endif /* L_call_via_rX */ + +#ifdef L_interwork_call_via_rX + +/* These labels & instructions are used by the Arm/Thumb interworking code, + when the target address is in an unknown instruction set. The address + of function to be called is loaded into a register and then one of these + labels is called via a BL instruction. This puts the return address + into the link register with the bottom bit set, and the code here + switches to the correct mode before executing the function. Unfortunately + the target code cannot be relied upon to return via a BX instruction, so + instead we have to store the resturn address on the stack and allow the + called function to return here instead. Upon return we recover the real + return address and use a BX to get back to Thumb mode. */ + + .text + .align 0 + + .code 32 + .globl _arm_return +_arm_return: + ldmia r13!, {r12} + bx r12 + +.macro interwork register + .code 16 + + .globl SYM (_interwork_call_via_\register) + TYPE (_interwork_call_via_\register) + .thumb_func +SYM (_interwork_call_via_\register): + bx pc + nop + + .code 32 + .globl .Lchange_\register +.Lchange_\register: + tst \register, #1 + stmeqdb r13!, {lr} + adreq lr, _arm_return + bx \register + + SIZE (_interwork_call_via_\register) +.endm + + interwork r0 + interwork r1 + interwork r2 + interwork r3 + interwork r4 + interwork r5 + interwork r6 + interwork r7 + interwork r8 + interwork r9 + interwork sl + interwork fp + interwork ip + interwork sp + + /* The lr case has to be handled a little differently...*/ + .code 16 + .globl SYM (_interwork_call_via_lr) + TYPE (_interwork_call_via_lr) + .thumb_func +SYM (_interwork_call_via_lr): + bx pc + nop + + .code 32 + .globl .Lchange_lr +.Lchange_lr: + tst lr, #1 + stmeqdb r13!, {lr} + mov ip, lr + adreq lr, _arm_return + bx ip + + SIZE (_interwork_call_via_lr) + +#endif /* L_interwork_call_via_rX */ diff --git a/gcc_arm/config/arm/linux-aout.h b/gcc_arm/config/arm/linux-aout.h new file mode 100755 index 0000000..3a853bd --- /dev/null +++ b/gcc_arm/config/arm/linux-aout.h @@ -0,0 +1,58 @@ +/* Definitions for ARM running Linux-based GNU systems using a.out. + Copyright (C) 1993, 1994, 1997, 1998 Free Software Foundation, Inc. + Contributed by Russell King . + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include + +/* these are different... */ +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ +"%{pg:gcrt0.o%s} %{!pg:%{p:gcrt0.o%s} %{!p:crt0.o%s}} %{static:-static}" + +#undef ASM_APP_ON +#undef ASM_APP_OFF +#undef COMMENT_BEGIN + +/* We default to ARM3. */ +#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm3 + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES \ +"-Dunix -Darm -Dlinux -Asystem(unix) -Asystem(posix) -Acpu(arm) -Amachine(arm)" + +#undef LIB_SPEC +#define LIB_SPEC \ + "%{mieee-fp:-lieee} %{p:-lgmon} %{pg:-lgmon} %{!ggdb:-lc} %{ggdb:-lg}" + +#define HANDLE_SYSV_PRAGMA + +/* Run-time Target Specification. */ +#define TARGET_VERSION fputs (" (ARM GNU/Linux with a.out)", stderr); + +/* + * Maths operation domain error number, EDOM + * We don't really want this for libc6. However, taking it out would be + * too much of a pain for now and it doesn't hurt much. + */ +#define TARGET_EDOM 33 + +#include "arm/aout.h" + +#include "arm/linux-gas.h" diff --git a/gcc_arm/config/arm/linux-elf.h b/gcc_arm/config/arm/linux-elf.h new file mode 100755 index 0000000..d906093 --- /dev/null +++ b/gcc_arm/config/arm/linux-elf.h @@ -0,0 +1,204 @@ +/* Definitions for ARM running Linux-based GNU systems using ELF + Copyright (C) 1993, 1994, 1997, 1998 Free Software Foundation, Inc. + Contributed by Philip Blundell + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Run-time Target Specification. */ +#define TARGET_VERSION fputs (" (ARM GNU/Linux with ELF)", stderr); + +/* We have libgcc2. */ +#define HAVE_ATEXIT + +/* Default is to use APCS-32 mode. */ +#ifndef SUBTARGET_DEFAULT_APCS26 +#define TARGET_DEFAULT (ARM_FLAG_APCS_32 | ARM_FLAG_SHORT_BYTE) +#define SUBTARGET_EXTRA_LINK_SPEC \ + " %{mapcs-26:-m elf32arm26} %{!mapcs-26:-m elf32arm}" +#define SUBTARGET_EXTRA_ASM_SPEC \ + " %{mapcs-26:-mapcs-26} %(!mapcs-26:-mapcs-32}" +#endif + +/* Now we define the strings used to build the spec file. */ +#define LIB_SPEC "%{!shared:%{!symbolic:-lc}}" + +/* Add the compiler's crtend, and the library's crtn. */ +#define ENDFILE_SPEC "%{!shared:crtend.o%s} %{shared:crtendS.o%s} \ + %{pg:gcrtn.o%s}%{!pg:crtn.o%s}" + +#define STARTFILE_SPEC "%{!shared:crt1.o%s} \ + crti.o%s \ + %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}" + +#define LINK_SPEC "%{h*} %{version:-v} \ + %{b} %{Wl,*:%*} \ + %{static:-Bstatic} \ + %{shared:-shared} \ + %{symbolic:-Bsymbolic} \ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2} \ + -X \ + %{mbig-endian:-EB}" \ + SUBTARGET_EXTRA_LINK_SPEC + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES \ +"-Dunix -Darm -Dlinux -Asystem(unix) -Asystem(posix) -Acpu(arm) \ +-Amachine(arm) -D__ELF__ -Darm_elf" + +#ifndef SUBTARGET_DEFAULT_APCS26 +#undef CPP_APCS_PC_DEFAULT_SPEC +#define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__" +#endif + +/* Allow #sccs in preprocessor. */ +#define SCCS_DIRECTIVE + +#define USER_LABEL_PREFIX "" /* For ELF the default is no underscores */ +#define LOCAL_LABEL_PREFIX "." + +/* Attach a special .ident directive to the end of the file to identify + the version of GCC which compiled this code. */ +#define IDENT_ASM_OP ".ident" + +/* Output #ident as a .ident. */ +#define ASM_OUTPUT_IDENT(FILE, NAME) \ + fprintf (FILE, "\t%s\t\"%s\"\n", IDENT_ASM_OP, NAME); + +#ifdef IDENTIFY_WITH_IDENT +#define ASM_IDENTIFY_GCC(FILE) /* nothing */ +#define ASM_IDENTIFY_LANGUAGE(FILE) \ + fprintf (FILE, "\t%s \"GCC (%s) %s\"\n", IDENT_ASM_OP, \ + lang_identify (), version_string) +#else +#define ASM_FILE_END(FILE) \ +do { \ + fprintf ((FILE), "\t%s\t\"GCC: (GNU) %s\"\n", \ + IDENT_ASM_OP, version_string); \ + } while (0) +#endif + +/* Support const sections and the ctors and dtors sections for g++. + Note that there appears to be two different ways to support const + sections at the moment. You can either #define the symbol + READONLY_DATA_SECTION (giving it some code which switches to the + readonly data section) or else you can #define the symbols + EXTRA_SECTIONS, EXTRA_SECTION_FUNCTIONS, SELECT_SECTION, and + SELECT_RTX_SECTION. We do both here just to be on the safe side. */ +#define USE_CONST_SECTION 1 + +/* Support for Constructors and Destructors. */ +#define READONLY_DATA_SECTION() const_section () + +/* A default list of other sections which we might be "in" at any given + time. For targets that use additional sections (e.g. .tdesc) you + should override this definition in the target-specific file which + includes this file. */ +#define SUBTARGET_EXTRA_SECTIONS in_const, + +/* A default list of extra section function definitions. For targets + that use additional sections (e.g. .tdesc) you should override this + definition in the target-specific file which includes this file. */ +#define SUBTARGET_EXTRA_SECTION_FUNCTIONS CONST_SECTION_FUNCTION + +extern void text_section (); + +#define CONST_SECTION_ASM_OP ".section\t.rodata" + +#define CONST_SECTION_FUNCTION \ +void \ +const_section () \ +{ \ + if (!USE_CONST_SECTION) \ + text_section (); \ + else if (in_section != in_const) \ + { \ + fprintf (asm_out_file, "%s\n", CONST_SECTION_ASM_OP); \ + in_section = in_const; \ + } \ +} + +/* Switch into a generic section. + This is currently only used to support section attributes. + + We make the section read-only and executable for a function decl, + read-only for a const data decl, and writable for a non-const data decl. */ +#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME, RELOC) \ + fprintf (FILE, ".section\t%s,\"%s\",%%progbits\n", NAME, \ + (DECL) && TREE_CODE (DECL) == FUNCTION_DECL ? "ax" : \ + (DECL) && DECL_READONLY_SECTION (DECL, RELOC) ? "a" : "aw") + +/* A C statement or statements to 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. */ +#define SELECT_SECTION(DECL,RELOC) \ +{ \ + if (TREE_CODE (DECL) == STRING_CST) \ + { \ + if (! flag_writable_strings) \ + const_section (); \ + else \ + data_section (); \ + } \ + else if (TREE_CODE (DECL) == VAR_DECL) \ + { \ + if ((flag_pic && RELOC) \ + || !TREE_READONLY (DECL) || TREE_SIDE_EFFECTS (DECL) \ + || !DECL_INITIAL (DECL) \ + || (DECL_INITIAL (DECL) != error_mark_node \ + && !TREE_CONSTANT (DECL_INITIAL (DECL)))) \ + data_section (); \ + else \ + const_section (); \ + } \ + else \ + const_section (); \ +} + +/* A C statement or statements to switch to the appropriate + section for output of RTX in mode MODE. RTX is some kind + of constant in RTL. The argument MODE is redundant except + in the case of a `const_int' rtx. Currently, these always + go into the const section. */ +#define SELECT_RTX_SECTION(MODE,RTX) const_section () + +/* On svr4, we *do* have support for the .init and .fini sections, and we + can put stuff in there to be executed before and after `main'. We let + crtstuff.c and other files know this by defining the following symbols. + The definitions say how to change sections to the .init and .fini + sections. This is the same for all known svr4 assemblers. */ +#define INIT_SECTION_ASM_OP ".section\t.init" +#define FINI_SECTION_ASM_OP ".section\t.fini" + + +/* This is how we tell the assembler that a symbol is weak. */ +#define ASM_WEAKEN_LABEL(FILE,NAME) \ + do { fputs ("\t.weak\t", FILE); assemble_name (FILE, NAME); \ + fputc ('\n', FILE); } while (0) + +/* This is how we tell the assembler that two symbols have the same value. */ + +#define ASM_OUTPUT_DEF(FILE,NAME1,NAME2) \ + do { assemble_name (FILE, NAME1); \ + fputs (" = ", FILE); \ + assemble_name (FILE, NAME2); \ + fputc ('\n', FILE); } while (0) + +#include "arm/elf.h" +#include "arm/linux-gas.h" diff --git a/gcc_arm/config/arm/linux-elf26.h b/gcc_arm/config/arm/linux-elf26.h new file mode 100755 index 0000000..aa65ae7 --- /dev/null +++ b/gcc_arm/config/arm/linux-elf26.h @@ -0,0 +1,32 @@ +/* Definitions for 26-bit ARM running Linux-based GNU systems using ELF + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Philip Blundell + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define SUBTARGET_DEFAULT_APCS26 + +#define SUBTARGET_LINK_SPEC \ + " %{mapcs-32:-m elf32arm} %{!mapcs-32:-m elf32arm26}" + +#define SUBTARGET_EXTRA_ASM_SPEC \ + " %{mapcs-32:-mapcs-32} %(!mapcs-32:-mapcs-26}" + +#define TARGET_DEFAULT (ARM_FLAG_SHORT_BYTE) + +#include "arm/linux-elf.h" diff --git a/gcc_arm/config/arm/linux-gas.h b/gcc_arm/config/arm/linux-gas.h new file mode 100755 index 0000000..72567f3 --- /dev/null +++ b/gcc_arm/config/arm/linux-gas.h @@ -0,0 +1,87 @@ +/* Definitions of target machine for GNU compiler. + ARM Linux-based GNU systems version. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + Contributed by Russell King . + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* + * We are using GAS, so stabs should work. + */ + +#ifndef DBX_DEBUGGING_INFO +#define DBX_DEBUGGING_INFO 1 +#endif + +/* + * This is how we tell the assembler that a symbol is weak. GAS always + * supports weak symbols. + */ + +#define ASM_WEAKEN_LABEL(FILE,NAME) \ + do { fputs ("\t.weak\t", FILE); assemble_name (FILE, NAME); \ + fputc ('\n', FILE); } while (0) + +/* This is used in ASM_FILE_START */ +#undef ARM_OS_NAME +#define ARM_OS_NAME "Linux" + +/* Unsigned chars produces much better code than signed. */ +#define DEFAULT_SIGNED_CHAR 0 + +#undef SUBTARGET_CPP_SPEC +#define SUBTARGET_CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__}" + +#undef SIZE_TYPE +#define SIZE_TYPE "unsigned int" + +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE "int" + +#undef WCHAR_TYPE +#define WCHAR_TYPE "long int" + +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE BITS_PER_WORD + +#if 0 /* not yet */ + +/* Clear the instruction cache from `beg' to `end'. This makes an + inline system call to SYS_cacheflush. The arguments are as + follows: + + cacheflush (start, end, flags) + +*/ + +#define CLEAR_INSN_CACHE(BEG, END) \ +{ \ + register unsigned long _beg __asm ("a1") = (unsigned long) (BEG); \ + register unsigned long _end __asm ("a2") = (unsigned long) (END); \ + register unsigned long _flg __asm ("a3") = 0; \ + __asm __volatile ("swi 0x9000b8"); \ +} + +#endif + +/* If cross-compiling, don't require stdio.h etc to build libgcc.a. */ +#ifdef CROSS_COMPILE +#ifndef inhibit_libc +#define inhibit_libc +#endif +#endif diff --git a/gcc_arm/config/arm/linux.h b/gcc_arm/config/arm/linux.h new file mode 100755 index 0000000..fa8fef1 --- /dev/null +++ b/gcc_arm/config/arm/linux.h @@ -0,0 +1,72 @@ +/* Definitions for ARM running Linux-based GNU systems. + Copyright (C) 1993, 1994, 1997 Free Software Foundation, Inc. + Contributed by Russell King . + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include + +/* these are different... */ +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ +"%{pg:gcrt0.o%s} %{!pg:%{p:gcrt0.o%s} %{!p:crt0.o%s}} %{static:-static}" + +#undef ASM_APP_ON +#undef ASM_APP_OFF +#undef COMMENT_BEGIN + +/* We default to ARM3. */ +#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm3 + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES \ +"-Dunix -Darm -Dlinux -Asystem(unix) -Asystem(posix) -Acpu(arm) -Amachine(arm)" + +#undef LIB_SPEC +#define LIB_SPEC \ + "%{mieee-fp:-lieee} %{p:-lgmon} %{pg:-lgmon} %{!ggdb:-lc} %{ggdb:-lg}" + +#undef SIZE_TYPE +#define SIZE_TYPE "unsigned int" + +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE "int" + +#undef WCHAR_TYPE +#define WCHAR_TYPE "long int" + +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE BITS_PER_WORD + +#define HANDLE_SYSV_PRAGMA + +/* Run-time Target Specification. */ +#define TARGET_VERSION fputs (" (ARM GNU/Linux with a.out)", stderr); + +/* This is used in ASM_FILE_START */ +#define ARM_OS_NAME "Linux" + +/* Unsigned chars produces much better code than signed. */ +#define DEFAULT_SIGNED_CHAR 0 + +/* Maths operation domain error number, EDOM */ +#define TARGET_EDOM 33 +#include "arm/aout.h" + +#undef SUBTARGET_CPP_SPEC +#define SUBTARGET_CPP_SPEC "%{posix:-D_POSIX_SOURCE}" diff --git a/gcc_arm/config/arm/netbsd.h b/gcc_arm/config/arm/netbsd.h new file mode 100755 index 0000000..7b03d4a --- /dev/null +++ b/gcc_arm/config/arm/netbsd.h @@ -0,0 +1,161 @@ +/* NetBSD/arm (RiscBSD) version. + Copyright (C) 1993, 1994, 1997, 1998 Free Software Foundation, Inc. + Contributed by Mark Brinicombe (amb@physig.ph.kcl.ac.uk) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Run-time Target Specification. */ +#define TARGET_VERSION fputs (" (ARM/NetBSD)", stderr); + +/* This is used in ASM_FILE_START. */ +#define ARM_OS_NAME "NetBSD" + +/* Unsigned chars produces much better code than signed. */ +#define DEFAULT_SIGNED_CHAR 0 + +/* Since we always use GAS as our assembler we support stabs. */ +#define DBX_DEBUGGING_INFO 1 + +/*#undef ASM_DECLARE_FUNCTION_NAME*/ + +/* ARM6 family default cpu. */ +#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +/* Default is to use APCS-32 mode. */ +#define TARGET_DEFAULT (ARM_FLAG_APCS_32 | ARM_FLAG_SOFT_FLOAT) + +#include "arm/aout.h" + +/* This gets redefined in config/netbsd.h. */ +#undef TARGET_MEM_FUNCTIONS + +#include + +/* Until they use ELF or something that handles dwarf2 unwinds + and initialization stuff better. */ +#undef DWARF2_UNWIND_INFO + +/* Some defines for CPP. + arm32 is the NetBSD port name, so we always define arm32 and __arm32__. */ +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "\ +-Dunix -Driscbsd -Darm32 -D__arm32__ -D__arm__ -D__NetBSD__ \ +-Asystem(unix) -Asystem(NetBSD) -Acpu(arm) -Amachine(arm)" + +/* Define _POSIX_SOURCE if necessary. */ +#undef CPP_SPEC +#define CPP_SPEC "\ +%(cpp_cpu_arch) %(cpp_apcs_pc) %(cpp_float) %(cpp_endian) \ +%{posix:-D_POSIX_SOURCE} \ +" + +/* Because TARGET_DEFAULT sets ARM_FLAG_APCS_32 */ +#undef CPP_APCS_PC_DEFAULT_SPEC +#define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__" + +/* Because TARGET_DEFAULT sets ARM_FLAG_SOFT_FLOAT */ +#undef CPP_FLOAT_DEFAULT_SPEC +#define CPP_FLOAT_DEFAULT_SPEC "-D__SOFTFP__" + +/* Pass -X to the linker so that it will strip symbols starting with 'L' */ +#undef LINK_SPEC +#define LINK_SPEC "\ +-X %{!nostdlib:%{!r*:%{!e*:-e start}}} -dc -dp %{R*} \ +%{static:-Bstatic} %{assert*} \ +" + +#undef SIZE_TYPE +#define SIZE_TYPE "unsigned int" + +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE "int" + +#undef WCHAR_TYPE +#define WCHAR_TYPE "int" + +#undef WCHAR_UNSIGNED +#define WCHAR_UNSIGNED 0 + +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 32 + +#define HANDLE_SYSV_PRAGMA + +/* We don't have any limit on the length as out debugger is GDB. */ +#undef DBX_CONTIN_LENGTH + +/* NetBSD does its profiling differently to the Acorn compiler. We + don't need a word following the mcount call; and to skip it + requires either an assembly stub or use of fomit-frame-pointer when + compiling the profiling functions. Since we break Acorn CC + compatibility below a little more won't hurt. */ + +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(STREAM,LABELNO) \ +{ \ + fprintf(STREAM, "\tmov\t%sip, %slr\n", REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf(STREAM, "\tbl\tmcount\n"); \ +} + +/* On the ARM `@' introduces a comment, so we must use something else + for .type directives. */ +#undef TYPE_OPERAND_FMT +#define TYPE_OPERAND_FMT "%%%s" + +/* NetBSD uses the old PCC style aggregate returning conventions. */ +#undef DEFAULT_PCC_STRUCT_RETURN +#define DEFAULT_PCC_STRUCT_RETURN 1 + +/* Although not normally relevant (since by default, all aggregates + are returned in memory) compiling some parts of libc requires + non-APCS style struct returns. */ +#undef RETURN_IN_MEMORY + +/* VERY BIG NOTE : Change of structure alignment for RiscBSD. + There are consequences you should be aware of... + + Normally GCC/arm uses a structure alignment of 32 for compatibility + with armcc. This means that structures are padded to a word + boundary. However this causes problems with bugged NetBSD kernel + code (possibly userland code as well - I have not checked every + binary). The nature of this bugged code is to rely on sizeof() + returning the correct size of various structures rounded to the + nearest byte (SCSI and ether code are two examples, the vm system + is another). This code breaks when the structure alignment is 32 + as sizeof() will report a word=rounded size. By changing the + structure alignment to 8. GCC will conform to what is expected by + NetBSD. + + This has several side effects that should be considered. + 1. Structures will only be aligned to the size of the largest member. + i.e. structures containing only bytes will be byte aligned. + structures containing shorts will be half word alinged. + structures containing ints will be word aligned. + + This means structures should be padded to a word boundary if + alignment of 32 is required for byte structures etc. + + 2. A potential performance penalty may exist if strings are no longer + word aligned. GCC will not be able to use word load/stores to copy + short strings. + + This modification is not encouraged but with the present state of the + NetBSD source tree it is currently the only solution that meets the + requirements. */ +#undef STRUCTURE_SIZE_BOUNDARY +#define STRUCTURE_SIZE_BOUNDARY 8 diff --git a/gcc_arm/config/arm/pe.c b/gcc_arm/config/arm/pe.c new file mode 100755 index 0000000..491f505 --- /dev/null +++ b/gcc_arm/config/arm/pe.c @@ -0,0 +1,521 @@ +/* CYGNUS LOCAL dje/pe, entire file */ +/* Routines for GCC for ARM/pe. + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + Contributed by Doug Evans (dje@cygnus.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include +#include +#include "config.h" +#include "rtl.h" +#include "output.h" +#include "flags.h" +#include "tree.h" +#include "expr.h" + +extern int current_function_anonymous_args; + +/* ARM/PE specific attribute support. + + ARM/PE has three new attributes: + naked - for interrupt functions + dllexport - for exporting a function/variable that will live in a dll + dllimport - for importing a function/variable from a dll + + Microsoft allows multiple declspecs in one __declspec, separating + them with spaces. We do NOT support this. Instead, use __declspec + multiple times. +*/ + +/* Return nonzero if ATTR is a valid attribute for DECL. + ATTRIBUTES are any existing attributes and ARGS are the arguments + supplied with ATTR. */ + +int +arm_pe_valid_machine_decl_attribute (decl, attributes, attr, args) + tree decl; + tree attributes; + tree attr; + tree args; +{ + if (args != NULL_TREE) + return 0; + + if (is_attribute_p ("dllexport", attr)) + return 1; + if (is_attribute_p ("dllimport", attr)) + return 1; + + return arm_valid_machine_decl_attribute (decl, attributes, attr, args); +} + +#if 0 /* needed when we tried type attributes */ +/* Return zero if TYPE1 and TYPE2 are incompatible, one if they are compatible, + and two if they are nearly compatible (which causes a warning to be + generated). */ + +int +arm_pe_comp_type_attributes (type1, type2) + tree type1, type2; +{ + type1 = TYPE_ATTRIBUTES (type1); + type2 = TYPE_ATTRIBUTES (type2); + + if (lookup_attribute ("dllimport", type1) + && lookup_attribute ("dllexport", type2)) + return 0; + + if (lookup_attribute ("dllimport", type2) + && lookup_attribute ("dllexport", type1)) + return 0; + + return 1; +} +#endif + +/* Merge attributes in decls OLD and NEW. + + This handles the following situation: + + __declspec (dllimport) int foo; + int foo; + + The second instance of `foo' nullifies the dllimport. */ + +tree +arm_pe_merge_machine_decl_attributes (old, new) + tree old, new; +{ + tree a; + int delete_dllimport_p; + + old = DECL_MACHINE_ATTRIBUTES (old); + new = DECL_MACHINE_ATTRIBUTES (new); + + /* What we need to do here is remove from `old' dllimport if it doesn't + appear in `new'. dllimport behaves like extern: if a declaration is + marked dllimport and a definition appears later, then the object + is not dllimport'd. */ + + if (lookup_attribute ("dllimport", old) != NULL_TREE + && lookup_attribute ("dllimport", new) == NULL_TREE) + delete_dllimport_p = 1; + else + delete_dllimport_p = 0; + + a = merge_attributes (old, new); + + if (delete_dllimport_p) + { + tree prev,t; + + /* Scan the list for dllimport and delete it. */ + for (prev = NULL_TREE, t = a; t; prev = t, t = TREE_CHAIN (t)) + { + if (is_attribute_p ("dllimport", TREE_PURPOSE (t))) + { + if (prev == NULL_TREE) + a = TREE_CHAIN (a); + else + TREE_CHAIN (prev) = TREE_CHAIN (t); + break; + } + } + } + + return a; +} + +/* Check a type that has a virtual table, and see if any virtual methods are + marked for import or export, and if so, arrange for the vtable to + be imported or exported. */ + +static int +arm_check_vtable_importexport (type) + tree type; +{ + tree methods = TYPE_METHODS (type); + tree fndecl; + + if (TREE_CODE (methods) == FUNCTION_DECL) + fndecl = methods; + else if (TREE_VEC_ELT (methods, 0) != NULL_TREE) + fndecl = TREE_VEC_ELT (methods, 0); + else + fndecl = TREE_VEC_ELT (methods, 1); + + while (fndecl) + { + if (DECL_VIRTUAL_P (fndecl) || DECL_VINDEX (fndecl) != NULL_TREE) + { + tree exp = lookup_attribute ("dllimport", + DECL_MACHINE_ATTRIBUTES (fndecl)); + if (exp == 0) + exp = lookup_attribute ("dllexport", + DECL_MACHINE_ATTRIBUTES (fndecl)); + if (exp) + return 1; + } + + fndecl = TREE_CHAIN (fndecl); + } + + return 0; +} + +/* Return non-zero if DECL is a dllexport'd object. */ + +tree current_class_type; /* FIXME */ + +int +arm_dllexport_p (decl) + tree decl; +{ + tree exp; + + if (TREE_CODE (decl) != VAR_DECL + && TREE_CODE (decl) != FUNCTION_DECL) + return 0; + exp = lookup_attribute ("dllexport", DECL_MACHINE_ATTRIBUTES (decl)); + if (exp) + return 1; + +#if 0 /* This was a hack to get vtable's exported or imported since only one + copy of them is ever output. Disabled pending better solution. */ + /* For C++, the vtables might have to be marked. */ + if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl)) + { + if (TREE_PUBLIC (decl) + && DECL_EXTERNAL (decl) == 0 + && (DECL_CONTEXT (decl) + ? arm_check_vtable_importexport (DECL_CONTEXT (decl)) + : current_class_type + ? arm_check_vtable_importexport (current_class_type) + : 0) + ) + return 1; + } +#endif + + return 0; +} + +/* Return non-zero if DECL is a dllimport'd object. */ + +int +arm_dllimport_p (decl) + tree decl; +{ + tree imp; + + if (TREE_CODE (decl) == FUNCTION_DECL + && TARGET_NOP_FUN_DLLIMPORT) + return 0; + + if (TREE_CODE (decl) != VAR_DECL + && TREE_CODE (decl) != FUNCTION_DECL) + return 0; + imp = lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES (decl)); + if (imp) + return 1; + +#if 0 /* This was a hack to get vtable's exported or imported since only one + copy of them is ever output. Disabled pending better solution. */ + /* For C++, the vtables might have to be marked. */ + if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl)) + { + if (TREE_PUBLIC (decl) + && DECL_EXTERNAL (decl) + && (DECL_CONTEXT (decl) + ? arm_check_vtable_importexport (DECL_CONTEXT (decl)) + : current_class_type + ? arm_check_vtable_importexport (current_class_type) + : 0) + ) + return 1; + } +#endif + + return 0; +} + +/* Return non-zero if SYMBOL is marked as being dllexport'd. */ + +int +arm_dllexport_name_p (symbol) + char *symbol; +{ + return symbol[0] == '@' && symbol[1] == 'e' && symbol[2] == '.'; +} + +/* Return non-zero if SYMBOL is marked as being dllimport'd. */ + +int +arm_dllimport_name_p (symbol) + char *symbol; +{ + return symbol[0] == '@' && symbol[1] == 'i' && symbol[2] == '.'; +} + +/* Mark a DECL as being dllexport'd. + Note that we override the previous setting (eg: dllimport). */ + +void +arm_mark_dllexport (decl) + tree decl; +{ + char *oldname, *newname; + rtx rtlname; + tree idp; + + rtlname = XEXP (DECL_RTL (decl), 0); + if (GET_CODE (rtlname) == SYMBOL_REF) + oldname = XSTR (rtlname, 0); + else if (GET_CODE (rtlname) == MEM + && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF) + oldname = XSTR (XEXP (rtlname, 0), 0); + else + abort (); + if (arm_dllimport_name_p (oldname)) + oldname += 9; + else if (arm_dllexport_name_p (oldname)) + return; /* already done */ + + newname = alloca (strlen (oldname) + 4); + sprintf (newname, "@e.%s", oldname); + + /* We pass newname through get_identifier to ensure it has a unique + address. RTL processing can sometimes peek inside the symbol ref + and compare the string's addresses to see if two symbols are + identical. */ + /* ??? At least I think that's why we do this. */ + idp = get_identifier (newname); + + XEXP (DECL_RTL (decl), 0) = + gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp)); +} + +/* Mark a DECL as being dllimport'd. */ + +void +arm_mark_dllimport (decl) + tree decl; +{ + char *oldname, *newname; + tree idp; + rtx rtlname, newrtl; + + rtlname = XEXP (DECL_RTL (decl), 0); + if (GET_CODE (rtlname) == SYMBOL_REF) + oldname = XSTR (rtlname, 0); + else if (GET_CODE (rtlname) == MEM + && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF) + oldname = XSTR (XEXP (rtlname, 0), 0); + else + abort (); + if (arm_dllexport_name_p (oldname)) + abort (); /* this shouldn't happen */ + else if (arm_dllimport_name_p (oldname)) + return; /* already done */ + + /* ??? One can well ask why we're making these checks here, + and that would be a good question. */ + + /* Imported variables can't be initialized. */ + if (TREE_CODE (decl) == VAR_DECL + && !DECL_VIRTUAL_P (decl) + && DECL_INITIAL (decl)) + { + error_with_decl (decl, "initialized variable `%s' is marked dllimport"); + return; + } + /* Nor can they be static. */ + if (TREE_CODE (decl) == VAR_DECL + /* ??? Is this test for vtables needed? */ + && !DECL_VIRTUAL_P (decl) + && 0 /*???*/) + { + error_with_decl (decl, "static variable `%s' is marked dllimport"); + return; + } + + /* `extern' needn't be specified with dllimport. + Specify `extern' now and hope for the best. Sigh. */ + if (TREE_CODE (decl) == VAR_DECL + /* ??? Is this test for vtables needed? */ + && !DECL_VIRTUAL_P (decl)) + { + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + } + + newname = alloca (strlen (oldname) + 11); + sprintf (newname, "@i.__imp_%s", oldname); + + /* We pass newname through get_identifier to ensure it has a unique + address. RTL processing can sometimes peek inside the symbol ref + and compare the string's addresses to see if two symbols are + identical. */ + /* ??? At least I think that's why we do this. */ + idp = get_identifier (newname); + + newrtl = gen_rtx (MEM, Pmode, + gen_rtx (SYMBOL_REF, Pmode, + IDENTIFIER_POINTER (idp))); + XEXP (DECL_RTL (decl), 0) = newrtl; +} + +/* Cover function to implement ENCODE_SECTION_INFO. */ + +void +arm_pe_encode_section_info (decl) + tree decl; +{ + /* This bit is copied from arm.h. */ + if (optimize > 0 && TREE_CONSTANT (decl) + && (!flag_writable_strings || TREE_CODE (decl) != STRING_CST)) + { + rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd' + ? TREE_CST_RTL (decl) : DECL_RTL (decl)); + SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1; + } + + /* Mark the decl so we can tell from the rtl whether the object is + dllexport'd or dllimport'd. */ + + if (arm_dllexport_p (decl)) + arm_mark_dllexport (decl); + else if (arm_dllimport_p (decl)) + arm_mark_dllimport (decl); + /* It might be that DECL has already been marked as dllimport, but a + subsequent definition nullified that. The attribute is gone but + DECL_RTL still has @i.__imp_foo. We need to remove that. */ + else if ((TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == VAR_DECL) + && DECL_RTL (decl) != NULL_RTX + && GET_CODE (DECL_RTL (decl)) == MEM + && GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM + && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == SYMBOL_REF + && arm_dllimport_name_p (XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0))) + { + char *oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0); + tree idp = get_identifier (oldname + 9); + rtx newrtl = gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp)); + + XEXP (DECL_RTL (decl), 0) = newrtl; + + /* We previously set TREE_PUBLIC and DECL_EXTERNAL. + ??? We leave these alone for now. */ + } +} + +/* Cover function for UNIQUE_SECTION. */ + +void +arm_pe_unique_section (decl, reloc) + tree decl; + int reloc; +{ + int len; + char *name,*string,*prefix; + + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + /* Strip off any encoding in fnname. */ + STRIP_NAME_ENCODING (name, name); + + /* The object is put in, for example, section .text$foo. + The linker will then ultimately place them in .text + (everything from the $ on is stripped). */ + if (TREE_CODE (decl) == FUNCTION_DECL) + prefix = ".text$"; + else if (DECL_READONLY_SECTION (decl, reloc)) + prefix = ".rdata$"; + else + prefix = ".data$"; + len = strlen (name) + strlen (prefix); + string = alloca (len + 1); + sprintf (string, "%s%s", prefix, name); + + DECL_SECTION_NAME (decl) = build_string (len, string); +} + +/* This is to better conform to the ARM PCS. + Richard Earnshaw hasn't put this into FSF sources yet so it's here. */ + +int +arm_pe_return_in_memory (type) + tree type; +{ + if (TREE_CODE (type) == RECORD_TYPE) + { + tree field; + int num_fields = 0; + + /* For a record containing just a single element, we can be a little + less restrictive. */ + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) == FIELD_DECL && ! TREE_STATIC (field)) + { + if ((AGGREGATE_TYPE_P (TREE_TYPE (field)) + && RETURN_IN_MEMORY (TREE_TYPE (field))) + || FLOAT_TYPE_P (TREE_TYPE (field))) + return 1; + num_fields++; + } + } + + if (num_fields == 1) + return 0; + + /* For a struct, we can return in a register if every element was a + bit-field and it all fits in one word. */ + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) == FIELD_DECL + && ! TREE_STATIC (field) + && (! DECL_BIT_FIELD_TYPE (field) + || (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field)) + + TREE_INT_CST_LOW (DECL_SIZE (field))) > 32)) + return 1; + } + return 0; + } + else if (TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE) + { + tree field; + + /* Unions can be returned in registers if every element is + integral, or can be returned in an integer register. */ + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) == FIELD_DECL + && ! TREE_STATIC (field) + && ((AGGREGATE_TYPE_P (TREE_TYPE (field)) + && RETURN_IN_MEMORY (TREE_TYPE (field))) + || FLOAT_TYPE_P (TREE_TYPE (field)))) + return 1; + } + return 0; + } + /* XXX Not sure what should be done for other aggregates, so put them in + memory. */ + return 1; +} diff --git a/gcc_arm/config/arm/pe.h b/gcc_arm/config/arm/pe.h new file mode 100755 index 0000000..dcc2042 --- /dev/null +++ b/gcc_arm/config/arm/pe.h @@ -0,0 +1,295 @@ +/* CYGNUS LOCAL entire file */ +/* Definitions of target machine for GNU compiler, for ARM with PE obj format. + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + Contributed by Doug Evans (dje@cygnus.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "arm/coff.h" + +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "_" + + +/* Run-time Target Specification. */ +#undef TARGET_VERSION +#define TARGET_VERSION fputs (" (ARM/pe)", stderr) + +/* Support the __declspec keyword by turning them into attributes. + We currently only support: naked, dllimport, and dllexport. + Note that the current way we do this may result in a collision with + predefined attributes later on. This can be solved by using one attribute, + say __declspec__, and passing args to it. The problem with that approach + is that args are not accumulated: each new appearance would clobber any + existing args. */ +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "\ +-Darm -D__pe__ -Acpu(arm) -Amachine(arm) \ +-D__declspec(x)=__attribute__((x)) \ +" + +/* Experimental addition for pr 7885. + Ignore dllimport for functions. */ +#define TARGET_NOP_FUN_DLLIMPORT (target_flags & 0x20000) + +#undef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES \ +{ "nop-fun-dllimport", 0x20000 }, \ +{ "no-nop-fun-dllimport", -0x20000 }, + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT + 0x20000) + +#undef WCHAR_TYPE +#define WCHAR_TYPE "short unsigned int" +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 16 + +/* Same as arm.h except r10 is call-saved, not fixed. */ +#undef FIXED_REGISTERS +#define FIXED_REGISTERS \ +{ \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,1,0,1,0,1, \ + 0,0,0,0,0,0,0,0, \ + 1,1,1 \ +} + +/* Same as arm.h except r10 is call-saved, not fixed. */ +#undef CALL_USED_REGISTERS +#define CALL_USED_REGISTERS \ +{ \ + 1,1,1,1,0,0,0,0, \ + 0,0,0,1,1,1,1,1, \ + 1,1,1,1,0,0,0,0, \ + 1,1,1 \ +} + +/* This is to better conform to the ARM PCS. + Richard Earnshaw hasn't put this into FSF sources yet so it's here. */ +#undef RETURN_IN_MEMORY +#define RETURN_IN_MEMORY(TYPE) \ + ((TYPE_MODE ((TYPE)) == BLKmode && ! TYPE_NO_FORCE_BLK (TYPE)) \ + || (AGGREGATE_TYPE_P ((TYPE)) && arm_pe_return_in_memory ((TYPE)))) + +/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS + is a valid machine specific attribute for DECL. + The attributes in ATTRIBUTES have previously been assigned to DECL. */ +extern int arm_pe_valid_machine_decl_attribute (); +#undef VALID_MACHINE_DECL_ATTRIBUTE +#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \ +arm_pe_valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS) + +#if 0 /* Needed when we tried type attributes. */ +/* A C expression whose value is zero if the attributes on + TYPE1 and TYPE2 are incompatible, one if they are compatible, + and two if they are nearly compatible (which causes a warning to be + generated). */ +extern int arm_pe_comp_type_attributes (); +#define COMP_TYPE_ATTRIBUTES(TYPE1, TYPE2) \ +arm_pe_comp_type_attributes ((TYPE1), (TYPE2)) +#endif + +extern union tree_node *arm_pe_merge_machine_decl_attributes (); +#define MERGE_MACHINE_DECL_ATTRIBUTES(OLD, NEW) \ +arm_pe_merge_machine_decl_attributes ((OLD), (NEW)) + +/* In addition to the stuff done in arm.h, we must mark dll symbols specially. + Definitions of dllexport'd objects install some info in the .drectve + section. References to dllimport'd objects are fetched indirectly via + __imp_. If both are declared, dllexport overrides. + This is also needed to implement one-only vtables: they go into their own + section and we need to set DECL_SECTION_NAME so we do that here. + Note that we can be called twice on the same decl. */ +extern void arm_pe_encode_section_info (); +#undef ENCODE_SECTION_INFO +#define ENCODE_SECTION_INFO(DECL) \ +arm_pe_encode_section_info (DECL) + +/* Used to implement dllexport overriding dllimport semantics. It's also used + to handle vtables - the first pass won't do anything because + DECL_CONTEXT (DECL) will be 0 so arm_dll{ex,im}port_p will return 0. + It's also used to handle dllimport override semantics. */ +#if 0 +#define REDO_SECTION_INFO_P(DECL) \ +((DECL_MACHINE_ATTRIBUTES (DECL) != NULL_TREE) \ + || (TREE_CODE (DECL) == VAR_DECL && DECL_VIRTUAL_P (DECL))) +#else +#define REDO_SECTION_INFO_P(DECL) 1 +#endif + +/* Utility used only in this file. */ +#define ARM_STRIP_NAME_ENCODING(SYM_NAME) \ +((SYM_NAME) + ((SYM_NAME)[0] == '@' ? 3 : 0)) + +/* Strip any text from SYM_NAME added by ENCODE_SECTION_INFO and store + the result in VAR. */ +#undef STRIP_NAME_ENCODING +#define STRIP_NAME_ENCODING(VAR, SYM_NAME) \ +(VAR) = ARM_STRIP_NAME_ENCODING (SYM_NAME) + +/* Define this macro if in some cases global symbols from one translation + unit may not be bound to undefined symbols in another translation unit + without user intervention. For instance, under Microsoft Windows + symbols must be explicitly imported from shared libraries (DLLs). */ +#define MULTIPLE_SYMBOL_SPACES + +#define UNIQUE_SECTION_P(DECL) DECL_ONE_ONLY (DECL) +extern void arm_pe_unique_section (); +#define UNIQUE_SECTION(DECL,RELOC) arm_pe_unique_section (DECL, RELOC) + +#define SUPPORTS_ONE_ONLY 1 + +/* A C statement to output something to the assembler file to switch to section + NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or + NULL_TREE. Some target formats do not support arbitrary sections. Do not + define this macro in such cases. */ +#undef ASM_OUTPUT_SECTION_NAME +#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ +do { \ + if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ + fprintf (STREAM, "\t.section %s,\"x\"\n", (NAME)); \ + else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ + fprintf (STREAM, "\t.section %s,\"\"\n", (NAME)); \ + else \ + fprintf (STREAM, "\t.section %s,\"w\"\n", (NAME)); \ + /* Functions may have been compiled at various levels of \ + optimization so we can't use `same_size' here. Instead, \ + have the linker pick one. */ \ + if ((DECL) && DECL_ONE_ONLY (DECL)) \ + fprintf (STREAM, "\t.linkonce %s\n", \ + TREE_CODE (DECL) == FUNCTION_DECL \ + ? "discard" : "same_size"); \ +} while (0) + +/* This outputs a lot of .req's to define alias for various registers. + Let's try to avoid this. */ +#undef ASM_FILE_START +#define ASM_FILE_START(STREAM) \ +do { \ + extern char *version_string; \ + fprintf (STREAM, "%s Generated by gcc %s for ARM/pe\n", \ + ASM_COMMENT_START, version_string); \ + output_file_directive ((STREAM), main_input_filename); \ +} while (0) + +/* Output a reference to a label. */ +#undef ASM_OUTPUT_LABELREF +#define ASM_OUTPUT_LABELREF(STREAM, NAME) \ +fprintf (STREAM, "%s%s", USER_LABEL_PREFIX, ARM_STRIP_NAME_ENCODING (NAME)) + +/* Output a function definition label. */ +#undef ASM_DECLARE_FUNCTION_NAME +#define ASM_DECLARE_FUNCTION_NAME(STREAM, NAME, DECL) \ +do { \ + if (arm_dllexport_name_p (NAME)) \ + { \ + drectve_section (); \ + fprintf (STREAM, "\t.ascii \" -export:%s\"\n", \ + ARM_STRIP_NAME_ENCODING (NAME)); \ + function_section (DECL); \ + } \ + ASM_OUTPUT_LABEL ((STREAM), (NAME)); \ +} while (0) + +/* Output a common block. */ +#undef ASM_OUTPUT_COMMON +#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ +do { \ + if (arm_dllexport_name_p (NAME)) \ + { \ + drectve_section (); \ + fprintf ((STREAM), "\t.ascii \" -export:%s\"\n", \ + ARM_STRIP_NAME_ENCODING (NAME)); \ + } \ + if (! arm_dllimport_name_p (NAME)) \ + { \ + fprintf ((STREAM), "\t.comm\t"); \ + assemble_name ((STREAM), (NAME)); \ + fprintf ((STREAM), ", %d\t%s %d\n", \ + (ROUNDED), ASM_COMMENT_START, (SIZE)); \ + } \ +} while (0) + +/* Output the label for an initialized variable. */ +#undef ASM_DECLARE_OBJECT_NAME +#define ASM_DECLARE_OBJECT_NAME(STREAM, NAME, DECL) \ +do { \ + if (arm_dllexport_name_p (NAME)) \ + { \ + enum in_section save_section = in_section; \ + drectve_section (); \ + fprintf (STREAM, "\t.ascii \" -export:%s\"\n", \ + ARM_STRIP_NAME_ENCODING (NAME)); \ + switch_to_section (save_section, (DECL)); \ + } \ + ASM_OUTPUT_LABEL ((STREAM), (NAME)); \ +} while (0) + +/* Support the ctors/dtors and other sections. */ + +#define DRECTVE_SECTION_ASM_OP "\t.section .drectve" + +/* A list of other sections which the compiler might be "in" at any + given time. */ + +#undef SUBTARGET_EXTRA_SECTIONS +#define SUBTARGET_EXTRA_SECTIONS in_drectve, + +/* A list of extra section function definitions. */ + +#undef SUBTARGET_EXTRA_SECTION_FUNCTIONS +#define SUBTARGET_EXTRA_SECTION_FUNCTIONS \ + DRECTVE_SECTION_FUNCTION \ + SWITCH_TO_SECTION_FUNCTION + +#define DRECTVE_SECTION_FUNCTION \ +void \ +drectve_section () \ +{ \ + if (in_section != in_drectve) \ + { \ + fprintf (asm_out_file, "%s\n", DRECTVE_SECTION_ASM_OP); \ + in_section = in_drectve; \ + } \ +} + +/* Switch to SECTION (an `enum in_section'). + + ??? This facility should be provided by GCC proper. + The problem is that we want to temporarily switch sections in + ASM_DECLARE_OBJECT_NAME and then switch back to the original section + afterwards. */ +#define SWITCH_TO_SECTION_FUNCTION \ +void \ +switch_to_section (section, decl) \ + enum in_section section; \ + tree decl; \ +{ \ + switch (section) \ + { \ + case in_text: text_section (); break; \ + case in_data: data_section (); break; \ + case in_named: named_section (decl, NULL, 0); break; \ + case in_rdata: rdata_section (); break; \ + case in_ctors: ctors_section (); break; \ + case in_dtors: dtors_section (); break; \ + case in_drectve: drectve_section (); break; \ + default: abort (); break; \ + } \ +} diff --git a/gcc_arm/config/arm/riscix.h b/gcc_arm/config/arm/riscix.h new file mode 100755 index 0000000..a96e784 --- /dev/null +++ b/gcc_arm/config/arm/riscix.h @@ -0,0 +1,151 @@ +/* Definitions of target machine for GNU compiler. ARM RISCiX version. + Copyright (C) 1993, 1994, 1995, 1997 Free Software Foundation, Inc. + Contributed by Richard Earnshaw (rwe11@cl.cam.ac.uk), based on original + work by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl) + and Martin Simmons (@harleqn.co.uk). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Translation to find startup files. On RISC iX boxes, + crt0, mcrt0 and gcrt0.o are in /usr/lib. */ +#define STARTFILE_SPEC "\ + %{pg:/usr/lib/gcrt0.o%s}\ + %{!pg:%{p:/usr/lib/mcrt0.o%s}\ + %{!p:/usr/lib/crt0.o%s}}" + +/* RISC iX has no concept of -lg */ +/* If -static is specified then link with -lc_n */ + +#ifndef LIB_SPEC +#define LIB_SPEC "\ + %{g*:-lg}\ + %{!p:%{!pg:%{!static:-lc}%{static:-lc_n}}}\ + %{p:-lc_p}\ + %{pg:-lc_p}" +#endif + +/* The RISC iX assembler never deletes any symbols from the object module; + and, by default, ld doesn't either. -X causes local symbols starting + with 'L' to be deleted, which is what we want. */ +#ifndef LINK_SPEC +#define LINK_SPEC "-X" +#endif + +#ifndef CPP_PREDEFINES +#define CPP_PREDEFINES \ + "-Darm -Driscix -Dunix -Asystem(unix) -Acpu(arm) -Amachine(arm)" +#endif + +#ifndef CPP_SPEC /* CYGNYS LOCAL */ +#define CPP_SPEC "%{m6:-D__arm6__} \ + %{mbsd:%{pedantic:%e-mbsd and -pedantic incompatible} -D_BSD_C} \ + %{mxopen:%{mbsd:%e-mbsd and -mxopen incompatible} \ + %{pedantic:%e-mxopen and -pedantic incompatible} -D_XOPEN_C} \ + %{!mbsd:%{!mxopen:%{!ansi: -D_BSD_C}}}" +#endif /* END CYGNUS LOCAL */ + +/* RISCiX has some weird symbol name munging, that is done to the object module + after assembly, which enables multiple libraries to be supported within + one (possibly shared) library. It basically changes the symbol name of + certain symbols (for example _bcopy is converted to _$bcopy if using BSD) + Symrename's parameters are determined as follows: + -mno-symrename Don't run symrename + -mbsd symrename -BSD + -mxopen symrename -XOPEN + -ansi symrename - + symrename -BSD + */ + +#ifndef ASM_FINAL_SPEC +#if !defined (CROSS_COMPILE) +#define ASM_FINAL_SPEC "\ +%{!mno-symrename: \ + \n /usr/bin/symrename \ + -%{mbsd:%{pedantic:%e-mbsd and -pedantic incompatible}BSD}\ +%{mxopen:%{mbsd:%e-mbsd and -mxopen incompatible}\ +%{pedantic:%e-mxopen and -pedantic incompatible}XOPEN}\ +%{!mbsd:%{!mxopen:%{!ansi:BSD}}} %{c:%{o*:%*}%{!o*:%b.o}}%{!c:%U.o}}" +#endif +#endif + +/* None of these is actually used in cc1. If we don't define them in target + switches cc1 complains about them. For the sake of argument lets allocate + bit 31 of target flags for such options. */ +#define SUBTARGET_SWITCHES \ +{"bsd", 0x80000000}, {"xopen", 0x80000000}, {"no-symrename", 0x80000000}, + + +/* Run-time Target Specification. */ +#define TARGET_VERSION \ + fputs (" (ARM/RISCiX)", stderr); + +/* This is used in ASM_FILE_START */ +#define ARM_OS_NAME "RISCiX" + +/* Unsigned chars produces much better code than signed. */ +#define DEFAULT_SIGNED_CHAR 0 + +/* Define this if the target system supports the function atexit from the + ANSI C standard. If this is not defined, and INIT_SECTION_ASM_OP is not + defined, a default exit function will be provided to support C++. + The man page only describes on_exit, but atexit is also there. */ +#define HAVE_ATEXIT 1 + +/* 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 + must define both, or neither. */ +#ifndef NAME__MAIN +#define NAME__MAIN "__gccmain" +#define SYMBOL__MAIN __gccmain +#endif + +/* size_t is "unsigned int" in RISCiX */ +#define SIZE_TYPE "unsigned int" + +/* ptrdiff_t is "int" in RISCiX */ +#define PTRDIFF_TYPE "int" + +/* Maths operation domain error number, EDOM */ +#define TARGET_EDOM 33 + +/* Override the normal default CPU */ +#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm2 + +#include "arm/aout.h" + +/* The RISCiX assembler does not understand .set */ +#undef SET_ASM_OP + +/* Override CPP_SPEC, there's no point handling endianness (and probably + not much point handling apcs_pc), and we want to add the right #defines + when using the include files. */ +#undef CPP_SPEC +#define CPP_SPEC "%(cpp_cpu_arch) %(cpp_apcs_pc) %(cpp_float) \ + %{mbsd:%{pedantic:%e-mbsd and -pedantic incompatible} -D_BSD_C} \ + %{mxopen:%{mbsd:%e-mbsd and -mxopen incompatible} \ + %{pedantic:%e-mxopen and -pedantic incompatible} -D_XOPEN_C} \ + %{!mbsd:%{!mxopen:%{!ansi: -D_BSD_C}}}" + +/* The native RISCiX assembler does not support stabs of any kind; because + the native assembler is not used by the compiler, Acorn didn't feel it was + necessary to put them in! */ + +#ifdef DBX_DEBUGGING_INFO +#undef DBX_DEBUGGING_INFO +#endif diff --git a/gcc_arm/config/arm/riscix1-1.h b/gcc_arm/config/arm/riscix1-1.h new file mode 100755 index 0000000..aa27965 --- /dev/null +++ b/gcc_arm/config/arm/riscix1-1.h @@ -0,0 +1,100 @@ +/* Definitions of target machine for GNU compiler. ARM RISCiX 1.1x version. + Copyright (C) 1993, 1995, 1997 Free Software Foundation, Inc. + Contributed by Richard Earnshaw (rwe11@cl.cam.ac.uk), based on original + work by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl) + and Martin Simmons (@harleqn.co.uk). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* RISCiX 1.1x is basically the same as 1.2x except that it doesn't have + symrename or atexit. */ + +/* Translation to find startup files. On RISCiX boxes, gcrt0.o is in + /usr/lib. */ +#define STARTFILE_SPEC \ + "%{pg:/usr/lib/gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}" + +#ifndef CPP_PREDEFINES +#define CPP_PREDEFINES "-Darm -Driscix -Dunix -Asystem(unix) -Acpu(arm) -Amachine(arm)" +#endif + +#ifndef CPP_SPEC /* CYGNUS LOCAL */ +#define CPP_SPEC "%{m6:-D__arm6__} %{!ansi: -D_BSD_C}" +#endif /* END CYGNUS LOCAL */ + +/* Riscix 1.1 doesn't have X/OPEN support, so only accept -mbsd (but ignore + it). + By not having -mxopen and -mno-symrename, we get warning messages, + but everything still compiles. */ +/* None of these is actually used in cc1, so they modify bit 31 */ +#define SUBTARGET_SWITCHES \ +{"bsd", 0x80000000}, + + +/* Run-time Target Specification. */ +#define TARGET_VERSION \ + fputs (" (ARM/RISCiX)", stderr); + +/* This is used in ASM_FILE_START */ +#define ARM_OS_NAME "RISCiX" + +#ifdef riscos +#define TARGET_WHEN_DEBUGGING 3 +#else +#define TARGET_WHEN_DEBUGGING 1 +#endif + +/* 'char' is signed by default on RISCiX, unsigned on RISCOS. */ +#ifdef riscos +#define DEFAULT_SIGNED_CHAR 0 +#else +#define DEFAULT_SIGNED_CHAR 1 +#endif + +/* Define this if the target system supports the function atexit form the + ANSI C standard. If this is not defined, and INIT_SECTION_ASM_OP is not + defined, a default exit function will be provided to support C++. + The man page only describes on_exit, but atexit is also there. + This seems to be missing in early versions. */ +/*#define HAVE_ATEXIT 1 */ +/* 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 + must define both, or neither. */ +#ifndef NAME__MAIN +#define NAME__MAIN "__gccmain" +#define SYMBOL__MAIN __gccmain +#endif + +/* Override the normal default CPU */ +#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm2 + +#include "arm/aout.h" + +#undef CPP_SPEC +#define CPP_SPEC "\ +%(cpp_cpu_arch) %(cpp_apcs_pc) %(cpp_float) %{!ansi: -D_BSD_C} \ +" + +/* The native RISCiX assembler does not support stabs of any kind; because + the native assembler is not used by the compiler, Acorn didn't feel it was + necessary to put them in! */ + +#ifdef DBX_DEBUGGING_INFO +#undef DBX_DEBUGGING_INFO +#endif diff --git a/gcc_arm/config/arm/rix-gas.h b/gcc_arm/config/arm/rix-gas.h new file mode 100755 index 0000000..dae16d0 --- /dev/null +++ b/gcc_arm/config/arm/rix-gas.h @@ -0,0 +1,43 @@ +/* Definitions of target machine for GNU compiler. ARM RISCiX(stabs) version. + Copyright (C) 1993 Free Software Foundation, Inc. + Contributed by Richard Earnshaw (rwe11@cl.cam.ac.uk), based on original + work by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl) + and Martin Simmons (@harleqn.co.uk). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Limit the length of a stabs entry (for the broken Acorn assembler) */ +#define DBX_CONTIN_LENGTH 80 + +#include "arm/riscix.h" + +/* The native RISCiX assembler does not support stabs of any kind; because + the native assembler is not used by the compiler, Acorn didn't feel it was + necessary to put them in! + However, this file assumes that we have an assembler that does have stabs, + so we put them back in. */ + +#define DBX_DEBUGGING_INFO + +/* Unfortunately dbx doesn't understand these */ +/* Dbx on RISCiX is so broken that I've given up trying to support it. + lets just support gdb. */ +/* #define DEFAULT_GDB_EXTENSIONS 0 */ +/* RISCiX dbx doesn't accept xrefs */ +/* #define DBX_NO_XREFS 1 */ + diff --git a/gcc_arm/config/arm/semi.h b/gcc_arm/config/arm/semi.h new file mode 100755 index 0000000..98f26ce --- /dev/null +++ b/gcc_arm/config/arm/semi.h @@ -0,0 +1,55 @@ +/* Definitions of target machine for GNU compiler. ARM on semi-hosted platform + Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc. + Contributed by Richard Earnshaw (richard.earnshaw@armltd.co.uk) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* CYGNUS LOCAL */ +/* Note: The definitions LOCAL_LABEL_PREFIX and USER_LABEL_PREFIX here + *must* match the definitions in bfd/coff-arm.c */ +#undef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "." +/* #define LOCAL_LABEL_PREFIX "" */ +/* #define NO_DOT_IN_LABEL */ + +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "" +/* END CYGNUS LOCAL */ + +/* CYGNUS LOCAL */ +#define STARTFILE_SPEC "%scrt0.o" +/* END CYGNUS LOCAL */ + +#define LIB_SPEC "-lc" + +#define CPP_PREDEFINES \ + "-Darm -D__semi__ -Acpu(arm) -Amachine(arm)" + +/* CYGNUS LOCAL */ +#define ASM_SPEC "%{mbig-endian:-EB} %{mcpu=*:-m%*} %{march=*:-m%*} \ + %{mapcs-*:-mapcs-%*} %{mthumb-interwork:-mthumb-interwork}" +/* END CYGNUS LOCAL */ + +#define LINK_SPEC "%{mbig-endian:-EB} -X" + +#define TARGET_VERSION fputs (" (ARM/semi-hosted)", stderr); + +#define TARGET_DEFAULT ARM_FLAG_APCS_32 + +#undef CPP_APCS_PC_DEFAULT_SPEC +#define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__" diff --git a/gcc_arm/config/arm/semiaof.h b/gcc_arm/config/arm/semiaof.h new file mode 100755 index 0000000..14de3b2 --- /dev/null +++ b/gcc_arm/config/arm/semiaof.h @@ -0,0 +1,59 @@ +/* Definitions of target machine for GNU compiler. ARM on semi-hosted platform + AOF Syntax assembler. + Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. + Contributed by Richard Earnshaw (richard.earnshaw@armltd.co.uk) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define CPP_PREDEFINES \ + "-Darm -Dsemi -Acpu(arm) -Amachine(arm)" + + /* CYGNUS LOCAL */ +#define CPP_SPEC "%{m6:-D__arm6__} \ +%{mcpu-*:-D__%*} \ +%{mcpu=*:-D__%*} \ +%{mapcs-32:-D__APCS_32__ -U__APCS_26__} \ +%{mapcs-26:-D__APCS_26__ -U__APCS_32__} \ +%{!mapcs-32: %{!mapcs-26:-D__APCS_32__}} \ +%{msoft-float:-D__SOFTFP__} \ +%{mhard-float:-U__SOFTFP__} \ +%{!mhard-float: %{!msoft-float:-U__SOFTFP__}} \ +%{mbig-endian:-D__ARMEB__ %{mwords-little-endian:-D__ARMWEL__}} \ +%{mbe:-D__ARMEB__ %{mwords-little-endian:-D__ARMWEL__}} \ +%{!mbe: %{!mbig-endian:-D__ARMEL__}} \ +" + /* END CYGNUS LOCAL */ + +#define ASM_SPEC "%{g -g} -arch 4 \ +-apcs 3%{mapcs-32:/32bit}%{mapcs-26:/26bit}%{!mapcs-26:%{!macps-32:/32bit}}" + +#define LIB_SPEC "%{Eb: armlib_h.32b%s}%{!Eb: armlib_h.32l%s}" + +#define TARGET_VERSION fputs (" (ARM/semi-hosted)", stderr); + +#define TARGET_DEFAULT ARM_FLAG_APCS_32 + +/* The Norcroft C library defines size_t as "unsigned int" */ +#define SIZE_TYPE "unsigned int" + +#include "arm/aof.h" + +#undef CPP_APCS_PC_DEFAULT_SPEC +#define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__" + + diff --git a/gcc_arm/config/arm/t-arm-elf b/gcc_arm/config/arm/t-arm-elf new file mode 100755 index 0000000..b57eeca --- /dev/null +++ b/gcc_arm/config/arm/t-arm-elf @@ -0,0 +1,35 @@ +CROSS_LIBGCC1 = libgcc1-asm.a +LIB1ASMSRC = arm/lib1funcs.asm +# CYGNUS LOCAL interworking +LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX +# END CYGNUS LOCAL interworking + +# These are really part of libgcc1, but this will cause them to be +# built correctly, so... + +LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c + +fp-bit.c: $(srcdir)/config/fp-bit.c + echo '#define FLOAT' > fp-bit.c + echo '#ifndef __ARMEB__' >> fp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c + echo '#endif' >> fp-bit.c + cat $(srcdir)/config/fp-bit.c >> fp-bit.c + +dp-bit.c: $(srcdir)/config/fp-bit.c + echo '#ifndef __ARMEB__' > dp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> dp-bit.c + echo '#define FLOAT_WORD_ORDER_MISMATCH' >> dp-bit.c + echo '#endif' >> dp-bit.c + cat $(srcdir)/config/fp-bit.c >> dp-bit.c + +# CYGNUS LOCAL +MULTILIB_OPTIONS = mlittle-endian/mbig-endian mhard-float/msoft-float mapcs-32/mapcs-26 mno-thumb-interwork/mthumb-interwork fno-leading-underscore/fleading-underscore mcpu=arm7 +MULTILIB_DIRNAMES = le be fpu soft 32bit 26bit normal interwork elf under nofmult +MULTILIB_EXCEPTIONS = *mapcs-26/*mthumb-interwork* *mthumb-interwork*/*mcpu=arm7* +MULTILIB_MATCHES = mbig-endian=mbe mlittle-endian=mle mcpu?arm7=mcpu?arm7d mcpu?arm7=mcpu?arm7di mcpu?arm7=mcpu?arm70 mcpu?arm7=mcpu?arm700 mcpu?arm7=mcpu?arm700i mcpu?arm7=mcpu?arm710 mcpu?arm7=mcpu?arm710c mcpu?arm7=mcpu?arm7100 mcpu?arm7=mcpu?arm7500 mcpu?arm7=mcpu?arm7500fe mcpu?arm7=mcpu?arm6 mcpu?arm7=mcpu?arm60 mcpu?arm7=mcpu?arm600 mcpu?arm7=mcpu?arm610 mcpu?arm7=mcpu?arm620 +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib +# END CYGNUS LOCAL + +TARGET_LIBGCC2_CFLAGS = -Dinhibit_libc diff --git a/gcc_arm/config/arm/t-bare b/gcc_arm/config/arm/t-bare new file mode 100755 index 0000000..21e4dd6 --- /dev/null +++ b/gcc_arm/config/arm/t-bare @@ -0,0 +1,34 @@ +CROSS_LIBGCC1 = libgcc1-asm.a +LIB1ASMSRC = arm/lib1funcs.asm +# CYGNUS LOCAL interworking +LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX +# END CYGNUS LOCAL interworking + +# These are really part of libgcc1, but this will cause them to be +# built correctly, so... + +LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c + +fp-bit.c: $(srcdir)/config/fp-bit.c + echo '#define FLOAT' > fp-bit.c + echo '#ifndef __ARMEB__' >> fp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c + echo '#endif' >> fp-bit.c + cat $(srcdir)/config/fp-bit.c >> fp-bit.c + +dp-bit.c: $(srcdir)/config/fp-bit.c + echo '#ifndef __ARMEB__' > dp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> dp-bit.c + echo '#define FLOAT_WORD_ORDER_MISMATCH' >> dp-bit.c + echo '#endif' >> dp-bit.c + cat $(srcdir)/config/fp-bit.c >> dp-bit.c + +# CYGNUS LOCAL +MULTILIB_OPTIONS = mlittle-endian/mbig-endian mhard-float/msoft-float mapcs-32/mapcs-26 mno-thumb-interwork/mthumb-interwork +MULTILIB_DIRNAMES = le be fpu soft 32bit 26bit normal interwork +MULTILIB_MATCHES = +MULTILIB_EXCEPTIONS = *mapcs-26/*mthumb-interwork* +# END CYGNUS LOCAL + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib diff --git a/gcc_arm/config/arm/t-linux b/gcc_arm/config/arm/t-linux new file mode 100755 index 0000000..0160ee6 --- /dev/null +++ b/gcc_arm/config/arm/t-linux @@ -0,0 +1,42 @@ +# Just for these, we omit the frame pointer since it makes such a big +# difference. It is then pointless adding debugging. +LIBGCC2_CFLAGS=-O2 -fomit-frame-pointer $(LIBGCC2_INCLUDES) $(GCC_CFLAGS) -g0 + +# Don't build enquire +ENQUIRE= + +# Since libgcc1 is an assembler file, we can build it automatically for the +# cross-compiler. +CROSS_LIBGCC1 = libgcc1-asm.a +LIBGCC1 = libgcc1-asm.a +LIB1ASMSRC = arm/lib1funcs.asm +LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_lnx + +# CYGNUS LOCAL +# These are really part of libgcc1, but this will cause them to be +# built correctly, so... + +LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c + +fp-bit.c: $(srcdir)/config/fp-bit.c + echo '#define FLOAT' > fp-bit.c + echo '#ifndef __ARMEB__' >> fp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c + echo '#endif' >> fp-bit.c + cat $(srcdir)/config/fp-bit.c >> fp-bit.c + +dp-bit.c: $(srcdir)/config/fp-bit.c + echo '#ifndef __ARMEB__' > dp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> dp-bit.c + echo '#define FLOAT_WORD_ORDER_MISMATCH' >> dp-bit.c + echo '#endif' >> dp-bit.c + cat $(srcdir)/config/fp-bit.c >> dp-bit.c + +MULTILIB_OPTIONS = mlittle-endian/mbig-endian mhard-float/msoft-float mapcs-32/mapcs-26 mno-thumb-interwork/mthumb-interwork +MULTILIB_DIRNAMES = le be fpu soft 32bit 26bit normal interwork +MULTILIB_MATCHES = +MULTILIB_EXCEPTIONS = *mapcs-26/*mthumb-interwork* +# END CYGNUS LOCAL + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib diff --git a/gcc_arm/config/arm/t-netbsd b/gcc_arm/config/arm/t-netbsd new file mode 100755 index 0000000..cc2f658 --- /dev/null +++ b/gcc_arm/config/arm/t-netbsd @@ -0,0 +1,7 @@ +# Just for these, we omit the frame pointer since it makes such a big +# difference. It is then pointless adding debugging. +LIBGCC2_CFLAGS=-O2 -fomit-frame-pointer $(LIBGCC2_INCLUDES) $(GCC_CFLAGS) -g0 +# -Dinhibit_libc + +# Don't build enquire +ENQUIRE= diff --git a/gcc_arm/config/arm/t-pe b/gcc_arm/config/arm/t-pe new file mode 100755 index 0000000..e68b3c9 --- /dev/null +++ b/gcc_arm/config/arm/t-pe @@ -0,0 +1,31 @@ +CROSS_LIBGCC1 = libgcc1-asm.a +LIB1ASMSRC = arm/lib1funcs.asm +LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX _interwork_call_via_rX + +# These are really part of libgcc1, but this will cause them to be +# built correctly, so... + +LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c + +fp-bit.c: $(srcdir)/config/fp-bit.c + echo '#define FLOAT' > fp-bit.c + echo '#ifndef __ARMEB__' >> fp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c + echo '#endif' >> fp-bit.c + cat $(srcdir)/config/fp-bit.c >> fp-bit.c + +dp-bit.c: $(srcdir)/config/fp-bit.c + echo '#ifndef __ARMEB__' > dp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> dp-bit.c + echo '#define FLOAT_WORD_ORDER_MISMATCH' >> dp-bit.c + echo '#endif' >> dp-bit.c + cat $(srcdir)/config/fp-bit.c >> dp-bit.c + +pe.o: $(srcdir)/config/arm/pe.c + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/arm/pe.c + +MULTILIB_OPTIONS = mhard-float +MULTILIB_DIRNAMES = fpu + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib diff --git a/gcc_arm/config/arm/t-pe-thumb b/gcc_arm/config/arm/t-pe-thumb new file mode 100755 index 0000000..253c814 --- /dev/null +++ b/gcc_arm/config/arm/t-pe-thumb @@ -0,0 +1,37 @@ +# Makefile fragment +# Copyright (c) 1998 Free Software Foundation +# CYGNUS LOCAL (entire file) nickc/thumb-pe + +CROSS_LIBGCC1 = libgcc1-asm.a +LIB1ASMSRC = arm/lib1thumb.asm +LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX _interwork_call_via_rX + +# These are really part of libgcc1, but this will cause them to be +# built correctly, so... + +LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c + +fp-bit.c: $(srcdir)/config/fp-bit.c + echo '#define FLOAT' > fp-bit.c + echo '#ifndef __ARMEB__' >> fp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c + echo '#endif' >> fp-bit.c + cat $(srcdir)/config/fp-bit.c >> fp-bit.c + +dp-bit.c: $(srcdir)/config/fp-bit.c + echo '#ifndef __ARMEB__' > dp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> dp-bit.c + echo '#define FLOAT_WORD_ORDER_MISMATCH' >> dp-bit.c + echo '#endif' >> dp-bit.c + cat $(srcdir)/config/fp-bit.c >> dp-bit.c + +# Rule to build Psion specific GCC functions. +pe.o: $(srcdir)/config/arm/pe.c + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/arm/pe.c + +# Avoid building a duplicate set of libraries for the default endian-ness. +MULTILIB_OPTIONS = mthumb-interwork +MULTILIB_DIRNAMES = interwork + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib diff --git a/gcc_arm/config/arm/t-riscix b/gcc_arm/config/arm/t-riscix new file mode 100755 index 0000000..e5a2213 --- /dev/null +++ b/gcc_arm/config/arm/t-riscix @@ -0,0 +1,3 @@ +# Just for these, we omit the frame pointer since it makes such a big +# difference. It is then pointless adding debugging. +LIBGCC2_CFLAGS=-O2 -fomit-frame-pointer $(LIBGCC2_INCLUDES) $(GCC_CFLAGS) -g0 diff --git a/gcc_arm/config/arm/t-semi b/gcc_arm/config/arm/t-semi new file mode 100755 index 0000000..61c1c37 --- /dev/null +++ b/gcc_arm/config/arm/t-semi @@ -0,0 +1,47 @@ +# Just for these, we omit the frame pointer since it makes such a big +# difference. It is then pointless adding debugging. +LIBGCC2_CFLAGS=-O2 -fomit-frame-pointer $(LIBGCC2_INCLUDES) $(GCC_CFLAGS) -g0 + +# Don't build enquire +ENQUIRE= + +# Can't test libgcc1 since it tries to bring in things like malloc, and +# there probably isn't a libc to link against until we have a compiler. +LIBGCC1_TEST = + +CROSS_LIBGCC1 = libgcc1-asm.a +LIB1ASMSRC = arm/lib1funcs.asm +LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX _interwork_call_via_rX + +#Don't try to run fixproto +STMP_FIXPROTO = + +# These are really part of libgcc1, but this will cause them to be +# built correctly, so... + +LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c + +fp-bit.c: $(srcdir)/config/fp-bit.c + echo '#ifdef __SOFTFP__' > fp-bit.c + echo '#define FLOAT' >> fp-bit.c + echo '#ifndef __ARMEB__' >> fp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c + echo '#endif' >> fp-bit.c + cat $(srcdir)/config/fp-bit.c >> fp-bit.c + echo '#endif' >> fp-bit.c + +dp-bit.c: $(srcdir)/config/fp-bit.c + echo '#ifdef __SOFTFP__' > dp-bit.c + echo '#ifndef __ARMEB__' >> dp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> dp-bit.c + echo '#define FLOAT_WORD_ORDER_MISMATCH' >> dp-bit.c + echo '#endif' >> dp-bit.c + cat $(srcdir)/config/fp-bit.c >> dp-bit.c + echo '#endif' >> dp-bit.c + +MULTILIB_OPTIONS = msoft-float mapcs-26 mbig-endian mwords-little-endian +MULTILIB_DIRNAMES = soft apcs26 big wlittle +MULTILIB_EXCEPTIONS = *mapcs-26/*mbig-endian* mwords-little-endian *mapcs-26/mwords-little-endian msoft-float/mwords-little-endian + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib diff --git a/gcc_arm/config/arm/t-semiaof b/gcc_arm/config/arm/t-semiaof new file mode 100755 index 0000000..1017543 --- /dev/null +++ b/gcc_arm/config/arm/t-semiaof @@ -0,0 +1,64 @@ +OLDCC = armcc -w +# Don't build enquire +ENQUIRE= +CROSS_LIBGCC1 = libgcc1-aof.a +LIBGCC2 = libgcc2-aof.a +LIBGCC = libgcc-aof.a +LIBGCC2_CFLAGS = -O2 -fomit-frame-pointer +LIBGCC1_TEST = #libgcc1-atest +EXTRA_PARTS = crtbegin.o crtend.o +STMP_FIXPROTO = + +# Rule to build libgcc1.a and libgcc2.a and libgcc.a, since the librarian +# for the ARM tools is somewhat quirky, and needs a special rule to use it. +libgcc1-aof.a: libgcc1.c $(CONFIG_H) config.status + -rm -rf tmplib libgcc1.a libgcc1-aof.a tmplibgcc1.a + mkdir tmplib + for name in $(LIB1FUNCS); \ + do \ + echo $${name}; \ + rm -f $${name}$(objext); \ + $(OLDCC) $(CCLIBFLAGS) $(INCLUDES) -c -DL$${name} $(srcdir)/libgcc1.c; \ + if [ $$? -eq 0 ] ; then true; else exit 1; fi; \ + mv libgcc1$(objext) tmplib/$${name}$(objext); \ + done + (cd tmplib; \ + armlib -c tmplibgcc1.a *; \ + mv tmplibgcc1.a ..) + mv tmplibgcc1.a libgcc1-aof.a + rm -rf tmplib + +libgcc2-aof.a: libgcc2.c libgcc2.ready $(CONFIG_H) $(LIB2FUNCS_EXTRA) \ + machmode.h longlong.h gbl-ctors.h config.status + -rm -f tmplibgcc2.a + -rm -rf tmplib + mkdir tmplib + for name in $(LIB2FUNCS); \ + do \ + echo $${name}; \ + $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) -c -DL$${name} \ + $(srcdir)/libgcc2.c -o tmplib/$${name}$(objext); \ + if [ $$? -eq 0 ] ; then true; else exit 1; fi; \ + done + (cd tmplib; \ + armlib -c tmplibgcc2.a *; \ + mv tmplibgcc2.a ..) + mv tmplibgcc2.a libgcc2-aof.a + rm -rf tmplib + +# Combine the various libraries into a single library, libgcc.a. +libgcc-aof.a: $(CROSS_LIBGCC1) $(LIBGCC2) + -rm -rf tmplibgcc.a libgcc.a tmpcopy libgcc-aof.a + mkdir tmpcopy + (cd tmpcopy; armlib -e ../$(LIBGCC1) \*) + -(cd tmpcopy; chmod +w * > /dev/null 2>&1) + (cd tmpcopy; armlib -e ../$(LIBGCC2) \*) + (cd tmpcopy; armlib -co ../tmplibgcc.a *$(objext)) + rm -rf tmpcopy + mv tmplibgcc.a libgcc.a + ln libgcc.a libgcc-aof.a + +libgcc1-atest: libgcc1-test.o native $(GCC_PARTS) $(EXTRA_PARTS) + @echo "Testing libgcc1. Ignore linker warning messages." + $(GCC_FOR_TARGET) $(GCC_CFLAGS) libgcc1-test.o -o libgcc1-test \ + -v diff --git a/gcc_arm/config/arm/t-thumb b/gcc_arm/config/arm/t-thumb new file mode 100755 index 0000000..6cd8a13 --- /dev/null +++ b/gcc_arm/config/arm/t-thumb @@ -0,0 +1,31 @@ +CROSS_LIBGCC1 = libgcc1-asm.a +LIB1ASMSRC = arm/lib1thumb.asm +LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX _interwork_call_via_rX +# adddi3/subdi3 added to machine description + +# These are really part of libgcc1, but this will cause them to be +# built correctly, so... + +LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c + +fp-bit.c: $(srcdir)/config/fp-bit.c + echo '#define FLOAT' > fp-bit.c + echo '#ifndef __ARMEB__' >> fp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c + echo '#endif' >> fp-bit.c + cat $(srcdir)/config/fp-bit.c >> fp-bit.c + +dp-bit.c: $(srcdir)/config/fp-bit.c + echo '#ifndef __ARMEB__' > dp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> dp-bit.c + echo '#define FLOAT_WORD_ORDER_MISMATCH' >> dp-bit.c + echo '#endif' >> dp-bit.c + cat $(srcdir)/config/fp-bit.c >> dp-bit.c + +# Avoid building a duplicate set of libraries for the default endian-ness. +MULTILIB_OPTIONS = mlittle-endian/mbig-endian mno-thumb-interwork/mthumb-interwork +MULTILIB_DIRNAMES = le be normal interwork +MULTILIB_MATCHES = mbig-endian=mbe mlittle-endian=mle + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib diff --git a/gcc_arm/config/arm/t-thumb-elf b/gcc_arm/config/arm/t-thumb-elf new file mode 100755 index 0000000..2f5054d --- /dev/null +++ b/gcc_arm/config/arm/t-thumb-elf @@ -0,0 +1,32 @@ +# CYGNUS LOCAL (entire file) clm/arm-elf +CROSS_LIBGCC1 = libgcc1-asm.a +LIB1ASMSRC = arm/lib1thumb.asm +LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX _interwork_call_via_rX +# adddi3/subdi3 added to machine description + +# These are really part of libgcc1, but this will cause them to be +# built correctly, so... + +LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c + +fp-bit.c: $(srcdir)/config/fp-bit.c + echo '#define FLOAT' > fp-bit.c + echo '#ifndef __ARMEB__' >> fp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c + echo '#endif' >> fp-bit.c + cat $(srcdir)/config/fp-bit.c >> fp-bit.c + +dp-bit.c: $(srcdir)/config/fp-bit.c + echo '#ifndef __ARMEB__' > dp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> dp-bit.c + echo '#define FLOAT_WORD_ORDER_MISMATCH' >> dp-bit.c + echo '#endif' >> dp-bit.c + cat $(srcdir)/config/fp-bit.c >> dp-bit.c + +# Avoid building a duplicate set of libraries for the default endian-ness. +MULTILIB_OPTIONS = mlittle-endian/mbig-endian mno-thumb-interwork/mthumb-interwork fno-leading-underscore/fleading-underscore +MULTILIB_DIRNAMES = le be normal interwork elf under +MULTILIB_MATCHES = mbig-endian=mbe mlittle-endian=mle + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib diff --git a/gcc_arm/config/arm/tcoff.h b/gcc_arm/config/arm/tcoff.h new file mode 100755 index 0000000..6fa4705 --- /dev/null +++ b/gcc_arm/config/arm/tcoff.h @@ -0,0 +1,192 @@ +/* Definitions of target machine for GNU compiler, + for Thumb with COFF obj format. + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + Derived from arm/coff.h originally by Doug Evans (dje@cygnus.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "arm/thumb.h" + +/* Run-time Target Specification. */ +#undef TARGET_VERSION +#define TARGET_VERSION fputs (" (Thumb/coff)", stderr) + +#define MULTILIB_DEFAULTS { "mlittle-endian" } + +/* Setting this to 32 produces more efficient code, but the value set in previous + versions of this toolchain was 8, which produces more compact structures. The + command line option -mstructure_size_boundary= can be used to change this + value. */ +#undef STRUCTURE_SIZE_BOUNDARY +#define STRUCTURE_SIZE_BOUNDARY arm_structure_size_boundary + +extern int arm_structure_size_boundary; + +/* This is COFF, but prefer stabs. */ +#define SDB_DEBUGGING_INFO + +#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG + +#include "dbxcoff.h" + +/* Note - it is important that these definitions match those in semi.h for the ARM port. */ +#undef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "." + +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "" + +/* A C statement to output assembler commands which will identify the + object file as having been compiled with GNU CC (or another GNU + compiler). */ +#define ASM_IDENTIFY_GCC(STREAM) \ + fprintf (STREAM, "%sgcc2_compiled.:\n", LOCAL_LABEL_PREFIX ) + +#undef ASM_FILE_START +#define ASM_FILE_START(STREAM) \ +do { \ + extern char *version_string; \ + fprintf ((STREAM), "%s Generated by gcc %s for Thumb/coff\n", \ + ASM_COMMENT_START, version_string); \ + fprintf ((STREAM), ASM_APP_OFF); \ +} while (0) + +/* A C statement to output something to the assembler file to switch to section + NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or + NULL_TREE. Some target formats do not support arbitrary sections. Do not + define this macro in such cases. */ +#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ +do { \ + if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ + fprintf (STREAM, "\t.section %s,\"x\"\n", (NAME)); \ + else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ + fprintf (STREAM, "\t.section %s,\"\"\n", (NAME)); \ + else \ + fprintf (STREAM, "\t.section %s,\"w\"\n", (NAME)); \ +} while (0) + +/* Support the ctors/dtors and other sections. */ + +#undef INIT_SECTION_ASM_OP + +/* Define this macro if jump tables (for `tablejump' insns) should be + output in the text section, along with the assembler instructions. + Otherwise, the readonly data section is used. */ +#define JUMP_TABLES_IN_TEXT_SECTION 1 + +#undef READONLY_DATA_SECTION +#define READONLY_DATA_SECTION rdata_section +#undef RDATA_SECTION_ASM_OP +#define RDATA_SECTION_ASM_OP "\t.section .rdata" + +#undef CTORS_SECTION_ASM_OP +#define CTORS_SECTION_ASM_OP "\t.section .ctors,\"x\"" +#undef DTORS_SECTION_ASM_OP +#define DTORS_SECTION_ASM_OP "\t.section .dtors,\"x\"" + +/* A list of other sections which the compiler might be "in" at any + given time. */ + +#undef EXTRA_SECTIONS +#define EXTRA_SECTIONS SUBTARGET_EXTRA_SECTIONS in_rdata, in_ctors, in_dtors + +#define SUBTARGET_EXTRA_SECTIONS + +/* A list of extra section function definitions. */ + +#undef EXTRA_SECTION_FUNCTIONS +#define EXTRA_SECTION_FUNCTIONS \ + RDATA_SECTION_FUNCTION \ + CTORS_SECTION_FUNCTION \ + DTORS_SECTION_FUNCTION \ + SUBTARGET_EXTRA_SECTION_FUNCTIONS + +#define SUBTARGET_EXTRA_SECTION_FUNCTIONS + +#define RDATA_SECTION_FUNCTION \ +void \ +rdata_section () \ +{ \ + if (in_section != in_rdata) \ + { \ + fprintf (asm_out_file, "%s\n", RDATA_SECTION_ASM_OP); \ + in_section = in_rdata; \ + } \ +} + +#define CTORS_SECTION_FUNCTION \ +void \ +ctors_section () \ +{ \ + if (in_section != in_ctors) \ + { \ + fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \ + in_section = in_ctors; \ + } \ +} + +#define DTORS_SECTION_FUNCTION \ +void \ +dtors_section () \ +{ \ + if (in_section != in_dtors) \ + { \ + fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \ + in_section = in_dtors; \ + } \ +} + +/* Support the ctors/dtors sections for g++. */ + +#define INT_ASM_OP ".word" + +/* A C statement (sans semicolon) to output an element in the table of + global constructors. */ +#undef ASM_OUTPUT_CONSTRUCTOR +#define ASM_OUTPUT_CONSTRUCTOR(STREAM,NAME) \ +do { \ + ctors_section (); \ + fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} while (0) + +/* A C statement (sans semicolon) to output an element in the table of + global destructors. */ +#undef ASM_OUTPUT_DESTRUCTOR +#define ASM_OUTPUT_DESTRUCTOR(STREAM,NAME) \ +do { \ + dtors_section (); \ + fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} while (0) + +/* __CTOR_LIST__ and __DTOR_LIST__ must be defined by the linker script. */ +#define CTOR_LISTS_DEFINED_EXTERNALLY + +#undef DO_GLOBAL_CTORS_BODY +#undef DO_GLOBAL_DTORS_BODY + +/* The ARM development system has atexit and doesn't have _exit, + so define this for now. */ +#define HAVE_ATEXIT + +/* The ARM development system defines __main. */ +#define NAME__MAIN "__gccmain" +#define SYMBOL__MAIN __gccmain diff --git a/gcc_arm/config/arm/telf-oabi.h b/gcc_arm/config/arm/telf-oabi.h new file mode 100755 index 0000000..17e85e2 --- /dev/null +++ b/gcc_arm/config/arm/telf-oabi.h @@ -0,0 +1,244 @@ +/* CYGNUS LOCAL (entire file) clm/arm-elf */ +/* Definitions of target machine for GNU compiler, + for Thumb with ELF obj format. + Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define OBJECT_FORMAT_ELF + +#define CPP_PREDEFINES "-Darm_oabi -Dthumb -Dthumbelf -D__thumb -Acpu(arm) -Amachine(arm)" + +#define ASM_SPEC "-moabi -marm7tdmi %{mthumb-interwork:-mthumb-interwork} %{mbig-endian:-EB}" + +#include "arm/thumb.h" + +/* Run-time Target Specification. */ +#undef TARGET_VERSION +#define TARGET_VERSION fputs (" (Thumb/elf)", stderr) + +#define MULTILIB_DEFAULTS { "mlittle-endian" } + +/* Setting this to 32 produces more efficient code, but the value set in previous + versions of this toolchain was 8, which produces more compact structures. The + command line option -mstructure_size_boundary= can be used to change this + value. */ +#undef STRUCTURE_SIZE_BOUNDARY +#define STRUCTURE_SIZE_BOUNDARY arm_structure_size_boundary + +extern int arm_structure_size_boundary; + +/* Debug */ +#define DWARF_DEBUGGING_INFO +#define DWARF2_DEBUGGING_INFO +#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG + + +/* Note - it is important that these definitions match those in semi.h for the ARM port. */ +#undef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "." + + +/* A C statement to output assembler commands which will identify the + object file as having been compiled with GNU CC (or another GNU + compiler). */ +#define ASM_IDENTIFY_GCC(STREAM) \ + fprintf (STREAM, "%sgcc2_compiled.:\n", LOCAL_LABEL_PREFIX ) + +#undef ASM_FILE_START +#define ASM_FILE_START(STREAM) \ +do { \ + extern char *version_string; \ + fprintf ((STREAM), "%s Generated by gcc %s for Thumb/elf\n", \ + ASM_COMMENT_START, version_string); \ + fprintf ((STREAM), ASM_APP_OFF); \ +} while (0) + +/* A C statement to output something to the assembler file to switch to section + NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or + NULL_TREE. Some target formats do not support arbitrary sections. Do not + define this macro in such cases. */ +#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ +do { \ + if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ + fprintf (STREAM, "\t.section %s,\"ax\",@progbits\n", (NAME)); \ + else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ + fprintf (STREAM, "\t.section %s,\"a\"\n", (NAME)); \ + else \ + fprintf (STREAM, "\t.section %s,\"aw\"\n", (NAME)); \ +} while (0) + +/* Support the ctors/dtors and other sections. */ + +#undef INIT_SECTION_ASM_OP + +/* Define this macro if jump tables (for `tablejump' insns) should be + output in the text section, along with the assembler instructions. + Otherwise, the readonly data section is used. */ +#define JUMP_TABLES_IN_TEXT_SECTION 1 + +#undef READONLY_DATA_SECTION +#define READONLY_DATA_SECTION rdata_section +#undef RDATA_SECTION_ASM_OP +#define RDATA_SECTION_ASM_OP "\t.section .rodata" + +#undef CTORS_SECTION_ASM_OP +#define CTORS_SECTION_ASM_OP "\t.section .ctors,\"aw\"" +#undef DTORS_SECTION_ASM_OP +#define DTORS_SECTION_ASM_OP "\t.section .dtors,\"aw\"" + +#define USER_LABEL_PREFIX "" + +/* Don't know how to order these. UNALIGNED_WORD_ASM_OP is in + dwarf2.out. */ +#define UNALIGNED_WORD_ASM_OP ".4byte" + +#define ASM_OUTPUT_DWARF2_ADDR_CONST(FILE,ADDR) \ + if (((ADDR)[0] == '.') && ((ADDR)[1] == 'L')) \ + fprintf ((FILE), "\t%s\t%s", UNALIGNED_WORD_ASM_OP, (ADDR)); \ + else \ + fprintf ((FILE), "\t%s\t%s", \ + UNALIGNED_WORD_ASM_OP, (ADDR)) + +#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,RTX) \ +do { \ + fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \ + output_addr_const ((FILE), (RTX)); \ + fputc ('\n', (FILE)); \ +} while (0) + +/* This is how to equate one symbol to another symbol. The syntax used is + `SYM1=SYM2'. Note that this is different from the way equates are done + with most svr4 assemblers, where the syntax is `.set SYM1,SYM2'. */ + +#define ASM_OUTPUT_DEF(FILE,LABEL1,LABEL2) \ + do { fprintf ((FILE), "\t"); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, " = "); \ + assemble_name (FILE, LABEL2); \ + fprintf (FILE, "\n"); \ + } while (0) + +/* A list of other sections which the compiler might be "in" at any + given time. */ +#undef EXTRA_SECTIONS +#define EXTRA_SECTIONS SUBTARGET_EXTRA_SECTIONS in_rdata, in_ctors, in_dtors + +#define SUBTARGET_EXTRA_SECTIONS + +/* A list of extra section function definitions. */ + +#undef EXTRA_SECTION_FUNCTIONS +#define EXTRA_SECTION_FUNCTIONS \ + RDATA_SECTION_FUNCTION \ + CTORS_SECTION_FUNCTION \ + DTORS_SECTION_FUNCTION \ + SUBTARGET_EXTRA_SECTION_FUNCTIONS + +#define SUBTARGET_EXTRA_SECTION_FUNCTIONS + +#define RDATA_SECTION_FUNCTION \ +void \ +rdata_section () \ +{ \ + if (in_section != in_rdata) \ + { \ + fprintf (asm_out_file, "%s\n", RDATA_SECTION_ASM_OP); \ + in_section = in_rdata; \ + } \ +} + +#define CTOR_LIST_BEGIN \ +asm (CTORS_SECTION_ASM_OP); \ +func_ptr __CTOR_LIST__[1] = { (func_ptr) (-1) } + +#define CTOR_LIST_END \ +asm (CTORS_SECTION_ASM_OP); \ +func_ptr __CTOR_END__[1] = { (func_ptr) 0 }; + +#define DTOR_LIST_BEGIN \ +asm (DTORS_SECTION_ASM_OP); \ +func_ptr __DTOR_LIST__[1] = { (func_ptr) (-1) } + +#define DTOR_LIST_END \ +asm (DTORS_SECTION_ASM_OP); \ +func_ptr __DTOR_END__[1] = { (func_ptr) 0 }; + +#define CTORS_SECTION_FUNCTION \ +void \ +ctors_section () \ +{ \ + if (in_section != in_ctors) \ + { \ + fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \ + in_section = in_ctors; \ + } \ +} + +#define DTORS_SECTION_FUNCTION \ +void \ +dtors_section () \ +{ \ + if (in_section != in_dtors) \ + { \ + fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \ + in_section = in_dtors; \ + } \ +} + +/* Support the ctors/dtors sections for g++. */ + +#define INT_ASM_OP ".word" + +#define INVOKE__main + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "crtbegin%O%s crt0%O%s" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtend%O%s" + +/* A C statement (sans semicolon) to output an element in the table of + global constructors. */ +#undef ASM_OUTPUT_CONSTRUCTOR +#define ASM_OUTPUT_CONSTRUCTOR(STREAM,NAME) \ +do { \ + ctors_section (); \ + fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} while (0) + +/* A C statement (sans semicolon) to output an element in the table of + global destructors. */ +#undef ASM_OUTPUT_DESTRUCTOR +#define ASM_OUTPUT_DESTRUCTOR(STREAM,NAME) \ +do { \ + dtors_section (); \ + fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} while (0) + +/* The ARM development system has atexit and doesn't have _exit, + so define this for now. */ +#define HAVE_ATEXIT + +/* The ARM development system defines __main. */ +#define NAME__MAIN "__gccmain" +#define SYMBOL__MAIN __gccmain diff --git a/gcc_arm/config/arm/telf-oabi_020422.h b/gcc_arm/config/arm/telf-oabi_020422.h new file mode 100755 index 0000000..9b7d6c7 --- /dev/null +++ b/gcc_arm/config/arm/telf-oabi_020422.h @@ -0,0 +1,237 @@ +/* CYGNUS LOCAL (entire file) clm/arm-elf */ +/* Definitions of target machine for GNU compiler, + for Thumb with ELF obj format. + Copyright (C) 1995, 1996, 1997, 1998, 1999, 2001 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define OBJECT_FORMAT_ELF + +#define CPP_PREDEFINES "-Darm_oabi -Dthumb -Dthumbelf -D__thumb -Acpu(arm) -Amachine(arm)" + +#define ASM_SPEC "-moabi -marm7tdmi %{mthumb-interwork:-mthumb-interwork} %{mbig-endian:-EB}" + +#include "arm/thumb.h" + +/* Run-time Target Specification. */ +#undef TARGET_VERSION +#define TARGET_VERSION fputs (" (Thumb/elf)", stderr) + +#define MULTILIB_DEFAULTS { "mlittle-endian" } + +/* Setting this to 32 produces more efficient code, but the value set in previous + versions of this toolchain was 8, which produces more compact structures. The + command line option -mstructure_size_boundary= can be used to change this + value. */ +#undef STRUCTURE_SIZE_BOUNDARY +#define STRUCTURE_SIZE_BOUNDARY arm_structure_size_boundary + +extern int arm_structure_size_boundary; + +/* Debug */ +#define DWARF_DEBUGGING_INFO +#define DWARF2_DEBUGGING_INFO +#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG + + +/* Note - it is important that these definitions match those in semi.h for the ARM port. */ +#undef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "." + + +/* A C statement to output assembler commands which will identify the + object file as having been compiled with GNU CC (or another GNU + compiler). */ +#define ASM_IDENTIFY_GCC(STREAM) \ + fprintf (STREAM, "%sgcc2_compiled.:\n", LOCAL_LABEL_PREFIX ) + +#undef ASM_FILE_START +#define ASM_FILE_START(STREAM) \ +do { \ + extern char *version_string; \ + fprintf ((STREAM), "%s Generated by gcc %s for Thumb/elf\n", \ + ASM_COMMENT_START, version_string); \ + fprintf ((STREAM), ASM_APP_OFF); \ +} while (0) + +/* A C statement to output something to the assembler file to switch to section + NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or + NULL_TREE. Some target formats do not support arbitrary sections. Do not + define this macro in such cases. */ +#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ +do { \ + if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ + fprintf (STREAM, "\t.section %s,\"ax\",@progbits\n", (NAME)); \ + else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ + fprintf (STREAM, "\t.section %s,\"a\"\n", (NAME)); \ + else \ + fprintf (STREAM, "\t.section %s,\"aw\"\n", (NAME)); \ +} while (0) + +/* Support the ctors/dtors and other sections. */ + +#undef INIT_SECTION_ASM_OP + +/* Define this macro if jump tables (for `tablejump' insns) should be + output in the text section, along with the assembler instructions. + Otherwise, the readonly data section is used. */ +#define JUMP_TABLES_IN_TEXT_SECTION 1 + +#undef READONLY_DATA_SECTION +#define READONLY_DATA_SECTION rdata_section +#undef RDATA_SECTION_ASM_OP +#define RDATA_SECTION_ASM_OP "\t.section .rodata" + +#undef CTORS_SECTION_ASM_OP +#define CTORS_SECTION_ASM_OP "\t.section .ctors,\"aw\"" +#undef DTORS_SECTION_ASM_OP +#define DTORS_SECTION_ASM_OP "\t.section .dtors,\"aw\"" + +#define USER_LABEL_PREFIX "" + +/* Don't know how to order these. UNALIGNED_WORD_ASM_OP is in + dwarf2.out. */ +#define UNALIGNED_WORD_ASM_OP ".4byte" + +#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,RTX) \ +do { \ + fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \ + output_addr_const ((FILE), (RTX)); \ + fputc ('\n', (FILE)); \ +} while (0) + +/* This is how to equate one symbol to another symbol. The syntax used is + `SYM1=SYM2'. Note that this is different from the way equates are done + with most svr4 assemblers, where the syntax is `.set SYM1,SYM2'. */ + +#define ASM_OUTPUT_DEF(FILE,LABEL1,LABEL2) \ + do { fprintf ((FILE), "\t"); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, " = "); \ + assemble_name (FILE, LABEL2); \ + fprintf (FILE, "\n"); \ + } while (0) + +/* A list of other sections which the compiler might be "in" at any + given time. */ +#undef EXTRA_SECTIONS +#define EXTRA_SECTIONS SUBTARGET_EXTRA_SECTIONS in_rdata, in_ctors, in_dtors + +#define SUBTARGET_EXTRA_SECTIONS + +/* A list of extra section function definitions. */ + +#undef EXTRA_SECTION_FUNCTIONS +#define EXTRA_SECTION_FUNCTIONS \ + RDATA_SECTION_FUNCTION \ + CTORS_SECTION_FUNCTION \ + DTORS_SECTION_FUNCTION \ + SUBTARGET_EXTRA_SECTION_FUNCTIONS + +#define SUBTARGET_EXTRA_SECTION_FUNCTIONS + +#define RDATA_SECTION_FUNCTION \ +void \ +rdata_section () \ +{ \ + if (in_section != in_rdata) \ + { \ + fprintf (asm_out_file, "%s\n", RDATA_SECTION_ASM_OP); \ + in_section = in_rdata; \ + } \ +} + +#define CTOR_LIST_BEGIN \ +asm (CTORS_SECTION_ASM_OP); \ +func_ptr __CTOR_LIST__[1] = { (func_ptr) (-1) } + +#define CTOR_LIST_END \ +asm (CTORS_SECTION_ASM_OP); \ +func_ptr __CTOR_END__[1] = { (func_ptr) 0 }; + +#define DTOR_LIST_BEGIN \ +asm (DTORS_SECTION_ASM_OP); \ +func_ptr __DTOR_LIST__[1] = { (func_ptr) (-1) } + +#define DTOR_LIST_END \ +asm (DTORS_SECTION_ASM_OP); \ +func_ptr __DTOR_END__[1] = { (func_ptr) 0 }; + +#define CTORS_SECTION_FUNCTION \ +void \ +ctors_section () \ +{ \ + if (in_section != in_ctors) \ + { \ + fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \ + in_section = in_ctors; \ + } \ +} + +#define DTORS_SECTION_FUNCTION \ +void \ +dtors_section () \ +{ \ + if (in_section != in_dtors) \ + { \ + fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \ + in_section = in_dtors; \ + } \ +} + +/* Support the ctors/dtors sections for g++. */ + +#define INT_ASM_OP ".word" + +#define INVOKE__main + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "crtbegin%O%s crt0%O%s" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtend%O%s" + +/* A C statement (sans semicolon) to output an element in the table of + global constructors. */ +#undef ASM_OUTPUT_CONSTRUCTOR +#define ASM_OUTPUT_CONSTRUCTOR(STREAM,NAME) \ +do { \ + ctors_section (); \ + fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} while (0) + +/* A C statement (sans semicolon) to output an element in the table of + global destructors. */ +#undef ASM_OUTPUT_DESTRUCTOR +#define ASM_OUTPUT_DESTRUCTOR(STREAM,NAME) \ +do { \ + dtors_section (); \ + fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} while (0) + +/* The ARM development system has atexit and doesn't have _exit, + so define this for now. */ +#define HAVE_ATEXIT + +/* The ARM development system defines __main. */ +#define NAME__MAIN "__gccmain" +#define SYMBOL__MAIN __gccmain diff --git a/gcc_arm/config/arm/telf.h b/gcc_arm/config/arm/telf.h new file mode 100755 index 0000000..29297b0 --- /dev/null +++ b/gcc_arm/config/arm/telf.h @@ -0,0 +1,450 @@ +/* CYGNUS LOCAL (entire file) clm/arm-elf */ +/* Definitions of target machine for GNU compiler, + for Thumb with ELF obj format. + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define OBJECT_FORMAT_ELF + +#define CPP_PREDEFINES "-Dthumb -Dthumbelf -D__thumb -Acpu(arm) -Amachine(arm)" + +#include "arm/thumb.h" + +/* Run-time Target Specification. */ +#undef TARGET_VERSION +#define TARGET_VERSION fputs (" (Thumb/elf)", stderr) + +#define MULTILIB_DEFAULTS { "mlittle-endian" } + +/* Setting this to 32 produces more efficient code, but the value set in previous + versions of this toolchain was 8, which produces more compact structures. The + command line option -mstructure_size_boundary= can be used to change this + value. */ +#undef STRUCTURE_SIZE_BOUNDARY +#define STRUCTURE_SIZE_BOUNDARY arm_structure_size_boundary + +extern int arm_structure_size_boundary; + +/* Debug */ +#define DWARF_DEBUGGING_INFO +#define DWARF2_DEBUGGING_INFO +#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG + + +/* Note - it is important that these definitions match those in semi.h for the ARM port. */ +#undef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "." + + +/* A C statement to output assembler commands which will identify the + object file as having been compiled with GNU CC (or another GNU + compiler). */ +#define ASM_IDENTIFY_GCC(STREAM) \ + fprintf (STREAM, "%sgcc2_compiled.:\n", LOCAL_LABEL_PREFIX ) + +#undef ASM_FILE_START +#define ASM_FILE_START(STREAM) \ +do { \ + extern char *version_string; \ + fprintf ((STREAM), "%s Generated by gcc %s for Thumb/elf\n", \ + ASM_COMMENT_START, version_string); \ + fprintf ((STREAM), ASM_APP_OFF); \ +} while (0) + +/* A C statement to output something to the assembler file to switch to section + NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or + NULL_TREE. Some target formats do not support arbitrary sections. Do not + define this macro in such cases. */ +#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ +do { \ + if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ + fprintf (STREAM, "\t.section %s,\"ax\",%%progbits\n", (NAME)); \ + else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ + fprintf (STREAM, "\t.section %s,\"a\"\n", (NAME)); \ + else if (0 == strncmp((NAME), ".bss", sizeof(".bss") - 1)) \ + fprintf (STREAM, "\t.section %s,\"aw\",%%nobits\n", (NAME)); \ + else \ + fprintf (STREAM, "\t.section %s,\"aw\"\n", (NAME)); \ +} while (0) + +/* Support the ctors/dtors and other sections. */ + +#undef INIT_SECTION_ASM_OP + +/* Define this macro if jump tables (for `tablejump' insns) should be + output in the text section, along with the assembler instructions. + Otherwise, the readonly data section is used. */ +#define JUMP_TABLES_IN_TEXT_SECTION 1 + +#undef READONLY_DATA_SECTION +#define READONLY_DATA_SECTION rdata_section +#undef RDATA_SECTION_ASM_OP +#define RDATA_SECTION_ASM_OP "\t.section .rodata" + +#undef CTORS_SECTION_ASM_OP +#define CTORS_SECTION_ASM_OP "\t.section .ctors,\"aw\"" +#undef DTORS_SECTION_ASM_OP +#define DTORS_SECTION_ASM_OP "\t.section .dtors,\"aw\"" + +#define USER_LABEL_PREFIX "" + +/* 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. */ +#ifndef BSS_SECTION_ASM_OP +#define BSS_SECTION_ASM_OP ".section\t.bss" +#endif + +/* 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. */ +#ifndef ASM_OUTPUT_ALIGNED_BSS +#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \ + asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN) +#endif + +/* Don't know how to order these. UNALIGNED_WORD_ASM_OP is in + dwarf2.out. */ +#define UNALIGNED_WORD_ASM_OP ".4byte" + +#define ASM_OUTPUT_DWARF2_ADDR_CONST(FILE,ADDR) \ + if (((ADDR)[0] == '.') && ((ADDR)[1] == 'L')) \ + fprintf ((FILE), "\t%s\t%s", UNALIGNED_WORD_ASM_OP, (ADDR)); \ + else \ + fprintf ((FILE), "\t%s\t%s", \ + UNALIGNED_WORD_ASM_OP, (ADDR)) + +#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,RTX) \ +do { \ + fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \ + output_addr_const ((FILE), (RTX)); \ + fputc ('\n', (FILE)); \ +} while (0) + +/* This is how to equate one symbol to another symbol. The syntax used is + `SYM1=SYM2'. Note that this is different from the way equates are done + with most svr4 assemblers, where the syntax is `.set SYM1,SYM2'. */ + +#define ASM_OUTPUT_DEF(FILE,LABEL1,LABEL2) \ + do { fprintf ((FILE), "\t"); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, " = "); \ + assemble_name (FILE, LABEL2); \ + fprintf (FILE, "\n"); \ + } while (0) + +/* For aliases of functions we use .thumb_set instead. */ +#define ASM_OUTPUT_DEF_FROM_DECLS(FILE,DECL1,DECL2) \ + do \ + { \ + char * LABEL1 = XSTR (XEXP (DECL_RTL (decl), 0), 0); \ + char * LABEL2 = IDENTIFIER_POINTER (DECL2); \ + \ + if (TREE_CODE (DECL1) == FUNCTION_DECL) \ + { \ + fprintf (FILE, "\t.thumb_set "); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, ","); \ + assemble_name (FILE, LABEL2); \ + fprintf (FILE, "\n"); \ + } \ + else \ + ASM_OUTPUT_DEF (FILE, LABEL1, LABEL2); \ + } \ + while (0) + +/* A list of other sections which the compiler might be "in" at any + given time. */ +#undef EXTRA_SECTIONS +#define EXTRA_SECTIONS SUBTARGET_EXTRA_SECTIONS in_rdata, in_ctors, in_dtors + +#define SUBTARGET_EXTRA_SECTIONS + +/* A list of extra section function definitions. */ + +#undef EXTRA_SECTION_FUNCTIONS +#define EXTRA_SECTION_FUNCTIONS \ + RDATA_SECTION_FUNCTION \ + CTORS_SECTION_FUNCTION \ + DTORS_SECTION_FUNCTION \ + SUBTARGET_EXTRA_SECTION_FUNCTIONS + +#define SUBTARGET_EXTRA_SECTION_FUNCTIONS + +#define RDATA_SECTION_FUNCTION \ +void \ +rdata_section () \ +{ \ + if (in_section != in_rdata) \ + { \ + fprintf (asm_out_file, "%s\n", RDATA_SECTION_ASM_OP); \ + in_section = in_rdata; \ + } \ +} + +#define CTOR_LIST_BEGIN \ +asm (CTORS_SECTION_ASM_OP); \ +func_ptr __CTOR_LIST__[1] = { (func_ptr) (-1) } + +#define CTOR_LIST_END \ +asm (CTORS_SECTION_ASM_OP); \ +func_ptr __CTOR_END__[1] = { (func_ptr) 0 }; + +#define DTOR_LIST_BEGIN \ +asm (DTORS_SECTION_ASM_OP); \ +func_ptr __DTOR_LIST__[1] = { (func_ptr) (-1) } + +#define DTOR_LIST_END \ +asm (DTORS_SECTION_ASM_OP); \ +func_ptr __DTOR_END__[1] = { (func_ptr) 0 }; + +#define CTORS_SECTION_FUNCTION \ +void \ +ctors_section () \ +{ \ + if (in_section != in_ctors) \ + { \ + fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \ + in_section = in_ctors; \ + } \ +} + +#define DTORS_SECTION_FUNCTION \ +void \ +dtors_section () \ +{ \ + if (in_section != in_dtors) \ + { \ + fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \ + in_section = in_dtors; \ + } \ +} + +/* Support the ctors/dtors sections for g++. */ + +#define INT_ASM_OP ".word" + +#define INVOKE__main + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "crtbegin%O%s crt0%O%s" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtend%O%s" + +/* A C statement (sans semicolon) to output an element in the table of + global constructors. */ +#undef ASM_OUTPUT_CONSTRUCTOR +#define ASM_OUTPUT_CONSTRUCTOR(STREAM,NAME) \ +do { \ + ctors_section (); \ + fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} while (0) + +/* A C statement (sans semicolon) to output an element in the table of + global destructors. */ +#undef ASM_OUTPUT_DESTRUCTOR +#define ASM_OUTPUT_DESTRUCTOR(STREAM,NAME) \ +do { \ + dtors_section (); \ + fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} while (0) + +/* The ARM development system has atexit and doesn't have _exit, + so define this for now. */ +#define HAVE_ATEXIT + +/* The ARM development system defines __main. */ +#define NAME__MAIN "__gccmain" +#define SYMBOL__MAIN __gccmain + +#define MAKE_DECL_ONE_ONLY(DECL) (DECL_WEAK (DECL) = 1) +#define UNIQUE_SECTION_P(DECL) (DECL_ONE_ONLY (DECL)) +#define UNIQUE_SECTION(DECL,RELOC) \ +do { \ + int len; \ + char * name, * string, * prefix; \ + \ + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (DECL)); \ + \ + if (! DECL_ONE_ONLY (DECL)) \ + { \ + prefix = "."; \ + if (TREE_CODE (DECL) == FUNCTION_DECL) \ + prefix = ".text."; \ + else if (DECL_READONLY_SECTION (DECL, RELOC)) \ + prefix = ".rodata."; \ + else \ + prefix = ".data."; \ + } \ + else if (TREE_CODE (DECL) == FUNCTION_DECL) \ + prefix = ".gnu.linkonce.t."; \ + else if (DECL_READONLY_SECTION (DECL, RELOC)) \ + prefix = ".gnu.linkonce.r."; \ + else \ + prefix = ".gnu.linkonce.d."; \ + \ + len = strlen (name) + strlen (prefix); \ + string = alloca (len + 1); \ + sprintf (string, "%s%s", prefix, name); \ + \ + DECL_SECTION_NAME (DECL) = build_string (len, string); \ +} while (0) + +/* This is how we tell the assembler that a symbol is weak. */ +#ifndef ASM_WEAKEN_LABEL +#define ASM_WEAKEN_LABEL(FILE, NAME) \ + do \ + { \ + fputs ("\t.weak\t", FILE); \ + assemble_name (FILE, NAME); \ + fputc ('\n', FILE); \ + } \ + while (0) +#endif + +#ifndef TYPE_ASM_OP + +/* These macros generate the special .type and .size directives which + are used to set the corresponding fields of the linker symbol table + entries in an ELF object file under SVR4. These macros also output + the starting labels for the relevant functions/objects. */ +#define TYPE_ASM_OP ".type" +#define SIZE_ASM_OP ".size" + +/* The following macro defines the format used to output the second + operand of the .type assembler directive. Different svr4 assemblers + expect various different forms for this operand. The one given here + is just a default. You may need to override it in your machine- + specific tm.h file (depending upon the particulars of your assembler). */ +#define TYPE_OPERAND_FMT "%s" + +/* Write the extra assembler code needed to declare a function's result. + Most svr4 assemblers don't require any special declaration of the + result value, but there are exceptions. */ +#ifndef ASM_DECLARE_RESULT +#define ASM_DECLARE_RESULT(FILE, RESULT) +#endif + +/* Write the extra assembler code needed to declare a function properly. + Some svr4 assemblers need to also have something extra said about the + function's return value. We allow for that here. */ +#undef ASM_DECLARE_FUNCTION_NAME +#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ + do \ + { \ + fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \ + assemble_name (FILE, NAME); \ + putc (',', FILE); \ + fprintf (FILE, TYPE_OPERAND_FMT, "function"); \ + putc ('\n', FILE); \ + ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \ + if (! is_called_in_ARM_mode (decl)) \ + fprintf (FILE, "\t.thumb_func\n") ; \ + else \ + fprintf (FILE, "\t.code\t32\n") ; \ + ASM_OUTPUT_LABEL(FILE, NAME); \ + } \ + while (0) + +/* Write the extra assembler code needed to declare an object properly. */ +#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \ + do \ + { \ + fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \ + assemble_name (FILE, NAME); \ + putc (',', FILE); \ + fprintf (FILE, TYPE_OPERAND_FMT, "object"); \ + putc ('\n', FILE); \ + size_directive_output = 0; \ + if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \ + { \ + size_directive_output = 1; \ + fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ + assemble_name (FILE, NAME); \ + putc (',', FILE); \ + fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, \ + int_size_in_bytes (TREE_TYPE (DECL))); \ + fputc ('\n', FILE); \ + } \ + ASM_OUTPUT_LABEL(FILE, NAME); \ + } \ + while (0) + +/* Output the size directive for a decl in rest_of_decl_compilation + in the case where we did not do so before the initializer. + Once we find the error_mark_node, we know that the value of + size_directive_output was set + by ASM_DECLARE_OBJECT_NAME when it was run for the same decl. */ +#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \ + do \ + { \ + char * name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \ + if (!flag_inhibit_size_directive && DECL_SIZE (DECL) \ + && ! AT_END && TOP_LEVEL \ + && DECL_INITIAL (DECL) == error_mark_node \ + && !size_directive_output) \ + { \ + size_directive_output = 1; \ + fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ + assemble_name (FILE, name); \ + putc (',', FILE); \ + fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, \ + int_size_in_bytes (TREE_TYPE (DECL))); \ + fputc ('\n', FILE); \ + } \ + } \ + while (0) + +/* This is how to declare the size of a function. */ +#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \ + do \ + { \ + if (!flag_inhibit_size_directive) \ + { \ + char label[256]; \ + static int labelno; \ + labelno ++; \ + ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno); \ + ASM_OUTPUT_INTERNAL_LABEL (FILE, "Lfe", labelno); \ + fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ + assemble_name (FILE, (FNAME)); \ + fprintf (FILE, ","); \ + assemble_name (FILE, label); \ + fprintf (FILE, "-"); \ + assemble_name (FILE, (FNAME)); \ + putc ('\n', FILE); \ + } \ + } \ + while (0) + +#endif /* TYPE_ASM_OP */ diff --git a/gcc_arm/config/arm/telf_020422.h b/gcc_arm/config/arm/telf_020422.h new file mode 100755 index 0000000..6e59404 --- /dev/null +++ b/gcc_arm/config/arm/telf_020422.h @@ -0,0 +1,443 @@ +/* CYGNUS LOCAL (entire file) clm/arm-elf */ +/* Definitions of target machine for GNU compiler, + for Thumb with ELF obj format. + Copyright (C) 1995, 1996, 2001 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define OBJECT_FORMAT_ELF + +#define CPP_PREDEFINES "-Dthumb -Dthumbelf -D__thumb -Acpu(arm) -Amachine(arm)" + +#include "arm/thumb.h" + +/* Run-time Target Specification. */ +#undef TARGET_VERSION +#define TARGET_VERSION fputs (" (Thumb/elf)", stderr) + +#define MULTILIB_DEFAULTS { "mlittle-endian" } + +/* Setting this to 32 produces more efficient code, but the value set in previous + versions of this toolchain was 8, which produces more compact structures. The + command line option -mstructure_size_boundary= can be used to change this + value. */ +#undef STRUCTURE_SIZE_BOUNDARY +#define STRUCTURE_SIZE_BOUNDARY arm_structure_size_boundary + +extern int arm_structure_size_boundary; + +/* Debug */ +#define DWARF_DEBUGGING_INFO +#define DWARF2_DEBUGGING_INFO +#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG + + +/* Note - it is important that these definitions match those in semi.h for the ARM port. */ +#undef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "." + + +/* A C statement to output assembler commands which will identify the + object file as having been compiled with GNU CC (or another GNU + compiler). */ +#define ASM_IDENTIFY_GCC(STREAM) \ + fprintf (STREAM, "%sgcc2_compiled.:\n", LOCAL_LABEL_PREFIX ) + +#undef ASM_FILE_START +#define ASM_FILE_START(STREAM) \ +do { \ + extern char *version_string; \ + fprintf ((STREAM), "%s Generated by gcc %s for Thumb/elf\n", \ + ASM_COMMENT_START, version_string); \ + fprintf ((STREAM), ASM_APP_OFF); \ +} while (0) + +/* A C statement to output something to the assembler file to switch to section + NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or + NULL_TREE. Some target formats do not support arbitrary sections. Do not + define this macro in such cases. */ +#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ +do { \ + if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ + fprintf (STREAM, "\t.section %s,\"ax\",%%progbits\n", (NAME)); \ + else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ + fprintf (STREAM, "\t.section %s,\"a\"\n", (NAME)); \ + else if (0 == strncmp((NAME), ".bss", sizeof(".bss") - 1)) \ + fprintf (STREAM, "\t.section %s,\"aw\",%%nobits\n", (NAME)); \ + else \ + fprintf (STREAM, "\t.section %s,\"aw\"\n", (NAME)); \ +} while (0) + +/* Support the ctors/dtors and other sections. */ + +#undef INIT_SECTION_ASM_OP + +/* Define this macro if jump tables (for `tablejump' insns) should be + output in the text section, along with the assembler instructions. + Otherwise, the readonly data section is used. */ +#define JUMP_TABLES_IN_TEXT_SECTION 1 + +#undef READONLY_DATA_SECTION +#define READONLY_DATA_SECTION rdata_section +#undef RDATA_SECTION_ASM_OP +#define RDATA_SECTION_ASM_OP "\t.section .rodata" + +#undef CTORS_SECTION_ASM_OP +#define CTORS_SECTION_ASM_OP "\t.section .ctors,\"aw\"" +#undef DTORS_SECTION_ASM_OP +#define DTORS_SECTION_ASM_OP "\t.section .dtors,\"aw\"" + +#define USER_LABEL_PREFIX "" + +/* 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. */ +#ifndef BSS_SECTION_ASM_OP +#define BSS_SECTION_ASM_OP ".section\t.bss" +#endif + +/* 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. */ +#ifndef ASM_OUTPUT_ALIGNED_BSS +#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \ + asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN) +#endif + +/* Don't know how to order these. UNALIGNED_WORD_ASM_OP is in + dwarf2.out. */ +#define UNALIGNED_WORD_ASM_OP ".4byte" + +#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,RTX) \ +do { \ + fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \ + output_addr_const ((FILE), (RTX)); \ + fputc ('\n', (FILE)); \ +} while (0) + +/* This is how to equate one symbol to another symbol. The syntax used is + `SYM1=SYM2'. Note that this is different from the way equates are done + with most svr4 assemblers, where the syntax is `.set SYM1,SYM2'. */ + +#define ASM_OUTPUT_DEF(FILE,LABEL1,LABEL2) \ + do { fprintf ((FILE), "\t"); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, " = "); \ + assemble_name (FILE, LABEL2); \ + fprintf (FILE, "\n"); \ + } while (0) + +/* For aliases of functions we use .thumb_set instead. */ +#define ASM_OUTPUT_DEF_FROM_DECLS(FILE,DECL1,DECL2) \ + do \ + { \ + char * LABEL1 = XSTR (XEXP (DECL_RTL (decl), 0), 0); \ + char * LABEL2 = IDENTIFIER_POINTER (DECL2); \ + \ + if (TREE_CODE (DECL1) == FUNCTION_DECL) \ + { \ + fprintf (FILE, "\t.thumb_set "); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, ","); \ + assemble_name (FILE, LABEL2); \ + fprintf (FILE, "\n"); \ + } \ + else \ + ASM_OUTPUT_DEF (FILE, LABEL1, LABEL2); \ + } \ + while (0) + +/* A list of other sections which the compiler might be "in" at any + given time. */ +#undef EXTRA_SECTIONS +#define EXTRA_SECTIONS SUBTARGET_EXTRA_SECTIONS in_rdata, in_ctors, in_dtors + +#define SUBTARGET_EXTRA_SECTIONS + +/* A list of extra section function definitions. */ + +#undef EXTRA_SECTION_FUNCTIONS +#define EXTRA_SECTION_FUNCTIONS \ + RDATA_SECTION_FUNCTION \ + CTORS_SECTION_FUNCTION \ + DTORS_SECTION_FUNCTION \ + SUBTARGET_EXTRA_SECTION_FUNCTIONS + +#define SUBTARGET_EXTRA_SECTION_FUNCTIONS + +#define RDATA_SECTION_FUNCTION \ +void \ +rdata_section () \ +{ \ + if (in_section != in_rdata) \ + { \ + fprintf (asm_out_file, "%s\n", RDATA_SECTION_ASM_OP); \ + in_section = in_rdata; \ + } \ +} + +#define CTOR_LIST_BEGIN \ +asm (CTORS_SECTION_ASM_OP); \ +func_ptr __CTOR_LIST__[1] = { (func_ptr) (-1) } + +#define CTOR_LIST_END \ +asm (CTORS_SECTION_ASM_OP); \ +func_ptr __CTOR_END__[1] = { (func_ptr) 0 }; + +#define DTOR_LIST_BEGIN \ +asm (DTORS_SECTION_ASM_OP); \ +func_ptr __DTOR_LIST__[1] = { (func_ptr) (-1) } + +#define DTOR_LIST_END \ +asm (DTORS_SECTION_ASM_OP); \ +func_ptr __DTOR_END__[1] = { (func_ptr) 0 }; + +#define CTORS_SECTION_FUNCTION \ +void \ +ctors_section () \ +{ \ + if (in_section != in_ctors) \ + { \ + fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \ + in_section = in_ctors; \ + } \ +} + +#define DTORS_SECTION_FUNCTION \ +void \ +dtors_section () \ +{ \ + if (in_section != in_dtors) \ + { \ + fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \ + in_section = in_dtors; \ + } \ +} + +/* Support the ctors/dtors sections for g++. */ + +#define INT_ASM_OP ".word" + +#define INVOKE__main + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "crtbegin%O%s crt0%O%s" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtend%O%s" + +/* A C statement (sans semicolon) to output an element in the table of + global constructors. */ +#undef ASM_OUTPUT_CONSTRUCTOR +#define ASM_OUTPUT_CONSTRUCTOR(STREAM,NAME) \ +do { \ + ctors_section (); \ + fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} while (0) + +/* A C statement (sans semicolon) to output an element in the table of + global destructors. */ +#undef ASM_OUTPUT_DESTRUCTOR +#define ASM_OUTPUT_DESTRUCTOR(STREAM,NAME) \ +do { \ + dtors_section (); \ + fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} while (0) + +/* The ARM development system has atexit and doesn't have _exit, + so define this for now. */ +#define HAVE_ATEXIT + +/* The ARM development system defines __main. */ +#define NAME__MAIN "__gccmain" +#define SYMBOL__MAIN __gccmain + +#define MAKE_DECL_ONE_ONLY(DECL) (DECL_WEAK (DECL) = 1) +#define UNIQUE_SECTION_P(DECL) (DECL_ONE_ONLY (DECL)) +#define UNIQUE_SECTION(DECL,RELOC) \ +do { \ + int len; \ + char * name, * string, * prefix; \ + \ + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (DECL)); \ + \ + if (! DECL_ONE_ONLY (DECL)) \ + { \ + prefix = "."; \ + if (TREE_CODE (DECL) == FUNCTION_DECL) \ + prefix = ".text."; \ + else if (DECL_READONLY_SECTION (DECL, RELOC)) \ + prefix = ".rodata."; \ + else \ + prefix = ".data."; \ + } \ + else if (TREE_CODE (DECL) == FUNCTION_DECL) \ + prefix = ".gnu.linkonce.t."; \ + else if (DECL_READONLY_SECTION (DECL, RELOC)) \ + prefix = ".gnu.linkonce.r."; \ + else \ + prefix = ".gnu.linkonce.d."; \ + \ + len = strlen (name) + strlen (prefix); \ + string = alloca (len + 1); \ + sprintf (string, "%s%s", prefix, name); \ + \ + DECL_SECTION_NAME (DECL) = build_string (len, string); \ +} while (0) + +/* This is how we tell the assembler that a symbol is weak. */ +#ifndef ASM_WEAKEN_LABEL +#define ASM_WEAKEN_LABEL(FILE, NAME) \ + do \ + { \ + fputs ("\t.weak\t", FILE); \ + assemble_name (FILE, NAME); \ + fputc ('\n', FILE); \ + } \ + while (0) +#endif + +#ifndef TYPE_ASM_OP + +/* These macros generate the special .type and .size directives which + are used to set the corresponding fields of the linker symbol table + entries in an ELF object file under SVR4. These macros also output + the starting labels for the relevant functions/objects. */ +#define TYPE_ASM_OP ".type" +#define SIZE_ASM_OP ".size" + +/* The following macro defines the format used to output the second + operand of the .type assembler directive. Different svr4 assemblers + expect various different forms for this operand. The one given here + is just a default. You may need to override it in your machine- + specific tm.h file (depending upon the particulars of your assembler). */ +#define TYPE_OPERAND_FMT "%s" + +/* Write the extra assembler code needed to declare a function's result. + Most svr4 assemblers don't require any special declaration of the + result value, but there are exceptions. */ +#ifndef ASM_DECLARE_RESULT +#define ASM_DECLARE_RESULT(FILE, RESULT) +#endif + +/* Write the extra assembler code needed to declare a function properly. + Some svr4 assemblers need to also have something extra said about the + function's return value. We allow for that here. */ +#undef ASM_DECLARE_FUNCTION_NAME +#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ + do \ + { \ + fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \ + assemble_name (FILE, NAME); \ + putc (',', FILE); \ + fprintf (FILE, TYPE_OPERAND_FMT, "function"); \ + putc ('\n', FILE); \ + ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \ + if (! is_called_in_ARM_mode (decl)) \ + fprintf (FILE, "\t.thumb_func\n") ; \ + else \ + fprintf (FILE, "\t.code\t32\n") ; \ + ASM_OUTPUT_LABEL(FILE, NAME); \ + } \ + while (0) + +/* Write the extra assembler code needed to declare an object properly. */ +#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \ + do \ + { \ + fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \ + assemble_name (FILE, NAME); \ + putc (',', FILE); \ + fprintf (FILE, TYPE_OPERAND_FMT, "object"); \ + putc ('\n', FILE); \ + size_directive_output = 0; \ + if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \ + { \ + size_directive_output = 1; \ + fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ + assemble_name (FILE, NAME); \ + putc (',', FILE); \ + fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, \ + int_size_in_bytes (TREE_TYPE (DECL))); \ + fputc ('\n', FILE); \ + } \ + ASM_OUTPUT_LABEL(FILE, NAME); \ + } \ + while (0) + +/* Output the size directive for a decl in rest_of_decl_compilation + in the case where we did not do so before the initializer. + Once we find the error_mark_node, we know that the value of + size_directive_output was set + by ASM_DECLARE_OBJECT_NAME when it was run for the same decl. */ +#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \ + do \ + { \ + char * name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \ + if (!flag_inhibit_size_directive && DECL_SIZE (DECL) \ + && ! AT_END && TOP_LEVEL \ + && DECL_INITIAL (DECL) == error_mark_node \ + && !size_directive_output) \ + { \ + size_directive_output = 1; \ + fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ + assemble_name (FILE, name); \ + putc (',', FILE); \ + fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, \ + int_size_in_bytes (TREE_TYPE (DECL))); \ + fputc ('\n', FILE); \ + } \ + } \ + while (0) + +/* This is how to declare the size of a function. */ +#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \ + do \ + { \ + if (!flag_inhibit_size_directive) \ + { \ + char label[256]; \ + static int labelno; \ + labelno ++; \ + ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno); \ + ASM_OUTPUT_INTERNAL_LABEL (FILE, "Lfe", labelno); \ + fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ + assemble_name (FILE, (FNAME)); \ + fprintf (FILE, ","); \ + assemble_name (FILE, label); \ + fprintf (FILE, "-"); \ + assemble_name (FILE, (FNAME)); \ + putc ('\n', FILE); \ + } \ + } \ + while (0) + +#endif /* TYPE_ASM_OP */ diff --git a/gcc_arm/config/arm/thumb.c b/gcc_arm/config/arm/thumb.c new file mode 100755 index 0000000..778cda9 --- /dev/null +++ b/gcc_arm/config/arm/thumb.c @@ -0,0 +1,2132 @@ +/* Output routines for GCC for ARM/Thumb + Copyright (C) 1996 Cygnus Software Technologies Ltd + The basis of this contribution was generated by + Richard Earnshaw, Advanced RISC Machines Ltd + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include +#include +#include "config.h" +#include "rtl.h" +#include "hard-reg-set.h" +#include "regs.h" +#include "output.h" +#include "insn-flags.h" +#include "insn-attr.h" +#include "flags.h" +#include "tree.h" +#include "expr.h" + + +int current_function_anonymous_args = 0; +static int current_function_has_far_jump = 0; + +/* Used to parse -mstructure_size_boundary command line option. */ +char * structure_size_string = NULL; +int arm_structure_size_boundary = 32; /* Used to be 8 */ + + +/* Predicates */ +int +reload_memory_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + int regno = true_regnum (op); + + return (! CONSTANT_P (op) + && (regno == -1 + || (GET_CODE (op) == REG + && REGNO (op) >= FIRST_PSEUDO_REGISTER))); +} + +/* Return nonzero if op is suitable for the RHS of a cmp instruction. */ +int +thumb_cmp_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return ((GET_CODE (op) == CONST_INT + && (unsigned HOST_WIDE_INT) (INTVAL (op)) < 256) + || register_operand (op, mode)); +} + +int +thumb_shiftable_const (val) + HOST_WIDE_INT val; +{ + unsigned HOST_WIDE_INT x = val; + unsigned HOST_WIDE_INT mask = 0xff; + int i; + + for (i = 0; i < 25; i++) + if ((val & (mask << i)) == val) + return 1; + + return 0; +} + +int +thumb_trivial_epilogue () +{ + int regno; + + /* ??? If this function ever returns 1, we get a function without any + epilogue at all. It appears that the intent was to cause a "return" + insn to be emitted, but that does not happen. */ + return 0; + +#if 0 + if (get_frame_size () + || current_function_outgoing_args_size + || current_function_pretend_args_size) + return 0; + + for (regno = 8; regno < 13; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + return 0; + + return 1; +#endif +} + + +/* Routines for handling the constant pool */ +/* This is unashamedly hacked from the version in sh.c, since the problem is + extremely similar. */ + +/* Thumb instructions cannot load a large constant into a register, + constants have to come from a pc relative load. The reference of a pc + relative load instruction must be less than 1k infront of the instruction. + This means that we often have to dump a constant inside a function, and + generate code to branch around it. + + It is important to minimize this, since the branches will slow things + down and make things bigger. + + Worst case code looks like: + + ldr rn, L1 + b L2 + align + L1: .long value + L2: + .. + + ldr rn, L3 + b L4 + align + L3: .long value + L4: + .. + + We fix this by performing a scan before scheduling, which notices which + instructions need to have their operands fetched from the constant table + and builds the table. + + + The algorithm is: + + scan, find an instruction which needs a pcrel move. Look forward, find the + last barrier which is within MAX_COUNT bytes of the requirement. + If there isn't one, make one. Process all the instructions between + the find and the barrier. + + In the above example, we can tell that L3 is within 1k of L1, so + the first move can be shrunk from the 2 insn+constant sequence into + just 1 insn, and the constant moved to L3 to make: + + ldr rn, L1 + .. + ldr rn, L3 + b L4 + align + L1: .long value + L3: .long value + L4: + + Then the second move becomes the target for the shortening process. + + */ + +typedef struct +{ + rtx value; /* Value in table */ + HOST_WIDE_INT next_offset; + enum machine_mode mode; /* Mode of value */ +} pool_node; + +/* The maximum number of constants that can fit into one pool, since + the pc relative range is 0...1020 bytes and constants are at least 4 + bytes long */ + +#define MAX_POOL_SIZE (1020/4) +static pool_node pool_vector[MAX_POOL_SIZE]; +static int pool_size; +static rtx pool_vector_label; + +/* Add a constant to the pool and return its label. */ + +static HOST_WIDE_INT +add_constant (x, mode) + rtx x; + enum machine_mode mode; +{ + int i; + rtx lab; + HOST_WIDE_INT offset; + + if (mode == SImode && GET_CODE (x) == MEM && CONSTANT_P (XEXP (x, 0)) + && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0))) + x = get_pool_constant (XEXP (x, 0)); + + /* First see if we've already got it */ + + for (i = 0; i < pool_size; i++) + { + if (x->code == pool_vector[i].value->code + && mode == pool_vector[i].mode) + { + if (x->code == CODE_LABEL) + { + if (XINT (x, 3) != XINT (pool_vector[i].value, 3)) + continue; + } + if (rtx_equal_p (x, pool_vector[i].value)) + return pool_vector[i].next_offset - GET_MODE_SIZE (mode); + } + } + + /* Need a new one */ + + pool_vector[pool_size].next_offset = GET_MODE_SIZE (mode); + offset = 0; + if (pool_size == 0) + pool_vector_label = gen_label_rtx (); + else + pool_vector[pool_size].next_offset + += (offset = pool_vector[pool_size - 1].next_offset); + + pool_vector[pool_size].value = x; + pool_vector[pool_size].mode = mode; + pool_size++; + return offset; +} + +/* Output the literal table */ + +static void +dump_table (scan) + rtx scan; +{ + int i; + + scan = emit_label_after (gen_label_rtx (), scan); + scan = emit_insn_after (gen_align_4 (), scan); + scan = emit_label_after (pool_vector_label, scan); + + for (i = 0; i < pool_size; i++) + { + pool_node *p = pool_vector + i; + + switch (GET_MODE_SIZE (p->mode)) + { + case 4: + scan = emit_insn_after (gen_consttable_4 (p->value), scan); + break; + + case 8: + scan = emit_insn_after (gen_consttable_8 (p->value), scan); + break; + + default: + abort (); + break; + } + } + + scan = emit_insn_after (gen_consttable_end (), scan); + scan = emit_barrier_after (scan); + pool_size = 0; +} + +/* Non zero if the src operand needs to be fixed up */ +static +int +fixit (src, mode) + rtx src; + enum machine_mode mode; +{ + return ((CONSTANT_P (src) + && (GET_CODE (src) != CONST_INT + || ! (CONST_OK_FOR_LETTER_P (INTVAL (src), 'I') + || CONST_OK_FOR_LETTER_P (INTVAL (src), 'J') + || (mode != DImode + && CONST_OK_FOR_LETTER_P (INTVAL (src), 'K'))))) + || (mode == SImode && GET_CODE (src) == MEM + && GET_CODE (XEXP (src, 0)) == SYMBOL_REF + && CONSTANT_POOL_ADDRESS_P (XEXP (src, 0)))); +} + +/* Find the last barrier less than MAX_COUNT bytes from FROM, or create one. */ + +#define MAX_COUNT_SI 1000 + +static rtx +find_barrier (from) + rtx from; +{ + int count = 0; + rtx found_barrier = 0; + rtx label; + + while (from && count < MAX_COUNT_SI) + { + if (GET_CODE (from) == BARRIER) + return from; + + /* Count the length of this insn */ + if (GET_CODE (from) == INSN + && GET_CODE (PATTERN (from)) == SET + && CONSTANT_P (SET_SRC (PATTERN (from))) + && CONSTANT_POOL_ADDRESS_P (SET_SRC (PATTERN (from)))) + { + rtx src = SET_SRC (PATTERN (from)); + count += 2; + } + else + count += get_attr_length (from); + + from = NEXT_INSN (from); + } + + /* We didn't find a barrier in time to + dump our stuff, so we'll make one */ + label = gen_label_rtx (); + + if (from) + from = PREV_INSN (from); + else + from = get_last_insn (); + + /* Walk back to be just before any jump */ + while (GET_CODE (from) == JUMP_INSN + || GET_CODE (from) == NOTE + || GET_CODE (from) == CODE_LABEL) + from = PREV_INSN (from); + + from = emit_jump_insn_after (gen_jump (label), from); + JUMP_LABEL (from) = label; + found_barrier = emit_barrier_after (from); + emit_label_after (label, found_barrier); + return found_barrier; +} + +/* Non zero if the insn is a move instruction which needs to be fixed. */ + +static int +broken_move (insn) + rtx insn; +{ + if (!INSN_DELETED_P (insn) + && GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == SET) + { + rtx pat = PATTERN (insn); + rtx src = SET_SRC (pat); + rtx dst = SET_DEST (pat); + enum machine_mode mode = GET_MODE (dst); + if (dst == pc_rtx) + return 0; + return fixit (src, mode); + } + return 0; +} + +/* Recursively search through all of the blocks in a function + checking to see if any of the variables created in that + function match the RTX called 'orig'. If they do then + replace them with the RTX called 'new'. */ + +static void +replace_symbols_in_block (tree block, rtx orig, rtx new) +{ + for (; block; block = BLOCK_CHAIN (block)) + { + tree sym; + + if (! TREE_USED (block)) + continue; + + for (sym = BLOCK_VARS (block); sym; sym = TREE_CHAIN (sym)) + { + if ( (DECL_NAME (sym) == 0 && TREE_CODE (sym) != TYPE_DECL) + || DECL_IGNORED_P (sym) + || TREE_CODE (sym) != VAR_DECL + || DECL_EXTERNAL (sym) + || ! rtx_equal_p (DECL_RTL (sym), orig) + ) + continue; + + DECL_RTL (sym) = new; + } + + replace_symbols_in_block (BLOCK_SUBBLOCKS (block), orig, new); + } +} + +void +thumb_reorg (first) + rtx first; +{ + rtx insn; + for (insn = first; insn; insn = NEXT_INSN (insn)) + { + if (broken_move (insn)) + { + /* This is a broken move instruction, scan ahead looking for + a barrier to stick the constant table behind */ + rtx scan; + rtx barrier = find_barrier (insn); + + /* Now find all the moves between the points and modify them */ + for (scan = insn; scan != barrier; scan = NEXT_INSN (scan)) + { + if (broken_move (scan)) + { + /* This is a broken move instruction, add it to the pool */ + rtx pat = PATTERN (scan); + rtx src = SET_SRC (pat); + rtx dst = SET_DEST (pat); + enum machine_mode mode = GET_MODE (dst); + HOST_WIDE_INT offset; + rtx newinsn; + rtx newsrc; + + /* If this is an HImode constant load, convert it into + an SImode constant load. Since the register is always + 32 bits this is safe. We have to do this, since the + load pc-relative instruction only does a 32-bit load. */ + if (mode == HImode) + { + mode = SImode; + if (GET_CODE (dst) != REG) + abort (); + PUT_MODE (dst, SImode); + } + + offset = add_constant (src, mode); + newsrc = gen_rtx (MEM, mode, + plus_constant (gen_rtx (LABEL_REF, + VOIDmode, + pool_vector_label), + offset)); + + /* Build a jump insn wrapper around the move instead + of an ordinary insn, because we want to have room for + the target label rtx in fld[7], which an ordinary + insn doesn't have. */ + newinsn = emit_jump_insn_after (gen_rtx (SET, VOIDmode, + dst, newsrc), scan); + JUMP_LABEL (newinsn) = pool_vector_label; + + /* But it's still an ordinary insn */ + PUT_CODE (newinsn, INSN); + + /* If debugging information is going to be emitted + then we must make sure that any refences to + symbols which are removed by the above code are + also removed in the descriptions of the + function's variables. Failure to do this means + that the debugging information emitted could + refer to symbols which are not emited by + output_constant_pool() because + mark_constant_pool() never sees them as being + used. */ + + + /* These are the tests used in + output_constant_pool() to decide if the constant + pool will be marked. Only necessary if debugging + info is being emitted. Only necessary for + references to memory whose address is given by a + symbol. */ + + if (optimize > 0 + && flag_expensive_optimizations + && write_symbols != NO_DEBUG + && GET_CODE (src) == MEM + && GET_CODE (XEXP (src, 0)) == SYMBOL_REF) + replace_symbols_in_block + (DECL_INITIAL (current_function_decl), src, newsrc); + + /* Kill old insn */ + delete_insn (scan); + scan = newinsn; + } + } + dump_table (barrier); + } + } +} + + +/* Routines for generating rtl */ + +void +thumb_expand_movstrqi (operands) + rtx *operands; +{ + rtx out = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); + rtx in = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); + HOST_WIDE_INT len = INTVAL (operands[2]); + HOST_WIDE_INT offset = 0; + + while (len >= 12) + { + emit_insn (gen_movmem12b (out, in)); + len -= 12; + } + if (len >= 8) + { + emit_insn (gen_movmem8b (out, in)); + len -= 8; + } + if (len >= 4) + { + rtx reg = gen_reg_rtx (SImode); + emit_insn (gen_movsi (reg, gen_rtx (MEM, SImode, in))); + emit_insn (gen_movsi (gen_rtx (MEM, SImode, out), reg)); + len -= 4; + offset += 4; + } + if (len >= 2) + { + rtx reg = gen_reg_rtx (HImode); + emit_insn (gen_movhi (reg, gen_rtx (MEM, HImode, + plus_constant (in, offset)))); + emit_insn (gen_movhi (gen_rtx (MEM, HImode, plus_constant (out, offset)), + reg)); + len -= 2; + offset += 2; + } + if (len) + { + rtx reg = gen_reg_rtx (QImode); + emit_insn (gen_movqi (reg, gen_rtx (MEM, QImode, + plus_constant (in, offset)))); + emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (out, offset)), + reg)); + } +} + + +/* Routines for reloading */ + +void +thumb_reload_out_si (operands) + rtx operands; +{ + abort (); +} + +/* CYGNUS LOCAL nickc/thumb-pe */ + +#ifdef THUMB_PE +/* Return non-zero if FUNC is a naked function. */ + +static int +arm_naked_function_p (func) + tree func; +{ + tree a; + + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + + a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func)); + return a != NULL_TREE; +} +#endif +/* END CYGNUS LOCAL nickc/thumb-pe */ + +/* Return non-zero if FUNC must be entered in ARM mode. */ +int +is_called_in_ARM_mode (func) + tree func; +{ + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + + /* Ignore the problem about functions whoes address is taken. */ + if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func)) + return TRUE; + +/* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + return lookup_attribute ("interfacearm", DECL_MACHINE_ATTRIBUTES (func)) != NULL_TREE; +#else + return FALSE; +#endif +/* END CYGNUS LOCAL */ +} + + +/* Routines for emitting code */ + +void +final_prescan_insn(insn) + rtx insn; +{ + extern int *insn_addresses; + + if (flag_print_asm_name) + fprintf (asm_out_file, "%s 0x%04x\n", ASM_COMMENT_START, + insn_addresses[INSN_UID (insn)]); +} + + +static void thumb_pushpop ( FILE *, int, int ); /* Forward declaration. */ + +#ifdef __GNUC__ +inline +#endif +static int +number_of_first_bit_set (mask) + int mask; +{ + int bit; + + for (bit = 0; + (mask & (1 << bit)) == 0; + ++ bit) + continue; + + return bit; +} + +#define ARG_1_REGISTER 0 +#define ARG_2_REGISTER 1 +#define ARG_3_REGISTER 2 +#define ARG_4_REGISTER 3 +#define WORK_REGISTER 7 +#define FRAME_POINTER 11 +#define IP_REGISTER 12 +#define STACK_POINTER STACK_POINTER_REGNUM +#define LINK_REGISTER 14 +#define PROGRAM_COUNTER 15 + +/* Generate code to return from a thumb function. If + 'reg_containing_return_addr' is -1, then the return address is + actually on the stack, at the stack pointer. */ +static void +thumb_exit (f, reg_containing_return_addr) + FILE * f; + int reg_containing_return_addr; +{ + int regs_available_for_popping; + int regs_to_pop; + int pops_needed; + int reg; + int available; + int required; + int mode; + int size; + int restore_a4 = FALSE; + + /* Compute the registers we need to pop. */ + regs_to_pop = 0; + pops_needed = 0; + + if (reg_containing_return_addr == -1) + { + regs_to_pop |= 1 << LINK_REGISTER; + ++ pops_needed; + } + + if (TARGET_BACKTRACE) + { + /* Restore frame pointer and stack pointer. */ + regs_to_pop |= (1 << FRAME_POINTER) | (1 << STACK_POINTER); + pops_needed += 2; + } + + /* If there is nothing to pop then just emit the BX instruction and return.*/ + if (pops_needed == 0) + { + asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]); + + return; + } + + /* Otherwise if we are not supporting interworking and we have not created + a backtrace structure and the function was not entered in ARM mode then + just pop the return address straight into the PC. */ + else if ( ! TARGET_THUMB_INTERWORK + && ! TARGET_BACKTRACE + && ! is_called_in_ARM_mode (current_function_decl)) + { + asm_fprintf (f, "\tpop\t{pc}\n" ); + + return; + } + + /* Find out how many of the (return) argument registers we can corrupt. */ + regs_available_for_popping = 0; + +#ifdef RTX_CODE + /* If we can deduce the registers used from the function's return value. + This is more reliable that examining regs_ever_live[] because that + will be set if the register is ever used in the function, not just if + the register is used to hold a return value. */ + + if (current_function_return_rtx != 0) + mode = GET_MODE (current_function_return_rtx); + else +#endif + mode = DECL_MODE (DECL_RESULT (current_function_decl)); + + size = GET_MODE_SIZE (mode); + + if (size == 0) + { + /* In a void function we can use any argument register. + In a function that returns a structure on the stack + we can use the second and third argument registers. */ + if (mode == VOIDmode) + regs_available_for_popping = + (1 << ARG_1_REGISTER) + | (1 << ARG_2_REGISTER) + | (1 << ARG_3_REGISTER); + else + regs_available_for_popping = + (1 << ARG_2_REGISTER) + | (1 << ARG_3_REGISTER); + } + else if (size <= 4) regs_available_for_popping = + (1 << ARG_2_REGISTER) + | (1 << ARG_3_REGISTER); + else if (size <= 8) regs_available_for_popping = + (1 << ARG_3_REGISTER); + + /* Match registers to be popped with registers into which we pop them. */ + for (available = regs_available_for_popping, + required = regs_to_pop; + required != 0 && available != 0; + available &= ~(available & - available), + required &= ~(required & - required)) + -- pops_needed; + + /* If we have any popping registers left over, remove them. */ + if (available > 0) + regs_available_for_popping &= ~ available; + + /* Otherwise if we need another popping register we can use + the fourth argument register. */ + else if (pops_needed) + { + /* If we have not found any free argument registers and + reg a4 contains the return address, we must move it. */ + if (regs_available_for_popping == 0 + && reg_containing_return_addr == ARG_4_REGISTER) + { + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]); + reg_containing_return_addr = LINK_REGISTER; + } + else if (size > 12) + { + /* Register a4 is being used to hold part of the return value, + but we have dire need of a free, low register. */ + restore_a4 = TRUE; + + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [IP_REGISTER], reg_names [ARG_4_REGISTER]); + } + + if (reg_containing_return_addr != ARG_4_REGISTER) + { + /* The fourth argument register is available. */ + regs_available_for_popping |= 1 << ARG_4_REGISTER; + + -- pops_needed; + } + } + + /* Pop as many registers as we can. */ + thumb_pushpop (f, regs_available_for_popping, FALSE); + + /* Process the registers we popped. */ + if (reg_containing_return_addr == -1) + { + /* The return address was popped into the lowest numbered register. */ + regs_to_pop &= ~ (1 << LINK_REGISTER); + + reg_containing_return_addr = + number_of_first_bit_set (regs_available_for_popping); + + /* Remove this register for the mask of available registers, so that + the return address will not be corrupted by futher pops. */ + regs_available_for_popping &= ~ (1 << reg_containing_return_addr); + } + + /* If we popped other registers then handle them here. */ + if (regs_available_for_popping) + { + int frame_pointer; + + /* Work out which register currently contains the frame pointer. */ + frame_pointer = number_of_first_bit_set (regs_available_for_popping); + + /* Move it into the correct place. */ + asm_fprintf (f, "\tmov\tfp, %s\n", reg_names [frame_pointer]); + + /* (Temporarily) remove it from the mask of popped registers. */ + regs_available_for_popping &= ~ (1 << frame_pointer); + regs_to_pop &= ~ (1 << FRAME_POINTER); + + if (regs_available_for_popping) + { + int stack_pointer; + + /* We popped the stack pointer as well, find the register that + contains it.*/ + stack_pointer = number_of_first_bit_set (regs_available_for_popping); + + /* Move it into the stack register. */ + asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [stack_pointer]); + + /* At this point we have popped all necessary registers, so + do not worry about restoring regs_available_for_popping + to its correct value: + + assert (pops_needed == 0) + assert (regs_available_for_popping == (1 << frame_pointer)) + assert (regs_to_pop == (1 << STACK_POINTER)) */ + } + else + { + /* Since we have just move the popped value into the frame + pointer, the popping register is available for reuse, and + we know that we still have the stack pointer left to pop. */ + regs_available_for_popping |= (1 << frame_pointer); + } + } + + /* If we still have registers left on the stack, but we no longer have + any registers into which we can pop them, then we must move the return + address into the link register and make available the register that + contained it. */ + if (regs_available_for_popping == 0 && pops_needed > 0) + { + regs_available_for_popping |= 1 << reg_containing_return_addr; + + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [LINK_REGISTER], + reg_names [reg_containing_return_addr]); + + reg_containing_return_addr = LINK_REGISTER; + } + + /* If we have registers left on the stack then pop some more. + We know that at most we will want to pop FP and SP. */ + if (pops_needed > 0) + { + int popped_into; + int move_to; + + thumb_pushpop (f, regs_available_for_popping, FALSE); + + /* We have popped either FP or SP. + Move whichever one it is into the correct register. */ + popped_into = number_of_first_bit_set (regs_available_for_popping); + move_to = number_of_first_bit_set (regs_to_pop); + + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [move_to], reg_names [popped_into]); + + regs_to_pop &= ~ (1 << move_to); + + -- pops_needed; + } + + /* If we still have not popped everything then we must have only + had one register available to us and we are now popping the SP. */ + if (pops_needed > 0) + { + int popped_into; + + thumb_pushpop (f, regs_available_for_popping, FALSE); + + popped_into = number_of_first_bit_set (regs_available_for_popping); + + asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [popped_into]); + + /* + assert (regs_to_pop == (1 << STACK_POINTER)) + assert (pops_needed == 1) + */ + } + + /* If necessary restore the a4 register. */ + if (restore_a4) + { + if (reg_containing_return_addr != LINK_REGISTER) + { + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]); + reg_containing_return_addr = LINK_REGISTER; + } + + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [ARG_4_REGISTER], reg_names [IP_REGISTER]); + } + + /* Return to caller. */ + asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]); +} + +/* Emit code to push or pop registers to or from the stack. */ +static void +thumb_pushpop (f, mask, push) + FILE * f; + int mask; + int push; +{ + int regno; + int lo_mask = mask & 0xFF; + + if (lo_mask == 0 && ! push && (mask & (1 << 15))) + { + /* Special case. Do not generate a POP PC statement here, do it in + thumb_exit() */ + + thumb_exit (f, -1); + return; + } + + asm_fprintf (f, "\t%s\t{", push ? "push" : "pop"); + + /* Look at the low registers first. */ + + for (regno = 0; regno < 8; regno ++, lo_mask >>= 1) + { + if (lo_mask & 1) + { + asm_fprintf (f, reg_names[regno]); + + if ((lo_mask & ~1) != 0) + asm_fprintf (f, ", "); + } + } + + if (push && (mask & (1 << 14))) + { + /* Catch pushing the LR. */ + + if (mask & 0xFF) + asm_fprintf (f, ", "); + + asm_fprintf (f, reg_names[14]); + } + else if (!push && (mask & (1 << 15))) + { + /* Catch popping the PC. */ + + if (TARGET_THUMB_INTERWORK || TARGET_BACKTRACE) + { + /* The PC is never poped directly, instead + it is popped into r3 and then BX is used. */ + + asm_fprintf (f, "}\n"); + + thumb_exit (f, -1); + + return; + } + else + { + if (mask & 0xFF) + asm_fprintf (f, ", "); + + asm_fprintf (f, reg_names[15]); + } + } + + asm_fprintf (f, "}\n"); +} + +/* Returns non-zero if the current function contains a far jump */ + +int +far_jump_used_p (void) +{ + rtx insn; + + if (current_function_has_far_jump) + return 1; + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + if (GET_CODE (insn) == JUMP_INSN + /* Ignore tablejump patterns. */ + && GET_CODE (PATTERN (insn)) != ADDR_VEC + && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC + && get_attr_far_jump (insn) == FAR_JUMP_YES) + { + current_function_has_far_jump = 1; + return 1; + } + } + + return 0; +} + +static int return_used_this_function = 0; + +char * +output_return () +{ + int regno; + int live_regs_mask = 0; + + /* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + /* If a function is naked, don't use the "return" insn. */ + if (arm_naked_function_p (current_function_decl)) + return ""; +#endif + /* END CYGNUS LOCAL nickc/thumb-pe */ + + return_used_this_function = 1; + + for (regno = 0; regno < 8; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + live_regs_mask |= 1 << regno; + + if (live_regs_mask == 0) + { + if (leaf_function_p () && ! far_jump_used_p()) + { + thumb_exit (asm_out_file, 14); + } + else if ( TARGET_THUMB_INTERWORK + || TARGET_BACKTRACE + || is_called_in_ARM_mode (current_function_decl)) + { + thumb_exit (asm_out_file, -1); + } + else + asm_fprintf (asm_out_file, "\tpop\t{pc}\n"); + } + else + { + asm_fprintf (asm_out_file, "\tpop\t{"); + + for (regno = 0; live_regs_mask; regno ++, live_regs_mask >>= 1) + if (live_regs_mask & 1) + { + asm_fprintf (asm_out_file, reg_names[regno]); + if (live_regs_mask & ~1) + asm_fprintf (asm_out_file, ", "); + } + + if ( TARGET_THUMB_INTERWORK + || TARGET_BACKTRACE + || is_called_in_ARM_mode (current_function_decl)) + { + asm_fprintf (asm_out_file, "}\n"); + thumb_exit (asm_out_file, -1); + } + else + asm_fprintf (asm_out_file, ", pc}\n"); + } + + return ""; +} + +void +thumb_function_prologue (f, frame_size) + FILE *f; + int frame_size; +{ + int amount = frame_size + current_function_outgoing_args_size; + int live_regs_mask = 0; + int high_regs_pushed = 0; + int store_arg_regs = 0; + int regno; + +/* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + if (arm_naked_function_p (current_function_decl)) + return; +#endif +/* CYGNUS LOCAL nickc/thumb-pe */ + + if (is_called_in_ARM_mode (current_function_decl)) + { + char * name; + if (GET_CODE (DECL_RTL (current_function_decl)) != MEM) + abort(); + if (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0)) != SYMBOL_REF) + abort(); + name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); + + /* Generate code sequence to switch us into Thumb mode. */ + /* The .code 32 directive has already been emitted by + ASM_DECLARE_FUNCITON_NAME */ + asm_fprintf (f, "\torr\tr12, pc, #1\n"); + asm_fprintf (f, "\tbx\tr12\n"); + + /* Generate a label, so that the debugger will notice the + change in instruction sets. This label is also used by + the assembler to bypass the ARM code when this function + is called from a Thumb encoded function elsewhere in the + same file. Hence the definition of STUB_NAME here must + agree with the definition in gas/config/tc-arm.c */ + +#define STUB_NAME ".real_start_of" + + asm_fprintf (f, "\t.code\t16\n"); + asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name); + asm_fprintf (f, "\t.thumb_func\n"); + asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name); + } + + if (current_function_anonymous_args && current_function_pretend_args_size) + store_arg_regs = 1; + + if (current_function_pretend_args_size) + { + if (store_arg_regs) + { + asm_fprintf (f, "\tpush\t{"); + for (regno = 4 - current_function_pretend_args_size / 4 ; regno < 4; + regno++) + asm_fprintf (f, "%s%s", reg_names[regno], regno == 3 ? "" : ", "); + asm_fprintf (f, "}\n"); + } + else + asm_fprintf (f, "\tsub\t%Rsp, %Rsp, #%d\n", + current_function_pretend_args_size); + } + + for (regno = 0; regno < 8; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + live_regs_mask |= 1 << regno; + + if (live_regs_mask || ! leaf_function_p () || far_jump_used_p()) + live_regs_mask |= 1 << 14; + + if (TARGET_BACKTRACE) + { + char * name; + int offset; + int work_register = 0; + + + /* We have been asked to create a stack backtrace structure. + The code looks like this: + + 0 .align 2 + 0 func: + 0 sub SP, #16 Reserve space for 4 registers. + 2 push {R7} Get a work register. + 4 add R7, SP, #20 Get the stack pointer before the push. + 6 str R7, [SP, #8] Store the stack pointer (before reserving the space). + 8 mov R7, PC Get hold of the start of this code plus 12. + 10 str R7, [SP, #16] Store it. + 12 mov R7, FP Get hold of the current frame pointer. + 14 str R7, [SP, #4] Store it. + 16 mov R7, LR Get hold of the current return address. + 18 str R7, [SP, #12] Store it. + 20 add R7, SP, #16 Point at the start of the backtrace structure. + 22 mov FP, R7 Put this value into the frame pointer. */ + + if ((live_regs_mask & 0xFF) == 0) + { + /* See if the a4 register is free. */ + + if (regs_ever_live[ 3 ] == 0) + work_register = 3; + else /* We must push a register of our own */ + live_regs_mask |= (1 << 7); + } + + if (work_register == 0) + { + /* Select a register from the list that will be pushed to use as our work register. */ + + for (work_register = 8; work_register--;) + if ((1 << work_register) & live_regs_mask) + break; + } + + name = reg_names[ work_register ]; + + asm_fprintf (f, "\tsub\tsp, sp, #16\t@ Create stack backtrace structure\n"); + + if (live_regs_mask) + thumb_pushpop (f, live_regs_mask, 1); + + for (offset = 0, work_register = 1 << 15; work_register; work_register >>= 1) + if (work_register & live_regs_mask) + offset += 4; + + asm_fprintf (f, "\tadd\t%s, sp, #%d\n", + name, offset + 16 + current_function_pretend_args_size); + + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 4); + + /* Make sure that the instruction fetching the PC is in the right place + to calculate "start of backtrace creation code + 12". */ + + if (live_regs_mask) + { + asm_fprintf (f, "\tmov\t%s, pc\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); + asm_fprintf (f, "\tmov\t%s, fp\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); + } + else + { + asm_fprintf (f, "\tmov\t%s, fp\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); + asm_fprintf (f, "\tmov\t%s, pc\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); + } + + asm_fprintf (f, "\tmov\t%s, lr\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 8); + asm_fprintf (f, "\tadd\t%s, sp, #%d\n", name, offset + 12); + asm_fprintf (f, "\tmov\tfp, %s\t\t@ Backtrace structure created\n", name); + } + else if (live_regs_mask) + thumb_pushpop (f, live_regs_mask, 1); + + for (regno = 8; regno < 13; regno++) + { + if (regs_ever_live[regno] && ! call_used_regs[regno]) + high_regs_pushed++; + } + + if (high_regs_pushed) + { + int pushable_regs = 0; + int mask = live_regs_mask & 0xff; + int next_hi_reg; + + for (next_hi_reg = 12; next_hi_reg > 7; next_hi_reg--) + { + if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) + break; + } + + pushable_regs = mask; + + if (pushable_regs == 0) + { + /* desperation time -- this probably will never happen */ + if (regs_ever_live[3] || ! call_used_regs[3]) + asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[12], reg_names[3]); + mask = 1 << 3; + } + + while (high_regs_pushed > 0) + { + for (regno = 7; regno >= 0; regno--) + { + if (mask & (1 << regno)) + { + asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[regno], + reg_names[next_hi_reg]); + high_regs_pushed--; + if (high_regs_pushed) + for (next_hi_reg--; next_hi_reg > 7; next_hi_reg--) + { + if (regs_ever_live[next_hi_reg] + && ! call_used_regs[next_hi_reg]) + break; + } + else + { + mask &= ~ ((1 << regno) - 1); + break; + } + } + } + thumb_pushpop (f, mask, 1); + } + + if (pushable_regs == 0 && (regs_ever_live[3] || ! call_used_regs[3])) + asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[3], reg_names[12]); + } +} + +void +thumb_expand_prologue () +{ + HOST_WIDE_INT amount = (get_frame_size () + + current_function_outgoing_args_size); + int regno; + int live_regs_mask; + + /* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + /* Naked functions don't have prologues. */ + if (arm_naked_function_p (current_function_decl)) + return; +#endif + /* END CYGNUS LOCAL nickc/thumb-pe */ + + if (amount) + { + live_regs_mask = 0; + for (regno = 0; regno < 8; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + live_regs_mask |= 1 << regno; + + if (amount < 512) + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (-amount))); + else + { + rtx reg, spare; + + if ((live_regs_mask & 0xff) == 0) /* Very unlikely */ + emit_insn (gen_movsi (spare = gen_rtx (REG, SImode, 12), + reg = gen_rtx (REG, SImode, 4))); + else + { + for (regno = 0; regno < 8; regno++) + if (live_regs_mask & (1 << regno)) + break; + reg = gen_rtx (REG, SImode, regno); + } + + emit_insn (gen_movsi (reg, GEN_INT (-amount))); + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); + if ((live_regs_mask & 0xff) == 0) + emit_insn (gen_movsi (reg, spare)); + } + } + + if (frame_pointer_needed) + { + if (current_function_outgoing_args_size) + { + rtx offset = GEN_INT (current_function_outgoing_args_size); + + if (current_function_outgoing_args_size < 1024) + emit_insn (gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx, + offset)); + else + { + emit_insn (gen_movsi (frame_pointer_rtx, offset)); + emit_insn (gen_addsi3 (frame_pointer_rtx, frame_pointer_rtx, + stack_pointer_rtx)); + } + } + else + emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx)); + } + + /* if (profile_flag || profile_block_flag) */ + emit_insn (gen_blockage ()); +} + +void +thumb_expand_epilogue () +{ + HOST_WIDE_INT amount = (get_frame_size () + + current_function_outgoing_args_size); + int regno; + + /* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + /* Naked functions don't have epilogues. */ + if (arm_naked_function_p (current_function_decl)) + return; +#endif + /* END CYGNUS LOCAL nickc/thumb-pe */ + + if (amount) + { + if (amount < 512) + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (amount))); + else + { + rtx reg = gen_rtx (REG, SImode, 3); /* Always free in the epilogue */ + + emit_insn (gen_movsi (reg, GEN_INT (amount))); + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); + } + /* if (profile_flag || profile_block_flag) */ + emit_insn (gen_blockage ()); + } +} + +void +thumb_function_epilogue (f, frame_size) + FILE *f; + int frame_size; +{ + /* ??? Probably not safe to set this here, since it assumes that a + function will be emitted as assembly immediately after we generate + RTL for it. This does not happen for inline functions. */ + return_used_this_function = 0; + current_function_has_far_jump = 0; +#if 0 /* TODO : comment not really needed */ + fprintf (f, "%s THUMB Epilogue\n", ASM_COMMENT_START); +#endif +} + +/* The bits which aren't usefully expanded as rtl. */ +char * +thumb_unexpanded_epilogue () +{ + int regno; + int live_regs_mask = 0; + int high_regs_pushed = 0; + int leaf_function = leaf_function_p (); + int had_to_push_lr; + + if (return_used_this_function) + return ""; + + for (regno = 0; regno < 8; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + live_regs_mask |= 1 << regno; + + for (regno = 8; regno < 13; regno++) + { + if (regs_ever_live[regno] && ! call_used_regs[regno]) + high_regs_pushed ++; + } + + /* The prolog may have pushed some high registers to use as + work registers. eg the testuite file: + gcc/testsuite/gcc/gcc.c-torture/execute/complex-2.c + compiles to produce: + push {r4, r5, r6, r7, lr} + mov r7, r9 + mov r6, r8 + push {r6, r7} + as part of the prolog. We have to undo that pushing here. */ + + if (high_regs_pushed) + { + int mask = live_regs_mask; + int next_hi_reg; + int size; + int mode; + +#ifdef RTX_CODE + /* If we can deduce the registers used from the function's return value. + This is more reliable that examining regs_ever_live[] because that + will be set if the register is ever used in the function, not just if + the register is used to hold a return value. */ + + if (current_function_return_rtx != 0) + { + mode = GET_MODE (current_function_return_rtx); + } + else +#endif + { + mode = DECL_MODE (DECL_RESULT (current_function_decl)); + } + + size = GET_MODE_SIZE (mode); + + /* Unless we are returning a type of size > 12 register r3 is available. */ + if (size < 13) + mask |= 1 << 3; + + if (mask == 0) + { + /* Oh dear! We have no low registers into which we can pop high registers! */ + + fatal ("No low registers available for popping high registers"); + } + + for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++) + if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) + break; + + while (high_regs_pushed) + { + /* Find low register(s) into which the high register(s) can be popped. */ + for (regno = 0; regno < 8; regno++) + { + if (mask & (1 << regno)) + high_regs_pushed--; + if (high_regs_pushed == 0) + break; + } + + mask &= (2 << regno) - 1; /* A noop if regno == 8 */ + + /* Pop the values into the low register(s). */ + thumb_pushpop (asm_out_file, mask, 0); + + /* Move the value(s) into the high registers. */ + for (regno = 0; regno < 8; regno++) + { + if (mask & (1 << regno)) + { + asm_fprintf (asm_out_file, "\tmov\t%s, %s\n", + reg_names[next_hi_reg], reg_names[regno]); + for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++) + if (regs_ever_live[next_hi_reg] && + ! call_used_regs[next_hi_reg]) + break; + } + } + } + } + + had_to_push_lr = (live_regs_mask || ! leaf_function || far_jump_used_p()); + + if (TARGET_BACKTRACE && ((live_regs_mask & 0xFF) == 0) && regs_ever_live[ ARG_4_REGISTER ] != 0) + { + /* The stack backtrace structure creation code had to + push R7 in order to get a work register, so we pop + it now. */ + + live_regs_mask |= (1 << WORK_REGISTER); + } + + if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE) + { + if (had_to_push_lr + && ! is_called_in_ARM_mode (current_function_decl)) + live_regs_mask |= 1 << PROGRAM_COUNTER; + + /* Either no argument registers were pushed or a backtrace + structure was created which includes an adjusted stack + pointer, so just pop everything. */ + + if (live_regs_mask) + thumb_pushpop (asm_out_file, live_regs_mask, FALSE); + + /* We have either just popped the return address into the + PC or it is was kept in LR for the entire function or + it is still on the stack because we do not want to + return by doing a pop {pc}. */ + + if ((live_regs_mask & (1 << PROGRAM_COUNTER)) == 0) + thumb_exit (asm_out_file, + (had_to_push_lr + && is_called_in_ARM_mode (current_function_decl)) ? + -1 : LINK_REGISTER); + } + else + { + /* Pop everything but the return address. */ + live_regs_mask &= ~ (1 << PROGRAM_COUNTER); + + if (live_regs_mask) + thumb_pushpop (asm_out_file, live_regs_mask, FALSE); + + if (had_to_push_lr) + { + /* Get the return address into a temporary register. */ + thumb_pushpop (asm_out_file, 1 << ARG_4_REGISTER, 0); + } + + /* Remove the argument registers that were pushed onto the stack. */ + asm_fprintf (asm_out_file, "\tadd\t%s, %s, #%d\n", + reg_names [STACK_POINTER], + reg_names [STACK_POINTER], + current_function_pretend_args_size); + + thumb_exit (asm_out_file, had_to_push_lr ? ARG_4_REGISTER : LINK_REGISTER); + } + + return ""; +} + +/* Handle the case of a double word load into a low register from + a computed memory address. The computed address may involve a + register which is overwritten by the load. */ + +char * +thumb_load_double_from_address (operands) + rtx * operands; +{ + rtx addr; + rtx base; + rtx offset; + rtx arg1; + rtx arg2; + + if (GET_CODE (operands[0]) != REG) + fatal ("thumb_load_double_from_address: destination is not a register"); + + if (GET_CODE (operands[1]) != MEM) + fatal ("thumb_load_double_from_address: source is not a computed memory address"); + + /* Get the memory address. */ + + addr = XEXP (operands[1], 0); + + /* Work out how the memory address is computed. */ + + switch (GET_CODE (addr)) + { + case REG: + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); + + if (REGNO (operands[0]) == REGNO (addr)) + { + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + } + else + { + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + } + break; + + case CONST: + /* Compute
+ 4 for the high order load. */ + + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); + + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + break; + + case PLUS: + arg1 = XEXP (addr, 0); + arg2 = XEXP (addr, 1); + + if (CONSTANT_P (arg1)) + base = arg2, offset = arg1; + else + base = arg1, offset = arg2; + + if (GET_CODE (base) != REG) + fatal ("thumb_load_double_from_address: base is not a register"); + + /* Catch the case of
= + */ + + if (GET_CODE (offset) == REG) + { + int reg_offset = REGNO (offset); + int reg_base = REGNO (base); + int reg_dest = REGNO (operands[0]); + + /* Add the base and offset registers together into the higher destination register. */ + + fprintf (asm_out_file, "\tadd\t%s, %s, %s\t\t%s created by thumb_load_double_from_address", + reg_names[ reg_dest + 1 ], + reg_names[ reg_base ], + reg_names[ reg_offset ], + ASM_COMMENT_START); + + /* Load the lower destination register from the address in the higher destination register. */ + + fprintf (asm_out_file, "\tldr\t%s, [%s, #0]\t\t%s created by thumb_load_double_from_address", + reg_names[ reg_dest ], + reg_names[ reg_dest + 1], + ASM_COMMENT_START); + + /* Load the higher destination register from its own address plus 4. */ + + fprintf (asm_out_file, "\tldr\t%s, [%s, #4]\t\t%s created by thumb_load_double_from_address", + reg_names[ reg_dest + 1 ], + reg_names[ reg_dest + 1 ], + ASM_COMMENT_START); + } + else + { + /* Compute
+ 4 for the high order load. */ + + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); + + /* If the computed address is held in the low order register + then load the high order register first, otherwise always + load the low order register first. */ + + if (REGNO (operands[0]) == REGNO (base)) + { + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + } + else + { + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + } + } + break; + + case LABEL_REF: + /* With no registers to worry about we can just load the value directly. */ + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); + + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + break; + + default: + debug_rtx (operands[1]); + fatal ("thumb_load_double_from_address: Unhandled address calculation"); + break; + } + + return ""; +} + +char * +output_move_mem_multiple (n, operands) + int n; + rtx *operands; +{ + rtx tmp; + + switch (n) + { + case 2: + if (REGNO (operands[2]) > REGNO (operands[3])) + { + tmp = operands[2]; + operands[2] = operands[3]; + operands[3] = tmp; + } + output_asm_insn ("ldmia\t%1!, {%2, %3}", operands); + output_asm_insn ("stmia\t%0!, {%2, %3}", operands); + break; + + case 3: + if (REGNO (operands[2]) > REGNO (operands[3])) + { + tmp = operands[2]; + operands[2] = operands[3]; + operands[3] = tmp; + } + if (REGNO (operands[3]) > REGNO (operands[4])) + { + tmp = operands[3]; + operands[3] = operands[4]; + operands[4] = tmp; + } + if (REGNO (operands[2]) > REGNO (operands[3])) + { + tmp = operands[2]; + operands[2] = operands[3]; + operands[3] = tmp; + } + output_asm_insn ("ldmia\t%1!, {%2, %3, %4}", operands); + output_asm_insn ("stmia\t%0!, {%2, %3, %4}", operands); + break; + + default: + abort (); + } + + return ""; +} + + +int +thumb_epilogue_size () +{ + return 42; /* The answer to .... */ +} + +static char *conds[] = +{ + "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", + "hi", "ls", "ge", "lt", "gt", "le" +}; + +static char * +thumb_condition_code (x, invert) + rtx x; + int invert; +{ + int val; + + switch (GET_CODE (x)) + { + case EQ: val = 0; break; + case NE: val = 1; break; + case GEU: val = 2; break; + case LTU: val = 3; break; + case GTU: val = 8; break; + case LEU: val = 9; break; + case GE: val = 10; break; + case LT: val = 11; break; + case GT: val = 12; break; + case LE: val = 13; break; + default: + abort (); + } + + return conds[val ^ invert]; +} + +void +thumb_print_operand (f, x, code) + FILE *f; + rtx x; + int code; +{ + if (code) + { + switch (code) + { + case '@': + fputs (ASM_COMMENT_START, f); + return; + + case '_': + fputs (user_label_prefix, f); + return; + + case 'D': + if (x) + fputs (thumb_condition_code (x, 1), f); + return; + + case 'd': + if (x) + fputs (thumb_condition_code (x, 0), f); + return; + + /* An explanation of the 'Q', 'R' and 'H' register operands: + + In a pair of registers containing a DI or DF value the 'Q' + operand returns the register number of the register containing + the least signficant part of the value. The 'R' operand returns + the register number of the register containing the most + significant part of the value. + + The 'H' operand returns the higher of the two register numbers. + On a run where WORDS_BIG_ENDIAN is true the 'H' operand is the + same as the 'Q' operand, since the most signficant part of the + value is held in the lower number register. The reverse is true + on systems where WORDS_BIG_ENDIAN is false. + + The purpose of these operands is to distinguish between cases + where the endian-ness of the values is important (for example + when they are added together), and cases where the endian-ness + is irrelevant, but the order of register operations is important. + For example when loading a value from memory into a register + pair, the endian-ness does not matter. Provided that the value + from the lower memory address is put into the lower numbered + register, and the value from the higher address is put into the + higher numbered register, the load will work regardless of whether + the value being loaded is big-wordian or little-wordian. The + order of the two register loads can matter however, if the address + of the memory location is actually held in one of the registers + being overwritten by the load. */ + case 'Q': + if (REGNO (x) > 15) + abort (); + fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0)], f); + return; + + case 'R': + if (REGNO (x) > 15) + abort (); + fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1)], f); + return; + + case 'H': + if (REGNO (x) > 15) + abort (); + fputs (reg_names[REGNO (x) + 1], f); + return; + + case 'c': + /* We use 'c' operands with symbols for .vtinherit */ + if (GET_CODE (x) == SYMBOL_REF) + output_addr_const(f, x); + return; + + default: + abort (); + } + } + if (GET_CODE (x) == REG) + fputs (reg_names[REGNO (x)], f); + else if (GET_CODE (x) == MEM) + output_address (XEXP (x, 0)); + else if (GET_CODE (x) == CONST_INT) + { + fputc ('#', f); + output_addr_const (f, x); + } + else + abort (); +} + +#ifdef AOF_ASSEMBLER +int arm_text_section_count = 1; + +char * +aof_text_section (in_readonly) + int in_readonly; +{ + static char buf[100]; + if (in_readonly) + return ""; + sprintf (buf, "\tCODE16\n\tAREA |C$$code%d|, CODE, READONLY", + arm_text_section_count++); + return buf; +} + +static int arm_data_section_count = 1; + +char * +aof_data_section () +{ + static char buf[100]; + sprintf (buf, "\tAREA |C$$data%d|, DATA", arm_data_section_count++); + return buf; +} + +/* The AOF thumb assembler is religiously strict about declarations of + imported and exported symbols, so that it is impossible to declare a + function as imported near the begining of the file, and then to export + it later on. It is, however, possible to delay the decision until all + the functions in the file have been compiled. To get around this, we + maintain a list of the imports and exports, and delete from it any that + are subsequently defined. At the end of compilation we spit the + remainder of the list out before the END directive. */ + +struct import +{ + struct import *next; + char *name; +}; + +static struct import *imports_list = NULL; + +void +thumb_aof_add_import (name) + char *name; +{ + struct import *new; + + for (new = imports_list; new; new = new->next) + if (new->name == name) + return; + + new = (struct import *) xmalloc (sizeof (struct import)); + new->next = imports_list; + imports_list = new; + new->name = name; +} + +void +thumb_aof_delete_import (name) + char *name; +{ + struct import **old; + + for (old = &imports_list; *old; old = & (*old)->next) + { + if ((*old)->name == name) + { + *old = (*old)->next; + return; + } + } +} + +void +thumb_aof_dump_imports (f) + FILE *f; +{ + while (imports_list) + { + fprintf (f, "\tIMPORT\t"); + assemble_name (f, imports_list->name); + fputc ('\n', f); + imports_list = imports_list->next; + } +} +#endif + +/* Decide whether a type should be returned in memory (true) + or in a register (false). This is called by the macro + RETURN_IN_MEMORY. */ + +int +thumb_return_in_memory (type) + tree type; +{ + if (! AGGREGATE_TYPE_P (type)) + { + /* All simple types are returned in registers. */ + + return 0; + } + else if (int_size_in_bytes (type) > 4) + { + /* All structures/unions bigger than one word are returned in memory. */ + + return 1; + } + else if (TREE_CODE (type) == RECORD_TYPE) + { + tree field; + + /* For a struct the APCS says that we must return in a register if + every addressable element has an offset of zero. For practical + purposes this means that the structure can have at most one non- + bit-field element and that this element must be the first one in + the structure. */ + + /* Find the first field, ignoring non FIELD_DECL things which will + have been created by C++. */ + for (field = TYPE_FIELDS (type); + field && TREE_CODE (field) != FIELD_DECL; + field = TREE_CHAIN (field)) + continue; + + if (field == NULL) + return 0; /* An empty structure. Allowed by an extension to ANSI C. */ + + /* Now check the remaining fields, if any. */ + for (field = TREE_CHAIN (field); field; field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + + if (! DECL_BIT_FIELD_TYPE (field)) + return 1; + } + + return 0; + } + else if (TREE_CODE (type) == UNION_TYPE) + { + tree field; + + /* Unions can be returned in registers if every element is + integral, or can be returned in an integer register. */ + + for (field = TYPE_FIELDS (type); + field; + field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + + if (RETURN_IN_MEMORY (TREE_TYPE (field))) + return 1; + } + + return 0; + } + /* XXX Not sure what should be done for other aggregates, so put them in + memory. */ + return 1; +} + +void +thumb_override_options () +{ + if (structure_size_string != NULL) + { + int size = strtol (structure_size_string, NULL, 0); + + if (size == 8 || size == 32) + arm_structure_size_boundary = size; + else + warning ("Structure size boundary can only be set to 8 or 32"); + } + + if (flag_pic) + { + warning ("Position independent code not supported. Ignored"); + flag_pic = 0; + } +} + +/* CYGNUS LOCAL nickc/thumb-pe */ + +#ifdef THUMB_PE +/* Return nonzero if ATTR is a valid attribute for DECL. + ATTRIBUTES are any existing attributes and ARGS are the arguments + supplied with ATTR. + + Supported attributes: + + naked: don't output any prologue or epilogue code, the user is assumed + to do the right thing. + + interfacearm: Always assume that this function will be entered in ARM + mode, not Thumb mode, and that the caller wishes to be returned to in + ARM mode. */ +int +arm_valid_machine_decl_attribute (decl, attributes, attr, args) + tree decl; + tree attributes; + tree attr; + tree args; +{ + if (args != NULL_TREE) + return 0; + + if (is_attribute_p ("naked", attr)) + return TREE_CODE (decl) == FUNCTION_DECL; + + if (is_attribute_p ("interfacearm", attr)) + return TREE_CODE (decl) == FUNCTION_DECL; + + return 0; +} +#endif /* THUMB_PE */ +/* END CYGNUS LOCAL nickc/thumb-pe */ + +/* s_register_operand is the same as register_operand, but it doesn't accept + (SUBREG (MEM)...). + + This function exists because at the time it was put in it led to better + code. SUBREG(MEM) always needs a reload in the places where + s_register_operand is used, and this seemed to lead to excessive + reloading. */ + +int +s_register_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + if (GET_MODE (op) != mode && mode != VOIDmode) + return 0; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + /* We don't consider registers whose class is NO_REGS + to be a register operand. */ + /* XXX might have to check for lo regs only for thumb ??? */ + return (GET_CODE (op) == REG + && (REGNO (op) >= FIRST_PSEUDO_REGISTER + || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); +} diff --git a/gcc_arm/config/arm/thumb.c.orig b/gcc_arm/config/arm/thumb.c.orig new file mode 100755 index 0000000..778cda9 --- /dev/null +++ b/gcc_arm/config/arm/thumb.c.orig @@ -0,0 +1,2132 @@ +/* Output routines for GCC for ARM/Thumb + Copyright (C) 1996 Cygnus Software Technologies Ltd + The basis of this contribution was generated by + Richard Earnshaw, Advanced RISC Machines Ltd + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include +#include +#include "config.h" +#include "rtl.h" +#include "hard-reg-set.h" +#include "regs.h" +#include "output.h" +#include "insn-flags.h" +#include "insn-attr.h" +#include "flags.h" +#include "tree.h" +#include "expr.h" + + +int current_function_anonymous_args = 0; +static int current_function_has_far_jump = 0; + +/* Used to parse -mstructure_size_boundary command line option. */ +char * structure_size_string = NULL; +int arm_structure_size_boundary = 32; /* Used to be 8 */ + + +/* Predicates */ +int +reload_memory_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + int regno = true_regnum (op); + + return (! CONSTANT_P (op) + && (regno == -1 + || (GET_CODE (op) == REG + && REGNO (op) >= FIRST_PSEUDO_REGISTER))); +} + +/* Return nonzero if op is suitable for the RHS of a cmp instruction. */ +int +thumb_cmp_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return ((GET_CODE (op) == CONST_INT + && (unsigned HOST_WIDE_INT) (INTVAL (op)) < 256) + || register_operand (op, mode)); +} + +int +thumb_shiftable_const (val) + HOST_WIDE_INT val; +{ + unsigned HOST_WIDE_INT x = val; + unsigned HOST_WIDE_INT mask = 0xff; + int i; + + for (i = 0; i < 25; i++) + if ((val & (mask << i)) == val) + return 1; + + return 0; +} + +int +thumb_trivial_epilogue () +{ + int regno; + + /* ??? If this function ever returns 1, we get a function without any + epilogue at all. It appears that the intent was to cause a "return" + insn to be emitted, but that does not happen. */ + return 0; + +#if 0 + if (get_frame_size () + || current_function_outgoing_args_size + || current_function_pretend_args_size) + return 0; + + for (regno = 8; regno < 13; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + return 0; + + return 1; +#endif +} + + +/* Routines for handling the constant pool */ +/* This is unashamedly hacked from the version in sh.c, since the problem is + extremely similar. */ + +/* Thumb instructions cannot load a large constant into a register, + constants have to come from a pc relative load. The reference of a pc + relative load instruction must be less than 1k infront of the instruction. + This means that we often have to dump a constant inside a function, and + generate code to branch around it. + + It is important to minimize this, since the branches will slow things + down and make things bigger. + + Worst case code looks like: + + ldr rn, L1 + b L2 + align + L1: .long value + L2: + .. + + ldr rn, L3 + b L4 + align + L3: .long value + L4: + .. + + We fix this by performing a scan before scheduling, which notices which + instructions need to have their operands fetched from the constant table + and builds the table. + + + The algorithm is: + + scan, find an instruction which needs a pcrel move. Look forward, find the + last barrier which is within MAX_COUNT bytes of the requirement. + If there isn't one, make one. Process all the instructions between + the find and the barrier. + + In the above example, we can tell that L3 is within 1k of L1, so + the first move can be shrunk from the 2 insn+constant sequence into + just 1 insn, and the constant moved to L3 to make: + + ldr rn, L1 + .. + ldr rn, L3 + b L4 + align + L1: .long value + L3: .long value + L4: + + Then the second move becomes the target for the shortening process. + + */ + +typedef struct +{ + rtx value; /* Value in table */ + HOST_WIDE_INT next_offset; + enum machine_mode mode; /* Mode of value */ +} pool_node; + +/* The maximum number of constants that can fit into one pool, since + the pc relative range is 0...1020 bytes and constants are at least 4 + bytes long */ + +#define MAX_POOL_SIZE (1020/4) +static pool_node pool_vector[MAX_POOL_SIZE]; +static int pool_size; +static rtx pool_vector_label; + +/* Add a constant to the pool and return its label. */ + +static HOST_WIDE_INT +add_constant (x, mode) + rtx x; + enum machine_mode mode; +{ + int i; + rtx lab; + HOST_WIDE_INT offset; + + if (mode == SImode && GET_CODE (x) == MEM && CONSTANT_P (XEXP (x, 0)) + && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0))) + x = get_pool_constant (XEXP (x, 0)); + + /* First see if we've already got it */ + + for (i = 0; i < pool_size; i++) + { + if (x->code == pool_vector[i].value->code + && mode == pool_vector[i].mode) + { + if (x->code == CODE_LABEL) + { + if (XINT (x, 3) != XINT (pool_vector[i].value, 3)) + continue; + } + if (rtx_equal_p (x, pool_vector[i].value)) + return pool_vector[i].next_offset - GET_MODE_SIZE (mode); + } + } + + /* Need a new one */ + + pool_vector[pool_size].next_offset = GET_MODE_SIZE (mode); + offset = 0; + if (pool_size == 0) + pool_vector_label = gen_label_rtx (); + else + pool_vector[pool_size].next_offset + += (offset = pool_vector[pool_size - 1].next_offset); + + pool_vector[pool_size].value = x; + pool_vector[pool_size].mode = mode; + pool_size++; + return offset; +} + +/* Output the literal table */ + +static void +dump_table (scan) + rtx scan; +{ + int i; + + scan = emit_label_after (gen_label_rtx (), scan); + scan = emit_insn_after (gen_align_4 (), scan); + scan = emit_label_after (pool_vector_label, scan); + + for (i = 0; i < pool_size; i++) + { + pool_node *p = pool_vector + i; + + switch (GET_MODE_SIZE (p->mode)) + { + case 4: + scan = emit_insn_after (gen_consttable_4 (p->value), scan); + break; + + case 8: + scan = emit_insn_after (gen_consttable_8 (p->value), scan); + break; + + default: + abort (); + break; + } + } + + scan = emit_insn_after (gen_consttable_end (), scan); + scan = emit_barrier_after (scan); + pool_size = 0; +} + +/* Non zero if the src operand needs to be fixed up */ +static +int +fixit (src, mode) + rtx src; + enum machine_mode mode; +{ + return ((CONSTANT_P (src) + && (GET_CODE (src) != CONST_INT + || ! (CONST_OK_FOR_LETTER_P (INTVAL (src), 'I') + || CONST_OK_FOR_LETTER_P (INTVAL (src), 'J') + || (mode != DImode + && CONST_OK_FOR_LETTER_P (INTVAL (src), 'K'))))) + || (mode == SImode && GET_CODE (src) == MEM + && GET_CODE (XEXP (src, 0)) == SYMBOL_REF + && CONSTANT_POOL_ADDRESS_P (XEXP (src, 0)))); +} + +/* Find the last barrier less than MAX_COUNT bytes from FROM, or create one. */ + +#define MAX_COUNT_SI 1000 + +static rtx +find_barrier (from) + rtx from; +{ + int count = 0; + rtx found_barrier = 0; + rtx label; + + while (from && count < MAX_COUNT_SI) + { + if (GET_CODE (from) == BARRIER) + return from; + + /* Count the length of this insn */ + if (GET_CODE (from) == INSN + && GET_CODE (PATTERN (from)) == SET + && CONSTANT_P (SET_SRC (PATTERN (from))) + && CONSTANT_POOL_ADDRESS_P (SET_SRC (PATTERN (from)))) + { + rtx src = SET_SRC (PATTERN (from)); + count += 2; + } + else + count += get_attr_length (from); + + from = NEXT_INSN (from); + } + + /* We didn't find a barrier in time to + dump our stuff, so we'll make one */ + label = gen_label_rtx (); + + if (from) + from = PREV_INSN (from); + else + from = get_last_insn (); + + /* Walk back to be just before any jump */ + while (GET_CODE (from) == JUMP_INSN + || GET_CODE (from) == NOTE + || GET_CODE (from) == CODE_LABEL) + from = PREV_INSN (from); + + from = emit_jump_insn_after (gen_jump (label), from); + JUMP_LABEL (from) = label; + found_barrier = emit_barrier_after (from); + emit_label_after (label, found_barrier); + return found_barrier; +} + +/* Non zero if the insn is a move instruction which needs to be fixed. */ + +static int +broken_move (insn) + rtx insn; +{ + if (!INSN_DELETED_P (insn) + && GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == SET) + { + rtx pat = PATTERN (insn); + rtx src = SET_SRC (pat); + rtx dst = SET_DEST (pat); + enum machine_mode mode = GET_MODE (dst); + if (dst == pc_rtx) + return 0; + return fixit (src, mode); + } + return 0; +} + +/* Recursively search through all of the blocks in a function + checking to see if any of the variables created in that + function match the RTX called 'orig'. If they do then + replace them with the RTX called 'new'. */ + +static void +replace_symbols_in_block (tree block, rtx orig, rtx new) +{ + for (; block; block = BLOCK_CHAIN (block)) + { + tree sym; + + if (! TREE_USED (block)) + continue; + + for (sym = BLOCK_VARS (block); sym; sym = TREE_CHAIN (sym)) + { + if ( (DECL_NAME (sym) == 0 && TREE_CODE (sym) != TYPE_DECL) + || DECL_IGNORED_P (sym) + || TREE_CODE (sym) != VAR_DECL + || DECL_EXTERNAL (sym) + || ! rtx_equal_p (DECL_RTL (sym), orig) + ) + continue; + + DECL_RTL (sym) = new; + } + + replace_symbols_in_block (BLOCK_SUBBLOCKS (block), orig, new); + } +} + +void +thumb_reorg (first) + rtx first; +{ + rtx insn; + for (insn = first; insn; insn = NEXT_INSN (insn)) + { + if (broken_move (insn)) + { + /* This is a broken move instruction, scan ahead looking for + a barrier to stick the constant table behind */ + rtx scan; + rtx barrier = find_barrier (insn); + + /* Now find all the moves between the points and modify them */ + for (scan = insn; scan != barrier; scan = NEXT_INSN (scan)) + { + if (broken_move (scan)) + { + /* This is a broken move instruction, add it to the pool */ + rtx pat = PATTERN (scan); + rtx src = SET_SRC (pat); + rtx dst = SET_DEST (pat); + enum machine_mode mode = GET_MODE (dst); + HOST_WIDE_INT offset; + rtx newinsn; + rtx newsrc; + + /* If this is an HImode constant load, convert it into + an SImode constant load. Since the register is always + 32 bits this is safe. We have to do this, since the + load pc-relative instruction only does a 32-bit load. */ + if (mode == HImode) + { + mode = SImode; + if (GET_CODE (dst) != REG) + abort (); + PUT_MODE (dst, SImode); + } + + offset = add_constant (src, mode); + newsrc = gen_rtx (MEM, mode, + plus_constant (gen_rtx (LABEL_REF, + VOIDmode, + pool_vector_label), + offset)); + + /* Build a jump insn wrapper around the move instead + of an ordinary insn, because we want to have room for + the target label rtx in fld[7], which an ordinary + insn doesn't have. */ + newinsn = emit_jump_insn_after (gen_rtx (SET, VOIDmode, + dst, newsrc), scan); + JUMP_LABEL (newinsn) = pool_vector_label; + + /* But it's still an ordinary insn */ + PUT_CODE (newinsn, INSN); + + /* If debugging information is going to be emitted + then we must make sure that any refences to + symbols which are removed by the above code are + also removed in the descriptions of the + function's variables. Failure to do this means + that the debugging information emitted could + refer to symbols which are not emited by + output_constant_pool() because + mark_constant_pool() never sees them as being + used. */ + + + /* These are the tests used in + output_constant_pool() to decide if the constant + pool will be marked. Only necessary if debugging + info is being emitted. Only necessary for + references to memory whose address is given by a + symbol. */ + + if (optimize > 0 + && flag_expensive_optimizations + && write_symbols != NO_DEBUG + && GET_CODE (src) == MEM + && GET_CODE (XEXP (src, 0)) == SYMBOL_REF) + replace_symbols_in_block + (DECL_INITIAL (current_function_decl), src, newsrc); + + /* Kill old insn */ + delete_insn (scan); + scan = newinsn; + } + } + dump_table (barrier); + } + } +} + + +/* Routines for generating rtl */ + +void +thumb_expand_movstrqi (operands) + rtx *operands; +{ + rtx out = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); + rtx in = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); + HOST_WIDE_INT len = INTVAL (operands[2]); + HOST_WIDE_INT offset = 0; + + while (len >= 12) + { + emit_insn (gen_movmem12b (out, in)); + len -= 12; + } + if (len >= 8) + { + emit_insn (gen_movmem8b (out, in)); + len -= 8; + } + if (len >= 4) + { + rtx reg = gen_reg_rtx (SImode); + emit_insn (gen_movsi (reg, gen_rtx (MEM, SImode, in))); + emit_insn (gen_movsi (gen_rtx (MEM, SImode, out), reg)); + len -= 4; + offset += 4; + } + if (len >= 2) + { + rtx reg = gen_reg_rtx (HImode); + emit_insn (gen_movhi (reg, gen_rtx (MEM, HImode, + plus_constant (in, offset)))); + emit_insn (gen_movhi (gen_rtx (MEM, HImode, plus_constant (out, offset)), + reg)); + len -= 2; + offset += 2; + } + if (len) + { + rtx reg = gen_reg_rtx (QImode); + emit_insn (gen_movqi (reg, gen_rtx (MEM, QImode, + plus_constant (in, offset)))); + emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (out, offset)), + reg)); + } +} + + +/* Routines for reloading */ + +void +thumb_reload_out_si (operands) + rtx operands; +{ + abort (); +} + +/* CYGNUS LOCAL nickc/thumb-pe */ + +#ifdef THUMB_PE +/* Return non-zero if FUNC is a naked function. */ + +static int +arm_naked_function_p (func) + tree func; +{ + tree a; + + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + + a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func)); + return a != NULL_TREE; +} +#endif +/* END CYGNUS LOCAL nickc/thumb-pe */ + +/* Return non-zero if FUNC must be entered in ARM mode. */ +int +is_called_in_ARM_mode (func) + tree func; +{ + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + + /* Ignore the problem about functions whoes address is taken. */ + if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func)) + return TRUE; + +/* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + return lookup_attribute ("interfacearm", DECL_MACHINE_ATTRIBUTES (func)) != NULL_TREE; +#else + return FALSE; +#endif +/* END CYGNUS LOCAL */ +} + + +/* Routines for emitting code */ + +void +final_prescan_insn(insn) + rtx insn; +{ + extern int *insn_addresses; + + if (flag_print_asm_name) + fprintf (asm_out_file, "%s 0x%04x\n", ASM_COMMENT_START, + insn_addresses[INSN_UID (insn)]); +} + + +static void thumb_pushpop ( FILE *, int, int ); /* Forward declaration. */ + +#ifdef __GNUC__ +inline +#endif +static int +number_of_first_bit_set (mask) + int mask; +{ + int bit; + + for (bit = 0; + (mask & (1 << bit)) == 0; + ++ bit) + continue; + + return bit; +} + +#define ARG_1_REGISTER 0 +#define ARG_2_REGISTER 1 +#define ARG_3_REGISTER 2 +#define ARG_4_REGISTER 3 +#define WORK_REGISTER 7 +#define FRAME_POINTER 11 +#define IP_REGISTER 12 +#define STACK_POINTER STACK_POINTER_REGNUM +#define LINK_REGISTER 14 +#define PROGRAM_COUNTER 15 + +/* Generate code to return from a thumb function. If + 'reg_containing_return_addr' is -1, then the return address is + actually on the stack, at the stack pointer. */ +static void +thumb_exit (f, reg_containing_return_addr) + FILE * f; + int reg_containing_return_addr; +{ + int regs_available_for_popping; + int regs_to_pop; + int pops_needed; + int reg; + int available; + int required; + int mode; + int size; + int restore_a4 = FALSE; + + /* Compute the registers we need to pop. */ + regs_to_pop = 0; + pops_needed = 0; + + if (reg_containing_return_addr == -1) + { + regs_to_pop |= 1 << LINK_REGISTER; + ++ pops_needed; + } + + if (TARGET_BACKTRACE) + { + /* Restore frame pointer and stack pointer. */ + regs_to_pop |= (1 << FRAME_POINTER) | (1 << STACK_POINTER); + pops_needed += 2; + } + + /* If there is nothing to pop then just emit the BX instruction and return.*/ + if (pops_needed == 0) + { + asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]); + + return; + } + + /* Otherwise if we are not supporting interworking and we have not created + a backtrace structure and the function was not entered in ARM mode then + just pop the return address straight into the PC. */ + else if ( ! TARGET_THUMB_INTERWORK + && ! TARGET_BACKTRACE + && ! is_called_in_ARM_mode (current_function_decl)) + { + asm_fprintf (f, "\tpop\t{pc}\n" ); + + return; + } + + /* Find out how many of the (return) argument registers we can corrupt. */ + regs_available_for_popping = 0; + +#ifdef RTX_CODE + /* If we can deduce the registers used from the function's return value. + This is more reliable that examining regs_ever_live[] because that + will be set if the register is ever used in the function, not just if + the register is used to hold a return value. */ + + if (current_function_return_rtx != 0) + mode = GET_MODE (current_function_return_rtx); + else +#endif + mode = DECL_MODE (DECL_RESULT (current_function_decl)); + + size = GET_MODE_SIZE (mode); + + if (size == 0) + { + /* In a void function we can use any argument register. + In a function that returns a structure on the stack + we can use the second and third argument registers. */ + if (mode == VOIDmode) + regs_available_for_popping = + (1 << ARG_1_REGISTER) + | (1 << ARG_2_REGISTER) + | (1 << ARG_3_REGISTER); + else + regs_available_for_popping = + (1 << ARG_2_REGISTER) + | (1 << ARG_3_REGISTER); + } + else if (size <= 4) regs_available_for_popping = + (1 << ARG_2_REGISTER) + | (1 << ARG_3_REGISTER); + else if (size <= 8) regs_available_for_popping = + (1 << ARG_3_REGISTER); + + /* Match registers to be popped with registers into which we pop them. */ + for (available = regs_available_for_popping, + required = regs_to_pop; + required != 0 && available != 0; + available &= ~(available & - available), + required &= ~(required & - required)) + -- pops_needed; + + /* If we have any popping registers left over, remove them. */ + if (available > 0) + regs_available_for_popping &= ~ available; + + /* Otherwise if we need another popping register we can use + the fourth argument register. */ + else if (pops_needed) + { + /* If we have not found any free argument registers and + reg a4 contains the return address, we must move it. */ + if (regs_available_for_popping == 0 + && reg_containing_return_addr == ARG_4_REGISTER) + { + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]); + reg_containing_return_addr = LINK_REGISTER; + } + else if (size > 12) + { + /* Register a4 is being used to hold part of the return value, + but we have dire need of a free, low register. */ + restore_a4 = TRUE; + + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [IP_REGISTER], reg_names [ARG_4_REGISTER]); + } + + if (reg_containing_return_addr != ARG_4_REGISTER) + { + /* The fourth argument register is available. */ + regs_available_for_popping |= 1 << ARG_4_REGISTER; + + -- pops_needed; + } + } + + /* Pop as many registers as we can. */ + thumb_pushpop (f, regs_available_for_popping, FALSE); + + /* Process the registers we popped. */ + if (reg_containing_return_addr == -1) + { + /* The return address was popped into the lowest numbered register. */ + regs_to_pop &= ~ (1 << LINK_REGISTER); + + reg_containing_return_addr = + number_of_first_bit_set (regs_available_for_popping); + + /* Remove this register for the mask of available registers, so that + the return address will not be corrupted by futher pops. */ + regs_available_for_popping &= ~ (1 << reg_containing_return_addr); + } + + /* If we popped other registers then handle them here. */ + if (regs_available_for_popping) + { + int frame_pointer; + + /* Work out which register currently contains the frame pointer. */ + frame_pointer = number_of_first_bit_set (regs_available_for_popping); + + /* Move it into the correct place. */ + asm_fprintf (f, "\tmov\tfp, %s\n", reg_names [frame_pointer]); + + /* (Temporarily) remove it from the mask of popped registers. */ + regs_available_for_popping &= ~ (1 << frame_pointer); + regs_to_pop &= ~ (1 << FRAME_POINTER); + + if (regs_available_for_popping) + { + int stack_pointer; + + /* We popped the stack pointer as well, find the register that + contains it.*/ + stack_pointer = number_of_first_bit_set (regs_available_for_popping); + + /* Move it into the stack register. */ + asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [stack_pointer]); + + /* At this point we have popped all necessary registers, so + do not worry about restoring regs_available_for_popping + to its correct value: + + assert (pops_needed == 0) + assert (regs_available_for_popping == (1 << frame_pointer)) + assert (regs_to_pop == (1 << STACK_POINTER)) */ + } + else + { + /* Since we have just move the popped value into the frame + pointer, the popping register is available for reuse, and + we know that we still have the stack pointer left to pop. */ + regs_available_for_popping |= (1 << frame_pointer); + } + } + + /* If we still have registers left on the stack, but we no longer have + any registers into which we can pop them, then we must move the return + address into the link register and make available the register that + contained it. */ + if (regs_available_for_popping == 0 && pops_needed > 0) + { + regs_available_for_popping |= 1 << reg_containing_return_addr; + + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [LINK_REGISTER], + reg_names [reg_containing_return_addr]); + + reg_containing_return_addr = LINK_REGISTER; + } + + /* If we have registers left on the stack then pop some more. + We know that at most we will want to pop FP and SP. */ + if (pops_needed > 0) + { + int popped_into; + int move_to; + + thumb_pushpop (f, regs_available_for_popping, FALSE); + + /* We have popped either FP or SP. + Move whichever one it is into the correct register. */ + popped_into = number_of_first_bit_set (regs_available_for_popping); + move_to = number_of_first_bit_set (regs_to_pop); + + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [move_to], reg_names [popped_into]); + + regs_to_pop &= ~ (1 << move_to); + + -- pops_needed; + } + + /* If we still have not popped everything then we must have only + had one register available to us and we are now popping the SP. */ + if (pops_needed > 0) + { + int popped_into; + + thumb_pushpop (f, regs_available_for_popping, FALSE); + + popped_into = number_of_first_bit_set (regs_available_for_popping); + + asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [popped_into]); + + /* + assert (regs_to_pop == (1 << STACK_POINTER)) + assert (pops_needed == 1) + */ + } + + /* If necessary restore the a4 register. */ + if (restore_a4) + { + if (reg_containing_return_addr != LINK_REGISTER) + { + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]); + reg_containing_return_addr = LINK_REGISTER; + } + + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [ARG_4_REGISTER], reg_names [IP_REGISTER]); + } + + /* Return to caller. */ + asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]); +} + +/* Emit code to push or pop registers to or from the stack. */ +static void +thumb_pushpop (f, mask, push) + FILE * f; + int mask; + int push; +{ + int regno; + int lo_mask = mask & 0xFF; + + if (lo_mask == 0 && ! push && (mask & (1 << 15))) + { + /* Special case. Do not generate a POP PC statement here, do it in + thumb_exit() */ + + thumb_exit (f, -1); + return; + } + + asm_fprintf (f, "\t%s\t{", push ? "push" : "pop"); + + /* Look at the low registers first. */ + + for (regno = 0; regno < 8; regno ++, lo_mask >>= 1) + { + if (lo_mask & 1) + { + asm_fprintf (f, reg_names[regno]); + + if ((lo_mask & ~1) != 0) + asm_fprintf (f, ", "); + } + } + + if (push && (mask & (1 << 14))) + { + /* Catch pushing the LR. */ + + if (mask & 0xFF) + asm_fprintf (f, ", "); + + asm_fprintf (f, reg_names[14]); + } + else if (!push && (mask & (1 << 15))) + { + /* Catch popping the PC. */ + + if (TARGET_THUMB_INTERWORK || TARGET_BACKTRACE) + { + /* The PC is never poped directly, instead + it is popped into r3 and then BX is used. */ + + asm_fprintf (f, "}\n"); + + thumb_exit (f, -1); + + return; + } + else + { + if (mask & 0xFF) + asm_fprintf (f, ", "); + + asm_fprintf (f, reg_names[15]); + } + } + + asm_fprintf (f, "}\n"); +} + +/* Returns non-zero if the current function contains a far jump */ + +int +far_jump_used_p (void) +{ + rtx insn; + + if (current_function_has_far_jump) + return 1; + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + if (GET_CODE (insn) == JUMP_INSN + /* Ignore tablejump patterns. */ + && GET_CODE (PATTERN (insn)) != ADDR_VEC + && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC + && get_attr_far_jump (insn) == FAR_JUMP_YES) + { + current_function_has_far_jump = 1; + return 1; + } + } + + return 0; +} + +static int return_used_this_function = 0; + +char * +output_return () +{ + int regno; + int live_regs_mask = 0; + + /* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + /* If a function is naked, don't use the "return" insn. */ + if (arm_naked_function_p (current_function_decl)) + return ""; +#endif + /* END CYGNUS LOCAL nickc/thumb-pe */ + + return_used_this_function = 1; + + for (regno = 0; regno < 8; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + live_regs_mask |= 1 << regno; + + if (live_regs_mask == 0) + { + if (leaf_function_p () && ! far_jump_used_p()) + { + thumb_exit (asm_out_file, 14); + } + else if ( TARGET_THUMB_INTERWORK + || TARGET_BACKTRACE + || is_called_in_ARM_mode (current_function_decl)) + { + thumb_exit (asm_out_file, -1); + } + else + asm_fprintf (asm_out_file, "\tpop\t{pc}\n"); + } + else + { + asm_fprintf (asm_out_file, "\tpop\t{"); + + for (regno = 0; live_regs_mask; regno ++, live_regs_mask >>= 1) + if (live_regs_mask & 1) + { + asm_fprintf (asm_out_file, reg_names[regno]); + if (live_regs_mask & ~1) + asm_fprintf (asm_out_file, ", "); + } + + if ( TARGET_THUMB_INTERWORK + || TARGET_BACKTRACE + || is_called_in_ARM_mode (current_function_decl)) + { + asm_fprintf (asm_out_file, "}\n"); + thumb_exit (asm_out_file, -1); + } + else + asm_fprintf (asm_out_file, ", pc}\n"); + } + + return ""; +} + +void +thumb_function_prologue (f, frame_size) + FILE *f; + int frame_size; +{ + int amount = frame_size + current_function_outgoing_args_size; + int live_regs_mask = 0; + int high_regs_pushed = 0; + int store_arg_regs = 0; + int regno; + +/* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + if (arm_naked_function_p (current_function_decl)) + return; +#endif +/* CYGNUS LOCAL nickc/thumb-pe */ + + if (is_called_in_ARM_mode (current_function_decl)) + { + char * name; + if (GET_CODE (DECL_RTL (current_function_decl)) != MEM) + abort(); + if (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0)) != SYMBOL_REF) + abort(); + name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); + + /* Generate code sequence to switch us into Thumb mode. */ + /* The .code 32 directive has already been emitted by + ASM_DECLARE_FUNCITON_NAME */ + asm_fprintf (f, "\torr\tr12, pc, #1\n"); + asm_fprintf (f, "\tbx\tr12\n"); + + /* Generate a label, so that the debugger will notice the + change in instruction sets. This label is also used by + the assembler to bypass the ARM code when this function + is called from a Thumb encoded function elsewhere in the + same file. Hence the definition of STUB_NAME here must + agree with the definition in gas/config/tc-arm.c */ + +#define STUB_NAME ".real_start_of" + + asm_fprintf (f, "\t.code\t16\n"); + asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name); + asm_fprintf (f, "\t.thumb_func\n"); + asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name); + } + + if (current_function_anonymous_args && current_function_pretend_args_size) + store_arg_regs = 1; + + if (current_function_pretend_args_size) + { + if (store_arg_regs) + { + asm_fprintf (f, "\tpush\t{"); + for (regno = 4 - current_function_pretend_args_size / 4 ; regno < 4; + regno++) + asm_fprintf (f, "%s%s", reg_names[regno], regno == 3 ? "" : ", "); + asm_fprintf (f, "}\n"); + } + else + asm_fprintf (f, "\tsub\t%Rsp, %Rsp, #%d\n", + current_function_pretend_args_size); + } + + for (regno = 0; regno < 8; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + live_regs_mask |= 1 << regno; + + if (live_regs_mask || ! leaf_function_p () || far_jump_used_p()) + live_regs_mask |= 1 << 14; + + if (TARGET_BACKTRACE) + { + char * name; + int offset; + int work_register = 0; + + + /* We have been asked to create a stack backtrace structure. + The code looks like this: + + 0 .align 2 + 0 func: + 0 sub SP, #16 Reserve space for 4 registers. + 2 push {R7} Get a work register. + 4 add R7, SP, #20 Get the stack pointer before the push. + 6 str R7, [SP, #8] Store the stack pointer (before reserving the space). + 8 mov R7, PC Get hold of the start of this code plus 12. + 10 str R7, [SP, #16] Store it. + 12 mov R7, FP Get hold of the current frame pointer. + 14 str R7, [SP, #4] Store it. + 16 mov R7, LR Get hold of the current return address. + 18 str R7, [SP, #12] Store it. + 20 add R7, SP, #16 Point at the start of the backtrace structure. + 22 mov FP, R7 Put this value into the frame pointer. */ + + if ((live_regs_mask & 0xFF) == 0) + { + /* See if the a4 register is free. */ + + if (regs_ever_live[ 3 ] == 0) + work_register = 3; + else /* We must push a register of our own */ + live_regs_mask |= (1 << 7); + } + + if (work_register == 0) + { + /* Select a register from the list that will be pushed to use as our work register. */ + + for (work_register = 8; work_register--;) + if ((1 << work_register) & live_regs_mask) + break; + } + + name = reg_names[ work_register ]; + + asm_fprintf (f, "\tsub\tsp, sp, #16\t@ Create stack backtrace structure\n"); + + if (live_regs_mask) + thumb_pushpop (f, live_regs_mask, 1); + + for (offset = 0, work_register = 1 << 15; work_register; work_register >>= 1) + if (work_register & live_regs_mask) + offset += 4; + + asm_fprintf (f, "\tadd\t%s, sp, #%d\n", + name, offset + 16 + current_function_pretend_args_size); + + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 4); + + /* Make sure that the instruction fetching the PC is in the right place + to calculate "start of backtrace creation code + 12". */ + + if (live_regs_mask) + { + asm_fprintf (f, "\tmov\t%s, pc\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); + asm_fprintf (f, "\tmov\t%s, fp\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); + } + else + { + asm_fprintf (f, "\tmov\t%s, fp\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); + asm_fprintf (f, "\tmov\t%s, pc\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); + } + + asm_fprintf (f, "\tmov\t%s, lr\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 8); + asm_fprintf (f, "\tadd\t%s, sp, #%d\n", name, offset + 12); + asm_fprintf (f, "\tmov\tfp, %s\t\t@ Backtrace structure created\n", name); + } + else if (live_regs_mask) + thumb_pushpop (f, live_regs_mask, 1); + + for (regno = 8; regno < 13; regno++) + { + if (regs_ever_live[regno] && ! call_used_regs[regno]) + high_regs_pushed++; + } + + if (high_regs_pushed) + { + int pushable_regs = 0; + int mask = live_regs_mask & 0xff; + int next_hi_reg; + + for (next_hi_reg = 12; next_hi_reg > 7; next_hi_reg--) + { + if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) + break; + } + + pushable_regs = mask; + + if (pushable_regs == 0) + { + /* desperation time -- this probably will never happen */ + if (regs_ever_live[3] || ! call_used_regs[3]) + asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[12], reg_names[3]); + mask = 1 << 3; + } + + while (high_regs_pushed > 0) + { + for (regno = 7; regno >= 0; regno--) + { + if (mask & (1 << regno)) + { + asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[regno], + reg_names[next_hi_reg]); + high_regs_pushed--; + if (high_regs_pushed) + for (next_hi_reg--; next_hi_reg > 7; next_hi_reg--) + { + if (regs_ever_live[next_hi_reg] + && ! call_used_regs[next_hi_reg]) + break; + } + else + { + mask &= ~ ((1 << regno) - 1); + break; + } + } + } + thumb_pushpop (f, mask, 1); + } + + if (pushable_regs == 0 && (regs_ever_live[3] || ! call_used_regs[3])) + asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[3], reg_names[12]); + } +} + +void +thumb_expand_prologue () +{ + HOST_WIDE_INT amount = (get_frame_size () + + current_function_outgoing_args_size); + int regno; + int live_regs_mask; + + /* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + /* Naked functions don't have prologues. */ + if (arm_naked_function_p (current_function_decl)) + return; +#endif + /* END CYGNUS LOCAL nickc/thumb-pe */ + + if (amount) + { + live_regs_mask = 0; + for (regno = 0; regno < 8; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + live_regs_mask |= 1 << regno; + + if (amount < 512) + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (-amount))); + else + { + rtx reg, spare; + + if ((live_regs_mask & 0xff) == 0) /* Very unlikely */ + emit_insn (gen_movsi (spare = gen_rtx (REG, SImode, 12), + reg = gen_rtx (REG, SImode, 4))); + else + { + for (regno = 0; regno < 8; regno++) + if (live_regs_mask & (1 << regno)) + break; + reg = gen_rtx (REG, SImode, regno); + } + + emit_insn (gen_movsi (reg, GEN_INT (-amount))); + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); + if ((live_regs_mask & 0xff) == 0) + emit_insn (gen_movsi (reg, spare)); + } + } + + if (frame_pointer_needed) + { + if (current_function_outgoing_args_size) + { + rtx offset = GEN_INT (current_function_outgoing_args_size); + + if (current_function_outgoing_args_size < 1024) + emit_insn (gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx, + offset)); + else + { + emit_insn (gen_movsi (frame_pointer_rtx, offset)); + emit_insn (gen_addsi3 (frame_pointer_rtx, frame_pointer_rtx, + stack_pointer_rtx)); + } + } + else + emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx)); + } + + /* if (profile_flag || profile_block_flag) */ + emit_insn (gen_blockage ()); +} + +void +thumb_expand_epilogue () +{ + HOST_WIDE_INT amount = (get_frame_size () + + current_function_outgoing_args_size); + int regno; + + /* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + /* Naked functions don't have epilogues. */ + if (arm_naked_function_p (current_function_decl)) + return; +#endif + /* END CYGNUS LOCAL nickc/thumb-pe */ + + if (amount) + { + if (amount < 512) + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (amount))); + else + { + rtx reg = gen_rtx (REG, SImode, 3); /* Always free in the epilogue */ + + emit_insn (gen_movsi (reg, GEN_INT (amount))); + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); + } + /* if (profile_flag || profile_block_flag) */ + emit_insn (gen_blockage ()); + } +} + +void +thumb_function_epilogue (f, frame_size) + FILE *f; + int frame_size; +{ + /* ??? Probably not safe to set this here, since it assumes that a + function will be emitted as assembly immediately after we generate + RTL for it. This does not happen for inline functions. */ + return_used_this_function = 0; + current_function_has_far_jump = 0; +#if 0 /* TODO : comment not really needed */ + fprintf (f, "%s THUMB Epilogue\n", ASM_COMMENT_START); +#endif +} + +/* The bits which aren't usefully expanded as rtl. */ +char * +thumb_unexpanded_epilogue () +{ + int regno; + int live_regs_mask = 0; + int high_regs_pushed = 0; + int leaf_function = leaf_function_p (); + int had_to_push_lr; + + if (return_used_this_function) + return ""; + + for (regno = 0; regno < 8; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + live_regs_mask |= 1 << regno; + + for (regno = 8; regno < 13; regno++) + { + if (regs_ever_live[regno] && ! call_used_regs[regno]) + high_regs_pushed ++; + } + + /* The prolog may have pushed some high registers to use as + work registers. eg the testuite file: + gcc/testsuite/gcc/gcc.c-torture/execute/complex-2.c + compiles to produce: + push {r4, r5, r6, r7, lr} + mov r7, r9 + mov r6, r8 + push {r6, r7} + as part of the prolog. We have to undo that pushing here. */ + + if (high_regs_pushed) + { + int mask = live_regs_mask; + int next_hi_reg; + int size; + int mode; + +#ifdef RTX_CODE + /* If we can deduce the registers used from the function's return value. + This is more reliable that examining regs_ever_live[] because that + will be set if the register is ever used in the function, not just if + the register is used to hold a return value. */ + + if (current_function_return_rtx != 0) + { + mode = GET_MODE (current_function_return_rtx); + } + else +#endif + { + mode = DECL_MODE (DECL_RESULT (current_function_decl)); + } + + size = GET_MODE_SIZE (mode); + + /* Unless we are returning a type of size > 12 register r3 is available. */ + if (size < 13) + mask |= 1 << 3; + + if (mask == 0) + { + /* Oh dear! We have no low registers into which we can pop high registers! */ + + fatal ("No low registers available for popping high registers"); + } + + for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++) + if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) + break; + + while (high_regs_pushed) + { + /* Find low register(s) into which the high register(s) can be popped. */ + for (regno = 0; regno < 8; regno++) + { + if (mask & (1 << regno)) + high_regs_pushed--; + if (high_regs_pushed == 0) + break; + } + + mask &= (2 << regno) - 1; /* A noop if regno == 8 */ + + /* Pop the values into the low register(s). */ + thumb_pushpop (asm_out_file, mask, 0); + + /* Move the value(s) into the high registers. */ + for (regno = 0; regno < 8; regno++) + { + if (mask & (1 << regno)) + { + asm_fprintf (asm_out_file, "\tmov\t%s, %s\n", + reg_names[next_hi_reg], reg_names[regno]); + for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++) + if (regs_ever_live[next_hi_reg] && + ! call_used_regs[next_hi_reg]) + break; + } + } + } + } + + had_to_push_lr = (live_regs_mask || ! leaf_function || far_jump_used_p()); + + if (TARGET_BACKTRACE && ((live_regs_mask & 0xFF) == 0) && regs_ever_live[ ARG_4_REGISTER ] != 0) + { + /* The stack backtrace structure creation code had to + push R7 in order to get a work register, so we pop + it now. */ + + live_regs_mask |= (1 << WORK_REGISTER); + } + + if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE) + { + if (had_to_push_lr + && ! is_called_in_ARM_mode (current_function_decl)) + live_regs_mask |= 1 << PROGRAM_COUNTER; + + /* Either no argument registers were pushed or a backtrace + structure was created which includes an adjusted stack + pointer, so just pop everything. */ + + if (live_regs_mask) + thumb_pushpop (asm_out_file, live_regs_mask, FALSE); + + /* We have either just popped the return address into the + PC or it is was kept in LR for the entire function or + it is still on the stack because we do not want to + return by doing a pop {pc}. */ + + if ((live_regs_mask & (1 << PROGRAM_COUNTER)) == 0) + thumb_exit (asm_out_file, + (had_to_push_lr + && is_called_in_ARM_mode (current_function_decl)) ? + -1 : LINK_REGISTER); + } + else + { + /* Pop everything but the return address. */ + live_regs_mask &= ~ (1 << PROGRAM_COUNTER); + + if (live_regs_mask) + thumb_pushpop (asm_out_file, live_regs_mask, FALSE); + + if (had_to_push_lr) + { + /* Get the return address into a temporary register. */ + thumb_pushpop (asm_out_file, 1 << ARG_4_REGISTER, 0); + } + + /* Remove the argument registers that were pushed onto the stack. */ + asm_fprintf (asm_out_file, "\tadd\t%s, %s, #%d\n", + reg_names [STACK_POINTER], + reg_names [STACK_POINTER], + current_function_pretend_args_size); + + thumb_exit (asm_out_file, had_to_push_lr ? ARG_4_REGISTER : LINK_REGISTER); + } + + return ""; +} + +/* Handle the case of a double word load into a low register from + a computed memory address. The computed address may involve a + register which is overwritten by the load. */ + +char * +thumb_load_double_from_address (operands) + rtx * operands; +{ + rtx addr; + rtx base; + rtx offset; + rtx arg1; + rtx arg2; + + if (GET_CODE (operands[0]) != REG) + fatal ("thumb_load_double_from_address: destination is not a register"); + + if (GET_CODE (operands[1]) != MEM) + fatal ("thumb_load_double_from_address: source is not a computed memory address"); + + /* Get the memory address. */ + + addr = XEXP (operands[1], 0); + + /* Work out how the memory address is computed. */ + + switch (GET_CODE (addr)) + { + case REG: + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); + + if (REGNO (operands[0]) == REGNO (addr)) + { + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + } + else + { + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + } + break; + + case CONST: + /* Compute
+ 4 for the high order load. */ + + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); + + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + break; + + case PLUS: + arg1 = XEXP (addr, 0); + arg2 = XEXP (addr, 1); + + if (CONSTANT_P (arg1)) + base = arg2, offset = arg1; + else + base = arg1, offset = arg2; + + if (GET_CODE (base) != REG) + fatal ("thumb_load_double_from_address: base is not a register"); + + /* Catch the case of
= + */ + + if (GET_CODE (offset) == REG) + { + int reg_offset = REGNO (offset); + int reg_base = REGNO (base); + int reg_dest = REGNO (operands[0]); + + /* Add the base and offset registers together into the higher destination register. */ + + fprintf (asm_out_file, "\tadd\t%s, %s, %s\t\t%s created by thumb_load_double_from_address", + reg_names[ reg_dest + 1 ], + reg_names[ reg_base ], + reg_names[ reg_offset ], + ASM_COMMENT_START); + + /* Load the lower destination register from the address in the higher destination register. */ + + fprintf (asm_out_file, "\tldr\t%s, [%s, #0]\t\t%s created by thumb_load_double_from_address", + reg_names[ reg_dest ], + reg_names[ reg_dest + 1], + ASM_COMMENT_START); + + /* Load the higher destination register from its own address plus 4. */ + + fprintf (asm_out_file, "\tldr\t%s, [%s, #4]\t\t%s created by thumb_load_double_from_address", + reg_names[ reg_dest + 1 ], + reg_names[ reg_dest + 1 ], + ASM_COMMENT_START); + } + else + { + /* Compute
+ 4 for the high order load. */ + + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); + + /* If the computed address is held in the low order register + then load the high order register first, otherwise always + load the low order register first. */ + + if (REGNO (operands[0]) == REGNO (base)) + { + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + } + else + { + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + } + } + break; + + case LABEL_REF: + /* With no registers to worry about we can just load the value directly. */ + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); + + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + break; + + default: + debug_rtx (operands[1]); + fatal ("thumb_load_double_from_address: Unhandled address calculation"); + break; + } + + return ""; +} + +char * +output_move_mem_multiple (n, operands) + int n; + rtx *operands; +{ + rtx tmp; + + switch (n) + { + case 2: + if (REGNO (operands[2]) > REGNO (operands[3])) + { + tmp = operands[2]; + operands[2] = operands[3]; + operands[3] = tmp; + } + output_asm_insn ("ldmia\t%1!, {%2, %3}", operands); + output_asm_insn ("stmia\t%0!, {%2, %3}", operands); + break; + + case 3: + if (REGNO (operands[2]) > REGNO (operands[3])) + { + tmp = operands[2]; + operands[2] = operands[3]; + operands[3] = tmp; + } + if (REGNO (operands[3]) > REGNO (operands[4])) + { + tmp = operands[3]; + operands[3] = operands[4]; + operands[4] = tmp; + } + if (REGNO (operands[2]) > REGNO (operands[3])) + { + tmp = operands[2]; + operands[2] = operands[3]; + operands[3] = tmp; + } + output_asm_insn ("ldmia\t%1!, {%2, %3, %4}", operands); + output_asm_insn ("stmia\t%0!, {%2, %3, %4}", operands); + break; + + default: + abort (); + } + + return ""; +} + + +int +thumb_epilogue_size () +{ + return 42; /* The answer to .... */ +} + +static char *conds[] = +{ + "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", + "hi", "ls", "ge", "lt", "gt", "le" +}; + +static char * +thumb_condition_code (x, invert) + rtx x; + int invert; +{ + int val; + + switch (GET_CODE (x)) + { + case EQ: val = 0; break; + case NE: val = 1; break; + case GEU: val = 2; break; + case LTU: val = 3; break; + case GTU: val = 8; break; + case LEU: val = 9; break; + case GE: val = 10; break; + case LT: val = 11; break; + case GT: val = 12; break; + case LE: val = 13; break; + default: + abort (); + } + + return conds[val ^ invert]; +} + +void +thumb_print_operand (f, x, code) + FILE *f; + rtx x; + int code; +{ + if (code) + { + switch (code) + { + case '@': + fputs (ASM_COMMENT_START, f); + return; + + case '_': + fputs (user_label_prefix, f); + return; + + case 'D': + if (x) + fputs (thumb_condition_code (x, 1), f); + return; + + case 'd': + if (x) + fputs (thumb_condition_code (x, 0), f); + return; + + /* An explanation of the 'Q', 'R' and 'H' register operands: + + In a pair of registers containing a DI or DF value the 'Q' + operand returns the register number of the register containing + the least signficant part of the value. The 'R' operand returns + the register number of the register containing the most + significant part of the value. + + The 'H' operand returns the higher of the two register numbers. + On a run where WORDS_BIG_ENDIAN is true the 'H' operand is the + same as the 'Q' operand, since the most signficant part of the + value is held in the lower number register. The reverse is true + on systems where WORDS_BIG_ENDIAN is false. + + The purpose of these operands is to distinguish between cases + where the endian-ness of the values is important (for example + when they are added together), and cases where the endian-ness + is irrelevant, but the order of register operations is important. + For example when loading a value from memory into a register + pair, the endian-ness does not matter. Provided that the value + from the lower memory address is put into the lower numbered + register, and the value from the higher address is put into the + higher numbered register, the load will work regardless of whether + the value being loaded is big-wordian or little-wordian. The + order of the two register loads can matter however, if the address + of the memory location is actually held in one of the registers + being overwritten by the load. */ + case 'Q': + if (REGNO (x) > 15) + abort (); + fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0)], f); + return; + + case 'R': + if (REGNO (x) > 15) + abort (); + fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1)], f); + return; + + case 'H': + if (REGNO (x) > 15) + abort (); + fputs (reg_names[REGNO (x) + 1], f); + return; + + case 'c': + /* We use 'c' operands with symbols for .vtinherit */ + if (GET_CODE (x) == SYMBOL_REF) + output_addr_const(f, x); + return; + + default: + abort (); + } + } + if (GET_CODE (x) == REG) + fputs (reg_names[REGNO (x)], f); + else if (GET_CODE (x) == MEM) + output_address (XEXP (x, 0)); + else if (GET_CODE (x) == CONST_INT) + { + fputc ('#', f); + output_addr_const (f, x); + } + else + abort (); +} + +#ifdef AOF_ASSEMBLER +int arm_text_section_count = 1; + +char * +aof_text_section (in_readonly) + int in_readonly; +{ + static char buf[100]; + if (in_readonly) + return ""; + sprintf (buf, "\tCODE16\n\tAREA |C$$code%d|, CODE, READONLY", + arm_text_section_count++); + return buf; +} + +static int arm_data_section_count = 1; + +char * +aof_data_section () +{ + static char buf[100]; + sprintf (buf, "\tAREA |C$$data%d|, DATA", arm_data_section_count++); + return buf; +} + +/* The AOF thumb assembler is religiously strict about declarations of + imported and exported symbols, so that it is impossible to declare a + function as imported near the begining of the file, and then to export + it later on. It is, however, possible to delay the decision until all + the functions in the file have been compiled. To get around this, we + maintain a list of the imports and exports, and delete from it any that + are subsequently defined. At the end of compilation we spit the + remainder of the list out before the END directive. */ + +struct import +{ + struct import *next; + char *name; +}; + +static struct import *imports_list = NULL; + +void +thumb_aof_add_import (name) + char *name; +{ + struct import *new; + + for (new = imports_list; new; new = new->next) + if (new->name == name) + return; + + new = (struct import *) xmalloc (sizeof (struct import)); + new->next = imports_list; + imports_list = new; + new->name = name; +} + +void +thumb_aof_delete_import (name) + char *name; +{ + struct import **old; + + for (old = &imports_list; *old; old = & (*old)->next) + { + if ((*old)->name == name) + { + *old = (*old)->next; + return; + } + } +} + +void +thumb_aof_dump_imports (f) + FILE *f; +{ + while (imports_list) + { + fprintf (f, "\tIMPORT\t"); + assemble_name (f, imports_list->name); + fputc ('\n', f); + imports_list = imports_list->next; + } +} +#endif + +/* Decide whether a type should be returned in memory (true) + or in a register (false). This is called by the macro + RETURN_IN_MEMORY. */ + +int +thumb_return_in_memory (type) + tree type; +{ + if (! AGGREGATE_TYPE_P (type)) + { + /* All simple types are returned in registers. */ + + return 0; + } + else if (int_size_in_bytes (type) > 4) + { + /* All structures/unions bigger than one word are returned in memory. */ + + return 1; + } + else if (TREE_CODE (type) == RECORD_TYPE) + { + tree field; + + /* For a struct the APCS says that we must return in a register if + every addressable element has an offset of zero. For practical + purposes this means that the structure can have at most one non- + bit-field element and that this element must be the first one in + the structure. */ + + /* Find the first field, ignoring non FIELD_DECL things which will + have been created by C++. */ + for (field = TYPE_FIELDS (type); + field && TREE_CODE (field) != FIELD_DECL; + field = TREE_CHAIN (field)) + continue; + + if (field == NULL) + return 0; /* An empty structure. Allowed by an extension to ANSI C. */ + + /* Now check the remaining fields, if any. */ + for (field = TREE_CHAIN (field); field; field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + + if (! DECL_BIT_FIELD_TYPE (field)) + return 1; + } + + return 0; + } + else if (TREE_CODE (type) == UNION_TYPE) + { + tree field; + + /* Unions can be returned in registers if every element is + integral, or can be returned in an integer register. */ + + for (field = TYPE_FIELDS (type); + field; + field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + + if (RETURN_IN_MEMORY (TREE_TYPE (field))) + return 1; + } + + return 0; + } + /* XXX Not sure what should be done for other aggregates, so put them in + memory. */ + return 1; +} + +void +thumb_override_options () +{ + if (structure_size_string != NULL) + { + int size = strtol (structure_size_string, NULL, 0); + + if (size == 8 || size == 32) + arm_structure_size_boundary = size; + else + warning ("Structure size boundary can only be set to 8 or 32"); + } + + if (flag_pic) + { + warning ("Position independent code not supported. Ignored"); + flag_pic = 0; + } +} + +/* CYGNUS LOCAL nickc/thumb-pe */ + +#ifdef THUMB_PE +/* Return nonzero if ATTR is a valid attribute for DECL. + ATTRIBUTES are any existing attributes and ARGS are the arguments + supplied with ATTR. + + Supported attributes: + + naked: don't output any prologue or epilogue code, the user is assumed + to do the right thing. + + interfacearm: Always assume that this function will be entered in ARM + mode, not Thumb mode, and that the caller wishes to be returned to in + ARM mode. */ +int +arm_valid_machine_decl_attribute (decl, attributes, attr, args) + tree decl; + tree attributes; + tree attr; + tree args; +{ + if (args != NULL_TREE) + return 0; + + if (is_attribute_p ("naked", attr)) + return TREE_CODE (decl) == FUNCTION_DECL; + + if (is_attribute_p ("interfacearm", attr)) + return TREE_CODE (decl) == FUNCTION_DECL; + + return 0; +} +#endif /* THUMB_PE */ +/* END CYGNUS LOCAL nickc/thumb-pe */ + +/* s_register_operand is the same as register_operand, but it doesn't accept + (SUBREG (MEM)...). + + This function exists because at the time it was put in it led to better + code. SUBREG(MEM) always needs a reload in the places where + s_register_operand is used, and this seemed to lead to excessive + reloading. */ + +int +s_register_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + if (GET_MODE (op) != mode && mode != VOIDmode) + return 0; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + /* We don't consider registers whose class is NO_REGS + to be a register operand. */ + /* XXX might have to check for lo regs only for thumb ??? */ + return (GET_CODE (op) == REG + && (REGNO (op) >= FIRST_PSEUDO_REGISTER + || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); +} diff --git a/gcc_arm/config/arm/thumb.c.rej b/gcc_arm/config/arm/thumb.c.rej new file mode 100755 index 0000000..2b5e409 --- /dev/null +++ b/gcc_arm/config/arm/thumb.c.rej @@ -0,0 +1,168 @@ +*************** +*** 2103,2105 **** + } + #endif /* THUMB_PE */ + /* END CYGNUS LOCAL nickc/thumb-pe */ +--- 2103,2264 ---- + } + #endif /* THUMB_PE */ + /* END CYGNUS LOCAL nickc/thumb-pe */ ++ ++ /* Return nonzero if ATTR is a valid attribute for TYPE. ++ ATTRIBUTES are any existing attributes and ARGS are the arguments ++ supplied with ATTR. ++ ++ Supported attributes: ++ ++ short_call: assume the offset from the caller to the callee is small. ++ ++ long_call: don't assume the offset is small. */ ++ ++ int ++ arm_valid_machine_type_attribute (type, attributes, attr, args) ++ tree type; ++ tree attributes; ++ tree attr; ++ tree args; ++ { ++ if (args != NULL_TREE) ++ return 0; ++ ++ if (is_attribute_p ("long_call", attr)) ++ return 1; ++ ++ if (is_attribute_p ("short_call", attr)) ++ return 1; ++ ++ return 0; ++ } ++ ++ /* Encode long_call or short_call attribute by prefixing ++ symbol name in DECL with a special character FLAG. */ ++ ++ void ++ arm_encode_call_attribute (decl, flag) ++ tree decl; ++ int flag; ++ { ++ const char * str = XSTR (XEXP (DECL_RTL (decl), 0), 0); ++ int len = strlen (str); ++ char * newstr; ++ ++ /* Do not allow weak functions to be treated as short call. */ ++ if (DECL_WEAK (decl) && flag == SHORT_CALL_FLAG_CHAR) ++ return; ++ ++ if (ENCODED_SHORT_CALL_ATTR_P (str) ++ || ENCODED_LONG_CALL_ATTR_P (str)) ++ return; ++ ++ newstr = malloc (len + 2); ++ newstr[0] = flag; ++ strcpy (newstr + 1, str); ++ ++ XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr; ++ } ++ ++ /* Return the length of a function name prefix ++ that starts with the character 'c'. */ ++ ++ static int ++ arm_get_strip_length (char c) ++ { ++ switch (c) ++ { ++ ARM_NAME_ENCODING_LENGTHS ++ default: return 0; ++ } ++ } ++ ++ /* Return a pointer to a function's name with any ++ and all prefix encodings stripped from it. */ ++ ++ char * ++ arm_strip_name_encoding (char * name) ++ { ++ int skip; ++ ++ while ((skip = arm_get_strip_length (* name))) ++ name += skip; ++ ++ return name; ++ } ++ ++ /* Return 1 if the operand is a SYMBOL_REF for a function known to be ++ defined within the current compilation unit. If this caanot be ++ determined, then 0 is returned. */ ++ ++ static int ++ current_file_function_operand (sym_ref) ++ rtx sym_ref; ++ { ++ /* This is a bit of a fib. A function will have a short call flag ++ applied to its name if it has the short call attribute, or it has ++ already been defined within the current compilation unit. */ ++ if (ENCODED_SHORT_CALL_ATTR_P (XSTR (sym_ref, 0))) ++ return 1; ++ ++ /* The current function is always defined within the current compilation ++ unit. if it s a weak definition however, then this may not be the real ++ definition of the function, and so we have to say no. */ ++ if (sym_ref == XEXP (DECL_RTL (current_function_decl), 0) ++ && !DECL_WEAK (current_function_decl)) ++ return 1; ++ ++ /* We cannot make the determination - default to returning 0. */ ++ return 0; ++ } ++ ++ /* Return non-zero if a 32 bit "long_call" should be generated for ++ this call. We generate a long_call if the function: ++ ++ a. has an __attribute__((long call)) ++ or b. the -mlong-calls command line switch has been specified ++ ++ However we do not generate a long call if the function: ++ ++ c. has an __attribute__ ((short_call)) ++ or d. has an __attribute__ ((section)) ++ or e. is defined within the current compilation unit. ++ ++ This function will be called by C fragments contained in the machine ++ description file. CALL_REF and CALL_COOKIE correspond to the matched ++ rtl operands. CALL_SYMBOL is used to distinguish between ++ two different callers of the function. It is set to 1 in the ++ "call_symbol" and "call_symbol_value" patterns and to 0 in the "call" ++ and "call_value" patterns. This is because of the difference in the ++ SYM_REFs passed by these patterns. */ ++ ++ int ++ arm_is_longcall_p (sym_ref, call_cookie, call_symbol) ++ rtx sym_ref; ++ int call_cookie; ++ int call_symbol; ++ { ++ if (!call_symbol) ++ { ++ if (GET_CODE (sym_ref) != MEM) ++ return 0; ++ ++ sym_ref = XEXP (sym_ref, 0); ++ } ++ ++ if (GET_CODE (sym_ref) != SYMBOL_REF) ++ return 0; ++ ++ if (call_cookie & CALL_SHORT) ++ return 0; ++ ++ if (TARGET_LONG_CALLS && flag_function_sections) ++ return 1; ++ ++ if (current_file_function_operand (sym_ref)) ++ return 0; ++ ++ return (call_cookie & CALL_LONG) ++ || ENCODED_LONG_CALL_ATTR_P (XSTR (sym_ref, 0)) ++ || TARGET_LONG_CALLS; ++ } diff --git a/gcc_arm/config/arm/thumb.h b/gcc_arm/config/arm/thumb.h new file mode 100755 index 0000000..9cd719a --- /dev/null +++ b/gcc_arm/config/arm/thumb.h @@ -0,0 +1,1195 @@ +/* Definitions of target machine for GNU compiler, for ARM/Thumb. + Copyright (C) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc. + The basis of this contribution was generated by + Richard Earnshaw, Advanced RISC Machines Ltd + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* ??? The files thumb.{c,h,md} are all seriously lacking comments. */ + +/* ??? The files thumb.{c,h,md} need to be reviewed by an experienced + gcc hacker in their entirety. */ + +/* ??? The files thumb.{c,h,md} and tcoff.h are all separate from the arm + files, which will lead to many maintenance problems. These files are + likely missing all bug fixes made to the arm port since they diverged. */ + +/* ??? Many patterns in the md file accept operands that will require a + reload. These should be eliminated if possible by tightening the + predicates and/or constraints. This will give faster/smaller code. */ + +/* ??? There is no pattern for the TST instuction. Check for other unsupported + instructions. */ + +/* Run Time Target Specifications */ +#ifndef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dthumb -D__thumb -Acpu(arm) -Amachine(arm)" +#endif + +#ifndef CPP_SPEC +#define CPP_SPEC "\ +%{mbig-endian:-D__ARMEB__ -D__THUMBEB__} \ +%{mbe:-D__ARMEB__ -D__THUMBEB__} \ +%{!mbe: %{!mbig-endian:-D__ARMEL__ -D__THUMBEL__}} \ +" +#endif + +#ifndef ASM_SPEC +#define ASM_SPEC "-marm7tdmi %{mthumb-interwork:-mthumb-interwork} %{mbig-endian:-EB}" +#endif +#define LINK_SPEC "%{mbig-endian:-EB} -X" + +#define TARGET_VERSION fputs (" (ARM/THUMB:generic)", stderr); + +/* Nonzero if we should compile with BYTES_BIG_ENDIAN set to 1. */ +#define THUMB_FLAG_BIG_END 0x0001 +#define THUMB_FLAG_BACKTRACE 0x0002 +#define THUMB_FLAG_LEAF_BACKTRACE 0x0004 +#define ARM_FLAG_THUMB 0x1000 /* same as in arm.h */ +#define THUMB_FLAG_CALLEE_SUPER_INTERWORKING 0x40000 +#define THUMB_FLAG_CALLER_SUPER_INTERWORKING 0x80000 + +/* Nonzero if all call instructions should be indirect. */ +#define ARM_FLAG_LONG_CALLS (0x10000) /* same as in arm.h */ + + +/* Run-time compilation parameters selecting different hardware/software subsets. */ +extern int target_flags; +#define TARGET_DEFAULT 0 /* ARM_FLAG_THUMB */ +#define TARGET_BIG_END (target_flags & THUMB_FLAG_BIG_END) +#define TARGET_THUMB_INTERWORK (target_flags & ARM_FLAG_THUMB) +#define TARGET_BACKTRACE (leaf_function_p() \ + ? (target_flags & THUMB_FLAG_LEAF_BACKTRACE) \ + : (target_flags & THUMB_FLAG_BACKTRACE)) + +/* Set if externally visable functions should assume that they + might be called in ARM mode, from a non-thumb aware code. */ +#define TARGET_CALLEE_INTERWORKING \ + (target_flags & THUMB_FLAG_CALLEE_SUPER_INTERWORKING) + +/* Set if calls via function pointers should assume that their + destination is non-Thumb aware. */ +#define TARGET_CALLER_INTERWORKING \ + (target_flags & THUMB_FLAG_CALLER_SUPER_INTERWORKING) + +#define TARGET_LONG_CALLS (target_flags & ARM_FLAG_LONG_CALLS) + +/* SUBTARGET_SWITCHES is used to add flags on a per-config basis. */ +#ifndef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES +#endif + +#define TARGET_SWITCHES \ +{ \ + {"big-endian", THUMB_FLAG_BIG_END}, \ + {"little-endian", -THUMB_FLAG_BIG_END}, \ + {"thumb-interwork", ARM_FLAG_THUMB}, \ + {"no-thumb-interwork", -ARM_FLAG_THUMB}, \ + {"tpcs-frame", THUMB_FLAG_BACKTRACE}, \ + {"no-tpcs-frame", -THUMB_FLAG_BACKTRACE}, \ + {"tpcs-leaf-frame", THUMB_FLAG_LEAF_BACKTRACE}, \ + {"no-tpcs-leaf-frame", -THUMB_FLAG_LEAF_BACKTRACE}, \ + {"callee-super-interworking", THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \ + {"no-callee-super-interworking", -THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \ + {"caller-super-interworking", THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \ + {"no-caller-super-interworking", -THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \ + {"long-calls", ARM_FLAG_LONG_CALLS, \ + "Generate all call instructions as indirect calls"}, \ + {"no-long-calls", -ARM_FLAG_LONG_CALLS, ""}, \ + SUBTARGET_SWITCHES \ + {"", TARGET_DEFAULT} \ +} + +#define TARGET_OPTIONS \ +{ \ + { "structure-size-boundary=", & structure_size_string }, \ +} + +#define REGISTER_PREFIX "" + +#define CAN_DEBUG_WITHOUT_FP 1 + +#define ASM_APP_ON "" +#define ASM_APP_OFF "\t.code\t16\n" + +/* Output a gap. In fact we fill it with nulls. */ +#define ASM_OUTPUT_SKIP(STREAM, NBYTES) \ + fprintf ((STREAM), "\t.space\t%u\n", (NBYTES)) + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ +#define ASM_OUTPUT_ALIGN(STREAM,LOG) \ +{ \ + if ((LOG) > 0) \ + fprintf (STREAM, "\t.align\t%d\n", (LOG)); \ +} + +/* Output a common block */ +#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ + (fprintf ((STREAM), "\t.comm\t"), \ + assemble_name ((STREAM), (NAME)), \ + fprintf((STREAM), ", %d\t%s %d\n", (ROUNDED), (ASM_COMMENT_START), (SIZE))) + +#define ASM_GENERATE_INTERNAL_LABEL(STRING,PREFIX,NUM) \ + sprintf ((STRING), "*%s%s%d", (LOCAL_LABEL_PREFIX), (PREFIX), (NUM)) + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ +#define ASM_OUTPUT_INTERNAL_LABEL(STREAM,PREFIX,NUM) \ + fprintf ((STREAM), "%s%s%d:\n", (LOCAL_LABEL_PREFIX), (PREFIX), (NUM)) + +/* This is how to output a label which precedes a jumptable. Since + instructions are 2 bytes, we need explicit alignment here. */ + +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,JUMPTABLE) \ + do { \ + ASM_OUTPUT_ALIGN (FILE, 2); \ + ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM); \ + } while (0) + +/* This says how to define a local common symbol (ie, not visible to + linker). */ +#define ASM_OUTPUT_LOCAL(STREAM, NAME, SIZE, ROUNDED) \ + (fprintf((STREAM),"\n\t.lcomm\t"), \ + assemble_name((STREAM),(NAME)), \ + fprintf((STREAM),",%u\n",(SIZE))) + +/* Output a reference to a label. */ +#define ASM_OUTPUT_LABELREF(STREAM,NAME) \ + fprintf ((STREAM), "%s%s", user_label_prefix, (NAME)) + +/* This is how to output an assembler line for a numeric constant byte. */ +#define ASM_OUTPUT_BYTE(STREAM,VALUE) \ + fprintf ((STREAM), "\t.byte\t0x%x\n", (VALUE)) + +#define ASM_OUTPUT_INT(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.word\t"); \ + output_addr_const (STREAM, (VALUE)); \ + fprintf (STREAM, "\n"); \ +} + +#define ASM_OUTPUT_SHORT(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.short\t"); \ + output_addr_const (STREAM, (VALUE)); \ + fprintf (STREAM, "\n"); \ +} + +#define ASM_OUTPUT_CHAR(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.byte\t"); \ + output_addr_const (STREAM, (VALUE)); \ + fprintf (STREAM, "\n"); \ +} + +#define ASM_OUTPUT_LONG_DOUBLE(STREAM,VALUE) \ +do { char dstr[30]; \ + long l[3]; \ + REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ + fprintf (STREAM, "\t.long 0x%lx,0x%lx,0x%lx\t%s long double %s\n", \ + l[0], l[1], l[2], ASM_COMMENT_START, dstr); \ + } while (0) + +#define ASM_OUTPUT_DOUBLE(STREAM, VALUE) \ +do { char dstr[30]; \ + long l[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.14g", dstr); \ + fprintf (STREAM, "\t.long 0x%lx, 0x%lx\t%s double %s\n", l[0], \ + l[1], ASM_COMMENT_START, dstr); \ + } while (0) + +#define ASM_OUTPUT_FLOAT(STREAM, VALUE) \ +do { char dstr[30]; \ + long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.7g", dstr); \ + fprintf (STREAM, "\t.word 0x%lx\t%s float %s\n", l, \ + ASM_COMMENT_START, dstr); \ + } while (0); + +/* Define results of standard character escape sequences. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* This is how to output a string. */ +#define ASM_OUTPUT_ASCII(STREAM, STRING, LEN) \ +do { \ + register int i, c, len = (LEN), cur_pos = 17; \ + register unsigned char *string = (unsigned char *)(STRING); \ + fprintf ((STREAM), "\t.ascii\t\""); \ + for (i = 0; i < len; i++) \ + { \ + register int c = string[i]; \ + \ + switch (c) \ + { \ + case '\"': \ + case '\\': \ + putc ('\\', (STREAM)); \ + putc (c, (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_NEWLINE: \ + fputs ("\\n", (STREAM)); \ + if (i+1 < len \ + && (((c = string[i+1]) >= '\040' && c <= '~') \ + || c == TARGET_TAB)) \ + cur_pos = 32767; /* break right here */ \ + else \ + cur_pos += 2; \ + break; \ + \ + case TARGET_TAB: \ + fputs ("\\t", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_FF: \ + fputs ("\\f", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_BS: \ + fputs ("\\b", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_CR: \ + fputs ("\\r", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + default: \ + if (c >= ' ' && c < 0177) \ + { \ + putc (c, (STREAM)); \ + cur_pos++; \ + } \ + else \ + { \ + fprintf ((STREAM), "\\%03o", c); \ + cur_pos += 4; \ + } \ + } \ + \ + if (cur_pos > 72 && i+1 < len) \ + { \ + cur_pos = 17; \ + fprintf ((STREAM), "\"\n\t.ascii\t\""); \ + } \ + } \ + fprintf ((STREAM), "\"\n"); \ +} while (0) + +/* Output and Generation of Labels */ +#define ASM_OUTPUT_LABEL(STREAM,NAME) \ + (assemble_name ((STREAM), (NAME)), \ + fprintf ((STREAM), ":\n")) + +#define ASM_GLOBALIZE_LABEL(STREAM,NAME) \ + (fprintf ((STREAM), "\t.globl\t"), \ + assemble_name ((STREAM), (NAME)), \ + fputc ('\n', (STREAM))) + +/* Construct a private name. */ +#define ASM_FORMAT_PRIVATE_NAME(OUTVAR,NAME,NUMBER) \ + ((OUTVAR) = (char *) alloca (strlen (NAME) + 10), \ + sprintf ((OUTVAR), "%s.%d", (NAME), (NUMBER))) + +/* Switch to the text or data segment. */ +#define TEXT_SECTION_ASM_OP ".text" +#define DATA_SECTION_ASM_OP ".data" +#define BSS_SECTION_ASM_OP ".bss" + +/* The assembler's names for the registers. */ +#ifndef REGISTER_NAMES +#define REGISTER_NAMES \ +{ \ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc", "ap" \ +} +#endif + +#ifndef ADDITIONAL_REGISTER_NAMES +#define ADDITIONAL_REGISTER_NAMES \ +{ \ + {"a1", 0}, \ + {"a2", 1}, \ + {"a3", 2}, \ + {"a4", 3}, \ + {"v1", 4}, \ + {"v2", 5}, \ + {"v3", 6}, \ + {"v4", 7}, \ + {"v5", 8}, \ + {"v6", 9}, \ + {"sb", 9}, \ + {"v7", 10}, \ + {"r10", 10}, /* sl */ \ + {"r11", 11}, /* fp */ \ + {"r12", 12}, /* ip */ \ + {"r13", 13}, /* sp */ \ + {"r14", 14}, /* lr */ \ + {"r15", 15} /* pc */ \ +} +#endif + +/* The assembler's parentheses characters. */ +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + +#ifndef ASM_COMMENT_START +#define ASM_COMMENT_START "@" +#endif + +/* Output an element of a dispatch table. */ +#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM,VALUE) \ + fprintf (STREAM, "\t.word\t%sL%d\n", (LOCAL_LABEL_PREFIX), (VALUE)) + +#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM,BODY,VALUE,REL) \ + fprintf (STREAM, "\tb\t%sL%d\n", (LOCAL_LABEL_PREFIX), (VALUE)) + +/* Storage Layout */ + +/* Define this is most significant bit is lowest numbered in + instructions that operate on numbered bit-fields. */ +#define BITS_BIG_ENDIAN 0 + +/* Define this if most significant byte of a word is the lowest + numbered. */ +#define BYTES_BIG_ENDIAN (TARGET_BIG_END != 0) + +#define WORDS_BIG_ENDIAN (BYTES_BIG_ENDIAN) + +/* LIBGCC2_WORDS_BIG_ENDIAN has to be a constant, so we define this based + on processor pre-defineds when compiling libgcc2.c. */ +#if defined(__THUMBEB__) && !defined(__THUMBEL__) +#define LIBGCC2_WORDS_BIG_ENDIAN 1 +#else +#define LIBGCC2_WORDS_BIG_ENDIAN 0 +#endif + +#define FLOAT_WORDS_BIG_ENDIAN 1 + +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 + +#define UNITS_PER_WORD 4 + +#define POINTER_SIZE 32 + +#define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \ +{ \ + if (GET_MODE_CLASS (MODE) == MODE_INT \ + && GET_MODE_SIZE (MODE) < 4) \ + { \ + (UNSIGNEDP) = 1; \ + (MODE) = SImode; \ + } \ +} + +#define PARM_BOUNDARY 32 +#define STACK_BOUNDARY 32 + +#define FUNCTION_BOUNDARY 32 +#define BIGGEST_ALIGNMENT 32 + +/* Make strings word-aligned so strcpy from constants will be faster. */ +#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ + (TREE_CODE (EXP) == STRING_CST \ + && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) + +#define EMPTY_FIELD_BOUNDARY 32 + +#define STRUCTURE_SIZE_BOUNDARY 32 + +/* Used when parsing command line option -mstructure_size_boundary. */ +extern char * structure_size_string; + +#define STRICT_ALIGNMENT 1 + +#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT + + +/* Layout of Source Language Data Types */ + +#define DEFAULT_SIGNED_CHAR 0 + +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + + +/* Register Usage */ + +/* Note there are 16 hard registers on the Thumb. We invent a 17th register + which is assigned to ARG_POINTER_REGNUM, but this is later removed by + elimination passes in the compiler. */ +#define FIRST_PSEUDO_REGISTER 17 + +/* ??? This is questionable. */ +#define FIXED_REGISTERS \ +{ \ + 0,0,0,0, \ + 0,0,0,0, \ + 0,0,0,1, \ + 0,1,1,1,1 \ +} + +/* ??? This is questionable. */ +#define CALL_USED_REGISTERS \ +{ \ + 1,1,1,1, \ + 0,0,0,0, \ + 0,0,0,1, \ + 1,1,1,1,1 \ +} + +#define HARD_REGNO_NREGS(REGNO,MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ + / UNITS_PER_WORD) + +/* ??? Probably should only allow DImode/DFmode in even numbered registers. */ +#define HARD_REGNO_MODE_OK(REGNO,MODE) ((GET_MODE_SIZE (MODE) > UNITS_PER_WORD) ? (REGNO < 7) : 1) + +#define MODES_TIEABLE_P(MODE1,MODE2) 1 + +/* The NOARG_LO_REGS class is the set of LO_REGS that are not used for passing + arguments to functions. These are the registers that are available for + spilling during reload. The code in reload1.c:init_reload() will detect this + class and place it into 'reload_address_base_reg_class'. */ + +enum reg_class +{ + NO_REGS, + NONARG_LO_REGS, + LO_REGS, + STACK_REG, + BASE_REGS, + HI_REGS, + ALL_REGS, + LIM_REG_CLASSES +}; + +#define GENERAL_REGS ALL_REGS + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +#define REG_CLASS_NAMES \ +{ \ + "NO_REGS", \ + "NONARG_LO_REGS", \ + "LO_REGS", \ + "STACK_REG", \ + "BASE_REGS", \ + "HI_REGS", \ + "ALL_REGS" \ +} + +#define REG_CLASS_CONTENTS \ +{ \ + 0x00000, \ + 0x000f0, \ + 0x000ff, \ + 0x02000, \ + 0x020ff, \ + 0x0ff00, \ + 0x1ffff, \ +} + +#define REGNO_REG_CLASS(REGNO) \ + ((REGNO) == STACK_POINTER_REGNUM ? STACK_REG \ + : (REGNO) < 8 ? ((REGNO) < 4 ? LO_REGS \ + : NONARG_LO_REGS) \ + : HI_REGS) + +#define BASE_REG_CLASS BASE_REGS + +#define MODE_BASE_REG_CLASS(MODE) \ + ((MODE) != QImode && (MODE) != HImode \ + ? BASE_REGS : LO_REGS) + +#define INDEX_REG_CLASS LO_REGS + +/* When SMALL_REGISTER_CLASSES is nonzero, the compiler allows + registers explicitly used in the rtl to be used as spill registers + but prevents the compiler from extending the lifetime of these + registers. */ + +#define SMALL_REGISTER_CLASSES 1 + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'l' ? LO_REGS \ + : (C) == 'h' ? HI_REGS \ + : (C) == 'b' ? BASE_REGS \ + : (C) == 'k' ? STACK_REG \ + : NO_REGS) + +#define REGNO_OK_FOR_BASE_P(REGNO) \ + ((REGNO) < 8 \ + || (REGNO) == STACK_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO] < 8 \ + || (unsigned) reg_renumber[REGNO] == STACK_POINTER_REGNUM) + +#define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) \ + ((REGNO) < 8 \ + || (unsigned) reg_renumber[REGNO] < 8 \ + || (GET_MODE_SIZE (MODE) >= 4 \ + && ((REGNO) == STACK_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO] == STACK_POINTER_REGNUM))) + +#define REGNO_OK_FOR_INDEX_P(REGNO) \ + ((REGNO) < 8 \ + || (unsigned) reg_renumber[REGNO] < 8) + +/* ??? This looks suspiciously wrong. */ +/* We need to leave BASE_REGS reloads alone, in order to avoid caller_save + lossage. Caller_saves requests a BASE_REGS reload (caller_save_spill_class) + and then later we verify that one was allocated. If PREFERRED_RELOAD_CLASS + says to allocate a LO_REGS spill instead, then this mismatch gives an + abort. Alternatively, this could be fixed by modifying BASE_REG_CLASS + to be LO_REGS instead of BASE_REGS. It is not clear what affect this + change would have. */ +/* ??? This looks even more suspiciously wrong. PREFERRED_RELOAD_CLASS + must always return a strict subset of the input class. Just blindly + returning LO_REGS is safe only if the input class is a superset of LO_REGS, + but there is no check for this. Added another exception for NONARG_LO_REGS + because it is not a superset of LO_REGS. */ +/* ??? We now use NONARG_LO_REGS for caller_save_spill_class, so the + comments about BASE_REGS are now obsolete. */ +#define PREFERRED_RELOAD_CLASS(X,CLASS) \ + ((CLASS) == BASE_REGS || (CLASS) == NONARG_LO_REGS ? (CLASS) \ + : LO_REGS) +/* + ((CONSTANT_P ((X)) && GET_CODE ((X)) != CONST_INT \ + && ! CONSTANT_POOL_ADDRESS_P((X))) ? NO_REGS \ + : (GET_CODE ((X)) == CONST_INT \ + && (unsigned HOST_WIDE_INT) INTVAL ((X)) > 255) ? NO_REGS \ + : LO_REGS) */ + +/* Must leave BASE_REGS and NONARG_LO_REGS reloads alone, see comment + above. */ +#define SECONDARY_RELOAD_CLASS(CLASS,MODE,X) \ + ((CLASS) != LO_REGS && (CLASS) != BASE_REGS && (CLASS) != NONARG_LO_REGS \ + ? ((true_regnum (X) == -1 ? LO_REGS \ + : (true_regnum (X) + HARD_REGNO_NREGS (0, MODE) > 8) ? LO_REGS \ + : NO_REGS)) \ + : NO_REGS) + +#define CLASS_MAX_NREGS(CLASS,MODE) HARD_REGNO_NREGS(0,(MODE)) + +int thumb_shiftable_const (); + +#define CONST_OK_FOR_LETTER_P(VAL,C) \ + ((C) == 'I' ? (unsigned HOST_WIDE_INT) (VAL) < 256 \ + : (C) == 'J' ? (VAL) > -256 && (VAL) <= 0 \ + : (C) == 'K' ? thumb_shiftable_const (VAL) \ + : (C) == 'L' ? (VAL) > -8 && (VAL) < 8 \ + : (C) == 'M' ? ((unsigned HOST_WIDE_INT) (VAL) < 1024 \ + && ((VAL) & 3) == 0) \ + : (C) == 'N' ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ + : (C) == 'O' ? ((VAL) >= -508 && (VAL) <= 508) \ + : 0) + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VAL,C) 0 + +#define EXTRA_CONSTRAINT(X,C) \ + ((C) == 'Q' ? (GET_CODE (X) == MEM \ + && GET_CODE (XEXP (X, 0)) == LABEL_REF) : 0) + +/* Stack Layout and Calling Conventions */ + +#define STACK_GROWS_DOWNWARD 1 + +/* #define FRAME_GROWS_DOWNWARD 1 */ + +/* #define ARGS_GROW_DOWNWARD 1 */ + +#define STARTING_FRAME_OFFSET 0 + +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* Registers that address the stack frame */ + +#define STACK_POINTER_REGNUM 13 /* Defined by the TPCS. */ + +#define FRAME_POINTER_REGNUM 7 /* TPCS defines this as 11 but it does not really mean it. */ + +#define ARG_POINTER_REGNUM 16 /* A fake hard register that is eliminated later on. */ + +#define STATIC_CHAIN_REGNUM 9 + +#define FRAME_POINTER_REQUIRED 0 + +#define ELIMINABLE_REGS \ +{{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ + {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}} + +/* On the Thumb we always want to perform the eliminations as we + actually only have one real register pointing to the stashed + variables: the stack pointer, and we never use the frame pointer. */ +#define CAN_ELIMINATE(FROM,TO) 1 + +/* Note: This macro must match the code in thumb_function_prologue() in thumb.c. */ +#define INITIAL_ELIMINATION_OFFSET(FROM,TO,OFFSET) \ +{ \ + (OFFSET) = 0; \ + if ((FROM) == ARG_POINTER_REGNUM) \ + { \ + int count_regs = 0; \ + int regno; \ + (OFFSET) += get_frame_size (); \ + for (regno = 8; regno < 13; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + count_regs++; \ + if (count_regs) \ + (OFFSET) += 4 * count_regs; \ + count_regs = 0; \ + for (regno = 0; regno < 8; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + count_regs++; \ + if (count_regs || ! leaf_function_p () || far_jump_used_p()) \ + (OFFSET) += 4 * (count_regs + 1); \ + if (TARGET_BACKTRACE) { \ + if ((count_regs & 0xFF) == 0 && (regs_ever_live[3] != 0)) \ + (OFFSET) += 20; \ + else \ + (OFFSET) += 16; } \ + } \ + if ((TO) == STACK_POINTER_REGNUM) \ + (OFFSET) += current_function_outgoing_args_size; \ +} + +/* Passing Arguments on the stack */ + +#define PROMOTE_PROTOTYPES 1 + +#define ACCUMULATE_OUTGOING_ARGS 1 + +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 + +#define FUNCTION_ARG(CUM,MODE,TYPE,NAMED) \ + ((NAMED) ? ((CUM) >= 16 ? 0 : gen_rtx (REG, (MODE), (CUM) / 4)) \ + : 0) + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM,MODE,TYPE,NAMED) \ + (((CUM) < 16 && (CUM) + (((MODE) == BLKmode) \ + ? int_size_in_bytes (TYPE) \ + : HARD_REGNO_NREGS (0, (MODE)) * 4) > 16) \ + ? 4 - (CUM) / 4 : 0) + +#define CUMULATIVE_ARGS int + +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ + ((CUM) = ((FNTYPE) && aggregate_value_p (TREE_TYPE (FNTYPE))) ? 4 : 0) + +#define FUNCTION_ARG_ADVANCE(CUM,MODE,TYPE,NAMED) \ + (CUM) += ((((MODE) == BLKmode) \ + ? int_size_in_bytes (TYPE) \ + : GET_MODE_SIZE (MODE)) + 3) & ~3 + +#define FUNCTION_ARG_REGNO_P(REGNO) \ + ((REGNO) >=0 && (REGNO) <= 3) + +#define FUNCTION_VALUE(VALTYPE,FUNC) gen_rtx (REG, TYPE_MODE (VALTYPE), 0) + +#define LIBCALL_VALUE(MODE) gen_rtx (REG, (MODE), 0) + +#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == 0) + + /* How large values are returned */ +/* A C expression which can inhibit the returning of certain function values + in registers, based on the type of value. */ +#define RETURN_IN_MEMORY(TYPE) thumb_return_in_memory (TYPE) + +/* Define DEFAULT_PCC_STRUCT_RETURN to 1 if all structure and union return + values must be in memory. On the ARM, they need only do so if larger + than a word, or if they contain elements offset from zero in the struct. */ +#define DEFAULT_PCC_STRUCT_RETURN 0 + + +#define STRUCT_VALUE_REGNUM 0 + +#define FUNCTION_PROLOGUE(FILE,SIZE) thumb_function_prologue((FILE),(SIZE)) + +#define FUNCTION_EPILOGUE(FILE,SIZE) thumb_function_epilogue((FILE),(SIZE)) + +/* Implementing the Varargs Macros */ + +#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \ +{ \ + extern int current_function_anonymous_args; \ + current_function_anonymous_args = 1; \ + if ((CUM) < 16) \ + (PRETEND_SIZE) = 16 - (CUM); \ +} + +/* Trampolines for nested functions */ + +/* Output assembler code for a block containing the constant parts of + a trampoline, leaving space for the variable parts. + + On the Thumb we always switch into ARM mode to execute the trampoline. + Why - because it is easier. This code will always be branched to via + a BX instruction and since the compiler magically generates the address + of the function the linker has no opportunity to ensure that the + bottom bit is set. Thus the processor will be in ARM mode when it + reaches this code. So we duplicate the ARM trampoline code and add + a switch into Thumb mode as well. + + On the ARM, (if r8 is the static chain regnum, and remembering that + referencing pc adds an offset of 8) the trampoline looks like: + ldr r8, [pc, #0] + ldr pc, [pc] + .word static chain value + .word function's address + ??? FIXME: When the trampoline returns, r8 will be clobbered. */ +#define TRAMPOLINE_TEMPLATE(FILE) \ +{ \ + fprintf ((FILE), "\t.code 32\n"); \ + fprintf ((FILE), ".Ltrampoline_start:\n"); \ + fprintf ((FILE), "\tldr\t%s, [%spc, #8]\n", \ + reg_names[STATIC_CHAIN_REGNUM], REGISTER_PREFIX); \ + fprintf ((FILE), "\tldr\t%sip, [%spc, #8]\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\torr\t%sip, %sip, #1\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\tbx\t%sip\n", REGISTER_PREFIX); \ + fprintf ((FILE), "\t.word\t0\n"); \ + fprintf ((FILE), "\t.word\t0\n"); \ + fprintf ((FILE), "\t.code 16\n"); \ +} + +/* Length in units of the trampoline for entering a nested function. */ +#define TRAMPOLINE_SIZE 24 + +/* Alignment required for a trampoline in units. */ +#define TRAMPOLINE_ALIGN 4 + +#define INITIALIZE_TRAMPOLINE(ADDR,FNADDR,CHAIN) \ +{ \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((ADDR), 16)), \ + (CHAIN)); \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((ADDR), 20)), \ + (FNADDR)); \ +} + + +/* Implicit Calls to Library Routines */ + +#define TARGET_MEM_FUNCTIONS 1 + +#define OVERRIDE_OPTIONS thumb_override_options () + + +/* Addressing Modes */ + +#define HAVE_POST_INCREMENT 1 + +#define CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (X)) + +#define MAX_REGS_PER_ADDRESS 2 + +#ifdef REG_OK_STRICT + +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) + +#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ + REGNO_MODE_OK_FOR_BASE_P (REGNO (X), MODE) + +#else /* REG_OK_STRICT */ + +#define REG_OK_FOR_BASE_P(X) \ + (REGNO (X) < 8 || REGNO (X) == STACK_POINTER_REGNUM \ + || (X) == arg_pointer_rtx \ + || REGNO (X) >= FIRST_PSEUDO_REGISTER) + +#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ + (REGNO (X) < 8 \ + || REGNO (X) >= FIRST_PSEUDO_REGISTER \ + || (GET_MODE_SIZE (MODE) >= 4 \ + && (REGNO (X) == STACK_POINTER_REGNUM \ + || (X) == arg_pointer_rtx))) + +#define REG_OK_FOR_INDEX_P(X) \ + (REGNO (X) < 8 \ + || REGNO (X) >= FIRST_PSEUDO_REGISTER) + +#endif /* REG_OK_STRICT */ + +/* In a REG+REG address, both must be INDEX registers. */ +#define REG_OK_FOR_INDEXED_BASE_P(X) REG_OK_FOR_INDEX_P(X) + +#define LEGITIMATE_OFFSET(MODE,VAL) \ +(GET_MODE_SIZE (MODE) == 1 ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ + : GET_MODE_SIZE (MODE) == 2 ? ((unsigned HOST_WIDE_INT) (VAL) < 64 \ + && ((VAL) & 1) == 0) \ + : ((VAL) >= 0 && ((VAL) + GET_MODE_SIZE (MODE)) <= 128 \ + && ((VAL) & 3) == 0)) + +/* The AP may be eliminated to either the SP or the FP, so we use the + least common denominator, e.g. SImode, and offsets from 0 to 64. */ + +/* ??? Verify whether the above is the right approach. */ + +/* ??? Also, the FP may be eliminated to the SP, so perhaps that + needs special handling also. */ + +/* ??? Look at how the mips16 port solves this problem. It probably uses + better ways to solve some of these problems. */ + +/* Although it is not incorrect, we don't accept QImode and HImode + addresses based on the frame pointer or arg pointer until the reload pass starts. + This is so that eliminating such addresses into stack based ones + won't produce impossible code. */ +#define GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \ +{ \ + /* ??? Not clear if this is right. Experiment. */ \ + if (GET_MODE_SIZE (MODE) < 4 \ + && ! (reload_in_progress || reload_completed) \ + && (reg_mentioned_p (frame_pointer_rtx, X) \ + || reg_mentioned_p (arg_pointer_rtx, X) \ + || reg_mentioned_p (virtual_incoming_args_rtx, X) \ + || reg_mentioned_p (virtual_outgoing_args_rtx, X) \ + || reg_mentioned_p (virtual_stack_dynamic_rtx, X) \ + || reg_mentioned_p (virtual_stack_vars_rtx, X))) \ + ; \ + /* Accept any base register. SP only in SImode or larger. */ \ + else if (GET_CODE (X) == REG && REG_MODE_OK_FOR_BASE_P(X, MODE)) \ + goto WIN; \ + /* This is PC relative data before MACHINE_DEPENDENT_REORG runs. */ \ + else if (GET_MODE_SIZE (MODE) >= 4 && CONSTANT_P (X) \ + && CONSTANT_POOL_ADDRESS_P (X)) \ + goto WIN; \ + /* This is PC relative data after MACHINE_DEPENDENT_REORG runs. */ \ + else if (GET_MODE_SIZE (MODE) >= 4 && reload_completed \ + && (GET_CODE (X) == LABEL_REF \ + || (GET_CODE (X) == CONST \ + && GET_CODE (XEXP (X, 0)) == PLUS \ + && GET_CODE (XEXP (XEXP (X, 0), 0)) == LABEL_REF \ + && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT))) \ + goto WIN; \ + /* Post-inc indexing only supported for SImode and larger. */ \ + else if (GET_CODE (X) == POST_INC && GET_MODE_SIZE (MODE) >= 4 \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_INDEX_P (XEXP (X, 0))) \ + goto WIN; \ + else if (GET_CODE (X) == PLUS) \ + { \ + /* REG+REG address can be any two index registers. */ \ + /* ??? REG+REG addresses have been completely disabled before \ + reload completes, because we do not have enough available \ + reload registers. We only have 3 guaranteed reload registers \ + (NONARG_LO_REGS - the frame pointer), but we need at least 4 \ + to support REG+REG addresses. We have left them enabled after \ + reload completes, in the hope that reload_cse_regs and related \ + routines will be able to create them after the fact. It is \ + probably possible to support REG+REG addresses with additional \ + reload work, but I do not not have enough time to attempt such \ + a change at this time. */ \ + /* ??? Normally checking the mode here is wrong, since it isn't \ + impossible to use REG+REG with DFmode. However, the movdf \ + pattern requires offsettable addresses, and REG+REG is not \ + offsettable, so it must be rejected somehow. Trying to use \ + 'o' fails, because offsettable_address_p does a QImode check. \ + QImode is not valid for stack addresses, and has a smaller \ + range for non-stack bases, and this causes valid addresses \ + to be rejected. So we just eliminate REG+REG here by checking \ + the mode. */ \ + /* We also disallow FRAME+REG addressing since we know that FRAME \ + will be replaced with STACK, and SP relative addressing only \ + permits SP+OFFSET. */ \ + if (GET_MODE_SIZE (MODE) <= 4 \ + /* ??? See comment above. */ \ + && reload_completed \ + && GET_CODE (XEXP (X, 0)) == REG \ + && GET_CODE (XEXP (X, 1)) == REG \ + && XEXP (X, 0) != frame_pointer_rtx \ + && XEXP (X, 1) != frame_pointer_rtx \ + && XEXP (X, 0) != virtual_stack_vars_rtx \ + && XEXP (X, 1) != virtual_stack_vars_rtx \ + && REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ + && REG_OK_FOR_INDEX_P (XEXP (X, 1))) \ + goto WIN; \ + /* REG+const has 5-7 bit offset for non-SP registers. */ \ + else if (GET_CODE (XEXP (X, 0)) == REG \ + && (REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ + || XEXP (X, 0) == arg_pointer_rtx) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ + goto WIN; \ + /* REG+const has 10 bit offset for SP, but only SImode and \ + larger is supported. */ \ + /* ??? Should probably check for DI/DFmode overflow here \ + just like GO_IF_LEGITIMATE_OFFSET does. */ \ + else if (GET_CODE (XEXP (X, 0)) == REG \ + && REGNO (XEXP (X, 0)) == STACK_POINTER_REGNUM \ + && GET_MODE_SIZE (MODE) >= 4 \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (unsigned HOST_WIDE_INT) INTVAL (XEXP (X, 1)) < 1024 \ + && (INTVAL (XEXP (X, 1)) & 3) == 0) \ + goto WIN; \ + } \ +} + +/* ??? If an HImode FP+large_offset address is converted to an HImode + SP+large_offset address, then reload won't know how to fix it. It sees + only that SP isn't valid for HImode, and so reloads the SP into an index + register, but the resulting address is still invalid because the offset + is too big. We fix it here instead by reloading the entire address. */ +/* We could probably achieve better results by defining PROMOTE_MODE to help + cope with the variances between the Thumb's signed and unsigned byte and + halfword load instructions. */ +#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \ +{ \ + if (GET_CODE (X) == PLUS \ + && GET_MODE_SIZE (MODE) < 4 \ + && GET_CODE (XEXP (X, 0)) == REG \ + && XEXP (X, 0) == stack_pointer_rtx \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && ! LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ + { \ + rtx orig_X = X; \ + X = copy_rtx (X); \ + push_reload (orig_X, NULL_RTX, &X, NULL_PTR, \ + BASE_REG_CLASS, \ + Pmode, VOIDmode, 0, 0, OPNUM, TYPE); \ + goto WIN; \ + } \ +} + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) + +#define LEGITIMATE_CONSTANT_P(X) \ + (GET_CODE (X) == CONST_INT \ + || GET_CODE (X) == CONST_DOUBLE \ + || CONSTANT_ADDRESS_P (X)) + + +/* Condition Code Status */ + +#define NOTICE_UPDATE_CC(EXP,INSN) \ +{ \ + if (get_attr_conds ((INSN)) != CONDS_UNCHANGED) \ + CC_STATUS_INIT; \ +} + + +/* Describing Relative Costs of Operations */ + +#define SLOW_BYTE_ACCESS 0 + +#define SLOW_UNALIGNED_ACCESS 1 + +#define NO_FUNCTION_CSE 1 + +#define NO_RECURSIVE_FUNCTION_CSE 1 + +#define REGISTER_MOVE_COST(FROM,TO) \ + (((FROM) == HI_REGS || (TO) == HI_REGS) ? 4 : 2) + +#define MEMORY_MOVE_COST(M,CLASS,IN) \ + ((GET_MODE_SIZE(M) < 4 ? 8 : 2 * GET_MODE_SIZE(M)) * (CLASS == LO_REGS ? 1 : 2)) + +/* This will allow better space optimization when compiling with -O */ +#define BRANCH_COST (optimize > 1 ? 1 : 0) + +#define RTX_COSTS(X,CODE,OUTER) \ + case MULT: \ + if (GET_CODE (XEXP (X, 1)) == CONST_INT) \ + { \ + int cycles = 0; \ + unsigned HOST_WIDE_INT i = INTVAL (XEXP (X, 1)); \ + while (i) \ + { \ + i >>= 2; \ + cycles++; \ + } \ + return COSTS_N_INSNS (2) + cycles; \ + } \ + return COSTS_N_INSNS (1) + 16; \ + case ASHIFT: case ASHIFTRT: case LSHIFTRT: case ROTATERT: \ + case PLUS: case MINUS: case COMPARE: case NEG: case NOT: \ + return COSTS_N_INSNS (1); \ + case SET: \ + return (COSTS_N_INSNS (1) \ + + 4 * ((GET_CODE (SET_SRC (X)) == MEM) \ + + GET_CODE (SET_DEST (X)) == MEM)) + +#define CONST_COSTS(X,CODE,OUTER) \ + case CONST_INT: \ + if ((OUTER) == SET) \ + { \ + if ((unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ + return 0; \ + if (thumb_shiftable_const (INTVAL (X))) \ + return COSTS_N_INSNS (2); \ + return COSTS_N_INSNS (3); \ + } \ + else if (OUTER == PLUS \ + && INTVAL (X) < 256 && INTVAL (X) > -256) \ + return 0; \ + else if (OUTER == COMPARE \ + && (unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ + return 0; \ + else if (OUTER == ASHIFT || OUTER == ASHIFTRT \ + || OUTER == LSHIFTRT) \ + return 0; \ + return COSTS_N_INSNS (2); \ + case CONST: \ + case CONST_DOUBLE: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return COSTS_N_INSNS(3); + +#define ADDRESS_COST(X) \ + ((GET_CODE (X) == REG \ + || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \ + && GET_CODE (XEXP (X, 1)) == CONST_INT)) \ + ? 1 : 2) + + +/* Position Independent Code */ + +#define PRINT_OPERAND(STREAM,X,CODE) \ + thumb_print_operand((STREAM), (X), (CODE)) + +#define PRINT_OPERAND_ADDRESS(STREAM,X) \ +{ \ + if (GET_CODE ((X)) == REG) \ + fprintf ((STREAM), "[%s]", reg_names[REGNO ((X))]); \ + else if (GET_CODE ((X)) == POST_INC) \ + fprintf ((STREAM), "%s!", reg_names[REGNO (XEXP (X, 0))]); \ + else if (GET_CODE ((X)) == PLUS) \ + { \ + if (GET_CODE (XEXP ((X), 1)) == CONST_INT) \ + fprintf ((STREAM), "[%s, #%d]", \ + reg_names[REGNO (XEXP ((X), 0))], \ + (int) INTVAL (XEXP ((X), 1))); \ + else \ + fprintf ((STREAM), "[%s, %s]", \ + reg_names[REGNO (XEXP ((X), 0))], \ + reg_names[REGNO (XEXP ((X), 1))]); \ + } \ + else \ + output_addr_const ((STREAM), (X)); \ +} + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '@' || ((CODE) == '_')) + +/* Emit a special directive when defining a function name. + This is used by the assembler to assit with interworking. */ +#define ASM_DECLARE_FUNCTION_NAME(file, name, decl) \ + if (! is_called_in_ARM_mode (decl)) \ + fprintf (file, "\t.thumb_func\n") ; \ + else \ + fprintf (file, "\t.code\t32\n") ; \ + ASM_OUTPUT_LABEL (file, name) + +#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ + asm_fprintf ((STREAM), "\tpush {%R%s}\n", reg_names[(REGNO)]) + +#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \ + fprintf ((STREAM), "\tpop {%R%s}\n", reg_names[(REGNO)]) + +#define FINAL_PRESCAN_INSN(INSN,OPVEC,NOPERANDS) \ + final_prescan_insn((INSN)) + +/* Controlling Debugging Information Format */ +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* Specific options for DBX Output */ + +#define DBX_DEBUGGING_INFO 1 + +#define DEFAULT_GDB_EXTENSIONS 1 + + +/* Cross Compilation and Floating Point */ + +#define REAL_ARITHMETIC + + +/* Miscellaneous Parameters */ + +#define PREDICATE_CODES \ + {"thumb_cmp_operand", {SUBREG, REG, CONST_INT}}, + +#define CASE_VECTOR_MODE Pmode + +#define WORD_REGISTER_OPERATIONS + +#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND + +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +#define MOVE_MAX 4 + +#define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) 1 + +#define STORE_FLAG_VALUE 1 + +#define Pmode SImode + +#define FUNCTION_MODE SImode + +#define DOLLARS_IN_IDENTIFIERS 0 + +#define NO_DOLLAR_IN_LABEL 1 + +#define HAVE_ATEXIT + +/* The literal pool needs to reside in the text area due to the + limited PC addressing range: */ +#define MACHINE_DEPENDENT_REORG(INSN) thumb_reorg ((INSN)) + + +/* Options specific to Thumb */ + +/* True if a return instruction can be used in this function. */ +int thumb_trivial_epilogue (); +#define USE_RETURN (reload_completed && thumb_trivial_epilogue ()) + +extern char * thumb_unexpanded_epilogue (); +extern char * output_move_mem_multiple (); +extern char * thumb_load_double_from_address (); +extern char * output_return (); +extern int far_jump_used_p(); +extern int is_called_in_ARM_mode (); + diff --git a/gcc_arm/config/arm/thumb.h.orig b/gcc_arm/config/arm/thumb.h.orig new file mode 100755 index 0000000..9cd719a --- /dev/null +++ b/gcc_arm/config/arm/thumb.h.orig @@ -0,0 +1,1195 @@ +/* Definitions of target machine for GNU compiler, for ARM/Thumb. + Copyright (C) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc. + The basis of this contribution was generated by + Richard Earnshaw, Advanced RISC Machines Ltd + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* ??? The files thumb.{c,h,md} are all seriously lacking comments. */ + +/* ??? The files thumb.{c,h,md} need to be reviewed by an experienced + gcc hacker in their entirety. */ + +/* ??? The files thumb.{c,h,md} and tcoff.h are all separate from the arm + files, which will lead to many maintenance problems. These files are + likely missing all bug fixes made to the arm port since they diverged. */ + +/* ??? Many patterns in the md file accept operands that will require a + reload. These should be eliminated if possible by tightening the + predicates and/or constraints. This will give faster/smaller code. */ + +/* ??? There is no pattern for the TST instuction. Check for other unsupported + instructions. */ + +/* Run Time Target Specifications */ +#ifndef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dthumb -D__thumb -Acpu(arm) -Amachine(arm)" +#endif + +#ifndef CPP_SPEC +#define CPP_SPEC "\ +%{mbig-endian:-D__ARMEB__ -D__THUMBEB__} \ +%{mbe:-D__ARMEB__ -D__THUMBEB__} \ +%{!mbe: %{!mbig-endian:-D__ARMEL__ -D__THUMBEL__}} \ +" +#endif + +#ifndef ASM_SPEC +#define ASM_SPEC "-marm7tdmi %{mthumb-interwork:-mthumb-interwork} %{mbig-endian:-EB}" +#endif +#define LINK_SPEC "%{mbig-endian:-EB} -X" + +#define TARGET_VERSION fputs (" (ARM/THUMB:generic)", stderr); + +/* Nonzero if we should compile with BYTES_BIG_ENDIAN set to 1. */ +#define THUMB_FLAG_BIG_END 0x0001 +#define THUMB_FLAG_BACKTRACE 0x0002 +#define THUMB_FLAG_LEAF_BACKTRACE 0x0004 +#define ARM_FLAG_THUMB 0x1000 /* same as in arm.h */ +#define THUMB_FLAG_CALLEE_SUPER_INTERWORKING 0x40000 +#define THUMB_FLAG_CALLER_SUPER_INTERWORKING 0x80000 + +/* Nonzero if all call instructions should be indirect. */ +#define ARM_FLAG_LONG_CALLS (0x10000) /* same as in arm.h */ + + +/* Run-time compilation parameters selecting different hardware/software subsets. */ +extern int target_flags; +#define TARGET_DEFAULT 0 /* ARM_FLAG_THUMB */ +#define TARGET_BIG_END (target_flags & THUMB_FLAG_BIG_END) +#define TARGET_THUMB_INTERWORK (target_flags & ARM_FLAG_THUMB) +#define TARGET_BACKTRACE (leaf_function_p() \ + ? (target_flags & THUMB_FLAG_LEAF_BACKTRACE) \ + : (target_flags & THUMB_FLAG_BACKTRACE)) + +/* Set if externally visable functions should assume that they + might be called in ARM mode, from a non-thumb aware code. */ +#define TARGET_CALLEE_INTERWORKING \ + (target_flags & THUMB_FLAG_CALLEE_SUPER_INTERWORKING) + +/* Set if calls via function pointers should assume that their + destination is non-Thumb aware. */ +#define TARGET_CALLER_INTERWORKING \ + (target_flags & THUMB_FLAG_CALLER_SUPER_INTERWORKING) + +#define TARGET_LONG_CALLS (target_flags & ARM_FLAG_LONG_CALLS) + +/* SUBTARGET_SWITCHES is used to add flags on a per-config basis. */ +#ifndef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES +#endif + +#define TARGET_SWITCHES \ +{ \ + {"big-endian", THUMB_FLAG_BIG_END}, \ + {"little-endian", -THUMB_FLAG_BIG_END}, \ + {"thumb-interwork", ARM_FLAG_THUMB}, \ + {"no-thumb-interwork", -ARM_FLAG_THUMB}, \ + {"tpcs-frame", THUMB_FLAG_BACKTRACE}, \ + {"no-tpcs-frame", -THUMB_FLAG_BACKTRACE}, \ + {"tpcs-leaf-frame", THUMB_FLAG_LEAF_BACKTRACE}, \ + {"no-tpcs-leaf-frame", -THUMB_FLAG_LEAF_BACKTRACE}, \ + {"callee-super-interworking", THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \ + {"no-callee-super-interworking", -THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \ + {"caller-super-interworking", THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \ + {"no-caller-super-interworking", -THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \ + {"long-calls", ARM_FLAG_LONG_CALLS, \ + "Generate all call instructions as indirect calls"}, \ + {"no-long-calls", -ARM_FLAG_LONG_CALLS, ""}, \ + SUBTARGET_SWITCHES \ + {"", TARGET_DEFAULT} \ +} + +#define TARGET_OPTIONS \ +{ \ + { "structure-size-boundary=", & structure_size_string }, \ +} + +#define REGISTER_PREFIX "" + +#define CAN_DEBUG_WITHOUT_FP 1 + +#define ASM_APP_ON "" +#define ASM_APP_OFF "\t.code\t16\n" + +/* Output a gap. In fact we fill it with nulls. */ +#define ASM_OUTPUT_SKIP(STREAM, NBYTES) \ + fprintf ((STREAM), "\t.space\t%u\n", (NBYTES)) + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ +#define ASM_OUTPUT_ALIGN(STREAM,LOG) \ +{ \ + if ((LOG) > 0) \ + fprintf (STREAM, "\t.align\t%d\n", (LOG)); \ +} + +/* Output a common block */ +#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ + (fprintf ((STREAM), "\t.comm\t"), \ + assemble_name ((STREAM), (NAME)), \ + fprintf((STREAM), ", %d\t%s %d\n", (ROUNDED), (ASM_COMMENT_START), (SIZE))) + +#define ASM_GENERATE_INTERNAL_LABEL(STRING,PREFIX,NUM) \ + sprintf ((STRING), "*%s%s%d", (LOCAL_LABEL_PREFIX), (PREFIX), (NUM)) + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ +#define ASM_OUTPUT_INTERNAL_LABEL(STREAM,PREFIX,NUM) \ + fprintf ((STREAM), "%s%s%d:\n", (LOCAL_LABEL_PREFIX), (PREFIX), (NUM)) + +/* This is how to output a label which precedes a jumptable. Since + instructions are 2 bytes, we need explicit alignment here. */ + +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,JUMPTABLE) \ + do { \ + ASM_OUTPUT_ALIGN (FILE, 2); \ + ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM); \ + } while (0) + +/* This says how to define a local common symbol (ie, not visible to + linker). */ +#define ASM_OUTPUT_LOCAL(STREAM, NAME, SIZE, ROUNDED) \ + (fprintf((STREAM),"\n\t.lcomm\t"), \ + assemble_name((STREAM),(NAME)), \ + fprintf((STREAM),",%u\n",(SIZE))) + +/* Output a reference to a label. */ +#define ASM_OUTPUT_LABELREF(STREAM,NAME) \ + fprintf ((STREAM), "%s%s", user_label_prefix, (NAME)) + +/* This is how to output an assembler line for a numeric constant byte. */ +#define ASM_OUTPUT_BYTE(STREAM,VALUE) \ + fprintf ((STREAM), "\t.byte\t0x%x\n", (VALUE)) + +#define ASM_OUTPUT_INT(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.word\t"); \ + output_addr_const (STREAM, (VALUE)); \ + fprintf (STREAM, "\n"); \ +} + +#define ASM_OUTPUT_SHORT(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.short\t"); \ + output_addr_const (STREAM, (VALUE)); \ + fprintf (STREAM, "\n"); \ +} + +#define ASM_OUTPUT_CHAR(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.byte\t"); \ + output_addr_const (STREAM, (VALUE)); \ + fprintf (STREAM, "\n"); \ +} + +#define ASM_OUTPUT_LONG_DOUBLE(STREAM,VALUE) \ +do { char dstr[30]; \ + long l[3]; \ + REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ + fprintf (STREAM, "\t.long 0x%lx,0x%lx,0x%lx\t%s long double %s\n", \ + l[0], l[1], l[2], ASM_COMMENT_START, dstr); \ + } while (0) + +#define ASM_OUTPUT_DOUBLE(STREAM, VALUE) \ +do { char dstr[30]; \ + long l[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.14g", dstr); \ + fprintf (STREAM, "\t.long 0x%lx, 0x%lx\t%s double %s\n", l[0], \ + l[1], ASM_COMMENT_START, dstr); \ + } while (0) + +#define ASM_OUTPUT_FLOAT(STREAM, VALUE) \ +do { char dstr[30]; \ + long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.7g", dstr); \ + fprintf (STREAM, "\t.word 0x%lx\t%s float %s\n", l, \ + ASM_COMMENT_START, dstr); \ + } while (0); + +/* Define results of standard character escape sequences. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* This is how to output a string. */ +#define ASM_OUTPUT_ASCII(STREAM, STRING, LEN) \ +do { \ + register int i, c, len = (LEN), cur_pos = 17; \ + register unsigned char *string = (unsigned char *)(STRING); \ + fprintf ((STREAM), "\t.ascii\t\""); \ + for (i = 0; i < len; i++) \ + { \ + register int c = string[i]; \ + \ + switch (c) \ + { \ + case '\"': \ + case '\\': \ + putc ('\\', (STREAM)); \ + putc (c, (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_NEWLINE: \ + fputs ("\\n", (STREAM)); \ + if (i+1 < len \ + && (((c = string[i+1]) >= '\040' && c <= '~') \ + || c == TARGET_TAB)) \ + cur_pos = 32767; /* break right here */ \ + else \ + cur_pos += 2; \ + break; \ + \ + case TARGET_TAB: \ + fputs ("\\t", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_FF: \ + fputs ("\\f", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_BS: \ + fputs ("\\b", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_CR: \ + fputs ("\\r", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + default: \ + if (c >= ' ' && c < 0177) \ + { \ + putc (c, (STREAM)); \ + cur_pos++; \ + } \ + else \ + { \ + fprintf ((STREAM), "\\%03o", c); \ + cur_pos += 4; \ + } \ + } \ + \ + if (cur_pos > 72 && i+1 < len) \ + { \ + cur_pos = 17; \ + fprintf ((STREAM), "\"\n\t.ascii\t\""); \ + } \ + } \ + fprintf ((STREAM), "\"\n"); \ +} while (0) + +/* Output and Generation of Labels */ +#define ASM_OUTPUT_LABEL(STREAM,NAME) \ + (assemble_name ((STREAM), (NAME)), \ + fprintf ((STREAM), ":\n")) + +#define ASM_GLOBALIZE_LABEL(STREAM,NAME) \ + (fprintf ((STREAM), "\t.globl\t"), \ + assemble_name ((STREAM), (NAME)), \ + fputc ('\n', (STREAM))) + +/* Construct a private name. */ +#define ASM_FORMAT_PRIVATE_NAME(OUTVAR,NAME,NUMBER) \ + ((OUTVAR) = (char *) alloca (strlen (NAME) + 10), \ + sprintf ((OUTVAR), "%s.%d", (NAME), (NUMBER))) + +/* Switch to the text or data segment. */ +#define TEXT_SECTION_ASM_OP ".text" +#define DATA_SECTION_ASM_OP ".data" +#define BSS_SECTION_ASM_OP ".bss" + +/* The assembler's names for the registers. */ +#ifndef REGISTER_NAMES +#define REGISTER_NAMES \ +{ \ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc", "ap" \ +} +#endif + +#ifndef ADDITIONAL_REGISTER_NAMES +#define ADDITIONAL_REGISTER_NAMES \ +{ \ + {"a1", 0}, \ + {"a2", 1}, \ + {"a3", 2}, \ + {"a4", 3}, \ + {"v1", 4}, \ + {"v2", 5}, \ + {"v3", 6}, \ + {"v4", 7}, \ + {"v5", 8}, \ + {"v6", 9}, \ + {"sb", 9}, \ + {"v7", 10}, \ + {"r10", 10}, /* sl */ \ + {"r11", 11}, /* fp */ \ + {"r12", 12}, /* ip */ \ + {"r13", 13}, /* sp */ \ + {"r14", 14}, /* lr */ \ + {"r15", 15} /* pc */ \ +} +#endif + +/* The assembler's parentheses characters. */ +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + +#ifndef ASM_COMMENT_START +#define ASM_COMMENT_START "@" +#endif + +/* Output an element of a dispatch table. */ +#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM,VALUE) \ + fprintf (STREAM, "\t.word\t%sL%d\n", (LOCAL_LABEL_PREFIX), (VALUE)) + +#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM,BODY,VALUE,REL) \ + fprintf (STREAM, "\tb\t%sL%d\n", (LOCAL_LABEL_PREFIX), (VALUE)) + +/* Storage Layout */ + +/* Define this is most significant bit is lowest numbered in + instructions that operate on numbered bit-fields. */ +#define BITS_BIG_ENDIAN 0 + +/* Define this if most significant byte of a word is the lowest + numbered. */ +#define BYTES_BIG_ENDIAN (TARGET_BIG_END != 0) + +#define WORDS_BIG_ENDIAN (BYTES_BIG_ENDIAN) + +/* LIBGCC2_WORDS_BIG_ENDIAN has to be a constant, so we define this based + on processor pre-defineds when compiling libgcc2.c. */ +#if defined(__THUMBEB__) && !defined(__THUMBEL__) +#define LIBGCC2_WORDS_BIG_ENDIAN 1 +#else +#define LIBGCC2_WORDS_BIG_ENDIAN 0 +#endif + +#define FLOAT_WORDS_BIG_ENDIAN 1 + +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 + +#define UNITS_PER_WORD 4 + +#define POINTER_SIZE 32 + +#define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \ +{ \ + if (GET_MODE_CLASS (MODE) == MODE_INT \ + && GET_MODE_SIZE (MODE) < 4) \ + { \ + (UNSIGNEDP) = 1; \ + (MODE) = SImode; \ + } \ +} + +#define PARM_BOUNDARY 32 +#define STACK_BOUNDARY 32 + +#define FUNCTION_BOUNDARY 32 +#define BIGGEST_ALIGNMENT 32 + +/* Make strings word-aligned so strcpy from constants will be faster. */ +#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ + (TREE_CODE (EXP) == STRING_CST \ + && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) + +#define EMPTY_FIELD_BOUNDARY 32 + +#define STRUCTURE_SIZE_BOUNDARY 32 + +/* Used when parsing command line option -mstructure_size_boundary. */ +extern char * structure_size_string; + +#define STRICT_ALIGNMENT 1 + +#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT + + +/* Layout of Source Language Data Types */ + +#define DEFAULT_SIGNED_CHAR 0 + +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + + +/* Register Usage */ + +/* Note there are 16 hard registers on the Thumb. We invent a 17th register + which is assigned to ARG_POINTER_REGNUM, but this is later removed by + elimination passes in the compiler. */ +#define FIRST_PSEUDO_REGISTER 17 + +/* ??? This is questionable. */ +#define FIXED_REGISTERS \ +{ \ + 0,0,0,0, \ + 0,0,0,0, \ + 0,0,0,1, \ + 0,1,1,1,1 \ +} + +/* ??? This is questionable. */ +#define CALL_USED_REGISTERS \ +{ \ + 1,1,1,1, \ + 0,0,0,0, \ + 0,0,0,1, \ + 1,1,1,1,1 \ +} + +#define HARD_REGNO_NREGS(REGNO,MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ + / UNITS_PER_WORD) + +/* ??? Probably should only allow DImode/DFmode in even numbered registers. */ +#define HARD_REGNO_MODE_OK(REGNO,MODE) ((GET_MODE_SIZE (MODE) > UNITS_PER_WORD) ? (REGNO < 7) : 1) + +#define MODES_TIEABLE_P(MODE1,MODE2) 1 + +/* The NOARG_LO_REGS class is the set of LO_REGS that are not used for passing + arguments to functions. These are the registers that are available for + spilling during reload. The code in reload1.c:init_reload() will detect this + class and place it into 'reload_address_base_reg_class'. */ + +enum reg_class +{ + NO_REGS, + NONARG_LO_REGS, + LO_REGS, + STACK_REG, + BASE_REGS, + HI_REGS, + ALL_REGS, + LIM_REG_CLASSES +}; + +#define GENERAL_REGS ALL_REGS + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +#define REG_CLASS_NAMES \ +{ \ + "NO_REGS", \ + "NONARG_LO_REGS", \ + "LO_REGS", \ + "STACK_REG", \ + "BASE_REGS", \ + "HI_REGS", \ + "ALL_REGS" \ +} + +#define REG_CLASS_CONTENTS \ +{ \ + 0x00000, \ + 0x000f0, \ + 0x000ff, \ + 0x02000, \ + 0x020ff, \ + 0x0ff00, \ + 0x1ffff, \ +} + +#define REGNO_REG_CLASS(REGNO) \ + ((REGNO) == STACK_POINTER_REGNUM ? STACK_REG \ + : (REGNO) < 8 ? ((REGNO) < 4 ? LO_REGS \ + : NONARG_LO_REGS) \ + : HI_REGS) + +#define BASE_REG_CLASS BASE_REGS + +#define MODE_BASE_REG_CLASS(MODE) \ + ((MODE) != QImode && (MODE) != HImode \ + ? BASE_REGS : LO_REGS) + +#define INDEX_REG_CLASS LO_REGS + +/* When SMALL_REGISTER_CLASSES is nonzero, the compiler allows + registers explicitly used in the rtl to be used as spill registers + but prevents the compiler from extending the lifetime of these + registers. */ + +#define SMALL_REGISTER_CLASSES 1 + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'l' ? LO_REGS \ + : (C) == 'h' ? HI_REGS \ + : (C) == 'b' ? BASE_REGS \ + : (C) == 'k' ? STACK_REG \ + : NO_REGS) + +#define REGNO_OK_FOR_BASE_P(REGNO) \ + ((REGNO) < 8 \ + || (REGNO) == STACK_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO] < 8 \ + || (unsigned) reg_renumber[REGNO] == STACK_POINTER_REGNUM) + +#define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) \ + ((REGNO) < 8 \ + || (unsigned) reg_renumber[REGNO] < 8 \ + || (GET_MODE_SIZE (MODE) >= 4 \ + && ((REGNO) == STACK_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO] == STACK_POINTER_REGNUM))) + +#define REGNO_OK_FOR_INDEX_P(REGNO) \ + ((REGNO) < 8 \ + || (unsigned) reg_renumber[REGNO] < 8) + +/* ??? This looks suspiciously wrong. */ +/* We need to leave BASE_REGS reloads alone, in order to avoid caller_save + lossage. Caller_saves requests a BASE_REGS reload (caller_save_spill_class) + and then later we verify that one was allocated. If PREFERRED_RELOAD_CLASS + says to allocate a LO_REGS spill instead, then this mismatch gives an + abort. Alternatively, this could be fixed by modifying BASE_REG_CLASS + to be LO_REGS instead of BASE_REGS. It is not clear what affect this + change would have. */ +/* ??? This looks even more suspiciously wrong. PREFERRED_RELOAD_CLASS + must always return a strict subset of the input class. Just blindly + returning LO_REGS is safe only if the input class is a superset of LO_REGS, + but there is no check for this. Added another exception for NONARG_LO_REGS + because it is not a superset of LO_REGS. */ +/* ??? We now use NONARG_LO_REGS for caller_save_spill_class, so the + comments about BASE_REGS are now obsolete. */ +#define PREFERRED_RELOAD_CLASS(X,CLASS) \ + ((CLASS) == BASE_REGS || (CLASS) == NONARG_LO_REGS ? (CLASS) \ + : LO_REGS) +/* + ((CONSTANT_P ((X)) && GET_CODE ((X)) != CONST_INT \ + && ! CONSTANT_POOL_ADDRESS_P((X))) ? NO_REGS \ + : (GET_CODE ((X)) == CONST_INT \ + && (unsigned HOST_WIDE_INT) INTVAL ((X)) > 255) ? NO_REGS \ + : LO_REGS) */ + +/* Must leave BASE_REGS and NONARG_LO_REGS reloads alone, see comment + above. */ +#define SECONDARY_RELOAD_CLASS(CLASS,MODE,X) \ + ((CLASS) != LO_REGS && (CLASS) != BASE_REGS && (CLASS) != NONARG_LO_REGS \ + ? ((true_regnum (X) == -1 ? LO_REGS \ + : (true_regnum (X) + HARD_REGNO_NREGS (0, MODE) > 8) ? LO_REGS \ + : NO_REGS)) \ + : NO_REGS) + +#define CLASS_MAX_NREGS(CLASS,MODE) HARD_REGNO_NREGS(0,(MODE)) + +int thumb_shiftable_const (); + +#define CONST_OK_FOR_LETTER_P(VAL,C) \ + ((C) == 'I' ? (unsigned HOST_WIDE_INT) (VAL) < 256 \ + : (C) == 'J' ? (VAL) > -256 && (VAL) <= 0 \ + : (C) == 'K' ? thumb_shiftable_const (VAL) \ + : (C) == 'L' ? (VAL) > -8 && (VAL) < 8 \ + : (C) == 'M' ? ((unsigned HOST_WIDE_INT) (VAL) < 1024 \ + && ((VAL) & 3) == 0) \ + : (C) == 'N' ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ + : (C) == 'O' ? ((VAL) >= -508 && (VAL) <= 508) \ + : 0) + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VAL,C) 0 + +#define EXTRA_CONSTRAINT(X,C) \ + ((C) == 'Q' ? (GET_CODE (X) == MEM \ + && GET_CODE (XEXP (X, 0)) == LABEL_REF) : 0) + +/* Stack Layout and Calling Conventions */ + +#define STACK_GROWS_DOWNWARD 1 + +/* #define FRAME_GROWS_DOWNWARD 1 */ + +/* #define ARGS_GROW_DOWNWARD 1 */ + +#define STARTING_FRAME_OFFSET 0 + +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* Registers that address the stack frame */ + +#define STACK_POINTER_REGNUM 13 /* Defined by the TPCS. */ + +#define FRAME_POINTER_REGNUM 7 /* TPCS defines this as 11 but it does not really mean it. */ + +#define ARG_POINTER_REGNUM 16 /* A fake hard register that is eliminated later on. */ + +#define STATIC_CHAIN_REGNUM 9 + +#define FRAME_POINTER_REQUIRED 0 + +#define ELIMINABLE_REGS \ +{{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ + {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}} + +/* On the Thumb we always want to perform the eliminations as we + actually only have one real register pointing to the stashed + variables: the stack pointer, and we never use the frame pointer. */ +#define CAN_ELIMINATE(FROM,TO) 1 + +/* Note: This macro must match the code in thumb_function_prologue() in thumb.c. */ +#define INITIAL_ELIMINATION_OFFSET(FROM,TO,OFFSET) \ +{ \ + (OFFSET) = 0; \ + if ((FROM) == ARG_POINTER_REGNUM) \ + { \ + int count_regs = 0; \ + int regno; \ + (OFFSET) += get_frame_size (); \ + for (regno = 8; regno < 13; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + count_regs++; \ + if (count_regs) \ + (OFFSET) += 4 * count_regs; \ + count_regs = 0; \ + for (regno = 0; regno < 8; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + count_regs++; \ + if (count_regs || ! leaf_function_p () || far_jump_used_p()) \ + (OFFSET) += 4 * (count_regs + 1); \ + if (TARGET_BACKTRACE) { \ + if ((count_regs & 0xFF) == 0 && (regs_ever_live[3] != 0)) \ + (OFFSET) += 20; \ + else \ + (OFFSET) += 16; } \ + } \ + if ((TO) == STACK_POINTER_REGNUM) \ + (OFFSET) += current_function_outgoing_args_size; \ +} + +/* Passing Arguments on the stack */ + +#define PROMOTE_PROTOTYPES 1 + +#define ACCUMULATE_OUTGOING_ARGS 1 + +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 + +#define FUNCTION_ARG(CUM,MODE,TYPE,NAMED) \ + ((NAMED) ? ((CUM) >= 16 ? 0 : gen_rtx (REG, (MODE), (CUM) / 4)) \ + : 0) + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM,MODE,TYPE,NAMED) \ + (((CUM) < 16 && (CUM) + (((MODE) == BLKmode) \ + ? int_size_in_bytes (TYPE) \ + : HARD_REGNO_NREGS (0, (MODE)) * 4) > 16) \ + ? 4 - (CUM) / 4 : 0) + +#define CUMULATIVE_ARGS int + +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ + ((CUM) = ((FNTYPE) && aggregate_value_p (TREE_TYPE (FNTYPE))) ? 4 : 0) + +#define FUNCTION_ARG_ADVANCE(CUM,MODE,TYPE,NAMED) \ + (CUM) += ((((MODE) == BLKmode) \ + ? int_size_in_bytes (TYPE) \ + : GET_MODE_SIZE (MODE)) + 3) & ~3 + +#define FUNCTION_ARG_REGNO_P(REGNO) \ + ((REGNO) >=0 && (REGNO) <= 3) + +#define FUNCTION_VALUE(VALTYPE,FUNC) gen_rtx (REG, TYPE_MODE (VALTYPE), 0) + +#define LIBCALL_VALUE(MODE) gen_rtx (REG, (MODE), 0) + +#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == 0) + + /* How large values are returned */ +/* A C expression which can inhibit the returning of certain function values + in registers, based on the type of value. */ +#define RETURN_IN_MEMORY(TYPE) thumb_return_in_memory (TYPE) + +/* Define DEFAULT_PCC_STRUCT_RETURN to 1 if all structure and union return + values must be in memory. On the ARM, they need only do so if larger + than a word, or if they contain elements offset from zero in the struct. */ +#define DEFAULT_PCC_STRUCT_RETURN 0 + + +#define STRUCT_VALUE_REGNUM 0 + +#define FUNCTION_PROLOGUE(FILE,SIZE) thumb_function_prologue((FILE),(SIZE)) + +#define FUNCTION_EPILOGUE(FILE,SIZE) thumb_function_epilogue((FILE),(SIZE)) + +/* Implementing the Varargs Macros */ + +#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \ +{ \ + extern int current_function_anonymous_args; \ + current_function_anonymous_args = 1; \ + if ((CUM) < 16) \ + (PRETEND_SIZE) = 16 - (CUM); \ +} + +/* Trampolines for nested functions */ + +/* Output assembler code for a block containing the constant parts of + a trampoline, leaving space for the variable parts. + + On the Thumb we always switch into ARM mode to execute the trampoline. + Why - because it is easier. This code will always be branched to via + a BX instruction and since the compiler magically generates the address + of the function the linker has no opportunity to ensure that the + bottom bit is set. Thus the processor will be in ARM mode when it + reaches this code. So we duplicate the ARM trampoline code and add + a switch into Thumb mode as well. + + On the ARM, (if r8 is the static chain regnum, and remembering that + referencing pc adds an offset of 8) the trampoline looks like: + ldr r8, [pc, #0] + ldr pc, [pc] + .word static chain value + .word function's address + ??? FIXME: When the trampoline returns, r8 will be clobbered. */ +#define TRAMPOLINE_TEMPLATE(FILE) \ +{ \ + fprintf ((FILE), "\t.code 32\n"); \ + fprintf ((FILE), ".Ltrampoline_start:\n"); \ + fprintf ((FILE), "\tldr\t%s, [%spc, #8]\n", \ + reg_names[STATIC_CHAIN_REGNUM], REGISTER_PREFIX); \ + fprintf ((FILE), "\tldr\t%sip, [%spc, #8]\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\torr\t%sip, %sip, #1\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\tbx\t%sip\n", REGISTER_PREFIX); \ + fprintf ((FILE), "\t.word\t0\n"); \ + fprintf ((FILE), "\t.word\t0\n"); \ + fprintf ((FILE), "\t.code 16\n"); \ +} + +/* Length in units of the trampoline for entering a nested function. */ +#define TRAMPOLINE_SIZE 24 + +/* Alignment required for a trampoline in units. */ +#define TRAMPOLINE_ALIGN 4 + +#define INITIALIZE_TRAMPOLINE(ADDR,FNADDR,CHAIN) \ +{ \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((ADDR), 16)), \ + (CHAIN)); \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((ADDR), 20)), \ + (FNADDR)); \ +} + + +/* Implicit Calls to Library Routines */ + +#define TARGET_MEM_FUNCTIONS 1 + +#define OVERRIDE_OPTIONS thumb_override_options () + + +/* Addressing Modes */ + +#define HAVE_POST_INCREMENT 1 + +#define CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (X)) + +#define MAX_REGS_PER_ADDRESS 2 + +#ifdef REG_OK_STRICT + +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) + +#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ + REGNO_MODE_OK_FOR_BASE_P (REGNO (X), MODE) + +#else /* REG_OK_STRICT */ + +#define REG_OK_FOR_BASE_P(X) \ + (REGNO (X) < 8 || REGNO (X) == STACK_POINTER_REGNUM \ + || (X) == arg_pointer_rtx \ + || REGNO (X) >= FIRST_PSEUDO_REGISTER) + +#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ + (REGNO (X) < 8 \ + || REGNO (X) >= FIRST_PSEUDO_REGISTER \ + || (GET_MODE_SIZE (MODE) >= 4 \ + && (REGNO (X) == STACK_POINTER_REGNUM \ + || (X) == arg_pointer_rtx))) + +#define REG_OK_FOR_INDEX_P(X) \ + (REGNO (X) < 8 \ + || REGNO (X) >= FIRST_PSEUDO_REGISTER) + +#endif /* REG_OK_STRICT */ + +/* In a REG+REG address, both must be INDEX registers. */ +#define REG_OK_FOR_INDEXED_BASE_P(X) REG_OK_FOR_INDEX_P(X) + +#define LEGITIMATE_OFFSET(MODE,VAL) \ +(GET_MODE_SIZE (MODE) == 1 ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ + : GET_MODE_SIZE (MODE) == 2 ? ((unsigned HOST_WIDE_INT) (VAL) < 64 \ + && ((VAL) & 1) == 0) \ + : ((VAL) >= 0 && ((VAL) + GET_MODE_SIZE (MODE)) <= 128 \ + && ((VAL) & 3) == 0)) + +/* The AP may be eliminated to either the SP or the FP, so we use the + least common denominator, e.g. SImode, and offsets from 0 to 64. */ + +/* ??? Verify whether the above is the right approach. */ + +/* ??? Also, the FP may be eliminated to the SP, so perhaps that + needs special handling also. */ + +/* ??? Look at how the mips16 port solves this problem. It probably uses + better ways to solve some of these problems. */ + +/* Although it is not incorrect, we don't accept QImode and HImode + addresses based on the frame pointer or arg pointer until the reload pass starts. + This is so that eliminating such addresses into stack based ones + won't produce impossible code. */ +#define GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \ +{ \ + /* ??? Not clear if this is right. Experiment. */ \ + if (GET_MODE_SIZE (MODE) < 4 \ + && ! (reload_in_progress || reload_completed) \ + && (reg_mentioned_p (frame_pointer_rtx, X) \ + || reg_mentioned_p (arg_pointer_rtx, X) \ + || reg_mentioned_p (virtual_incoming_args_rtx, X) \ + || reg_mentioned_p (virtual_outgoing_args_rtx, X) \ + || reg_mentioned_p (virtual_stack_dynamic_rtx, X) \ + || reg_mentioned_p (virtual_stack_vars_rtx, X))) \ + ; \ + /* Accept any base register. SP only in SImode or larger. */ \ + else if (GET_CODE (X) == REG && REG_MODE_OK_FOR_BASE_P(X, MODE)) \ + goto WIN; \ + /* This is PC relative data before MACHINE_DEPENDENT_REORG runs. */ \ + else if (GET_MODE_SIZE (MODE) >= 4 && CONSTANT_P (X) \ + && CONSTANT_POOL_ADDRESS_P (X)) \ + goto WIN; \ + /* This is PC relative data after MACHINE_DEPENDENT_REORG runs. */ \ + else if (GET_MODE_SIZE (MODE) >= 4 && reload_completed \ + && (GET_CODE (X) == LABEL_REF \ + || (GET_CODE (X) == CONST \ + && GET_CODE (XEXP (X, 0)) == PLUS \ + && GET_CODE (XEXP (XEXP (X, 0), 0)) == LABEL_REF \ + && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT))) \ + goto WIN; \ + /* Post-inc indexing only supported for SImode and larger. */ \ + else if (GET_CODE (X) == POST_INC && GET_MODE_SIZE (MODE) >= 4 \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_INDEX_P (XEXP (X, 0))) \ + goto WIN; \ + else if (GET_CODE (X) == PLUS) \ + { \ + /* REG+REG address can be any two index registers. */ \ + /* ??? REG+REG addresses have been completely disabled before \ + reload completes, because we do not have enough available \ + reload registers. We only have 3 guaranteed reload registers \ + (NONARG_LO_REGS - the frame pointer), but we need at least 4 \ + to support REG+REG addresses. We have left them enabled after \ + reload completes, in the hope that reload_cse_regs and related \ + routines will be able to create them after the fact. It is \ + probably possible to support REG+REG addresses with additional \ + reload work, but I do not not have enough time to attempt such \ + a change at this time. */ \ + /* ??? Normally checking the mode here is wrong, since it isn't \ + impossible to use REG+REG with DFmode. However, the movdf \ + pattern requires offsettable addresses, and REG+REG is not \ + offsettable, so it must be rejected somehow. Trying to use \ + 'o' fails, because offsettable_address_p does a QImode check. \ + QImode is not valid for stack addresses, and has a smaller \ + range for non-stack bases, and this causes valid addresses \ + to be rejected. So we just eliminate REG+REG here by checking \ + the mode. */ \ + /* We also disallow FRAME+REG addressing since we know that FRAME \ + will be replaced with STACK, and SP relative addressing only \ + permits SP+OFFSET. */ \ + if (GET_MODE_SIZE (MODE) <= 4 \ + /* ??? See comment above. */ \ + && reload_completed \ + && GET_CODE (XEXP (X, 0)) == REG \ + && GET_CODE (XEXP (X, 1)) == REG \ + && XEXP (X, 0) != frame_pointer_rtx \ + && XEXP (X, 1) != frame_pointer_rtx \ + && XEXP (X, 0) != virtual_stack_vars_rtx \ + && XEXP (X, 1) != virtual_stack_vars_rtx \ + && REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ + && REG_OK_FOR_INDEX_P (XEXP (X, 1))) \ + goto WIN; \ + /* REG+const has 5-7 bit offset for non-SP registers. */ \ + else if (GET_CODE (XEXP (X, 0)) == REG \ + && (REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ + || XEXP (X, 0) == arg_pointer_rtx) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ + goto WIN; \ + /* REG+const has 10 bit offset for SP, but only SImode and \ + larger is supported. */ \ + /* ??? Should probably check for DI/DFmode overflow here \ + just like GO_IF_LEGITIMATE_OFFSET does. */ \ + else if (GET_CODE (XEXP (X, 0)) == REG \ + && REGNO (XEXP (X, 0)) == STACK_POINTER_REGNUM \ + && GET_MODE_SIZE (MODE) >= 4 \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (unsigned HOST_WIDE_INT) INTVAL (XEXP (X, 1)) < 1024 \ + && (INTVAL (XEXP (X, 1)) & 3) == 0) \ + goto WIN; \ + } \ +} + +/* ??? If an HImode FP+large_offset address is converted to an HImode + SP+large_offset address, then reload won't know how to fix it. It sees + only that SP isn't valid for HImode, and so reloads the SP into an index + register, but the resulting address is still invalid because the offset + is too big. We fix it here instead by reloading the entire address. */ +/* We could probably achieve better results by defining PROMOTE_MODE to help + cope with the variances between the Thumb's signed and unsigned byte and + halfword load instructions. */ +#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \ +{ \ + if (GET_CODE (X) == PLUS \ + && GET_MODE_SIZE (MODE) < 4 \ + && GET_CODE (XEXP (X, 0)) == REG \ + && XEXP (X, 0) == stack_pointer_rtx \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && ! LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ + { \ + rtx orig_X = X; \ + X = copy_rtx (X); \ + push_reload (orig_X, NULL_RTX, &X, NULL_PTR, \ + BASE_REG_CLASS, \ + Pmode, VOIDmode, 0, 0, OPNUM, TYPE); \ + goto WIN; \ + } \ +} + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) + +#define LEGITIMATE_CONSTANT_P(X) \ + (GET_CODE (X) == CONST_INT \ + || GET_CODE (X) == CONST_DOUBLE \ + || CONSTANT_ADDRESS_P (X)) + + +/* Condition Code Status */ + +#define NOTICE_UPDATE_CC(EXP,INSN) \ +{ \ + if (get_attr_conds ((INSN)) != CONDS_UNCHANGED) \ + CC_STATUS_INIT; \ +} + + +/* Describing Relative Costs of Operations */ + +#define SLOW_BYTE_ACCESS 0 + +#define SLOW_UNALIGNED_ACCESS 1 + +#define NO_FUNCTION_CSE 1 + +#define NO_RECURSIVE_FUNCTION_CSE 1 + +#define REGISTER_MOVE_COST(FROM,TO) \ + (((FROM) == HI_REGS || (TO) == HI_REGS) ? 4 : 2) + +#define MEMORY_MOVE_COST(M,CLASS,IN) \ + ((GET_MODE_SIZE(M) < 4 ? 8 : 2 * GET_MODE_SIZE(M)) * (CLASS == LO_REGS ? 1 : 2)) + +/* This will allow better space optimization when compiling with -O */ +#define BRANCH_COST (optimize > 1 ? 1 : 0) + +#define RTX_COSTS(X,CODE,OUTER) \ + case MULT: \ + if (GET_CODE (XEXP (X, 1)) == CONST_INT) \ + { \ + int cycles = 0; \ + unsigned HOST_WIDE_INT i = INTVAL (XEXP (X, 1)); \ + while (i) \ + { \ + i >>= 2; \ + cycles++; \ + } \ + return COSTS_N_INSNS (2) + cycles; \ + } \ + return COSTS_N_INSNS (1) + 16; \ + case ASHIFT: case ASHIFTRT: case LSHIFTRT: case ROTATERT: \ + case PLUS: case MINUS: case COMPARE: case NEG: case NOT: \ + return COSTS_N_INSNS (1); \ + case SET: \ + return (COSTS_N_INSNS (1) \ + + 4 * ((GET_CODE (SET_SRC (X)) == MEM) \ + + GET_CODE (SET_DEST (X)) == MEM)) + +#define CONST_COSTS(X,CODE,OUTER) \ + case CONST_INT: \ + if ((OUTER) == SET) \ + { \ + if ((unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ + return 0; \ + if (thumb_shiftable_const (INTVAL (X))) \ + return COSTS_N_INSNS (2); \ + return COSTS_N_INSNS (3); \ + } \ + else if (OUTER == PLUS \ + && INTVAL (X) < 256 && INTVAL (X) > -256) \ + return 0; \ + else if (OUTER == COMPARE \ + && (unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ + return 0; \ + else if (OUTER == ASHIFT || OUTER == ASHIFTRT \ + || OUTER == LSHIFTRT) \ + return 0; \ + return COSTS_N_INSNS (2); \ + case CONST: \ + case CONST_DOUBLE: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return COSTS_N_INSNS(3); + +#define ADDRESS_COST(X) \ + ((GET_CODE (X) == REG \ + || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \ + && GET_CODE (XEXP (X, 1)) == CONST_INT)) \ + ? 1 : 2) + + +/* Position Independent Code */ + +#define PRINT_OPERAND(STREAM,X,CODE) \ + thumb_print_operand((STREAM), (X), (CODE)) + +#define PRINT_OPERAND_ADDRESS(STREAM,X) \ +{ \ + if (GET_CODE ((X)) == REG) \ + fprintf ((STREAM), "[%s]", reg_names[REGNO ((X))]); \ + else if (GET_CODE ((X)) == POST_INC) \ + fprintf ((STREAM), "%s!", reg_names[REGNO (XEXP (X, 0))]); \ + else if (GET_CODE ((X)) == PLUS) \ + { \ + if (GET_CODE (XEXP ((X), 1)) == CONST_INT) \ + fprintf ((STREAM), "[%s, #%d]", \ + reg_names[REGNO (XEXP ((X), 0))], \ + (int) INTVAL (XEXP ((X), 1))); \ + else \ + fprintf ((STREAM), "[%s, %s]", \ + reg_names[REGNO (XEXP ((X), 0))], \ + reg_names[REGNO (XEXP ((X), 1))]); \ + } \ + else \ + output_addr_const ((STREAM), (X)); \ +} + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '@' || ((CODE) == '_')) + +/* Emit a special directive when defining a function name. + This is used by the assembler to assit with interworking. */ +#define ASM_DECLARE_FUNCTION_NAME(file, name, decl) \ + if (! is_called_in_ARM_mode (decl)) \ + fprintf (file, "\t.thumb_func\n") ; \ + else \ + fprintf (file, "\t.code\t32\n") ; \ + ASM_OUTPUT_LABEL (file, name) + +#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ + asm_fprintf ((STREAM), "\tpush {%R%s}\n", reg_names[(REGNO)]) + +#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \ + fprintf ((STREAM), "\tpop {%R%s}\n", reg_names[(REGNO)]) + +#define FINAL_PRESCAN_INSN(INSN,OPVEC,NOPERANDS) \ + final_prescan_insn((INSN)) + +/* Controlling Debugging Information Format */ +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* Specific options for DBX Output */ + +#define DBX_DEBUGGING_INFO 1 + +#define DEFAULT_GDB_EXTENSIONS 1 + + +/* Cross Compilation and Floating Point */ + +#define REAL_ARITHMETIC + + +/* Miscellaneous Parameters */ + +#define PREDICATE_CODES \ + {"thumb_cmp_operand", {SUBREG, REG, CONST_INT}}, + +#define CASE_VECTOR_MODE Pmode + +#define WORD_REGISTER_OPERATIONS + +#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND + +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +#define MOVE_MAX 4 + +#define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) 1 + +#define STORE_FLAG_VALUE 1 + +#define Pmode SImode + +#define FUNCTION_MODE SImode + +#define DOLLARS_IN_IDENTIFIERS 0 + +#define NO_DOLLAR_IN_LABEL 1 + +#define HAVE_ATEXIT + +/* The literal pool needs to reside in the text area due to the + limited PC addressing range: */ +#define MACHINE_DEPENDENT_REORG(INSN) thumb_reorg ((INSN)) + + +/* Options specific to Thumb */ + +/* True if a return instruction can be used in this function. */ +int thumb_trivial_epilogue (); +#define USE_RETURN (reload_completed && thumb_trivial_epilogue ()) + +extern char * thumb_unexpanded_epilogue (); +extern char * output_move_mem_multiple (); +extern char * thumb_load_double_from_address (); +extern char * output_return (); +extern int far_jump_used_p(); +extern int is_called_in_ARM_mode (); + diff --git a/gcc_arm/config/arm/thumb.md b/gcc_arm/config/arm/thumb.md new file mode 100755 index 0000000..dd86008 --- /dev/null +++ b/gcc_arm/config/arm/thumb.md @@ -0,0 +1,1174 @@ +;; thumb.md Machine description for ARM/Thumb processors +;; Copyright (C) 1996, 1997, 1998, 2002 Free Software Foundation, Inc. +;; The basis of this contribution was generated by +;; Richard Earnshaw, Advanced RISC Machines Ltd + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;; LENGTH of an instruction is 2 bytes +(define_attr "length" "" (const_int 2)) + +;; CONDS is set to UNCHANGED when an insn does not affect the condition codes +;; Most insns change the condition codes +(define_attr "conds" "changed,unchanged" (const_string "changed")) + +;; FAR_JUMP is "yes" if a BL instruction is used to generate a branch to a +;; distant label. +(define_attr "far_jump" "yes,no" (const_string "no")) + +;; Start with move insns + +(define_expand "movsi" + [(set (match_operand:SI 0 "general_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (SImode, operands[1]); + } +") + +(define_insn "*movsi_insn" + [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l,m,*r,*h") + (match_operand:SI 1 "general_operand" "l,I,J,K,>,l,mi,l,*h,*r"))] + "register_operand (operands[0], SImode) + || register_operand (operands[1], SImode)" + "@ + add\\t%0, %1, #0 + mov\\t%0, %1 + # + # + ldmia\\t%1, {%0} + stmia\\t%0, {%1} + ldr\\t%0, %1 + str\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1" +[(set_attr "length" "2,2,4,4,2,2,2,2,2,2")]) + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "thumb_shiftable_const (INTVAL (operands[1]))" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))] + " +{ + unsigned HOST_WIDE_INT val = INTVAL (operands[1]); + unsigned HOST_WIDE_INT mask = 0xff; + int i; + for (i = 0; i < 25; i++) + if ((val & (mask << i)) == val) + break; + + if (i == 0) + FAIL; + + operands[1] = GEN_INT (val >> i); + operands[2] = GEN_INT (i); +}") + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "INTVAL (operands[1]) < 0 && INTVAL (operands[1]) > -256" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 0) (neg:SI (match_dup 0)))] + " + operands[1] = GEN_INT (- INTVAL (operands[1])); +") + +;;(define_expand "reload_outsi" +;; [(set (match_operand:SI 2 "register_operand" "=&l") +;; (match_operand:SI 1 "register_operand" "h")) +;; (set (match_operand:SI 0 "reload_memory_operand" "=o") +;; (match_dup 2))] +;; "" +;; " +;;/* thumb_reload_out_si (operands); +;; DONE; */ +;;") + +(define_expand "movhi" + [(set (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + " +{ + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (HImode, operands[1]); + + /* ??? We shouldn't really get invalid addresses here, but this can + happen if we are passed a SP (never OK for HImode/QImode) or virtual + register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) + relative address. */ + /* ??? This should perhaps be fixed elsewhere, for instance, in + fixup_stack_1, by checking for other kinds of invalid addresses, + e.g. a bare reference to a virtual register. This may confuse the + alpha though, which must handle this case differently. */ + if (GET_CODE (operands[0]) == MEM + && ! memory_address_p (GET_MODE (operands[0]), + XEXP (operands[0], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[0], 0)); + operands[0] = change_address (operands[0], VOIDmode, temp); + } + if (GET_CODE (operands[1]) == MEM + && ! memory_address_p (GET_MODE (operands[1]), + XEXP (operands[1], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[1], 0)); + operands[1] = change_address (operands[1], VOIDmode, temp); + } + } + /* Handle loading a large integer during reload */ + else if (GET_CODE (operands[1]) == CONST_INT + && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) + { + /* Writing a constant to memory needs a scratch, which should + be handled with SECONDARY_RELOADs. */ + if (GET_CODE (operands[0]) != REG) + abort (); + + operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); + emit_insn (gen_movsi (operands[0], operands[1])); + DONE; + } +}") + +(define_insn "*movhi_insn" + [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") + (match_operand:HI 1 "general_operand" "l,m,l,*h,*r,I"))] + "register_operand (operands[0], HImode) + || register_operand (operands[1], HImode)" + "@ + add\\t%0, %1, #0 + ldrh\\t%0, %1 + strh\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1 + mov\\t%0, %1") + +(define_expand "movqi" + [(set (match_operand:QI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" + " +{ + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (QImode, operands[1]); + + /* ??? We shouldn't really get invalid addresses here, but this can + happen if we are passed a SP (never OK for HImode/QImode) or virtual + register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) + relative address. */ + /* ??? This should perhaps be fixed elsewhere, for instance, in + fixup_stack_1, by checking for other kinds of invalid addresses, + e.g. a bare reference to a virtual register. This may confuse the + alpha though, which must handle this case differently. */ + if (GET_CODE (operands[0]) == MEM + && ! memory_address_p (GET_MODE (operands[0]), + XEXP (operands[0], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[0], 0)); + operands[0] = change_address (operands[0], VOIDmode, temp); + } + if (GET_CODE (operands[1]) == MEM + && ! memory_address_p (GET_MODE (operands[1]), + XEXP (operands[1], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[1], 0)); + operands[1] = change_address (operands[1], VOIDmode, temp); + } + } + /* Handle loading a large integer during reload */ + else if (GET_CODE (operands[1]) == CONST_INT + && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) + { + /* Writing a constant to memory needs a scratch, which should + be handled with SECONDARY_RELOADs. */ + if (GET_CODE (operands[0]) != REG) + abort (); + + operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); + emit_insn (gen_movsi (operands[0], operands[1])); + DONE; + } +}") + +(define_insn "*movqi_insn" + [(set (match_operand:QI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") + (match_operand:QI 1 "general_operand" "l,m,l,*h,*r,I"))] + "register_operand (operands[0], QImode) + || register_operand (operands[1], QImode)" + "@ + add\\t%0, %1, #0 + ldrb\\t%0, %1 + strb\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1 + mov\\t%0, %1") + +(define_expand "movdi" + [(set (match_operand:DI 0 "general_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (DImode, operands[1]); + } +") + +;;; ??? This should have alternatives for constants. +;;; ??? This was originally identical to the movdf_insn pattern. +;;; ??? The 'i' constraint looks funny, but it should always be replaced by +;;; thumb_reorg with a memory reference. +(define_insn "*movdi_insn" + [(set (match_operand:DI 0 "general_operand" "=l,l,l,l,>,l,m,*r") + (match_operand:DI 1 "general_operand" "l,I,J,>,l,mi,l,*r"))] + "register_operand (operands[0], DImode) + || register_operand (operands[1], DImode)" + "* +{ + switch (which_alternative) + { + case 0: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; + return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; + case 1: + return \"mov\\t%Q0, %1\;mov\\t%R0, #0\"; + case 2: + operands[1] = GEN_INT (- INTVAL (operands[1])); + return \"mov\\t%Q0, %1\;neg\\t%Q0, %Q0\;asr\\t%R0, %Q0, #31\"; + case 3: + return \"ldmia\\t%1, {%0, %H0}\"; + case 4: + return \"stmia\\t%0, {%1, %H1}\"; + case 5: + return thumb_load_double_from_address (operands); + case 6: + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); + output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); + return \"\"; + case 7: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; + return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; + } +}"[(set_attr "length" "4,4,6,2,2,6,4,4")]) + +(define_expand "movdf" + [(set (match_operand:DF 0 "general_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (DFmode, operands[1]); + } +") + +;;; ??? This should have alternatives for constants. +;;; ??? This was originally identical to the movdi_insn pattern. +;;; ??? The 'F' constraint looks funny, but it should always be replaced by +;;; thumb_reorg with a memory reference. +(define_insn "*movdf_insn" + [(set (match_operand:DF 0 "general_operand" "=l,l,>,l,m,*r") + (match_operand:DF 1 "general_operand" "l,>,l,mF,l,*r"))] + "register_operand (operands[0], DFmode) + || register_operand (operands[1], DFmode)" + "* + switch (which_alternative) + { + case 0: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; + return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; + case 1: + return \"ldmia\\t%1, {%0, %H0}\"; + case 2: + return \"stmia\\t%0, {%1, %H1}\"; + case 3: + return thumb_load_double_from_address (operands); + case 4: + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); + output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); + return \"\"; + case 5: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; + return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; + } +"[(set_attr "length" "4,2,2,6,4,4")]) + +(define_expand "movsf" + [(set (match_operand:SF 0 "general_operand" "") + (match_operand:SF 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (SFmode, operands[1]); + } +") + +;;; ??? This should have alternatives for constants. +(define_insn "*movsf_insn" + [(set (match_operand:SF 0 "nonimmediate_operand" "=l,l,>,l,m,*r,*h") + (match_operand:SF 1 "general_operand" "l,>,l,mF,l,*h,*r"))] + "register_operand (operands[0], SFmode) + || register_operand (operands[1], SFmode)" + "@ + add\\t%0, %1, #0 + ldmia\\t%1, {%0} + stmia\\t%0, {%1} + ldr\\t%0, %1 + str\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1") + +;; Widening move insns + +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "s_register_operand" "") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (HImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); + emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (16))); + DONE; + } +") + +(define_insn "*zero_extendhisi2_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + "" + "ldrh\\t%0, %1") + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "s_register_operand" "") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (QImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); + emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (24))); + DONE; + } +") + +(define_insn "*zero_extendqisi2_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + "" + "ldrb\\t%0, %1") + +(define_expand "extendhisi2" + [(parallel [(set (match_operand:SI 0 "s_register_operand" "") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" ""))) + (clobber (match_scratch:SI 2 ""))])] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (HImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); + emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (16))); + DONE; + } +") + +(define_insn "*extendhisi2_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))) + (clobber (match_scratch:SI 2 "=&l"))] + "" + "* +{ + rtx ops[4]; + /* This code used to try to use 'V', and fix the address only if it was + offsettable, but this fails for e.g. REG+48 because 48 is outside the + range of QImode offsets, and offsettable_address_p does a QImode + address check. */ + + if (GET_CODE (XEXP (operands[1], 0)) == PLUS) + { + ops[1] = XEXP (XEXP (operands[1], 0), 0); + ops[2] = XEXP (XEXP (operands[1], 0), 1); + } + else + { + ops[1] = XEXP (operands[1], 0); + ops[2] = const0_rtx; + } + if (GET_CODE (ops[2]) == REG) + return \"ldrsh\\t%0, %1\"; + + ops[0] = operands[0]; + ops[3] = operands[2]; + output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops); + return \"\"; +}" +[(set_attr "length" "4")]) + +(define_expand "extendqisi2" + [(set (match_operand:SI 0 "s_register_operand" "") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (QImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); + emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (24))); + DONE; + } +") + +(define_insn "*extendqisi2_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))] + "" + "* +{ + rtx ops[3]; + + if (which_alternative == 0) + return \"ldrsb\\t%0, %1\"; + ops[0] = operands[0]; + if (GET_CODE (XEXP (operands[1], 0)) == PLUS) + { + ops[1] = XEXP (XEXP (operands[1], 0), 0); + ops[2] = XEXP (XEXP (operands[1], 0), 1); + + if (GET_CODE (ops[1]) == REG && GET_CODE (ops[2]) == REG) + output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops); + else if (GET_CODE (ops[1]) == REG) + { + if (REGNO (ops[1]) == REGNO (operands[0])) + output_asm_insn (\"ldrb\\t%0, [%1, %2]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); + else + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + else + { + if (REGNO (ops[2]) == REGNO (operands[0])) + output_asm_insn (\"ldrb\\t%0, [%2, %1]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); + else + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + } + else if (REGNO (operands[0]) == REGNO (XEXP (operands[1], 0))) + { + output_asm_insn (\"ldrb\\t%0, [%0, #0]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); + } + else + { + ops[1] = XEXP (operands[1], 0); + ops[2] = const0_rtx; + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + return \"\"; +}" +[(set_attr "length" "2,6")]) + +;; We don't really have extzv, but defining this using shifts helps +;; to reduce register pressure later on. + +(define_expand "extzv" + [(set (match_dup 4) + (ashift:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "const_int_operand" ""))) + (set (match_operand:SI 0 "register_operand" "") + (lshiftrt:SI (match_dup 4) + (match_operand:SI 3 "const_int_operand" "")))] + "" + " +{ + HOST_WIDE_INT lshift = 32 - INTVAL (operands[2]) - INTVAL (operands[3]); + HOST_WIDE_INT rshift = 32 - INTVAL (operands[2]); + operands[3] = GEN_INT (rshift); + if (lshift == 0) + { + emit_insn (gen_lshrsi3 (operands[0], operands[1], operands[3])); + DONE; + } + operands[2] = GEN_INT (lshift); + operands[4] = gen_reg_rtx (SImode); +} +") + +;; Block-move insns + +(define_expand "movstrqi" + [(match_operand:BLK 0 "general_operand" "") + (match_operand:BLK 1 "general_operand" "") + (match_operand:SI 2 "" "") + (match_operand:SI 3 "const_int_operand" "")] + "" + " + if (INTVAL (operands[3]) != 4 + || GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) > 48) + FAIL; + + thumb_expand_movstrqi (operands); + DONE; +") + +(define_insn "movmem12b" + [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) + (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) + (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (mem:SI (plus:SI (match_dup 0) (const_int 8))) + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_dup 0) (plus:SI (match_dup 0) (const_int 12))) + (set (match_dup 1) (plus:SI (match_dup 1) (const_int 12))) + (clobber (match_scratch:SI 2 "=&l")) + (clobber (match_scratch:SI 3 "=&l")) + (clobber (match_scratch:SI 4 "=&l"))] + "" + "* return output_move_mem_multiple (3, operands);" +[(set_attr "length" "4")]) + +(define_insn "movmem8b" + [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) + (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) + (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_dup 0) (plus:SI (match_dup 0) (const_int 8))) + (set (match_dup 1) (plus:SI (match_dup 1) (const_int 8))) + (clobber (match_scratch:SI 2 "=&l")) + (clobber (match_scratch:SI 3 "=&l"))] + "" + "* return output_move_mem_multiple (2, operands);" +[(set_attr "length" "4")]) + +;; Arithmetic insns + +(define_insn "adddi3" + [(set (match_operand:DI 0 "s_register_operand" "=l") + (plus:DI (match_operand:DI 1 "s_register_operand" "%0") + (match_operand:DI 2 "s_register_operand" "l")))] + "" + "add\\t%Q0, %Q0, %Q2\;adc\\t%R0, %R0, %R2" +[(set_attr "conds" "changed") + (set_attr "length" "8")]) + +;; register group 'k' is a single register group containing only the stack +;; register. Trying to reload it will always fail catastrophically, +;; so never allow those alternatives to match if reloading is needed. +(define_insn "addsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l,l,l,*r,*h,l,!k") + (plus:SI (match_operand:SI 1 "s_register_operand" "%0,0,l,*0,*0,!k,!k") + (match_operand:SI 2 "nonmemory_operand" "I,J,lL,*h,*r,!M,!O")))] + "" + "* + static char *asms[] = +{ + \"add\\t%0, %0, %2\", + \"sub\\t%0, %0, #%n2\", + \"add\\t%0, %1, %2\", + \"add\\t%0, %0, %2\", + \"add\\t%0, %0, %2\", + \"add\\t%0, %1, %2\", + \"add\\t%0, %1, %2\" +}; + if (which_alternative == 2 && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) < 0) + return \"sub\\t%0, %1, #%n2\"; + return asms[which_alternative]; +") + +; reloading and elimination of the frame pointer can sometimes cause this +; optimization to be missed. +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=l") + (match_operand:SI 1 "const_int_operand" "M")) + (set (match_dup 0) + (plus:SI (match_dup 0) (match_operand:SI 2 "register_operand" "k")))] + "REGNO (operands[2]) == STACK_POINTER_REGNUM + && (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) < 1024 + && (INTVAL (operands[1]) & 3) == 0" + "add\\t%0, %2, %1") + +(define_insn "subdi3" + [(set (match_operand:DI 0 "s_register_operand" "=l") + (minus:DI (match_operand:DI 1 "s_register_operand" "0") + (match_operand:DI 2 "s_register_operand" "l")))] + "" + "sub\\t%Q0, %Q0, %Q2\;sbc\\t%R0, %R0, %R2" +[(set_attr "conds" "changed") + (set_attr "length" "8")]) + +(define_insn "subsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (minus:SI (match_operand:SI 1 "s_register_operand" "l") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "sub\\t%0, %1, %2") + +;; We must ensure that one input matches the output, and that the other input +;; does not match the output. Using 0 satisfies the first, and using & +;; satisfies the second. Unfortunately, this fails when operands 1 and 2 +;; are the same, because reload will make operand 0 match operand 1 without +;; realizing that this conflicts with operand 2. We fix this by adding another +;; alternative to match this case, and then `reload' it ourselves. This +;; alternative must come first. +(define_insn "mulsi3" + [(set (match_operand:SI 0 "s_register_operand" "=&l,&l,&l") + (mult:SI (match_operand:SI 1 "s_register_operand" "%l,*h,0") + (match_operand:SI 2 "s_register_operand" "l,l,l")))] + "" + "* +{ + if (which_alternative < 2) + return \"mov\\t%0, %1\;mul\\t%0, %0, %2\"; + else + return \"mul\\t%0, %0, %2\"; +}" + [(set_attr "length" "4,4,2")]) + +(define_insn "negsi2" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (neg:SI (match_operand:SI 1 "s_register_operand" "l")))] + "" + "neg\\t%0, %1") + +;; Logical insns + +(define_expand "andsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (and:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] + "" + " + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = force_reg (SImode, operands[2]); + else + { + int i; + if (((unsigned HOST_WIDE_INT) ~ INTVAL (operands[2])) < 256) + { + operands[2] = force_reg (SImode, GEN_INT (~INTVAL (operands[2]))); + emit_insn (gen_bicsi3 (operands[0], operands[2], operands[1])); + DONE; + } + + for (i = 9; i <= 31; i++) + if ((((HOST_WIDE_INT) 1) << i) - 1 == INTVAL (operands[2])) + { + emit_insn (gen_extzv (operands[0], operands[1], GEN_INT (i), + const0_rtx)); + DONE; + } + else if ((((HOST_WIDE_INT) 1) << i) - 1 == ~ INTVAL (operands[2])) + { + rtx shift = GEN_INT (i); + rtx reg = gen_reg_rtx (SImode); + emit_insn (gen_lshrsi3 (reg, operands[1], shift)); + emit_insn (gen_ashlsi3 (operands[0], reg, shift)); + DONE; + } + + operands[2] = force_reg (SImode, operands[2]); + } +") + +(define_insn "*andsi3_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (and:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "and\\t%0, %0, %2") + +(define_insn "bicsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (and:SI (not:SI (match_operand:SI 1 "s_register_operand" "l")) + (match_operand:SI 2 "s_register_operand" "0")))] + "" + "bic\\t%0, %0, %1") + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (ior:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "orr\\t%0, %0, %2") + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (xor:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "eor\\t%0, %0, %2") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (not:SI (match_operand:SI 1 "s_register_operand" "l")))] + "" + "mvn\\t%0, %1") + +;; Shift and rotation insns + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (ashift:SI (match_operand:SI 1 "s_register_operand" "l,0") + (match_operand:SI 2 "nonmemory_operand" "N,l")))] + "" + "@ + lsl\\t%0, %1, %2 + lsl\\t%0, %0, %2") + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (ashiftrt:SI (match_operand:SI 1 "s_register_operand" "l,0") + (match_operand:SI 2 "nonmemory_operand" "N,l")))] + "" + "@ + asr\\t%0, %1, %2 + asr\\t%0, %0, %2") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (lshiftrt:SI (match_operand:SI 1 "s_register_operand" "l,0") + (match_operand:SI 2 "nonmemory_operand" "N,l")))] + "" + "@ + lsr\\t%0, %1, %2 + lsr\\t%0, %0, %2") + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (rotatert:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "ror\\t%0, %0, %2") + +;; Comparison insns + +(define_expand "cmpsi" + [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "") + (match_operand:SI 1 "nonmemory_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != REG && GET_CODE (operands[1]) != SUBREG) + { + if (GET_CODE (operands[1]) != CONST_INT + || (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) >= 256) + { + if (GET_CODE (operands[1]) != CONST_INT + || INTVAL (operands[1]) < -255 + || INTVAL (operands[1]) > 0) + operands[1] = force_reg (SImode, operands[1]); + else + { + operands[1] = force_reg (SImode, + GEN_INT (- INTVAL (operands[1]))); + emit_insn (gen_cmnsi (operands[0], operands[1])); + DONE; + } + } + } +") + +(define_insn "*cmpsi_insn" + [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "l,*r,*h") + (match_operand:SI 1 "thumb_cmp_operand" "lI,*h,*r")))] + "" + "@ + cmp\\t%0, %1 + cmp\\t%0, %1 + cmp\\t%0, %1") + +(define_insn "tstsi" + [(set (cc0) (match_operand:SI 0 "s_register_operand" "l"))] + "" + "cmp\\t%0, #0") + +(define_insn "cmnsi" + [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "l") + (neg:SI (match_operand:SI 1 "s_register_operand" "l"))))] + "" + "cmn\\t%0, %1") + +;; Jump insns + +(define_insn "jump" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "" + "* + if (get_attr_length (insn) == 2) + return \"b\\t%l0\"; + return \"bl\\t%l0\\t%@ far jump\"; +"[(set (attr "far_jump") + (if_then_else (eq_attr "length" "4") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2048)) + (le (minus (match_dup 0) (pc)) (const_int 2044))) + (const_int 2) + (const_int 4)))]) + + +(define_expand "beq" + [(set (pc) (if_then_else (eq (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bne" + [(set (pc) (if_then_else (ne (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bge" + [(set (pc) (if_then_else (ge (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "ble" + [(set (pc) (if_then_else (le (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bgt" + [(set (pc) (if_then_else (gt (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "blt" + [(set (pc) (if_then_else (lt (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bgeu" + [(set (pc) (if_then_else (geu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bleu" + [(set (pc) (if_then_else (leu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bgtu" + [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bltu" + [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_insn "*cond_branch" + [(set (pc) (if_then_else (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + switch (get_attr_length (insn)) + { + case 2: return \"b%d1\\t%l0\\t%@cond_branch\"; + case 4: return \"b%D1\\t.LCB%=\;b\\t%l0\\t%@long jump\\n.LCB%=:\"; + default: return \"b%D1\\t.LCB%=\;bl\\t%l0\\t%@far jump\\n.LCB%=:\"; + } +"[(set (attr "far_jump") + (if_then_else (eq_attr "length" "6") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 0) (pc)) (const_int -252)) + (le (minus (match_dup 0) (pc)) (const_int 254))) + (const_int 2) + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) + (le (minus (match_dup 0) (pc)) (const_int 2044))) + (const_int 4) + (const_int 6))))]) + +(define_insn "*cond_branch_reversed" + [(set (pc) (if_then_else (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + switch (get_attr_length (insn)) + { + case 2: return \"b%D1\\t%l0\\t%@cond_branch_reversed\"; + case 4: return \"b%d1\\t.LCBR%=\;b\\t%l0\\t%@long jump\\n.LCBR%=:\"; + default: return \"b%d1\\t.LCBR%=\;bl\\t%l0\\t%@far jump\\n.LCBR%=:\"; + } + return \"\"; +"[(set (attr "far_jump") + (if_then_else (eq_attr "length" "6") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 0) (pc)) (const_int -252)) + (le (minus (match_dup 0) (pc)) (const_int 254))) + (const_int 2) + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) + (le (minus (match_dup 0) (pc)) (const_int 2044))) + (const_int 4) + (const_int 6))))]) + +(define_insn "indirect_jump" + [(set (pc) (match_operand:SI 0 "s_register_operand" "l*r"))] + "" + "mov\\tpc, %0") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "s_register_operand" "l*r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "mov\\tpc, %0") + +(define_insn "return" + [(return)] + "USE_RETURN" + "* return output_return ();" +[(set_attr "length" "18")]) + +;; Call insns + +(define_expand "call" + [(call (match_operand:SI 0 "memory_operand" "") + (match_operand 1 "" ""))] + "" + " +{ + if (TARGET_LONG_CALLS && GET_CODE (XEXP (operands[0], 0)) != REG) + XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0)); +}") + +(define_insn "*call_indirect" + [(call (mem:SI (match_operand:SI 0 "s_register_operand" "l*r")) + (match_operand 1 "" ""))] + "! TARGET_CALLER_INTERWORKING" + "bl\\t%__call_via_%0" +[(set_attr "length" "4")]) +;; The non THUMB_INTERWORK, non TARGET_CALLER_INTERWORKING version +;; used to be: "mov\\tlr,pc\;bx\\t%0", but the mov does not set +;; the bottom bit of lr so that a function return (using bx) +;; would switch back into ARM mode... + +(define_insn "*call_indirect_interwork" + [(call (mem:SI (match_operand:SI 0 "s_register_operand" "l*r")) + (match_operand 1 "" ""))] + "TARGET_CALLER_INTERWORKING" + "bl\\t%__interwork_call_via_%0" +[(set_attr "length" "4")]) + +(define_expand "call_value" + [(set (match_operand 0 "" "") + (call (match_operand 1 "memory_operand" "") + (match_operand 2 "" "")))] + "" + " +{ + if (TARGET_LONG_CALLS && GET_CODE (XEXP (operands[1], 0)) != REG) + XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0)); +}") + +(define_insn "*call_value_indirect" + [(set (match_operand 0 "" "=l") + (call (mem:SI (match_operand:SI 1 "s_register_operand" "l*r")) + (match_operand 2 "" "")))] + "! TARGET_CALLER_INTERWORKING" + "bl\\t%__call_via_%1" +[(set_attr "length" "4")]) +;; See comment for call_indirect pattern + +(define_insn "*call_value_indirect_interwork" + [(set (match_operand 0 "" "=l") + (call (mem:SI (match_operand:SI 1 "s_register_operand" "l*r")) + (match_operand 2 "" "")))] + "TARGET_CALLER_INTERWORKING" + "bl\\t%__interwork_call_via_%1" +[(set_attr "length" "4")]) + + +(define_insn "*call_insn" + [(call (mem:SI (match_operand:SI 0 "" "i")) + (match_operand:SI 1 "" ""))] + "! TARGET_LONG_CALLS && GET_CODE (operands[0]) == SYMBOL_REF" + "bl\\t%a0" +[(set_attr "length" "4")]) + +(define_insn "*call_value_insn" + [(set (match_operand 0 "s_register_operand" "=l") + (call (mem:SI (match_operand 1 "" "i")) + (match_operand 2 "" "")))] + "! TARGET_LONG_CALLS && GET_CODE (operands[1]) == SYMBOL_REF" + "bl\\t%a1" +[(set_attr "length" "4")]) + +;; Untyped call not required, since all funcs return in r0 + +;; Miscellaneous patterns + +(define_insn "nop" + [(clobber (const_int 0))] + "" + "mov\\tr8, r8") + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] 0)] + "" + "" + [(set_attr "length" "0")]) + +(define_expand "prologue" + [(const_int 0)] + "" + " + thumb_expand_prologue (); + DONE; +") + +(define_expand "epilogue" + [(unspec_volatile [(const_int 0)] 1)] + "! thumb_trivial_epilogue ()" + " + thumb_expand_epilogue (); +") + +(define_insn "*epilogue_insns" + [(unspec_volatile [(const_int 0)] 1)] + "" + "* + return thumb_unexpanded_epilogue (); +" +[(set_attr "length" "42")]) + +;; Special patterns for dealing with the constant pool + +(define_insn "consttable_4" + [(unspec_volatile [(match_operand 0 "" "")] 2)] + "" + "* +{ + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) + { + case MODE_FLOAT: + { + union real_extract u; + bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); + assemble_real (u.d, GET_MODE (operands[0])); + break; + } + default: + assemble_integer (operands[0], 4, 1); + break; + } + return \"\"; +}" +[(set_attr "length" "4")]) + +(define_insn "consttable_8" + [(unspec_volatile [(match_operand 0 "" "")] 3)] + "" + "* +{ + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) + { + case MODE_FLOAT: + { + union real_extract u; + bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); + assemble_real (u.d, GET_MODE (operands[0])); + break; + } + default: + assemble_integer (operands[0], 8, 1); + break; + } + return \"\"; +}" +[(set_attr "length" "8")]) + +(define_insn "consttable_end" + [(unspec_volatile [(const_int 0)] 4)] + "" + "* + /* Nothing to do (currently). */ + return \"\"; +") + +(define_insn "align_4" + [(unspec_volatile [(const_int 0)] 5)] + "" + "* + assemble_align (32); + return \"\"; +") diff --git a/gcc_arm/config/arm/thumb.md.orig b/gcc_arm/config/arm/thumb.md.orig new file mode 100755 index 0000000..dd86008 --- /dev/null +++ b/gcc_arm/config/arm/thumb.md.orig @@ -0,0 +1,1174 @@ +;; thumb.md Machine description for ARM/Thumb processors +;; Copyright (C) 1996, 1997, 1998, 2002 Free Software Foundation, Inc. +;; The basis of this contribution was generated by +;; Richard Earnshaw, Advanced RISC Machines Ltd + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;; LENGTH of an instruction is 2 bytes +(define_attr "length" "" (const_int 2)) + +;; CONDS is set to UNCHANGED when an insn does not affect the condition codes +;; Most insns change the condition codes +(define_attr "conds" "changed,unchanged" (const_string "changed")) + +;; FAR_JUMP is "yes" if a BL instruction is used to generate a branch to a +;; distant label. +(define_attr "far_jump" "yes,no" (const_string "no")) + +;; Start with move insns + +(define_expand "movsi" + [(set (match_operand:SI 0 "general_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (SImode, operands[1]); + } +") + +(define_insn "*movsi_insn" + [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l,m,*r,*h") + (match_operand:SI 1 "general_operand" "l,I,J,K,>,l,mi,l,*h,*r"))] + "register_operand (operands[0], SImode) + || register_operand (operands[1], SImode)" + "@ + add\\t%0, %1, #0 + mov\\t%0, %1 + # + # + ldmia\\t%1, {%0} + stmia\\t%0, {%1} + ldr\\t%0, %1 + str\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1" +[(set_attr "length" "2,2,4,4,2,2,2,2,2,2")]) + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "thumb_shiftable_const (INTVAL (operands[1]))" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))] + " +{ + unsigned HOST_WIDE_INT val = INTVAL (operands[1]); + unsigned HOST_WIDE_INT mask = 0xff; + int i; + for (i = 0; i < 25; i++) + if ((val & (mask << i)) == val) + break; + + if (i == 0) + FAIL; + + operands[1] = GEN_INT (val >> i); + operands[2] = GEN_INT (i); +}") + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "INTVAL (operands[1]) < 0 && INTVAL (operands[1]) > -256" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 0) (neg:SI (match_dup 0)))] + " + operands[1] = GEN_INT (- INTVAL (operands[1])); +") + +;;(define_expand "reload_outsi" +;; [(set (match_operand:SI 2 "register_operand" "=&l") +;; (match_operand:SI 1 "register_operand" "h")) +;; (set (match_operand:SI 0 "reload_memory_operand" "=o") +;; (match_dup 2))] +;; "" +;; " +;;/* thumb_reload_out_si (operands); +;; DONE; */ +;;") + +(define_expand "movhi" + [(set (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + " +{ + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (HImode, operands[1]); + + /* ??? We shouldn't really get invalid addresses here, but this can + happen if we are passed a SP (never OK for HImode/QImode) or virtual + register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) + relative address. */ + /* ??? This should perhaps be fixed elsewhere, for instance, in + fixup_stack_1, by checking for other kinds of invalid addresses, + e.g. a bare reference to a virtual register. This may confuse the + alpha though, which must handle this case differently. */ + if (GET_CODE (operands[0]) == MEM + && ! memory_address_p (GET_MODE (operands[0]), + XEXP (operands[0], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[0], 0)); + operands[0] = change_address (operands[0], VOIDmode, temp); + } + if (GET_CODE (operands[1]) == MEM + && ! memory_address_p (GET_MODE (operands[1]), + XEXP (operands[1], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[1], 0)); + operands[1] = change_address (operands[1], VOIDmode, temp); + } + } + /* Handle loading a large integer during reload */ + else if (GET_CODE (operands[1]) == CONST_INT + && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) + { + /* Writing a constant to memory needs a scratch, which should + be handled with SECONDARY_RELOADs. */ + if (GET_CODE (operands[0]) != REG) + abort (); + + operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); + emit_insn (gen_movsi (operands[0], operands[1])); + DONE; + } +}") + +(define_insn "*movhi_insn" + [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") + (match_operand:HI 1 "general_operand" "l,m,l,*h,*r,I"))] + "register_operand (operands[0], HImode) + || register_operand (operands[1], HImode)" + "@ + add\\t%0, %1, #0 + ldrh\\t%0, %1 + strh\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1 + mov\\t%0, %1") + +(define_expand "movqi" + [(set (match_operand:QI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" + " +{ + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (QImode, operands[1]); + + /* ??? We shouldn't really get invalid addresses here, but this can + happen if we are passed a SP (never OK for HImode/QImode) or virtual + register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) + relative address. */ + /* ??? This should perhaps be fixed elsewhere, for instance, in + fixup_stack_1, by checking for other kinds of invalid addresses, + e.g. a bare reference to a virtual register. This may confuse the + alpha though, which must handle this case differently. */ + if (GET_CODE (operands[0]) == MEM + && ! memory_address_p (GET_MODE (operands[0]), + XEXP (operands[0], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[0], 0)); + operands[0] = change_address (operands[0], VOIDmode, temp); + } + if (GET_CODE (operands[1]) == MEM + && ! memory_address_p (GET_MODE (operands[1]), + XEXP (operands[1], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[1], 0)); + operands[1] = change_address (operands[1], VOIDmode, temp); + } + } + /* Handle loading a large integer during reload */ + else if (GET_CODE (operands[1]) == CONST_INT + && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) + { + /* Writing a constant to memory needs a scratch, which should + be handled with SECONDARY_RELOADs. */ + if (GET_CODE (operands[0]) != REG) + abort (); + + operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); + emit_insn (gen_movsi (operands[0], operands[1])); + DONE; + } +}") + +(define_insn "*movqi_insn" + [(set (match_operand:QI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") + (match_operand:QI 1 "general_operand" "l,m,l,*h,*r,I"))] + "register_operand (operands[0], QImode) + || register_operand (operands[1], QImode)" + "@ + add\\t%0, %1, #0 + ldrb\\t%0, %1 + strb\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1 + mov\\t%0, %1") + +(define_expand "movdi" + [(set (match_operand:DI 0 "general_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (DImode, operands[1]); + } +") + +;;; ??? This should have alternatives for constants. +;;; ??? This was originally identical to the movdf_insn pattern. +;;; ??? The 'i' constraint looks funny, but it should always be replaced by +;;; thumb_reorg with a memory reference. +(define_insn "*movdi_insn" + [(set (match_operand:DI 0 "general_operand" "=l,l,l,l,>,l,m,*r") + (match_operand:DI 1 "general_operand" "l,I,J,>,l,mi,l,*r"))] + "register_operand (operands[0], DImode) + || register_operand (operands[1], DImode)" + "* +{ + switch (which_alternative) + { + case 0: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; + return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; + case 1: + return \"mov\\t%Q0, %1\;mov\\t%R0, #0\"; + case 2: + operands[1] = GEN_INT (- INTVAL (operands[1])); + return \"mov\\t%Q0, %1\;neg\\t%Q0, %Q0\;asr\\t%R0, %Q0, #31\"; + case 3: + return \"ldmia\\t%1, {%0, %H0}\"; + case 4: + return \"stmia\\t%0, {%1, %H1}\"; + case 5: + return thumb_load_double_from_address (operands); + case 6: + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); + output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); + return \"\"; + case 7: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; + return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; + } +}"[(set_attr "length" "4,4,6,2,2,6,4,4")]) + +(define_expand "movdf" + [(set (match_operand:DF 0 "general_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (DFmode, operands[1]); + } +") + +;;; ??? This should have alternatives for constants. +;;; ??? This was originally identical to the movdi_insn pattern. +;;; ??? The 'F' constraint looks funny, but it should always be replaced by +;;; thumb_reorg with a memory reference. +(define_insn "*movdf_insn" + [(set (match_operand:DF 0 "general_operand" "=l,l,>,l,m,*r") + (match_operand:DF 1 "general_operand" "l,>,l,mF,l,*r"))] + "register_operand (operands[0], DFmode) + || register_operand (operands[1], DFmode)" + "* + switch (which_alternative) + { + case 0: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; + return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; + case 1: + return \"ldmia\\t%1, {%0, %H0}\"; + case 2: + return \"stmia\\t%0, {%1, %H1}\"; + case 3: + return thumb_load_double_from_address (operands); + case 4: + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); + output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); + return \"\"; + case 5: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; + return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; + } +"[(set_attr "length" "4,2,2,6,4,4")]) + +(define_expand "movsf" + [(set (match_operand:SF 0 "general_operand" "") + (match_operand:SF 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (SFmode, operands[1]); + } +") + +;;; ??? This should have alternatives for constants. +(define_insn "*movsf_insn" + [(set (match_operand:SF 0 "nonimmediate_operand" "=l,l,>,l,m,*r,*h") + (match_operand:SF 1 "general_operand" "l,>,l,mF,l,*h,*r"))] + "register_operand (operands[0], SFmode) + || register_operand (operands[1], SFmode)" + "@ + add\\t%0, %1, #0 + ldmia\\t%1, {%0} + stmia\\t%0, {%1} + ldr\\t%0, %1 + str\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1") + +;; Widening move insns + +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "s_register_operand" "") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (HImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); + emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (16))); + DONE; + } +") + +(define_insn "*zero_extendhisi2_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + "" + "ldrh\\t%0, %1") + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "s_register_operand" "") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (QImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); + emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (24))); + DONE; + } +") + +(define_insn "*zero_extendqisi2_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + "" + "ldrb\\t%0, %1") + +(define_expand "extendhisi2" + [(parallel [(set (match_operand:SI 0 "s_register_operand" "") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" ""))) + (clobber (match_scratch:SI 2 ""))])] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (HImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); + emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (16))); + DONE; + } +") + +(define_insn "*extendhisi2_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))) + (clobber (match_scratch:SI 2 "=&l"))] + "" + "* +{ + rtx ops[4]; + /* This code used to try to use 'V', and fix the address only if it was + offsettable, but this fails for e.g. REG+48 because 48 is outside the + range of QImode offsets, and offsettable_address_p does a QImode + address check. */ + + if (GET_CODE (XEXP (operands[1], 0)) == PLUS) + { + ops[1] = XEXP (XEXP (operands[1], 0), 0); + ops[2] = XEXP (XEXP (operands[1], 0), 1); + } + else + { + ops[1] = XEXP (operands[1], 0); + ops[2] = const0_rtx; + } + if (GET_CODE (ops[2]) == REG) + return \"ldrsh\\t%0, %1\"; + + ops[0] = operands[0]; + ops[3] = operands[2]; + output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops); + return \"\"; +}" +[(set_attr "length" "4")]) + +(define_expand "extendqisi2" + [(set (match_operand:SI 0 "s_register_operand" "") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (QImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); + emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (24))); + DONE; + } +") + +(define_insn "*extendqisi2_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))] + "" + "* +{ + rtx ops[3]; + + if (which_alternative == 0) + return \"ldrsb\\t%0, %1\"; + ops[0] = operands[0]; + if (GET_CODE (XEXP (operands[1], 0)) == PLUS) + { + ops[1] = XEXP (XEXP (operands[1], 0), 0); + ops[2] = XEXP (XEXP (operands[1], 0), 1); + + if (GET_CODE (ops[1]) == REG && GET_CODE (ops[2]) == REG) + output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops); + else if (GET_CODE (ops[1]) == REG) + { + if (REGNO (ops[1]) == REGNO (operands[0])) + output_asm_insn (\"ldrb\\t%0, [%1, %2]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); + else + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + else + { + if (REGNO (ops[2]) == REGNO (operands[0])) + output_asm_insn (\"ldrb\\t%0, [%2, %1]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); + else + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + } + else if (REGNO (operands[0]) == REGNO (XEXP (operands[1], 0))) + { + output_asm_insn (\"ldrb\\t%0, [%0, #0]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); + } + else + { + ops[1] = XEXP (operands[1], 0); + ops[2] = const0_rtx; + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + return \"\"; +}" +[(set_attr "length" "2,6")]) + +;; We don't really have extzv, but defining this using shifts helps +;; to reduce register pressure later on. + +(define_expand "extzv" + [(set (match_dup 4) + (ashift:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "const_int_operand" ""))) + (set (match_operand:SI 0 "register_operand" "") + (lshiftrt:SI (match_dup 4) + (match_operand:SI 3 "const_int_operand" "")))] + "" + " +{ + HOST_WIDE_INT lshift = 32 - INTVAL (operands[2]) - INTVAL (operands[3]); + HOST_WIDE_INT rshift = 32 - INTVAL (operands[2]); + operands[3] = GEN_INT (rshift); + if (lshift == 0) + { + emit_insn (gen_lshrsi3 (operands[0], operands[1], operands[3])); + DONE; + } + operands[2] = GEN_INT (lshift); + operands[4] = gen_reg_rtx (SImode); +} +") + +;; Block-move insns + +(define_expand "movstrqi" + [(match_operand:BLK 0 "general_operand" "") + (match_operand:BLK 1 "general_operand" "") + (match_operand:SI 2 "" "") + (match_operand:SI 3 "const_int_operand" "")] + "" + " + if (INTVAL (operands[3]) != 4 + || GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) > 48) + FAIL; + + thumb_expand_movstrqi (operands); + DONE; +") + +(define_insn "movmem12b" + [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) + (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) + (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (mem:SI (plus:SI (match_dup 0) (const_int 8))) + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_dup 0) (plus:SI (match_dup 0) (const_int 12))) + (set (match_dup 1) (plus:SI (match_dup 1) (const_int 12))) + (clobber (match_scratch:SI 2 "=&l")) + (clobber (match_scratch:SI 3 "=&l")) + (clobber (match_scratch:SI 4 "=&l"))] + "" + "* return output_move_mem_multiple (3, operands);" +[(set_attr "length" "4")]) + +(define_insn "movmem8b" + [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) + (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) + (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_dup 0) (plus:SI (match_dup 0) (const_int 8))) + (set (match_dup 1) (plus:SI (match_dup 1) (const_int 8))) + (clobber (match_scratch:SI 2 "=&l")) + (clobber (match_scratch:SI 3 "=&l"))] + "" + "* return output_move_mem_multiple (2, operands);" +[(set_attr "length" "4")]) + +;; Arithmetic insns + +(define_insn "adddi3" + [(set (match_operand:DI 0 "s_register_operand" "=l") + (plus:DI (match_operand:DI 1 "s_register_operand" "%0") + (match_operand:DI 2 "s_register_operand" "l")))] + "" + "add\\t%Q0, %Q0, %Q2\;adc\\t%R0, %R0, %R2" +[(set_attr "conds" "changed") + (set_attr "length" "8")]) + +;; register group 'k' is a single register group containing only the stack +;; register. Trying to reload it will always fail catastrophically, +;; so never allow those alternatives to match if reloading is needed. +(define_insn "addsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l,l,l,*r,*h,l,!k") + (plus:SI (match_operand:SI 1 "s_register_operand" "%0,0,l,*0,*0,!k,!k") + (match_operand:SI 2 "nonmemory_operand" "I,J,lL,*h,*r,!M,!O")))] + "" + "* + static char *asms[] = +{ + \"add\\t%0, %0, %2\", + \"sub\\t%0, %0, #%n2\", + \"add\\t%0, %1, %2\", + \"add\\t%0, %0, %2\", + \"add\\t%0, %0, %2\", + \"add\\t%0, %1, %2\", + \"add\\t%0, %1, %2\" +}; + if (which_alternative == 2 && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) < 0) + return \"sub\\t%0, %1, #%n2\"; + return asms[which_alternative]; +") + +; reloading and elimination of the frame pointer can sometimes cause this +; optimization to be missed. +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=l") + (match_operand:SI 1 "const_int_operand" "M")) + (set (match_dup 0) + (plus:SI (match_dup 0) (match_operand:SI 2 "register_operand" "k")))] + "REGNO (operands[2]) == STACK_POINTER_REGNUM + && (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) < 1024 + && (INTVAL (operands[1]) & 3) == 0" + "add\\t%0, %2, %1") + +(define_insn "subdi3" + [(set (match_operand:DI 0 "s_register_operand" "=l") + (minus:DI (match_operand:DI 1 "s_register_operand" "0") + (match_operand:DI 2 "s_register_operand" "l")))] + "" + "sub\\t%Q0, %Q0, %Q2\;sbc\\t%R0, %R0, %R2" +[(set_attr "conds" "changed") + (set_attr "length" "8")]) + +(define_insn "subsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (minus:SI (match_operand:SI 1 "s_register_operand" "l") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "sub\\t%0, %1, %2") + +;; We must ensure that one input matches the output, and that the other input +;; does not match the output. Using 0 satisfies the first, and using & +;; satisfies the second. Unfortunately, this fails when operands 1 and 2 +;; are the same, because reload will make operand 0 match operand 1 without +;; realizing that this conflicts with operand 2. We fix this by adding another +;; alternative to match this case, and then `reload' it ourselves. This +;; alternative must come first. +(define_insn "mulsi3" + [(set (match_operand:SI 0 "s_register_operand" "=&l,&l,&l") + (mult:SI (match_operand:SI 1 "s_register_operand" "%l,*h,0") + (match_operand:SI 2 "s_register_operand" "l,l,l")))] + "" + "* +{ + if (which_alternative < 2) + return \"mov\\t%0, %1\;mul\\t%0, %0, %2\"; + else + return \"mul\\t%0, %0, %2\"; +}" + [(set_attr "length" "4,4,2")]) + +(define_insn "negsi2" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (neg:SI (match_operand:SI 1 "s_register_operand" "l")))] + "" + "neg\\t%0, %1") + +;; Logical insns + +(define_expand "andsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (and:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] + "" + " + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = force_reg (SImode, operands[2]); + else + { + int i; + if (((unsigned HOST_WIDE_INT) ~ INTVAL (operands[2])) < 256) + { + operands[2] = force_reg (SImode, GEN_INT (~INTVAL (operands[2]))); + emit_insn (gen_bicsi3 (operands[0], operands[2], operands[1])); + DONE; + } + + for (i = 9; i <= 31; i++) + if ((((HOST_WIDE_INT) 1) << i) - 1 == INTVAL (operands[2])) + { + emit_insn (gen_extzv (operands[0], operands[1], GEN_INT (i), + const0_rtx)); + DONE; + } + else if ((((HOST_WIDE_INT) 1) << i) - 1 == ~ INTVAL (operands[2])) + { + rtx shift = GEN_INT (i); + rtx reg = gen_reg_rtx (SImode); + emit_insn (gen_lshrsi3 (reg, operands[1], shift)); + emit_insn (gen_ashlsi3 (operands[0], reg, shift)); + DONE; + } + + operands[2] = force_reg (SImode, operands[2]); + } +") + +(define_insn "*andsi3_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (and:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "and\\t%0, %0, %2") + +(define_insn "bicsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (and:SI (not:SI (match_operand:SI 1 "s_register_operand" "l")) + (match_operand:SI 2 "s_register_operand" "0")))] + "" + "bic\\t%0, %0, %1") + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (ior:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "orr\\t%0, %0, %2") + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (xor:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "eor\\t%0, %0, %2") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (not:SI (match_operand:SI 1 "s_register_operand" "l")))] + "" + "mvn\\t%0, %1") + +;; Shift and rotation insns + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (ashift:SI (match_operand:SI 1 "s_register_operand" "l,0") + (match_operand:SI 2 "nonmemory_operand" "N,l")))] + "" + "@ + lsl\\t%0, %1, %2 + lsl\\t%0, %0, %2") + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (ashiftrt:SI (match_operand:SI 1 "s_register_operand" "l,0") + (match_operand:SI 2 "nonmemory_operand" "N,l")))] + "" + "@ + asr\\t%0, %1, %2 + asr\\t%0, %0, %2") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (lshiftrt:SI (match_operand:SI 1 "s_register_operand" "l,0") + (match_operand:SI 2 "nonmemory_operand" "N,l")))] + "" + "@ + lsr\\t%0, %1, %2 + lsr\\t%0, %0, %2") + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (rotatert:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "ror\\t%0, %0, %2") + +;; Comparison insns + +(define_expand "cmpsi" + [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "") + (match_operand:SI 1 "nonmemory_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != REG && GET_CODE (operands[1]) != SUBREG) + { + if (GET_CODE (operands[1]) != CONST_INT + || (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) >= 256) + { + if (GET_CODE (operands[1]) != CONST_INT + || INTVAL (operands[1]) < -255 + || INTVAL (operands[1]) > 0) + operands[1] = force_reg (SImode, operands[1]); + else + { + operands[1] = force_reg (SImode, + GEN_INT (- INTVAL (operands[1]))); + emit_insn (gen_cmnsi (operands[0], operands[1])); + DONE; + } + } + } +") + +(define_insn "*cmpsi_insn" + [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "l,*r,*h") + (match_operand:SI 1 "thumb_cmp_operand" "lI,*h,*r")))] + "" + "@ + cmp\\t%0, %1 + cmp\\t%0, %1 + cmp\\t%0, %1") + +(define_insn "tstsi" + [(set (cc0) (match_operand:SI 0 "s_register_operand" "l"))] + "" + "cmp\\t%0, #0") + +(define_insn "cmnsi" + [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "l") + (neg:SI (match_operand:SI 1 "s_register_operand" "l"))))] + "" + "cmn\\t%0, %1") + +;; Jump insns + +(define_insn "jump" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "" + "* + if (get_attr_length (insn) == 2) + return \"b\\t%l0\"; + return \"bl\\t%l0\\t%@ far jump\"; +"[(set (attr "far_jump") + (if_then_else (eq_attr "length" "4") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2048)) + (le (minus (match_dup 0) (pc)) (const_int 2044))) + (const_int 2) + (const_int 4)))]) + + +(define_expand "beq" + [(set (pc) (if_then_else (eq (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bne" + [(set (pc) (if_then_else (ne (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bge" + [(set (pc) (if_then_else (ge (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "ble" + [(set (pc) (if_then_else (le (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bgt" + [(set (pc) (if_then_else (gt (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "blt" + [(set (pc) (if_then_else (lt (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bgeu" + [(set (pc) (if_then_else (geu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bleu" + [(set (pc) (if_then_else (leu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bgtu" + [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bltu" + [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_insn "*cond_branch" + [(set (pc) (if_then_else (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + switch (get_attr_length (insn)) + { + case 2: return \"b%d1\\t%l0\\t%@cond_branch\"; + case 4: return \"b%D1\\t.LCB%=\;b\\t%l0\\t%@long jump\\n.LCB%=:\"; + default: return \"b%D1\\t.LCB%=\;bl\\t%l0\\t%@far jump\\n.LCB%=:\"; + } +"[(set (attr "far_jump") + (if_then_else (eq_attr "length" "6") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 0) (pc)) (const_int -252)) + (le (minus (match_dup 0) (pc)) (const_int 254))) + (const_int 2) + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) + (le (minus (match_dup 0) (pc)) (const_int 2044))) + (const_int 4) + (const_int 6))))]) + +(define_insn "*cond_branch_reversed" + [(set (pc) (if_then_else (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + switch (get_attr_length (insn)) + { + case 2: return \"b%D1\\t%l0\\t%@cond_branch_reversed\"; + case 4: return \"b%d1\\t.LCBR%=\;b\\t%l0\\t%@long jump\\n.LCBR%=:\"; + default: return \"b%d1\\t.LCBR%=\;bl\\t%l0\\t%@far jump\\n.LCBR%=:\"; + } + return \"\"; +"[(set (attr "far_jump") + (if_then_else (eq_attr "length" "6") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 0) (pc)) (const_int -252)) + (le (minus (match_dup 0) (pc)) (const_int 254))) + (const_int 2) + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) + (le (minus (match_dup 0) (pc)) (const_int 2044))) + (const_int 4) + (const_int 6))))]) + +(define_insn "indirect_jump" + [(set (pc) (match_operand:SI 0 "s_register_operand" "l*r"))] + "" + "mov\\tpc, %0") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "s_register_operand" "l*r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "mov\\tpc, %0") + +(define_insn "return" + [(return)] + "USE_RETURN" + "* return output_return ();" +[(set_attr "length" "18")]) + +;; Call insns + +(define_expand "call" + [(call (match_operand:SI 0 "memory_operand" "") + (match_operand 1 "" ""))] + "" + " +{ + if (TARGET_LONG_CALLS && GET_CODE (XEXP (operands[0], 0)) != REG) + XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0)); +}") + +(define_insn "*call_indirect" + [(call (mem:SI (match_operand:SI 0 "s_register_operand" "l*r")) + (match_operand 1 "" ""))] + "! TARGET_CALLER_INTERWORKING" + "bl\\t%__call_via_%0" +[(set_attr "length" "4")]) +;; The non THUMB_INTERWORK, non TARGET_CALLER_INTERWORKING version +;; used to be: "mov\\tlr,pc\;bx\\t%0", but the mov does not set +;; the bottom bit of lr so that a function return (using bx) +;; would switch back into ARM mode... + +(define_insn "*call_indirect_interwork" + [(call (mem:SI (match_operand:SI 0 "s_register_operand" "l*r")) + (match_operand 1 "" ""))] + "TARGET_CALLER_INTERWORKING" + "bl\\t%__interwork_call_via_%0" +[(set_attr "length" "4")]) + +(define_expand "call_value" + [(set (match_operand 0 "" "") + (call (match_operand 1 "memory_operand" "") + (match_operand 2 "" "")))] + "" + " +{ + if (TARGET_LONG_CALLS && GET_CODE (XEXP (operands[1], 0)) != REG) + XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0)); +}") + +(define_insn "*call_value_indirect" + [(set (match_operand 0 "" "=l") + (call (mem:SI (match_operand:SI 1 "s_register_operand" "l*r")) + (match_operand 2 "" "")))] + "! TARGET_CALLER_INTERWORKING" + "bl\\t%__call_via_%1" +[(set_attr "length" "4")]) +;; See comment for call_indirect pattern + +(define_insn "*call_value_indirect_interwork" + [(set (match_operand 0 "" "=l") + (call (mem:SI (match_operand:SI 1 "s_register_operand" "l*r")) + (match_operand 2 "" "")))] + "TARGET_CALLER_INTERWORKING" + "bl\\t%__interwork_call_via_%1" +[(set_attr "length" "4")]) + + +(define_insn "*call_insn" + [(call (mem:SI (match_operand:SI 0 "" "i")) + (match_operand:SI 1 "" ""))] + "! TARGET_LONG_CALLS && GET_CODE (operands[0]) == SYMBOL_REF" + "bl\\t%a0" +[(set_attr "length" "4")]) + +(define_insn "*call_value_insn" + [(set (match_operand 0 "s_register_operand" "=l") + (call (mem:SI (match_operand 1 "" "i")) + (match_operand 2 "" "")))] + "! TARGET_LONG_CALLS && GET_CODE (operands[1]) == SYMBOL_REF" + "bl\\t%a1" +[(set_attr "length" "4")]) + +;; Untyped call not required, since all funcs return in r0 + +;; Miscellaneous patterns + +(define_insn "nop" + [(clobber (const_int 0))] + "" + "mov\\tr8, r8") + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] 0)] + "" + "" + [(set_attr "length" "0")]) + +(define_expand "prologue" + [(const_int 0)] + "" + " + thumb_expand_prologue (); + DONE; +") + +(define_expand "epilogue" + [(unspec_volatile [(const_int 0)] 1)] + "! thumb_trivial_epilogue ()" + " + thumb_expand_epilogue (); +") + +(define_insn "*epilogue_insns" + [(unspec_volatile [(const_int 0)] 1)] + "" + "* + return thumb_unexpanded_epilogue (); +" +[(set_attr "length" "42")]) + +;; Special patterns for dealing with the constant pool + +(define_insn "consttable_4" + [(unspec_volatile [(match_operand 0 "" "")] 2)] + "" + "* +{ + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) + { + case MODE_FLOAT: + { + union real_extract u; + bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); + assemble_real (u.d, GET_MODE (operands[0])); + break; + } + default: + assemble_integer (operands[0], 4, 1); + break; + } + return \"\"; +}" +[(set_attr "length" "4")]) + +(define_insn "consttable_8" + [(unspec_volatile [(match_operand 0 "" "")] 3)] + "" + "* +{ + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) + { + case MODE_FLOAT: + { + union real_extract u; + bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); + assemble_real (u.d, GET_MODE (operands[0])); + break; + } + default: + assemble_integer (operands[0], 8, 1); + break; + } + return \"\"; +}" +[(set_attr "length" "8")]) + +(define_insn "consttable_end" + [(unspec_volatile [(const_int 0)] 4)] + "" + "* + /* Nothing to do (currently). */ + return \"\"; +") + +(define_insn "align_4" + [(unspec_volatile [(const_int 0)] 5)] + "" + "* + assemble_align (32); + return \"\"; +") diff --git a/gcc_arm/config/arm/thumb.md.rej b/gcc_arm/config/arm/thumb.md.rej new file mode 100755 index 0000000..745d220 --- /dev/null +++ b/gcc_arm/config/arm/thumb.md.rej @@ -0,0 +1,168 @@ +*************** +*** 1002,1019 **** + ;; Call insns + + (define_expand "call" +- [(call (match_operand:SI 0 "memory_operand" "") +- (match_operand 1 "" ""))] + "" + " + { +- if (TARGET_LONG_CALLS && GET_CODE (XEXP (operands[0], 0)) != REG) + XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0)); + }") + + (define_insn "*call_indirect" +- [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) +- (match_operand 1 "" ""))] + "! TARGET_CALLER_INTERWORKING" + "bl\\t%__call_via_%0" + [(set_attr "length" "4")]) +--- 1002,1024 ---- + ;; Call insns + + (define_expand "call" ++ [(parallel ++ [(call (match_operand:SI 0 "memory_operand" "") ++ (match_operand 1 "" "")) ++ (use (match_operand 2 "" ""))])] + "" + " + { ++ if (GET_CODE (XEXP (operands[0], 0)) != REG ++ && arm_is_longcall_p (operands[0], INTVAL (operands[2]), 0)) + XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0)); + }") + + (define_insn "*call_indirect" ++ [(parallel ++ [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) ++ (match_operand 1 "" "")) ++ (use (match_operand 2 "" ""))])] + "! TARGET_CALLER_INTERWORKING" + "bl\\t%__call_via_%0" + [(set_attr "length" "4")]) +*************** +*** 1023,1075 **** + ;; would switch back into ARM mode... + + (define_insn "*call_indirect_interwork" +- [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) +- (match_operand 1 "" ""))] + "TARGET_CALLER_INTERWORKING" + "bl\\t%__interwork_call_via_%0" + [(set_attr "length" "4")]) + + (define_expand "call_value" +- [(set (match_operand 0 "" "") +- (call (match_operand 1 "memory_operand" "") +- (match_operand 2 "" "")))] + "" + " + { +- if (TARGET_LONG_CALLS && GET_CODE (XEXP (operands[1], 0)) != REG) + XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0)); + }") + + (define_insn "*call_value_indirect" +- [(set (match_operand 0 "" "=l") +- (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) +- (match_operand 2 "" "")))] + "! TARGET_CALLER_INTERWORKING" + "bl\\t%__call_via_%1" + [(set_attr "length" "4")]) + ;; See comment for call_indirect pattern + + (define_insn "*call_value_indirect_interwork" +- [(set (match_operand 0 "" "=l") +- (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) +- (match_operand 2 "" "")))] + "TARGET_CALLER_INTERWORKING" + "bl\\t%__interwork_call_via_%1" + [(set_attr "length" "4")]) + + + (define_insn "*call_insn" +- [(call (mem:SI (match_operand:SI 0 "" "i")) +- (match_operand:SI 1 "" ""))] +- "! TARGET_LONG_CALLS && GET_CODE (operands[0]) == SYMBOL_REF" + "bl\\t%a0" + [(set_attr "length" "4")]) + + (define_insn "*call_value_insn" +- [(set (match_operand 0 "register_operand" "=l") + (call (mem:SI (match_operand 1 "" "i")) +- (match_operand 2 "" "")))] +- "! TARGET_LONG_CALLS && GET_CODE (operands[1]) == SYMBOL_REF" + "bl\\t%a1" + [(set_attr "length" "4")]) + +--- 1028,1095 ---- + ;; would switch back into ARM mode... + + (define_insn "*call_indirect_interwork" ++ [(parallel ++ [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) ++ (match_operand 1 "" "")) ++ (use (match_operand 2 "" ""))])] + "TARGET_CALLER_INTERWORKING" + "bl\\t%__interwork_call_via_%0" + [(set_attr "length" "4")]) + + (define_expand "call_value" ++ [(parallel ++ [(set (match_operand 0 "" "") ++ (call (match_operand 1 "memory_operand" "") ++ (match_operand 2 "" ""))) ++ (use (match_operand 3 "" ""))])] + "" + " + { ++ if (GET_CODE (XEXP (operands[1], 0)) != REG ++ && arm_is_longcall_p (operands[1], INTVAL (operands[3]), 0)) + XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0)); + }") + + (define_insn "*call_value_indirect" ++ [(parallel ++ [(set (match_operand 0 "" "=l") ++ (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) ++ (match_operand 2 "" ""))) ++ (use (match_operand 3 "" ""))])] + "! TARGET_CALLER_INTERWORKING" + "bl\\t%__call_via_%1" + [(set_attr "length" "4")]) + ;; See comment for call_indirect pattern + + (define_insn "*call_value_indirect_interwork" ++ [(parallel ++ [(set (match_operand 0 "" "=l") ++ (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) ++ (match_operand 2 "" ""))) ++ (use (match_operand 3 "" ""))])] + "TARGET_CALLER_INTERWORKING" + "bl\\t%__interwork_call_via_%1" + [(set_attr "length" "4")]) + + + (define_insn "*call_insn" ++ [(parallel ++ [(call (mem:SI (match_operand:SI 0 "" "i")) ++ (match_operand:SI 1 "" "")) ++ (use (match_operand 2 "" ""))])] ++ "GET_CODE (operands[0]) == SYMBOL_REF ++ && ! arm_is_longcall_p (operands[0], INTVAL (operands[2]), 1)" + "bl\\t%a0" + [(set_attr "length" "4")]) + + (define_insn "*call_value_insn" ++ [(parallel ++ [(set (match_operand 0 "register_operand" "=l") + (call (mem:SI (match_operand 1 "" "i")) ++ (match_operand 2 "" ""))) ++ (use (match_operand 3 "" ""))])] ++ "GET_CODE(operands[1]) == SYMBOL_REF ++ && ! arm_is_longcall_p (operands[1], INTVAL (operands[3]), 1)" + "bl\\t%a1" + [(set_attr "length" "4")]) + diff --git a/gcc_arm/config/arm/thumb_000513.h b/gcc_arm/config/arm/thumb_000513.h new file mode 100755 index 0000000..a5c25b9 --- /dev/null +++ b/gcc_arm/config/arm/thumb_000513.h @@ -0,0 +1,1187 @@ +/* Definitions of target machine for GNU compiler, for ARM/Thumb. + Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. + The basis of this contribution was generated by + Richard Earnshaw, Advanced RISC Machines Ltd + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* ??? The files thumb.{c,h,md} are all seriously lacking comments. */ + +/* ??? The files thumb.{c,h,md} need to be reviewed by an experienced + gcc hacker in their entirety. */ + +/* ??? The files thumb.{c,h,md} and tcoff.h are all separate from the arm + files, which will lead to many maintenance problems. These files are + likely missing all bug fixes made to the arm port since they diverged. */ + +/* ??? Many patterns in the md file accept operands that will require a + reload. These should be eliminated if possible by tightening the + predicates and/or constraints. This will give faster/smaller code. */ + +/* ??? There is no pattern for the TST instuction. Check for other unsupported + instructions. */ + +/* Run Time Target Specifications */ +#ifndef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dthumb -D__thumb -Acpu(arm) -Amachine(arm)" +#endif + +#ifndef CPP_SPEC +#define CPP_SPEC "\ +%{mbig-endian:-D__ARMEB__ -D__THUMBEB__} \ +%{mbe:-D__ARMEB__ -D__THUMBEB__} \ +%{!mbe: %{!mbig-endian:-D__ARMEL__ -D__THUMBEL__}} \ +" +#endif + +#ifndef ASM_SPEC +#define ASM_SPEC "-marm7tdmi %{mthumb-interwork:-mthumb-interwork} %{mbig-endian:-EB}" +#endif +#define LINK_SPEC "%{mbig-endian:-EB} -X" + +#define TARGET_VERSION fputs (" (ARM/THUMB:generic)", stderr); + +/* Nonzero if we should compile with BYTES_BIG_ENDIAN set to 1. */ +#define THUMB_FLAG_BIG_END 0x0001 +#define THUMB_FLAG_BACKTRACE 0x0002 +#define THUMB_FLAG_LEAF_BACKTRACE 0x0004 +#define ARM_FLAG_THUMB 0x1000 /* same as in arm.h */ +#define THUMB_FLAG_CALLEE_SUPER_INTERWORKING 0x40000 +#define THUMB_FLAG_CALLER_SUPER_INTERWORKING 0x80000 + + +/* Run-time compilation parameters selecting different hardware/software subsets. */ +extern int target_flags; +#define TARGET_DEFAULT 0 /* ARM_FLAG_THUMB */ +#define TARGET_BIG_END (target_flags & THUMB_FLAG_BIG_END) +#define TARGET_THUMB_INTERWORK (target_flags & ARM_FLAG_THUMB) +#define TARGET_BACKTRACE (leaf_function_p() \ + ? (target_flags & THUMB_FLAG_LEAF_BACKTRACE) \ + : (target_flags & THUMB_FLAG_BACKTRACE)) + +/* Set if externally visable functions should assume that they + might be called in ARM mode, from a non-thumb aware code. */ +#define TARGET_CALLEE_INTERWORKING \ + (target_flags & THUMB_FLAG_CALLEE_SUPER_INTERWORKING) + +/* Set if calls via function pointers should assume that their + destination is non-Thumb aware. */ +#define TARGET_CALLER_INTERWORKING \ + (target_flags & THUMB_FLAG_CALLER_SUPER_INTERWORKING) + +/* SUBTARGET_SWITCHES is used to add flags on a per-config basis. */ +#ifndef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES +#endif + +#define TARGET_SWITCHES \ +{ \ + {"big-endian", THUMB_FLAG_BIG_END}, \ + {"little-endian", -THUMB_FLAG_BIG_END}, \ + {"thumb-interwork", ARM_FLAG_THUMB}, \ + {"no-thumb-interwork", -ARM_FLAG_THUMB}, \ + {"tpcs-frame", THUMB_FLAG_BACKTRACE}, \ + {"no-tpcs-frame", -THUMB_FLAG_BACKTRACE}, \ + {"tpcs-leaf-frame", THUMB_FLAG_LEAF_BACKTRACE}, \ + {"no-tpcs-leaf-frame", -THUMB_FLAG_LEAF_BACKTRACE}, \ + {"callee-super-interworking", THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \ + {"no-callee-super-interworking", -THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \ + {"caller-super-interworking", THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \ + {"no-caller-super-interworking", -THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \ + SUBTARGET_SWITCHES \ + {"", TARGET_DEFAULT} \ +} + +#define TARGET_OPTIONS \ +{ \ + { "structure-size-boundary=", & structure_size_string }, \ +} + +#define REGISTER_PREFIX "" + +#define CAN_DEBUG_WITHOUT_FP 1 + +#define ASM_APP_ON "" +#define ASM_APP_OFF "\t.code\t16\n" + +/* Output a gap. In fact we fill it with nulls. */ +#define ASM_OUTPUT_SKIP(STREAM, NBYTES) \ + fprintf ((STREAM), "\t.space\t%u\n", (NBYTES)) + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ +#define ASM_OUTPUT_ALIGN(STREAM,LOG) \ +{ \ + if ((LOG) > 0) \ + fprintf (STREAM, "\t.align\t%d\n", (LOG)); \ +} + +/* Output a common block */ +#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ + (fprintf ((STREAM), "\t.comm\t"), \ + assemble_name ((STREAM), (NAME)), \ + fprintf((STREAM), ", %d\t%s %d\n", (ROUNDED), (ASM_COMMENT_START), (SIZE))) + +#define ASM_GENERATE_INTERNAL_LABEL(STRING,PREFIX,NUM) \ + sprintf ((STRING), "*%s%s%d", (LOCAL_LABEL_PREFIX), (PREFIX), (NUM)) + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ +#define ASM_OUTPUT_INTERNAL_LABEL(STREAM,PREFIX,NUM) \ + fprintf ((STREAM), "%s%s%d:\n", (LOCAL_LABEL_PREFIX), (PREFIX), (NUM)) + +/* This is how to output a label which precedes a jumptable. Since + instructions are 2 bytes, we need explicit alignment here. */ + +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,JUMPTABLE) \ + do { \ + ASM_OUTPUT_ALIGN (FILE, 2); \ + ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM); \ + } while (0) + +/* This says how to define a local common symbol (ie, not visible to + linker). */ +#define ASM_OUTPUT_LOCAL(STREAM, NAME, SIZE, ROUNDED) \ + (fprintf((STREAM),"\n\t.lcomm\t"), \ + assemble_name((STREAM),(NAME)), \ + fprintf((STREAM),",%u\n",(SIZE))) + +/* Output a reference to a label. */ +#define ASM_OUTPUT_LABELREF(STREAM,NAME) \ + fprintf ((STREAM), "%s%s", user_label_prefix, (NAME)) + +/* This is how to output an assembler line for a numeric constant byte. */ +#define ASM_OUTPUT_BYTE(STREAM,VALUE) \ + fprintf ((STREAM), "\t.byte\t0x%x\n", (VALUE)) + +#define ASM_OUTPUT_INT(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.word\t"); \ + output_addr_const (STREAM, (VALUE)); \ + fprintf (STREAM, "\n"); \ +} + +#define ASM_OUTPUT_SHORT(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.short\t"); \ + output_addr_const (STREAM, (VALUE)); \ + fprintf (STREAM, "\n"); \ +} + +#define ASM_OUTPUT_CHAR(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.byte\t"); \ + output_addr_const (STREAM, (VALUE)); \ + fprintf (STREAM, "\n"); \ +} + +#define ASM_OUTPUT_LONG_DOUBLE(STREAM,VALUE) \ +do { char dstr[30]; \ + long l[3]; \ + REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ + fprintf (STREAM, "\t.long 0x%lx,0x%lx,0x%lx\t%s long double %s\n", \ + l[0], l[1], l[2], ASM_COMMENT_START, dstr); \ + } while (0) + +#define ASM_OUTPUT_DOUBLE(STREAM, VALUE) \ +do { char dstr[30]; \ + long l[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.14g", dstr); \ + fprintf (STREAM, "\t.long 0x%lx, 0x%lx\t%s double %s\n", l[0], \ + l[1], ASM_COMMENT_START, dstr); \ + } while (0) + +#define ASM_OUTPUT_FLOAT(STREAM, VALUE) \ +do { char dstr[30]; \ + long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.7g", dstr); \ + fprintf (STREAM, "\t.word 0x%lx\t%s float %s\n", l, \ + ASM_COMMENT_START, dstr); \ + } while (0); + +/* Define results of standard character escape sequences. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* This is how to output a string. */ +#define ASM_OUTPUT_ASCII(STREAM, STRING, LEN) \ +do { \ + register int i, c, len = (LEN), cur_pos = 17; \ + register unsigned char *string = (unsigned char *)(STRING); \ + fprintf ((STREAM), "\t.ascii\t\""); \ + for (i = 0; i < len; i++) \ + { \ + register int c = string[i]; \ + \ + switch (c) \ + { \ + case '\"': \ + case '\\': \ + putc ('\\', (STREAM)); \ + putc (c, (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_NEWLINE: \ + fputs ("\\n", (STREAM)); \ + if (i+1 < len \ + && (((c = string[i+1]) >= '\040' && c <= '~') \ + || c == TARGET_TAB)) \ + cur_pos = 32767; /* break right here */ \ + else \ + cur_pos += 2; \ + break; \ + \ + case TARGET_TAB: \ + fputs ("\\t", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_FF: \ + fputs ("\\f", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_BS: \ + fputs ("\\b", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_CR: \ + fputs ("\\r", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + default: \ + if (c >= ' ' && c < 0177) \ + { \ + putc (c, (STREAM)); \ + cur_pos++; \ + } \ + else \ + { \ + fprintf ((STREAM), "\\%03o", c); \ + cur_pos += 4; \ + } \ + } \ + \ + if (cur_pos > 72 && i+1 < len) \ + { \ + cur_pos = 17; \ + fprintf ((STREAM), "\"\n\t.ascii\t\""); \ + } \ + } \ + fprintf ((STREAM), "\"\n"); \ +} while (0) + +/* Output and Generation of Labels */ +#define ASM_OUTPUT_LABEL(STREAM,NAME) \ + (assemble_name ((STREAM), (NAME)), \ + fprintf ((STREAM), ":\n")) + +#define ASM_GLOBALIZE_LABEL(STREAM,NAME) \ + (fprintf ((STREAM), "\t.globl\t"), \ + assemble_name ((STREAM), (NAME)), \ + fputc ('\n', (STREAM))) + +/* Construct a private name. */ +#define ASM_FORMAT_PRIVATE_NAME(OUTVAR,NAME,NUMBER) \ + ((OUTVAR) = (char *) alloca (strlen (NAME) + 10), \ + sprintf ((OUTVAR), "%s.%d", (NAME), (NUMBER))) + +/* Switch to the text or data segment. */ +#define TEXT_SECTION_ASM_OP ".text" +#define DATA_SECTION_ASM_OP ".data" +#define BSS_SECTION_ASM_OP ".bss" + +/* The assembler's names for the registers. */ +#ifndef REGISTER_NAMES +#define REGISTER_NAMES \ +{ \ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc", "ap" \ +} +#endif + +#ifndef ADDITIONAL_REGISTER_NAMES +#define ADDITIONAL_REGISTER_NAMES \ +{ \ + {"a1", 0}, \ + {"a2", 1}, \ + {"a3", 2}, \ + {"a4", 3}, \ + {"v1", 4}, \ + {"v2", 5}, \ + {"v3", 6}, \ + {"v4", 7}, \ + {"v5", 8}, \ + {"v6", 9}, \ + {"sb", 9}, \ + {"v7", 10}, \ + {"r10", 10}, /* sl */ \ + {"r11", 11}, /* fp */ \ + {"r12", 12}, /* ip */ \ + {"r13", 13}, /* sp */ \ + {"r14", 14}, /* lr */ \ + {"r15", 15} /* pc */ \ +} +#endif + +/* The assembler's parentheses characters. */ +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + +#ifndef ASM_COMMENT_START +#define ASM_COMMENT_START "@" +#endif + +/* Output an element of a dispatch table. */ +#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM,VALUE) \ + fprintf (STREAM, "\t.word\t%sL%d\n", (LOCAL_LABEL_PREFIX), (VALUE)) + +#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM,BODY,VALUE,REL) \ + fprintf (STREAM, "\tb\t%sL%d\n", (LOCAL_LABEL_PREFIX), (VALUE)) + +/* Storage Layout */ + +/* Define this is most significant bit is lowest numbered in + instructions that operate on numbered bit-fields. */ +#define BITS_BIG_ENDIAN 0 + +/* Define this if most significant byte of a word is the lowest + numbered. */ +#define BYTES_BIG_ENDIAN (TARGET_BIG_END != 0) + +#define WORDS_BIG_ENDIAN (BYTES_BIG_ENDIAN) + +/* LIBGCC2_WORDS_BIG_ENDIAN has to be a constant, so we define this based + on processor pre-defineds when compiling libgcc2.c. */ +#if defined(__THUMBEB__) && !defined(__THUMBEL__) +#define LIBGCC2_WORDS_BIG_ENDIAN 1 +#else +#define LIBGCC2_WORDS_BIG_ENDIAN 0 +#endif + +#define FLOAT_WORDS_BIG_ENDIAN 1 + +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 + +#define UNITS_PER_WORD 4 + +#define POINTER_SIZE 32 + +#define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \ +{ \ + if (GET_MODE_CLASS (MODE) == MODE_INT \ + && GET_MODE_SIZE (MODE) < 4) \ + { \ + (UNSIGNEDP) = 1; \ + (MODE) = SImode; \ + } \ +} + +#define PARM_BOUNDARY 32 +#define STACK_BOUNDARY 32 + +#define FUNCTION_BOUNDARY 32 +#define BIGGEST_ALIGNMENT 32 + +/* Make strings word-aligned so strcpy from constants will be faster. */ +#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ + (TREE_CODE (EXP) == STRING_CST \ + && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) + +#define EMPTY_FIELD_BOUNDARY 32 + +#define STRUCTURE_SIZE_BOUNDARY 32 + +/* Used when parsing command line option -mstructure_size_boundary. */ +extern char * structure_size_string; + +#define STRICT_ALIGNMENT 1 + +#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT + + +/* Layout of Source Language Data Types */ + +#define DEFAULT_SIGNED_CHAR 0 + +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + + +/* Register Usage */ + +/* Note there are 16 hard registers on the Thumb. We invent a 17th register + which is assigned to ARG_POINTER_REGNUM, but this is later removed by + elimination passes in the compiler. */ +#define FIRST_PSEUDO_REGISTER 17 + +/* ??? This is questionable. */ +#define FIXED_REGISTERS \ +{ \ + 0,0,0,0, \ + 0,0,0,0, \ + 0,0,0,1, \ + 0,1,1,1,1 \ +} + +/* ??? This is questionable. */ +#define CALL_USED_REGISTERS \ +{ \ + 1,1,1,1, \ + 0,0,0,0, \ + 0,0,0,1, \ + 1,1,1,1,1 \ +} + +#define HARD_REGNO_NREGS(REGNO,MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ + / UNITS_PER_WORD) + +/* ??? Probably should only allow DImode/DFmode in even numbered registers. */ +#define HARD_REGNO_MODE_OK(REGNO,MODE) ((GET_MODE_SIZE (MODE) > UNITS_PER_WORD) ? (REGNO < 7) : 1) + +#define MODES_TIEABLE_P(MODE1,MODE2) 1 + +/* The NOARG_LO_REGS class is the set of LO_REGS that are not used for passing + arguments to functions. These are the registers that are available for + spilling during reload. The code in reload1.c:init_reload() will detect this + class and place it into 'reload_address_base_reg_class'. */ + +enum reg_class +{ + NO_REGS, + NONARG_LO_REGS, + LO_REGS, + STACK_REG, + BASE_REGS, + HI_REGS, + ALL_REGS, + LIM_REG_CLASSES +}; + +#define GENERAL_REGS ALL_REGS + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +#define REG_CLASS_NAMES \ +{ \ + "NO_REGS", \ + "NONARG_LO_REGS", \ + "LO_REGS", \ + "STACK_REG", \ + "BASE_REGS", \ + "HI_REGS", \ + "ALL_REGS" \ +} + +#define REG_CLASS_CONTENTS \ +{ \ + 0x00000, \ + 0x000f0, \ + 0x000ff, \ + 0x02000, \ + 0x020ff, \ + 0x0ff00, \ + 0x1ffff, \ +} + +#define REGNO_REG_CLASS(REGNO) \ + ((REGNO) == STACK_POINTER_REGNUM ? STACK_REG \ + : (REGNO) < 8 ? ((REGNO) < 4 ? LO_REGS \ + : NONARG_LO_REGS) \ + : HI_REGS) + +#define BASE_REG_CLASS BASE_REGS + +#define MODE_BASE_REG_CLASS(MODE) \ + ((MODE) != QImode && (MODE) != HImode \ + ? BASE_REGS : LO_REGS) + +#define INDEX_REG_CLASS LO_REGS + +/* When SMALL_REGISTER_CLASSES is nonzero, the compiler allows + registers explicitly used in the rtl to be used as spill registers + but prevents the compiler from extending the lifetime of these + registers. */ + +#define SMALL_REGISTER_CLASSES 1 + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'l' ? LO_REGS \ + : (C) == 'h' ? HI_REGS \ + : (C) == 'b' ? BASE_REGS \ + : (C) == 'k' ? STACK_REG \ + : NO_REGS) + +#define REGNO_OK_FOR_BASE_P(REGNO) \ + ((REGNO) < 8 \ + || (REGNO) == STACK_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO] < 8 \ + || (unsigned) reg_renumber[REGNO] == STACK_POINTER_REGNUM) + +#define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) \ + ((REGNO) < 8 \ + || (unsigned) reg_renumber[REGNO] < 8 \ + || (GET_MODE_SIZE (MODE) >= 4 \ + && ((REGNO) == STACK_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO] == STACK_POINTER_REGNUM))) + +#define REGNO_OK_FOR_INDEX_P(REGNO) \ + ((REGNO) < 8 \ + || (unsigned) reg_renumber[REGNO] < 8) + +/* ??? This looks suspiciously wrong. */ +/* We need to leave BASE_REGS reloads alone, in order to avoid caller_save + lossage. Caller_saves requests a BASE_REGS reload (caller_save_spill_class) + and then later we verify that one was allocated. If PREFERRED_RELOAD_CLASS + says to allocate a LO_REGS spill instead, then this mismatch gives an + abort. Alternatively, this could be fixed by modifying BASE_REG_CLASS + to be LO_REGS instead of BASE_REGS. It is not clear what affect this + change would have. */ +/* ??? This looks even more suspiciously wrong. PREFERRED_RELOAD_CLASS + must always return a strict subset of the input class. Just blindly + returning LO_REGS is safe only if the input class is a superset of LO_REGS, + but there is no check for this. Added another exception for NONARG_LO_REGS + because it is not a superset of LO_REGS. */ +/* ??? We now use NONARG_LO_REGS for caller_save_spill_class, so the + comments about BASE_REGS are now obsolete. */ +#define PREFERRED_RELOAD_CLASS(X,CLASS) \ + ((CLASS) == BASE_REGS || (CLASS) == NONARG_LO_REGS ? (CLASS) \ + : LO_REGS) +/* + ((CONSTANT_P ((X)) && GET_CODE ((X)) != CONST_INT \ + && ! CONSTANT_POOL_ADDRESS_P((X))) ? NO_REGS \ + : (GET_CODE ((X)) == CONST_INT \ + && (unsigned HOST_WIDE_INT) INTVAL ((X)) > 255) ? NO_REGS \ + : LO_REGS) */ + +/* Must leave BASE_REGS and NONARG_LO_REGS reloads alone, see comment + above. */ +#define SECONDARY_RELOAD_CLASS(CLASS,MODE,X) \ + ((CLASS) != LO_REGS && (CLASS) != BASE_REGS && (CLASS) != NONARG_LO_REGS \ + ? ((true_regnum (X) == -1 ? LO_REGS \ + : (true_regnum (X) + HARD_REGNO_NREGS (0, MODE) > 8) ? LO_REGS \ + : NO_REGS)) \ + : NO_REGS) + +#define CLASS_MAX_NREGS(CLASS,MODE) HARD_REGNO_NREGS(0,(MODE)) + +int thumb_shiftable_const (); + +#define CONST_OK_FOR_LETTER_P(VAL,C) \ + ((C) == 'I' ? (unsigned HOST_WIDE_INT) (VAL) < 256 \ + : (C) == 'J' ? (VAL) > -256 && (VAL) <= 0 \ + : (C) == 'K' ? thumb_shiftable_const (VAL) \ + : (C) == 'L' ? (VAL) > -8 && (VAL) < 8 \ + : (C) == 'M' ? ((unsigned HOST_WIDE_INT) (VAL) < 1024 \ + && ((VAL) & 3) == 0) \ + : (C) == 'N' ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ + : (C) == 'O' ? ((VAL) >= -508 && (VAL) <= 508) \ + : 0) + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VAL,C) 0 + +#define EXTRA_CONSTRAINT(X,C) \ + ((C) == 'Q' ? (GET_CODE (X) == MEM \ + && GET_CODE (XEXP (X, 0)) == LABEL_REF) : 0) + +/* Stack Layout and Calling Conventions */ + +#define STACK_GROWS_DOWNWARD 1 + +/* #define FRAME_GROWS_DOWNWARD 1 */ + +/* #define ARGS_GROW_DOWNWARD 1 */ + +#define STARTING_FRAME_OFFSET 0 + +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* Registers that address the stack frame */ + +#define STACK_POINTER_REGNUM 13 /* Defined by the TPCS. */ + +#define FRAME_POINTER_REGNUM 7 /* TPCS defines this as 11 but it does not really mean it. */ + +#define ARG_POINTER_REGNUM 16 /* A fake hard register that is eliminated later on. */ + +#define STATIC_CHAIN_REGNUM 9 + +#define FRAME_POINTER_REQUIRED 0 + +#define ELIMINABLE_REGS \ +{{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ + {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}} + +/* On the Thumb we always want to perform the eliminations as we + actually only have one real register pointing to the stashed + variables: the stack pointer, and we never use the frame pointer. */ +#define CAN_ELIMINATE(FROM,TO) 1 + +/* Note: This macro must match the code in thumb_function_prologue() in thumb.c. */ +#define INITIAL_ELIMINATION_OFFSET(FROM,TO,OFFSET) \ +{ \ + (OFFSET) = 0; \ + if ((FROM) == ARG_POINTER_REGNUM) \ + { \ + int count_regs = 0; \ + int regno; \ + (OFFSET) += get_frame_size (); \ + for (regno = 8; regno < 13; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + count_regs++; \ + if (count_regs) \ + (OFFSET) += 4 * count_regs; \ + count_regs = 0; \ + for (regno = 0; regno < 8; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + count_regs++; \ + if (count_regs || ! leaf_function_p () || far_jump_used_p()) \ + (OFFSET) += 4 * (count_regs + 1); \ + if (TARGET_BACKTRACE) { \ + if ((count_regs & 0xFF) == 0 && (regs_ever_live[3] != 0)) \ + (OFFSET) += 20; \ + else \ + (OFFSET) += 16; } \ + } \ + if ((TO) == STACK_POINTER_REGNUM) \ + (OFFSET) += current_function_outgoing_args_size; \ +} + +/* Passing Arguments on the stack */ + +#define PROMOTE_PROTOTYPES 1 + +#define ACCUMULATE_OUTGOING_ARGS 1 + +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 + +#define FUNCTION_ARG(CUM,MODE,TYPE,NAMED) \ + ((NAMED) ? ((CUM) >= 16 ? 0 : gen_rtx (REG, (MODE), (CUM) / 4)) \ + : 0) + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM,MODE,TYPE,NAMED) \ + (((CUM) < 16 && (CUM) + (((MODE) == BLKmode) \ + ? int_size_in_bytes (TYPE) \ + : HARD_REGNO_NREGS (0, (MODE)) * 4) > 16) \ + ? 4 - (CUM) / 4 : 0) + +#define CUMULATIVE_ARGS int + +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ + ((CUM) = ((FNTYPE) && aggregate_value_p (TREE_TYPE (FNTYPE))) ? 4 : 0) + +#define FUNCTION_ARG_ADVANCE(CUM,MODE,TYPE,NAMED) \ + (CUM) += ((((MODE) == BLKmode) \ + ? int_size_in_bytes (TYPE) \ + : GET_MODE_SIZE (MODE)) + 3) & ~3 + +#define FUNCTION_ARG_REGNO_P(REGNO) \ + ((REGNO) >=0 && (REGNO) <= 3) + +#define FUNCTION_VALUE(VALTYPE,FUNC) gen_rtx (REG, TYPE_MODE (VALTYPE), 0) + +#define LIBCALL_VALUE(MODE) gen_rtx (REG, (MODE), 0) + +#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == 0) + + /* How large values are returned */ +/* A C expression which can inhibit the returning of certain function values + in registers, based on the type of value. */ +#define RETURN_IN_MEMORY(TYPE) thumb_return_in_memory (TYPE) + +/* Define DEFAULT_PCC_STRUCT_RETURN to 1 if all structure and union return + values must be in memory. On the ARM, they need only do so if larger + than a word, or if they contain elements offset from zero in the struct. */ +#define DEFAULT_PCC_STRUCT_RETURN 0 + + +#define STRUCT_VALUE_REGNUM 0 + +#define FUNCTION_PROLOGUE(FILE,SIZE) thumb_function_prologue((FILE),(SIZE)) + +#define FUNCTION_EPILOGUE(FILE,SIZE) thumb_function_epilogue((FILE),(SIZE)) + +/* Implementing the Varargs Macros */ + +#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \ +{ \ + extern int current_function_anonymous_args; \ + current_function_anonymous_args = 1; \ + if ((CUM) < 16) \ + (PRETEND_SIZE) = 16 - (CUM); \ +} + +/* Trampolines for nested functions */ + +/* Output assembler code for a block containing the constant parts of + a trampoline, leaving space for the variable parts. + + On the Thumb we always switch into ARM mode to execute the trampoline. + Why - because it is easier. This code will always be branched to via + a BX instruction and since the compiler magically generates the address + of the function the linker has no opportunity to ensure that the + bottom bit is set. Thus the processor will be in ARM mode when it + reaches this code. So we duplicate the ARM trampoline code and add + a switch into Thumb mode as well. + + On the ARM, (if r8 is the static chain regnum, and remembering that + referencing pc adds an offset of 8) the trampoline looks like: + ldr r8, [pc, #0] + ldr pc, [pc] + .word static chain value + .word function's address + ??? FIXME: When the trampoline returns, r8 will be clobbered. */ +#define TRAMPOLINE_TEMPLATE(FILE) \ +{ \ + fprintf ((FILE), "\t.code 32\n"); \ + fprintf ((FILE), ".Ltrampoline_start:\n"); \ + fprintf ((FILE), "\tldr\t%s, [%spc, #8]\n", \ + reg_names[STATIC_CHAIN_REGNUM], REGISTER_PREFIX); \ + fprintf ((FILE), "\tldr\t%sip, [%spc, #8]\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\torr\t%sip, %sip, #1\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\tbx\t%sip\n", REGISTER_PREFIX); \ + fprintf ((FILE), "\t.word\t0\n"); \ + fprintf ((FILE), "\t.word\t0\n"); \ + fprintf ((FILE), "\t.code 16\n"); \ +} + +/* Length in units of the trampoline for entering a nested function. */ +#define TRAMPOLINE_SIZE 24 + +/* Alignment required for a trampoline in units. */ +#define TRAMPOLINE_ALIGN 4 + +#define INITIALIZE_TRAMPOLINE(ADDR,FNADDR,CHAIN) \ +{ \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((ADDR), 16)), \ + (CHAIN)); \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((ADDR), 20)), \ + (FNADDR)); \ +} + + +/* Implicit Calls to Library Routines */ + +#define TARGET_MEM_FUNCTIONS 1 + +#define OVERRIDE_OPTIONS thumb_override_options () + + +/* Addressing Modes */ + +#define HAVE_POST_INCREMENT 1 + +#define CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (X)) + +#define MAX_REGS_PER_ADDRESS 2 + +#ifdef REG_OK_STRICT + +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) + +#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ + REGNO_MODE_OK_FOR_BASE_P (REGNO (X), MODE) + +#else /* REG_OK_STRICT */ + +#define REG_OK_FOR_BASE_P(X) \ + (REGNO (X) < 8 || REGNO (X) == STACK_POINTER_REGNUM \ + || (X) == arg_pointer_rtx \ + || REGNO (X) >= FIRST_PSEUDO_REGISTER) + +#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ + (REGNO (X) < 8 \ + || REGNO (X) >= FIRST_PSEUDO_REGISTER \ + || (GET_MODE_SIZE (MODE) >= 4 \ + && (REGNO (X) == STACK_POINTER_REGNUM \ + || (X) == arg_pointer_rtx))) + +#define REG_OK_FOR_INDEX_P(X) \ + (REGNO (X) < 8 \ + || REGNO (X) >= FIRST_PSEUDO_REGISTER) + +#endif /* REG_OK_STRICT */ + +/* In a REG+REG address, both must be INDEX registers. */ +#define REG_OK_FOR_INDEXED_BASE_P(X) REG_OK_FOR_INDEX_P(X) + +#define LEGITIMATE_OFFSET(MODE,VAL) \ +(GET_MODE_SIZE (MODE) == 1 ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ + : GET_MODE_SIZE (MODE) == 2 ? ((unsigned HOST_WIDE_INT) (VAL) < 64 \ + && ((VAL) & 1) == 0) \ + : ((VAL) >= 0 && ((VAL) + GET_MODE_SIZE (MODE)) <= 128 \ + && ((VAL) & 3) == 0)) + +/* The AP may be eliminated to either the SP or the FP, so we use the + least common denominator, e.g. SImode, and offsets from 0 to 64. */ + +/* ??? Verify whether the above is the right approach. */ + +/* ??? Also, the FP may be eliminated to the SP, so perhaps that + needs special handling also. */ + +/* ??? Look at how the mips16 port solves this problem. It probably uses + better ways to solve some of these problems. */ + +/* Although it is not incorrect, we don't accept QImode and HImode + addresses based on the frame pointer or arg pointer until the reload pass starts. + This is so that eliminating such addresses into stack based ones + won't produce impossible code. */ +#define GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \ +{ \ + /* ??? Not clear if this is right. Experiment. */ \ + if (GET_MODE_SIZE (MODE) < 4 \ + && ! (reload_in_progress || reload_completed) \ + && (reg_mentioned_p (frame_pointer_rtx, X) \ + || reg_mentioned_p (arg_pointer_rtx, X) \ + || reg_mentioned_p (virtual_incoming_args_rtx, X) \ + || reg_mentioned_p (virtual_outgoing_args_rtx, X) \ + || reg_mentioned_p (virtual_stack_dynamic_rtx, X) \ + || reg_mentioned_p (virtual_stack_vars_rtx, X))) \ + ; \ + /* Accept any base register. SP only in SImode or larger. */ \ + else if (GET_CODE (X) == REG && REG_MODE_OK_FOR_BASE_P(X, MODE)) \ + goto WIN; \ + /* This is PC relative data before MACHINE_DEPENDENT_REORG runs. */ \ + else if (GET_MODE_SIZE (MODE) >= 4 && CONSTANT_P (X) \ + && CONSTANT_POOL_ADDRESS_P (X)) \ + goto WIN; \ + /* This is PC relative data after MACHINE_DEPENDENT_REORG runs. */ \ + else if (GET_MODE_SIZE (MODE) >= 4 && reload_completed \ + && (GET_CODE (X) == LABEL_REF \ + || (GET_CODE (X) == CONST \ + && GET_CODE (XEXP (X, 0)) == PLUS \ + && GET_CODE (XEXP (XEXP (X, 0), 0)) == LABEL_REF \ + && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT))) \ + goto WIN; \ + /* Post-inc indexing only supported for SImode and larger. */ \ + else if (GET_CODE (X) == POST_INC && GET_MODE_SIZE (MODE) >= 4 \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_INDEX_P (XEXP (X, 0))) \ + goto WIN; \ + else if (GET_CODE (X) == PLUS) \ + { \ + /* REG+REG address can be any two index registers. */ \ + /* ??? REG+REG addresses have been completely disabled before \ + reload completes, because we do not have enough available \ + reload registers. We only have 3 guaranteed reload registers \ + (NONARG_LO_REGS - the frame pointer), but we need at least 4 \ + to support REG+REG addresses. We have left them enabled after \ + reload completes, in the hope that reload_cse_regs and related \ + routines will be able to create them after the fact. It is \ + probably possible to support REG+REG addresses with additional \ + reload work, but I do not not have enough time to attempt such \ + a change at this time. */ \ + /* ??? Normally checking the mode here is wrong, since it isn't \ + impossible to use REG+REG with DFmode. However, the movdf \ + pattern requires offsettable addresses, and REG+REG is not \ + offsettable, so it must be rejected somehow. Trying to use \ + 'o' fails, because offsettable_address_p does a QImode check. \ + QImode is not valid for stack addresses, and has a smaller \ + range for non-stack bases, and this causes valid addresses \ + to be rejected. So we just eliminate REG+REG here by checking \ + the mode. */ \ + /* We also disallow FRAME+REG addressing since we know that FRAME \ + will be replaced with STACK, and SP relative addressing only \ + permits SP+OFFSET. */ \ + if (GET_MODE_SIZE (MODE) <= 4 \ + /* ??? See comment above. */ \ + && reload_completed \ + && GET_CODE (XEXP (X, 0)) == REG \ + && GET_CODE (XEXP (X, 1)) == REG \ + && XEXP (X, 0) != frame_pointer_rtx \ + && XEXP (X, 1) != frame_pointer_rtx \ + && XEXP (X, 0) != virtual_stack_vars_rtx \ + && XEXP (X, 1) != virtual_stack_vars_rtx \ + && REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ + && REG_OK_FOR_INDEX_P (XEXP (X, 1))) \ + goto WIN; \ + /* REG+const has 5-7 bit offset for non-SP registers. */ \ + else if (GET_CODE (XEXP (X, 0)) == REG \ + && (REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ + || XEXP (X, 0) == arg_pointer_rtx) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ + goto WIN; \ + /* REG+const has 10 bit offset for SP, but only SImode and \ + larger is supported. */ \ + /* ??? Should probably check for DI/DFmode overflow here \ + just like GO_IF_LEGITIMATE_OFFSET does. */ \ + else if (GET_CODE (XEXP (X, 0)) == REG \ + && REGNO (XEXP (X, 0)) == STACK_POINTER_REGNUM \ + && GET_MODE_SIZE (MODE) >= 4 \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (unsigned HOST_WIDE_INT) INTVAL (XEXP (X, 1)) < 1024 \ + && (INTVAL (XEXP (X, 1)) & 3) == 0) \ + goto WIN; \ + } \ +} + +/* ??? If an HImode FP+large_offset address is converted to an HImode + SP+large_offset address, then reload won't know how to fix it. It sees + only that SP isn't valid for HImode, and so reloads the SP into an index + register, but the resulting address is still invalid because the offset + is too big. We fix it here instead by reloading the entire address. */ +/* We could probably achieve better results by defining PROMOTE_MODE to help + cope with the variances between the Thumb's signed and unsigned byte and + halfword load instructions. */ +#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \ +{ \ + if (GET_CODE (X) == PLUS \ + && GET_MODE_SIZE (MODE) < 4 \ + && GET_CODE (XEXP (X, 0)) == REG \ + && XEXP (X, 0) == stack_pointer_rtx \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && ! LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ + { \ + rtx orig_X = X; \ + X = copy_rtx (X); \ + push_reload (orig_X, NULL_RTX, &X, NULL_PTR, \ + BASE_REG_CLASS, \ + Pmode, VOIDmode, 0, 0, OPNUM, TYPE); \ + goto WIN; \ + } \ +} + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) + +#define LEGITIMATE_CONSTANT_P(X) \ + (GET_CODE (X) == CONST_INT \ + || GET_CODE (X) == CONST_DOUBLE \ + || CONSTANT_ADDRESS_P (X)) + + +/* Condition Code Status */ + +#define NOTICE_UPDATE_CC(EXP,INSN) \ +{ \ + if (get_attr_conds ((INSN)) != CONDS_UNCHANGED) \ + CC_STATUS_INIT; \ +} + + +/* Describing Relative Costs of Operations */ + +#define SLOW_BYTE_ACCESS 0 + +#define SLOW_UNALIGNED_ACCESS 1 + +#define NO_FUNCTION_CSE 1 + +#define NO_RECURSIVE_FUNCTION_CSE 1 + +#define REGISTER_MOVE_COST(FROM,TO) \ + (((FROM) == HI_REGS || (TO) == HI_REGS) ? 4 : 2) + +#define MEMORY_MOVE_COST(M,CLASS,IN) \ + ((GET_MODE_SIZE(M) < 4 ? 8 : 2 * GET_MODE_SIZE(M)) * (CLASS == LO_REGS ? 1 : 2)) + +/* This will allow better space optimization when compiling with -O */ +#define BRANCH_COST (optimize > 1 ? 1 : 0) + +#define RTX_COSTS(X,CODE,OUTER) \ + case MULT: \ + if (GET_CODE (XEXP (X, 1)) == CONST_INT) \ + { \ + int cycles = 0; \ + unsigned HOST_WIDE_INT i = INTVAL (XEXP (X, 1)); \ + while (i) \ + { \ + i >>= 2; \ + cycles++; \ + } \ + return COSTS_N_INSNS (2) + cycles; \ + } \ + return COSTS_N_INSNS (1) + 16; \ + case ASHIFT: case ASHIFTRT: case LSHIFTRT: case ROTATERT: \ + case PLUS: case MINUS: case COMPARE: case NEG: case NOT: \ + return COSTS_N_INSNS (1); \ + case SET: \ + return (COSTS_N_INSNS (1) \ + + 4 * ((GET_CODE (SET_SRC (X)) == MEM) \ + + GET_CODE (SET_DEST (X)) == MEM)) + +#define CONST_COSTS(X,CODE,OUTER) \ + case CONST_INT: \ + if ((OUTER) == SET) \ + { \ + if ((unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ + return 0; \ + if (thumb_shiftable_const (INTVAL (X))) \ + return COSTS_N_INSNS (2); \ + return COSTS_N_INSNS (3); \ + } \ + else if (OUTER == PLUS \ + && INTVAL (X) < 256 && INTVAL (X) > -256) \ + return 0; \ + else if (OUTER == COMPARE \ + && (unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ + return 0; \ + else if (OUTER == ASHIFT || OUTER == ASHIFTRT \ + || OUTER == LSHIFTRT) \ + return 0; \ + return COSTS_N_INSNS (2); \ + case CONST: \ + case CONST_DOUBLE: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return COSTS_N_INSNS(3); + +#define ADDRESS_COST(X) \ + ((GET_CODE (X) == REG \ + || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \ + && GET_CODE (XEXP (X, 1)) == CONST_INT)) \ + ? 1 : 2) + + +/* Position Independent Code */ + +#define PRINT_OPERAND(STREAM,X,CODE) \ + thumb_print_operand((STREAM), (X), (CODE)) + +#define PRINT_OPERAND_ADDRESS(STREAM,X) \ +{ \ + if (GET_CODE ((X)) == REG) \ + fprintf ((STREAM), "[%s]", reg_names[REGNO ((X))]); \ + else if (GET_CODE ((X)) == POST_INC) \ + fprintf ((STREAM), "%s!", reg_names[REGNO (XEXP (X, 0))]); \ + else if (GET_CODE ((X)) == PLUS) \ + { \ + if (GET_CODE (XEXP ((X), 1)) == CONST_INT) \ + fprintf ((STREAM), "[%s, #%d]", \ + reg_names[REGNO (XEXP ((X), 0))], \ + (int) INTVAL (XEXP ((X), 1))); \ + else \ + fprintf ((STREAM), "[%s, %s]", \ + reg_names[REGNO (XEXP ((X), 0))], \ + reg_names[REGNO (XEXP ((X), 1))]); \ + } \ + else \ + output_addr_const ((STREAM), (X)); \ +} + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '@' || ((CODE) == '_')) + +/* Emit a special directive when defining a function name. + This is used by the assembler to assit with interworking. */ +#define ASM_DECLARE_FUNCTION_NAME(file, name, decl) \ + if (! is_called_in_ARM_mode (decl)) \ + fprintf (file, "\t.thumb_func\n") ; \ + else \ + fprintf (file, "\t.code\t32\n") ; \ + ASM_OUTPUT_LABEL (file, name) + +#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ + asm_fprintf ((STREAM), "\tpush {%R%s}\n", reg_names[(REGNO)]) + +#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \ + fprintf ((STREAM), "\tpop {%R%s}\n", reg_names[(REGNO)]) + +#define FINAL_PRESCAN_INSN(INSN,OPVEC,NOPERANDS) \ + final_prescan_insn((INSN)) + +/* Controlling Debugging Information Format */ +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* Specific options for DBX Output */ + +#define DBX_DEBUGGING_INFO 1 + +#define DEFAULT_GDB_EXTENSIONS 1 + + +/* Cross Compilation and Floating Point */ + +#define REAL_ARITHMETIC + + +/* Miscellaneous Parameters */ + +#define PREDICATE_CODES \ + {"thumb_cmp_operand", {SUBREG, REG, CONST_INT}}, + +#define CASE_VECTOR_MODE Pmode + +#define WORD_REGISTER_OPERATIONS + +#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND + +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +#define MOVE_MAX 4 + +#define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) 1 + +#define STORE_FLAG_VALUE 1 + +#define Pmode SImode + +#define FUNCTION_MODE SImode + +#define DOLLARS_IN_IDENTIFIERS 0 + +#define NO_DOLLAR_IN_LABEL 1 + +#define HAVE_ATEXIT + +/* The literal pool needs to reside in the text area due to the + limited PC addressing range: */ +#define MACHINE_DEPENDENT_REORG(INSN) thumb_reorg ((INSN)) + + +/* Options specific to Thumb */ + +/* True if a return instruction can be used in this function. */ +int thumb_trivial_epilogue (); +#define USE_RETURN (reload_completed && thumb_trivial_epilogue ()) + +extern char * thumb_unexpanded_epilogue (); +extern char * output_move_mem_multiple (); +extern char * thumb_load_double_from_address (); +extern char * output_return (); +extern int far_jump_used_p(); +extern int is_called_in_ARM_mode (); + diff --git a/gcc_arm/config/arm/thumb_010110a.c b/gcc_arm/config/arm/thumb_010110a.c new file mode 100755 index 0000000..ef7ebff --- /dev/null +++ b/gcc_arm/config/arm/thumb_010110a.c @@ -0,0 +1,2124 @@ +/* Output routines for GCC for ARM/Thumb + Copyright (C) 1996 Cygnus Software Technologies Ltd + The basis of this contribution was generated by + Richard Earnshaw, Advanced RISC Machines Ltd + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include +#include +#include "config.h" +#include "rtl.h" +#include "hard-reg-set.h" +#include "regs.h" +#include "output.h" +#include "insn-flags.h" +#include "insn-attr.h" +#include "flags.h" +#include "tree.h" +#include "expr.h" + + +int current_function_anonymous_args = 0; + +/* Used to parse -mstructure_size_boundary command line option. */ +char * structure_size_string = NULL; +int arm_structure_size_boundary = 32; /* Used to be 8 */ + + +/* Predicates */ +int +reload_memory_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + int regno = true_regnum (op); + + return (! CONSTANT_P (op) + && (regno == -1 + || (GET_CODE (op) == REG + && REGNO (op) >= FIRST_PSEUDO_REGISTER))); +} + +/* Return nonzero if op is suitable for the RHS of a cmp instruction. */ +int +thumb_cmp_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return ((GET_CODE (op) == CONST_INT + && (unsigned HOST_WIDE_INT) (INTVAL (op)) < 256) + || register_operand (op, mode)); +} + +int +thumb_shiftable_const (val) + HOST_WIDE_INT val; +{ + unsigned HOST_WIDE_INT x = val; + unsigned HOST_WIDE_INT mask = 0xff; + int i; + + for (i = 0; i < 25; i++) + if ((val & (mask << i)) == val) + return 1; + + return 0; +} + +int +thumb_trivial_epilogue () +{ + int regno; + + /* ??? If this function ever returns 1, we get a function without any + epilogue at all. It appears that the intent was to cause a "return" + insn to be emitted, but that does not happen. */ + return 0; + +#if 0 + if (get_frame_size () + || current_function_outgoing_args_size + || current_function_pretend_args_size) + return 0; + + for (regno = 8; regno < 13; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + return 0; + + return 1; +#endif +} + + +/* Routines for handling the constant pool */ +/* This is unashamedly hacked from the version in sh.c, since the problem is + extremely similar. */ + +/* Thumb instructions cannot load a large constant into a register, + constants have to come from a pc relative load. The reference of a pc + relative load instruction must be less than 1k infront of the instruction. + This means that we often have to dump a constant inside a function, and + generate code to branch around it. + + It is important to minimize this, since the branches will slow things + down and make things bigger. + + Worst case code looks like: + + ldr rn, L1 + b L2 + align + L1: .long value + L2: + .. + + ldr rn, L3 + b L4 + align + L3: .long value + L4: + .. + + We fix this by performing a scan before scheduling, which notices which + instructions need to have their operands fetched from the constant table + and builds the table. + + + The algorithm is: + + scan, find an instruction which needs a pcrel move. Look forward, find the + last barrier which is within MAX_COUNT bytes of the requirement. + If there isn't one, make one. Process all the instructions between + the find and the barrier. + + In the above example, we can tell that L3 is within 1k of L1, so + the first move can be shrunk from the 2 insn+constant sequence into + just 1 insn, and the constant moved to L3 to make: + + ldr rn, L1 + .. + ldr rn, L3 + b L4 + align + L1: .long value + L3: .long value + L4: + + Then the second move becomes the target for the shortening process. + + */ + +typedef struct +{ + rtx value; /* Value in table */ + HOST_WIDE_INT next_offset; + enum machine_mode mode; /* Mode of value */ +} pool_node; + +/* The maximum number of constants that can fit into one pool, since + the pc relative range is 0...1020 bytes and constants are at least 4 + bytes long */ + +#define MAX_POOL_SIZE (1020/4) +static pool_node pool_vector[MAX_POOL_SIZE]; +static int pool_size; +static rtx pool_vector_label; + +/* Add a constant to the pool and return its label. */ + +static HOST_WIDE_INT +add_constant (x, mode) + rtx x; + enum machine_mode mode; +{ + int i; + rtx lab; + HOST_WIDE_INT offset; + + if (mode == SImode && GET_CODE (x) == MEM && CONSTANT_P (XEXP (x, 0)) + && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0))) + x = get_pool_constant (XEXP (x, 0)); + + /* First see if we've already got it */ + + for (i = 0; i < pool_size; i++) + { + if (x->code == pool_vector[i].value->code + && mode == pool_vector[i].mode) + { + if (x->code == CODE_LABEL) + { + if (XINT (x, 3) != XINT (pool_vector[i].value, 3)) + continue; + } + if (rtx_equal_p (x, pool_vector[i].value)) + return pool_vector[i].next_offset - GET_MODE_SIZE (mode); + } + } + + /* Need a new one */ + + pool_vector[pool_size].next_offset = GET_MODE_SIZE (mode); + offset = 0; + if (pool_size == 0) + pool_vector_label = gen_label_rtx (); + else + pool_vector[pool_size].next_offset + += (offset = pool_vector[pool_size - 1].next_offset); + + pool_vector[pool_size].value = x; + pool_vector[pool_size].mode = mode; + pool_size++; + return offset; +} + +/* Output the literal table */ + +static void +dump_table (scan) + rtx scan; +{ + int i; + + scan = emit_label_after (gen_label_rtx (), scan); + scan = emit_insn_after (gen_align_4 (), scan); + scan = emit_label_after (pool_vector_label, scan); + + for (i = 0; i < pool_size; i++) + { + pool_node *p = pool_vector + i; + + switch (GET_MODE_SIZE (p->mode)) + { + case 4: + scan = emit_insn_after (gen_consttable_4 (p->value), scan); + break; + + case 8: + scan = emit_insn_after (gen_consttable_8 (p->value), scan); + break; + + default: + abort (); + break; + } + } + + scan = emit_insn_after (gen_consttable_end (), scan); + scan = emit_barrier_after (scan); + pool_size = 0; +} + +/* Non zero if the src operand needs to be fixed up */ +static +int +fixit (src, mode) + rtx src; + enum machine_mode mode; +{ + return ((CONSTANT_P (src) + && (GET_CODE (src) != CONST_INT + || ! (CONST_OK_FOR_LETTER_P (INTVAL (src), 'I') + || CONST_OK_FOR_LETTER_P (INTVAL (src), 'J') + || (mode != DImode + && CONST_OK_FOR_LETTER_P (INTVAL (src), 'K'))))) + || (mode == SImode && GET_CODE (src) == MEM + && GET_CODE (XEXP (src, 0)) == SYMBOL_REF + && CONSTANT_POOL_ADDRESS_P (XEXP (src, 0)))); +} + +/* Find the last barrier less than MAX_COUNT bytes from FROM, or create one. */ + +#define MAX_COUNT_SI 1000 + +static rtx +find_barrier (from) + rtx from; +{ + int count = 0; + rtx found_barrier = 0; + rtx label; + + while (from && count < MAX_COUNT_SI) + { + if (GET_CODE (from) == BARRIER) + return from; + + /* Count the length of this insn */ + if (GET_CODE (from) == INSN + && GET_CODE (PATTERN (from)) == SET + && CONSTANT_P (SET_SRC (PATTERN (from))) + && CONSTANT_POOL_ADDRESS_P (SET_SRC (PATTERN (from)))) + { + rtx src = SET_SRC (PATTERN (from)); + count += 2; + } + else + count += get_attr_length (from); + + from = NEXT_INSN (from); + } + + /* We didn't find a barrier in time to + dump our stuff, so we'll make one */ + label = gen_label_rtx (); + + if (from) + from = PREV_INSN (from); + else + from = get_last_insn (); + + /* Walk back to be just before any jump */ + while (GET_CODE (from) == JUMP_INSN + || GET_CODE (from) == NOTE + || GET_CODE (from) == CODE_LABEL) + from = PREV_INSN (from); + + from = emit_jump_insn_after (gen_jump (label), from); + JUMP_LABEL (from) = label; + found_barrier = emit_barrier_after (from); + emit_label_after (label, found_barrier); + return found_barrier; +} + +/* Non zero if the insn is a move instruction which needs to be fixed. */ + +static int +broken_move (insn) + rtx insn; +{ + if (!INSN_DELETED_P (insn) + && GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == SET) + { + rtx pat = PATTERN (insn); + rtx src = SET_SRC (pat); + rtx dst = SET_DEST (pat); + enum machine_mode mode = GET_MODE (dst); + if (dst == pc_rtx) + return 0; + return fixit (src, mode); + } + return 0; +} + +/* Recursively search through all of the blocks in a function + checking to see if any of the variables created in that + function match the RTX called 'orig'. If they do then + replace them with the RTX called 'new'. */ + +static void +replace_symbols_in_block (tree block, rtx orig, rtx new) +{ + for (; block; block = BLOCK_CHAIN (block)) + { + tree sym; + + if (! TREE_USED (block)) + continue; + + for (sym = BLOCK_VARS (block); sym; sym = TREE_CHAIN (sym)) + { + if ( (DECL_NAME (sym) == 0 && TREE_CODE (sym) != TYPE_DECL) + || DECL_IGNORED_P (sym) + || TREE_CODE (sym) != VAR_DECL + || DECL_EXTERNAL (sym) + || ! rtx_equal_p (DECL_RTL (sym), orig) + ) + continue; + + DECL_RTL (sym) = new; + } + + replace_symbols_in_block (BLOCK_SUBBLOCKS (block), orig, new); + } +} + +void +thumb_reorg (first) + rtx first; +{ + rtx insn; + for (insn = first; insn; insn = NEXT_INSN (insn)) + { + if (broken_move (insn)) + { + /* This is a broken move instruction, scan ahead looking for + a barrier to stick the constant table behind */ + rtx scan; + rtx barrier = find_barrier (insn); + + /* Now find all the moves between the points and modify them */ + for (scan = insn; scan != barrier; scan = NEXT_INSN (scan)) + { + if (broken_move (scan)) + { + /* This is a broken move instruction, add it to the pool */ + rtx pat = PATTERN (scan); + rtx src = SET_SRC (pat); + rtx dst = SET_DEST (pat); + enum machine_mode mode = GET_MODE (dst); + HOST_WIDE_INT offset; + rtx newinsn; + rtx newsrc; + + /* If this is an HImode constant load, convert it into + an SImode constant load. Since the register is always + 32 bits this is safe. We have to do this, since the + load pc-relative instruction only does a 32-bit load. */ + if (mode == HImode) + { + mode = SImode; + if (GET_CODE (dst) != REG) + abort (); + PUT_MODE (dst, SImode); + } + + offset = add_constant (src, mode); + newsrc = gen_rtx (MEM, mode, + plus_constant (gen_rtx (LABEL_REF, + VOIDmode, + pool_vector_label), + offset)); + + /* Build a jump insn wrapper around the move instead + of an ordinary insn, because we want to have room for + the target label rtx in fld[7], which an ordinary + insn doesn't have. */ + newinsn = emit_jump_insn_after (gen_rtx (SET, VOIDmode, + dst, newsrc), scan); + JUMP_LABEL (newinsn) = pool_vector_label; + + /* But it's still an ordinary insn */ + PUT_CODE (newinsn, INSN); + + /* If debugging information is going to be emitted + then we must make sure that any refences to + symbols which are removed by the above code are + also removed in the descriptions of the + function's variables. Failure to do this means + that the debugging information emitted could + refer to symbols which are not emited by + output_constant_pool() because + mark_constant_pool() never sees them as being + used. */ + + + /* These are the tests used in + output_constant_pool() to decide if the constant + pool will be marked. Only necessary if debugging + info is being emitted. Only necessary for + references to memory whose address is given by a + symbol. */ + + if (optimize > 0 + && flag_expensive_optimizations + && write_symbols != NO_DEBUG + && GET_CODE (src) == MEM + && GET_CODE (XEXP (src, 0)) == SYMBOL_REF) + replace_symbols_in_block + (DECL_INITIAL (current_function_decl), src, newsrc); + + /* Kill old insn */ + delete_insn (scan); + scan = newinsn; + } + } + dump_table (barrier); + } + } +} + + +/* Routines for generating rtl */ + +void +thumb_expand_movstrqi (operands) + rtx *operands; +{ + rtx out = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); + rtx in = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); + HOST_WIDE_INT len = INTVAL (operands[2]); + HOST_WIDE_INT offset = 0; + + while (len >= 12) + { + emit_insn (gen_movmem12b (out, in)); + len -= 12; + } + if (len >= 8) + { + emit_insn (gen_movmem8b (out, in)); + len -= 8; + } + if (len >= 4) + { + rtx reg = gen_reg_rtx (SImode); + emit_insn (gen_movsi (reg, gen_rtx (MEM, SImode, in))); + emit_insn (gen_movsi (gen_rtx (MEM, SImode, out), reg)); + len -= 4; + offset += 4; + } + if (len >= 2) + { + rtx reg = gen_reg_rtx (HImode); + emit_insn (gen_movhi (reg, gen_rtx (MEM, HImode, + plus_constant (in, offset)))); + emit_insn (gen_movhi (gen_rtx (MEM, HImode, plus_constant (out, offset)), + reg)); + len -= 2; + offset += 2; + } + if (len) + { + rtx reg = gen_reg_rtx (QImode); + emit_insn (gen_movqi (reg, gen_rtx (MEM, QImode, + plus_constant (in, offset)))); + emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (out, offset)), + reg)); + } +} + + +/* Routines for reloading */ + +void +thumb_reload_out_si (operands) + rtx operands; +{ + abort (); +} + +/* CYGNUS LOCAL nickc/thumb-pe */ + +#ifdef THUMB_PE +/* Return non-zero if FUNC is a naked function. */ + +static int +arm_naked_function_p (func) + tree func; +{ + tree a; + + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + + a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func)); + return a != NULL_TREE; +} +#endif +/* END CYGNUS LOCAL nickc/thumb-pe */ + +/* Return non-zero if FUNC must be entered in ARM mode. */ +int +is_called_in_ARM_mode (func) + tree func; +{ + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + + /* Ignore the problem about functions whoes address is taken. */ + if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func)) + return TRUE; + +/* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + return lookup_attribute ("interfacearm", DECL_MACHINE_ATTRIBUTES (func)) != NULL_TREE; +#else + return FALSE; +#endif +/* END CYGNUS LOCAL */ +} + + +/* Routines for emitting code */ + +void +final_prescan_insn(insn) + rtx insn; +{ + extern int *insn_addresses; + + if (flag_print_asm_name) + fprintf (asm_out_file, "%s 0x%04x\n", ASM_COMMENT_START, + insn_addresses[INSN_UID (insn)]); +} + + +static void thumb_pushpop ( FILE *, int, int ); /* Forward declaration. */ + +#ifdef __GNUC__ +inline +#endif +static int +number_of_first_bit_set (mask) + int mask; +{ + int bit; + + for (bit = 0; + (mask & (1 << bit)) == 0; + ++ bit) + continue; + + return bit; +} + +#define ARG_1_REGISTER 0 +#define ARG_2_REGISTER 1 +#define ARG_3_REGISTER 2 +#define ARG_4_REGISTER 3 +#define WORK_REGISTER 7 +#define FRAME_POINTER 11 +#define IP_REGISTER 12 +#define STACK_POINTER STACK_POINTER_REGNUM +#define LINK_REGISTER 14 +#define PROGRAM_COUNTER 15 + +/* Generate code to return from a thumb function. If + 'reg_containing_return_addr' is -1, then the return address is + actually on the stack, at the stack pointer. */ +static void +thumb_exit (f, reg_containing_return_addr) + FILE * f; + int reg_containing_return_addr; +{ + int regs_available_for_popping; + int regs_to_pop; + int pops_needed; + int reg; + int available; + int required; + int mode; + int size; + int restore_a4 = FALSE; + + /* Compute the registers we need to pop. */ + regs_to_pop = 0; + pops_needed = 0; + + if (reg_containing_return_addr == -1) + { + regs_to_pop |= 1 << LINK_REGISTER; + ++ pops_needed; + } + + if (TARGET_BACKTRACE) + { + /* Restore frame pointer and stack pointer. */ + regs_to_pop |= (1 << FRAME_POINTER) | (1 << STACK_POINTER); + pops_needed += 2; + } + + /* If there is nothing to pop then just emit the BX instruction and return.*/ + if (pops_needed == 0) + { + asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]); + + return; + } + + /* Otherwise if we are not supporting interworking and we have not created + a backtrace structure and the function was not entered in ARM mode then + just pop the return address straight into the PC. */ + else if ( ! TARGET_THUMB_INTERWORK + && ! TARGET_BACKTRACE + && ! is_called_in_ARM_mode (current_function_decl)) + { + asm_fprintf (f, "\tpop\t{pc}\n" ); + + return; + } + + /* Find out how many of the (return) argument registers we can corrupt. */ + regs_available_for_popping = 0; + +#ifdef RTX_CODE + /* If we can deduce the registers used from the function's return value. + This is more reliable that examining regs_ever_live[] because that + will be set if the register is ever used in the function, not just if + the register is used to hold a return value. */ + + if (current_function_return_rtx != 0) + mode = GET_MODE (current_function_return_rtx); + else +#endif + mode = DECL_MODE (DECL_RESULT (current_function_decl)); + + size = GET_MODE_SIZE (mode); + + if (size == 0) + { + /* In a void function we can use any argument register. + In a function that returns a structure on the stack + we can use the second and third argument registers. */ + if (mode == VOIDmode) + regs_available_for_popping = + (1 << ARG_1_REGISTER) + | (1 << ARG_2_REGISTER) + | (1 << ARG_3_REGISTER); + else + regs_available_for_popping = + (1 << ARG_2_REGISTER) + | (1 << ARG_3_REGISTER); + } + else if (size <= 4) regs_available_for_popping = + (1 << ARG_2_REGISTER) + | (1 << ARG_3_REGISTER); + else if (size <= 8) regs_available_for_popping = + (1 << ARG_3_REGISTER); + + /* Match registers to be popped with registers into which we pop them. */ + for (available = regs_available_for_popping, + required = regs_to_pop; + required != 0 && available != 0; + available &= ~(available & - available), + required &= ~(required & - required)) + -- pops_needed; + + /* If we have any popping registers left over, remove them. */ + if (available > 0) + regs_available_for_popping &= ~ available; + + /* Otherwise if we need another popping register we can use + the fourth argument register. */ + else if (pops_needed) + { + /* If we have not found any free argument registers and + reg a4 contains the return address, we must move it. */ + if (regs_available_for_popping == 0 + && reg_containing_return_addr == ARG_4_REGISTER) + { + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]); + reg_containing_return_addr = LINK_REGISTER; + } + else if (size > 12) + { + /* Register a4 is being used to hold part of the return value, + but we have dire need of a free, low register. */ + restore_a4 = TRUE; + + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [IP_REGISTER], reg_names [ARG_4_REGISTER]); + } + + if (reg_containing_return_addr != ARG_4_REGISTER) + { + /* The fourth argument register is available. */ + regs_available_for_popping |= 1 << ARG_4_REGISTER; + + -- pops_needed; + } + } + + /* Pop as many registers as we can. */ + thumb_pushpop (f, regs_available_for_popping, FALSE); + + /* Process the registers we popped. */ + if (reg_containing_return_addr == -1) + { + /* The return address was popped into the lowest numbered register. */ + regs_to_pop &= ~ (1 << LINK_REGISTER); + + reg_containing_return_addr = + number_of_first_bit_set (regs_available_for_popping); + + /* Remove this register for the mask of available registers, so that + the return address will not be corrupted by futher pops. */ + regs_available_for_popping &= ~ (1 << reg_containing_return_addr); + } + + /* If we popped other registers then handle them here. */ + if (regs_available_for_popping) + { + int frame_pointer; + + /* Work out which register currently contains the frame pointer. */ + frame_pointer = number_of_first_bit_set (regs_available_for_popping); + + /* Move it into the correct place. */ + asm_fprintf (f, "\tmov\tfp, %s\n", reg_names [frame_pointer]); + + /* (Temporarily) remove it from the mask of popped registers. */ + regs_available_for_popping &= ~ (1 << frame_pointer); + regs_to_pop &= ~ (1 << FRAME_POINTER); + + if (regs_available_for_popping) + { + int stack_pointer; + + /* We popped the stack pointer as well, find the register that + contains it.*/ + stack_pointer = number_of_first_bit_set (regs_available_for_popping); + + /* Move it into the stack register. */ + asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [stack_pointer]); + + /* At this point we have popped all necessary registers, so + do not worry about restoring regs_available_for_popping + to its correct value: + + assert (pops_needed == 0) + assert (regs_available_for_popping == (1 << frame_pointer)) + assert (regs_to_pop == (1 << STACK_POINTER)) */ + } + else + { + /* Since we have just move the popped value into the frame + pointer, the popping register is available for reuse, and + we know that we still have the stack pointer left to pop. */ + regs_available_for_popping |= (1 << frame_pointer); + } + } + + /* If we still have registers left on the stack, but we no longer have + any registers into which we can pop them, then we must move the return + address into the link register and make available the register that + contained it. */ + if (regs_available_for_popping == 0 && pops_needed > 0) + { + regs_available_for_popping |= 1 << reg_containing_return_addr; + + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [LINK_REGISTER], + reg_names [reg_containing_return_addr]); + + reg_containing_return_addr = LINK_REGISTER; + } + + /* If we have registers left on the stack then pop some more. + We know that at most we will want to pop FP and SP. */ + if (pops_needed > 0) + { + int popped_into; + int move_to; + + thumb_pushpop (f, regs_available_for_popping, FALSE); + + /* We have popped either FP or SP. + Move whichever one it is into the correct register. */ + popped_into = number_of_first_bit_set (regs_available_for_popping); + move_to = number_of_first_bit_set (regs_to_pop); + + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [move_to], reg_names [popped_into]); + + regs_to_pop &= ~ (1 << move_to); + + -- pops_needed; + } + + /* If we still have not popped everything then we must have only + had one register available to us and we are now popping the SP. */ + if (pops_needed > 0) + { + int popped_into; + + thumb_pushpop (f, regs_available_for_popping, FALSE); + + popped_into = number_of_first_bit_set (regs_available_for_popping); + + asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [popped_into]); + + /* + assert (regs_to_pop == (1 << STACK_POINTER)) + assert (pops_needed == 1) + */ + } + + /* If necessary restore the a4 register. */ + if (restore_a4) + { + if (reg_containing_return_addr != LINK_REGISTER) + { + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]); + reg_containing_return_addr = LINK_REGISTER; + } + + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [ARG_4_REGISTER], reg_names [IP_REGISTER]); + } + + /* Return to caller. */ + asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]); +} + +/* Emit code to push or pop registers to or from the stack. */ +static void +thumb_pushpop (f, mask, push) + FILE * f; + int mask; + int push; +{ + int regno; + int lo_mask = mask & 0xFF; + + if (lo_mask == 0 && ! push && (mask & (1 << 15))) + { + /* Special case. Do not generate a POP PC statement here, do it in + thumb_exit() */ + + thumb_exit (f, -1); + return; + } + + asm_fprintf (f, "\t%s\t{", push ? "push" : "pop"); + + /* Look at the low registers first. */ + + for (regno = 0; regno < 8; regno ++, lo_mask >>= 1) + { + if (lo_mask & 1) + { + asm_fprintf (f, reg_names[regno]); + + if ((lo_mask & ~1) != 0) + asm_fprintf (f, ", "); + } + } + + if (push && (mask & (1 << 14))) + { + /* Catch pushing the LR. */ + + if (mask & 0xFF) + asm_fprintf (f, ", "); + + asm_fprintf (f, reg_names[14]); + } + else if (!push && (mask & (1 << 15))) + { + /* Catch popping the PC. */ + + if (TARGET_THUMB_INTERWORK || TARGET_BACKTRACE) + { + /* The PC is never poped directly, instead + it is popped into r3 and then BX is used. */ + + asm_fprintf (f, "}\n"); + + thumb_exit (f, -1); + + return; + } + else + { + if (mask & 0xFF) + asm_fprintf (f, ", "); + + asm_fprintf (f, reg_names[15]); + } + } + + asm_fprintf (f, "}\n"); +} + +/* Returns non-zero if the current function contains a far jump */ + +int +far_jump_used_p (void) +{ + rtx insn; + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + if (GET_CODE (insn) == JUMP_INSN + /* Ignore tablejump patterns. */ + && GET_CODE (PATTERN (insn)) != ADDR_VEC + && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC + && get_attr_far_jump (insn) == FAR_JUMP_YES) + return 1; + } + + return 0; +} + +static int return_used_this_function = 0; + +char * +output_return () +{ + int regno; + int live_regs_mask = 0; + + /* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + /* If a function is naked, don't use the "return" insn. */ + if (arm_naked_function_p (current_function_decl)) + return ""; +#endif + /* END CYGNUS LOCAL nickc/thumb-pe */ + + return_used_this_function = 1; + + for (regno = 0; regno < 8; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + live_regs_mask |= 1 << regno; + + if (live_regs_mask == 0) + { + if (leaf_function_p () && ! far_jump_used_p()) + { + thumb_exit (asm_out_file, 14); + } + else if ( TARGET_THUMB_INTERWORK + || TARGET_BACKTRACE + || is_called_in_ARM_mode (current_function_decl)) + { + thumb_exit (asm_out_file, -1); + } + else + asm_fprintf (asm_out_file, "\tpop\t{pc}\n"); + } + else + { + asm_fprintf (asm_out_file, "\tpop\t{"); + + for (regno = 0; live_regs_mask; regno ++, live_regs_mask >>= 1) + if (live_regs_mask & 1) + { + asm_fprintf (asm_out_file, reg_names[regno]); + if (live_regs_mask & ~1) + asm_fprintf (asm_out_file, ", "); + } + + if ( TARGET_THUMB_INTERWORK + || TARGET_BACKTRACE + || is_called_in_ARM_mode (current_function_decl)) + { + asm_fprintf (asm_out_file, "}\n"); + thumb_exit (asm_out_file, -1); + } + else + asm_fprintf (asm_out_file, ", pc}\n"); + } + + return ""; +} + +void +thumb_function_prologue (f, frame_size) + FILE *f; + int frame_size; +{ + int amount = frame_size + current_function_outgoing_args_size; + int live_regs_mask = 0; + int high_regs_pushed = 0; + int store_arg_regs = 0; + int regno; + +/* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + if (arm_naked_function_p (current_function_decl)) + return; +#endif +/* CYGNUS LOCAL nickc/thumb-pe */ + + if (is_called_in_ARM_mode (current_function_decl)) + { + char * name; + if (GET_CODE (DECL_RTL (current_function_decl)) != MEM) + abort(); + if (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0)) != SYMBOL_REF) + abort(); + name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); + + /* Generate code sequence to switch us into Thumb mode. */ + /* The .code 32 directive has already been emitted by + ASM_DECLARE_FUNCITON_NAME */ + asm_fprintf (f, "\torr\tr12, pc, #1\n"); + asm_fprintf (f, "\tbx\tr12\n"); + + /* Generate a label, so that the debugger will notice the + change in instruction sets. This label is also used by + the assembler to bypass the ARM code when this function + is called from a Thumb encoded function elsewhere in the + same file. Hence the definition of STUB_NAME here must + agree with the definition in gas/config/tc-arm.c */ + +#define STUB_NAME ".real_start_of" + + asm_fprintf (f, "\t.code\t16\n"); + asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name); + asm_fprintf (f, "\t.thumb_func\n"); + asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name); + } + + if (current_function_anonymous_args && current_function_pretend_args_size) + store_arg_regs = 1; + + if (current_function_pretend_args_size) + { + if (store_arg_regs) + { + asm_fprintf (f, "\tpush\t{"); + for (regno = 4 - current_function_pretend_args_size / 4 ; regno < 4; + regno++) + asm_fprintf (f, "%s%s", reg_names[regno], regno == 3 ? "" : ", "); + asm_fprintf (f, "}\n"); + } + else + asm_fprintf (f, "\tsub\t%Rsp, %Rsp, #%d\n", + current_function_pretend_args_size); + } + + for (regno = 0; regno < 8; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + live_regs_mask |= 1 << regno; + + if (live_regs_mask || ! leaf_function_p () || far_jump_used_p()) + live_regs_mask |= 1 << 14; + + if (TARGET_BACKTRACE) + { + char * name; + int offset; + int work_register = 0; + + + /* We have been asked to create a stack backtrace structure. + The code looks like this: + + 0 .align 2 + 0 func: + 0 sub SP, #16 Reserve space for 4 registers. + 2 push {R7} Get a work register. + 4 add R7, SP, #20 Get the stack pointer before the push. + 6 str R7, [SP, #8] Store the stack pointer (before reserving the space). + 8 mov R7, PC Get hold of the start of this code plus 12. + 10 str R7, [SP, #16] Store it. + 12 mov R7, FP Get hold of the current frame pointer. + 14 str R7, [SP, #4] Store it. + 16 mov R7, LR Get hold of the current return address. + 18 str R7, [SP, #12] Store it. + 20 add R7, SP, #16 Point at the start of the backtrace structure. + 22 mov FP, R7 Put this value into the frame pointer. */ + + if ((live_regs_mask & 0xFF) == 0) + { + /* See if the a4 register is free. */ + + if (regs_ever_live[ 3 ] == 0) + work_register = 3; + else /* We must push a register of our own */ + live_regs_mask |= (1 << 7); + } + + if (work_register == 0) + { + /* Select a register from the list that will be pushed to use as our work register. */ + + for (work_register = 8; work_register--;) + if ((1 << work_register) & live_regs_mask) + break; + } + + name = reg_names[ work_register ]; + + asm_fprintf (f, "\tsub\tsp, sp, #16\t@ Create stack backtrace structure\n"); + + if (live_regs_mask) + thumb_pushpop (f, live_regs_mask, 1); + + for (offset = 0, work_register = 1 << 15; work_register; work_register >>= 1) + if (work_register & live_regs_mask) + offset += 4; + + asm_fprintf (f, "\tadd\t%s, sp, #%d\n", + name, offset + 16 + current_function_pretend_args_size); + + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 4); + + /* Make sure that the instruction fetching the PC is in the right place + to calculate "start of backtrace creation code + 12". */ + + if (live_regs_mask) + { + asm_fprintf (f, "\tmov\t%s, pc\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); + asm_fprintf (f, "\tmov\t%s, fp\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); + } + else + { + asm_fprintf (f, "\tmov\t%s, fp\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); + asm_fprintf (f, "\tmov\t%s, pc\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); + } + + asm_fprintf (f, "\tmov\t%s, lr\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 8); + asm_fprintf (f, "\tadd\t%s, sp, #%d\n", name, offset + 12); + asm_fprintf (f, "\tmov\tfp, %s\t\t@ Backtrace structure created\n", name); + } + else if (live_regs_mask) + thumb_pushpop (f, live_regs_mask, 1); + + for (regno = 8; regno < 13; regno++) + { + if (regs_ever_live[regno] && ! call_used_regs[regno]) + high_regs_pushed++; + } + + if (high_regs_pushed) + { + int pushable_regs = 0; + int mask = live_regs_mask & 0xff; + int next_hi_reg; + + for (next_hi_reg = 12; next_hi_reg > 7; next_hi_reg--) + { + if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) + break; + } + + pushable_regs = mask; + + if (pushable_regs == 0) + { + /* desperation time -- this probably will never happen */ + if (regs_ever_live[3] || ! call_used_regs[3]) + asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[12], reg_names[3]); + mask = 1 << 3; + } + + while (high_regs_pushed > 0) + { + for (regno = 7; regno >= 0; regno--) + { + if (mask & (1 << regno)) + { + asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[regno], + reg_names[next_hi_reg]); + high_regs_pushed--; + if (high_regs_pushed) + for (next_hi_reg--; next_hi_reg > 7; next_hi_reg--) + { + if (regs_ever_live[next_hi_reg] + && ! call_used_regs[next_hi_reg]) + break; + } + else + { + mask &= ~ ((1 << regno) - 1); + break; + } + } + } + thumb_pushpop (f, mask, 1); + } + + if (pushable_regs == 0 && (regs_ever_live[3] || ! call_used_regs[3])) + asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[3], reg_names[12]); + } +} + +void +thumb_expand_prologue () +{ + HOST_WIDE_INT amount = (get_frame_size () + + current_function_outgoing_args_size); + int regno; + int live_regs_mask; + + /* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + /* Naked functions don't have prologues. */ + if (arm_naked_function_p (current_function_decl)) + return; +#endif + /* END CYGNUS LOCAL nickc/thumb-pe */ + + if (amount) + { + live_regs_mask = 0; + for (regno = 0; regno < 8; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + live_regs_mask |= 1 << regno; + + if (amount < 512) + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (-amount))); + else + { + rtx reg, spare; + + if ((live_regs_mask & 0xff) == 0) /* Very unlikely */ + emit_insn (gen_movsi (spare = gen_rtx (REG, SImode, 12), + reg = gen_rtx (REG, SImode, 4))); + else + { + for (regno = 0; regno < 8; regno++) + if (live_regs_mask & (1 << regno)) + break; + reg = gen_rtx (REG, SImode, regno); + } + + emit_insn (gen_movsi (reg, GEN_INT (-amount))); + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); + if ((live_regs_mask & 0xff) == 0) + emit_insn (gen_movsi (reg, spare)); + } + } + + if (frame_pointer_needed) + { + if (current_function_outgoing_args_size) + { + rtx offset = GEN_INT (current_function_outgoing_args_size); + + if (current_function_outgoing_args_size < 1024) + emit_insn (gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx, + offset)); + else + { + emit_insn (gen_movsi (frame_pointer_rtx, offset)); + emit_insn (gen_addsi3 (frame_pointer_rtx, frame_pointer_rtx, + stack_pointer_rtx)); + } + } + else + emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx)); + } + + /* if (profile_flag || profile_block_flag) */ + emit_insn (gen_blockage ()); +} + +void +thumb_expand_epilogue () +{ + HOST_WIDE_INT amount = (get_frame_size () + + current_function_outgoing_args_size); + int regno; + + /* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + /* Naked functions don't have epilogues. */ + if (arm_naked_function_p (current_function_decl)) + return; +#endif + /* END CYGNUS LOCAL nickc/thumb-pe */ + + if (amount) + { + if (amount < 512) + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (amount))); + else + { + rtx reg = gen_rtx (REG, SImode, 3); /* Always free in the epilogue */ + + emit_insn (gen_movsi (reg, GEN_INT (amount))); + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); + } + /* if (profile_flag || profile_block_flag) */ + emit_insn (gen_blockage ()); + } +} + +void +thumb_function_epilogue (f, frame_size) + FILE *f; + int frame_size; +{ + /* ??? Probably not safe to set this here, since it assumes that a + function will be emitted as assembly immediately after we generate + RTL for it. This does not happen for inline functions. */ + return_used_this_function = 0; +#if 0 /* TODO : comment not really needed */ + fprintf (f, "%s THUMB Epilogue\n", ASM_COMMENT_START); +#endif +} + +/* The bits which aren't usefully expanded as rtl. */ +char * +thumb_unexpanded_epilogue () +{ + int regno; + int live_regs_mask = 0; + int high_regs_pushed = 0; + int leaf_function = leaf_function_p (); + int had_to_push_lr; + + if (return_used_this_function) + return ""; + + for (regno = 0; regno < 8; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + live_regs_mask |= 1 << regno; + + for (regno = 8; regno < 13; regno++) + { + if (regs_ever_live[regno] && ! call_used_regs[regno]) + high_regs_pushed ++; + } + + /* The prolog may have pushed some high registers to use as + work registers. eg the testuite file: + gcc/testsuite/gcc/gcc.c-torture/execute/complex-2.c + compiles to produce: + push {r4, r5, r6, r7, lr} + mov r7, r9 + mov r6, r8 + push {r6, r7} + as part of the prolog. We have to undo that pushing here. */ + + if (high_regs_pushed) + { + int mask = live_regs_mask; + int next_hi_reg; + int size; + int mode; + +#ifdef RTX_CODE + /* If we can deduce the registers used from the function's return value. + This is more reliable that examining regs_ever_live[] because that + will be set if the register is ever used in the function, not just if + the register is used to hold a return value. */ + + if (current_function_return_rtx != 0) + { + mode = GET_MODE (current_function_return_rtx); + } + else +#endif + { + mode = DECL_MODE (DECL_RESULT (current_function_decl)); + } + + size = GET_MODE_SIZE (mode); + + /* Unless we are returning a type of size > 12 register r3 is available. */ + if (size < 13) + mask |= 1 << 3; + + if (mask == 0) + { + /* Oh dear! We have no low registers into which we can pop high registers! */ + + fatal ("No low registers available for popping high registers"); + } + + for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++) + if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) + break; + + while (high_regs_pushed) + { + /* Find low register(s) into which the high register(s) can be popped. */ + for (regno = 0; regno < 8; regno++) + { + if (mask & (1 << regno)) + high_regs_pushed--; + if (high_regs_pushed == 0) + break; + } + + mask &= (2 << regno) - 1; /* A noop if regno == 8 */ + + /* Pop the values into the low register(s). */ + thumb_pushpop (asm_out_file, mask, 0); + + /* Move the value(s) into the high registers. */ + for (regno = 0; regno < 8; regno++) + { + if (mask & (1 << regno)) + { + asm_fprintf (asm_out_file, "\tmov\t%s, %s\n", + reg_names[next_hi_reg], reg_names[regno]); + for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++) + if (regs_ever_live[next_hi_reg] && + ! call_used_regs[next_hi_reg]) + break; + } + } + } + } + + had_to_push_lr = (live_regs_mask || ! leaf_function || far_jump_used_p()); + + if (TARGET_BACKTRACE && ((live_regs_mask & 0xFF) == 0) && regs_ever_live[ ARG_4_REGISTER ] != 0) + { + /* The stack backtrace structure creation code had to + push R7 in order to get a work register, so we pop + it now. */ + + live_regs_mask |= (1 << WORK_REGISTER); + } + + if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE) + { + if (had_to_push_lr + && ! is_called_in_ARM_mode (current_function_decl)) + live_regs_mask |= 1 << PROGRAM_COUNTER; + + /* Either no argument registers were pushed or a backtrace + structure was created which includes an adjusted stack + pointer, so just pop everything. */ + + if (live_regs_mask) + thumb_pushpop (asm_out_file, live_regs_mask, FALSE); + + /* We have either just popped the return address into the + PC or it is was kept in LR for the entire function or + it is still on the stack because we do not want to + return by doing a pop {pc}. */ + + if ((live_regs_mask & (1 << PROGRAM_COUNTER)) == 0) + thumb_exit (asm_out_file, + (had_to_push_lr + && is_called_in_ARM_mode (current_function_decl)) ? + -1 : LINK_REGISTER); + } + else + { + /* Pop everything but the return address. */ + live_regs_mask &= ~ (1 << PROGRAM_COUNTER); + + if (live_regs_mask) + thumb_pushpop (asm_out_file, live_regs_mask, FALSE); + + if (had_to_push_lr) + { + /* Get the return address into a temporary register. */ + thumb_pushpop (asm_out_file, 1 << ARG_4_REGISTER, 0); + } + + /* Remove the argument registers that were pushed onto the stack. */ + asm_fprintf (asm_out_file, "\tadd\t%s, %s, #%d\n", + reg_names [STACK_POINTER], + reg_names [STACK_POINTER], + current_function_pretend_args_size); + + thumb_exit (asm_out_file, had_to_push_lr ? ARG_4_REGISTER : LINK_REGISTER); + } + + return ""; +} + +/* Handle the case of a double word load into a low register from + a computed memory address. The computed address may involve a + register which is overwritten by the load. */ + +char * +thumb_load_double_from_address (operands) + rtx * operands; +{ + rtx addr; + rtx base; + rtx offset; + rtx arg1; + rtx arg2; + + if (GET_CODE (operands[0]) != REG) + fatal ("thumb_load_double_from_address: destination is not a register"); + + if (GET_CODE (operands[1]) != MEM) + fatal ("thumb_load_double_from_address: source is not a computed memory address"); + + /* Get the memory address. */ + + addr = XEXP (operands[1], 0); + + /* Work out how the memory address is computed. */ + + switch (GET_CODE (addr)) + { + case REG: + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); + + if (REGNO (operands[0]) == REGNO (addr)) + { + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + } + else + { + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + } + break; + + case CONST: + /* Compute
+ 4 for the high order load. */ + + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); + + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + break; + + case PLUS: + arg1 = XEXP (addr, 0); + arg2 = XEXP (addr, 1); + + if (CONSTANT_P (arg1)) + base = arg2, offset = arg1; + else + base = arg1, offset = arg2; + + if (GET_CODE (base) != REG) + fatal ("thumb_load_double_from_address: base is not a register"); + + /* Catch the case of
= + */ + + if (GET_CODE (offset) == REG) + { + int reg_offset = REGNO (offset); + int reg_base = REGNO (base); + int reg_dest = REGNO (operands[0]); + + /* Add the base and offset registers together into the higher destination register. */ + + fprintf (asm_out_file, "\tadd\t%s, %s, %s\t\t%s created by thumb_load_double_from_address", + reg_names[ reg_dest + 1 ], + reg_names[ reg_base ], + reg_names[ reg_offset ], + ASM_COMMENT_START); + + /* Load the lower destination register from the address in the higher destination register. */ + + fprintf (asm_out_file, "\tldr\t%s, [%s, #0]\t\t%s created by thumb_load_double_from_address", + reg_names[ reg_dest ], + reg_names[ reg_dest + 1], + ASM_COMMENT_START); + + /* Load the higher destination register from its own address plus 4. */ + + fprintf (asm_out_file, "\tldr\t%s, [%s, #4]\t\t%s created by thumb_load_double_from_address", + reg_names[ reg_dest + 1 ], + reg_names[ reg_dest + 1 ], + ASM_COMMENT_START); + } + else + { + /* Compute
+ 4 for the high order load. */ + + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); + + /* If the computed address is held in the low order register + then load the high order register first, otherwise always + load the low order register first. */ + + if (REGNO (operands[0]) == REGNO (base)) + { + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + } + else + { + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + } + } + break; + + case LABEL_REF: + /* With no registers to worry about we can just load the value directly. */ + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); + + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + break; + + default: + debug_rtx (operands[1]); + fatal ("thumb_load_double_from_address: Unhandled address calculation"); + break; + } + + return ""; +} + +char * +output_move_mem_multiple (n, operands) + int n; + rtx *operands; +{ + rtx tmp; + + switch (n) + { + case 2: + if (REGNO (operands[2]) > REGNO (operands[3])) + { + tmp = operands[2]; + operands[2] = operands[3]; + operands[3] = tmp; + } + output_asm_insn ("ldmia\t%1!, {%2, %3}", operands); + output_asm_insn ("stmia\t%0!, {%2, %3}", operands); + break; + + case 3: + if (REGNO (operands[2]) > REGNO (operands[3])) + { + tmp = operands[2]; + operands[2] = operands[3]; + operands[3] = tmp; + } + if (REGNO (operands[3]) > REGNO (operands[4])) + { + tmp = operands[3]; + operands[3] = operands[4]; + operands[4] = tmp; + } + if (REGNO (operands[2]) > REGNO (operands[3])) + { + tmp = operands[2]; + operands[2] = operands[3]; + operands[3] = tmp; + } + output_asm_insn ("ldmia\t%1!, {%2, %3, %4}", operands); + output_asm_insn ("stmia\t%0!, {%2, %3, %4}", operands); + break; + + default: + abort (); + } + + return ""; +} + + +int +thumb_epilogue_size () +{ + return 42; /* The answer to .... */ +} + +static char *conds[] = +{ + "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", + "hi", "ls", "ge", "lt", "gt", "le" +}; + +static char * +thumb_condition_code (x, invert) + rtx x; + int invert; +{ + int val; + + switch (GET_CODE (x)) + { + case EQ: val = 0; break; + case NE: val = 1; break; + case GEU: val = 2; break; + case LTU: val = 3; break; + case GTU: val = 8; break; + case LEU: val = 9; break; + case GE: val = 10; break; + case LT: val = 11; break; + case GT: val = 12; break; + case LE: val = 13; break; + default: + abort (); + } + + return conds[val ^ invert]; +} + +void +thumb_print_operand (f, x, code) + FILE *f; + rtx x; + int code; +{ + if (code) + { + switch (code) + { + case '@': + fputs (ASM_COMMENT_START, f); + return; + + case '_': + fputs (user_label_prefix, f); + return; + + case 'D': + if (x) + fputs (thumb_condition_code (x, 1), f); + return; + + case 'd': + if (x) + fputs (thumb_condition_code (x, 0), f); + return; + + /* An explanation of the 'Q', 'R' and 'H' register operands: + + In a pair of registers containing a DI or DF value the 'Q' + operand returns the register number of the register containing + the least signficant part of the value. The 'R' operand returns + the register number of the register containing the most + significant part of the value. + + The 'H' operand returns the higher of the two register numbers. + On a run where WORDS_BIG_ENDIAN is true the 'H' operand is the + same as the 'Q' operand, since the most signficant part of the + value is held in the lower number register. The reverse is true + on systems where WORDS_BIG_ENDIAN is false. + + The purpose of these operands is to distinguish between cases + where the endian-ness of the values is important (for example + when they are added together), and cases where the endian-ness + is irrelevant, but the order of register operations is important. + For example when loading a value from memory into a register + pair, the endian-ness does not matter. Provided that the value + from the lower memory address is put into the lower numbered + register, and the value from the higher address is put into the + higher numbered register, the load will work regardless of whether + the value being loaded is big-wordian or little-wordian. The + order of the two register loads can matter however, if the address + of the memory location is actually held in one of the registers + being overwritten by the load. */ + case 'Q': + if (REGNO (x) > 15) + abort (); + fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0)], f); + return; + + case 'R': + if (REGNO (x) > 15) + abort (); + fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1)], f); + return; + + case 'H': + if (REGNO (x) > 15) + abort (); + fputs (reg_names[REGNO (x) + 1], f); + return; + + case 'c': + /* We use 'c' operands with symbols for .vtinherit */ + if (GET_CODE (x) == SYMBOL_REF) + output_addr_const(f, x); + return; + + default: + abort (); + } + } + if (GET_CODE (x) == REG) + fputs (reg_names[REGNO (x)], f); + else if (GET_CODE (x) == MEM) + output_address (XEXP (x, 0)); + else if (GET_CODE (x) == CONST_INT) + { + fputc ('#', f); + output_addr_const (f, x); + } + else + abort (); +} + +#ifdef AOF_ASSEMBLER +int arm_text_section_count = 1; + +char * +aof_text_section (in_readonly) + int in_readonly; +{ + static char buf[100]; + if (in_readonly) + return ""; + sprintf (buf, "\tCODE16\n\tAREA |C$$code%d|, CODE, READONLY", + arm_text_section_count++); + return buf; +} + +static int arm_data_section_count = 1; + +char * +aof_data_section () +{ + static char buf[100]; + sprintf (buf, "\tAREA |C$$data%d|, DATA", arm_data_section_count++); + return buf; +} + +/* The AOF thumb assembler is religiously strict about declarations of + imported and exported symbols, so that it is impossible to declare a + function as imported near the begining of the file, and then to export + it later on. It is, however, possible to delay the decision until all + the functions in the file have been compiled. To get around this, we + maintain a list of the imports and exports, and delete from it any that + are subsequently defined. At the end of compilation we spit the + remainder of the list out before the END directive. */ + +struct import +{ + struct import *next; + char *name; +}; + +static struct import *imports_list = NULL; + +void +thumb_aof_add_import (name) + char *name; +{ + struct import *new; + + for (new = imports_list; new; new = new->next) + if (new->name == name) + return; + + new = (struct import *) xmalloc (sizeof (struct import)); + new->next = imports_list; + imports_list = new; + new->name = name; +} + +void +thumb_aof_delete_import (name) + char *name; +{ + struct import **old; + + for (old = &imports_list; *old; old = & (*old)->next) + { + if ((*old)->name == name) + { + *old = (*old)->next; + return; + } + } +} + +void +thumb_aof_dump_imports (f) + FILE *f; +{ + while (imports_list) + { + fprintf (f, "\tIMPORT\t"); + assemble_name (f, imports_list->name); + fputc ('\n', f); + imports_list = imports_list->next; + } +} +#endif + +/* Decide whether a type should be returned in memory (true) + or in a register (false). This is called by the macro + RETURN_IN_MEMORY. */ + +int +thumb_return_in_memory (type) + tree type; +{ + if (! AGGREGATE_TYPE_P (type)) + { + /* All simple types are returned in registers. */ + + return 0; + } + else if (int_size_in_bytes (type) > 4) + { + /* All structures/unions bigger than one word are returned in memory. */ + + return 1; + } + else if (TREE_CODE (type) == RECORD_TYPE) + { + tree field; + + /* For a struct the APCS says that we must return in a register if + every addressable element has an offset of zero. For practical + purposes this means that the structure can have at most one non- + bit-field element and that this element must be the first one in + the structure. */ + + /* Find the first field, ignoring non FIELD_DECL things which will + have been created by C++. */ + for (field = TYPE_FIELDS (type); + field && TREE_CODE (field) != FIELD_DECL; + field = TREE_CHAIN (field)) + continue; + + if (field == NULL) + return 0; /* An empty structure. Allowed by an extension to ANSI C. */ + + /* Now check the remaining fields, if any. */ + for (field = TREE_CHAIN (field); field; field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + + if (! DECL_BIT_FIELD_TYPE (field)) + return 1; + } + + return 0; + } + else if (TREE_CODE (type) == UNION_TYPE) + { + tree field; + + /* Unions can be returned in registers if every element is + integral, or can be returned in an integer register. */ + + for (field = TYPE_FIELDS (type); + field; + field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + + if (RETURN_IN_MEMORY (TREE_TYPE (field))) + return 1; + } + + return 0; + } + /* XXX Not sure what should be done for other aggregates, so put them in + memory. */ + return 1; +} + +void +thumb_override_options () +{ + if (structure_size_string != NULL) + { + int size = strtol (structure_size_string, NULL, 0); + + if (size == 8 || size == 32) + arm_structure_size_boundary = size; + else + warning ("Structure size boundary can only be set to 8 or 32"); + } + + if (flag_pic) + { + warning ("Position independent code not supported. Ignored"); + flag_pic = 0; + } +} + +/* CYGNUS LOCAL nickc/thumb-pe */ + +#ifdef THUMB_PE +/* Return nonzero if ATTR is a valid attribute for DECL. + ATTRIBUTES are any existing attributes and ARGS are the arguments + supplied with ATTR. + + Supported attributes: + + naked: don't output any prologue or epilogue code, the user is assumed + to do the right thing. + + interfacearm: Always assume that this function will be entered in ARM + mode, not Thumb mode, and that the caller wishes to be returned to in + ARM mode. */ +int +arm_valid_machine_decl_attribute (decl, attributes, attr, args) + tree decl; + tree attributes; + tree attr; + tree args; +{ + if (args != NULL_TREE) + return 0; + + if (is_attribute_p ("naked", attr)) + return TREE_CODE (decl) == FUNCTION_DECL; + + if (is_attribute_p ("interfacearm", attr)) + return TREE_CODE (decl) == FUNCTION_DECL; + + return 0; +} +#endif /* THUMB_PE */ +/* END CYGNUS LOCAL nickc/thumb-pe */ + +/* s_register_operand is the same as register_operand, but it doesn't accept + (SUBREG (MEM)...). + + This function exists because at the time it was put in it led to better + code. SUBREG(MEM) always needs a reload in the places where + s_register_operand is used, and this seemed to lead to excessive + reloading. */ + +int +s_register_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + if (GET_MODE (op) != mode && mode != VOIDmode) + return 0; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + /* We don't consider registers whose class is NO_REGS + to be a register operand. */ + /* XXX might have to check for lo regs only for thumb ??? */ + return (GET_CODE (op) == REG + && (REGNO (op) >= FIRST_PSEUDO_REGISTER + || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); +} diff --git a/gcc_arm/config/arm/thumb_010110a.md b/gcc_arm/config/arm/thumb_010110a.md new file mode 100755 index 0000000..29a75bb --- /dev/null +++ b/gcc_arm/config/arm/thumb_010110a.md @@ -0,0 +1,1166 @@ +;; thumb.md Machine description for ARM/Thumb processors +;; Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. +;; The basis of this contribution was generated by +;; Richard Earnshaw, Advanced RISC Machines Ltd + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;; LENGTH of an instruction is 2 bytes +(define_attr "length" "" (const_int 2)) + +;; CONDS is set to UNCHANGED when an insn does not affect the condition codes +;; Most insns change the condition codes +(define_attr "conds" "changed,unchanged" (const_string "changed")) + +;; FAR_JUMP is "yes" if a BL instruction is used to generate a branch to a +;; distant label. +(define_attr "far_jump" "yes,no" (const_string "no")) + +;; Start with move insns + +(define_expand "movsi" + [(set (match_operand:SI 0 "general_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (SImode, operands[1]); + } +") + +(define_insn "*movsi_insn" + [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l,m,*r,*h") + (match_operand:SI 1 "general_operand" "l,I,J,K,>,l,mi,l,*h,*r"))] + "register_operand (operands[0], SImode) + || register_operand (operands[1], SImode)" + "@ + add\\t%0, %1, #0 + mov\\t%0, %1 + # + # + ldmia\\t%1, {%0} + stmia\\t%0, {%1} + ldr\\t%0, %1 + str\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1" +[(set_attr "length" "2,2,4,4,2,2,2,2,2,2")]) + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "thumb_shiftable_const (INTVAL (operands[1]))" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))] + " +{ + unsigned HOST_WIDE_INT val = INTVAL (operands[1]); + unsigned HOST_WIDE_INT mask = 0xff; + int i; + for (i = 0; i < 25; i++) + if ((val & (mask << i)) == val) + break; + + if (i == 0) + FAIL; + + operands[1] = GEN_INT (val >> i); + operands[2] = GEN_INT (i); +}") + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "INTVAL (operands[1]) < 0 && INTVAL (operands[1]) > -256" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 0) (neg:SI (match_dup 0)))] + " + operands[1] = GEN_INT (- INTVAL (operands[1])); +") + +;;(define_expand "reload_outsi" +;; [(set (match_operand:SI 2 "register_operand" "=&l") +;; (match_operand:SI 1 "register_operand" "h")) +;; (set (match_operand:SI 0 "reload_memory_operand" "=o") +;; (match_dup 2))] +;; "" +;; " +;;/* thumb_reload_out_si (operands); +;; DONE; */ +;;") + +(define_expand "movhi" + [(set (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + " +{ + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (HImode, operands[1]); + + /* ??? We shouldn't really get invalid addresses here, but this can + happen if we are passed a SP (never OK for HImode/QImode) or virtual + register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) + relative address. */ + /* ??? This should perhaps be fixed elsewhere, for instance, in + fixup_stack_1, by checking for other kinds of invalid addresses, + e.g. a bare reference to a virtual register. This may confuse the + alpha though, which must handle this case differently. */ + if (GET_CODE (operands[0]) == MEM + && ! memory_address_p (GET_MODE (operands[0]), + XEXP (operands[0], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[0], 0)); + operands[0] = change_address (operands[0], VOIDmode, temp); + } + if (GET_CODE (operands[1]) == MEM + && ! memory_address_p (GET_MODE (operands[1]), + XEXP (operands[1], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[1], 0)); + operands[1] = change_address (operands[1], VOIDmode, temp); + } + } + /* Handle loading a large integer during reload */ + else if (GET_CODE (operands[1]) == CONST_INT + && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) + { + /* Writing a constant to memory needs a scratch, which should + be handled with SECONDARY_RELOADs. */ + if (GET_CODE (operands[0]) != REG) + abort (); + + operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); + emit_insn (gen_movsi (operands[0], operands[1])); + DONE; + } +}") + +(define_insn "*movhi_insn" + [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") + (match_operand:HI 1 "general_operand" "l,m,l,*h,*r,I"))] + "register_operand (operands[0], HImode) + || register_operand (operands[1], HImode)" + "@ + add\\t%0, %1, #0 + ldrh\\t%0, %1 + strh\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1 + mov\\t%0, %1") + +(define_expand "movqi" + [(set (match_operand:QI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" + " +{ + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (QImode, operands[1]); + + /* ??? We shouldn't really get invalid addresses here, but this can + happen if we are passed a SP (never OK for HImode/QImode) or virtual + register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) + relative address. */ + /* ??? This should perhaps be fixed elsewhere, for instance, in + fixup_stack_1, by checking for other kinds of invalid addresses, + e.g. a bare reference to a virtual register. This may confuse the + alpha though, which must handle this case differently. */ + if (GET_CODE (operands[0]) == MEM + && ! memory_address_p (GET_MODE (operands[0]), + XEXP (operands[0], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[0], 0)); + operands[0] = change_address (operands[0], VOIDmode, temp); + } + if (GET_CODE (operands[1]) == MEM + && ! memory_address_p (GET_MODE (operands[1]), + XEXP (operands[1], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[1], 0)); + operands[1] = change_address (operands[1], VOIDmode, temp); + } + } + /* Handle loading a large integer during reload */ + else if (GET_CODE (operands[1]) == CONST_INT + && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) + { + /* Writing a constant to memory needs a scratch, which should + be handled with SECONDARY_RELOADs. */ + if (GET_CODE (operands[0]) != REG) + abort (); + + operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); + emit_insn (gen_movsi (operands[0], operands[1])); + DONE; + } +}") + +(define_insn "*movqi_insn" + [(set (match_operand:QI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") + (match_operand:QI 1 "general_operand" "l,m,l,*h,*r,I"))] + "register_operand (operands[0], QImode) + || register_operand (operands[1], QImode)" + "@ + add\\t%0, %1, #0 + ldrb\\t%0, %1 + strb\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1 + mov\\t%0, %1") + +(define_expand "movdi" + [(set (match_operand:DI 0 "general_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (DImode, operands[1]); + } +") + +;;; ??? This should have alternatives for constants. +;;; ??? This was originally identical to the movdf_insn pattern. +;;; ??? The 'i' constraint looks funny, but it should always be replaced by +;;; thumb_reorg with a memory reference. +(define_insn "*movdi_insn" + [(set (match_operand:DI 0 "general_operand" "=l,l,l,l,>,l,m,*r") + (match_operand:DI 1 "general_operand" "l,I,J,>,l,mi,l,*r"))] + "register_operand (operands[0], DImode) + || register_operand (operands[1], DImode)" + "* +{ + switch (which_alternative) + { + case 0: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; + return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; + case 1: + return \"mov\\t%Q0, %1\;mov\\t%R0, #0\"; + case 2: + operands[1] = GEN_INT (- INTVAL (operands[1])); + return \"mov\\t%Q0, %1\;neg\\t%Q0, %Q0\;asr\\t%R0, %Q0, #31\"; + case 3: + return \"ldmia\\t%1, {%0, %H0}\"; + case 4: + return \"stmia\\t%0, {%1, %H1}\"; + case 5: + return thumb_load_double_from_address (operands); + case 6: + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); + output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); + return \"\"; + case 7: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; + return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; + } +}"[(set_attr "length" "4,4,6,2,2,6,4,4")]) + +(define_expand "movdf" + [(set (match_operand:DF 0 "general_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (DFmode, operands[1]); + } +") + +;;; ??? This should have alternatives for constants. +;;; ??? This was originally identical to the movdi_insn pattern. +;;; ??? The 'F' constraint looks funny, but it should always be replaced by +;;; thumb_reorg with a memory reference. +(define_insn "*movdf_insn" + [(set (match_operand:DF 0 "general_operand" "=l,l,>,l,m,*r") + (match_operand:DF 1 "general_operand" "l,>,l,mF,l,*r"))] + "register_operand (operands[0], DFmode) + || register_operand (operands[1], DFmode)" + "* + switch (which_alternative) + { + case 0: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; + return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; + case 1: + return \"ldmia\\t%1, {%0, %H0}\"; + case 2: + return \"stmia\\t%0, {%1, %H1}\"; + case 3: + return thumb_load_double_from_address (operands); + case 4: + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); + output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); + return \"\"; + case 5: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; + return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; + } +"[(set_attr "length" "4,2,2,6,4,4")]) + +(define_expand "movsf" + [(set (match_operand:SF 0 "general_operand" "") + (match_operand:SF 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (SFmode, operands[1]); + } +") + +;;; ??? This should have alternatives for constants. +(define_insn "*movsf_insn" + [(set (match_operand:SF 0 "nonimmediate_operand" "=l,l,>,l,m,*r,*h") + (match_operand:SF 1 "general_operand" "l,>,l,mF,l,*h,*r"))] + "register_operand (operands[0], SFmode) + || register_operand (operands[1], SFmode)" + "@ + add\\t%0, %1, #0 + ldmia\\t%1, {%0} + stmia\\t%0, {%1} + ldr\\t%0, %1 + str\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1") + +;; Widening move insns + +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "s_register_operand" "") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (HImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); + emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (16))); + DONE; + } +") + +(define_insn "*zero_extendhisi2_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + "" + "ldrh\\t%0, %1") + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "s_register_operand" "") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (QImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); + emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (24))); + DONE; + } +") + +(define_insn "*zero_extendqisi2_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + "" + "ldrb\\t%0, %1") + +(define_expand "extendhisi2" + [(parallel [(set (match_operand:SI 0 "s_register_operand" "") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" ""))) + (clobber (match_scratch:SI 2 ""))])] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (HImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); + emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (16))); + DONE; + } +") + +(define_insn "*extendhisi2_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))) + (clobber (match_scratch:SI 2 "=&l"))] + "" + "* +{ + rtx ops[4]; + /* This code used to try to use 'V', and fix the address only if it was + offsettable, but this fails for e.g. REG+48 because 48 is outside the + range of QImode offsets, and offsettable_address_p does a QImode + address check. */ + + if (GET_CODE (XEXP (operands[1], 0)) == PLUS) + { + ops[1] = XEXP (XEXP (operands[1], 0), 0); + ops[2] = XEXP (XEXP (operands[1], 0), 1); + } + else + { + ops[1] = XEXP (operands[1], 0); + ops[2] = const0_rtx; + } + if (GET_CODE (ops[2]) == REG) + return \"ldrsh\\t%0, %1\"; + + ops[0] = operands[0]; + ops[3] = operands[2]; + output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops); + return \"\"; +}" +[(set_attr "length" "4")]) + +(define_expand "extendqisi2" + [(set (match_operand:SI 0 "s_register_operand" "") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (QImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); + emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (24))); + DONE; + } +") + +(define_insn "*extendqisi2_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))] + "" + "* +{ + rtx ops[3]; + + if (which_alternative == 0) + return \"ldrsb\\t%0, %1\"; + ops[0] = operands[0]; + if (GET_CODE (XEXP (operands[1], 0)) == PLUS) + { + ops[1] = XEXP (XEXP (operands[1], 0), 0); + ops[2] = XEXP (XEXP (operands[1], 0), 1); + + if (GET_CODE (ops[1]) == REG && GET_CODE (ops[2]) == REG) + output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops); + else if (GET_CODE (ops[1]) == REG) + { + if (REGNO (ops[1]) == REGNO (operands[0])) + output_asm_insn (\"ldrb\\t%0, [%1, %2]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); + else + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + else + { + if (REGNO (ops[2]) == REGNO (operands[0])) + output_asm_insn (\"ldrb\\t%0, [%2, %1]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); + else + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + } + else if (REGNO (operands[0]) == REGNO (XEXP (operands[1], 0))) + { + output_asm_insn (\"ldrb\\t%0, [%0, #0]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); + } + else + { + ops[1] = XEXP (operands[1], 0); + ops[2] = const0_rtx; + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + return \"\"; +}" +[(set_attr "length" "2,6")]) + +;; We don't really have extzv, but defining this using shifts helps +;; to reduce register pressure later on. + +(define_expand "extzv" + [(set (match_dup 4) + (ashift:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "const_int_operand" ""))) + (set (match_operand:SI 0 "register_operand" "") + (lshiftrt:SI (match_dup 4) + (match_operand:SI 3 "const_int_operand" "")))] + "" + " +{ + HOST_WIDE_INT lshift = 32 - INTVAL (operands[2]) - INTVAL (operands[3]); + HOST_WIDE_INT rshift = 32 - INTVAL (operands[2]); + operands[3] = GEN_INT (rshift); + if (lshift == 0) + { + emit_insn (gen_lshrsi3 (operands[0], operands[1], operands[3])); + DONE; + } + operands[2] = GEN_INT (lshift); + operands[4] = gen_reg_rtx (SImode); +} +") + +;; Block-move insns + +(define_expand "movstrqi" + [(match_operand:BLK 0 "general_operand" "") + (match_operand:BLK 1 "general_operand" "") + (match_operand:SI 2 "" "") + (match_operand:SI 3 "const_int_operand" "")] + "" + " + if (INTVAL (operands[3]) != 4 + || GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) > 48) + FAIL; + + thumb_expand_movstrqi (operands); + DONE; +") + +(define_insn "movmem12b" + [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) + (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) + (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (mem:SI (plus:SI (match_dup 0) (const_int 8))) + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_dup 0) (plus:SI (match_dup 0) (const_int 12))) + (set (match_dup 1) (plus:SI (match_dup 1) (const_int 12))) + (clobber (match_scratch:SI 2 "=&l")) + (clobber (match_scratch:SI 3 "=&l")) + (clobber (match_scratch:SI 4 "=&l"))] + "" + "* return output_move_mem_multiple (3, operands);" +[(set_attr "length" "4")]) + +(define_insn "movmem8b" + [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) + (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) + (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_dup 0) (plus:SI (match_dup 0) (const_int 8))) + (set (match_dup 1) (plus:SI (match_dup 1) (const_int 8))) + (clobber (match_scratch:SI 2 "=&l")) + (clobber (match_scratch:SI 3 "=&l"))] + "" + "* return output_move_mem_multiple (2, operands);" +[(set_attr "length" "4")]) + +;; Arithmetic insns + +(define_insn "adddi3" + [(set (match_operand:DI 0 "s_register_operand" "=l") + (plus:DI (match_operand:DI 1 "s_register_operand" "%0") + (match_operand:DI 2 "s_register_operand" "l")))] + "" + "add\\t%Q0, %Q0, %Q2\;adc\\t%R0, %R0, %R2" +[(set_attr "conds" "changed") + (set_attr "length" "8")]) + +;; register group 'k' is a single register group containing only the stack +;; register. Trying to reload it will always fail catastrophically, +;; so never allow those alternatives to match if reloading is needed. +(define_insn "addsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l,l,l,*r,*h,l,!k") + (plus:SI (match_operand:SI 1 "s_register_operand" "%0,0,l,*0,*0,!k,!k") + (match_operand:SI 2 "nonmemory_operand" "I,J,lL,*h,*r,!M,!O")))] + "" + "* + static char *asms[] = +{ + \"add\\t%0, %0, %2\", + \"sub\\t%0, %0, #%n2\", + \"add\\t%0, %1, %2\", + \"add\\t%0, %0, %2\", + \"add\\t%0, %0, %2\", + \"add\\t%0, %1, %2\", + \"add\\t%0, %1, %2\" +}; + if (which_alternative == 2 && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) < 0) + return \"sub\\t%0, %1, #%n2\"; + return asms[which_alternative]; +") + +; reloading and elimination of the frame pointer can sometimes cause this +; optimization to be missed. +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=l") + (match_operand:SI 1 "const_int_operand" "M")) + (set (match_dup 0) + (plus:SI (match_dup 0) (match_operand:SI 2 "register_operand" "k")))] + "REGNO (operands[2]) == STACK_POINTER_REGNUM + && (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) < 1024 + && (INTVAL (operands[1]) & 3) == 0" + "add\\t%0, %2, %1") + +(define_insn "subdi3" + [(set (match_operand:DI 0 "s_register_operand" "=l") + (minus:DI (match_operand:DI 1 "s_register_operand" "0") + (match_operand:DI 2 "s_register_operand" "l")))] + "" + "sub\\t%Q0, %Q0, %Q2\;sbc\\t%R0, %R0, %R2" +[(set_attr "conds" "changed") + (set_attr "length" "8")]) + +(define_insn "subsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (minus:SI (match_operand:SI 1 "s_register_operand" "l") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "sub\\t%0, %1, %2") + +;; We must ensure that one input matches the output, and that the other input +;; does not match the output. Using 0 satisfies the first, and using & +;; satisfies the second. Unfortunately, this fails when operands 1 and 2 +;; are the same, because reload will make operand 0 match operand 1 without +;; realizing that this conflicts with operand 2. We fix this by adding another +;; alternative to match this case, and then `reload' it ourselves. This +;; alternative must come first. +(define_insn "mulsi3" + [(set (match_operand:SI 0 "s_register_operand" "=&l,&l,&l") + (mult:SI (match_operand:SI 1 "s_register_operand" "%l,*h,0") + (match_operand:SI 2 "s_register_operand" "l,l,l")))] + "" + "* +{ + if (which_alternative < 2) + return \"mov\\t%0, %1\;mul\\t%0, %0, %2\"; + else + return \"mul\\t%0, %0, %2\"; +}" + [(set_attr "length" "4,4,2")]) + +(define_insn "negsi2" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (neg:SI (match_operand:SI 1 "s_register_operand" "l")))] + "" + "neg\\t%0, %1") + +;; Logical insns + +(define_expand "andsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (and:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] + "" + " + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = force_reg (SImode, operands[2]); + else + { + int i; + if (((unsigned HOST_WIDE_INT) ~ INTVAL (operands[2])) < 256) + { + operands[2] = force_reg (SImode, GEN_INT (~INTVAL (operands[2]))); + emit_insn (gen_bicsi3 (operands[0], operands[2], operands[1])); + DONE; + } + + for (i = 9; i <= 31; i++) + if ((((HOST_WIDE_INT) 1) << i) - 1 == INTVAL (operands[2])) + { + emit_insn (gen_extzv (operands[0], operands[1], GEN_INT (i), + const0_rtx)); + DONE; + } + else if ((((HOST_WIDE_INT) 1) << i) - 1 == ~ INTVAL (operands[2])) + { + rtx shift = GEN_INT (i); + rtx reg = gen_reg_rtx (SImode); + emit_insn (gen_lshrsi3 (reg, operands[1], shift)); + emit_insn (gen_ashlsi3 (operands[0], reg, shift)); + DONE; + } + + operands[2] = force_reg (SImode, operands[2]); + } +") + +(define_insn "*andsi3_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (and:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "and\\t%0, %0, %2") + +(define_insn "bicsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (and:SI (not:SI (match_operand:SI 1 "s_register_operand" "l")) + (match_operand:SI 2 "s_register_operand" "0")))] + "" + "bic\\t%0, %0, %1") + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (ior:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "orr\\t%0, %0, %2") + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (xor:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "eor\\t%0, %0, %2") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (not:SI (match_operand:SI 1 "s_register_operand" "l")))] + "" + "mvn\\t%0, %1") + +;; Shift and rotation insns + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (ashift:SI (match_operand:SI 1 "s_register_operand" "l,0") + (match_operand:SI 2 "nonmemory_operand" "N,l")))] + "" + "@ + lsl\\t%0, %1, %2 + lsl\\t%0, %0, %2") + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (ashiftrt:SI (match_operand:SI 1 "s_register_operand" "l,0") + (match_operand:SI 2 "nonmemory_operand" "N,l")))] + "" + "@ + asr\\t%0, %1, %2 + asr\\t%0, %0, %2") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (lshiftrt:SI (match_operand:SI 1 "s_register_operand" "l,0") + (match_operand:SI 2 "nonmemory_operand" "N,l")))] + "" + "@ + lsr\\t%0, %1, %2 + lsr\\t%0, %0, %2") + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (rotatert:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "ror\\t%0, %0, %2") + +;; Comparison insns + +(define_expand "cmpsi" + [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "") + (match_operand:SI 1 "nonmemory_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != REG && GET_CODE (operands[1]) != SUBREG) + { + if (GET_CODE (operands[1]) != CONST_INT + || (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) >= 256) + { + if (GET_CODE (operands[1]) != CONST_INT + || INTVAL (operands[1]) < -255 + || INTVAL (operands[1]) > 0) + operands[1] = force_reg (SImode, operands[1]); + else + { + operands[1] = force_reg (SImode, + GEN_INT (- INTVAL (operands[1]))); + emit_insn (gen_cmnsi (operands[0], operands[1])); + DONE; + } + } + } +") + +(define_insn "*cmpsi_insn" + [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "l,*r,*h") + (match_operand:SI 1 "thumb_cmp_operand" "lI,*h,*r")))] + "" + "@ + cmp\\t%0, %1 + cmp\\t%0, %1 + cmp\\t%0, %1") + +(define_insn "tstsi" + [(set (cc0) (match_operand:SI 0 "s_register_operand" "l"))] + "" + "cmp\\t%0, #0") + +(define_insn "cmnsi" + [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "l") + (neg:SI (match_operand:SI 1 "s_register_operand" "l"))))] + "" + "cmn\\t%0, %1") + +;; Jump insns + +(define_insn "jump" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "" + "* + if (get_attr_length (insn) == 2) + return \"b\\t%l0\"; + return \"bl\\t%l0\\t%@ far jump\"; +"[(set (attr "far_jump") + (if_then_else (eq_attr "length" "4") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2048)) + (le (minus (match_dup 0) (pc)) (const_int 2044))) + (const_int 2) + (const_int 4)))]) + + +(define_expand "beq" + [(set (pc) (if_then_else (eq (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bne" + [(set (pc) (if_then_else (ne (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bge" + [(set (pc) (if_then_else (ge (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "ble" + [(set (pc) (if_then_else (le (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bgt" + [(set (pc) (if_then_else (gt (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "blt" + [(set (pc) (if_then_else (lt (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bgeu" + [(set (pc) (if_then_else (geu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bleu" + [(set (pc) (if_then_else (leu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bgtu" + [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bltu" + [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_insn "*cond_branch" + [(set (pc) (if_then_else (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + switch (get_attr_length (insn)) + { + case 2: return \"b%d1\\t%l0\\t%@cond_branch\"; + case 4: return \"b%D1\\t.LCB%=\;b\\t%l0\\t%@long jump\\n.LCB%=:\"; + default: return \"b%D1\\t.LCB%=\;bl\\t%l0\\t%@far jump\\n.LCB%=:\"; + } +"[(set (attr "far_jump") + (if_then_else (eq_attr "length" "6") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 0) (pc)) (const_int -252)) + (le (minus (match_dup 0) (pc)) (const_int 254))) + (const_int 2) + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) + (le (minus (match_dup 0) (pc)) (const_int 2044))) + (const_int 4) + (const_int 6))))]) + +(define_insn "*cond_branch_reversed" + [(set (pc) (if_then_else (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + switch (get_attr_length (insn)) + { + case 2: return \"b%D1\\t%l0\\t%@cond_branch_reversed\"; + case 4: return \"b%d1\\t.LCBR%=\;b\\t%l0\\t%@long jump\\n.LCBR%=:\"; + default: return \"b%d1\\t.LCBR%=\;bl\\t%l0\\t%@far jump\\n.LCBR%=:\"; + } + return \"\"; +"[(set (attr "far_jump") + (if_then_else (eq_attr "length" "6") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 0) (pc)) (const_int -252)) + (le (minus (match_dup 0) (pc)) (const_int 254))) + (const_int 2) + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) + (le (minus (match_dup 0) (pc)) (const_int 2044))) + (const_int 4) + (const_int 6))))]) + +(define_insn "indirect_jump" + [(set (pc) (match_operand:SI 0 "s_register_operand" "l*r"))] + "" + "mov\\tpc, %0") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "s_register_operand" "l*r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "mov\\tpc, %0") + +(define_insn "return" + [(return)] + "USE_RETURN" + "* return output_return ();" +[(set_attr "length" "18")]) + +;; Call insns + +(define_expand "call" + [(call (match_operand:SI 0 "memory_operand" "") + (match_operand 1 "" ""))] + "" + "") + +(define_insn "*call_indirect" + [(call (mem:SI (match_operand:SI 0 "s_register_operand" "l*r")) + (match_operand 1 "" ""))] + "! TARGET_CALLER_INTERWORKING" + "bl\\t%__call_via_%0" +[(set_attr "length" "4")]) +;; The non THUMB_INTERWORK, non TARGET_CALLER_INTERWORKING version +;; used to be: "mov\\tlr,pc\;bx\\t%0", but the mov does not set +;; the bottom bit of lr so that a function return (using bx) +;; would switch back into ARM mode... + +(define_insn "*call_indirect_interwork" + [(call (mem:SI (match_operand:SI 0 "s_register_operand" "l*r")) + (match_operand 1 "" ""))] + "TARGET_CALLER_INTERWORKING" + "bl\\t%__interwork_call_via_%0" +[(set_attr "length" "4")]) + +(define_expand "call_value" + [(set (match_operand 0 "" "") + (call (match_operand 1 "memory_operand" "") + (match_operand 2 "" "")))] + "" + "") + +(define_insn "*call_value_indirect" + [(set (match_operand 0 "" "=l") + (call (mem:SI (match_operand:SI 1 "s_register_operand" "l*r")) + (match_operand 2 "" "")))] + "! TARGET_CALLER_INTERWORKING" + "bl\\t%__call_via_%1" +[(set_attr "length" "4")]) +;; See comment for call_indirect pattern + +(define_insn "*call_value_indirect_interwork" + [(set (match_operand 0 "" "=l") + (call (mem:SI (match_operand:SI 1 "s_register_operand" "l*r")) + (match_operand 2 "" "")))] + "TARGET_CALLER_INTERWORKING" + "bl\\t%__interwork_call_via_%1" +[(set_attr "length" "4")]) + + +(define_insn "*call_insn" + [(call (mem:SI (match_operand:SI 0 "" "i")) + (match_operand:SI 1 "" ""))] + "GET_CODE (operands[0]) == SYMBOL_REF" + "bl\\t%a0" +[(set_attr "length" "4")]) + +(define_insn "*call_value_insn" + [(set (match_operand 0 "s_register_operand" "=l") + (call (mem:SI (match_operand 1 "" "i")) + (match_operand 2 "" "")))] + "GET_CODE (operands[1]) == SYMBOL_REF" + "bl\\t%a1" +[(set_attr "length" "4")]) + +;; Untyped call not required, since all funcs return in r0 + +;; Miscellaneous patterns + +(define_insn "nop" + [(clobber (const_int 0))] + "" + "mov\\tr8, r8") + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] 0)] + "" + "" + [(set_attr "length" "0")]) + +(define_expand "prologue" + [(const_int 0)] + "" + " + thumb_expand_prologue (); + DONE; +") + +(define_expand "epilogue" + [(unspec_volatile [(const_int 0)] 1)] + "! thumb_trivial_epilogue ()" + " + thumb_expand_epilogue (); +") + +(define_insn "*epilogue_insns" + [(unspec_volatile [(const_int 0)] 1)] + "" + "* + return thumb_unexpanded_epilogue (); +" +[(set_attr "length" "42")]) + +;; Special patterns for dealing with the constant pool + +(define_insn "consttable_4" + [(unspec_volatile [(match_operand 0 "" "")] 2)] + "" + "* +{ + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) + { + case MODE_FLOAT: + { + union real_extract u; + bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); + assemble_real (u.d, GET_MODE (operands[0])); + break; + } + default: + assemble_integer (operands[0], 4, 1); + break; + } + return \"\"; +}" +[(set_attr "length" "4")]) + +(define_insn "consttable_8" + [(unspec_volatile [(match_operand 0 "" "")] 3)] + "" + "* +{ + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) + { + case MODE_FLOAT: + { + union real_extract u; + bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); + assemble_real (u.d, GET_MODE (operands[0])); + break; + } + default: + assemble_integer (operands[0], 8, 1); + break; + } + return \"\"; +}" +[(set_attr "length" "8")]) + +(define_insn "consttable_end" + [(unspec_volatile [(const_int 0)] 4)] + "" + "* + /* Nothing to do (currently). */ + return \"\"; +") + +(define_insn "align_4" + [(unspec_volatile [(const_int 0)] 5)] + "" + "* + assemble_align (32); + return \"\"; +") diff --git a/gcc_arm/config/arm/thumb_010309a.c b/gcc_arm/config/arm/thumb_010309a.c new file mode 100755 index 0000000..778cda9 --- /dev/null +++ b/gcc_arm/config/arm/thumb_010309a.c @@ -0,0 +1,2132 @@ +/* Output routines for GCC for ARM/Thumb + Copyright (C) 1996 Cygnus Software Technologies Ltd + The basis of this contribution was generated by + Richard Earnshaw, Advanced RISC Machines Ltd + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include +#include +#include "config.h" +#include "rtl.h" +#include "hard-reg-set.h" +#include "regs.h" +#include "output.h" +#include "insn-flags.h" +#include "insn-attr.h" +#include "flags.h" +#include "tree.h" +#include "expr.h" + + +int current_function_anonymous_args = 0; +static int current_function_has_far_jump = 0; + +/* Used to parse -mstructure_size_boundary command line option. */ +char * structure_size_string = NULL; +int arm_structure_size_boundary = 32; /* Used to be 8 */ + + +/* Predicates */ +int +reload_memory_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + int regno = true_regnum (op); + + return (! CONSTANT_P (op) + && (regno == -1 + || (GET_CODE (op) == REG + && REGNO (op) >= FIRST_PSEUDO_REGISTER))); +} + +/* Return nonzero if op is suitable for the RHS of a cmp instruction. */ +int +thumb_cmp_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return ((GET_CODE (op) == CONST_INT + && (unsigned HOST_WIDE_INT) (INTVAL (op)) < 256) + || register_operand (op, mode)); +} + +int +thumb_shiftable_const (val) + HOST_WIDE_INT val; +{ + unsigned HOST_WIDE_INT x = val; + unsigned HOST_WIDE_INT mask = 0xff; + int i; + + for (i = 0; i < 25; i++) + if ((val & (mask << i)) == val) + return 1; + + return 0; +} + +int +thumb_trivial_epilogue () +{ + int regno; + + /* ??? If this function ever returns 1, we get a function without any + epilogue at all. It appears that the intent was to cause a "return" + insn to be emitted, but that does not happen. */ + return 0; + +#if 0 + if (get_frame_size () + || current_function_outgoing_args_size + || current_function_pretend_args_size) + return 0; + + for (regno = 8; regno < 13; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + return 0; + + return 1; +#endif +} + + +/* Routines for handling the constant pool */ +/* This is unashamedly hacked from the version in sh.c, since the problem is + extremely similar. */ + +/* Thumb instructions cannot load a large constant into a register, + constants have to come from a pc relative load. The reference of a pc + relative load instruction must be less than 1k infront of the instruction. + This means that we often have to dump a constant inside a function, and + generate code to branch around it. + + It is important to minimize this, since the branches will slow things + down and make things bigger. + + Worst case code looks like: + + ldr rn, L1 + b L2 + align + L1: .long value + L2: + .. + + ldr rn, L3 + b L4 + align + L3: .long value + L4: + .. + + We fix this by performing a scan before scheduling, which notices which + instructions need to have their operands fetched from the constant table + and builds the table. + + + The algorithm is: + + scan, find an instruction which needs a pcrel move. Look forward, find the + last barrier which is within MAX_COUNT bytes of the requirement. + If there isn't one, make one. Process all the instructions between + the find and the barrier. + + In the above example, we can tell that L3 is within 1k of L1, so + the first move can be shrunk from the 2 insn+constant sequence into + just 1 insn, and the constant moved to L3 to make: + + ldr rn, L1 + .. + ldr rn, L3 + b L4 + align + L1: .long value + L3: .long value + L4: + + Then the second move becomes the target for the shortening process. + + */ + +typedef struct +{ + rtx value; /* Value in table */ + HOST_WIDE_INT next_offset; + enum machine_mode mode; /* Mode of value */ +} pool_node; + +/* The maximum number of constants that can fit into one pool, since + the pc relative range is 0...1020 bytes and constants are at least 4 + bytes long */ + +#define MAX_POOL_SIZE (1020/4) +static pool_node pool_vector[MAX_POOL_SIZE]; +static int pool_size; +static rtx pool_vector_label; + +/* Add a constant to the pool and return its label. */ + +static HOST_WIDE_INT +add_constant (x, mode) + rtx x; + enum machine_mode mode; +{ + int i; + rtx lab; + HOST_WIDE_INT offset; + + if (mode == SImode && GET_CODE (x) == MEM && CONSTANT_P (XEXP (x, 0)) + && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0))) + x = get_pool_constant (XEXP (x, 0)); + + /* First see if we've already got it */ + + for (i = 0; i < pool_size; i++) + { + if (x->code == pool_vector[i].value->code + && mode == pool_vector[i].mode) + { + if (x->code == CODE_LABEL) + { + if (XINT (x, 3) != XINT (pool_vector[i].value, 3)) + continue; + } + if (rtx_equal_p (x, pool_vector[i].value)) + return pool_vector[i].next_offset - GET_MODE_SIZE (mode); + } + } + + /* Need a new one */ + + pool_vector[pool_size].next_offset = GET_MODE_SIZE (mode); + offset = 0; + if (pool_size == 0) + pool_vector_label = gen_label_rtx (); + else + pool_vector[pool_size].next_offset + += (offset = pool_vector[pool_size - 1].next_offset); + + pool_vector[pool_size].value = x; + pool_vector[pool_size].mode = mode; + pool_size++; + return offset; +} + +/* Output the literal table */ + +static void +dump_table (scan) + rtx scan; +{ + int i; + + scan = emit_label_after (gen_label_rtx (), scan); + scan = emit_insn_after (gen_align_4 (), scan); + scan = emit_label_after (pool_vector_label, scan); + + for (i = 0; i < pool_size; i++) + { + pool_node *p = pool_vector + i; + + switch (GET_MODE_SIZE (p->mode)) + { + case 4: + scan = emit_insn_after (gen_consttable_4 (p->value), scan); + break; + + case 8: + scan = emit_insn_after (gen_consttable_8 (p->value), scan); + break; + + default: + abort (); + break; + } + } + + scan = emit_insn_after (gen_consttable_end (), scan); + scan = emit_barrier_after (scan); + pool_size = 0; +} + +/* Non zero if the src operand needs to be fixed up */ +static +int +fixit (src, mode) + rtx src; + enum machine_mode mode; +{ + return ((CONSTANT_P (src) + && (GET_CODE (src) != CONST_INT + || ! (CONST_OK_FOR_LETTER_P (INTVAL (src), 'I') + || CONST_OK_FOR_LETTER_P (INTVAL (src), 'J') + || (mode != DImode + && CONST_OK_FOR_LETTER_P (INTVAL (src), 'K'))))) + || (mode == SImode && GET_CODE (src) == MEM + && GET_CODE (XEXP (src, 0)) == SYMBOL_REF + && CONSTANT_POOL_ADDRESS_P (XEXP (src, 0)))); +} + +/* Find the last barrier less than MAX_COUNT bytes from FROM, or create one. */ + +#define MAX_COUNT_SI 1000 + +static rtx +find_barrier (from) + rtx from; +{ + int count = 0; + rtx found_barrier = 0; + rtx label; + + while (from && count < MAX_COUNT_SI) + { + if (GET_CODE (from) == BARRIER) + return from; + + /* Count the length of this insn */ + if (GET_CODE (from) == INSN + && GET_CODE (PATTERN (from)) == SET + && CONSTANT_P (SET_SRC (PATTERN (from))) + && CONSTANT_POOL_ADDRESS_P (SET_SRC (PATTERN (from)))) + { + rtx src = SET_SRC (PATTERN (from)); + count += 2; + } + else + count += get_attr_length (from); + + from = NEXT_INSN (from); + } + + /* We didn't find a barrier in time to + dump our stuff, so we'll make one */ + label = gen_label_rtx (); + + if (from) + from = PREV_INSN (from); + else + from = get_last_insn (); + + /* Walk back to be just before any jump */ + while (GET_CODE (from) == JUMP_INSN + || GET_CODE (from) == NOTE + || GET_CODE (from) == CODE_LABEL) + from = PREV_INSN (from); + + from = emit_jump_insn_after (gen_jump (label), from); + JUMP_LABEL (from) = label; + found_barrier = emit_barrier_after (from); + emit_label_after (label, found_barrier); + return found_barrier; +} + +/* Non zero if the insn is a move instruction which needs to be fixed. */ + +static int +broken_move (insn) + rtx insn; +{ + if (!INSN_DELETED_P (insn) + && GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == SET) + { + rtx pat = PATTERN (insn); + rtx src = SET_SRC (pat); + rtx dst = SET_DEST (pat); + enum machine_mode mode = GET_MODE (dst); + if (dst == pc_rtx) + return 0; + return fixit (src, mode); + } + return 0; +} + +/* Recursively search through all of the blocks in a function + checking to see if any of the variables created in that + function match the RTX called 'orig'. If they do then + replace them with the RTX called 'new'. */ + +static void +replace_symbols_in_block (tree block, rtx orig, rtx new) +{ + for (; block; block = BLOCK_CHAIN (block)) + { + tree sym; + + if (! TREE_USED (block)) + continue; + + for (sym = BLOCK_VARS (block); sym; sym = TREE_CHAIN (sym)) + { + if ( (DECL_NAME (sym) == 0 && TREE_CODE (sym) != TYPE_DECL) + || DECL_IGNORED_P (sym) + || TREE_CODE (sym) != VAR_DECL + || DECL_EXTERNAL (sym) + || ! rtx_equal_p (DECL_RTL (sym), orig) + ) + continue; + + DECL_RTL (sym) = new; + } + + replace_symbols_in_block (BLOCK_SUBBLOCKS (block), orig, new); + } +} + +void +thumb_reorg (first) + rtx first; +{ + rtx insn; + for (insn = first; insn; insn = NEXT_INSN (insn)) + { + if (broken_move (insn)) + { + /* This is a broken move instruction, scan ahead looking for + a barrier to stick the constant table behind */ + rtx scan; + rtx barrier = find_barrier (insn); + + /* Now find all the moves between the points and modify them */ + for (scan = insn; scan != barrier; scan = NEXT_INSN (scan)) + { + if (broken_move (scan)) + { + /* This is a broken move instruction, add it to the pool */ + rtx pat = PATTERN (scan); + rtx src = SET_SRC (pat); + rtx dst = SET_DEST (pat); + enum machine_mode mode = GET_MODE (dst); + HOST_WIDE_INT offset; + rtx newinsn; + rtx newsrc; + + /* If this is an HImode constant load, convert it into + an SImode constant load. Since the register is always + 32 bits this is safe. We have to do this, since the + load pc-relative instruction only does a 32-bit load. */ + if (mode == HImode) + { + mode = SImode; + if (GET_CODE (dst) != REG) + abort (); + PUT_MODE (dst, SImode); + } + + offset = add_constant (src, mode); + newsrc = gen_rtx (MEM, mode, + plus_constant (gen_rtx (LABEL_REF, + VOIDmode, + pool_vector_label), + offset)); + + /* Build a jump insn wrapper around the move instead + of an ordinary insn, because we want to have room for + the target label rtx in fld[7], which an ordinary + insn doesn't have. */ + newinsn = emit_jump_insn_after (gen_rtx (SET, VOIDmode, + dst, newsrc), scan); + JUMP_LABEL (newinsn) = pool_vector_label; + + /* But it's still an ordinary insn */ + PUT_CODE (newinsn, INSN); + + /* If debugging information is going to be emitted + then we must make sure that any refences to + symbols which are removed by the above code are + also removed in the descriptions of the + function's variables. Failure to do this means + that the debugging information emitted could + refer to symbols which are not emited by + output_constant_pool() because + mark_constant_pool() never sees them as being + used. */ + + + /* These are the tests used in + output_constant_pool() to decide if the constant + pool will be marked. Only necessary if debugging + info is being emitted. Only necessary for + references to memory whose address is given by a + symbol. */ + + if (optimize > 0 + && flag_expensive_optimizations + && write_symbols != NO_DEBUG + && GET_CODE (src) == MEM + && GET_CODE (XEXP (src, 0)) == SYMBOL_REF) + replace_symbols_in_block + (DECL_INITIAL (current_function_decl), src, newsrc); + + /* Kill old insn */ + delete_insn (scan); + scan = newinsn; + } + } + dump_table (barrier); + } + } +} + + +/* Routines for generating rtl */ + +void +thumb_expand_movstrqi (operands) + rtx *operands; +{ + rtx out = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); + rtx in = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); + HOST_WIDE_INT len = INTVAL (operands[2]); + HOST_WIDE_INT offset = 0; + + while (len >= 12) + { + emit_insn (gen_movmem12b (out, in)); + len -= 12; + } + if (len >= 8) + { + emit_insn (gen_movmem8b (out, in)); + len -= 8; + } + if (len >= 4) + { + rtx reg = gen_reg_rtx (SImode); + emit_insn (gen_movsi (reg, gen_rtx (MEM, SImode, in))); + emit_insn (gen_movsi (gen_rtx (MEM, SImode, out), reg)); + len -= 4; + offset += 4; + } + if (len >= 2) + { + rtx reg = gen_reg_rtx (HImode); + emit_insn (gen_movhi (reg, gen_rtx (MEM, HImode, + plus_constant (in, offset)))); + emit_insn (gen_movhi (gen_rtx (MEM, HImode, plus_constant (out, offset)), + reg)); + len -= 2; + offset += 2; + } + if (len) + { + rtx reg = gen_reg_rtx (QImode); + emit_insn (gen_movqi (reg, gen_rtx (MEM, QImode, + plus_constant (in, offset)))); + emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (out, offset)), + reg)); + } +} + + +/* Routines for reloading */ + +void +thumb_reload_out_si (operands) + rtx operands; +{ + abort (); +} + +/* CYGNUS LOCAL nickc/thumb-pe */ + +#ifdef THUMB_PE +/* Return non-zero if FUNC is a naked function. */ + +static int +arm_naked_function_p (func) + tree func; +{ + tree a; + + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + + a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func)); + return a != NULL_TREE; +} +#endif +/* END CYGNUS LOCAL nickc/thumb-pe */ + +/* Return non-zero if FUNC must be entered in ARM mode. */ +int +is_called_in_ARM_mode (func) + tree func; +{ + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + + /* Ignore the problem about functions whoes address is taken. */ + if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func)) + return TRUE; + +/* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + return lookup_attribute ("interfacearm", DECL_MACHINE_ATTRIBUTES (func)) != NULL_TREE; +#else + return FALSE; +#endif +/* END CYGNUS LOCAL */ +} + + +/* Routines for emitting code */ + +void +final_prescan_insn(insn) + rtx insn; +{ + extern int *insn_addresses; + + if (flag_print_asm_name) + fprintf (asm_out_file, "%s 0x%04x\n", ASM_COMMENT_START, + insn_addresses[INSN_UID (insn)]); +} + + +static void thumb_pushpop ( FILE *, int, int ); /* Forward declaration. */ + +#ifdef __GNUC__ +inline +#endif +static int +number_of_first_bit_set (mask) + int mask; +{ + int bit; + + for (bit = 0; + (mask & (1 << bit)) == 0; + ++ bit) + continue; + + return bit; +} + +#define ARG_1_REGISTER 0 +#define ARG_2_REGISTER 1 +#define ARG_3_REGISTER 2 +#define ARG_4_REGISTER 3 +#define WORK_REGISTER 7 +#define FRAME_POINTER 11 +#define IP_REGISTER 12 +#define STACK_POINTER STACK_POINTER_REGNUM +#define LINK_REGISTER 14 +#define PROGRAM_COUNTER 15 + +/* Generate code to return from a thumb function. If + 'reg_containing_return_addr' is -1, then the return address is + actually on the stack, at the stack pointer. */ +static void +thumb_exit (f, reg_containing_return_addr) + FILE * f; + int reg_containing_return_addr; +{ + int regs_available_for_popping; + int regs_to_pop; + int pops_needed; + int reg; + int available; + int required; + int mode; + int size; + int restore_a4 = FALSE; + + /* Compute the registers we need to pop. */ + regs_to_pop = 0; + pops_needed = 0; + + if (reg_containing_return_addr == -1) + { + regs_to_pop |= 1 << LINK_REGISTER; + ++ pops_needed; + } + + if (TARGET_BACKTRACE) + { + /* Restore frame pointer and stack pointer. */ + regs_to_pop |= (1 << FRAME_POINTER) | (1 << STACK_POINTER); + pops_needed += 2; + } + + /* If there is nothing to pop then just emit the BX instruction and return.*/ + if (pops_needed == 0) + { + asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]); + + return; + } + + /* Otherwise if we are not supporting interworking and we have not created + a backtrace structure and the function was not entered in ARM mode then + just pop the return address straight into the PC. */ + else if ( ! TARGET_THUMB_INTERWORK + && ! TARGET_BACKTRACE + && ! is_called_in_ARM_mode (current_function_decl)) + { + asm_fprintf (f, "\tpop\t{pc}\n" ); + + return; + } + + /* Find out how many of the (return) argument registers we can corrupt. */ + regs_available_for_popping = 0; + +#ifdef RTX_CODE + /* If we can deduce the registers used from the function's return value. + This is more reliable that examining regs_ever_live[] because that + will be set if the register is ever used in the function, not just if + the register is used to hold a return value. */ + + if (current_function_return_rtx != 0) + mode = GET_MODE (current_function_return_rtx); + else +#endif + mode = DECL_MODE (DECL_RESULT (current_function_decl)); + + size = GET_MODE_SIZE (mode); + + if (size == 0) + { + /* In a void function we can use any argument register. + In a function that returns a structure on the stack + we can use the second and third argument registers. */ + if (mode == VOIDmode) + regs_available_for_popping = + (1 << ARG_1_REGISTER) + | (1 << ARG_2_REGISTER) + | (1 << ARG_3_REGISTER); + else + regs_available_for_popping = + (1 << ARG_2_REGISTER) + | (1 << ARG_3_REGISTER); + } + else if (size <= 4) regs_available_for_popping = + (1 << ARG_2_REGISTER) + | (1 << ARG_3_REGISTER); + else if (size <= 8) regs_available_for_popping = + (1 << ARG_3_REGISTER); + + /* Match registers to be popped with registers into which we pop them. */ + for (available = regs_available_for_popping, + required = regs_to_pop; + required != 0 && available != 0; + available &= ~(available & - available), + required &= ~(required & - required)) + -- pops_needed; + + /* If we have any popping registers left over, remove them. */ + if (available > 0) + regs_available_for_popping &= ~ available; + + /* Otherwise if we need another popping register we can use + the fourth argument register. */ + else if (pops_needed) + { + /* If we have not found any free argument registers and + reg a4 contains the return address, we must move it. */ + if (regs_available_for_popping == 0 + && reg_containing_return_addr == ARG_4_REGISTER) + { + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]); + reg_containing_return_addr = LINK_REGISTER; + } + else if (size > 12) + { + /* Register a4 is being used to hold part of the return value, + but we have dire need of a free, low register. */ + restore_a4 = TRUE; + + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [IP_REGISTER], reg_names [ARG_4_REGISTER]); + } + + if (reg_containing_return_addr != ARG_4_REGISTER) + { + /* The fourth argument register is available. */ + regs_available_for_popping |= 1 << ARG_4_REGISTER; + + -- pops_needed; + } + } + + /* Pop as many registers as we can. */ + thumb_pushpop (f, regs_available_for_popping, FALSE); + + /* Process the registers we popped. */ + if (reg_containing_return_addr == -1) + { + /* The return address was popped into the lowest numbered register. */ + regs_to_pop &= ~ (1 << LINK_REGISTER); + + reg_containing_return_addr = + number_of_first_bit_set (regs_available_for_popping); + + /* Remove this register for the mask of available registers, so that + the return address will not be corrupted by futher pops. */ + regs_available_for_popping &= ~ (1 << reg_containing_return_addr); + } + + /* If we popped other registers then handle them here. */ + if (regs_available_for_popping) + { + int frame_pointer; + + /* Work out which register currently contains the frame pointer. */ + frame_pointer = number_of_first_bit_set (regs_available_for_popping); + + /* Move it into the correct place. */ + asm_fprintf (f, "\tmov\tfp, %s\n", reg_names [frame_pointer]); + + /* (Temporarily) remove it from the mask of popped registers. */ + regs_available_for_popping &= ~ (1 << frame_pointer); + regs_to_pop &= ~ (1 << FRAME_POINTER); + + if (regs_available_for_popping) + { + int stack_pointer; + + /* We popped the stack pointer as well, find the register that + contains it.*/ + stack_pointer = number_of_first_bit_set (regs_available_for_popping); + + /* Move it into the stack register. */ + asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [stack_pointer]); + + /* At this point we have popped all necessary registers, so + do not worry about restoring regs_available_for_popping + to its correct value: + + assert (pops_needed == 0) + assert (regs_available_for_popping == (1 << frame_pointer)) + assert (regs_to_pop == (1 << STACK_POINTER)) */ + } + else + { + /* Since we have just move the popped value into the frame + pointer, the popping register is available for reuse, and + we know that we still have the stack pointer left to pop. */ + regs_available_for_popping |= (1 << frame_pointer); + } + } + + /* If we still have registers left on the stack, but we no longer have + any registers into which we can pop them, then we must move the return + address into the link register and make available the register that + contained it. */ + if (regs_available_for_popping == 0 && pops_needed > 0) + { + regs_available_for_popping |= 1 << reg_containing_return_addr; + + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [LINK_REGISTER], + reg_names [reg_containing_return_addr]); + + reg_containing_return_addr = LINK_REGISTER; + } + + /* If we have registers left on the stack then pop some more. + We know that at most we will want to pop FP and SP. */ + if (pops_needed > 0) + { + int popped_into; + int move_to; + + thumb_pushpop (f, regs_available_for_popping, FALSE); + + /* We have popped either FP or SP. + Move whichever one it is into the correct register. */ + popped_into = number_of_first_bit_set (regs_available_for_popping); + move_to = number_of_first_bit_set (regs_to_pop); + + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [move_to], reg_names [popped_into]); + + regs_to_pop &= ~ (1 << move_to); + + -- pops_needed; + } + + /* If we still have not popped everything then we must have only + had one register available to us and we are now popping the SP. */ + if (pops_needed > 0) + { + int popped_into; + + thumb_pushpop (f, regs_available_for_popping, FALSE); + + popped_into = number_of_first_bit_set (regs_available_for_popping); + + asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [popped_into]); + + /* + assert (regs_to_pop == (1 << STACK_POINTER)) + assert (pops_needed == 1) + */ + } + + /* If necessary restore the a4 register. */ + if (restore_a4) + { + if (reg_containing_return_addr != LINK_REGISTER) + { + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]); + reg_containing_return_addr = LINK_REGISTER; + } + + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [ARG_4_REGISTER], reg_names [IP_REGISTER]); + } + + /* Return to caller. */ + asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]); +} + +/* Emit code to push or pop registers to or from the stack. */ +static void +thumb_pushpop (f, mask, push) + FILE * f; + int mask; + int push; +{ + int regno; + int lo_mask = mask & 0xFF; + + if (lo_mask == 0 && ! push && (mask & (1 << 15))) + { + /* Special case. Do not generate a POP PC statement here, do it in + thumb_exit() */ + + thumb_exit (f, -1); + return; + } + + asm_fprintf (f, "\t%s\t{", push ? "push" : "pop"); + + /* Look at the low registers first. */ + + for (regno = 0; regno < 8; regno ++, lo_mask >>= 1) + { + if (lo_mask & 1) + { + asm_fprintf (f, reg_names[regno]); + + if ((lo_mask & ~1) != 0) + asm_fprintf (f, ", "); + } + } + + if (push && (mask & (1 << 14))) + { + /* Catch pushing the LR. */ + + if (mask & 0xFF) + asm_fprintf (f, ", "); + + asm_fprintf (f, reg_names[14]); + } + else if (!push && (mask & (1 << 15))) + { + /* Catch popping the PC. */ + + if (TARGET_THUMB_INTERWORK || TARGET_BACKTRACE) + { + /* The PC is never poped directly, instead + it is popped into r3 and then BX is used. */ + + asm_fprintf (f, "}\n"); + + thumb_exit (f, -1); + + return; + } + else + { + if (mask & 0xFF) + asm_fprintf (f, ", "); + + asm_fprintf (f, reg_names[15]); + } + } + + asm_fprintf (f, "}\n"); +} + +/* Returns non-zero if the current function contains a far jump */ + +int +far_jump_used_p (void) +{ + rtx insn; + + if (current_function_has_far_jump) + return 1; + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + if (GET_CODE (insn) == JUMP_INSN + /* Ignore tablejump patterns. */ + && GET_CODE (PATTERN (insn)) != ADDR_VEC + && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC + && get_attr_far_jump (insn) == FAR_JUMP_YES) + { + current_function_has_far_jump = 1; + return 1; + } + } + + return 0; +} + +static int return_used_this_function = 0; + +char * +output_return () +{ + int regno; + int live_regs_mask = 0; + + /* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + /* If a function is naked, don't use the "return" insn. */ + if (arm_naked_function_p (current_function_decl)) + return ""; +#endif + /* END CYGNUS LOCAL nickc/thumb-pe */ + + return_used_this_function = 1; + + for (regno = 0; regno < 8; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + live_regs_mask |= 1 << regno; + + if (live_regs_mask == 0) + { + if (leaf_function_p () && ! far_jump_used_p()) + { + thumb_exit (asm_out_file, 14); + } + else if ( TARGET_THUMB_INTERWORK + || TARGET_BACKTRACE + || is_called_in_ARM_mode (current_function_decl)) + { + thumb_exit (asm_out_file, -1); + } + else + asm_fprintf (asm_out_file, "\tpop\t{pc}\n"); + } + else + { + asm_fprintf (asm_out_file, "\tpop\t{"); + + for (regno = 0; live_regs_mask; regno ++, live_regs_mask >>= 1) + if (live_regs_mask & 1) + { + asm_fprintf (asm_out_file, reg_names[regno]); + if (live_regs_mask & ~1) + asm_fprintf (asm_out_file, ", "); + } + + if ( TARGET_THUMB_INTERWORK + || TARGET_BACKTRACE + || is_called_in_ARM_mode (current_function_decl)) + { + asm_fprintf (asm_out_file, "}\n"); + thumb_exit (asm_out_file, -1); + } + else + asm_fprintf (asm_out_file, ", pc}\n"); + } + + return ""; +} + +void +thumb_function_prologue (f, frame_size) + FILE *f; + int frame_size; +{ + int amount = frame_size + current_function_outgoing_args_size; + int live_regs_mask = 0; + int high_regs_pushed = 0; + int store_arg_regs = 0; + int regno; + +/* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + if (arm_naked_function_p (current_function_decl)) + return; +#endif +/* CYGNUS LOCAL nickc/thumb-pe */ + + if (is_called_in_ARM_mode (current_function_decl)) + { + char * name; + if (GET_CODE (DECL_RTL (current_function_decl)) != MEM) + abort(); + if (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0)) != SYMBOL_REF) + abort(); + name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); + + /* Generate code sequence to switch us into Thumb mode. */ + /* The .code 32 directive has already been emitted by + ASM_DECLARE_FUNCITON_NAME */ + asm_fprintf (f, "\torr\tr12, pc, #1\n"); + asm_fprintf (f, "\tbx\tr12\n"); + + /* Generate a label, so that the debugger will notice the + change in instruction sets. This label is also used by + the assembler to bypass the ARM code when this function + is called from a Thumb encoded function elsewhere in the + same file. Hence the definition of STUB_NAME here must + agree with the definition in gas/config/tc-arm.c */ + +#define STUB_NAME ".real_start_of" + + asm_fprintf (f, "\t.code\t16\n"); + asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name); + asm_fprintf (f, "\t.thumb_func\n"); + asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name); + } + + if (current_function_anonymous_args && current_function_pretend_args_size) + store_arg_regs = 1; + + if (current_function_pretend_args_size) + { + if (store_arg_regs) + { + asm_fprintf (f, "\tpush\t{"); + for (regno = 4 - current_function_pretend_args_size / 4 ; regno < 4; + regno++) + asm_fprintf (f, "%s%s", reg_names[regno], regno == 3 ? "" : ", "); + asm_fprintf (f, "}\n"); + } + else + asm_fprintf (f, "\tsub\t%Rsp, %Rsp, #%d\n", + current_function_pretend_args_size); + } + + for (regno = 0; regno < 8; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + live_regs_mask |= 1 << regno; + + if (live_regs_mask || ! leaf_function_p () || far_jump_used_p()) + live_regs_mask |= 1 << 14; + + if (TARGET_BACKTRACE) + { + char * name; + int offset; + int work_register = 0; + + + /* We have been asked to create a stack backtrace structure. + The code looks like this: + + 0 .align 2 + 0 func: + 0 sub SP, #16 Reserve space for 4 registers. + 2 push {R7} Get a work register. + 4 add R7, SP, #20 Get the stack pointer before the push. + 6 str R7, [SP, #8] Store the stack pointer (before reserving the space). + 8 mov R7, PC Get hold of the start of this code plus 12. + 10 str R7, [SP, #16] Store it. + 12 mov R7, FP Get hold of the current frame pointer. + 14 str R7, [SP, #4] Store it. + 16 mov R7, LR Get hold of the current return address. + 18 str R7, [SP, #12] Store it. + 20 add R7, SP, #16 Point at the start of the backtrace structure. + 22 mov FP, R7 Put this value into the frame pointer. */ + + if ((live_regs_mask & 0xFF) == 0) + { + /* See if the a4 register is free. */ + + if (regs_ever_live[ 3 ] == 0) + work_register = 3; + else /* We must push a register of our own */ + live_regs_mask |= (1 << 7); + } + + if (work_register == 0) + { + /* Select a register from the list that will be pushed to use as our work register. */ + + for (work_register = 8; work_register--;) + if ((1 << work_register) & live_regs_mask) + break; + } + + name = reg_names[ work_register ]; + + asm_fprintf (f, "\tsub\tsp, sp, #16\t@ Create stack backtrace structure\n"); + + if (live_regs_mask) + thumb_pushpop (f, live_regs_mask, 1); + + for (offset = 0, work_register = 1 << 15; work_register; work_register >>= 1) + if (work_register & live_regs_mask) + offset += 4; + + asm_fprintf (f, "\tadd\t%s, sp, #%d\n", + name, offset + 16 + current_function_pretend_args_size); + + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 4); + + /* Make sure that the instruction fetching the PC is in the right place + to calculate "start of backtrace creation code + 12". */ + + if (live_regs_mask) + { + asm_fprintf (f, "\tmov\t%s, pc\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); + asm_fprintf (f, "\tmov\t%s, fp\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); + } + else + { + asm_fprintf (f, "\tmov\t%s, fp\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); + asm_fprintf (f, "\tmov\t%s, pc\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); + } + + asm_fprintf (f, "\tmov\t%s, lr\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 8); + asm_fprintf (f, "\tadd\t%s, sp, #%d\n", name, offset + 12); + asm_fprintf (f, "\tmov\tfp, %s\t\t@ Backtrace structure created\n", name); + } + else if (live_regs_mask) + thumb_pushpop (f, live_regs_mask, 1); + + for (regno = 8; regno < 13; regno++) + { + if (regs_ever_live[regno] && ! call_used_regs[regno]) + high_regs_pushed++; + } + + if (high_regs_pushed) + { + int pushable_regs = 0; + int mask = live_regs_mask & 0xff; + int next_hi_reg; + + for (next_hi_reg = 12; next_hi_reg > 7; next_hi_reg--) + { + if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) + break; + } + + pushable_regs = mask; + + if (pushable_regs == 0) + { + /* desperation time -- this probably will never happen */ + if (regs_ever_live[3] || ! call_used_regs[3]) + asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[12], reg_names[3]); + mask = 1 << 3; + } + + while (high_regs_pushed > 0) + { + for (regno = 7; regno >= 0; regno--) + { + if (mask & (1 << regno)) + { + asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[regno], + reg_names[next_hi_reg]); + high_regs_pushed--; + if (high_regs_pushed) + for (next_hi_reg--; next_hi_reg > 7; next_hi_reg--) + { + if (regs_ever_live[next_hi_reg] + && ! call_used_regs[next_hi_reg]) + break; + } + else + { + mask &= ~ ((1 << regno) - 1); + break; + } + } + } + thumb_pushpop (f, mask, 1); + } + + if (pushable_regs == 0 && (regs_ever_live[3] || ! call_used_regs[3])) + asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[3], reg_names[12]); + } +} + +void +thumb_expand_prologue () +{ + HOST_WIDE_INT amount = (get_frame_size () + + current_function_outgoing_args_size); + int regno; + int live_regs_mask; + + /* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + /* Naked functions don't have prologues. */ + if (arm_naked_function_p (current_function_decl)) + return; +#endif + /* END CYGNUS LOCAL nickc/thumb-pe */ + + if (amount) + { + live_regs_mask = 0; + for (regno = 0; regno < 8; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + live_regs_mask |= 1 << regno; + + if (amount < 512) + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (-amount))); + else + { + rtx reg, spare; + + if ((live_regs_mask & 0xff) == 0) /* Very unlikely */ + emit_insn (gen_movsi (spare = gen_rtx (REG, SImode, 12), + reg = gen_rtx (REG, SImode, 4))); + else + { + for (regno = 0; regno < 8; regno++) + if (live_regs_mask & (1 << regno)) + break; + reg = gen_rtx (REG, SImode, regno); + } + + emit_insn (gen_movsi (reg, GEN_INT (-amount))); + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); + if ((live_regs_mask & 0xff) == 0) + emit_insn (gen_movsi (reg, spare)); + } + } + + if (frame_pointer_needed) + { + if (current_function_outgoing_args_size) + { + rtx offset = GEN_INT (current_function_outgoing_args_size); + + if (current_function_outgoing_args_size < 1024) + emit_insn (gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx, + offset)); + else + { + emit_insn (gen_movsi (frame_pointer_rtx, offset)); + emit_insn (gen_addsi3 (frame_pointer_rtx, frame_pointer_rtx, + stack_pointer_rtx)); + } + } + else + emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx)); + } + + /* if (profile_flag || profile_block_flag) */ + emit_insn (gen_blockage ()); +} + +void +thumb_expand_epilogue () +{ + HOST_WIDE_INT amount = (get_frame_size () + + current_function_outgoing_args_size); + int regno; + + /* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + /* Naked functions don't have epilogues. */ + if (arm_naked_function_p (current_function_decl)) + return; +#endif + /* END CYGNUS LOCAL nickc/thumb-pe */ + + if (amount) + { + if (amount < 512) + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (amount))); + else + { + rtx reg = gen_rtx (REG, SImode, 3); /* Always free in the epilogue */ + + emit_insn (gen_movsi (reg, GEN_INT (amount))); + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); + } + /* if (profile_flag || profile_block_flag) */ + emit_insn (gen_blockage ()); + } +} + +void +thumb_function_epilogue (f, frame_size) + FILE *f; + int frame_size; +{ + /* ??? Probably not safe to set this here, since it assumes that a + function will be emitted as assembly immediately after we generate + RTL for it. This does not happen for inline functions. */ + return_used_this_function = 0; + current_function_has_far_jump = 0; +#if 0 /* TODO : comment not really needed */ + fprintf (f, "%s THUMB Epilogue\n", ASM_COMMENT_START); +#endif +} + +/* The bits which aren't usefully expanded as rtl. */ +char * +thumb_unexpanded_epilogue () +{ + int regno; + int live_regs_mask = 0; + int high_regs_pushed = 0; + int leaf_function = leaf_function_p (); + int had_to_push_lr; + + if (return_used_this_function) + return ""; + + for (regno = 0; regno < 8; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + live_regs_mask |= 1 << regno; + + for (regno = 8; regno < 13; regno++) + { + if (regs_ever_live[regno] && ! call_used_regs[regno]) + high_regs_pushed ++; + } + + /* The prolog may have pushed some high registers to use as + work registers. eg the testuite file: + gcc/testsuite/gcc/gcc.c-torture/execute/complex-2.c + compiles to produce: + push {r4, r5, r6, r7, lr} + mov r7, r9 + mov r6, r8 + push {r6, r7} + as part of the prolog. We have to undo that pushing here. */ + + if (high_regs_pushed) + { + int mask = live_regs_mask; + int next_hi_reg; + int size; + int mode; + +#ifdef RTX_CODE + /* If we can deduce the registers used from the function's return value. + This is more reliable that examining regs_ever_live[] because that + will be set if the register is ever used in the function, not just if + the register is used to hold a return value. */ + + if (current_function_return_rtx != 0) + { + mode = GET_MODE (current_function_return_rtx); + } + else +#endif + { + mode = DECL_MODE (DECL_RESULT (current_function_decl)); + } + + size = GET_MODE_SIZE (mode); + + /* Unless we are returning a type of size > 12 register r3 is available. */ + if (size < 13) + mask |= 1 << 3; + + if (mask == 0) + { + /* Oh dear! We have no low registers into which we can pop high registers! */ + + fatal ("No low registers available for popping high registers"); + } + + for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++) + if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) + break; + + while (high_regs_pushed) + { + /* Find low register(s) into which the high register(s) can be popped. */ + for (regno = 0; regno < 8; regno++) + { + if (mask & (1 << regno)) + high_regs_pushed--; + if (high_regs_pushed == 0) + break; + } + + mask &= (2 << regno) - 1; /* A noop if regno == 8 */ + + /* Pop the values into the low register(s). */ + thumb_pushpop (asm_out_file, mask, 0); + + /* Move the value(s) into the high registers. */ + for (regno = 0; regno < 8; regno++) + { + if (mask & (1 << regno)) + { + asm_fprintf (asm_out_file, "\tmov\t%s, %s\n", + reg_names[next_hi_reg], reg_names[regno]); + for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++) + if (regs_ever_live[next_hi_reg] && + ! call_used_regs[next_hi_reg]) + break; + } + } + } + } + + had_to_push_lr = (live_regs_mask || ! leaf_function || far_jump_used_p()); + + if (TARGET_BACKTRACE && ((live_regs_mask & 0xFF) == 0) && regs_ever_live[ ARG_4_REGISTER ] != 0) + { + /* The stack backtrace structure creation code had to + push R7 in order to get a work register, so we pop + it now. */ + + live_regs_mask |= (1 << WORK_REGISTER); + } + + if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE) + { + if (had_to_push_lr + && ! is_called_in_ARM_mode (current_function_decl)) + live_regs_mask |= 1 << PROGRAM_COUNTER; + + /* Either no argument registers were pushed or a backtrace + structure was created which includes an adjusted stack + pointer, so just pop everything. */ + + if (live_regs_mask) + thumb_pushpop (asm_out_file, live_regs_mask, FALSE); + + /* We have either just popped the return address into the + PC or it is was kept in LR for the entire function or + it is still on the stack because we do not want to + return by doing a pop {pc}. */ + + if ((live_regs_mask & (1 << PROGRAM_COUNTER)) == 0) + thumb_exit (asm_out_file, + (had_to_push_lr + && is_called_in_ARM_mode (current_function_decl)) ? + -1 : LINK_REGISTER); + } + else + { + /* Pop everything but the return address. */ + live_regs_mask &= ~ (1 << PROGRAM_COUNTER); + + if (live_regs_mask) + thumb_pushpop (asm_out_file, live_regs_mask, FALSE); + + if (had_to_push_lr) + { + /* Get the return address into a temporary register. */ + thumb_pushpop (asm_out_file, 1 << ARG_4_REGISTER, 0); + } + + /* Remove the argument registers that were pushed onto the stack. */ + asm_fprintf (asm_out_file, "\tadd\t%s, %s, #%d\n", + reg_names [STACK_POINTER], + reg_names [STACK_POINTER], + current_function_pretend_args_size); + + thumb_exit (asm_out_file, had_to_push_lr ? ARG_4_REGISTER : LINK_REGISTER); + } + + return ""; +} + +/* Handle the case of a double word load into a low register from + a computed memory address. The computed address may involve a + register which is overwritten by the load. */ + +char * +thumb_load_double_from_address (operands) + rtx * operands; +{ + rtx addr; + rtx base; + rtx offset; + rtx arg1; + rtx arg2; + + if (GET_CODE (operands[0]) != REG) + fatal ("thumb_load_double_from_address: destination is not a register"); + + if (GET_CODE (operands[1]) != MEM) + fatal ("thumb_load_double_from_address: source is not a computed memory address"); + + /* Get the memory address. */ + + addr = XEXP (operands[1], 0); + + /* Work out how the memory address is computed. */ + + switch (GET_CODE (addr)) + { + case REG: + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); + + if (REGNO (operands[0]) == REGNO (addr)) + { + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + } + else + { + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + } + break; + + case CONST: + /* Compute
+ 4 for the high order load. */ + + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); + + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + break; + + case PLUS: + arg1 = XEXP (addr, 0); + arg2 = XEXP (addr, 1); + + if (CONSTANT_P (arg1)) + base = arg2, offset = arg1; + else + base = arg1, offset = arg2; + + if (GET_CODE (base) != REG) + fatal ("thumb_load_double_from_address: base is not a register"); + + /* Catch the case of
= + */ + + if (GET_CODE (offset) == REG) + { + int reg_offset = REGNO (offset); + int reg_base = REGNO (base); + int reg_dest = REGNO (operands[0]); + + /* Add the base and offset registers together into the higher destination register. */ + + fprintf (asm_out_file, "\tadd\t%s, %s, %s\t\t%s created by thumb_load_double_from_address", + reg_names[ reg_dest + 1 ], + reg_names[ reg_base ], + reg_names[ reg_offset ], + ASM_COMMENT_START); + + /* Load the lower destination register from the address in the higher destination register. */ + + fprintf (asm_out_file, "\tldr\t%s, [%s, #0]\t\t%s created by thumb_load_double_from_address", + reg_names[ reg_dest ], + reg_names[ reg_dest + 1], + ASM_COMMENT_START); + + /* Load the higher destination register from its own address plus 4. */ + + fprintf (asm_out_file, "\tldr\t%s, [%s, #4]\t\t%s created by thumb_load_double_from_address", + reg_names[ reg_dest + 1 ], + reg_names[ reg_dest + 1 ], + ASM_COMMENT_START); + } + else + { + /* Compute
+ 4 for the high order load. */ + + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); + + /* If the computed address is held in the low order register + then load the high order register first, otherwise always + load the low order register first. */ + + if (REGNO (operands[0]) == REGNO (base)) + { + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + } + else + { + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + } + } + break; + + case LABEL_REF: + /* With no registers to worry about we can just load the value directly. */ + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); + + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + break; + + default: + debug_rtx (operands[1]); + fatal ("thumb_load_double_from_address: Unhandled address calculation"); + break; + } + + return ""; +} + +char * +output_move_mem_multiple (n, operands) + int n; + rtx *operands; +{ + rtx tmp; + + switch (n) + { + case 2: + if (REGNO (operands[2]) > REGNO (operands[3])) + { + tmp = operands[2]; + operands[2] = operands[3]; + operands[3] = tmp; + } + output_asm_insn ("ldmia\t%1!, {%2, %3}", operands); + output_asm_insn ("stmia\t%0!, {%2, %3}", operands); + break; + + case 3: + if (REGNO (operands[2]) > REGNO (operands[3])) + { + tmp = operands[2]; + operands[2] = operands[3]; + operands[3] = tmp; + } + if (REGNO (operands[3]) > REGNO (operands[4])) + { + tmp = operands[3]; + operands[3] = operands[4]; + operands[4] = tmp; + } + if (REGNO (operands[2]) > REGNO (operands[3])) + { + tmp = operands[2]; + operands[2] = operands[3]; + operands[3] = tmp; + } + output_asm_insn ("ldmia\t%1!, {%2, %3, %4}", operands); + output_asm_insn ("stmia\t%0!, {%2, %3, %4}", operands); + break; + + default: + abort (); + } + + return ""; +} + + +int +thumb_epilogue_size () +{ + return 42; /* The answer to .... */ +} + +static char *conds[] = +{ + "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", + "hi", "ls", "ge", "lt", "gt", "le" +}; + +static char * +thumb_condition_code (x, invert) + rtx x; + int invert; +{ + int val; + + switch (GET_CODE (x)) + { + case EQ: val = 0; break; + case NE: val = 1; break; + case GEU: val = 2; break; + case LTU: val = 3; break; + case GTU: val = 8; break; + case LEU: val = 9; break; + case GE: val = 10; break; + case LT: val = 11; break; + case GT: val = 12; break; + case LE: val = 13; break; + default: + abort (); + } + + return conds[val ^ invert]; +} + +void +thumb_print_operand (f, x, code) + FILE *f; + rtx x; + int code; +{ + if (code) + { + switch (code) + { + case '@': + fputs (ASM_COMMENT_START, f); + return; + + case '_': + fputs (user_label_prefix, f); + return; + + case 'D': + if (x) + fputs (thumb_condition_code (x, 1), f); + return; + + case 'd': + if (x) + fputs (thumb_condition_code (x, 0), f); + return; + + /* An explanation of the 'Q', 'R' and 'H' register operands: + + In a pair of registers containing a DI or DF value the 'Q' + operand returns the register number of the register containing + the least signficant part of the value. The 'R' operand returns + the register number of the register containing the most + significant part of the value. + + The 'H' operand returns the higher of the two register numbers. + On a run where WORDS_BIG_ENDIAN is true the 'H' operand is the + same as the 'Q' operand, since the most signficant part of the + value is held in the lower number register. The reverse is true + on systems where WORDS_BIG_ENDIAN is false. + + The purpose of these operands is to distinguish between cases + where the endian-ness of the values is important (for example + when they are added together), and cases where the endian-ness + is irrelevant, but the order of register operations is important. + For example when loading a value from memory into a register + pair, the endian-ness does not matter. Provided that the value + from the lower memory address is put into the lower numbered + register, and the value from the higher address is put into the + higher numbered register, the load will work regardless of whether + the value being loaded is big-wordian or little-wordian. The + order of the two register loads can matter however, if the address + of the memory location is actually held in one of the registers + being overwritten by the load. */ + case 'Q': + if (REGNO (x) > 15) + abort (); + fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0)], f); + return; + + case 'R': + if (REGNO (x) > 15) + abort (); + fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1)], f); + return; + + case 'H': + if (REGNO (x) > 15) + abort (); + fputs (reg_names[REGNO (x) + 1], f); + return; + + case 'c': + /* We use 'c' operands with symbols for .vtinherit */ + if (GET_CODE (x) == SYMBOL_REF) + output_addr_const(f, x); + return; + + default: + abort (); + } + } + if (GET_CODE (x) == REG) + fputs (reg_names[REGNO (x)], f); + else if (GET_CODE (x) == MEM) + output_address (XEXP (x, 0)); + else if (GET_CODE (x) == CONST_INT) + { + fputc ('#', f); + output_addr_const (f, x); + } + else + abort (); +} + +#ifdef AOF_ASSEMBLER +int arm_text_section_count = 1; + +char * +aof_text_section (in_readonly) + int in_readonly; +{ + static char buf[100]; + if (in_readonly) + return ""; + sprintf (buf, "\tCODE16\n\tAREA |C$$code%d|, CODE, READONLY", + arm_text_section_count++); + return buf; +} + +static int arm_data_section_count = 1; + +char * +aof_data_section () +{ + static char buf[100]; + sprintf (buf, "\tAREA |C$$data%d|, DATA", arm_data_section_count++); + return buf; +} + +/* The AOF thumb assembler is religiously strict about declarations of + imported and exported symbols, so that it is impossible to declare a + function as imported near the begining of the file, and then to export + it later on. It is, however, possible to delay the decision until all + the functions in the file have been compiled. To get around this, we + maintain a list of the imports and exports, and delete from it any that + are subsequently defined. At the end of compilation we spit the + remainder of the list out before the END directive. */ + +struct import +{ + struct import *next; + char *name; +}; + +static struct import *imports_list = NULL; + +void +thumb_aof_add_import (name) + char *name; +{ + struct import *new; + + for (new = imports_list; new; new = new->next) + if (new->name == name) + return; + + new = (struct import *) xmalloc (sizeof (struct import)); + new->next = imports_list; + imports_list = new; + new->name = name; +} + +void +thumb_aof_delete_import (name) + char *name; +{ + struct import **old; + + for (old = &imports_list; *old; old = & (*old)->next) + { + if ((*old)->name == name) + { + *old = (*old)->next; + return; + } + } +} + +void +thumb_aof_dump_imports (f) + FILE *f; +{ + while (imports_list) + { + fprintf (f, "\tIMPORT\t"); + assemble_name (f, imports_list->name); + fputc ('\n', f); + imports_list = imports_list->next; + } +} +#endif + +/* Decide whether a type should be returned in memory (true) + or in a register (false). This is called by the macro + RETURN_IN_MEMORY. */ + +int +thumb_return_in_memory (type) + tree type; +{ + if (! AGGREGATE_TYPE_P (type)) + { + /* All simple types are returned in registers. */ + + return 0; + } + else if (int_size_in_bytes (type) > 4) + { + /* All structures/unions bigger than one word are returned in memory. */ + + return 1; + } + else if (TREE_CODE (type) == RECORD_TYPE) + { + tree field; + + /* For a struct the APCS says that we must return in a register if + every addressable element has an offset of zero. For practical + purposes this means that the structure can have at most one non- + bit-field element and that this element must be the first one in + the structure. */ + + /* Find the first field, ignoring non FIELD_DECL things which will + have been created by C++. */ + for (field = TYPE_FIELDS (type); + field && TREE_CODE (field) != FIELD_DECL; + field = TREE_CHAIN (field)) + continue; + + if (field == NULL) + return 0; /* An empty structure. Allowed by an extension to ANSI C. */ + + /* Now check the remaining fields, if any. */ + for (field = TREE_CHAIN (field); field; field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + + if (! DECL_BIT_FIELD_TYPE (field)) + return 1; + } + + return 0; + } + else if (TREE_CODE (type) == UNION_TYPE) + { + tree field; + + /* Unions can be returned in registers if every element is + integral, or can be returned in an integer register. */ + + for (field = TYPE_FIELDS (type); + field; + field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + + if (RETURN_IN_MEMORY (TREE_TYPE (field))) + return 1; + } + + return 0; + } + /* XXX Not sure what should be done for other aggregates, so put them in + memory. */ + return 1; +} + +void +thumb_override_options () +{ + if (structure_size_string != NULL) + { + int size = strtol (structure_size_string, NULL, 0); + + if (size == 8 || size == 32) + arm_structure_size_boundary = size; + else + warning ("Structure size boundary can only be set to 8 or 32"); + } + + if (flag_pic) + { + warning ("Position independent code not supported. Ignored"); + flag_pic = 0; + } +} + +/* CYGNUS LOCAL nickc/thumb-pe */ + +#ifdef THUMB_PE +/* Return nonzero if ATTR is a valid attribute for DECL. + ATTRIBUTES are any existing attributes and ARGS are the arguments + supplied with ATTR. + + Supported attributes: + + naked: don't output any prologue or epilogue code, the user is assumed + to do the right thing. + + interfacearm: Always assume that this function will be entered in ARM + mode, not Thumb mode, and that the caller wishes to be returned to in + ARM mode. */ +int +arm_valid_machine_decl_attribute (decl, attributes, attr, args) + tree decl; + tree attributes; + tree attr; + tree args; +{ + if (args != NULL_TREE) + return 0; + + if (is_attribute_p ("naked", attr)) + return TREE_CODE (decl) == FUNCTION_DECL; + + if (is_attribute_p ("interfacearm", attr)) + return TREE_CODE (decl) == FUNCTION_DECL; + + return 0; +} +#endif /* THUMB_PE */ +/* END CYGNUS LOCAL nickc/thumb-pe */ + +/* s_register_operand is the same as register_operand, but it doesn't accept + (SUBREG (MEM)...). + + This function exists because at the time it was put in it led to better + code. SUBREG(MEM) always needs a reload in the places where + s_register_operand is used, and this seemed to lead to excessive + reloading. */ + +int +s_register_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + if (GET_MODE (op) != mode && mode != VOIDmode) + return 0; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + /* We don't consider registers whose class is NO_REGS + to be a register operand. */ + /* XXX might have to check for lo regs only for thumb ??? */ + return (GET_CODE (op) == REG + && (REGNO (op) >= FIRST_PSEUDO_REGISTER + || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); +} diff --git a/gcc_arm/config/arm/thumb_020422.c b/gcc_arm/config/arm/thumb_020422.c new file mode 100755 index 0000000..cefc7d4 --- /dev/null +++ b/gcc_arm/config/arm/thumb_020422.c @@ -0,0 +1,2291 @@ +/* Output routines for GCC for ARM/Thumb + Copyright (C) 1996 Cygnus Software Technologies Ltd + The basis of this contribution was generated by + Richard Earnshaw, Advanced RISC Machines Ltd + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include +#include +#include "config.h" +#include "rtl.h" +#include "hard-reg-set.h" +#include "regs.h" +#include "output.h" +#include "insn-flags.h" +#include "insn-attr.h" +#include "flags.h" +#include "tree.h" +#include "expr.h" + + +int current_function_anonymous_args = 0; +static int current_function_has_far_jump = 0; + +/* Used to parse -mstructure_size_boundary command line option. */ +char * structure_size_string = NULL; +int arm_structure_size_boundary = 32; /* Used to be 8 */ + + +/* Predicates */ +int +reload_memory_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + int regno = true_regnum (op); + + return (! CONSTANT_P (op) + && (regno == -1 + || (GET_CODE (op) == REG + && REGNO (op) >= FIRST_PSEUDO_REGISTER))); +} + +/* Return nonzero if op is suitable for the RHS of a cmp instruction. */ +int +thumb_cmp_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return ((GET_CODE (op) == CONST_INT + && (unsigned HOST_WIDE_INT) (INTVAL (op)) < 256) + || register_operand (op, mode)); +} + +int +thumb_shiftable_const (val) + HOST_WIDE_INT val; +{ + unsigned HOST_WIDE_INT x = val; + unsigned HOST_WIDE_INT mask = 0xff; + int i; + + for (i = 0; i < 25; i++) + if ((val & (mask << i)) == val) + return 1; + + return 0; +} + +int +thumb_trivial_epilogue () +{ + int regno; + + /* ??? If this function ever returns 1, we get a function without any + epilogue at all. It appears that the intent was to cause a "return" + insn to be emitted, but that does not happen. */ + return 0; + +#if 0 + if (get_frame_size () + || current_function_outgoing_args_size + || current_function_pretend_args_size) + return 0; + + for (regno = 8; regno < 13; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + return 0; + + return 1; +#endif +} + + +/* Routines for handling the constant pool */ +/* This is unashamedly hacked from the version in sh.c, since the problem is + extremely similar. */ + +/* Thumb instructions cannot load a large constant into a register, + constants have to come from a pc relative load. The reference of a pc + relative load instruction must be less than 1k infront of the instruction. + This means that we often have to dump a constant inside a function, and + generate code to branch around it. + + It is important to minimize this, since the branches will slow things + down and make things bigger. + + Worst case code looks like: + + ldr rn, L1 + b L2 + align + L1: .long value + L2: + .. + + ldr rn, L3 + b L4 + align + L3: .long value + L4: + .. + + We fix this by performing a scan before scheduling, which notices which + instructions need to have their operands fetched from the constant table + and builds the table. + + + The algorithm is: + + scan, find an instruction which needs a pcrel move. Look forward, find the + last barrier which is within MAX_COUNT bytes of the requirement. + If there isn't one, make one. Process all the instructions between + the find and the barrier. + + In the above example, we can tell that L3 is within 1k of L1, so + the first move can be shrunk from the 2 insn+constant sequence into + just 1 insn, and the constant moved to L3 to make: + + ldr rn, L1 + .. + ldr rn, L3 + b L4 + align + L1: .long value + L3: .long value + L4: + + Then the second move becomes the target for the shortening process. + + */ + +typedef struct +{ + rtx value; /* Value in table */ + HOST_WIDE_INT next_offset; + enum machine_mode mode; /* Mode of value */ +} pool_node; + +/* The maximum number of constants that can fit into one pool, since + the pc relative range is 0...1020 bytes and constants are at least 4 + bytes long */ + +#define MAX_POOL_SIZE (1020/4) +static pool_node pool_vector[MAX_POOL_SIZE]; +static int pool_size; +static rtx pool_vector_label; + +/* Add a constant to the pool and return its label. */ + +static HOST_WIDE_INT +add_constant (x, mode) + rtx x; + enum machine_mode mode; +{ + int i; + rtx lab; + HOST_WIDE_INT offset; + + if (mode == SImode && GET_CODE (x) == MEM && CONSTANT_P (XEXP (x, 0)) + && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0))) + x = get_pool_constant (XEXP (x, 0)); + + /* First see if we've already got it */ + + for (i = 0; i < pool_size; i++) + { + if (x->code == pool_vector[i].value->code + && mode == pool_vector[i].mode) + { + if (x->code == CODE_LABEL) + { + if (XINT (x, 3) != XINT (pool_vector[i].value, 3)) + continue; + } + if (rtx_equal_p (x, pool_vector[i].value)) + return pool_vector[i].next_offset - GET_MODE_SIZE (mode); + } + } + + /* Need a new one */ + + pool_vector[pool_size].next_offset = GET_MODE_SIZE (mode); + offset = 0; + if (pool_size == 0) + pool_vector_label = gen_label_rtx (); + else + pool_vector[pool_size].next_offset + += (offset = pool_vector[pool_size - 1].next_offset); + + pool_vector[pool_size].value = x; + pool_vector[pool_size].mode = mode; + pool_size++; + return offset; +} + +/* Output the literal table */ + +static void +dump_table (scan) + rtx scan; +{ + int i; + + scan = emit_label_after (gen_label_rtx (), scan); + scan = emit_insn_after (gen_align_4 (), scan); + scan = emit_label_after (pool_vector_label, scan); + + for (i = 0; i < pool_size; i++) + { + pool_node *p = pool_vector + i; + + switch (GET_MODE_SIZE (p->mode)) + { + case 4: + scan = emit_insn_after (gen_consttable_4 (p->value), scan); + break; + + case 8: + scan = emit_insn_after (gen_consttable_8 (p->value), scan); + break; + + default: + abort (); + break; + } + } + + scan = emit_insn_after (gen_consttable_end (), scan); + scan = emit_barrier_after (scan); + pool_size = 0; +} + +/* Non zero if the src operand needs to be fixed up */ +static +int +fixit (src, mode) + rtx src; + enum machine_mode mode; +{ + return ((CONSTANT_P (src) + && (GET_CODE (src) != CONST_INT + || ! (CONST_OK_FOR_LETTER_P (INTVAL (src), 'I') + || CONST_OK_FOR_LETTER_P (INTVAL (src), 'J') + || (mode != DImode + && CONST_OK_FOR_LETTER_P (INTVAL (src), 'K'))))) + || (mode == SImode && GET_CODE (src) == MEM + && GET_CODE (XEXP (src, 0)) == SYMBOL_REF + && CONSTANT_POOL_ADDRESS_P (XEXP (src, 0)))); +} + +/* Find the last barrier less than MAX_COUNT bytes from FROM, or create one. */ + +#define MAX_COUNT_SI 1000 + +static rtx +find_barrier (from) + rtx from; +{ + int count = 0; + rtx found_barrier = 0; + rtx label; + + while (from && count < MAX_COUNT_SI) + { + if (GET_CODE (from) == BARRIER) + return from; + + /* Count the length of this insn */ + if (GET_CODE (from) == INSN + && GET_CODE (PATTERN (from)) == SET + && CONSTANT_P (SET_SRC (PATTERN (from))) + && CONSTANT_POOL_ADDRESS_P (SET_SRC (PATTERN (from)))) + { + rtx src = SET_SRC (PATTERN (from)); + count += 2; + } + else + count += get_attr_length (from); + + from = NEXT_INSN (from); + } + + /* We didn't find a barrier in time to + dump our stuff, so we'll make one */ + label = gen_label_rtx (); + + if (from) + from = PREV_INSN (from); + else + from = get_last_insn (); + + /* Walk back to be just before any jump */ + while (GET_CODE (from) == JUMP_INSN + || GET_CODE (from) == NOTE + || GET_CODE (from) == CODE_LABEL) + from = PREV_INSN (from); + + from = emit_jump_insn_after (gen_jump (label), from); + JUMP_LABEL (from) = label; + found_barrier = emit_barrier_after (from); + emit_label_after (label, found_barrier); + return found_barrier; +} + +/* Non zero if the insn is a move instruction which needs to be fixed. */ + +static int +broken_move (insn) + rtx insn; +{ + if (!INSN_DELETED_P (insn) + && GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == SET) + { + rtx pat = PATTERN (insn); + rtx src = SET_SRC (pat); + rtx dst = SET_DEST (pat); + enum machine_mode mode = GET_MODE (dst); + if (dst == pc_rtx) + return 0; + return fixit (src, mode); + } + return 0; +} + +/* Recursively search through all of the blocks in a function + checking to see if any of the variables created in that + function match the RTX called 'orig'. If they do then + replace them with the RTX called 'new'. */ + +static void +replace_symbols_in_block (tree block, rtx orig, rtx new) +{ + for (; block; block = BLOCK_CHAIN (block)) + { + tree sym; + + if (! TREE_USED (block)) + continue; + + for (sym = BLOCK_VARS (block); sym; sym = TREE_CHAIN (sym)) + { + if ( (DECL_NAME (sym) == 0 && TREE_CODE (sym) != TYPE_DECL) + || DECL_IGNORED_P (sym) + || TREE_CODE (sym) != VAR_DECL + || DECL_EXTERNAL (sym) + || ! rtx_equal_p (DECL_RTL (sym), orig) + ) + continue; + + DECL_RTL (sym) = new; + } + + replace_symbols_in_block (BLOCK_SUBBLOCKS (block), orig, new); + } +} + +void +thumb_reorg (first) + rtx first; +{ + rtx insn; + for (insn = first; insn; insn = NEXT_INSN (insn)) + { + if (broken_move (insn)) + { + /* This is a broken move instruction, scan ahead looking for + a barrier to stick the constant table behind */ + rtx scan; + rtx barrier = find_barrier (insn); + + /* Now find all the moves between the points and modify them */ + for (scan = insn; scan != barrier; scan = NEXT_INSN (scan)) + { + if (broken_move (scan)) + { + /* This is a broken move instruction, add it to the pool */ + rtx pat = PATTERN (scan); + rtx src = SET_SRC (pat); + rtx dst = SET_DEST (pat); + enum machine_mode mode = GET_MODE (dst); + HOST_WIDE_INT offset; + rtx newinsn; + rtx newsrc; + + /* If this is an HImode constant load, convert it into + an SImode constant load. Since the register is always + 32 bits this is safe. We have to do this, since the + load pc-relative instruction only does a 32-bit load. */ + if (mode == HImode) + { + mode = SImode; + if (GET_CODE (dst) != REG) + abort (); + PUT_MODE (dst, SImode); + } + + offset = add_constant (src, mode); + newsrc = gen_rtx (MEM, mode, + plus_constant (gen_rtx (LABEL_REF, + VOIDmode, + pool_vector_label), + offset)); + + /* Build a jump insn wrapper around the move instead + of an ordinary insn, because we want to have room for + the target label rtx in fld[7], which an ordinary + insn doesn't have. */ + newinsn = emit_jump_insn_after (gen_rtx (SET, VOIDmode, + dst, newsrc), scan); + JUMP_LABEL (newinsn) = pool_vector_label; + + /* But it's still an ordinary insn */ + PUT_CODE (newinsn, INSN); + + /* If debugging information is going to be emitted + then we must make sure that any refences to + symbols which are removed by the above code are + also removed in the descriptions of the + function's variables. Failure to do this means + that the debugging information emitted could + refer to symbols which are not emited by + output_constant_pool() because + mark_constant_pool() never sees them as being + used. */ + + + /* These are the tests used in + output_constant_pool() to decide if the constant + pool will be marked. Only necessary if debugging + info is being emitted. Only necessary for + references to memory whose address is given by a + symbol. */ + + if (optimize > 0 + && flag_expensive_optimizations + && write_symbols != NO_DEBUG + && GET_CODE (src) == MEM + && GET_CODE (XEXP (src, 0)) == SYMBOL_REF) + replace_symbols_in_block + (DECL_INITIAL (current_function_decl), src, newsrc); + + /* Kill old insn */ + delete_insn (scan); + scan = newinsn; + } + } + dump_table (barrier); + } + } +} + + +/* Routines for generating rtl */ + +void +thumb_expand_movstrqi (operands) + rtx *operands; +{ + rtx out = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); + rtx in = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); + HOST_WIDE_INT len = INTVAL (operands[2]); + HOST_WIDE_INT offset = 0; + + while (len >= 12) + { + emit_insn (gen_movmem12b (out, in)); + len -= 12; + } + if (len >= 8) + { + emit_insn (gen_movmem8b (out, in)); + len -= 8; + } + if (len >= 4) + { + rtx reg = gen_reg_rtx (SImode); + emit_insn (gen_movsi (reg, gen_rtx (MEM, SImode, in))); + emit_insn (gen_movsi (gen_rtx (MEM, SImode, out), reg)); + len -= 4; + offset += 4; + } + if (len >= 2) + { + rtx reg = gen_reg_rtx (HImode); + emit_insn (gen_movhi (reg, gen_rtx (MEM, HImode, + plus_constant (in, offset)))); + emit_insn (gen_movhi (gen_rtx (MEM, HImode, plus_constant (out, offset)), + reg)); + len -= 2; + offset += 2; + } + if (len) + { + rtx reg = gen_reg_rtx (QImode); + emit_insn (gen_movqi (reg, gen_rtx (MEM, QImode, + plus_constant (in, offset)))); + emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (out, offset)), + reg)); + } +} + + +/* Routines for reloading */ + +void +thumb_reload_out_si (operands) + rtx operands; +{ + abort (); +} + +/* CYGNUS LOCAL nickc/thumb-pe */ + +#ifdef THUMB_PE +/* Return non-zero if FUNC is a naked function. */ + +static int +arm_naked_function_p (func) + tree func; +{ + tree a; + + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + + a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func)); + return a != NULL_TREE; +} +#endif +/* END CYGNUS LOCAL nickc/thumb-pe */ + +/* Return non-zero if FUNC must be entered in ARM mode. */ +int +is_called_in_ARM_mode (func) + tree func; +{ + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + + /* Ignore the problem about functions whoes address is taken. */ + if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func)) + return TRUE; + +/* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + return lookup_attribute ("interfacearm", DECL_MACHINE_ATTRIBUTES (func)) != NULL_TREE; +#else + return FALSE; +#endif +/* END CYGNUS LOCAL */ +} + + +/* Routines for emitting code */ + +void +final_prescan_insn(insn) + rtx insn; +{ + extern int *insn_addresses; + + if (flag_print_asm_name) + fprintf (asm_out_file, "%s 0x%04x\n", ASM_COMMENT_START, + insn_addresses[INSN_UID (insn)]); +} + + +static void thumb_pushpop ( FILE *, int, int ); /* Forward declaration. */ + +#ifdef __GNUC__ +inline +#endif +static int +number_of_first_bit_set (mask) + int mask; +{ + int bit; + + for (bit = 0; + (mask & (1 << bit)) == 0; + ++ bit) + continue; + + return bit; +} + +#define ARG_1_REGISTER 0 +#define ARG_2_REGISTER 1 +#define ARG_3_REGISTER 2 +#define ARG_4_REGISTER 3 +#define WORK_REGISTER 7 +#define FRAME_POINTER 11 +#define IP_REGISTER 12 +#define STACK_POINTER STACK_POINTER_REGNUM +#define LINK_REGISTER 14 +#define PROGRAM_COUNTER 15 + +/* Generate code to return from a thumb function. If + 'reg_containing_return_addr' is -1, then the return address is + actually on the stack, at the stack pointer. */ +static void +thumb_exit (f, reg_containing_return_addr) + FILE * f; + int reg_containing_return_addr; +{ + int regs_available_for_popping; + int regs_to_pop; + int pops_needed; + int reg; + int available; + int required; + int mode; + int size; + int restore_a4 = FALSE; + + /* Compute the registers we need to pop. */ + regs_to_pop = 0; + pops_needed = 0; + + if (reg_containing_return_addr == -1) + { + regs_to_pop |= 1 << LINK_REGISTER; + ++ pops_needed; + } + + if (TARGET_BACKTRACE) + { + /* Restore frame pointer and stack pointer. */ + regs_to_pop |= (1 << FRAME_POINTER) | (1 << STACK_POINTER); + pops_needed += 2; + } + + /* If there is nothing to pop then just emit the BX instruction and return.*/ + if (pops_needed == 0) + { + asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]); + + return; + } + + /* Otherwise if we are not supporting interworking and we have not created + a backtrace structure and the function was not entered in ARM mode then + just pop the return address straight into the PC. */ + else if ( ! TARGET_THUMB_INTERWORK + && ! TARGET_BACKTRACE + && ! is_called_in_ARM_mode (current_function_decl)) + { + asm_fprintf (f, "\tpop\t{pc}\n" ); + + return; + } + + /* Find out how many of the (return) argument registers we can corrupt. */ + regs_available_for_popping = 0; + +#ifdef RTX_CODE + /* If we can deduce the registers used from the function's return value. + This is more reliable that examining regs_ever_live[] because that + will be set if the register is ever used in the function, not just if + the register is used to hold a return value. */ + + if (current_function_return_rtx != 0) + mode = GET_MODE (current_function_return_rtx); + else +#endif + mode = DECL_MODE (DECL_RESULT (current_function_decl)); + + size = GET_MODE_SIZE (mode); + + if (size == 0) + { + /* In a void function we can use any argument register. + In a function that returns a structure on the stack + we can use the second and third argument registers. */ + if (mode == VOIDmode) + regs_available_for_popping = + (1 << ARG_1_REGISTER) + | (1 << ARG_2_REGISTER) + | (1 << ARG_3_REGISTER); + else + regs_available_for_popping = + (1 << ARG_2_REGISTER) + | (1 << ARG_3_REGISTER); + } + else if (size <= 4) regs_available_for_popping = + (1 << ARG_2_REGISTER) + | (1 << ARG_3_REGISTER); + else if (size <= 8) regs_available_for_popping = + (1 << ARG_3_REGISTER); + + /* Match registers to be popped with registers into which we pop them. */ + for (available = regs_available_for_popping, + required = regs_to_pop; + required != 0 && available != 0; + available &= ~(available & - available), + required &= ~(required & - required)) + -- pops_needed; + + /* If we have any popping registers left over, remove them. */ + if (available > 0) + regs_available_for_popping &= ~ available; + + /* Otherwise if we need another popping register we can use + the fourth argument register. */ + else if (pops_needed) + { + /* If we have not found any free argument registers and + reg a4 contains the return address, we must move it. */ + if (regs_available_for_popping == 0 + && reg_containing_return_addr == ARG_4_REGISTER) + { + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]); + reg_containing_return_addr = LINK_REGISTER; + } + else if (size > 12) + { + /* Register a4 is being used to hold part of the return value, + but we have dire need of a free, low register. */ + restore_a4 = TRUE; + + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [IP_REGISTER], reg_names [ARG_4_REGISTER]); + } + + if (reg_containing_return_addr != ARG_4_REGISTER) + { + /* The fourth argument register is available. */ + regs_available_for_popping |= 1 << ARG_4_REGISTER; + + -- pops_needed; + } + } + + /* Pop as many registers as we can. */ + thumb_pushpop (f, regs_available_for_popping, FALSE); + + /* Process the registers we popped. */ + if (reg_containing_return_addr == -1) + { + /* The return address was popped into the lowest numbered register. */ + regs_to_pop &= ~ (1 << LINK_REGISTER); + + reg_containing_return_addr = + number_of_first_bit_set (regs_available_for_popping); + + /* Remove this register for the mask of available registers, so that + the return address will not be corrupted by futher pops. */ + regs_available_for_popping &= ~ (1 << reg_containing_return_addr); + } + + /* If we popped other registers then handle them here. */ + if (regs_available_for_popping) + { + int frame_pointer; + + /* Work out which register currently contains the frame pointer. */ + frame_pointer = number_of_first_bit_set (regs_available_for_popping); + + /* Move it into the correct place. */ + asm_fprintf (f, "\tmov\tfp, %s\n", reg_names [frame_pointer]); + + /* (Temporarily) remove it from the mask of popped registers. */ + regs_available_for_popping &= ~ (1 << frame_pointer); + regs_to_pop &= ~ (1 << FRAME_POINTER); + + if (regs_available_for_popping) + { + int stack_pointer; + + /* We popped the stack pointer as well, find the register that + contains it.*/ + stack_pointer = number_of_first_bit_set (regs_available_for_popping); + + /* Move it into the stack register. */ + asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [stack_pointer]); + + /* At this point we have popped all necessary registers, so + do not worry about restoring regs_available_for_popping + to its correct value: + + assert (pops_needed == 0) + assert (regs_available_for_popping == (1 << frame_pointer)) + assert (regs_to_pop == (1 << STACK_POINTER)) */ + } + else + { + /* Since we have just move the popped value into the frame + pointer, the popping register is available for reuse, and + we know that we still have the stack pointer left to pop. */ + regs_available_for_popping |= (1 << frame_pointer); + } + } + + /* If we still have registers left on the stack, but we no longer have + any registers into which we can pop them, then we must move the return + address into the link register and make available the register that + contained it. */ + if (regs_available_for_popping == 0 && pops_needed > 0) + { + regs_available_for_popping |= 1 << reg_containing_return_addr; + + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [LINK_REGISTER], + reg_names [reg_containing_return_addr]); + + reg_containing_return_addr = LINK_REGISTER; + } + + /* If we have registers left on the stack then pop some more. + We know that at most we will want to pop FP and SP. */ + if (pops_needed > 0) + { + int popped_into; + int move_to; + + thumb_pushpop (f, regs_available_for_popping, FALSE); + + /* We have popped either FP or SP. + Move whichever one it is into the correct register. */ + popped_into = number_of_first_bit_set (regs_available_for_popping); + move_to = number_of_first_bit_set (regs_to_pop); + + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [move_to], reg_names [popped_into]); + + regs_to_pop &= ~ (1 << move_to); + + -- pops_needed; + } + + /* If we still have not popped everything then we must have only + had one register available to us and we are now popping the SP. */ + if (pops_needed > 0) + { + int popped_into; + + thumb_pushpop (f, regs_available_for_popping, FALSE); + + popped_into = number_of_first_bit_set (regs_available_for_popping); + + asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [popped_into]); + + /* + assert (regs_to_pop == (1 << STACK_POINTER)) + assert (pops_needed == 1) + */ + } + + /* If necessary restore the a4 register. */ + if (restore_a4) + { + if (reg_containing_return_addr != LINK_REGISTER) + { + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]); + reg_containing_return_addr = LINK_REGISTER; + } + + asm_fprintf (f, "\tmov\t%s, %s\n", + reg_names [ARG_4_REGISTER], reg_names [IP_REGISTER]); + } + + /* Return to caller. */ + asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]); +} + +/* Emit code to push or pop registers to or from the stack. */ +static void +thumb_pushpop (f, mask, push) + FILE * f; + int mask; + int push; +{ + int regno; + int lo_mask = mask & 0xFF; + + if (lo_mask == 0 && ! push && (mask & (1 << 15))) + { + /* Special case. Do not generate a POP PC statement here, do it in + thumb_exit() */ + + thumb_exit (f, -1); + return; + } + + asm_fprintf (f, "\t%s\t{", push ? "push" : "pop"); + + /* Look at the low registers first. */ + + for (regno = 0; regno < 8; regno ++, lo_mask >>= 1) + { + if (lo_mask & 1) + { + asm_fprintf (f, reg_names[regno]); + + if ((lo_mask & ~1) != 0) + asm_fprintf (f, ", "); + } + } + + if (push && (mask & (1 << 14))) + { + /* Catch pushing the LR. */ + + if (mask & 0xFF) + asm_fprintf (f, ", "); + + asm_fprintf (f, reg_names[14]); + } + else if (!push && (mask & (1 << 15))) + { + /* Catch popping the PC. */ + + if (TARGET_THUMB_INTERWORK || TARGET_BACKTRACE) + { + /* The PC is never poped directly, instead + it is popped into r3 and then BX is used. */ + + asm_fprintf (f, "}\n"); + + thumb_exit (f, -1); + + return; + } + else + { + if (mask & 0xFF) + asm_fprintf (f, ", "); + + asm_fprintf (f, reg_names[15]); + } + } + + asm_fprintf (f, "}\n"); +} + +/* Returns non-zero if the current function contains a far jump */ + +int +far_jump_used_p (void) +{ + rtx insn; + + if (current_function_has_far_jump) + return 1; + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + if (GET_CODE (insn) == JUMP_INSN + /* Ignore tablejump patterns. */ + && GET_CODE (PATTERN (insn)) != ADDR_VEC + && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC + && get_attr_far_jump (insn) == FAR_JUMP_YES) + { + current_function_has_far_jump = 1; + return 1; + } + } + + return 0; +} + +static int return_used_this_function = 0; + +char * +output_return () +{ + int regno; + int live_regs_mask = 0; + + /* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + /* If a function is naked, don't use the "return" insn. */ + if (arm_naked_function_p (current_function_decl)) + return ""; +#endif + /* END CYGNUS LOCAL nickc/thumb-pe */ + + return_used_this_function = 1; + + for (regno = 0; regno < 8; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + live_regs_mask |= 1 << regno; + + if (live_regs_mask == 0) + { + if (leaf_function_p () && ! far_jump_used_p()) + { + thumb_exit (asm_out_file, 14); + } + else if ( TARGET_THUMB_INTERWORK + || TARGET_BACKTRACE + || is_called_in_ARM_mode (current_function_decl)) + { + thumb_exit (asm_out_file, -1); + } + else + asm_fprintf (asm_out_file, "\tpop\t{pc}\n"); + } + else + { + asm_fprintf (asm_out_file, "\tpop\t{"); + + for (regno = 0; live_regs_mask; regno ++, live_regs_mask >>= 1) + if (live_regs_mask & 1) + { + asm_fprintf (asm_out_file, reg_names[regno]); + if (live_regs_mask & ~1) + asm_fprintf (asm_out_file, ", "); + } + + if ( TARGET_THUMB_INTERWORK + || TARGET_BACKTRACE + || is_called_in_ARM_mode (current_function_decl)) + { + asm_fprintf (asm_out_file, "}\n"); + thumb_exit (asm_out_file, -1); + } + else + asm_fprintf (asm_out_file, ", pc}\n"); + } + + return ""; +} + +void +thumb_function_prologue (f, frame_size) + FILE *f; + int frame_size; +{ + int amount = frame_size + current_function_outgoing_args_size; + int live_regs_mask = 0; + int high_regs_pushed = 0; + int store_arg_regs = 0; + int regno; + +/* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + if (arm_naked_function_p (current_function_decl)) + return; +#endif +/* CYGNUS LOCAL nickc/thumb-pe */ + + if (is_called_in_ARM_mode (current_function_decl)) + { + char * name; + if (GET_CODE (DECL_RTL (current_function_decl)) != MEM) + abort(); + if (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0)) != SYMBOL_REF) + abort(); + name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); + + /* Generate code sequence to switch us into Thumb mode. */ + /* The .code 32 directive has already been emitted by + ASM_DECLARE_FUNCITON_NAME */ + asm_fprintf (f, "\torr\tr12, pc, #1\n"); + asm_fprintf (f, "\tbx\tr12\n"); + + /* Generate a label, so that the debugger will notice the + change in instruction sets. This label is also used by + the assembler to bypass the ARM code when this function + is called from a Thumb encoded function elsewhere in the + same file. Hence the definition of STUB_NAME here must + agree with the definition in gas/config/tc-arm.c */ + +#define STUB_NAME ".real_start_of" + + asm_fprintf (f, "\t.code\t16\n"); + asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name); + asm_fprintf (f, "\t.thumb_func\n"); + asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name); + } + + if (current_function_anonymous_args && current_function_pretend_args_size) + store_arg_regs = 1; + + if (current_function_pretend_args_size) + { + if (store_arg_regs) + { + asm_fprintf (f, "\tpush\t{"); + for (regno = 4 - current_function_pretend_args_size / 4 ; regno < 4; + regno++) + asm_fprintf (f, "%s%s", reg_names[regno], regno == 3 ? "" : ", "); + asm_fprintf (f, "}\n"); + } + else + asm_fprintf (f, "\tsub\t%Rsp, %Rsp, #%d\n", + current_function_pretend_args_size); + } + + for (regno = 0; regno < 8; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + live_regs_mask |= 1 << regno; + + if (live_regs_mask || ! leaf_function_p () || far_jump_used_p()) + live_regs_mask |= 1 << 14; + + if (TARGET_BACKTRACE) + { + char * name; + int offset; + int work_register = 0; + + + /* We have been asked to create a stack backtrace structure. + The code looks like this: + + 0 .align 2 + 0 func: + 0 sub SP, #16 Reserve space for 4 registers. + 2 push {R7} Get a work register. + 4 add R7, SP, #20 Get the stack pointer before the push. + 6 str R7, [SP, #8] Store the stack pointer (before reserving the space). + 8 mov R7, PC Get hold of the start of this code plus 12. + 10 str R7, [SP, #16] Store it. + 12 mov R7, FP Get hold of the current frame pointer. + 14 str R7, [SP, #4] Store it. + 16 mov R7, LR Get hold of the current return address. + 18 str R7, [SP, #12] Store it. + 20 add R7, SP, #16 Point at the start of the backtrace structure. + 22 mov FP, R7 Put this value into the frame pointer. */ + + if ((live_regs_mask & 0xFF) == 0) + { + /* See if the a4 register is free. */ + + if (regs_ever_live[ 3 ] == 0) + work_register = 3; + else /* We must push a register of our own */ + live_regs_mask |= (1 << 7); + } + + if (work_register == 0) + { + /* Select a register from the list that will be pushed to use as our work register. */ + + for (work_register = 8; work_register--;) + if ((1 << work_register) & live_regs_mask) + break; + } + + name = reg_names[ work_register ]; + + asm_fprintf (f, "\tsub\tsp, sp, #16\t@ Create stack backtrace structure\n"); + + if (live_regs_mask) + thumb_pushpop (f, live_regs_mask, 1); + + for (offset = 0, work_register = 1 << 15; work_register; work_register >>= 1) + if (work_register & live_regs_mask) + offset += 4; + + asm_fprintf (f, "\tadd\t%s, sp, #%d\n", + name, offset + 16 + current_function_pretend_args_size); + + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 4); + + /* Make sure that the instruction fetching the PC is in the right place + to calculate "start of backtrace creation code + 12". */ + + if (live_regs_mask) + { + asm_fprintf (f, "\tmov\t%s, pc\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); + asm_fprintf (f, "\tmov\t%s, fp\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); + } + else + { + asm_fprintf (f, "\tmov\t%s, fp\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); + asm_fprintf (f, "\tmov\t%s, pc\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); + } + + asm_fprintf (f, "\tmov\t%s, lr\n", name); + asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 8); + asm_fprintf (f, "\tadd\t%s, sp, #%d\n", name, offset + 12); + asm_fprintf (f, "\tmov\tfp, %s\t\t@ Backtrace structure created\n", name); + } + else if (live_regs_mask) + thumb_pushpop (f, live_regs_mask, 1); + + for (regno = 8; regno < 13; regno++) + { + if (regs_ever_live[regno] && ! call_used_regs[regno]) + high_regs_pushed++; + } + + if (high_regs_pushed) + { + int pushable_regs = 0; + int mask = live_regs_mask & 0xff; + int next_hi_reg; + + for (next_hi_reg = 12; next_hi_reg > 7; next_hi_reg--) + { + if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) + break; + } + + pushable_regs = mask; + + if (pushable_regs == 0) + { + /* desperation time -- this probably will never happen */ + if (regs_ever_live[3] || ! call_used_regs[3]) + asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[12], reg_names[3]); + mask = 1 << 3; + } + + while (high_regs_pushed > 0) + { + for (regno = 7; regno >= 0; regno--) + { + if (mask & (1 << regno)) + { + asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[regno], + reg_names[next_hi_reg]); + high_regs_pushed--; + if (high_regs_pushed) + for (next_hi_reg--; next_hi_reg > 7; next_hi_reg--) + { + if (regs_ever_live[next_hi_reg] + && ! call_used_regs[next_hi_reg]) + break; + } + else + { + mask &= ~ ((1 << regno) - 1); + break; + } + } + } + thumb_pushpop (f, mask, 1); + } + + if (pushable_regs == 0 && (regs_ever_live[3] || ! call_used_regs[3])) + asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[3], reg_names[12]); + } +} + +void +thumb_expand_prologue () +{ + HOST_WIDE_INT amount = (get_frame_size () + + current_function_outgoing_args_size); + int regno; + int live_regs_mask; + + /* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + /* Naked functions don't have prologues. */ + if (arm_naked_function_p (current_function_decl)) + return; +#endif + /* END CYGNUS LOCAL nickc/thumb-pe */ + + if (amount) + { + live_regs_mask = 0; + for (regno = 0; regno < 8; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + live_regs_mask |= 1 << regno; + + if (amount < 512) + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (-amount))); + else + { + rtx reg, spare; + + if ((live_regs_mask & 0xff) == 0) /* Very unlikely */ + emit_insn (gen_movsi (spare = gen_rtx (REG, SImode, 12), + reg = gen_rtx (REG, SImode, 4))); + else + { + for (regno = 0; regno < 8; regno++) + if (live_regs_mask & (1 << regno)) + break; + reg = gen_rtx (REG, SImode, regno); + } + + emit_insn (gen_movsi (reg, GEN_INT (-amount))); + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); + if ((live_regs_mask & 0xff) == 0) + emit_insn (gen_movsi (reg, spare)); + } + } + + if (frame_pointer_needed) + { + if (current_function_outgoing_args_size) + { + rtx offset = GEN_INT (current_function_outgoing_args_size); + + if (current_function_outgoing_args_size < 1024) + emit_insn (gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx, + offset)); + else + { + emit_insn (gen_movsi (frame_pointer_rtx, offset)); + emit_insn (gen_addsi3 (frame_pointer_rtx, frame_pointer_rtx, + stack_pointer_rtx)); + } + } + else + emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx)); + } + + /* if (profile_flag || profile_block_flag) */ + emit_insn (gen_blockage ()); +} + +void +thumb_expand_epilogue () +{ + HOST_WIDE_INT amount = (get_frame_size () + + current_function_outgoing_args_size); + int regno; + + /* CYGNUS LOCAL nickc/thumb-pe */ +#ifdef THUMB_PE + /* Naked functions don't have epilogues. */ + if (arm_naked_function_p (current_function_decl)) + return; +#endif + /* END CYGNUS LOCAL nickc/thumb-pe */ + + if (amount) + { + if (amount < 512) + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (amount))); + else + { + rtx reg = gen_rtx (REG, SImode, 3); /* Always free in the epilogue */ + + emit_insn (gen_movsi (reg, GEN_INT (amount))); + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); + } + /* if (profile_flag || profile_block_flag) */ + emit_insn (gen_blockage ()); + } +} + +void +thumb_function_epilogue (f, frame_size) + FILE *f; + int frame_size; +{ + /* ??? Probably not safe to set this here, since it assumes that a + function will be emitted as assembly immediately after we generate + RTL for it. This does not happen for inline functions. */ + return_used_this_function = 0; + current_function_has_far_jump = 0; +#if 0 /* TODO : comment not really needed */ + fprintf (f, "%s THUMB Epilogue\n", ASM_COMMENT_START); +#endif +} + +/* The bits which aren't usefully expanded as rtl. */ +char * +thumb_unexpanded_epilogue () +{ + int regno; + int live_regs_mask = 0; + int high_regs_pushed = 0; + int leaf_function = leaf_function_p (); + int had_to_push_lr; + + if (return_used_this_function) + return ""; + + for (regno = 0; regno < 8; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + live_regs_mask |= 1 << regno; + + for (regno = 8; regno < 13; regno++) + { + if (regs_ever_live[regno] && ! call_used_regs[regno]) + high_regs_pushed ++; + } + + /* The prolog may have pushed some high registers to use as + work registers. eg the testuite file: + gcc/testsuite/gcc/gcc.c-torture/execute/complex-2.c + compiles to produce: + push {r4, r5, r6, r7, lr} + mov r7, r9 + mov r6, r8 + push {r6, r7} + as part of the prolog. We have to undo that pushing here. */ + + if (high_regs_pushed) + { + int mask = live_regs_mask; + int next_hi_reg; + int size; + int mode; + +#ifdef RTX_CODE + /* If we can deduce the registers used from the function's return value. + This is more reliable that examining regs_ever_live[] because that + will be set if the register is ever used in the function, not just if + the register is used to hold a return value. */ + + if (current_function_return_rtx != 0) + { + mode = GET_MODE (current_function_return_rtx); + } + else +#endif + { + mode = DECL_MODE (DECL_RESULT (current_function_decl)); + } + + size = GET_MODE_SIZE (mode); + + /* Unless we are returning a type of size > 12 register r3 is available. */ + if (size < 13) + mask |= 1 << 3; + + if (mask == 0) + { + /* Oh dear! We have no low registers into which we can pop high registers! */ + + fatal ("No low registers available for popping high registers"); + } + + for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++) + if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) + break; + + while (high_regs_pushed) + { + /* Find low register(s) into which the high register(s) can be popped. */ + for (regno = 0; regno < 8; regno++) + { + if (mask & (1 << regno)) + high_regs_pushed--; + if (high_regs_pushed == 0) + break; + } + + mask &= (2 << regno) - 1; /* A noop if regno == 8 */ + + /* Pop the values into the low register(s). */ + thumb_pushpop (asm_out_file, mask, 0); + + /* Move the value(s) into the high registers. */ + for (regno = 0; regno < 8; regno++) + { + if (mask & (1 << regno)) + { + asm_fprintf (asm_out_file, "\tmov\t%s, %s\n", + reg_names[next_hi_reg], reg_names[regno]); + for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++) + if (regs_ever_live[next_hi_reg] && + ! call_used_regs[next_hi_reg]) + break; + } + } + } + } + + had_to_push_lr = (live_regs_mask || ! leaf_function || far_jump_used_p()); + + if (TARGET_BACKTRACE && ((live_regs_mask & 0xFF) == 0) && regs_ever_live[ ARG_4_REGISTER ] != 0) + { + /* The stack backtrace structure creation code had to + push R7 in order to get a work register, so we pop + it now. */ + + live_regs_mask |= (1 << WORK_REGISTER); + } + + if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE) + { + if (had_to_push_lr + && ! is_called_in_ARM_mode (current_function_decl)) + live_regs_mask |= 1 << PROGRAM_COUNTER; + + /* Either no argument registers were pushed or a backtrace + structure was created which includes an adjusted stack + pointer, so just pop everything. */ + + if (live_regs_mask) + thumb_pushpop (asm_out_file, live_regs_mask, FALSE); + + /* We have either just popped the return address into the + PC or it is was kept in LR for the entire function or + it is still on the stack because we do not want to + return by doing a pop {pc}. */ + + if ((live_regs_mask & (1 << PROGRAM_COUNTER)) == 0) + thumb_exit (asm_out_file, + (had_to_push_lr + && is_called_in_ARM_mode (current_function_decl)) ? + -1 : LINK_REGISTER); + } + else + { + /* Pop everything but the return address. */ + live_regs_mask &= ~ (1 << PROGRAM_COUNTER); + + if (live_regs_mask) + thumb_pushpop (asm_out_file, live_regs_mask, FALSE); + + if (had_to_push_lr) + { + /* Get the return address into a temporary register. */ + thumb_pushpop (asm_out_file, 1 << ARG_4_REGISTER, 0); + } + + /* Remove the argument registers that were pushed onto the stack. */ + asm_fprintf (asm_out_file, "\tadd\t%s, %s, #%d\n", + reg_names [STACK_POINTER], + reg_names [STACK_POINTER], + current_function_pretend_args_size); + + thumb_exit (asm_out_file, had_to_push_lr ? ARG_4_REGISTER : LINK_REGISTER); + } + + return ""; +} + +/* Handle the case of a double word load into a low register from + a computed memory address. The computed address may involve a + register which is overwritten by the load. */ + +char * +thumb_load_double_from_address (operands) + rtx * operands; +{ + rtx addr; + rtx base; + rtx offset; + rtx arg1; + rtx arg2; + + if (GET_CODE (operands[0]) != REG) + fatal ("thumb_load_double_from_address: destination is not a register"); + + if (GET_CODE (operands[1]) != MEM) + fatal ("thumb_load_double_from_address: source is not a computed memory address"); + + /* Get the memory address. */ + + addr = XEXP (operands[1], 0); + + /* Work out how the memory address is computed. */ + + switch (GET_CODE (addr)) + { + case REG: + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); + + if (REGNO (operands[0]) == REGNO (addr)) + { + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + } + else + { + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + } + break; + + case CONST: + /* Compute
+ 4 for the high order load. */ + + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); + + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + break; + + case PLUS: + arg1 = XEXP (addr, 0); + arg2 = XEXP (addr, 1); + + if (CONSTANT_P (arg1)) + base = arg2, offset = arg1; + else + base = arg1, offset = arg2; + + if (GET_CODE (base) != REG) + fatal ("thumb_load_double_from_address: base is not a register"); + + /* Catch the case of
= + */ + + if (GET_CODE (offset) == REG) + { + int reg_offset = REGNO (offset); + int reg_base = REGNO (base); + int reg_dest = REGNO (operands[0]); + + /* Add the base and offset registers together into the higher destination register. */ + + fprintf (asm_out_file, "\tadd\t%s, %s, %s\t\t%s created by thumb_load_double_from_address", + reg_names[ reg_dest + 1 ], + reg_names[ reg_base ], + reg_names[ reg_offset ], + ASM_COMMENT_START); + + /* Load the lower destination register from the address in the higher destination register. */ + + fprintf (asm_out_file, "\tldr\t%s, [%s, #0]\t\t%s created by thumb_load_double_from_address", + reg_names[ reg_dest ], + reg_names[ reg_dest + 1], + ASM_COMMENT_START); + + /* Load the higher destination register from its own address plus 4. */ + + fprintf (asm_out_file, "\tldr\t%s, [%s, #4]\t\t%s created by thumb_load_double_from_address", + reg_names[ reg_dest + 1 ], + reg_names[ reg_dest + 1 ], + ASM_COMMENT_START); + } + else + { + /* Compute
+ 4 for the high order load. */ + + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); + + /* If the computed address is held in the low order register + then load the high order register first, otherwise always + load the low order register first. */ + + if (REGNO (operands[0]) == REGNO (base)) + { + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + } + else + { + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + } + } + break; + + case LABEL_REF: + /* With no registers to worry about we can just load the value directly. */ + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); + + output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); + output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); + break; + + default: + debug_rtx (operands[1]); + fatal ("thumb_load_double_from_address: Unhandled address calculation"); + break; + } + + return ""; +} + +char * +output_move_mem_multiple (n, operands) + int n; + rtx *operands; +{ + rtx tmp; + + switch (n) + { + case 2: + if (REGNO (operands[2]) > REGNO (operands[3])) + { + tmp = operands[2]; + operands[2] = operands[3]; + operands[3] = tmp; + } + output_asm_insn ("ldmia\t%1!, {%2, %3}", operands); + output_asm_insn ("stmia\t%0!, {%2, %3}", operands); + break; + + case 3: + if (REGNO (operands[2]) > REGNO (operands[3])) + { + tmp = operands[2]; + operands[2] = operands[3]; + operands[3] = tmp; + } + if (REGNO (operands[3]) > REGNO (operands[4])) + { + tmp = operands[3]; + operands[3] = operands[4]; + operands[4] = tmp; + } + if (REGNO (operands[2]) > REGNO (operands[3])) + { + tmp = operands[2]; + operands[2] = operands[3]; + operands[3] = tmp; + } + output_asm_insn ("ldmia\t%1!, {%2, %3, %4}", operands); + output_asm_insn ("stmia\t%0!, {%2, %3, %4}", operands); + break; + + default: + abort (); + } + + return ""; +} + + +int +thumb_epilogue_size () +{ + return 42; /* The answer to .... */ +} + +static char *conds[] = +{ + "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", + "hi", "ls", "ge", "lt", "gt", "le" +}; + +static char * +thumb_condition_code (x, invert) + rtx x; + int invert; +{ + int val; + + switch (GET_CODE (x)) + { + case EQ: val = 0; break; + case NE: val = 1; break; + case GEU: val = 2; break; + case LTU: val = 3; break; + case GTU: val = 8; break; + case LEU: val = 9; break; + case GE: val = 10; break; + case LT: val = 11; break; + case GT: val = 12; break; + case LE: val = 13; break; + default: + abort (); + } + + return conds[val ^ invert]; +} + +void +thumb_print_operand (f, x, code) + FILE *f; + rtx x; + int code; +{ + if (code) + { + switch (code) + { + case '@': + fputs (ASM_COMMENT_START, f); + return; + + case '_': + fputs (user_label_prefix, f); + return; + + case 'D': + if (x) + fputs (thumb_condition_code (x, 1), f); + return; + + case 'd': + if (x) + fputs (thumb_condition_code (x, 0), f); + return; + + /* An explanation of the 'Q', 'R' and 'H' register operands: + + In a pair of registers containing a DI or DF value the 'Q' + operand returns the register number of the register containing + the least signficant part of the value. The 'R' operand returns + the register number of the register containing the most + significant part of the value. + + The 'H' operand returns the higher of the two register numbers. + On a run where WORDS_BIG_ENDIAN is true the 'H' operand is the + same as the 'Q' operand, since the most signficant part of the + value is held in the lower number register. The reverse is true + on systems where WORDS_BIG_ENDIAN is false. + + The purpose of these operands is to distinguish between cases + where the endian-ness of the values is important (for example + when they are added together), and cases where the endian-ness + is irrelevant, but the order of register operations is important. + For example when loading a value from memory into a register + pair, the endian-ness does not matter. Provided that the value + from the lower memory address is put into the lower numbered + register, and the value from the higher address is put into the + higher numbered register, the load will work regardless of whether + the value being loaded is big-wordian or little-wordian. The + order of the two register loads can matter however, if the address + of the memory location is actually held in one of the registers + being overwritten by the load. */ + case 'Q': + if (REGNO (x) > 15) + abort (); + fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0)], f); + return; + + case 'R': + if (REGNO (x) > 15) + abort (); + fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1)], f); + return; + + case 'H': + if (REGNO (x) > 15) + abort (); + fputs (reg_names[REGNO (x) + 1], f); + return; + + case 'c': + /* We use 'c' operands with symbols for .vtinherit */ + if (GET_CODE (x) == SYMBOL_REF) + output_addr_const(f, x); + return; + + default: + abort (); + } + } + if (GET_CODE (x) == REG) + fputs (reg_names[REGNO (x)], f); + else if (GET_CODE (x) == MEM) + output_address (XEXP (x, 0)); + else if (GET_CODE (x) == CONST_INT) + { + fputc ('#', f); + output_addr_const (f, x); + } + else + abort (); +} + +#ifdef AOF_ASSEMBLER +int arm_text_section_count = 1; + +char * +aof_text_section (in_readonly) + int in_readonly; +{ + static char buf[100]; + if (in_readonly) + return ""; + sprintf (buf, "\tCODE16\n\tAREA |C$$code%d|, CODE, READONLY", + arm_text_section_count++); + return buf; +} + +static int arm_data_section_count = 1; + +char * +aof_data_section () +{ + static char buf[100]; + sprintf (buf, "\tAREA |C$$data%d|, DATA", arm_data_section_count++); + return buf; +} + +/* The AOF thumb assembler is religiously strict about declarations of + imported and exported symbols, so that it is impossible to declare a + function as imported near the begining of the file, and then to export + it later on. It is, however, possible to delay the decision until all + the functions in the file have been compiled. To get around this, we + maintain a list of the imports and exports, and delete from it any that + are subsequently defined. At the end of compilation we spit the + remainder of the list out before the END directive. */ + +struct import +{ + struct import *next; + char *name; +}; + +static struct import *imports_list = NULL; + +void +thumb_aof_add_import (name) + char *name; +{ + struct import *new; + + for (new = imports_list; new; new = new->next) + if (new->name == name) + return; + + new = (struct import *) xmalloc (sizeof (struct import)); + new->next = imports_list; + imports_list = new; + new->name = name; +} + +void +thumb_aof_delete_import (name) + char *name; +{ + struct import **old; + + for (old = &imports_list; *old; old = & (*old)->next) + { + if ((*old)->name == name) + { + *old = (*old)->next; + return; + } + } +} + +void +thumb_aof_dump_imports (f) + FILE *f; +{ + while (imports_list) + { + fprintf (f, "\tIMPORT\t"); + assemble_name (f, imports_list->name); + fputc ('\n', f); + imports_list = imports_list->next; + } +} +#endif + +/* Decide whether a type should be returned in memory (true) + or in a register (false). This is called by the macro + RETURN_IN_MEMORY. */ + +int +thumb_return_in_memory (type) + tree type; +{ + if (! AGGREGATE_TYPE_P (type)) + { + /* All simple types are returned in registers. */ + + return 0; + } + else if (int_size_in_bytes (type) > 4) + { + /* All structures/unions bigger than one word are returned in memory. */ + + return 1; + } + else if (TREE_CODE (type) == RECORD_TYPE) + { + tree field; + + /* For a struct the APCS says that we must return in a register if + every addressable element has an offset of zero. For practical + purposes this means that the structure can have at most one non- + bit-field element and that this element must be the first one in + the structure. */ + + /* Find the first field, ignoring non FIELD_DECL things which will + have been created by C++. */ + for (field = TYPE_FIELDS (type); + field && TREE_CODE (field) != FIELD_DECL; + field = TREE_CHAIN (field)) + continue; + + if (field == NULL) + return 0; /* An empty structure. Allowed by an extension to ANSI C. */ + + /* Now check the remaining fields, if any. */ + for (field = TREE_CHAIN (field); field; field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + + if (! DECL_BIT_FIELD_TYPE (field)) + return 1; + } + + return 0; + } + else if (TREE_CODE (type) == UNION_TYPE) + { + tree field; + + /* Unions can be returned in registers if every element is + integral, or can be returned in an integer register. */ + + for (field = TYPE_FIELDS (type); + field; + field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + + if (RETURN_IN_MEMORY (TREE_TYPE (field))) + return 1; + } + + return 0; + } + /* XXX Not sure what should be done for other aggregates, so put them in + memory. */ + return 1; +} + +void +thumb_override_options () +{ + if (structure_size_string != NULL) + { + int size = strtol (structure_size_string, NULL, 0); + + if (size == 8 || size == 32) + arm_structure_size_boundary = size; + else + warning ("Structure size boundary can only be set to 8 or 32"); + } + + if (flag_pic) + { + warning ("Position independent code not supported. Ignored"); + flag_pic = 0; + } +} + +/* CYGNUS LOCAL nickc/thumb-pe */ + +#ifdef THUMB_PE +/* Return nonzero if ATTR is a valid attribute for DECL. + ATTRIBUTES are any existing attributes and ARGS are the arguments + supplied with ATTR. + + Supported attributes: + + naked: don't output any prologue or epilogue code, the user is assumed + to do the right thing. + + interfacearm: Always assume that this function will be entered in ARM + mode, not Thumb mode, and that the caller wishes to be returned to in + ARM mode. */ +int +arm_valid_machine_decl_attribute (decl, attributes, attr, args) + tree decl; + tree attributes; + tree attr; + tree args; +{ + if (args != NULL_TREE) + return 0; + + if (is_attribute_p ("naked", attr)) + return TREE_CODE (decl) == FUNCTION_DECL; + + if (is_attribute_p ("interfacearm", attr)) + return TREE_CODE (decl) == FUNCTION_DECL; + + return 0; +} +#endif /* THUMB_PE */ +/* END CYGNUS LOCAL nickc/thumb-pe */ + +/* Return nonzero if ATTR is a valid attribute for TYPE. + ATTRIBUTES are any existing attributes and ARGS are the arguments + supplied with ATTR. + + Supported attributes: + + short_call: assume the offset from the caller to the callee is small. + + long_call: don't assume the offset is small. */ + +int +arm_valid_machine_type_attribute (type, attributes, attr, args) + tree type; + tree attributes; + tree attr; + tree args; +{ + if (args != NULL_TREE) + return 0; + + if (is_attribute_p ("long_call", attr)) + return 1; + + if (is_attribute_p ("short_call", attr)) + return 1; + + return 0; +} + +/* Encode long_call or short_call attribute by prefixing + symbol name in DECL with a special character FLAG. */ + +void +arm_encode_call_attribute (decl, flag) + tree decl; + int flag; +{ + const char * str = XSTR (XEXP (DECL_RTL (decl), 0), 0); + int len = strlen (str); + char * newstr; + + /* Do not allow weak functions to be treated as short call. */ + if (DECL_WEAK (decl) && flag == SHORT_CALL_FLAG_CHAR) + return; + + if (ENCODED_SHORT_CALL_ATTR_P (str) + || ENCODED_LONG_CALL_ATTR_P (str)) + return; + + newstr = malloc (len + 2); + newstr[0] = flag; + strcpy (newstr + 1, str); + + XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr; +} + +/* Return the length of a function name prefix + that starts with the character 'c'. */ + +static int +arm_get_strip_length (char c) +{ + switch (c) + { + ARM_NAME_ENCODING_LENGTHS + default: return 0; + } +} + +/* Return a pointer to a function's name with any + and all prefix encodings stripped from it. */ + +char * +arm_strip_name_encoding (char * name) +{ + int skip; + + while ((skip = arm_get_strip_length (* name))) + name += skip; + + return name; +} + +/* Return 1 if the operand is a SYMBOL_REF for a function known to be + defined within the current compilation unit. If this caanot be + determined, then 0 is returned. */ + +static int +current_file_function_operand (sym_ref) + rtx sym_ref; +{ + /* This is a bit of a fib. A function will have a short call flag + applied to its name if it has the short call attribute, or it has + already been defined within the current compilation unit. */ + if (ENCODED_SHORT_CALL_ATTR_P (XSTR (sym_ref, 0))) + return 1; + + /* The current function is always defined within the current compilation + unit. if it s a weak definition however, then this may not be the real + definition of the function, and so we have to say no. */ + if (sym_ref == XEXP (DECL_RTL (current_function_decl), 0) + && !DECL_WEAK (current_function_decl)) + return 1; + + /* We cannot make the determination - default to returning 0. */ + return 0; +} + +/* Return non-zero if a 32 bit "long_call" should be generated for + this call. We generate a long_call if the function: + + a. has an __attribute__((long call)) + or b. the -mlong-calls command line switch has been specified + + However we do not generate a long call if the function: + + c. has an __attribute__ ((short_call)) + or d. has an __attribute__ ((section)) + or e. is defined within the current compilation unit. + + This function will be called by C fragments contained in the machine + description file. CALL_REF and CALL_COOKIE correspond to the matched + rtl operands. CALL_SYMBOL is used to distinguish between + two different callers of the function. It is set to 1 in the + "call_symbol" and "call_symbol_value" patterns and to 0 in the "call" + and "call_value" patterns. This is because of the difference in the + SYM_REFs passed by these patterns. */ + +int +arm_is_longcall_p (sym_ref, call_cookie, call_symbol) + rtx sym_ref; + int call_cookie; + int call_symbol; +{ + if (!call_symbol) + { + if (GET_CODE (sym_ref) != MEM) + return 0; + + sym_ref = XEXP (sym_ref, 0); + } + + if (GET_CODE (sym_ref) != SYMBOL_REF) + return 0; + + if (call_cookie & CALL_SHORT) + return 0; + + if (TARGET_LONG_CALLS && flag_function_sections) + return 1; + + if (current_file_function_operand (sym_ref)) + return 0; + + return (call_cookie & CALL_LONG) + || ENCODED_LONG_CALL_ATTR_P (XSTR (sym_ref, 0)) + || TARGET_LONG_CALLS; +} + +/* s_register_operand is the same as register_operand, but it doesn't accept + (SUBREG (MEM)...). + + This function exists because at the time it was put in it led to better + code. SUBREG(MEM) always needs a reload in the places where + s_register_operand is used, and this seemed to lead to excessive + reloading. */ + +int +s_register_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + if (GET_MODE (op) != mode && mode != VOIDmode) + return 0; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + /* We don't consider registers whose class is NO_REGS + to be a register operand. */ + /* XXX might have to check for lo regs only for thumb ??? */ + return (GET_CODE (op) == REG + && (REGNO (op) >= FIRST_PSEUDO_REGISTER + || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); +} diff --git a/gcc_arm/config/arm/thumb_020422.h b/gcc_arm/config/arm/thumb_020422.h new file mode 100755 index 0000000..554ed1d --- /dev/null +++ b/gcc_arm/config/arm/thumb_020422.h @@ -0,0 +1,1295 @@ +/* Definitions of target machine for GNU compiler, for ARM/Thumb. + Copyright (C) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc. + The basis of this contribution was generated by + Richard Earnshaw, Advanced RISC Machines Ltd + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* ??? The files thumb.{c,h,md} are all seriously lacking comments. */ + +/* ??? The files thumb.{c,h,md} need to be reviewed by an experienced + gcc hacker in their entirety. */ + +/* ??? The files thumb.{c,h,md} and tcoff.h are all separate from the arm + files, which will lead to many maintenance problems. These files are + likely missing all bug fixes made to the arm port since they diverged. */ + +/* ??? Many patterns in the md file accept operands that will require a + reload. These should be eliminated if possible by tightening the + predicates and/or constraints. This will give faster/smaller code. */ + +/* ??? There is no pattern for the TST instuction. Check for other unsupported + instructions. */ + +/* Run Time Target Specifications */ +#ifndef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dthumb -D__thumb -Acpu(arm) -Amachine(arm)" +#endif + +#ifndef CPP_SPEC +#define CPP_SPEC "\ +%{mbig-endian:-D__ARMEB__ -D__THUMBEB__} \ +%{mbe:-D__ARMEB__ -D__THUMBEB__} \ +%{!mbe: %{!mbig-endian:-D__ARMEL__ -D__THUMBEL__}} \ +" +#endif + +#ifndef ASM_SPEC +#define ASM_SPEC "-marm7tdmi %{mthumb-interwork:-mthumb-interwork} %{mbig-endian:-EB}" +#endif +#define LINK_SPEC "%{mbig-endian:-EB} -X" + +#define TARGET_VERSION fputs (" (ARM/THUMB:generic)", stderr); + +/* Nonzero if we should compile with BYTES_BIG_ENDIAN set to 1. */ +#define THUMB_FLAG_BIG_END 0x0001 +#define THUMB_FLAG_BACKTRACE 0x0002 +#define THUMB_FLAG_LEAF_BACKTRACE 0x0004 +#define ARM_FLAG_THUMB 0x1000 /* same as in arm.h */ +#define THUMB_FLAG_CALLEE_SUPER_INTERWORKING 0x40000 +#define THUMB_FLAG_CALLER_SUPER_INTERWORKING 0x80000 + +/* Nonzero if all call instructions should be indirect. */ +#define ARM_FLAG_LONG_CALLS (0x10000) /* same as in arm.h */ + + +/* Run-time compilation parameters selecting different hardware/software subsets. */ +extern int target_flags; +#define TARGET_DEFAULT 0 /* ARM_FLAG_THUMB */ +#define TARGET_BIG_END (target_flags & THUMB_FLAG_BIG_END) +#define TARGET_THUMB_INTERWORK (target_flags & ARM_FLAG_THUMB) +#define TARGET_BACKTRACE (leaf_function_p() \ + ? (target_flags & THUMB_FLAG_LEAF_BACKTRACE) \ + : (target_flags & THUMB_FLAG_BACKTRACE)) + +/* Set if externally visable functions should assume that they + might be called in ARM mode, from a non-thumb aware code. */ +#define TARGET_CALLEE_INTERWORKING \ + (target_flags & THUMB_FLAG_CALLEE_SUPER_INTERWORKING) + +/* Set if calls via function pointers should assume that their + destination is non-Thumb aware. */ +#define TARGET_CALLER_INTERWORKING \ + (target_flags & THUMB_FLAG_CALLER_SUPER_INTERWORKING) + +#define TARGET_LONG_CALLS (target_flags & ARM_FLAG_LONG_CALLS) + +/* SUBTARGET_SWITCHES is used to add flags on a per-config basis. */ +#ifndef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES +#endif + +#define TARGET_SWITCHES \ +{ \ + {"big-endian", THUMB_FLAG_BIG_END}, \ + {"little-endian", -THUMB_FLAG_BIG_END}, \ + {"thumb-interwork", ARM_FLAG_THUMB}, \ + {"no-thumb-interwork", -ARM_FLAG_THUMB}, \ + {"tpcs-frame", THUMB_FLAG_BACKTRACE}, \ + {"no-tpcs-frame", -THUMB_FLAG_BACKTRACE}, \ + {"tpcs-leaf-frame", THUMB_FLAG_LEAF_BACKTRACE}, \ + {"no-tpcs-leaf-frame", -THUMB_FLAG_LEAF_BACKTRACE}, \ + {"callee-super-interworking", THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \ + {"no-callee-super-interworking", -THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \ + {"caller-super-interworking", THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \ + {"no-caller-super-interworking", -THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \ + {"long-calls", ARM_FLAG_LONG_CALLS, \ + "Generate all call instructions as indirect calls"}, \ + {"no-long-calls", -ARM_FLAG_LONG_CALLS, ""}, \ + SUBTARGET_SWITCHES \ + {"", TARGET_DEFAULT} \ +} + +#define TARGET_OPTIONS \ +{ \ + { "structure-size-boundary=", & structure_size_string }, \ +} + +#define REGISTER_PREFIX "" + +#define CAN_DEBUG_WITHOUT_FP 1 + +#define ASM_APP_ON "" +#define ASM_APP_OFF "\t.code\t16\n" + +/* Output a gap. In fact we fill it with nulls. */ +#define ASM_OUTPUT_SKIP(STREAM, NBYTES) \ + fprintf ((STREAM), "\t.space\t%u\n", (NBYTES)) + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ +#define ASM_OUTPUT_ALIGN(STREAM,LOG) \ +{ \ + if ((LOG) > 0) \ + fprintf (STREAM, "\t.align\t%d\n", (LOG)); \ +} + +/* Output a common block */ +#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ + (fprintf ((STREAM), "\t.comm\t"), \ + assemble_name ((STREAM), (NAME)), \ + fprintf((STREAM), ", %d\t%s %d\n", (ROUNDED), (ASM_COMMENT_START), (SIZE))) + +#define ASM_GENERATE_INTERNAL_LABEL(STRING,PREFIX,NUM) \ + sprintf ((STRING), "*%s%s%d", (LOCAL_LABEL_PREFIX), (PREFIX), (NUM)) + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ +#define ASM_OUTPUT_INTERNAL_LABEL(STREAM,PREFIX,NUM) \ + fprintf ((STREAM), "%s%s%d:\n", (LOCAL_LABEL_PREFIX), (PREFIX), (NUM)) + +/* This is how to output a label which precedes a jumptable. Since + instructions are 2 bytes, we need explicit alignment here. */ + +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,JUMPTABLE) \ + do { \ + ASM_OUTPUT_ALIGN (FILE, 2); \ + ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM); \ + } while (0) + +/* This says how to define a local common symbol (ie, not visible to + linker). */ +#define ASM_OUTPUT_LOCAL(STREAM, NAME, SIZE, ROUNDED) \ + (fprintf((STREAM),"\n\t.lcomm\t"), \ + assemble_name((STREAM),(NAME)), \ + fprintf((STREAM),",%u\n",(SIZE))) + +/* This is how to output an assembler line for a numeric constant byte. */ +#define ASM_OUTPUT_BYTE(STREAM,VALUE) \ + fprintf ((STREAM), "\t.byte\t0x%x\n", (VALUE)) + +#define ASM_OUTPUT_INT(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.word\t"); \ + output_addr_const (STREAM, (VALUE)); \ + fprintf (STREAM, "\n"); \ +} + +#define ASM_OUTPUT_SHORT(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.short\t"); \ + output_addr_const (STREAM, (VALUE)); \ + fprintf (STREAM, "\n"); \ +} + +#define ASM_OUTPUT_CHAR(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.byte\t"); \ + output_addr_const (STREAM, (VALUE)); \ + fprintf (STREAM, "\n"); \ +} + +#define ASM_OUTPUT_LONG_DOUBLE(STREAM,VALUE) \ +do { char dstr[30]; \ + long l[3]; \ + REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ + fprintf (STREAM, "\t.long 0x%lx,0x%lx,0x%lx\t%s long double %s\n", \ + l[0], l[1], l[2], ASM_COMMENT_START, dstr); \ + } while (0) + +#define ASM_OUTPUT_DOUBLE(STREAM, VALUE) \ +do { char dstr[30]; \ + long l[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.14g", dstr); \ + fprintf (STREAM, "\t.long 0x%lx, 0x%lx\t%s double %s\n", l[0], \ + l[1], ASM_COMMENT_START, dstr); \ + } while (0) + +#define ASM_OUTPUT_FLOAT(STREAM, VALUE) \ +do { char dstr[30]; \ + long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.7g", dstr); \ + fprintf (STREAM, "\t.word 0x%lx\t%s float %s\n", l, \ + ASM_COMMENT_START, dstr); \ + } while (0); + +/* Define results of standard character escape sequences. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* This is how to output a string. */ +#define ASM_OUTPUT_ASCII(STREAM, STRING, LEN) \ +do { \ + register int i, c, len = (LEN), cur_pos = 17; \ + register unsigned char *string = (unsigned char *)(STRING); \ + fprintf ((STREAM), "\t.ascii\t\""); \ + for (i = 0; i < len; i++) \ + { \ + register int c = string[i]; \ + \ + switch (c) \ + { \ + case '\"': \ + case '\\': \ + putc ('\\', (STREAM)); \ + putc (c, (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_NEWLINE: \ + fputs ("\\n", (STREAM)); \ + if (i+1 < len \ + && (((c = string[i+1]) >= '\040' && c <= '~') \ + || c == TARGET_TAB)) \ + cur_pos = 32767; /* break right here */ \ + else \ + cur_pos += 2; \ + break; \ + \ + case TARGET_TAB: \ + fputs ("\\t", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_FF: \ + fputs ("\\f", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_BS: \ + fputs ("\\b", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_CR: \ + fputs ("\\r", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + default: \ + if (c >= ' ' && c < 0177) \ + { \ + putc (c, (STREAM)); \ + cur_pos++; \ + } \ + else \ + { \ + fprintf ((STREAM), "\\%03o", c); \ + cur_pos += 4; \ + } \ + } \ + \ + if (cur_pos > 72 && i+1 < len) \ + { \ + cur_pos = 17; \ + fprintf ((STREAM), "\"\n\t.ascii\t\""); \ + } \ + } \ + fprintf ((STREAM), "\"\n"); \ +} while (0) + +/* Output and Generation of Labels */ +#define ASM_OUTPUT_LABEL(STREAM,NAME) \ + (assemble_name ((STREAM), (NAME)), \ + fprintf ((STREAM), ":\n")) + +#define ASM_GLOBALIZE_LABEL(STREAM,NAME) \ + (fprintf ((STREAM), "\t.globl\t"), \ + assemble_name ((STREAM), (NAME)), \ + fputc ('\n', (STREAM))) + +/* Construct a private name. */ +#define ASM_FORMAT_PRIVATE_NAME(OUTVAR,NAME,NUMBER) \ + ((OUTVAR) = (char *) alloca (strlen (NAME) + 10), \ + sprintf ((OUTVAR), "%s.%d", (NAME), (NUMBER))) + +/* Switch to the text or data segment. */ +#define TEXT_SECTION_ASM_OP ".text" +#define DATA_SECTION_ASM_OP ".data" +#define BSS_SECTION_ASM_OP ".bss" + +/* The assembler's names for the registers. */ +#ifndef REGISTER_NAMES +#define REGISTER_NAMES \ +{ \ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc", "ap" \ +} +#endif + +#ifndef ADDITIONAL_REGISTER_NAMES +#define ADDITIONAL_REGISTER_NAMES \ +{ \ + {"a1", 0}, \ + {"a2", 1}, \ + {"a3", 2}, \ + {"a4", 3}, \ + {"v1", 4}, \ + {"v2", 5}, \ + {"v3", 6}, \ + {"v4", 7}, \ + {"v5", 8}, \ + {"v6", 9}, \ + {"sb", 9}, \ + {"v7", 10}, \ + {"r10", 10}, /* sl */ \ + {"r11", 11}, /* fp */ \ + {"r12", 12}, /* ip */ \ + {"r13", 13}, /* sp */ \ + {"r14", 14}, /* lr */ \ + {"r15", 15} /* pc */ \ +} +#endif + +/* The assembler's parentheses characters. */ +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + +#ifndef ASM_COMMENT_START +#define ASM_COMMENT_START "@" +#endif + +/* Output an element of a dispatch table. */ +#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM,VALUE) \ + fprintf (STREAM, "\t.word\t%sL%d\n", (LOCAL_LABEL_PREFIX), (VALUE)) + +#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM,BODY,VALUE,REL) \ + fprintf (STREAM, "\tb\t%sL%d\n", (LOCAL_LABEL_PREFIX), (VALUE)) + +/* Storage Layout */ + +/* Define this is most significant bit is lowest numbered in + instructions that operate on numbered bit-fields. */ +#define BITS_BIG_ENDIAN 0 + +/* Define this if most significant byte of a word is the lowest + numbered. */ +#define BYTES_BIG_ENDIAN (TARGET_BIG_END != 0) + +#define WORDS_BIG_ENDIAN (BYTES_BIG_ENDIAN) + +/* LIBGCC2_WORDS_BIG_ENDIAN has to be a constant, so we define this based + on processor pre-defineds when compiling libgcc2.c. */ +#if defined(__THUMBEB__) && !defined(__THUMBEL__) +#define LIBGCC2_WORDS_BIG_ENDIAN 1 +#else +#define LIBGCC2_WORDS_BIG_ENDIAN 0 +#endif + +#define FLOAT_WORDS_BIG_ENDIAN 1 + +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 + +#define UNITS_PER_WORD 4 + +#define POINTER_SIZE 32 + +#define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \ +{ \ + if (GET_MODE_CLASS (MODE) == MODE_INT \ + && GET_MODE_SIZE (MODE) < 4) \ + { \ + (UNSIGNEDP) = 1; \ + (MODE) = SImode; \ + } \ +} + +#define PARM_BOUNDARY 32 +#define STACK_BOUNDARY 32 + +#define FUNCTION_BOUNDARY 32 +#define BIGGEST_ALIGNMENT 32 + +/* Make strings word-aligned so strcpy from constants will be faster. */ +#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ + (TREE_CODE (EXP) == STRING_CST \ + && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) + +#define EMPTY_FIELD_BOUNDARY 32 + +#define STRUCTURE_SIZE_BOUNDARY 32 + +/* Used when parsing command line option -mstructure_size_boundary. */ +extern char * structure_size_string; + +#define STRICT_ALIGNMENT 1 + +#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT + + +/* Layout of Source Language Data Types */ + +#define DEFAULT_SIGNED_CHAR 0 + +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + + +/* Register Usage */ + +/* Note there are 16 hard registers on the Thumb. We invent a 17th register + which is assigned to ARG_POINTER_REGNUM, but this is later removed by + elimination passes in the compiler. */ +#define FIRST_PSEUDO_REGISTER 17 + +/* ??? This is questionable. */ +#define FIXED_REGISTERS \ +{ \ + 0,0,0,0, \ + 0,0,0,0, \ + 0,0,0,1, \ + 0,1,1,1,1 \ +} + +/* ??? This is questionable. */ +#define CALL_USED_REGISTERS \ +{ \ + 1,1,1,1, \ + 0,0,0,0, \ + 0,0,0,1, \ + 1,1,1,1,1 \ +} + +#define HARD_REGNO_NREGS(REGNO,MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ + / UNITS_PER_WORD) + +/* ??? Probably should only allow DImode/DFmode in even numbered registers. */ +#define HARD_REGNO_MODE_OK(REGNO,MODE) ((GET_MODE_SIZE (MODE) > UNITS_PER_WORD) ? (REGNO < 7) : 1) + +#define MODES_TIEABLE_P(MODE1,MODE2) 1 + +/* The NOARG_LO_REGS class is the set of LO_REGS that are not used for passing + arguments to functions. These are the registers that are available for + spilling during reload. The code in reload1.c:init_reload() will detect this + class and place it into 'reload_address_base_reg_class'. */ + +enum reg_class +{ + NO_REGS, + NONARG_LO_REGS, + LO_REGS, + STACK_REG, + BASE_REGS, + HI_REGS, + ALL_REGS, + LIM_REG_CLASSES +}; + +#define GENERAL_REGS ALL_REGS + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +#define REG_CLASS_NAMES \ +{ \ + "NO_REGS", \ + "NONARG_LO_REGS", \ + "LO_REGS", \ + "STACK_REG", \ + "BASE_REGS", \ + "HI_REGS", \ + "ALL_REGS" \ +} + +#define REG_CLASS_CONTENTS \ +{ \ + 0x00000, \ + 0x000f0, \ + 0x000ff, \ + 0x02000, \ + 0x020ff, \ + 0x0ff00, \ + 0x1ffff, \ +} + +#define REGNO_REG_CLASS(REGNO) \ + ((REGNO) == STACK_POINTER_REGNUM ? STACK_REG \ + : (REGNO) < 8 ? ((REGNO) < 4 ? LO_REGS \ + : NONARG_LO_REGS) \ + : HI_REGS) + +#define BASE_REG_CLASS BASE_REGS + +#define MODE_BASE_REG_CLASS(MODE) \ + ((MODE) != QImode && (MODE) != HImode \ + ? BASE_REGS : LO_REGS) + +#define INDEX_REG_CLASS LO_REGS + +/* When SMALL_REGISTER_CLASSES is nonzero, the compiler allows + registers explicitly used in the rtl to be used as spill registers + but prevents the compiler from extending the lifetime of these + registers. */ + +#define SMALL_REGISTER_CLASSES 1 + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'l' ? LO_REGS \ + : (C) == 'h' ? HI_REGS \ + : (C) == 'b' ? BASE_REGS \ + : (C) == 'k' ? STACK_REG \ + : NO_REGS) + +#define REGNO_OK_FOR_BASE_P(REGNO) \ + ((REGNO) < 8 \ + || (REGNO) == STACK_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO] < 8 \ + || (unsigned) reg_renumber[REGNO] == STACK_POINTER_REGNUM) + +#define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) \ + ((REGNO) < 8 \ + || (unsigned) reg_renumber[REGNO] < 8 \ + || (GET_MODE_SIZE (MODE) >= 4 \ + && ((REGNO) == STACK_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO] == STACK_POINTER_REGNUM))) + +#define REGNO_OK_FOR_INDEX_P(REGNO) \ + ((REGNO) < 8 \ + || (unsigned) reg_renumber[REGNO] < 8) + +/* ??? This looks suspiciously wrong. */ +/* We need to leave BASE_REGS reloads alone, in order to avoid caller_save + lossage. Caller_saves requests a BASE_REGS reload (caller_save_spill_class) + and then later we verify that one was allocated. If PREFERRED_RELOAD_CLASS + says to allocate a LO_REGS spill instead, then this mismatch gives an + abort. Alternatively, this could be fixed by modifying BASE_REG_CLASS + to be LO_REGS instead of BASE_REGS. It is not clear what affect this + change would have. */ +/* ??? This looks even more suspiciously wrong. PREFERRED_RELOAD_CLASS + must always return a strict subset of the input class. Just blindly + returning LO_REGS is safe only if the input class is a superset of LO_REGS, + but there is no check for this. Added another exception for NONARG_LO_REGS + because it is not a superset of LO_REGS. */ +/* ??? We now use NONARG_LO_REGS for caller_save_spill_class, so the + comments about BASE_REGS are now obsolete. */ +#define PREFERRED_RELOAD_CLASS(X,CLASS) \ + ((CLASS) == BASE_REGS || (CLASS) == NONARG_LO_REGS ? (CLASS) \ + : LO_REGS) +/* + ((CONSTANT_P ((X)) && GET_CODE ((X)) != CONST_INT \ + && ! CONSTANT_POOL_ADDRESS_P((X))) ? NO_REGS \ + : (GET_CODE ((X)) == CONST_INT \ + && (unsigned HOST_WIDE_INT) INTVAL ((X)) > 255) ? NO_REGS \ + : LO_REGS) */ + +/* Must leave BASE_REGS and NONARG_LO_REGS reloads alone, see comment + above. */ +#define SECONDARY_RELOAD_CLASS(CLASS,MODE,X) \ + ((CLASS) != LO_REGS && (CLASS) != BASE_REGS && (CLASS) != NONARG_LO_REGS \ + ? ((true_regnum (X) == -1 ? LO_REGS \ + : (true_regnum (X) + HARD_REGNO_NREGS (0, MODE) > 8) ? LO_REGS \ + : NO_REGS)) \ + : NO_REGS) + +#define CLASS_MAX_NREGS(CLASS,MODE) HARD_REGNO_NREGS(0,(MODE)) + +int thumb_shiftable_const (); + +#define CONST_OK_FOR_LETTER_P(VAL,C) \ + ((C) == 'I' ? (unsigned HOST_WIDE_INT) (VAL) < 256 \ + : (C) == 'J' ? (VAL) > -256 && (VAL) <= 0 \ + : (C) == 'K' ? thumb_shiftable_const (VAL) \ + : (C) == 'L' ? (VAL) > -8 && (VAL) < 8 \ + : (C) == 'M' ? ((unsigned HOST_WIDE_INT) (VAL) < 1024 \ + && ((VAL) & 3) == 0) \ + : (C) == 'N' ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ + : (C) == 'O' ? ((VAL) >= -508 && (VAL) <= 508) \ + : 0) + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VAL,C) 0 + +#define EXTRA_CONSTRAINT(X,C) \ + ((C) == 'Q' ? (GET_CODE (X) == MEM \ + && GET_CODE (XEXP (X, 0)) == LABEL_REF) : 0) + +/* Stack Layout and Calling Conventions */ + +#define STACK_GROWS_DOWNWARD 1 + +/* #define FRAME_GROWS_DOWNWARD 1 */ + +/* #define ARGS_GROW_DOWNWARD 1 */ + +#define STARTING_FRAME_OFFSET 0 + +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* Registers that address the stack frame */ + +#define STACK_POINTER_REGNUM 13 /* Defined by the TPCS. */ + +#define FRAME_POINTER_REGNUM 7 /* TPCS defines this as 11 but it does not really mean it. */ + +#define ARG_POINTER_REGNUM 16 /* A fake hard register that is eliminated later on. */ + +#define STATIC_CHAIN_REGNUM 9 + +#define FRAME_POINTER_REQUIRED 0 + +#define ELIMINABLE_REGS \ +{{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ + {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}} + +/* On the Thumb we always want to perform the eliminations as we + actually only have one real register pointing to the stashed + variables: the stack pointer, and we never use the frame pointer. */ +#define CAN_ELIMINATE(FROM,TO) 1 + +/* Note: This macro must match the code in thumb_function_prologue() in thumb.c. */ +#define INITIAL_ELIMINATION_OFFSET(FROM,TO,OFFSET) \ +{ \ + (OFFSET) = 0; \ + if ((FROM) == ARG_POINTER_REGNUM) \ + { \ + int count_regs = 0; \ + int regno; \ + (OFFSET) += get_frame_size (); \ + for (regno = 8; regno < 13; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + count_regs++; \ + if (count_regs) \ + (OFFSET) += 4 * count_regs; \ + count_regs = 0; \ + for (regno = 0; regno < 8; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + count_regs++; \ + if (count_regs || ! leaf_function_p () || far_jump_used_p()) \ + (OFFSET) += 4 * (count_regs + 1); \ + if (TARGET_BACKTRACE) { \ + if ((count_regs & 0xFF) == 0 && (regs_ever_live[3] != 0)) \ + (OFFSET) += 20; \ + else \ + (OFFSET) += 16; } \ + } \ + if ((TO) == STACK_POINTER_REGNUM) \ + (OFFSET) += current_function_outgoing_args_size; \ +} + +/* Passing Arguments on the stack */ + +#define PROMOTE_PROTOTYPES 1 + +#define ACCUMULATE_OUTGOING_ARGS 1 + +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + ((MODE) == VOIDmode \ + ? GEN_INT ((CUM).call_cookie) \ + : (NAMED) \ + ? ((CUM).nregs >= 16 ? 0 : gen_rtx (REG, MODE, (CUM).nregs / 4)) \ + : 0) + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM,MODE,TYPE,NAMED) \ + (((CUM).nregs < 16 && (CUM).nregs + (((MODE) == BLKmode) \ + ? int_size_in_bytes (TYPE) \ + : (HARD_REGNO_NREGS (0, (MODE)) \ + * 4)) > 16) \ + ? 4 - (CUM).nregs / 4 : 0) + +/* A C type for declaring a variable that is used as the first argument of + `FUNCTION_ARG' and other related values. For some target machines, the + type `int' suffices and can hold the number of bytes of argument so far. + + On the ARM, this is the number of bytes of arguments scanned so far. */ +typedef struct +{ + /* This is the number of registers of arguments scanned so far. */ + int nregs; + /* One of CALL_NORMAL, CALL_LONG or CALL_SHORT . */ + int call_cookie; +} CUMULATIVE_ARGS; + + +/* 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. + On the ARM, the offset starts at 0. */ +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ + ((CUM).nregs = (((FNTYPE) && aggregate_value_p (TREE_TYPE ((FNTYPE)))) \ + ? 4 : 0), \ + (CUM).call_cookie = \ + (((FNTYPE) && lookup_attribute ("short_call", TYPE_ATTRIBUTES (FNTYPE))) \ + ? CALL_SHORT \ + : (((FNTYPE) && lookup_attribute ("long_call", \ + TYPE_ATTRIBUTES (FNTYPE)))\ + || TARGET_LONG_CALLS) \ + ? CALL_LONG \ + : CALL_NORMAL)) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + (CUM).nregs += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3) \ + +#define FUNCTION_ARG_REGNO_P(REGNO) \ + ((REGNO) >=0 && (REGNO) <= 3) + +#define FUNCTION_VALUE(VALTYPE,FUNC) gen_rtx (REG, TYPE_MODE (VALTYPE), 0) + +#define LIBCALL_VALUE(MODE) gen_rtx (REG, (MODE), 0) + +#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == 0) + + /* How large values are returned */ +/* A C expression which can inhibit the returning of certain function values + in registers, based on the type of value. */ +#define RETURN_IN_MEMORY(TYPE) thumb_return_in_memory (TYPE) + +/* Define DEFAULT_PCC_STRUCT_RETURN to 1 if all structure and union return + values must be in memory. On the ARM, they need only do so if larger + than a word, or if they contain elements offset from zero in the struct. */ +#define DEFAULT_PCC_STRUCT_RETURN 0 + + +#define STRUCT_VALUE_REGNUM 0 + +#define FUNCTION_PROLOGUE(FILE,SIZE) thumb_function_prologue((FILE),(SIZE)) + +#define FUNCTION_EPILOGUE(FILE,SIZE) thumb_function_epilogue((FILE),(SIZE)) + +/* Implementing the Varargs Macros */ + +#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \ +{ \ + extern int current_function_anonymous_args; \ + current_function_anonymous_args = 1; \ + if ((CUM).nregs < 16) \ + (PRETEND_SIZE) = 16 - (CUM).nregs; \ +} + +/* Trampolines for nested functions */ + +/* Output assembler code for a block containing the constant parts of + a trampoline, leaving space for the variable parts. + + On the Thumb we always switch into ARM mode to execute the trampoline. + Why - because it is easier. This code will always be branched to via + a BX instruction and since the compiler magically generates the address + of the function the linker has no opportunity to ensure that the + bottom bit is set. Thus the processor will be in ARM mode when it + reaches this code. So we duplicate the ARM trampoline code and add + a switch into Thumb mode as well. + + On the ARM, (if r8 is the static chain regnum, and remembering that + referencing pc adds an offset of 8) the trampoline looks like: + ldr r8, [pc, #0] + ldr pc, [pc] + .word static chain value + .word function's address + ??? FIXME: When the trampoline returns, r8 will be clobbered. */ +#define TRAMPOLINE_TEMPLATE(FILE) \ +{ \ + fprintf ((FILE), "\t.code 32\n"); \ + fprintf ((FILE), ".Ltrampoline_start:\n"); \ + fprintf ((FILE), "\tldr\t%s, [%spc, #8]\n", \ + reg_names[STATIC_CHAIN_REGNUM], REGISTER_PREFIX); \ + fprintf ((FILE), "\tldr\t%sip, [%spc, #8]\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\torr\t%sip, %sip, #1\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\tbx\t%sip\n", REGISTER_PREFIX); \ + fprintf ((FILE), "\t.word\t0\n"); \ + fprintf ((FILE), "\t.word\t0\n"); \ + fprintf ((FILE), "\t.code 16\n"); \ +} + +/* Length in units of the trampoline for entering a nested function. */ +#define TRAMPOLINE_SIZE 24 + +/* Alignment required for a trampoline in units. */ +#define TRAMPOLINE_ALIGN 4 + +#define INITIALIZE_TRAMPOLINE(ADDR,FNADDR,CHAIN) \ +{ \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((ADDR), 16)), \ + (CHAIN)); \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((ADDR), 20)), \ + (FNADDR)); \ +} + + +/* Implicit Calls to Library Routines */ + +#define TARGET_MEM_FUNCTIONS 1 + +#define OVERRIDE_OPTIONS thumb_override_options () + + +/* Addressing Modes */ + +#define HAVE_POST_INCREMENT 1 + +#define CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (X)) + +#define MAX_REGS_PER_ADDRESS 2 + +#ifdef REG_OK_STRICT + +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) + +#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ + REGNO_MODE_OK_FOR_BASE_P (REGNO (X), MODE) + +#else /* REG_OK_STRICT */ + +#define REG_OK_FOR_BASE_P(X) \ + (REGNO (X) < 8 || REGNO (X) == STACK_POINTER_REGNUM \ + || (X) == arg_pointer_rtx \ + || REGNO (X) >= FIRST_PSEUDO_REGISTER) + +#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ + (REGNO (X) < 8 \ + || REGNO (X) >= FIRST_PSEUDO_REGISTER \ + || (GET_MODE_SIZE (MODE) >= 4 \ + && (REGNO (X) == STACK_POINTER_REGNUM \ + || (X) == arg_pointer_rtx))) + +#define REG_OK_FOR_INDEX_P(X) \ + (REGNO (X) < 8 \ + || REGNO (X) >= FIRST_PSEUDO_REGISTER) + +#endif /* REG_OK_STRICT */ + +/* In a REG+REG address, both must be INDEX registers. */ +#define REG_OK_FOR_INDEXED_BASE_P(X) REG_OK_FOR_INDEX_P(X) + +#define LEGITIMATE_OFFSET(MODE,VAL) \ +(GET_MODE_SIZE (MODE) == 1 ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ + : GET_MODE_SIZE (MODE) == 2 ? ((unsigned HOST_WIDE_INT) (VAL) < 64 \ + && ((VAL) & 1) == 0) \ + : ((VAL) >= 0 && ((VAL) + GET_MODE_SIZE (MODE)) <= 128 \ + && ((VAL) & 3) == 0)) + +/* The AP may be eliminated to either the SP or the FP, so we use the + least common denominator, e.g. SImode, and offsets from 0 to 64. */ + +/* ??? Verify whether the above is the right approach. */ + +/* ??? Also, the FP may be eliminated to the SP, so perhaps that + needs special handling also. */ + +/* ??? Look at how the mips16 port solves this problem. It probably uses + better ways to solve some of these problems. */ + +/* Although it is not incorrect, we don't accept QImode and HImode + addresses based on the frame pointer or arg pointer until the reload pass starts. + This is so that eliminating such addresses into stack based ones + won't produce impossible code. */ +#define GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \ +{ \ + /* ??? Not clear if this is right. Experiment. */ \ + if (GET_MODE_SIZE (MODE) < 4 \ + && ! (reload_in_progress || reload_completed) \ + && (reg_mentioned_p (frame_pointer_rtx, X) \ + || reg_mentioned_p (arg_pointer_rtx, X) \ + || reg_mentioned_p (virtual_incoming_args_rtx, X) \ + || reg_mentioned_p (virtual_outgoing_args_rtx, X) \ + || reg_mentioned_p (virtual_stack_dynamic_rtx, X) \ + || reg_mentioned_p (virtual_stack_vars_rtx, X))) \ + ; \ + /* Accept any base register. SP only in SImode or larger. */ \ + else if (GET_CODE (X) == REG && REG_MODE_OK_FOR_BASE_P(X, MODE)) \ + goto WIN; \ + /* This is PC relative data before MACHINE_DEPENDENT_REORG runs. */ \ + else if (GET_MODE_SIZE (MODE) >= 4 && CONSTANT_P (X) \ + && CONSTANT_POOL_ADDRESS_P (X)) \ + goto WIN; \ + /* This is PC relative data after MACHINE_DEPENDENT_REORG runs. */ \ + else if (GET_MODE_SIZE (MODE) >= 4 && reload_completed \ + && (GET_CODE (X) == LABEL_REF \ + || (GET_CODE (X) == CONST \ + && GET_CODE (XEXP (X, 0)) == PLUS \ + && GET_CODE (XEXP (XEXP (X, 0), 0)) == LABEL_REF \ + && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT))) \ + goto WIN; \ + /* Post-inc indexing only supported for SImode and larger. */ \ + else if (GET_CODE (X) == POST_INC && GET_MODE_SIZE (MODE) >= 4 \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_INDEX_P (XEXP (X, 0))) \ + goto WIN; \ + else if (GET_CODE (X) == PLUS) \ + { \ + /* REG+REG address can be any two index registers. */ \ + /* ??? REG+REG addresses have been completely disabled before \ + reload completes, because we do not have enough available \ + reload registers. We only have 3 guaranteed reload registers \ + (NONARG_LO_REGS - the frame pointer), but we need at least 4 \ + to support REG+REG addresses. We have left them enabled after \ + reload completes, in the hope that reload_cse_regs and related \ + routines will be able to create them after the fact. It is \ + probably possible to support REG+REG addresses with additional \ + reload work, but I do not not have enough time to attempt such \ + a change at this time. */ \ + /* ??? Normally checking the mode here is wrong, since it isn't \ + impossible to use REG+REG with DFmode. However, the movdf \ + pattern requires offsettable addresses, and REG+REG is not \ + offsettable, so it must be rejected somehow. Trying to use \ + 'o' fails, because offsettable_address_p does a QImode check. \ + QImode is not valid for stack addresses, and has a smaller \ + range for non-stack bases, and this causes valid addresses \ + to be rejected. So we just eliminate REG+REG here by checking \ + the mode. */ \ + /* We also disallow FRAME+REG addressing since we know that FRAME \ + will be replaced with STACK, and SP relative addressing only \ + permits SP+OFFSET. */ \ + if (GET_MODE_SIZE (MODE) <= 4 \ + /* ??? See comment above. */ \ + && reload_completed \ + && GET_CODE (XEXP (X, 0)) == REG \ + && GET_CODE (XEXP (X, 1)) == REG \ + && XEXP (X, 0) != frame_pointer_rtx \ + && XEXP (X, 1) != frame_pointer_rtx \ + && XEXP (X, 0) != virtual_stack_vars_rtx \ + && XEXP (X, 1) != virtual_stack_vars_rtx \ + && REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ + && REG_OK_FOR_INDEX_P (XEXP (X, 1))) \ + goto WIN; \ + /* REG+const has 5-7 bit offset for non-SP registers. */ \ + else if (GET_CODE (XEXP (X, 0)) == REG \ + && (REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ + || XEXP (X, 0) == arg_pointer_rtx) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ + goto WIN; \ + /* REG+const has 10 bit offset for SP, but only SImode and \ + larger is supported. */ \ + /* ??? Should probably check for DI/DFmode overflow here \ + just like GO_IF_LEGITIMATE_OFFSET does. */ \ + else if (GET_CODE (XEXP (X, 0)) == REG \ + && REGNO (XEXP (X, 0)) == STACK_POINTER_REGNUM \ + && GET_MODE_SIZE (MODE) >= 4 \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (unsigned HOST_WIDE_INT) INTVAL (XEXP (X, 1)) < 1024 \ + && (INTVAL (XEXP (X, 1)) & 3) == 0) \ + goto WIN; \ + } \ +} + +/* ??? If an HImode FP+large_offset address is converted to an HImode + SP+large_offset address, then reload won't know how to fix it. It sees + only that SP isn't valid for HImode, and so reloads the SP into an index + register, but the resulting address is still invalid because the offset + is too big. We fix it here instead by reloading the entire address. */ +/* We could probably achieve better results by defining PROMOTE_MODE to help + cope with the variances between the Thumb's signed and unsigned byte and + halfword load instructions. */ +#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \ +{ \ + if (GET_CODE (X) == PLUS \ + && GET_MODE_SIZE (MODE) < 4 \ + && GET_CODE (XEXP (X, 0)) == REG \ + && XEXP (X, 0) == stack_pointer_rtx \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && ! LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ + { \ + rtx orig_X = X; \ + X = copy_rtx (X); \ + push_reload (orig_X, NULL_RTX, &X, NULL_PTR, \ + BASE_REG_CLASS, \ + Pmode, VOIDmode, 0, 0, OPNUM, TYPE); \ + goto WIN; \ + } \ +} + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) + +#define LEGITIMATE_CONSTANT_P(X) \ + (GET_CODE (X) == CONST_INT \ + || GET_CODE (X) == CONST_DOUBLE \ + || CONSTANT_ADDRESS_P (X)) + +/* Flags for the call/call_value rtl operations set up by function_arg. */ +#define CALL_NORMAL 0x00000000 /* No special processing. */ +#define CALL_LONG 0x00000001 /* Always call indirect. */ +#define CALL_SHORT 0x00000002 /* Never call indirect. */ + +#define ENCODE_SECTION_INFO(decl) \ +{ \ + ARM_ENCODE_CALL_TYPE (decl) \ +} + +/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS + is a valid machine specific attribute for DECL. + The attributes in ATTRIBUTES have previously been assigned to DECL. */ +int arm_valid_machine_type_attribute (/* union tree_node *, union tree_node *, + union tree_node *, + union tree_node * */); +#define VALID_MACHINE_TYPE_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \ +arm_valid_machine_type_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS) + +/* If we are referencing a function that is weak then encode a long call + flag in the function name, otherwise if the function is static or + or known to be defined in this file then encode a short call flag. + This macro is used inside the ENCODE_SECTION macro. */ +#define ARM_ENCODE_CALL_TYPE(decl) \ + if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd') \ + { \ + if (TREE_CODE (decl) == FUNCTION_DECL && DECL_WEAK (decl)) \ + arm_encode_call_attribute (decl, LONG_CALL_FLAG_CHAR); \ + else if (! TREE_PUBLIC (decl)) \ + arm_encode_call_attribute (decl, SHORT_CALL_FLAG_CHAR); \ + } + +/* Special characters prefixed to function names + in order to encode attribute like information. + Note, '@' and '*' have already been taken. */ +#define SHORT_CALL_FLAG_CHAR '^' +#define LONG_CALL_FLAG_CHAR '#' + +#define ENCODED_SHORT_CALL_ATTR_P(SYMBOL_NAME) \ + (*(SYMBOL_NAME) == SHORT_CALL_FLAG_CHAR) + +#define ENCODED_LONG_CALL_ATTR_P(SYMBOL_NAME) \ + (*(SYMBOL_NAME) == LONG_CALL_FLAG_CHAR) + +#ifndef SUBTARGET_NAME_ENCODING_LENGTHS +#define SUBTARGET_NAME_ENCODING_LENGTHS +#endif + +/* This is a C fragement for the inside of a switch statement. + Each case label should return the number of characters to + be stripped from the start of a function's name, if that + name starts with the indicated character. */ +#define ARM_NAME_ENCODING_LENGTHS \ + case SHORT_CALL_FLAG_CHAR: return 1; \ + case LONG_CALL_FLAG_CHAR: return 1; \ + case '*': return 1; \ + SUBTARGET_NAME_ENCODING_LENGTHS + +/* This has to be handled by a function because more than part of the + ARM backend uses function name prefixes to encode attributes. */ +#undef STRIP_NAME_ENCODING +#define STRIP_NAME_ENCODING(VAR, SYMBOL_NAME) \ + (VAR) = arm_strip_name_encoding (SYMBOL_NAME) + +/* This is how to output a reference to a user-level label named NAME. + `assemble_name' uses this. */ +#undef ASM_OUTPUT_LABELREF +#define ASM_OUTPUT_LABELREF(FILE, NAME) \ + asm_fprintf (FILE, "%U%s", arm_strip_name_encoding (NAME)) + + +/* Condition Code Status */ + +#define NOTICE_UPDATE_CC(EXP,INSN) \ +{ \ + if (get_attr_conds ((INSN)) != CONDS_UNCHANGED) \ + CC_STATUS_INIT; \ +} + + +/* Describing Relative Costs of Operations */ + +#define SLOW_BYTE_ACCESS 0 + +#define SLOW_UNALIGNED_ACCESS 1 + +#define NO_FUNCTION_CSE 1 + +#define NO_RECURSIVE_FUNCTION_CSE 1 + +#define REGISTER_MOVE_COST(FROM,TO) \ + (((FROM) == HI_REGS || (TO) == HI_REGS) ? 4 : 2) + +#define MEMORY_MOVE_COST(M,CLASS,IN) \ + ((GET_MODE_SIZE(M) < 4 ? 8 : 2 * GET_MODE_SIZE(M)) * (CLASS == LO_REGS ? 1 : 2)) + +/* This will allow better space optimization when compiling with -O */ +#define BRANCH_COST (optimize > 1 ? 1 : 0) + +#define RTX_COSTS(X,CODE,OUTER) \ + case MULT: \ + if (GET_CODE (XEXP (X, 1)) == CONST_INT) \ + { \ + int cycles = 0; \ + unsigned HOST_WIDE_INT i = INTVAL (XEXP (X, 1)); \ + while (i) \ + { \ + i >>= 2; \ + cycles++; \ + } \ + return COSTS_N_INSNS (2) + cycles; \ + } \ + return COSTS_N_INSNS (1) + 16; \ + case ASHIFT: case ASHIFTRT: case LSHIFTRT: case ROTATERT: \ + case PLUS: case MINUS: case COMPARE: case NEG: case NOT: \ + return COSTS_N_INSNS (1); \ + case SET: \ + return (COSTS_N_INSNS (1) \ + + 4 * ((GET_CODE (SET_SRC (X)) == MEM) \ + + GET_CODE (SET_DEST (X)) == MEM)) + +#define CONST_COSTS(X,CODE,OUTER) \ + case CONST_INT: \ + if ((OUTER) == SET) \ + { \ + if ((unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ + return 0; \ + if (thumb_shiftable_const (INTVAL (X))) \ + return COSTS_N_INSNS (2); \ + return COSTS_N_INSNS (3); \ + } \ + else if (OUTER == PLUS \ + && INTVAL (X) < 256 && INTVAL (X) > -256) \ + return 0; \ + else if (OUTER == COMPARE \ + && (unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ + return 0; \ + else if (OUTER == ASHIFT || OUTER == ASHIFTRT \ + || OUTER == LSHIFTRT) \ + return 0; \ + return COSTS_N_INSNS (2); \ + case CONST: \ + case CONST_DOUBLE: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return COSTS_N_INSNS(3); + +#define ADDRESS_COST(X) \ + ((GET_CODE (X) == REG \ + || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \ + && GET_CODE (XEXP (X, 1)) == CONST_INT)) \ + ? 1 : 2) + + +/* Position Independent Code */ + +#define PRINT_OPERAND(STREAM,X,CODE) \ + thumb_print_operand((STREAM), (X), (CODE)) + +#define PRINT_OPERAND_ADDRESS(STREAM,X) \ +{ \ + if (GET_CODE ((X)) == REG) \ + fprintf ((STREAM), "[%s]", reg_names[REGNO ((X))]); \ + else if (GET_CODE ((X)) == POST_INC) \ + fprintf ((STREAM), "%s!", reg_names[REGNO (XEXP (X, 0))]); \ + else if (GET_CODE ((X)) == PLUS) \ + { \ + if (GET_CODE (XEXP ((X), 1)) == CONST_INT) \ + fprintf ((STREAM), "[%s, #%d]", \ + reg_names[REGNO (XEXP ((X), 0))], \ + (int) INTVAL (XEXP ((X), 1))); \ + else \ + fprintf ((STREAM), "[%s, %s]", \ + reg_names[REGNO (XEXP ((X), 0))], \ + reg_names[REGNO (XEXP ((X), 1))]); \ + } \ + else \ + output_addr_const ((STREAM), (X)); \ +} + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '@' || ((CODE) == '_')) + +/* Emit a special directive when defining a function name. + This is used by the assembler to assit with interworking. */ +#define ASM_DECLARE_FUNCTION_NAME(file, name, decl) \ + if (! is_called_in_ARM_mode (decl)) \ + fprintf (file, "\t.thumb_func\n") ; \ + else \ + fprintf (file, "\t.code\t32\n") ; \ + ASM_OUTPUT_LABEL (file, name) + +#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ + asm_fprintf ((STREAM), "\tpush {%R%s}\n", reg_names[(REGNO)]) + +#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \ + fprintf ((STREAM), "\tpop {%R%s}\n", reg_names[(REGNO)]) + +#define FINAL_PRESCAN_INSN(INSN,OPVEC,NOPERANDS) \ + final_prescan_insn((INSN)) + +/* Controlling Debugging Information Format */ +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* Specific options for DBX Output */ + +#define DBX_DEBUGGING_INFO 1 + +#define DEFAULT_GDB_EXTENSIONS 1 + + +/* Cross Compilation and Floating Point */ + +#define REAL_ARITHMETIC + + +/* Miscellaneous Parameters */ + +#define PREDICATE_CODES \ + {"thumb_cmp_operand", {SUBREG, REG, CONST_INT}}, + +#define CASE_VECTOR_MODE Pmode + +#define WORD_REGISTER_OPERATIONS + +#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND + +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +#define MOVE_MAX 4 + +#define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) 1 + +#define STORE_FLAG_VALUE 1 + +#define Pmode SImode + +#define FUNCTION_MODE SImode + +#define DOLLARS_IN_IDENTIFIERS 0 + +#define NO_DOLLAR_IN_LABEL 1 + +#define HAVE_ATEXIT + +/* The literal pool needs to reside in the text area due to the + limited PC addressing range: */ +#define MACHINE_DEPENDENT_REORG(INSN) thumb_reorg ((INSN)) + + +/* Options specific to Thumb */ + +/* True if a return instruction can be used in this function. */ +int thumb_trivial_epilogue (); +#define USE_RETURN (reload_completed && thumb_trivial_epilogue ()) + +extern char * thumb_unexpanded_epilogue (); +extern char * output_move_mem_multiple (); +extern char * thumb_load_double_from_address (); +extern char * output_return (); +extern int far_jump_used_p(); +extern int is_called_in_ARM_mode (); + +char *arm_strip_name_encoding (/* const char * */); +int arm_is_longcall_p (/* rtx, int, int */); diff --git a/gcc_arm/config/arm/thumb_020422.md b/gcc_arm/config/arm/thumb_020422.md new file mode 100755 index 0000000..04de07c --- /dev/null +++ b/gcc_arm/config/arm/thumb_020422.md @@ -0,0 +1,1194 @@ +;; thumb.md Machine description for ARM/Thumb processors +;; Copyright (C) 1996, 1997, 1998, 2002 Free Software Foundation, Inc. +;; The basis of this contribution was generated by +;; Richard Earnshaw, Advanced RISC Machines Ltd + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;; LENGTH of an instruction is 2 bytes +(define_attr "length" "" (const_int 2)) + +;; CONDS is set to UNCHANGED when an insn does not affect the condition codes +;; Most insns change the condition codes +(define_attr "conds" "changed,unchanged" (const_string "changed")) + +;; FAR_JUMP is "yes" if a BL instruction is used to generate a branch to a +;; distant label. +(define_attr "far_jump" "yes,no" (const_string "no")) + +;; Start with move insns + +(define_expand "movsi" + [(set (match_operand:SI 0 "general_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (SImode, operands[1]); + } +") + +(define_insn "*movsi_insn" + [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l,m,*r,*h") + (match_operand:SI 1 "general_operand" "l,I,J,K,>,l,mi,l,*h,*r"))] + "register_operand (operands[0], SImode) + || register_operand (operands[1], SImode)" + "@ + add\\t%0, %1, #0 + mov\\t%0, %1 + # + # + ldmia\\t%1, {%0} + stmia\\t%0, {%1} + ldr\\t%0, %1 + str\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1" +[(set_attr "length" "2,2,4,4,2,2,2,2,2,2")]) + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "thumb_shiftable_const (INTVAL (operands[1]))" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))] + " +{ + unsigned HOST_WIDE_INT val = INTVAL (operands[1]); + unsigned HOST_WIDE_INT mask = 0xff; + int i; + for (i = 0; i < 25; i++) + if ((val & (mask << i)) == val) + break; + + if (i == 0) + FAIL; + + operands[1] = GEN_INT (val >> i); + operands[2] = GEN_INT (i); +}") + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "INTVAL (operands[1]) < 0 && INTVAL (operands[1]) > -256" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 0) (neg:SI (match_dup 0)))] + " + operands[1] = GEN_INT (- INTVAL (operands[1])); +") + +;;(define_expand "reload_outsi" +;; [(set (match_operand:SI 2 "register_operand" "=&l") +;; (match_operand:SI 1 "register_operand" "h")) +;; (set (match_operand:SI 0 "reload_memory_operand" "=o") +;; (match_dup 2))] +;; "" +;; " +;;/* thumb_reload_out_si (operands); +;; DONE; */ +;;") + +(define_expand "movhi" + [(set (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + " +{ + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (HImode, operands[1]); + + /* ??? We shouldn't really get invalid addresses here, but this can + happen if we are passed a SP (never OK for HImode/QImode) or virtual + register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) + relative address. */ + /* ??? This should perhaps be fixed elsewhere, for instance, in + fixup_stack_1, by checking for other kinds of invalid addresses, + e.g. a bare reference to a virtual register. This may confuse the + alpha though, which must handle this case differently. */ + if (GET_CODE (operands[0]) == MEM + && ! memory_address_p (GET_MODE (operands[0]), + XEXP (operands[0], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[0], 0)); + operands[0] = change_address (operands[0], VOIDmode, temp); + } + if (GET_CODE (operands[1]) == MEM + && ! memory_address_p (GET_MODE (operands[1]), + XEXP (operands[1], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[1], 0)); + operands[1] = change_address (operands[1], VOIDmode, temp); + } + } + /* Handle loading a large integer during reload */ + else if (GET_CODE (operands[1]) == CONST_INT + && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) + { + /* Writing a constant to memory needs a scratch, which should + be handled with SECONDARY_RELOADs. */ + if (GET_CODE (operands[0]) != REG) + abort (); + + operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); + emit_insn (gen_movsi (operands[0], operands[1])); + DONE; + } +}") + +(define_insn "*movhi_insn" + [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") + (match_operand:HI 1 "general_operand" "l,m,l,*h,*r,I"))] + "register_operand (operands[0], HImode) + || register_operand (operands[1], HImode)" + "@ + add\\t%0, %1, #0 + ldrh\\t%0, %1 + strh\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1 + mov\\t%0, %1") + +(define_expand "movqi" + [(set (match_operand:QI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" + " +{ + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (QImode, operands[1]); + + /* ??? We shouldn't really get invalid addresses here, but this can + happen if we are passed a SP (never OK for HImode/QImode) or virtual + register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) + relative address. */ + /* ??? This should perhaps be fixed elsewhere, for instance, in + fixup_stack_1, by checking for other kinds of invalid addresses, + e.g. a bare reference to a virtual register. This may confuse the + alpha though, which must handle this case differently. */ + if (GET_CODE (operands[0]) == MEM + && ! memory_address_p (GET_MODE (operands[0]), + XEXP (operands[0], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[0], 0)); + operands[0] = change_address (operands[0], VOIDmode, temp); + } + if (GET_CODE (operands[1]) == MEM + && ! memory_address_p (GET_MODE (operands[1]), + XEXP (operands[1], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[1], 0)); + operands[1] = change_address (operands[1], VOIDmode, temp); + } + } + /* Handle loading a large integer during reload */ + else if (GET_CODE (operands[1]) == CONST_INT + && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) + { + /* Writing a constant to memory needs a scratch, which should + be handled with SECONDARY_RELOADs. */ + if (GET_CODE (operands[0]) != REG) + abort (); + + operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); + emit_insn (gen_movsi (operands[0], operands[1])); + DONE; + } +}") + +(define_insn "*movqi_insn" + [(set (match_operand:QI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") + (match_operand:QI 1 "general_operand" "l,m,l,*h,*r,I"))] + "register_operand (operands[0], QImode) + || register_operand (operands[1], QImode)" + "@ + add\\t%0, %1, #0 + ldrb\\t%0, %1 + strb\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1 + mov\\t%0, %1") + +(define_expand "movdi" + [(set (match_operand:DI 0 "general_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (DImode, operands[1]); + } +") + +;;; ??? This should have alternatives for constants. +;;; ??? This was originally identical to the movdf_insn pattern. +;;; ??? The 'i' constraint looks funny, but it should always be replaced by +;;; thumb_reorg with a memory reference. +(define_insn "*movdi_insn" + [(set (match_operand:DI 0 "general_operand" "=l,l,l,l,>,l,m,*r") + (match_operand:DI 1 "general_operand" "l,I,J,>,l,mi,l,*r"))] + "register_operand (operands[0], DImode) + || register_operand (operands[1], DImode)" + "* +{ + switch (which_alternative) + { + case 0: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; + return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; + case 1: + return \"mov\\t%Q0, %1\;mov\\t%R0, #0\"; + case 2: + operands[1] = GEN_INT (- INTVAL (operands[1])); + return \"mov\\t%Q0, %1\;neg\\t%Q0, %Q0\;asr\\t%R0, %Q0, #31\"; + case 3: + return \"ldmia\\t%1, {%0, %H0}\"; + case 4: + return \"stmia\\t%0, {%1, %H1}\"; + case 5: + return thumb_load_double_from_address (operands); + case 6: + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); + output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); + return \"\"; + case 7: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; + return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; + } +}"[(set_attr "length" "4,4,6,2,2,6,4,4")]) + +(define_expand "movdf" + [(set (match_operand:DF 0 "general_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (DFmode, operands[1]); + } +") + +;;; ??? This should have alternatives for constants. +;;; ??? This was originally identical to the movdi_insn pattern. +;;; ??? The 'F' constraint looks funny, but it should always be replaced by +;;; thumb_reorg with a memory reference. +(define_insn "*movdf_insn" + [(set (match_operand:DF 0 "general_operand" "=l,l,>,l,m,*r") + (match_operand:DF 1 "general_operand" "l,>,l,mF,l,*r"))] + "register_operand (operands[0], DFmode) + || register_operand (operands[1], DFmode)" + "* + switch (which_alternative) + { + case 0: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; + return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; + case 1: + return \"ldmia\\t%1, {%0, %H0}\"; + case 2: + return \"stmia\\t%0, {%1, %H1}\"; + case 3: + return thumb_load_double_from_address (operands); + case 4: + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); + output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); + return \"\"; + case 5: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; + return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; + } +"[(set_attr "length" "4,2,2,6,4,4")]) + +(define_expand "movsf" + [(set (match_operand:SF 0 "general_operand" "") + (match_operand:SF 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (SFmode, operands[1]); + } +") + +;;; ??? This should have alternatives for constants. +(define_insn "*movsf_insn" + [(set (match_operand:SF 0 "nonimmediate_operand" "=l,l,>,l,m,*r,*h") + (match_operand:SF 1 "general_operand" "l,>,l,mF,l,*h,*r"))] + "register_operand (operands[0], SFmode) + || register_operand (operands[1], SFmode)" + "@ + add\\t%0, %1, #0 + ldmia\\t%1, {%0} + stmia\\t%0, {%1} + ldr\\t%0, %1 + str\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1") + +;; Widening move insns + +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "s_register_operand" "") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (HImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); + emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (16))); + DONE; + } +") + +(define_insn "*zero_extendhisi2_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + "" + "ldrh\\t%0, %1") + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "s_register_operand" "") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (QImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); + emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (24))); + DONE; + } +") + +(define_insn "*zero_extendqisi2_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + "" + "ldrb\\t%0, %1") + +(define_expand "extendhisi2" + [(parallel [(set (match_operand:SI 0 "s_register_operand" "") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" ""))) + (clobber (match_scratch:SI 2 ""))])] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (HImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); + emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (16))); + DONE; + } +") + +(define_insn "*extendhisi2_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))) + (clobber (match_scratch:SI 2 "=&l"))] + "" + "* +{ + rtx ops[4]; + /* This code used to try to use 'V', and fix the address only if it was + offsettable, but this fails for e.g. REG+48 because 48 is outside the + range of QImode offsets, and offsettable_address_p does a QImode + address check. */ + + if (GET_CODE (XEXP (operands[1], 0)) == PLUS) + { + ops[1] = XEXP (XEXP (operands[1], 0), 0); + ops[2] = XEXP (XEXP (operands[1], 0), 1); + } + else + { + ops[1] = XEXP (operands[1], 0); + ops[2] = const0_rtx; + } + if (GET_CODE (ops[2]) == REG) + return \"ldrsh\\t%0, %1\"; + + ops[0] = operands[0]; + ops[3] = operands[2]; + output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops); + return \"\"; +}" +[(set_attr "length" "4")]) + +(define_expand "extendqisi2" + [(set (match_operand:SI 0 "s_register_operand" "") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (QImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); + emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (24))); + DONE; + } +") + +(define_insn "*extendqisi2_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))] + "" + "* +{ + rtx ops[3]; + + if (which_alternative == 0) + return \"ldrsb\\t%0, %1\"; + ops[0] = operands[0]; + if (GET_CODE (XEXP (operands[1], 0)) == PLUS) + { + ops[1] = XEXP (XEXP (operands[1], 0), 0); + ops[2] = XEXP (XEXP (operands[1], 0), 1); + + if (GET_CODE (ops[1]) == REG && GET_CODE (ops[2]) == REG) + output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops); + else if (GET_CODE (ops[1]) == REG) + { + if (REGNO (ops[1]) == REGNO (operands[0])) + output_asm_insn (\"ldrb\\t%0, [%1, %2]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); + else + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + else + { + if (REGNO (ops[2]) == REGNO (operands[0])) + output_asm_insn (\"ldrb\\t%0, [%2, %1]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); + else + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + } + else if (REGNO (operands[0]) == REGNO (XEXP (operands[1], 0))) + { + output_asm_insn (\"ldrb\\t%0, [%0, #0]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); + } + else + { + ops[1] = XEXP (operands[1], 0); + ops[2] = const0_rtx; + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + return \"\"; +}" +[(set_attr "length" "2,6")]) + +;; We don't really have extzv, but defining this using shifts helps +;; to reduce register pressure later on. + +(define_expand "extzv" + [(set (match_dup 4) + (ashift:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "const_int_operand" ""))) + (set (match_operand:SI 0 "register_operand" "") + (lshiftrt:SI (match_dup 4) + (match_operand:SI 3 "const_int_operand" "")))] + "" + " +{ + HOST_WIDE_INT lshift = 32 - INTVAL (operands[2]) - INTVAL (operands[3]); + HOST_WIDE_INT rshift = 32 - INTVAL (operands[2]); + operands[3] = GEN_INT (rshift); + if (lshift == 0) + { + emit_insn (gen_lshrsi3 (operands[0], operands[1], operands[3])); + DONE; + } + operands[2] = GEN_INT (lshift); + operands[4] = gen_reg_rtx (SImode); +} +") + +;; Block-move insns + +(define_expand "movstrqi" + [(match_operand:BLK 0 "general_operand" "") + (match_operand:BLK 1 "general_operand" "") + (match_operand:SI 2 "" "") + (match_operand:SI 3 "const_int_operand" "")] + "" + " + if (INTVAL (operands[3]) != 4 + || GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) > 48) + FAIL; + + thumb_expand_movstrqi (operands); + DONE; +") + +(define_insn "movmem12b" + [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) + (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) + (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (mem:SI (plus:SI (match_dup 0) (const_int 8))) + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_dup 0) (plus:SI (match_dup 0) (const_int 12))) + (set (match_dup 1) (plus:SI (match_dup 1) (const_int 12))) + (clobber (match_scratch:SI 2 "=&l")) + (clobber (match_scratch:SI 3 "=&l")) + (clobber (match_scratch:SI 4 "=&l"))] + "" + "* return output_move_mem_multiple (3, operands);" +[(set_attr "length" "4")]) + +(define_insn "movmem8b" + [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) + (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) + (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_dup 0) (plus:SI (match_dup 0) (const_int 8))) + (set (match_dup 1) (plus:SI (match_dup 1) (const_int 8))) + (clobber (match_scratch:SI 2 "=&l")) + (clobber (match_scratch:SI 3 "=&l"))] + "" + "* return output_move_mem_multiple (2, operands);" +[(set_attr "length" "4")]) + +;; Arithmetic insns + +(define_insn "adddi3" + [(set (match_operand:DI 0 "s_register_operand" "=l") + (plus:DI (match_operand:DI 1 "s_register_operand" "%0") + (match_operand:DI 2 "s_register_operand" "l")))] + "" + "add\\t%Q0, %Q0, %Q2\;adc\\t%R0, %R0, %R2" +[(set_attr "conds" "changed") + (set_attr "length" "8")]) + +;; register group 'k' is a single register group containing only the stack +;; register. Trying to reload it will always fail catastrophically, +;; so never allow those alternatives to match if reloading is needed. +(define_insn "addsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l,l,l,*r,*h,l,!k") + (plus:SI (match_operand:SI 1 "s_register_operand" "%0,0,l,*0,*0,!k,!k") + (match_operand:SI 2 "nonmemory_operand" "I,J,lL,*h,*r,!M,!O")))] + "" + "* + static char *asms[] = +{ + \"add\\t%0, %0, %2\", + \"sub\\t%0, %0, #%n2\", + \"add\\t%0, %1, %2\", + \"add\\t%0, %0, %2\", + \"add\\t%0, %0, %2\", + \"add\\t%0, %1, %2\", + \"add\\t%0, %1, %2\" +}; + if (which_alternative == 2 && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) < 0) + return \"sub\\t%0, %1, #%n2\"; + return asms[which_alternative]; +") + +; reloading and elimination of the frame pointer can sometimes cause this +; optimization to be missed. +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=l") + (match_operand:SI 1 "const_int_operand" "M")) + (set (match_dup 0) + (plus:SI (match_dup 0) (match_operand:SI 2 "register_operand" "k")))] + "REGNO (operands[2]) == STACK_POINTER_REGNUM + && (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) < 1024 + && (INTVAL (operands[1]) & 3) == 0" + "add\\t%0, %2, %1") + +(define_insn "subdi3" + [(set (match_operand:DI 0 "s_register_operand" "=l") + (minus:DI (match_operand:DI 1 "s_register_operand" "0") + (match_operand:DI 2 "s_register_operand" "l")))] + "" + "sub\\t%Q0, %Q0, %Q2\;sbc\\t%R0, %R0, %R2" +[(set_attr "conds" "changed") + (set_attr "length" "8")]) + +(define_insn "subsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (minus:SI (match_operand:SI 1 "s_register_operand" "l") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "sub\\t%0, %1, %2") + +;; We must ensure that one input matches the output, and that the other input +;; does not match the output. Using 0 satisfies the first, and using & +;; satisfies the second. Unfortunately, this fails when operands 1 and 2 +;; are the same, because reload will make operand 0 match operand 1 without +;; realizing that this conflicts with operand 2. We fix this by adding another +;; alternative to match this case, and then `reload' it ourselves. This +;; alternative must come first. +(define_insn "mulsi3" + [(set (match_operand:SI 0 "s_register_operand" "=&l,&l,&l") + (mult:SI (match_operand:SI 1 "s_register_operand" "%l,*h,0") + (match_operand:SI 2 "s_register_operand" "l,l,l")))] + "" + "* +{ + if (which_alternative < 2) + return \"mov\\t%0, %1\;mul\\t%0, %0, %2\"; + else + return \"mul\\t%0, %0, %2\"; +}" + [(set_attr "length" "4,4,2")]) + +(define_insn "negsi2" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (neg:SI (match_operand:SI 1 "s_register_operand" "l")))] + "" + "neg\\t%0, %1") + +;; Logical insns + +(define_expand "andsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (and:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] + "" + " + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = force_reg (SImode, operands[2]); + else + { + int i; + if (((unsigned HOST_WIDE_INT) ~ INTVAL (operands[2])) < 256) + { + operands[2] = force_reg (SImode, GEN_INT (~INTVAL (operands[2]))); + emit_insn (gen_bicsi3 (operands[0], operands[2], operands[1])); + DONE; + } + + for (i = 9; i <= 31; i++) + if ((((HOST_WIDE_INT) 1) << i) - 1 == INTVAL (operands[2])) + { + emit_insn (gen_extzv (operands[0], operands[1], GEN_INT (i), + const0_rtx)); + DONE; + } + else if ((((HOST_WIDE_INT) 1) << i) - 1 == ~ INTVAL (operands[2])) + { + rtx shift = GEN_INT (i); + rtx reg = gen_reg_rtx (SImode); + emit_insn (gen_lshrsi3 (reg, operands[1], shift)); + emit_insn (gen_ashlsi3 (operands[0], reg, shift)); + DONE; + } + + operands[2] = force_reg (SImode, operands[2]); + } +") + +(define_insn "*andsi3_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (and:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "and\\t%0, %0, %2") + +(define_insn "bicsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (and:SI (not:SI (match_operand:SI 1 "s_register_operand" "l")) + (match_operand:SI 2 "s_register_operand" "0")))] + "" + "bic\\t%0, %0, %1") + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (ior:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "orr\\t%0, %0, %2") + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (xor:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "eor\\t%0, %0, %2") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (not:SI (match_operand:SI 1 "s_register_operand" "l")))] + "" + "mvn\\t%0, %1") + +;; Shift and rotation insns + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (ashift:SI (match_operand:SI 1 "s_register_operand" "l,0") + (match_operand:SI 2 "nonmemory_operand" "N,l")))] + "" + "@ + lsl\\t%0, %1, %2 + lsl\\t%0, %0, %2") + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (ashiftrt:SI (match_operand:SI 1 "s_register_operand" "l,0") + (match_operand:SI 2 "nonmemory_operand" "N,l")))] + "" + "@ + asr\\t%0, %1, %2 + asr\\t%0, %0, %2") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (lshiftrt:SI (match_operand:SI 1 "s_register_operand" "l,0") + (match_operand:SI 2 "nonmemory_operand" "N,l")))] + "" + "@ + lsr\\t%0, %1, %2 + lsr\\t%0, %0, %2") + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (rotatert:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "ror\\t%0, %0, %2") + +;; Comparison insns + +(define_expand "cmpsi" + [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "") + (match_operand:SI 1 "nonmemory_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != REG && GET_CODE (operands[1]) != SUBREG) + { + if (GET_CODE (operands[1]) != CONST_INT + || (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) >= 256) + { + if (GET_CODE (operands[1]) != CONST_INT + || INTVAL (operands[1]) < -255 + || INTVAL (operands[1]) > 0) + operands[1] = force_reg (SImode, operands[1]); + else + { + operands[1] = force_reg (SImode, + GEN_INT (- INTVAL (operands[1]))); + emit_insn (gen_cmnsi (operands[0], operands[1])); + DONE; + } + } + } +") + +(define_insn "*cmpsi_insn" + [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "l,*r,*h") + (match_operand:SI 1 "thumb_cmp_operand" "lI,*h,*r")))] + "" + "@ + cmp\\t%0, %1 + cmp\\t%0, %1 + cmp\\t%0, %1") + +(define_insn "tstsi" + [(set (cc0) (match_operand:SI 0 "s_register_operand" "l"))] + "" + "cmp\\t%0, #0") + +(define_insn "cmnsi" + [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "l") + (neg:SI (match_operand:SI 1 "s_register_operand" "l"))))] + "" + "cmn\\t%0, %1") + +;; Jump insns + +(define_insn "jump" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "" + "* + if (get_attr_length (insn) == 2) + return \"b\\t%l0\"; + return \"bl\\t%l0\\t%@ far jump\"; +"[(set (attr "far_jump") + (if_then_else (eq_attr "length" "4") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2048)) + (le (minus (match_dup 0) (pc)) (const_int 2044))) + (const_int 2) + (const_int 4)))]) + + +(define_expand "beq" + [(set (pc) (if_then_else (eq (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bne" + [(set (pc) (if_then_else (ne (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bge" + [(set (pc) (if_then_else (ge (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "ble" + [(set (pc) (if_then_else (le (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bgt" + [(set (pc) (if_then_else (gt (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "blt" + [(set (pc) (if_then_else (lt (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bgeu" + [(set (pc) (if_then_else (geu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bleu" + [(set (pc) (if_then_else (leu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bgtu" + [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bltu" + [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_insn "*cond_branch" + [(set (pc) (if_then_else (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + switch (get_attr_length (insn)) + { + case 2: return \"b%d1\\t%l0\\t%@cond_branch\"; + case 4: return \"b%D1\\t.LCB%=\;b\\t%l0\\t%@long jump\\n.LCB%=:\"; + default: return \"b%D1\\t.LCB%=\;bl\\t%l0\\t%@far jump\\n.LCB%=:\"; + } +"[(set (attr "far_jump") + (if_then_else (eq_attr "length" "6") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 0) (pc)) (const_int -252)) + (le (minus (match_dup 0) (pc)) (const_int 254))) + (const_int 2) + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) + (le (minus (match_dup 0) (pc)) (const_int 2044))) + (const_int 4) + (const_int 6))))]) + +(define_insn "*cond_branch_reversed" + [(set (pc) (if_then_else (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + switch (get_attr_length (insn)) + { + case 2: return \"b%D1\\t%l0\\t%@cond_branch_reversed\"; + case 4: return \"b%d1\\t.LCBR%=\;b\\t%l0\\t%@long jump\\n.LCBR%=:\"; + default: return \"b%d1\\t.LCBR%=\;bl\\t%l0\\t%@far jump\\n.LCBR%=:\"; + } + return \"\"; +"[(set (attr "far_jump") + (if_then_else (eq_attr "length" "6") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 0) (pc)) (const_int -252)) + (le (minus (match_dup 0) (pc)) (const_int 254))) + (const_int 2) + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) + (le (minus (match_dup 0) (pc)) (const_int 2044))) + (const_int 4) + (const_int 6))))]) + +(define_insn "indirect_jump" + [(set (pc) (match_operand:SI 0 "s_register_operand" "l*r"))] + "" + "mov\\tpc, %0") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "s_register_operand" "l*r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "mov\\tpc, %0") + +(define_insn "return" + [(return)] + "USE_RETURN" + "* return output_return ();" +[(set_attr "length" "18")]) + +;; Call insns + +(define_expand "call" + [(parallel + [(call (match_operand:SI 0 "memory_operand" "") + (match_operand 1 "" "")) + (use (match_operand 2 "" ""))])] + "" + " +{ + if (GET_CODE (XEXP (operands[0], 0)) != REG + && arm_is_longcall_p (operands[0], INTVAL (operands[2]), 0)) + XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0)); +}") + +(define_insn "*call_indirect" + [(parallel + [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) + (match_operand 1 "" "")) + (use (match_operand 2 "" ""))])] + "! TARGET_CALLER_INTERWORKING" + "bl\\t%__call_via_%0" +[(set_attr "length" "4")]) +;; The non THUMB_INTERWORK, non TARGET_CALLER_INTERWORKING version +;; used to be: "mov\\tlr,pc\;bx\\t%0", but the mov does not set +;; the bottom bit of lr so that a function return (using bx) +;; would switch back into ARM mode... + +(define_insn "*call_indirect_interwork" + [(parallel + [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) + (match_operand 1 "" "")) + (use (match_operand 2 "" ""))])] + "TARGET_CALLER_INTERWORKING" + "bl\\t%__interwork_call_via_%0" +[(set_attr "length" "4")]) + +(define_expand "call_value" + [(parallel + [(set (match_operand 0 "" "") + (call (match_operand 1 "memory_operand" "") + (match_operand 2 "" ""))) + (use (match_operand 3 "" ""))])] + "" + " +{ + if (GET_CODE (XEXP (operands[1], 0)) != REG + && arm_is_longcall_p (operands[1], INTVAL (operands[3]), 0)) + XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0)); +}") + +(define_insn "*call_value_indirect" + [(parallel + [(set (match_operand 0 "" "=l") + (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" ""))])] + "! TARGET_CALLER_INTERWORKING" + "bl\\t%__call_via_%1" +[(set_attr "length" "4")]) +;; See comment for call_indirect pattern + +(define_insn "*call_value_indirect_interwork" + [(parallel + [(set (match_operand 0 "" "=l") + (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" ""))])] + "TARGET_CALLER_INTERWORKING" + "bl\\t%__interwork_call_via_%1" +[(set_attr "length" "4")]) + + +(define_insn "*call_insn" + [(parallel + [(call (mem:SI (match_operand:SI 0 "" "i")) + (match_operand:SI 1 "" "")) + (use (match_operand 2 "" ""))])] + "GET_CODE (operands[0]) == SYMBOL_REF + && ! arm_is_longcall_p (operands[0], INTVAL (operands[2]), 1)" + "bl\\t%a0" +[(set_attr "length" "4")]) + +(define_insn "*call_value_insn" + [(parallel + [(set (match_operand 0 "register_operand" "=l") + (call (mem:SI (match_operand 1 "" "i")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" ""))])] + "GET_CODE(operands[1]) == SYMBOL_REF + && ! arm_is_longcall_p (operands[1], INTVAL (operands[3]), 1)" + "bl\\t%a1" +[(set_attr "length" "4")]) + +;; Untyped call not required, since all funcs return in r0 + +;; Miscellaneous patterns + +(define_insn "nop" + [(clobber (const_int 0))] + "" + "mov\\tr8, r8") + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] 0)] + "" + "" + [(set_attr "length" "0")]) + +(define_expand "prologue" + [(const_int 0)] + "" + " + thumb_expand_prologue (); + DONE; +") + +(define_expand "epilogue" + [(unspec_volatile [(const_int 0)] 1)] + "! thumb_trivial_epilogue ()" + " + thumb_expand_epilogue (); +") + +(define_insn "*epilogue_insns" + [(unspec_volatile [(const_int 0)] 1)] + "" + "* + return thumb_unexpanded_epilogue (); +" +[(set_attr "length" "42")]) + +;; Special patterns for dealing with the constant pool + +(define_insn "consttable_4" + [(unspec_volatile [(match_operand 0 "" "")] 2)] + "" + "* +{ + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) + { + case MODE_FLOAT: + { + union real_extract u; + bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); + assemble_real (u.d, GET_MODE (operands[0])); + break; + } + default: + assemble_integer (operands[0], 4, 1); + break; + } + return \"\"; +}" +[(set_attr "length" "4")]) + +(define_insn "consttable_8" + [(unspec_volatile [(match_operand 0 "" "")] 3)] + "" + "* +{ + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) + { + case MODE_FLOAT: + { + union real_extract u; + bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); + assemble_real (u.d, GET_MODE (operands[0])); + break; + } + default: + assemble_integer (operands[0], 8, 1); + break; + } + return \"\"; +}" +[(set_attr "length" "8")]) + +(define_insn "consttable_end" + [(unspec_volatile [(const_int 0)] 4)] + "" + "* + /* Nothing to do (currently). */ + return \"\"; +") + +(define_insn "align_4" + [(unspec_volatile [(const_int 0)] 5)] + "" + "* + assemble_align (32); + return \"\"; +") diff --git a/gcc_arm/config/arm/thumb_020428.h b/gcc_arm/config/arm/thumb_020428.h new file mode 100755 index 0000000..8bba8d0 --- /dev/null +++ b/gcc_arm/config/arm/thumb_020428.h @@ -0,0 +1,1297 @@ +/* Definitions of target machine for GNU compiler, for ARM/Thumb. + Copyright (C) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc. + The basis of this contribution was generated by + Richard Earnshaw, Advanced RISC Machines Ltd + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* ??? The files thumb.{c,h,md} are all seriously lacking comments. */ + +/* ??? The files thumb.{c,h,md} need to be reviewed by an experienced + gcc hacker in their entirety. */ + +/* ??? The files thumb.{c,h,md} and tcoff.h are all separate from the arm + files, which will lead to many maintenance problems. These files are + likely missing all bug fixes made to the arm port since they diverged. */ + +/* ??? Many patterns in the md file accept operands that will require a + reload. These should be eliminated if possible by tightening the + predicates and/or constraints. This will give faster/smaller code. */ + +/* ??? There is no pattern for the TST instuction. Check for other unsupported + instructions. */ + +/* Run Time Target Specifications */ +#ifndef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dthumb -D__thumb -Acpu(arm) -Amachine(arm)" +#endif + +#ifndef CPP_SPEC +#define CPP_SPEC "\ +%{mbig-endian:-D__ARMEB__ -D__THUMBEB__} \ +%{mbe:-D__ARMEB__ -D__THUMBEB__} \ +%{!mbe: %{!mbig-endian:-D__ARMEL__ -D__THUMBEL__}} \ +" +#endif + +#ifndef ASM_SPEC +#define ASM_SPEC "-marm7tdmi %{mthumb-interwork:-mthumb-interwork} %{mbig-endian:-EB}" +#endif +#define LINK_SPEC "%{mbig-endian:-EB} -X" + +#define TARGET_VERSION fputs (" (ARM/THUMB:generic)", stderr); + +/* Nonzero if we should compile with BYTES_BIG_ENDIAN set to 1. */ +#define THUMB_FLAG_BIG_END 0x0001 +#define THUMB_FLAG_BACKTRACE 0x0002 +#define THUMB_FLAG_LEAF_BACKTRACE 0x0004 +#define ARM_FLAG_THUMB 0x1000 /* same as in arm.h */ +#define THUMB_FLAG_CALLEE_SUPER_INTERWORKING 0x40000 +#define THUMB_FLAG_CALLER_SUPER_INTERWORKING 0x80000 + +/* Nonzero if all call instructions should be indirect. */ +#define ARM_FLAG_LONG_CALLS (0x10000) /* same as in arm.h */ + + +/* Run-time compilation parameters selecting different hardware/software subsets. */ +extern int target_flags; +#define TARGET_DEFAULT 0 /* ARM_FLAG_THUMB */ +#define TARGET_BIG_END (target_flags & THUMB_FLAG_BIG_END) +#define TARGET_THUMB_INTERWORK (target_flags & ARM_FLAG_THUMB) +#define TARGET_BACKTRACE (leaf_function_p() \ + ? (target_flags & THUMB_FLAG_LEAF_BACKTRACE) \ + : (target_flags & THUMB_FLAG_BACKTRACE)) + +/* Set if externally visable functions should assume that they + might be called in ARM mode, from a non-thumb aware code. */ +#define TARGET_CALLEE_INTERWORKING \ + (target_flags & THUMB_FLAG_CALLEE_SUPER_INTERWORKING) + +/* Set if calls via function pointers should assume that their + destination is non-Thumb aware. */ +#define TARGET_CALLER_INTERWORKING \ + (target_flags & THUMB_FLAG_CALLER_SUPER_INTERWORKING) + +#define TARGET_LONG_CALLS (target_flags & ARM_FLAG_LONG_CALLS) + +/* SUBTARGET_SWITCHES is used to add flags on a per-config basis. */ +#ifndef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES +#endif + +#define TARGET_SWITCHES \ +{ \ + {"big-endian", THUMB_FLAG_BIG_END}, \ + {"little-endian", -THUMB_FLAG_BIG_END}, \ + {"thumb-interwork", ARM_FLAG_THUMB}, \ + {"no-thumb-interwork", -ARM_FLAG_THUMB}, \ + {"tpcs-frame", THUMB_FLAG_BACKTRACE}, \ + {"no-tpcs-frame", -THUMB_FLAG_BACKTRACE}, \ + {"tpcs-leaf-frame", THUMB_FLAG_LEAF_BACKTRACE}, \ + {"no-tpcs-leaf-frame", -THUMB_FLAG_LEAF_BACKTRACE}, \ + {"callee-super-interworking", THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \ + {"no-callee-super-interworking", -THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \ + {"caller-super-interworking", THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \ + {"no-caller-super-interworking", -THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \ + {"long-calls", ARM_FLAG_LONG_CALLS, \ + "Generate all call instructions as indirect calls"}, \ + {"no-long-calls", -ARM_FLAG_LONG_CALLS, ""}, \ + SUBTARGET_SWITCHES \ + {"", TARGET_DEFAULT} \ +} + +#define TARGET_OPTIONS \ +{ \ + { "structure-size-boundary=", & structure_size_string }, \ +} + +#define REGISTER_PREFIX "" + +#define CAN_DEBUG_WITHOUT_FP 1 + +#define ASM_APP_ON "" +#define ASM_APP_OFF "\t.code\t16\n" + +/* Output a gap. In fact we fill it with nulls. */ +#define ASM_OUTPUT_SKIP(STREAM, NBYTES) \ + fprintf ((STREAM), "\t.space\t%u\n", (NBYTES)) + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ +#define ASM_OUTPUT_ALIGN(STREAM,LOG) \ +{ \ + if ((LOG) > 0) \ + fprintf (STREAM, "\t.align\t%d\n", (LOG)); \ +} + +/* Output a common block */ +#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ + (fprintf ((STREAM), "\t.comm\t"), \ + assemble_name ((STREAM), (NAME)), \ + fprintf((STREAM), ", %d\t%s %d\n", (ROUNDED), (ASM_COMMENT_START), (SIZE))) + +#define ASM_GENERATE_INTERNAL_LABEL(STRING,PREFIX,NUM) \ + sprintf ((STRING), "*%s%s%d", (LOCAL_LABEL_PREFIX), (PREFIX), (NUM)) + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ +#define ASM_OUTPUT_INTERNAL_LABEL(STREAM,PREFIX,NUM) \ + fprintf ((STREAM), "%s%s%d:\n", (LOCAL_LABEL_PREFIX), (PREFIX), (NUM)) + +/* This is how to output a label which precedes a jumptable. Since + instructions are 2 bytes, we need explicit alignment here. */ + +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,JUMPTABLE) \ + do { \ + ASM_OUTPUT_ALIGN (FILE, 2); \ + ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM); \ + } while (0) + +/* This says how to define a local common symbol (ie, not visible to + linker). */ +#define ASM_OUTPUT_LOCAL(STREAM, NAME, SIZE, ROUNDED) \ + (fprintf((STREAM),"\n\t.lcomm\t"), \ + assemble_name((STREAM),(NAME)), \ + fprintf((STREAM),",%u\n",(SIZE))) + +/* This is how to output an assembler line for a numeric constant byte. */ +#define ASM_OUTPUT_BYTE(STREAM,VALUE) \ + fprintf ((STREAM), "\t.byte\t0x%x\n", (VALUE)) + +#define ASM_OUTPUT_INT(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.word\t"); \ + output_addr_const (STREAM, (VALUE)); \ + fprintf (STREAM, "\n"); \ +} + +#define ASM_OUTPUT_SHORT(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.short\t"); \ + output_addr_const (STREAM, (VALUE)); \ + fprintf (STREAM, "\n"); \ +} + +#define ASM_OUTPUT_CHAR(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.byte\t"); \ + output_addr_const (STREAM, (VALUE)); \ + fprintf (STREAM, "\n"); \ +} + +#define ASM_OUTPUT_LONG_DOUBLE(STREAM,VALUE) \ +do { char dstr[30]; \ + long l[3]; \ + REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ + fprintf (STREAM, "\t.long 0x%lx,0x%lx,0x%lx\t%s long double %s\n", \ + l[0], l[1], l[2], ASM_COMMENT_START, dstr); \ + } while (0) + +#define ASM_OUTPUT_DOUBLE(STREAM, VALUE) \ +do { char dstr[30]; \ + long l[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.14g", dstr); \ + fprintf (STREAM, "\t.long 0x%lx, 0x%lx\t%s double %s\n", l[0], \ + l[1], ASM_COMMENT_START, dstr); \ + } while (0) + +#define ASM_OUTPUT_FLOAT(STREAM, VALUE) \ +do { char dstr[30]; \ + long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.7g", dstr); \ + fprintf (STREAM, "\t.word 0x%lx\t%s float %s\n", l, \ + ASM_COMMENT_START, dstr); \ + } while (0); + +/* Define results of standard character escape sequences. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* This is how to output a string. */ +#define ASM_OUTPUT_ASCII(STREAM, STRING, LEN) \ +do { \ + register int i, c, len = (LEN), cur_pos = 17; \ + register unsigned char *string = (unsigned char *)(STRING); \ + fprintf ((STREAM), "\t.ascii\t\""); \ + for (i = 0; i < len; i++) \ + { \ + register int c = string[i]; \ + \ + switch (c) \ + { \ + case '\"': \ + case '\\': \ + putc ('\\', (STREAM)); \ + putc (c, (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_NEWLINE: \ + fputs ("\\n", (STREAM)); \ + if (i+1 < len \ + && (((c = string[i+1]) >= '\040' && c <= '~') \ + || c == TARGET_TAB)) \ + cur_pos = 32767; /* break right here */ \ + else \ + cur_pos += 2; \ + break; \ + \ + case TARGET_TAB: \ + fputs ("\\t", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_FF: \ + fputs ("\\f", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_BS: \ + fputs ("\\b", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_CR: \ + fputs ("\\r", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + default: \ + if (c >= ' ' && c < 0177) \ + { \ + putc (c, (STREAM)); \ + cur_pos++; \ + } \ + else \ + { \ + fprintf ((STREAM), "\\%03o", c); \ + cur_pos += 4; \ + } \ + } \ + \ + if (cur_pos > 72 && i+1 < len) \ + { \ + cur_pos = 17; \ + fprintf ((STREAM), "\"\n\t.ascii\t\""); \ + } \ + } \ + fprintf ((STREAM), "\"\n"); \ +} while (0) + +/* Output and Generation of Labels */ +#define ASM_OUTPUT_LABEL(STREAM,NAME) \ + (assemble_name ((STREAM), (NAME)), \ + fprintf ((STREAM), ":\n")) + +#define ASM_GLOBALIZE_LABEL(STREAM,NAME) \ + (fprintf ((STREAM), "\t.globl\t"), \ + assemble_name ((STREAM), (NAME)), \ + fputc ('\n', (STREAM))) + +/* Construct a private name. */ +#define ASM_FORMAT_PRIVATE_NAME(OUTVAR,NAME,NUMBER) \ + ((OUTVAR) = (char *) alloca (strlen (NAME) + 10), \ + sprintf ((OUTVAR), "%s.%d", (NAME), (NUMBER))) + +/* Switch to the text or data segment. */ +#define TEXT_SECTION_ASM_OP ".text" +#define DATA_SECTION_ASM_OP ".data" +#define BSS_SECTION_ASM_OP ".bss" + +/* The assembler's names for the registers. */ +#ifndef REGISTER_NAMES +#define REGISTER_NAMES \ +{ \ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc", "ap" \ +} +#endif + +#ifndef ADDITIONAL_REGISTER_NAMES +#define ADDITIONAL_REGISTER_NAMES \ +{ \ + {"a1", 0}, \ + {"a2", 1}, \ + {"a3", 2}, \ + {"a4", 3}, \ + {"v1", 4}, \ + {"v2", 5}, \ + {"v3", 6}, \ + {"v4", 7}, \ + {"v5", 8}, \ + {"v6", 9}, \ + {"sb", 9}, \ + {"v7", 10}, \ + {"r10", 10}, /* sl */ \ + {"r11", 11}, /* fp */ \ + {"r12", 12}, /* ip */ \ + {"r13", 13}, /* sp */ \ + {"r14", 14}, /* lr */ \ + {"r15", 15} /* pc */ \ +} +#endif + +/* The assembler's parentheses characters. */ +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + +#ifndef ASM_COMMENT_START +#define ASM_COMMENT_START "@" +#endif + +/* Output an element of a dispatch table. */ +#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM,VALUE) \ + fprintf (STREAM, "\t.word\t%sL%d\n", (LOCAL_LABEL_PREFIX), (VALUE)) + +#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM,BODY,VALUE,REL) \ + fprintf (STREAM, "\tb\t%sL%d\n", (LOCAL_LABEL_PREFIX), (VALUE)) + +/* Storage Layout */ + +/* Define this is most significant bit is lowest numbered in + instructions that operate on numbered bit-fields. */ +#define BITS_BIG_ENDIAN 0 + +/* Define this if most significant byte of a word is the lowest + numbered. */ +#define BYTES_BIG_ENDIAN (TARGET_BIG_END != 0) + +#define WORDS_BIG_ENDIAN (BYTES_BIG_ENDIAN) + +/* LIBGCC2_WORDS_BIG_ENDIAN has to be a constant, so we define this based + on processor pre-defineds when compiling libgcc2.c. */ +#if defined(__THUMBEB__) && !defined(__THUMBEL__) +#define LIBGCC2_WORDS_BIG_ENDIAN 1 +#else +#define LIBGCC2_WORDS_BIG_ENDIAN 0 +#endif + +#define FLOAT_WORDS_BIG_ENDIAN 1 + +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 + +#define UNITS_PER_WORD 4 + +#define POINTER_SIZE 32 + +#define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \ +{ \ + if (GET_MODE_CLASS (MODE) == MODE_INT \ + && GET_MODE_SIZE (MODE) < 4) \ + { \ + (UNSIGNEDP) = 1; \ + (MODE) = SImode; \ + } \ +} + +#define PARM_BOUNDARY 32 +#define STACK_BOUNDARY 32 + +#define FUNCTION_BOUNDARY 32 +#define BIGGEST_ALIGNMENT 32 + +/* Make strings word-aligned so strcpy from constants will be faster. */ +#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ + (TREE_CODE (EXP) == STRING_CST \ + && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) + +#define EMPTY_FIELD_BOUNDARY 32 + +#define STRUCTURE_SIZE_BOUNDARY 32 + +/* Used when parsing command line option -mstructure_size_boundary. */ +extern char * structure_size_string; + +#define STRICT_ALIGNMENT 1 + +#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT + + +/* Layout of Source Language Data Types */ + +#define DEFAULT_SIGNED_CHAR 0 + +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + + +/* Register Usage */ + +/* Note there are 16 hard registers on the Thumb. We invent a 17th register + which is assigned to ARG_POINTER_REGNUM, but this is later removed by + elimination passes in the compiler. */ +#define FIRST_PSEUDO_REGISTER 17 + +/* ??? This is questionable. */ +#define FIXED_REGISTERS \ +{ \ + 0,0,0,0, \ + 0,0,0,0, \ + 0,0,0,1, \ + 0,1,1,1,1 \ +} + +/* ??? This is questionable. */ +#define CALL_USED_REGISTERS \ +{ \ + 1,1,1,1, \ + 0,0,0,0, \ + 0,0,0,1, \ + 1,1,1,1,1 \ +} + +#define HARD_REGNO_NREGS(REGNO,MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ + / UNITS_PER_WORD) + +/* ??? Probably should only allow DImode/DFmode in even numbered registers. */ +#define HARD_REGNO_MODE_OK(REGNO,MODE) ((GET_MODE_SIZE (MODE) > UNITS_PER_WORD) ? (REGNO < 7) : 1) + +#define MODES_TIEABLE_P(MODE1,MODE2) 1 + +/* The NOARG_LO_REGS class is the set of LO_REGS that are not used for passing + arguments to functions. These are the registers that are available for + spilling during reload. The code in reload1.c:init_reload() will detect this + class and place it into 'reload_address_base_reg_class'. */ + +enum reg_class +{ + NO_REGS, + NONARG_LO_REGS, + LO_REGS, + STACK_REG, + BASE_REGS, + HI_REGS, + ALL_REGS, + LIM_REG_CLASSES +}; + +#define GENERAL_REGS ALL_REGS + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +#define REG_CLASS_NAMES \ +{ \ + "NO_REGS", \ + "NONARG_LO_REGS", \ + "LO_REGS", \ + "STACK_REG", \ + "BASE_REGS", \ + "HI_REGS", \ + "ALL_REGS" \ +} + +#define REG_CLASS_CONTENTS \ +{ \ + 0x00000, \ + 0x000f0, \ + 0x000ff, \ + 0x02000, \ + 0x020ff, \ + 0x0ff00, \ + 0x1ffff, \ +} + +#define REGNO_REG_CLASS(REGNO) \ + ((REGNO) == STACK_POINTER_REGNUM ? STACK_REG \ + : (REGNO) < 8 ? ((REGNO) < 4 ? LO_REGS \ + : NONARG_LO_REGS) \ + : HI_REGS) + +#define BASE_REG_CLASS BASE_REGS + +#define MODE_BASE_REG_CLASS(MODE) \ + ((MODE) != QImode && (MODE) != HImode \ + ? BASE_REGS : LO_REGS) + +#define INDEX_REG_CLASS LO_REGS + +/* When SMALL_REGISTER_CLASSES is nonzero, the compiler allows + registers explicitly used in the rtl to be used as spill registers + but prevents the compiler from extending the lifetime of these + registers. */ + +#define SMALL_REGISTER_CLASSES 1 + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'l' ? LO_REGS \ + : (C) == 'h' ? HI_REGS \ + : (C) == 'b' ? BASE_REGS \ + : (C) == 'k' ? STACK_REG \ + : NO_REGS) + +#define REGNO_OK_FOR_BASE_P(REGNO) \ + ((REGNO) < 8 \ + || (REGNO) == STACK_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO] < 8 \ + || (unsigned) reg_renumber[REGNO] == STACK_POINTER_REGNUM) + +#define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) \ + ((REGNO) < 8 \ + || (unsigned) reg_renumber[REGNO] < 8 \ + || (GET_MODE_SIZE (MODE) >= 4 \ + && ((REGNO) == STACK_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO] == STACK_POINTER_REGNUM))) + +#define REGNO_OK_FOR_INDEX_P(REGNO) \ + ((REGNO) < 8 \ + || (unsigned) reg_renumber[REGNO] < 8) + +/* ??? This looks suspiciously wrong. */ +/* We need to leave BASE_REGS reloads alone, in order to avoid caller_save + lossage. Caller_saves requests a BASE_REGS reload (caller_save_spill_class) + and then later we verify that one was allocated. If PREFERRED_RELOAD_CLASS + says to allocate a LO_REGS spill instead, then this mismatch gives an + abort. Alternatively, this could be fixed by modifying BASE_REG_CLASS + to be LO_REGS instead of BASE_REGS. It is not clear what affect this + change would have. */ +/* ??? This looks even more suspiciously wrong. PREFERRED_RELOAD_CLASS + must always return a strict subset of the input class. Just blindly + returning LO_REGS is safe only if the input class is a superset of LO_REGS, + but there is no check for this. Added another exception for NONARG_LO_REGS + because it is not a superset of LO_REGS. */ +/* ??? We now use NONARG_LO_REGS for caller_save_spill_class, so the + comments about BASE_REGS are now obsolete. */ +#define PREFERRED_RELOAD_CLASS(X,CLASS) \ + ((CLASS) == BASE_REGS || (CLASS) == NONARG_LO_REGS ? (CLASS) \ + : LO_REGS) +/* + ((CONSTANT_P ((X)) && GET_CODE ((X)) != CONST_INT \ + && ! CONSTANT_POOL_ADDRESS_P((X))) ? NO_REGS \ + : (GET_CODE ((X)) == CONST_INT \ + && (unsigned HOST_WIDE_INT) INTVAL ((X)) > 255) ? NO_REGS \ + : LO_REGS) */ + +/* Must leave BASE_REGS and NONARG_LO_REGS reloads alone, see comment + above. */ +#define SECONDARY_RELOAD_CLASS(CLASS,MODE,X) \ + ((CLASS) != LO_REGS && (CLASS) != BASE_REGS && (CLASS) != NONARG_LO_REGS \ + ? ((true_regnum (X) == -1 ? LO_REGS \ + : (true_regnum (X) + HARD_REGNO_NREGS (0, MODE) > 8) ? LO_REGS \ + : NO_REGS)) \ + : NO_REGS) + +#define CLASS_MAX_NREGS(CLASS,MODE) HARD_REGNO_NREGS(0,(MODE)) + +int thumb_shiftable_const (); + +#define CONST_OK_FOR_LETTER_P(VAL,C) \ + ((C) == 'I' ? (unsigned HOST_WIDE_INT) (VAL) < 256 \ + : (C) == 'J' ? (VAL) > -256 && (VAL) <= 0 \ + : (C) == 'K' ? thumb_shiftable_const (VAL) \ + : (C) == 'L' ? (VAL) > -8 && (VAL) < 8 \ + : (C) == 'M' ? ((unsigned HOST_WIDE_INT) (VAL) < 1024 \ + && ((VAL) & 3) == 0) \ + : (C) == 'N' ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ + : (C) == 'O' ? ((VAL) >= -508 && (VAL) <= 508) \ + : 0) + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VAL,C) 0 + +#define EXTRA_CONSTRAINT(X,C) \ + ((C) == 'Q' ? (GET_CODE (X) == MEM \ + && GET_CODE (XEXP (X, 0)) == LABEL_REF) : 0) + +/* Stack Layout and Calling Conventions */ + +#define STACK_GROWS_DOWNWARD 1 + +/* #define FRAME_GROWS_DOWNWARD 1 */ + +/* #define ARGS_GROW_DOWNWARD 1 */ + +#define STARTING_FRAME_OFFSET 0 + +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* Registers that address the stack frame */ + +#define STACK_POINTER_REGNUM 13 /* Defined by the TPCS. */ + +#define FRAME_POINTER_REGNUM 7 /* TPCS defines this as 11 but it does not really mean it. */ + +#define ARG_POINTER_REGNUM 16 /* A fake hard register that is eliminated later on. */ + +#define STATIC_CHAIN_REGNUM 9 + +#define FRAME_POINTER_REQUIRED 0 + +#define ELIMINABLE_REGS \ +{{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ + {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}} + +/* On the Thumb we always want to perform the eliminations as we + actually only have one real register pointing to the stashed + variables: the stack pointer, and we never use the frame pointer. */ +#define CAN_ELIMINATE(FROM,TO) 1 + +/* Note: This macro must match the code in thumb_function_prologue() in thumb.c. */ +#define INITIAL_ELIMINATION_OFFSET(FROM,TO,OFFSET) \ +{ \ + (OFFSET) = 0; \ + if ((FROM) == ARG_POINTER_REGNUM) \ + { \ + int count_regs = 0; \ + int regno; \ + (OFFSET) += get_frame_size (); \ + for (regno = 8; regno < 13; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + count_regs++; \ + if (count_regs) \ + (OFFSET) += 4 * count_regs; \ + count_regs = 0; \ + for (regno = 0; regno < 8; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + count_regs++; \ + if (count_regs || ! leaf_function_p () || far_jump_used_p()) \ + (OFFSET) += 4 * (count_regs + 1); \ + if (TARGET_BACKTRACE) { \ + if ((count_regs & 0xFF) == 0 && (regs_ever_live[3] != 0)) \ + (OFFSET) += 20; \ + else \ + (OFFSET) += 16; } \ + } \ + if ((TO) == STACK_POINTER_REGNUM) \ + (OFFSET) += current_function_outgoing_args_size; \ +} + +/* Passing Arguments on the stack */ + +#define PROMOTE_PROTOTYPES 1 + +#define ACCUMULATE_OUTGOING_ARGS 1 + +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + ((MODE) == VOIDmode \ + ? GEN_INT ((CUM).call_cookie) \ + : (NAMED) \ + ? ((CUM).nregs >= 16 ? 0 : gen_rtx (REG, MODE, (CUM).nregs / 4)) \ + : 0) + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM,MODE,TYPE,NAMED) \ + (((CUM).nregs < 16 && (CUM).nregs + (((MODE) == BLKmode) \ + ? int_size_in_bytes (TYPE) \ + : (HARD_REGNO_NREGS (0, (MODE)) \ + * 4)) > 16) \ + ? 4 - (CUM).nregs / 4 : 0) + +/* A C type for declaring a variable that is used as the first argument of + `FUNCTION_ARG' and other related values. For some target machines, the + type `int' suffices and can hold the number of bytes of argument so far. + + On the ARM, this is the number of bytes of arguments scanned so far. */ +typedef struct +{ + /* This is the number of registers of arguments scanned so far. */ + int nregs; + /* One of CALL_NORMAL, CALL_LONG or CALL_SHORT . */ + int call_cookie; +} CUMULATIVE_ARGS; + + +/* 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. + On the ARM, the offset starts at 0. */ +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ + ((CUM).nregs = (((FNTYPE) && aggregate_value_p (TREE_TYPE ((FNTYPE)))) \ + ? 4 : 0), \ + (CUM).call_cookie = \ + (((FNTYPE) && lookup_attribute ("short_call", TYPE_ATTRIBUTES (FNTYPE))) \ + ? CALL_SHORT \ + : (((FNTYPE) && lookup_attribute ("long_call", \ + TYPE_ATTRIBUTES (FNTYPE)))\ + || TARGET_LONG_CALLS) \ + ? CALL_LONG \ + : CALL_NORMAL)) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + (CUM).nregs += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3) \ + +#define FUNCTION_ARG_REGNO_P(REGNO) \ + ((REGNO) >=0 && (REGNO) <= 3) + +#define FUNCTION_VALUE(VALTYPE,FUNC) gen_rtx (REG, TYPE_MODE (VALTYPE), 0) + +#define LIBCALL_VALUE(MODE) gen_rtx (REG, (MODE), 0) + +#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == 0) + + /* How large values are returned */ +/* A C expression which can inhibit the returning of certain function values + in registers, based on the type of value. */ +#define RETURN_IN_MEMORY(TYPE) thumb_return_in_memory (TYPE) + +/* Define DEFAULT_PCC_STRUCT_RETURN to 1 if all structure and union return + values must be in memory. On the ARM, they need only do so if larger + than a word, or if they contain elements offset from zero in the struct. */ +#define DEFAULT_PCC_STRUCT_RETURN 0 + + +#define STRUCT_VALUE_REGNUM 0 + +#define FUNCTION_PROLOGUE(FILE,SIZE) thumb_function_prologue((FILE),(SIZE)) + +#define FUNCTION_EPILOGUE(FILE,SIZE) thumb_function_epilogue((FILE),(SIZE)) + +/* Implementing the Varargs Macros */ + +#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \ +{ \ + extern int current_function_anonymous_args; \ + current_function_anonymous_args = 1; \ + if ((CUM).nregs < 16) \ + (PRETEND_SIZE) = 16 - (CUM).nregs; \ +} + +/* Trampolines for nested functions */ + +/* Output assembler code for a block containing the constant parts of + a trampoline, leaving space for the variable parts. + + On the Thumb we always switch into ARM mode to execute the trampoline. + Why - because it is easier. This code will always be branched to via + a BX instruction and since the compiler magically generates the address + of the function the linker has no opportunity to ensure that the + bottom bit is set. Thus the processor will be in ARM mode when it + reaches this code. So we duplicate the ARM trampoline code and add + a switch into Thumb mode as well. + + On the ARM, (if r8 is the static chain regnum, and remembering that + referencing pc adds an offset of 8) the trampoline looks like: + ldr r8, [pc, #0] + ldr pc, [pc] + .word static chain value + .word function's address + ??? FIXME: When the trampoline returns, r8 will be clobbered. */ +#define TRAMPOLINE_TEMPLATE(FILE) \ +{ \ + fprintf ((FILE), "\t.code 32\n"); \ + fprintf ((FILE), ".Ltrampoline_start:\n"); \ + fprintf ((FILE), "\tldr\t%s, [%spc, #8]\n", \ + reg_names[STATIC_CHAIN_REGNUM], REGISTER_PREFIX); \ + fprintf ((FILE), "\tldr\t%sip, [%spc, #8]\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\torr\t%sip, %sip, #1\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\tbx\t%sip\n", REGISTER_PREFIX); \ + fprintf ((FILE), "\t.word\t0\n"); \ + fprintf ((FILE), "\t.word\t0\n"); \ + fprintf ((FILE), "\t.code 16\n"); \ +} + +/* Length in units of the trampoline for entering a nested function. */ +#define TRAMPOLINE_SIZE 24 + +/* Alignment required for a trampoline in units. */ +#define TRAMPOLINE_ALIGN 4 + +#define INITIALIZE_TRAMPOLINE(ADDR,FNADDR,CHAIN) \ +{ \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((ADDR), 16)), \ + (CHAIN)); \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((ADDR), 20)), \ + (FNADDR)); \ +} + + +/* Implicit Calls to Library Routines */ + +#define TARGET_MEM_FUNCTIONS 1 + +#define OVERRIDE_OPTIONS thumb_override_options () + + +/* Addressing Modes */ + +#define HAVE_POST_INCREMENT 1 + +#define CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (X)) + +#define MAX_REGS_PER_ADDRESS 2 + +#ifdef REG_OK_STRICT + +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) + +#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ + REGNO_MODE_OK_FOR_BASE_P (REGNO (X), MODE) + +#else /* REG_OK_STRICT */ + +#define REG_OK_FOR_BASE_P(X) \ + (REGNO (X) < 8 || REGNO (X) == STACK_POINTER_REGNUM \ + || (X) == arg_pointer_rtx \ + || REGNO (X) >= FIRST_PSEUDO_REGISTER) + +#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ + (REGNO (X) < 8 \ + || REGNO (X) >= FIRST_PSEUDO_REGISTER \ + || (GET_MODE_SIZE (MODE) >= 4 \ + && (REGNO (X) == STACK_POINTER_REGNUM \ + || (X) == arg_pointer_rtx))) + +#define REG_OK_FOR_INDEX_P(X) \ + (REGNO (X) < 8 \ + || REGNO (X) >= FIRST_PSEUDO_REGISTER) + +#endif /* REG_OK_STRICT */ + +/* In a REG+REG address, both must be INDEX registers. */ +#define REG_OK_FOR_INDEXED_BASE_P(X) REG_OK_FOR_INDEX_P(X) + +#define LEGITIMATE_OFFSET(MODE,VAL) \ +(GET_MODE_SIZE (MODE) == 1 ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ + : GET_MODE_SIZE (MODE) == 2 ? ((unsigned HOST_WIDE_INT) (VAL) < 64 \ + && ((VAL) & 1) == 0) \ + : ((VAL) >= 0 && ((VAL) + GET_MODE_SIZE (MODE)) <= 128 \ + && ((VAL) & 3) == 0)) + +/* The AP may be eliminated to either the SP or the FP, so we use the + least common denominator, e.g. SImode, and offsets from 0 to 64. */ + +/* ??? Verify whether the above is the right approach. */ + +/* ??? Also, the FP may be eliminated to the SP, so perhaps that + needs special handling also. */ + +/* ??? Look at how the mips16 port solves this problem. It probably uses + better ways to solve some of these problems. */ + +/* Although it is not incorrect, we don't accept QImode and HImode + addresses based on the frame pointer or arg pointer until the reload pass starts. + This is so that eliminating such addresses into stack based ones + won't produce impossible code. */ +#define GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \ +{ \ + /* ??? Not clear if this is right. Experiment. */ \ + if (GET_MODE_SIZE (MODE) < 4 \ + && ! (reload_in_progress || reload_completed) \ + && (reg_mentioned_p (frame_pointer_rtx, X) \ + || reg_mentioned_p (arg_pointer_rtx, X) \ + || reg_mentioned_p (virtual_incoming_args_rtx, X) \ + || reg_mentioned_p (virtual_outgoing_args_rtx, X) \ + || reg_mentioned_p (virtual_stack_dynamic_rtx, X) \ + || reg_mentioned_p (virtual_stack_vars_rtx, X))) \ + ; \ + /* Accept any base register. SP only in SImode or larger. */ \ + else if (GET_CODE (X) == REG && REG_MODE_OK_FOR_BASE_P(X, MODE)) \ + goto WIN; \ + /* This is PC relative data before MACHINE_DEPENDENT_REORG runs. */ \ + else if (GET_MODE_SIZE (MODE) >= 4 && CONSTANT_P (X) \ + && CONSTANT_POOL_ADDRESS_P (X)) \ + goto WIN; \ + /* This is PC relative data after MACHINE_DEPENDENT_REORG runs. */ \ + else if (GET_MODE_SIZE (MODE) >= 4 && reload_completed \ + && (GET_CODE (X) == LABEL_REF \ + || (GET_CODE (X) == CONST \ + && GET_CODE (XEXP (X, 0)) == PLUS \ + && GET_CODE (XEXP (XEXP (X, 0), 0)) == LABEL_REF \ + && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT))) \ + goto WIN; \ + /* Post-inc indexing only supported for SImode and larger. */ \ + else if (GET_CODE (X) == POST_INC && GET_MODE_SIZE (MODE) >= 4 \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_INDEX_P (XEXP (X, 0))) \ + goto WIN; \ + else if (GET_CODE (X) == PLUS) \ + { \ + /* REG+REG address can be any two index registers. */ \ + /* ??? REG+REG addresses have been completely disabled before \ + reload completes, because we do not have enough available \ + reload registers. We only have 3 guaranteed reload registers \ + (NONARG_LO_REGS - the frame pointer), but we need at least 4 \ + to support REG+REG addresses. We have left them enabled after \ + reload completes, in the hope that reload_cse_regs and related \ + routines will be able to create them after the fact. It is \ + probably possible to support REG+REG addresses with additional \ + reload work, but I do not not have enough time to attempt such \ + a change at this time. */ \ + /* ??? Normally checking the mode here is wrong, since it isn't \ + impossible to use REG+REG with DFmode. However, the movdf \ + pattern requires offsettable addresses, and REG+REG is not \ + offsettable, so it must be rejected somehow. Trying to use \ + 'o' fails, because offsettable_address_p does a QImode check. \ + QImode is not valid for stack addresses, and has a smaller \ + range for non-stack bases, and this causes valid addresses \ + to be rejected. So we just eliminate REG+REG here by checking \ + the mode. */ \ + /* We also disallow FRAME+REG addressing since we know that FRAME \ + will be replaced with STACK, and SP relative addressing only \ + permits SP+OFFSET. */ \ + if (GET_MODE_SIZE (MODE) <= 4 \ + /* ??? See comment above. */ \ + && reload_completed \ + && GET_CODE (XEXP (X, 0)) == REG \ + && GET_CODE (XEXP (X, 1)) == REG \ + && XEXP (X, 0) != frame_pointer_rtx \ + && XEXP (X, 1) != frame_pointer_rtx \ + && XEXP (X, 0) != virtual_stack_vars_rtx \ + && XEXP (X, 1) != virtual_stack_vars_rtx \ + && REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ + && REG_OK_FOR_INDEX_P (XEXP (X, 1))) \ + goto WIN; \ + /* REG+const has 5-7 bit offset for non-SP registers. */ \ + else if (GET_CODE (XEXP (X, 0)) == REG \ + && (REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ + || XEXP (X, 0) == arg_pointer_rtx) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ + goto WIN; \ + /* REG+const has 10 bit offset for SP, but only SImode and \ + larger is supported. */ \ + /* ??? Should probably check for DI/DFmode overflow here \ + just like GO_IF_LEGITIMATE_OFFSET does. */ \ + else if (GET_CODE (XEXP (X, 0)) == REG \ + && REGNO (XEXP (X, 0)) == STACK_POINTER_REGNUM \ + && GET_MODE_SIZE (MODE) >= 4 \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (unsigned HOST_WIDE_INT) INTVAL (XEXP (X, 1)) < 1024 \ + && (INTVAL (XEXP (X, 1)) & 3) == 0) \ + goto WIN; \ + } \ +} + +/* ??? If an HImode FP+large_offset address is converted to an HImode + SP+large_offset address, then reload won't know how to fix it. It sees + only that SP isn't valid for HImode, and so reloads the SP into an index + register, but the resulting address is still invalid because the offset + is too big. We fix it here instead by reloading the entire address. */ +/* We could probably achieve better results by defining PROMOTE_MODE to help + cope with the variances between the Thumb's signed and unsigned byte and + halfword load instructions. */ +#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \ +{ \ + if (GET_CODE (X) == PLUS \ + && GET_MODE_SIZE (MODE) < 4 \ + && GET_CODE (XEXP (X, 0)) == REG \ + && XEXP (X, 0) == stack_pointer_rtx \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && ! LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ + { \ + rtx orig_X = X; \ + X = copy_rtx (X); \ + push_reload (orig_X, NULL_RTX, &X, NULL_PTR, \ + BASE_REG_CLASS, \ + Pmode, VOIDmode, 0, 0, OPNUM, TYPE); \ + goto WIN; \ + } \ +} + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) + +#define LEGITIMATE_CONSTANT_P(X) \ + (GET_CODE (X) == CONST_INT \ + || GET_CODE (X) == CONST_DOUBLE \ + || CONSTANT_ADDRESS_P (X)) + +/* Flags for the call/call_value rtl operations set up by function_arg. */ +#define CALL_NORMAL 0x00000000 /* No special processing. */ +#define CALL_LONG 0x00000001 /* Always call indirect. */ +#define CALL_SHORT 0x00000002 /* Never call indirect. */ + +#define ENCODE_SECTION_INFO(decl) \ +{ \ + ARM_ENCODE_CALL_TYPE (decl) \ +} + +/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS + is a valid machine specific attribute for DECL. + The attributes in ATTRIBUTES have previously been assigned to DECL. */ +int arm_valid_machine_type_attribute (/* union tree_node *, union tree_node *, + union tree_node *, + union tree_node * */); +#define VALID_MACHINE_TYPE_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \ +arm_valid_machine_type_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS) + +/* If we are referencing a function that is weak then encode a long call + flag in the function name, otherwise if the function is static or + or known to be defined in this file then encode a short call flag. + This macro is used inside the ENCODE_SECTION macro. */ +#define ARM_ENCODE_CALL_TYPE(decl) \ + if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd') \ + { \ + if (TREE_CODE (decl) == FUNCTION_DECL && DECL_WEAK (decl)) \ + arm_encode_call_attribute (decl, LONG_CALL_FLAG_CHAR); \ + else if (! TREE_PUBLIC (decl)) \ + arm_encode_call_attribute (decl, SHORT_CALL_FLAG_CHAR); \ + } + +/* Special characters prefixed to function names + in order to encode attribute like information. + Note, '@' and '*' have already been taken. */ +#define SHORT_CALL_FLAG_CHAR '^' +#define LONG_CALL_FLAG_CHAR '#' + +#define ENCODED_SHORT_CALL_ATTR_P(SYMBOL_NAME) \ + (*(SYMBOL_NAME) == SHORT_CALL_FLAG_CHAR) + +#define ENCODED_LONG_CALL_ATTR_P(SYMBOL_NAME) \ + (*(SYMBOL_NAME) == LONG_CALL_FLAG_CHAR) + +#ifndef SUBTARGET_NAME_ENCODING_LENGTHS +#define SUBTARGET_NAME_ENCODING_LENGTHS +#endif + +/* This is a C fragement for the inside of a switch statement. + Each case label should return the number of characters to + be stripped from the start of a function's name, if that + name starts with the indicated character. */ +#define ARM_NAME_ENCODING_LENGTHS \ + case SHORT_CALL_FLAG_CHAR: return 1; \ + case LONG_CALL_FLAG_CHAR: return 1; \ + case '*': return 1; \ + SUBTARGET_NAME_ENCODING_LENGTHS + +/* This has to be handled by a function because more than part of the + ARM backend uses function name prefixes to encode attributes. */ +#undef STRIP_NAME_ENCODING +#define STRIP_NAME_ENCODING(VAR, SYMBOL_NAME) \ + (VAR) = arm_strip_name_encoding (SYMBOL_NAME) + +/* This is how to output a reference to a user-level label named NAME. + `assemble_name' uses this. */ +#undef ASM_OUTPUT_LABELREF +#define ASM_OUTPUT_LABELREF(FILE, NAME) \ + asm_fprintf (FILE, "%U%s", arm_strip_name_encoding (NAME)) + + +/* Condition Code Status */ + +#define NOTICE_UPDATE_CC(EXP,INSN) \ +{ \ + if (get_attr_conds ((INSN)) != CONDS_UNCHANGED) \ + CC_STATUS_INIT; \ +} + + +/* Describing Relative Costs of Operations */ + +#define SLOW_BYTE_ACCESS 0 + +#define SLOW_UNALIGNED_ACCESS 1 + +#define NO_FUNCTION_CSE 1 + +#define NO_RECURSIVE_FUNCTION_CSE 1 + +#define REGISTER_MOVE_COST(FROM,TO) \ + (((FROM) == HI_REGS || (TO) == HI_REGS) ? 4 : 2) + +#define MEMORY_MOVE_COST(M,CLASS,IN) \ + ((GET_MODE_SIZE(M) < 4 ? 8 : 2 * GET_MODE_SIZE(M)) * (CLASS == LO_REGS ? 1 : 2)) + +/* This will allow better space optimization when compiling with -O */ +#define BRANCH_COST (optimize > 1 ? 1 : 0) + +#define RTX_COSTS(X,CODE,OUTER) \ + case MULT: \ + if (GET_CODE (XEXP (X, 1)) == CONST_INT) \ + { \ + int cycles = 0; \ + unsigned HOST_WIDE_INT i = INTVAL (XEXP (X, 1)); \ + while (i) \ + { \ + i >>= 2; \ + cycles++; \ + } \ + return COSTS_N_INSNS (2) + cycles; \ + } \ + return COSTS_N_INSNS (1) + 16; \ + case ASHIFT: case ASHIFTRT: case LSHIFTRT: case ROTATERT: \ + case PLUS: case MINUS: case COMPARE: case NEG: case NOT: \ + return COSTS_N_INSNS (1); \ + case SET: \ + return (COSTS_N_INSNS (1) \ + + 4 * ((GET_CODE (SET_SRC (X)) == MEM) \ + + GET_CODE (SET_DEST (X)) == MEM)) + +#define CONST_COSTS(X,CODE,OUTER) \ + case CONST_INT: \ + if ((OUTER) == SET) \ + { \ + if ((unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ + return 0; \ + if (thumb_shiftable_const (INTVAL (X))) \ + return COSTS_N_INSNS (2); \ + return COSTS_N_INSNS (3); \ + } \ + else if (OUTER == PLUS \ + && INTVAL (X) < 256 && INTVAL (X) > -256) \ + return 0; \ + else if (OUTER == COMPARE \ + && (unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ + return 0; \ + else if (OUTER == ASHIFT || OUTER == ASHIFTRT \ + || OUTER == LSHIFTRT) \ + return 0; \ + return COSTS_N_INSNS (2); \ + case CONST: \ + case CONST_DOUBLE: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return COSTS_N_INSNS(3); + +#define ADDRESS_COST(X) \ + ((GET_CODE (X) == REG \ + || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \ + && GET_CODE (XEXP (X, 1)) == CONST_INT)) \ + ? 1 : 2) + + +/* Position Independent Code */ + +#define PRINT_OPERAND(STREAM,X,CODE) \ + thumb_print_operand((STREAM), (X), (CODE)) + +#define PRINT_OPERAND_ADDRESS(STREAM,X) \ +{ \ + if (GET_CODE ((X)) == REG) \ + fprintf ((STREAM), "[%s]", reg_names[REGNO ((X))]); \ + else if (GET_CODE ((X)) == POST_INC) \ + fprintf ((STREAM), "%s!", reg_names[REGNO (XEXP (X, 0))]); \ + else if (GET_CODE ((X)) == PLUS) \ + { \ + if (GET_CODE (XEXP ((X), 1)) == CONST_INT) \ + fprintf ((STREAM), "[%s, #%d]", \ + reg_names[REGNO (XEXP ((X), 0))], \ + (int) INTVAL (XEXP ((X), 1))); \ + else \ + fprintf ((STREAM), "[%s, %s]", \ + reg_names[REGNO (XEXP ((X), 0))], \ + reg_names[REGNO (XEXP ((X), 1))]); \ + } \ + else \ + output_addr_const ((STREAM), (X)); \ +} + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '@' || ((CODE) == '_')) + +/* Emit a special directive when defining a function name. + This is used by the assembler to assit with interworking. */ +#define ASM_DECLARE_FUNCTION_NAME(file, name, decl) \ + if (! is_called_in_ARM_mode (decl)) \ + fprintf (file, "\t.thumb_func\n") ; \ + else \ + fprintf (file, "\t.code\t32\n") ; \ + ASM_OUTPUT_LABEL (file, name) + +#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ + asm_fprintf ((STREAM), "\tpush {%R%s}\n", reg_names[(REGNO)]) + +#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \ + fprintf ((STREAM), "\tpop {%R%s}\n", reg_names[(REGNO)]) + +#define FINAL_PRESCAN_INSN(INSN,OPVEC,NOPERANDS) \ + final_prescan_insn((INSN)) + +/* Controlling Debugging Information Format */ +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* Specific options for DBX Output */ + +#define DBX_DEBUGGING_INFO 1 + +#define DEFAULT_GDB_EXTENSIONS 1 + + +/* Cross Compilation and Floating Point */ + +#define REAL_ARITHMETIC + + +/* Miscellaneous Parameters */ + +#define PREDICATE_CODES \ + {"s_register_operand", {SUBREG, REG}}, \ + {"thumb_cmp_operand", {SUBREG, REG, CONST_INT}}, + +#define CASE_VECTOR_MODE Pmode + +#define WORD_REGISTER_OPERATIONS + +#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND + +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +#define MOVE_MAX 4 + +#define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) 1 + +#define STORE_FLAG_VALUE 1 + +#define Pmode SImode + +#define FUNCTION_MODE SImode + +#define DOLLARS_IN_IDENTIFIERS 0 + +#define NO_DOLLAR_IN_LABEL 1 + +#define HAVE_ATEXIT + +/* The literal pool needs to reside in the text area due to the + limited PC addressing range: */ +#define MACHINE_DEPENDENT_REORG(INSN) thumb_reorg ((INSN)) + + +/* Options specific to Thumb */ + +/* True if a return instruction can be used in this function. */ +int thumb_trivial_epilogue (); +#define USE_RETURN (reload_completed && thumb_trivial_epilogue ()) + +extern char * thumb_unexpanded_epilogue (); +extern char * output_move_mem_multiple (); +extern char * thumb_load_double_from_address (); +extern char * output_return (); +extern int far_jump_used_p(); +extern int is_called_in_ARM_mode (); + +char *arm_strip_name_encoding (/* const char * */); +int arm_is_longcall_p (/* rtx, int, int */); +int s_register_operand (/* register rtx op, enum machine_mode mode */); diff --git a/gcc_arm/config/arm/thumb_020428.md b/gcc_arm/config/arm/thumb_020428.md new file mode 100755 index 0000000..dedf42e --- /dev/null +++ b/gcc_arm/config/arm/thumb_020428.md @@ -0,0 +1,1194 @@ +;; thumb.md Machine description for ARM/Thumb processors +;; Copyright (C) 1996, 1997, 1998, 2002 Free Software Foundation, Inc. +;; The basis of this contribution was generated by +;; Richard Earnshaw, Advanced RISC Machines Ltd + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;; LENGTH of an instruction is 2 bytes +(define_attr "length" "" (const_int 2)) + +;; CONDS is set to UNCHANGED when an insn does not affect the condition codes +;; Most insns change the condition codes +(define_attr "conds" "changed,unchanged" (const_string "changed")) + +;; FAR_JUMP is "yes" if a BL instruction is used to generate a branch to a +;; distant label. +(define_attr "far_jump" "yes,no" (const_string "no")) + +;; Start with move insns + +(define_expand "movsi" + [(set (match_operand:SI 0 "general_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (SImode, operands[1]); + } +") + +(define_insn "*movsi_insn" + [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l,m,*r,*h") + (match_operand:SI 1 "general_operand" "l,I,J,K,>,l,mi,l,*h,*r"))] + "register_operand (operands[0], SImode) + || register_operand (operands[1], SImode)" + "@ + add\\t%0, %1, #0 + mov\\t%0, %1 + # + # + ldmia\\t%1, {%0} + stmia\\t%0, {%1} + ldr\\t%0, %1 + str\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1" +[(set_attr "length" "2,2,4,4,2,2,2,2,2,2")]) + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "thumb_shiftable_const (INTVAL (operands[1]))" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))] + " +{ + unsigned HOST_WIDE_INT val = INTVAL (operands[1]); + unsigned HOST_WIDE_INT mask = 0xff; + int i; + for (i = 0; i < 25; i++) + if ((val & (mask << i)) == val) + break; + + if (i == 0) + FAIL; + + operands[1] = GEN_INT (val >> i); + operands[2] = GEN_INT (i); +}") + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "INTVAL (operands[1]) < 0 && INTVAL (operands[1]) > -256" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 0) (neg:SI (match_dup 0)))] + " + operands[1] = GEN_INT (- INTVAL (operands[1])); +") + +;;(define_expand "reload_outsi" +;; [(set (match_operand:SI 2 "register_operand" "=&l") +;; (match_operand:SI 1 "register_operand" "h")) +;; (set (match_operand:SI 0 "reload_memory_operand" "=o") +;; (match_dup 2))] +;; "" +;; " +;;/* thumb_reload_out_si (operands); +;; DONE; */ +;;") + +(define_expand "movhi" + [(set (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + " +{ + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (HImode, operands[1]); + + /* ??? We shouldn't really get invalid addresses here, but this can + happen if we are passed a SP (never OK for HImode/QImode) or virtual + register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) + relative address. */ + /* ??? This should perhaps be fixed elsewhere, for instance, in + fixup_stack_1, by checking for other kinds of invalid addresses, + e.g. a bare reference to a virtual register. This may confuse the + alpha though, which must handle this case differently. */ + if (GET_CODE (operands[0]) == MEM + && ! memory_address_p (GET_MODE (operands[0]), + XEXP (operands[0], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[0], 0)); + operands[0] = change_address (operands[0], VOIDmode, temp); + } + if (GET_CODE (operands[1]) == MEM + && ! memory_address_p (GET_MODE (operands[1]), + XEXP (operands[1], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[1], 0)); + operands[1] = change_address (operands[1], VOIDmode, temp); + } + } + /* Handle loading a large integer during reload */ + else if (GET_CODE (operands[1]) == CONST_INT + && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) + { + /* Writing a constant to memory needs a scratch, which should + be handled with SECONDARY_RELOADs. */ + if (GET_CODE (operands[0]) != REG) + abort (); + + operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); + emit_insn (gen_movsi (operands[0], operands[1])); + DONE; + } +}") + +(define_insn "*movhi_insn" + [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") + (match_operand:HI 1 "general_operand" "l,m,l,*h,*r,I"))] + "register_operand (operands[0], HImode) + || register_operand (operands[1], HImode)" + "@ + add\\t%0, %1, #0 + ldrh\\t%0, %1 + strh\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1 + mov\\t%0, %1") + +(define_expand "movqi" + [(set (match_operand:QI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" + " +{ + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (QImode, operands[1]); + + /* ??? We shouldn't really get invalid addresses here, but this can + happen if we are passed a SP (never OK for HImode/QImode) or virtual + register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) + relative address. */ + /* ??? This should perhaps be fixed elsewhere, for instance, in + fixup_stack_1, by checking for other kinds of invalid addresses, + e.g. a bare reference to a virtual register. This may confuse the + alpha though, which must handle this case differently. */ + if (GET_CODE (operands[0]) == MEM + && ! memory_address_p (GET_MODE (operands[0]), + XEXP (operands[0], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[0], 0)); + operands[0] = change_address (operands[0], VOIDmode, temp); + } + if (GET_CODE (operands[1]) == MEM + && ! memory_address_p (GET_MODE (operands[1]), + XEXP (operands[1], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[1], 0)); + operands[1] = change_address (operands[1], VOIDmode, temp); + } + } + /* Handle loading a large integer during reload */ + else if (GET_CODE (operands[1]) == CONST_INT + && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) + { + /* Writing a constant to memory needs a scratch, which should + be handled with SECONDARY_RELOADs. */ + if (GET_CODE (operands[0]) != REG) + abort (); + + operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); + emit_insn (gen_movsi (operands[0], operands[1])); + DONE; + } +}") + +(define_insn "*movqi_insn" + [(set (match_operand:QI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") + (match_operand:QI 1 "general_operand" "l,m,l,*h,*r,I"))] + "register_operand (operands[0], QImode) + || register_operand (operands[1], QImode)" + "@ + add\\t%0, %1, #0 + ldrb\\t%0, %1 + strb\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1 + mov\\t%0, %1") + +(define_expand "movdi" + [(set (match_operand:DI 0 "general_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (DImode, operands[1]); + } +") + +;;; ??? This should have alternatives for constants. +;;; ??? This was originally identical to the movdf_insn pattern. +;;; ??? The 'i' constraint looks funny, but it should always be replaced by +;;; thumb_reorg with a memory reference. +(define_insn "*movdi_insn" + [(set (match_operand:DI 0 "general_operand" "=l,l,l,l,>,l,m,*r") + (match_operand:DI 1 "general_operand" "l,I,J,>,l,mi,l,*r"))] + "register_operand (operands[0], DImode) + || register_operand (operands[1], DImode)" + "* +{ + switch (which_alternative) + { + case 0: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; + return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; + case 1: + return \"mov\\t%Q0, %1\;mov\\t%R0, #0\"; + case 2: + operands[1] = GEN_INT (- INTVAL (operands[1])); + return \"mov\\t%Q0, %1\;neg\\t%Q0, %Q0\;asr\\t%R0, %Q0, #31\"; + case 3: + return \"ldmia\\t%1, {%0, %H0}\"; + case 4: + return \"stmia\\t%0, {%1, %H1}\"; + case 5: + return thumb_load_double_from_address (operands); + case 6: + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); + output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); + return \"\"; + case 7: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; + return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; + } +}"[(set_attr "length" "4,4,6,2,2,6,4,4")]) + +(define_expand "movdf" + [(set (match_operand:DF 0 "general_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (DFmode, operands[1]); + } +") + +;;; ??? This should have alternatives for constants. +;;; ??? This was originally identical to the movdi_insn pattern. +;;; ??? The 'F' constraint looks funny, but it should always be replaced by +;;; thumb_reorg with a memory reference. +(define_insn "*movdf_insn" + [(set (match_operand:DF 0 "general_operand" "=l,l,>,l,m,*r") + (match_operand:DF 1 "general_operand" "l,>,l,mF,l,*r"))] + "register_operand (operands[0], DFmode) + || register_operand (operands[1], DFmode)" + "* + switch (which_alternative) + { + case 0: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; + return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; + case 1: + return \"ldmia\\t%1, {%0, %H0}\"; + case 2: + return \"stmia\\t%0, {%1, %H1}\"; + case 3: + return thumb_load_double_from_address (operands); + case 4: + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); + output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); + return \"\"; + case 5: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; + return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; + } +"[(set_attr "length" "4,2,2,6,4,4")]) + +(define_expand "movsf" + [(set (match_operand:SF 0 "general_operand" "") + (match_operand:SF 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (SFmode, operands[1]); + } +") + +;;; ??? This should have alternatives for constants. +(define_insn "*movsf_insn" + [(set (match_operand:SF 0 "nonimmediate_operand" "=l,l,>,l,m,*r,*h") + (match_operand:SF 1 "general_operand" "l,>,l,mF,l,*h,*r"))] + "register_operand (operands[0], SFmode) + || register_operand (operands[1], SFmode)" + "@ + add\\t%0, %1, #0 + ldmia\\t%1, {%0} + stmia\\t%0, {%1} + ldr\\t%0, %1 + str\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1") + +;; Widening move insns + +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "s_register_operand" "") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (HImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); + emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (16))); + DONE; + } +") + +(define_insn "*zero_extendhisi2_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + "" + "ldrh\\t%0, %1") + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "s_register_operand" "") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (QImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); + emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (24))); + DONE; + } +") + +(define_insn "*zero_extendqisi2_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + "" + "ldrb\\t%0, %1") + +(define_expand "extendhisi2" + [(parallel [(set (match_operand:SI 0 "s_register_operand" "") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" ""))) + (clobber (match_scratch:SI 2 ""))])] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (HImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); + emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (16))); + DONE; + } +") + +(define_insn "*extendhisi2_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))) + (clobber (match_scratch:SI 2 "=&l"))] + "" + "* +{ + rtx ops[4]; + /* This code used to try to use 'V', and fix the address only if it was + offsettable, but this fails for e.g. REG+48 because 48 is outside the + range of QImode offsets, and offsettable_address_p does a QImode + address check. */ + + if (GET_CODE (XEXP (operands[1], 0)) == PLUS) + { + ops[1] = XEXP (XEXP (operands[1], 0), 0); + ops[2] = XEXP (XEXP (operands[1], 0), 1); + } + else + { + ops[1] = XEXP (operands[1], 0); + ops[2] = const0_rtx; + } + if (GET_CODE (ops[2]) == REG) + return \"ldrsh\\t%0, %1\"; + + ops[0] = operands[0]; + ops[3] = operands[2]; + output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops); + return \"\"; +}" +[(set_attr "length" "4")]) + +(define_expand "extendqisi2" + [(set (match_operand:SI 0 "s_register_operand" "") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (QImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); + emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (24))); + DONE; + } +") + +(define_insn "*extendqisi2_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))] + "" + "* +{ + rtx ops[3]; + + if (which_alternative == 0) + return \"ldrsb\\t%0, %1\"; + ops[0] = operands[0]; + if (GET_CODE (XEXP (operands[1], 0)) == PLUS) + { + ops[1] = XEXP (XEXP (operands[1], 0), 0); + ops[2] = XEXP (XEXP (operands[1], 0), 1); + + if (GET_CODE (ops[1]) == REG && GET_CODE (ops[2]) == REG) + output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops); + else if (GET_CODE (ops[1]) == REG) + { + if (REGNO (ops[1]) == REGNO (operands[0])) + output_asm_insn (\"ldrb\\t%0, [%1, %2]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); + else + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + else + { + if (REGNO (ops[2]) == REGNO (operands[0])) + output_asm_insn (\"ldrb\\t%0, [%2, %1]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); + else + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + } + else if (REGNO (operands[0]) == REGNO (XEXP (operands[1], 0))) + { + output_asm_insn (\"ldrb\\t%0, [%0, #0]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); + } + else + { + ops[1] = XEXP (operands[1], 0); + ops[2] = const0_rtx; + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + return \"\"; +}" +[(set_attr "length" "2,6")]) + +;; We don't really have extzv, but defining this using shifts helps +;; to reduce register pressure later on. + +(define_expand "extzv" + [(set (match_dup 4) + (ashift:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "const_int_operand" ""))) + (set (match_operand:SI 0 "register_operand" "") + (lshiftrt:SI (match_dup 4) + (match_operand:SI 3 "const_int_operand" "")))] + "" + " +{ + HOST_WIDE_INT lshift = 32 - INTVAL (operands[2]) - INTVAL (operands[3]); + HOST_WIDE_INT rshift = 32 - INTVAL (operands[2]); + operands[3] = GEN_INT (rshift); + if (lshift == 0) + { + emit_insn (gen_lshrsi3 (operands[0], operands[1], operands[3])); + DONE; + } + operands[2] = GEN_INT (lshift); + operands[4] = gen_reg_rtx (SImode); +} +") + +;; Block-move insns + +(define_expand "movstrqi" + [(match_operand:BLK 0 "general_operand" "") + (match_operand:BLK 1 "general_operand" "") + (match_operand:SI 2 "" "") + (match_operand:SI 3 "const_int_operand" "")] + "" + " + if (INTVAL (operands[3]) != 4 + || GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) > 48) + FAIL; + + thumb_expand_movstrqi (operands); + DONE; +") + +(define_insn "movmem12b" + [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) + (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) + (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (mem:SI (plus:SI (match_dup 0) (const_int 8))) + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_dup 0) (plus:SI (match_dup 0) (const_int 12))) + (set (match_dup 1) (plus:SI (match_dup 1) (const_int 12))) + (clobber (match_scratch:SI 2 "=&l")) + (clobber (match_scratch:SI 3 "=&l")) + (clobber (match_scratch:SI 4 "=&l"))] + "" + "* return output_move_mem_multiple (3, operands);" +[(set_attr "length" "4")]) + +(define_insn "movmem8b" + [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) + (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) + (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_dup 0) (plus:SI (match_dup 0) (const_int 8))) + (set (match_dup 1) (plus:SI (match_dup 1) (const_int 8))) + (clobber (match_scratch:SI 2 "=&l")) + (clobber (match_scratch:SI 3 "=&l"))] + "" + "* return output_move_mem_multiple (2, operands);" +[(set_attr "length" "4")]) + +;; Arithmetic insns + +(define_insn "adddi3" + [(set (match_operand:DI 0 "s_register_operand" "=l") + (plus:DI (match_operand:DI 1 "s_register_operand" "%0") + (match_operand:DI 2 "s_register_operand" "l")))] + "" + "add\\t%Q0, %Q0, %Q2\;adc\\t%R0, %R0, %R2" +[(set_attr "conds" "changed") + (set_attr "length" "8")]) + +;; register group 'k' is a single register group containing only the stack +;; register. Trying to reload it will always fail catastrophically, +;; so never allow those alternatives to match if reloading is needed. +(define_insn "addsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l,l,l,*r,*h,l,!k") + (plus:SI (match_operand:SI 1 "s_register_operand" "%0,0,l,*0,*0,!k,!k") + (match_operand:SI 2 "nonmemory_operand" "I,J,lL,*h,*r,!M,!O")))] + "" + "* + static char *asms[] = +{ + \"add\\t%0, %0, %2\", + \"sub\\t%0, %0, #%n2\", + \"add\\t%0, %1, %2\", + \"add\\t%0, %0, %2\", + \"add\\t%0, %0, %2\", + \"add\\t%0, %1, %2\", + \"add\\t%0, %1, %2\" +}; + if (which_alternative == 2 && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) < 0) + return \"sub\\t%0, %1, #%n2\"; + return asms[which_alternative]; +") + +; reloading and elimination of the frame pointer can sometimes cause this +; optimization to be missed. +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=l") + (match_operand:SI 1 "const_int_operand" "M")) + (set (match_dup 0) + (plus:SI (match_dup 0) (match_operand:SI 2 "register_operand" "k")))] + "REGNO (operands[2]) == STACK_POINTER_REGNUM + && (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) < 1024 + && (INTVAL (operands[1]) & 3) == 0" + "add\\t%0, %2, %1") + +(define_insn "subdi3" + [(set (match_operand:DI 0 "s_register_operand" "=l") + (minus:DI (match_operand:DI 1 "s_register_operand" "0") + (match_operand:DI 2 "s_register_operand" "l")))] + "" + "sub\\t%Q0, %Q0, %Q2\;sbc\\t%R0, %R0, %R2" +[(set_attr "conds" "changed") + (set_attr "length" "8")]) + +(define_insn "subsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (minus:SI (match_operand:SI 1 "s_register_operand" "l") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "sub\\t%0, %1, %2") + +;; We must ensure that one input matches the output, and that the other input +;; does not match the output. Using 0 satisfies the first, and using & +;; satisfies the second. Unfortunately, this fails when operands 1 and 2 +;; are the same, because reload will make operand 0 match operand 1 without +;; realizing that this conflicts with operand 2. We fix this by adding another +;; alternative to match this case, and then `reload' it ourselves. This +;; alternative must come first. +(define_insn "mulsi3" + [(set (match_operand:SI 0 "s_register_operand" "=&l,&l,&l") + (mult:SI (match_operand:SI 1 "s_register_operand" "%l,*h,0") + (match_operand:SI 2 "s_register_operand" "l,l,l")))] + "" + "* +{ + if (which_alternative < 2) + return \"mov\\t%0, %1\;mul\\t%0, %0, %2\"; + else + return \"mul\\t%0, %0, %2\"; +}" + [(set_attr "length" "4,4,2")]) + +(define_insn "negsi2" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (neg:SI (match_operand:SI 1 "s_register_operand" "l")))] + "" + "neg\\t%0, %1") + +;; Logical insns + +(define_expand "andsi3" + [(set (match_operand:SI 0 "s_register_operand" "") + (and:SI (match_operand:SI 1 "s_register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] + "" + " + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = force_reg (SImode, operands[2]); + else + { + int i; + if (((unsigned HOST_WIDE_INT) ~ INTVAL (operands[2])) < 256) + { + operands[2] = force_reg (SImode, GEN_INT (~INTVAL (operands[2]))); + emit_insn (gen_bicsi3 (operands[0], operands[2], operands[1])); + DONE; + } + + for (i = 9; i <= 31; i++) + if ((((HOST_WIDE_INT) 1) << i) - 1 == INTVAL (operands[2])) + { + emit_insn (gen_extzv (operands[0], operands[1], GEN_INT (i), + const0_rtx)); + DONE; + } + else if ((((HOST_WIDE_INT) 1) << i) - 1 == ~ INTVAL (operands[2])) + { + rtx shift = GEN_INT (i); + rtx reg = gen_reg_rtx (SImode); + emit_insn (gen_lshrsi3 (reg, operands[1], shift)); + emit_insn (gen_ashlsi3 (operands[0], reg, shift)); + DONE; + } + + operands[2] = force_reg (SImode, operands[2]); + } +") + +(define_insn "*andsi3_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (and:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "and\\t%0, %0, %2") + +(define_insn "bicsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (and:SI (not:SI (match_operand:SI 1 "s_register_operand" "l")) + (match_operand:SI 2 "s_register_operand" "0")))] + "" + "bic\\t%0, %0, %1") + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (ior:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "orr\\t%0, %0, %2") + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (xor:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "eor\\t%0, %0, %2") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (not:SI (match_operand:SI 1 "s_register_operand" "l")))] + "" + "mvn\\t%0, %1") + +;; Shift and rotation insns + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (ashift:SI (match_operand:SI 1 "s_register_operand" "l,0") + (match_operand:SI 2 "nonmemory_operand" "N,l")))] + "" + "@ + lsl\\t%0, %1, %2 + lsl\\t%0, %0, %2") + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (ashiftrt:SI (match_operand:SI 1 "s_register_operand" "l,0") + (match_operand:SI 2 "nonmemory_operand" "N,l")))] + "" + "@ + asr\\t%0, %1, %2 + asr\\t%0, %0, %2") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (lshiftrt:SI (match_operand:SI 1 "s_register_operand" "l,0") + (match_operand:SI 2 "nonmemory_operand" "N,l")))] + "" + "@ + lsr\\t%0, %1, %2 + lsr\\t%0, %0, %2") + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (rotatert:SI (match_operand:SI 1 "s_register_operand" "0") + (match_operand:SI 2 "s_register_operand" "l")))] + "" + "ror\\t%0, %0, %2") + +;; Comparison insns + +(define_expand "cmpsi" + [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "") + (match_operand:SI 1 "nonmemory_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != REG && GET_CODE (operands[1]) != SUBREG) + { + if (GET_CODE (operands[1]) != CONST_INT + || (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) >= 256) + { + if (GET_CODE (operands[1]) != CONST_INT + || INTVAL (operands[1]) < -255 + || INTVAL (operands[1]) > 0) + operands[1] = force_reg (SImode, operands[1]); + else + { + operands[1] = force_reg (SImode, + GEN_INT (- INTVAL (operands[1]))); + emit_insn (gen_cmnsi (operands[0], operands[1])); + DONE; + } + } + } +") + +(define_insn "*cmpsi_insn" + [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "l,*r,*h") + (match_operand:SI 1 "thumb_cmp_operand" "lI,*h,*r")))] + "" + "@ + cmp\\t%0, %1 + cmp\\t%0, %1 + cmp\\t%0, %1") + +(define_insn "tstsi" + [(set (cc0) (match_operand:SI 0 "s_register_operand" "l"))] + "" + "cmp\\t%0, #0") + +(define_insn "cmnsi" + [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "l") + (neg:SI (match_operand:SI 1 "s_register_operand" "l"))))] + "" + "cmn\\t%0, %1") + +;; Jump insns + +(define_insn "jump" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "" + "* + if (get_attr_length (insn) == 2) + return \"b\\t%l0\"; + return \"bl\\t%l0\\t%@ far jump\"; +"[(set (attr "far_jump") + (if_then_else (eq_attr "length" "4") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2048)) + (le (minus (match_dup 0) (pc)) (const_int 2044))) + (const_int 2) + (const_int 4)))]) + + +(define_expand "beq" + [(set (pc) (if_then_else (eq (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bne" + [(set (pc) (if_then_else (ne (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bge" + [(set (pc) (if_then_else (ge (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "ble" + [(set (pc) (if_then_else (le (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bgt" + [(set (pc) (if_then_else (gt (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "blt" + [(set (pc) (if_then_else (lt (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bgeu" + [(set (pc) (if_then_else (geu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bleu" + [(set (pc) (if_then_else (leu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bgtu" + [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bltu" + [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_insn "*cond_branch" + [(set (pc) (if_then_else (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + switch (get_attr_length (insn)) + { + case 2: return \"b%d1\\t%l0\\t%@cond_branch\"; + case 4: return \"b%D1\\t.LCB%=\;b\\t%l0\\t%@long jump\\n.LCB%=:\"; + default: return \"b%D1\\t.LCB%=\;bl\\t%l0\\t%@far jump\\n.LCB%=:\"; + } +"[(set (attr "far_jump") + (if_then_else (eq_attr "length" "6") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 0) (pc)) (const_int -252)) + (le (minus (match_dup 0) (pc)) (const_int 254))) + (const_int 2) + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) + (le (minus (match_dup 0) (pc)) (const_int 2044))) + (const_int 4) + (const_int 6))))]) + +(define_insn "*cond_branch_reversed" + [(set (pc) (if_then_else (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + switch (get_attr_length (insn)) + { + case 2: return \"b%D1\\t%l0\\t%@cond_branch_reversed\"; + case 4: return \"b%d1\\t.LCBR%=\;b\\t%l0\\t%@long jump\\n.LCBR%=:\"; + default: return \"b%d1\\t.LCBR%=\;bl\\t%l0\\t%@far jump\\n.LCBR%=:\"; + } + return \"\"; +"[(set (attr "far_jump") + (if_then_else (eq_attr "length" "6") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 0) (pc)) (const_int -252)) + (le (minus (match_dup 0) (pc)) (const_int 254))) + (const_int 2) + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) + (le (minus (match_dup 0) (pc)) (const_int 2044))) + (const_int 4) + (const_int 6))))]) + +(define_insn "indirect_jump" + [(set (pc) (match_operand:SI 0 "s_register_operand" "l*r"))] + "" + "mov\\tpc, %0") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "s_register_operand" "l*r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "mov\\tpc, %0") + +(define_insn "return" + [(return)] + "USE_RETURN" + "* return output_return ();" +[(set_attr "length" "18")]) + +;; Call insns + +(define_expand "call" + [(parallel + [(call (match_operand:SI 0 "memory_operand" "") + (match_operand 1 "" "")) + (use (match_operand 2 "" ""))])] + "" + " +{ + if (GET_CODE (XEXP (operands[0], 0)) != REG + && arm_is_longcall_p (operands[0], INTVAL (operands[2]), 0)) + XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0)); +}") + +(define_insn "*call_indirect" + [(parallel + [(call (mem:SI (match_operand:SI 0 "s_register_operand" "l*r")) + (match_operand 1 "" "")) + (use (match_operand 2 "" ""))])] + "! TARGET_CALLER_INTERWORKING" + "bl\\t%__call_via_%0" +[(set_attr "length" "4")]) +;; The non THUMB_INTERWORK, non TARGET_CALLER_INTERWORKING version +;; used to be: "mov\\tlr,pc\;bx\\t%0", but the mov does not set +;; the bottom bit of lr so that a function return (using bx) +;; would switch back into ARM mode... + +(define_insn "*call_indirect_interwork" + [(parallel + [(call (mem:SI (match_operand:SI 0 "s_register_operand" "l*r")) + (match_operand 1 "" "")) + (use (match_operand 2 "" ""))])] + "TARGET_CALLER_INTERWORKING" + "bl\\t%__interwork_call_via_%0" +[(set_attr "length" "4")]) + +(define_expand "call_value" + [(parallel + [(set (match_operand 0 "" "") + (call (match_operand 1 "memory_operand" "") + (match_operand 2 "" ""))) + (use (match_operand 3 "" ""))])] + "" + " +{ + if (GET_CODE (XEXP (operands[1], 0)) != REG + && arm_is_longcall_p (operands[1], INTVAL (operands[3]), 0)) + XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0)); +}") + +(define_insn "*call_value_indirect" + [(parallel + [(set (match_operand 0 "" "=l") + (call (mem:SI (match_operand:SI 1 "s_register_operand" "l*r")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" ""))])] + "! TARGET_CALLER_INTERWORKING" + "bl\\t%__call_via_%1" +[(set_attr "length" "4")]) +;; See comment for call_indirect pattern + +(define_insn "*call_value_indirect_interwork" + [(parallel + [(set (match_operand 0 "" "=l") + (call (mem:SI (match_operand:SI 1 "s_register_operand" "l*r")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" ""))])] + "TARGET_CALLER_INTERWORKING" + "bl\\t%__interwork_call_via_%1" +[(set_attr "length" "4")]) + + +(define_insn "*call_insn" + [(parallel + [(call (mem:SI (match_operand:SI 0 "" "i")) + (match_operand:SI 1 "" "")) + (use (match_operand 2 "" ""))])] + "GET_CODE (operands[0]) == SYMBOL_REF + && ! arm_is_longcall_p (operands[0], INTVAL (operands[2]), 1)" + "bl\\t%a0" +[(set_attr "length" "4")]) + +(define_insn "*call_value_insn" + [(parallel + [(set (match_operand 0 "s_register_operand" "=l") + (call (mem:SI (match_operand 1 "" "i")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" ""))])] + "GET_CODE(operands[1]) == SYMBOL_REF + && ! arm_is_longcall_p (operands[1], INTVAL (operands[3]), 1)" + "bl\\t%a1" +[(set_attr "length" "4")]) + +;; Untyped call not required, since all funcs return in r0 + +;; Miscellaneous patterns + +(define_insn "nop" + [(clobber (const_int 0))] + "" + "mov\\tr8, r8") + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] 0)] + "" + "" + [(set_attr "length" "0")]) + +(define_expand "prologue" + [(const_int 0)] + "" + " + thumb_expand_prologue (); + DONE; +") + +(define_expand "epilogue" + [(unspec_volatile [(const_int 0)] 1)] + "! thumb_trivial_epilogue ()" + " + thumb_expand_epilogue (); +") + +(define_insn "*epilogue_insns" + [(unspec_volatile [(const_int 0)] 1)] + "" + "* + return thumb_unexpanded_epilogue (); +" +[(set_attr "length" "42")]) + +;; Special patterns for dealing with the constant pool + +(define_insn "consttable_4" + [(unspec_volatile [(match_operand 0 "" "")] 2)] + "" + "* +{ + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) + { + case MODE_FLOAT: + { + union real_extract u; + bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); + assemble_real (u.d, GET_MODE (operands[0])); + break; + } + default: + assemble_integer (operands[0], 4, 1); + break; + } + return \"\"; +}" +[(set_attr "length" "4")]) + +(define_insn "consttable_8" + [(unspec_volatile [(match_operand 0 "" "")] 3)] + "" + "* +{ + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) + { + case MODE_FLOAT: + { + union real_extract u; + bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); + assemble_real (u.d, GET_MODE (operands[0])); + break; + } + default: + assemble_integer (operands[0], 8, 1); + break; + } + return \"\"; +}" +[(set_attr "length" "8")]) + +(define_insn "consttable_end" + [(unspec_volatile [(const_int 0)] 4)] + "" + "* + /* Nothing to do (currently). */ + return \"\"; +") + +(define_insn "align_4" + [(unspec_volatile [(const_int 0)] 5)] + "" + "* + assemble_align (32); + return \"\"; +") diff --git a/gcc_arm/config/arm/thumb_981111.md b/gcc_arm/config/arm/thumb_981111.md new file mode 100755 index 0000000..93d0c05 --- /dev/null +++ b/gcc_arm/config/arm/thumb_981111.md @@ -0,0 +1,1166 @@ +;; thumb.md Machine description for ARM/Thumb processors +;; Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. +;; The basis of this contribution was generated by +;; Richard Earnshaw, Advanced RISC Machines Ltd + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;; LENGTH of an instruction is 2 bytes +(define_attr "length" "" (const_int 2)) + +;; CONDS is set to UNCHANGED when an insn does not affect the condition codes +;; Most insns change the condition codes +(define_attr "conds" "changed,unchanged" (const_string "changed")) + +;; FAR_JUMP is "yes" if a BL instruction is used to generate a branch to a +;; distant label. +(define_attr "far_jump" "yes,no" (const_string "no")) + +;; Start with move insns + +(define_expand "movsi" + [(set (match_operand:SI 0 "general_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (SImode, operands[1]); + } +") + +(define_insn "*movsi_insn" + [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l,m,*r,*h") + (match_operand:SI 1 "general_operand" "l,I,J,K,>,l,mi,l,*h,*r"))] + "register_operand (operands[0], SImode) + || register_operand (operands[1], SImode)" + "@ + add\\t%0, %1, #0 + mov\\t%0, %1 + # + # + ldmia\\t%1, {%0} + stmia\\t%0, {%1} + ldr\\t%0, %1 + str\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1" +[(set_attr "length" "2,2,4,4,2,2,2,2,2,2")]) + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "thumb_shiftable_const (INTVAL (operands[1]))" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))] + " +{ + unsigned HOST_WIDE_INT val = INTVAL (operands[1]); + unsigned HOST_WIDE_INT mask = 0xff; + int i; + for (i = 0; i < 25; i++) + if ((val & (mask << i)) == val) + break; + + if (i == 0) + FAIL; + + operands[1] = GEN_INT (val >> i); + operands[2] = GEN_INT (i); +}") + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "INTVAL (operands[1]) < 0 && INTVAL (operands[1]) > -256" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 0) (neg:SI (match_dup 0)))] + " + operands[1] = GEN_INT (- INTVAL (operands[1])); +") + +;;(define_expand "reload_outsi" +;; [(set (match_operand:SI 2 "register_operand" "=&l") +;; (match_operand:SI 1 "register_operand" "h")) +;; (set (match_operand:SI 0 "reload_memory_operand" "=o") +;; (match_dup 2))] +;; "" +;; " +;;/* thumb_reload_out_si (operands); +;; DONE; */ +;;") + +(define_expand "movhi" + [(set (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + " +{ + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (HImode, operands[1]); + + /* ??? We shouldn't really get invalid addresses here, but this can + happen if we are passed a SP (never OK for HImode/QImode) or virtual + register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) + relative address. */ + /* ??? This should perhaps be fixed elsewhere, for instance, in + fixup_stack_1, by checking for other kinds of invalid addresses, + e.g. a bare reference to a virtual register. This may confuse the + alpha though, which must handle this case differently. */ + if (GET_CODE (operands[0]) == MEM + && ! memory_address_p (GET_MODE (operands[0]), + XEXP (operands[0], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[0], 0)); + operands[0] = change_address (operands[0], VOIDmode, temp); + } + if (GET_CODE (operands[1]) == MEM + && ! memory_address_p (GET_MODE (operands[1]), + XEXP (operands[1], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[1], 0)); + operands[1] = change_address (operands[1], VOIDmode, temp); + } + } + /* Handle loading a large integer during reload */ + else if (GET_CODE (operands[1]) == CONST_INT + && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) + { + /* Writing a constant to memory needs a scratch, which should + be handled with SECONDARY_RELOADs. */ + if (GET_CODE (operands[0]) != REG) + abort (); + + operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); + emit_insn (gen_movsi (operands[0], operands[1])); + DONE; + } +}") + +(define_insn "*movhi_insn" + [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") + (match_operand:HI 1 "general_operand" "l,m,l,*h,*r,I"))] + "register_operand (operands[0], HImode) + || register_operand (operands[1], HImode)" + "@ + add\\t%0, %1, #0 + ldrh\\t%0, %1 + strh\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1 + mov\\t%0, %1") + +(define_expand "movqi" + [(set (match_operand:QI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" + " +{ + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (QImode, operands[1]); + + /* ??? We shouldn't really get invalid addresses here, but this can + happen if we are passed a SP (never OK for HImode/QImode) or virtual + register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) + relative address. */ + /* ??? This should perhaps be fixed elsewhere, for instance, in + fixup_stack_1, by checking for other kinds of invalid addresses, + e.g. a bare reference to a virtual register. This may confuse the + alpha though, which must handle this case differently. */ + if (GET_CODE (operands[0]) == MEM + && ! memory_address_p (GET_MODE (operands[0]), + XEXP (operands[0], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[0], 0)); + operands[0] = change_address (operands[0], VOIDmode, temp); + } + if (GET_CODE (operands[1]) == MEM + && ! memory_address_p (GET_MODE (operands[1]), + XEXP (operands[1], 0))) + { + rtx temp = copy_to_reg (XEXP (operands[1], 0)); + operands[1] = change_address (operands[1], VOIDmode, temp); + } + } + /* Handle loading a large integer during reload */ + else if (GET_CODE (operands[1]) == CONST_INT + && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) + { + /* Writing a constant to memory needs a scratch, which should + be handled with SECONDARY_RELOADs. */ + if (GET_CODE (operands[0]) != REG) + abort (); + + operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); + emit_insn (gen_movsi (operands[0], operands[1])); + DONE; + } +}") + +(define_insn "*movqi_insn" + [(set (match_operand:QI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") + (match_operand:QI 1 "general_operand" "l,m,l,*h,*r,I"))] + "register_operand (operands[0], QImode) + || register_operand (operands[1], QImode)" + "@ + add\\t%0, %1, #0 + ldrb\\t%0, %1 + strb\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1 + mov\\t%0, %1") + +(define_expand "movdi" + [(set (match_operand:DI 0 "general_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (DImode, operands[1]); + } +") + +;;; ??? This should have alternatives for constants. +;;; ??? This was originally identical to the movdf_insn pattern. +;;; ??? The 'i' constraint looks funny, but it should always be replaced by +;;; thumb_reorg with a memory reference. +(define_insn "*movdi_insn" + [(set (match_operand:DI 0 "general_operand" "=l,l,l,l,>,l,m,*r") + (match_operand:DI 1 "general_operand" "l,I,J,>,l,mi,l,*r"))] + "register_operand (operands[0], DImode) + || register_operand (operands[1], DImode)" + "* +{ + switch (which_alternative) + { + case 0: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; + return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; + case 1: + return \"mov\\t%Q0, %1\;mov\\t%R0, #0\"; + case 2: + operands[1] = GEN_INT (- INTVAL (operands[1])); + return \"mov\\t%Q0, %1\;neg\\t%Q0, %Q0\;asr\\t%R0, %Q0, #31\"; + case 3: + return \"ldmia\\t%1, {%0, %H0}\"; + case 4: + return \"stmia\\t%0, {%1, %H1}\"; + case 5: + return thumb_load_double_from_address (operands); + case 6: + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); + output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); + return \"\"; + case 7: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; + return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; + } +}"[(set_attr "length" "4,4,6,2,2,6,4,4")]) + +(define_expand "movdf" + [(set (match_operand:DF 0 "general_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (DFmode, operands[1]); + } +") + +;;; ??? This should have alternatives for constants. +;;; ??? This was originally identical to the movdi_insn pattern. +;;; ??? The 'F' constraint looks funny, but it should always be replaced by +;;; thumb_reorg with a memory reference. +(define_insn "*movdf_insn" + [(set (match_operand:DF 0 "general_operand" "=l,l,>,l,m,*r") + (match_operand:DF 1 "general_operand" "l,>,l,mF,l,*r"))] + "register_operand (operands[0], DFmode) + || register_operand (operands[1], DFmode)" + "* + switch (which_alternative) + { + case 0: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; + return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; + case 1: + return \"ldmia\\t%1, {%0, %H0}\"; + case 2: + return \"stmia\\t%0, {%1, %H1}\"; + case 3: + return thumb_load_double_from_address (operands); + case 4: + operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); + output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); + return \"\"; + case 5: + if (REGNO (operands[1]) == REGNO (operands[0]) + 1) + return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; + return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; + } +"[(set_attr "length" "4,2,2,6,4,4")]) + +(define_expand "movsf" + [(set (match_operand:SF 0 "general_operand" "") + (match_operand:SF 1 "general_operand" ""))] + "" + " + if (! (reload_in_progress || reload_completed)) + { + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (SFmode, operands[1]); + } +") + +;;; ??? This should have alternatives for constants. +(define_insn "*movsf_insn" + [(set (match_operand:SF 0 "nonimmediate_operand" "=l,l,>,l,m,*r,*h") + (match_operand:SF 1 "general_operand" "l,>,l,mF,l,*h,*r"))] + "register_operand (operands[0], SFmode) + || register_operand (operands[1], SFmode)" + "@ + add\\t%0, %1, #0 + ldmia\\t%1, {%0} + stmia\\t%0, {%1} + ldr\\t%0, %1 + str\\t%1, %0 + mov\\t%0, %1 + mov\\t%0, %1") + +;; Widening move insns + +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (HImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); + emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (16))); + DONE; + } +") + +(define_insn "*zero_extendhisi2_insn" + [(set (match_operand:SI 0 "register_operand" "=l") + (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + "" + "ldrh\\t%0, %1") + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (QImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); + emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (24))); + DONE; + } +") + +(define_insn "*zero_extendqisi2_insn" + [(set (match_operand:SI 0 "register_operand" "=l") + (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + "" + "ldrb\\t%0, %1") + +(define_expand "extendhisi2" + [(parallel [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" ""))) + (clobber (match_scratch:SI 2 ""))])] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (HImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); + emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (16))); + DONE; + } +") + +(define_insn "*extendhisi2_insn" + [(set (match_operand:SI 0 "register_operand" "=l") + (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))) + (clobber (match_scratch:SI 2 "=&l"))] + "" + "* +{ + rtx ops[4]; + /* This code used to try to use 'V', and fix the address only if it was + offsettable, but this fails for e.g. REG+48 because 48 is outside the + range of QImode offsets, and offsettable_address_p does a QImode + address check. */ + + if (GET_CODE (XEXP (operands[1], 0)) == PLUS) + { + ops[1] = XEXP (XEXP (operands[1], 0), 0); + ops[2] = XEXP (XEXP (operands[1], 0), 1); + } + else + { + ops[1] = XEXP (operands[1], 0); + ops[2] = const0_rtx; + } + if (GET_CODE (ops[2]) == REG) + return \"ldrsh\\t%0, %1\"; + + ops[0] = operands[0]; + ops[3] = operands[2]; + output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops); + return \"\"; +}" +[(set_attr "length" "4")]) + +(define_expand "extendqisi2" + [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != MEM) + { + rtx temp = gen_reg_rtx (SImode); + + operands[1] = force_reg (QImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); + emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (24))); + DONE; + } +") + +(define_insn "*extendqisi2_insn" + [(set (match_operand:SI 0 "register_operand" "=l,l") + (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))] + "" + "* +{ + rtx ops[3]; + + if (which_alternative == 0) + return \"ldrsb\\t%0, %1\"; + ops[0] = operands[0]; + if (GET_CODE (XEXP (operands[1], 0)) == PLUS) + { + ops[1] = XEXP (XEXP (operands[1], 0), 0); + ops[2] = XEXP (XEXP (operands[1], 0), 1); + + if (GET_CODE (ops[1]) == REG && GET_CODE (ops[2]) == REG) + output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops); + else if (GET_CODE (ops[1]) == REG) + { + if (REGNO (ops[1]) == REGNO (operands[0])) + output_asm_insn (\"ldrb\\t%0, [%1, %2]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); + else + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + else + { + if (REGNO (ops[2]) == REGNO (operands[0])) + output_asm_insn (\"ldrb\\t%0, [%2, %1]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); + else + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + } + else if (REGNO (operands[0]) == REGNO (XEXP (operands[1], 0))) + { + output_asm_insn (\"ldrb\\t%0, [%0, #0]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); + } + else + { + ops[1] = XEXP (operands[1], 0); + ops[2] = const0_rtx; + output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); + } + return \"\"; +}" +[(set_attr "length" "2,6")]) + +;; We don't really have extzv, but defining this using shifts helps +;; to reduce register pressure later on. + +(define_expand "extzv" + [(set (match_dup 4) + (ashift:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "const_int_operand" ""))) + (set (match_operand:SI 0 "register_operand" "") + (lshiftrt:SI (match_dup 4) + (match_operand:SI 3 "const_int_operand" "")))] + "" + " +{ + HOST_WIDE_INT lshift = 32 - INTVAL (operands[2]) - INTVAL (operands[3]); + HOST_WIDE_INT rshift = 32 - INTVAL (operands[2]); + operands[3] = GEN_INT (rshift); + if (lshift == 0) + { + emit_insn (gen_lshrsi3 (operands[0], operands[1], operands[3])); + DONE; + } + operands[2] = GEN_INT (lshift); + operands[4] = gen_reg_rtx (SImode); +} +") + +;; Block-move insns + +(define_expand "movstrqi" + [(match_operand:BLK 0 "general_operand" "") + (match_operand:BLK 1 "general_operand" "") + (match_operand:SI 2 "" "") + (match_operand:SI 3 "const_int_operand" "")] + "" + " + if (INTVAL (operands[3]) != 4 + || GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) > 48) + FAIL; + + thumb_expand_movstrqi (operands); + DONE; +") + +(define_insn "movmem12b" + [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) + (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) + (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (mem:SI (plus:SI (match_dup 0) (const_int 8))) + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_dup 0) (plus:SI (match_dup 0) (const_int 12))) + (set (match_dup 1) (plus:SI (match_dup 1) (const_int 12))) + (clobber (match_scratch:SI 2 "=&l")) + (clobber (match_scratch:SI 3 "=&l")) + (clobber (match_scratch:SI 4 "=&l"))] + "" + "* return output_move_mem_multiple (3, operands);" +[(set_attr "length" "4")]) + +(define_insn "movmem8b" + [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) + (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) + (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_dup 0) (plus:SI (match_dup 0) (const_int 8))) + (set (match_dup 1) (plus:SI (match_dup 1) (const_int 8))) + (clobber (match_scratch:SI 2 "=&l")) + (clobber (match_scratch:SI 3 "=&l"))] + "" + "* return output_move_mem_multiple (2, operands);" +[(set_attr "length" "4")]) + +;; Arithmetic insns + +(define_insn "adddi3" + [(set (match_operand:DI 0 "register_operand" "=l") + (plus:DI (match_operand:DI 1 "register_operand" "%0") + (match_operand:DI 2 "register_operand" "l")))] + "" + "add\\t%Q0, %Q0, %Q2\;adc\\t%R0, %R0, %R2" +[(set_attr "conds" "changed") + (set_attr "length" "8")]) + +;; register group 'k' is a single register group containing only the stack +;; register. Trying to reload it will always fail catastrophically, +;; so never allow those alternatives to match if reloading is needed. +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=l,l,l,*r,*h,l,!k") + (plus:SI (match_operand:SI 1 "register_operand" "%0,0,l,*0,*0,!k,!k") + (match_operand:SI 2 "nonmemory_operand" "I,J,lL,*h,*r,!M,!O")))] + "" + "* + static char *asms[] = +{ + \"add\\t%0, %0, %2\", + \"sub\\t%0, %0, #%n2\", + \"add\\t%0, %1, %2\", + \"add\\t%0, %0, %2\", + \"add\\t%0, %0, %2\", + \"add\\t%0, %1, %2\", + \"add\\t%0, %1, %2\" +}; + if (which_alternative == 2 && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) < 0) + return \"sub\\t%0, %1, #%n2\"; + return asms[which_alternative]; +") + +; reloading and elimination of the frame pointer can sometimes cause this +; optimization to be missed. +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=l") + (match_operand:SI 1 "const_int_operand" "M")) + (set (match_dup 0) + (plus:SI (match_dup 0) (match_operand:SI 2 "register_operand" "k")))] + "REGNO (operands[2]) == STACK_POINTER_REGNUM + && (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) < 1024 + && (INTVAL (operands[1]) & 3) == 0" + "add\\t%0, %2, %1") + +(define_insn "subdi3" + [(set (match_operand:DI 0 "register_operand" "=l") + (minus:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "register_operand" "l")))] + "" + "sub\\t%Q0, %Q0, %Q2\;sbc\\t%R0, %R0, %R2" +[(set_attr "conds" "changed") + (set_attr "length" "8")]) + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=l") + (minus:SI (match_operand:SI 1 "register_operand" "l") + (match_operand:SI 2 "register_operand" "l")))] + "" + "sub\\t%0, %1, %2") + +;; We must ensure that one input matches the output, and that the other input +;; does not match the output. Using 0 satisfies the first, and using & +;; satisfies the second. Unfortunately, this fails when operands 1 and 2 +;; are the same, because reload will make operand 0 match operand 1 without +;; realizing that this conflicts with operand 2. We fix this by adding another +;; alternative to match this case, and then `reload' it ourselves. This +;; alternative must come first. +(define_insn "mulsi3" + [(set (match_operand:SI 0 "register_operand" "=&l,&l,&l") + (mult:SI (match_operand:SI 1 "register_operand" "%l,*h,0") + (match_operand:SI 2 "register_operand" "l,l,l")))] + "" + "* +{ + if (which_alternative < 2) + return \"mov\\t%0, %1\;mul\\t%0, %0, %2\"; + else + return \"mul\\t%0, %0, %2\"; +}" + [(set_attr "length" "4,4,2")]) + +(define_insn "negsi2" + [(set (match_operand:SI 0 "register_operand" "=l") + (neg:SI (match_operand:SI 1 "register_operand" "l")))] + "" + "neg\\t%0, %1") + +;; Logical insns + +(define_expand "andsi3" + [(set (match_operand:SI 0 "register_operand" "") + (and:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] + "" + " + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = force_reg (SImode, operands[2]); + else + { + int i; + if (((unsigned HOST_WIDE_INT) ~ INTVAL (operands[2])) < 256) + { + operands[2] = force_reg (SImode, GEN_INT (~INTVAL (operands[2]))); + emit_insn (gen_bicsi3 (operands[0], operands[2], operands[1])); + DONE; + } + + for (i = 9; i <= 31; i++) + if ((((HOST_WIDE_INT) 1) << i) - 1 == INTVAL (operands[2])) + { + emit_insn (gen_extzv (operands[0], operands[1], GEN_INT (i), + const0_rtx)); + DONE; + } + else if ((((HOST_WIDE_INT) 1) << i) - 1 == ~ INTVAL (operands[2])) + { + rtx shift = GEN_INT (i); + rtx reg = gen_reg_rtx (SImode); + emit_insn (gen_lshrsi3 (reg, operands[1], shift)); + emit_insn (gen_ashlsi3 (operands[0], reg, shift)); + DONE; + } + + operands[2] = force_reg (SImode, operands[2]); + } +") + +(define_insn "*andsi3_insn" + [(set (match_operand:SI 0 "register_operand" "=l") + (and:SI (match_operand:SI 1 "register_operand" "%0") + (match_operand:SI 2 "register_operand" "l")))] + "" + "and\\t%0, %0, %2") + +(define_insn "bicsi3" + [(set (match_operand:SI 0 "register_operand" "=l") + (and:SI (not:SI (match_operand:SI 1 "register_operand" "l")) + (match_operand:SI 2 "register_operand" "0")))] + "" + "bic\\t%0, %0, %1") + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=l") + (ior:SI (match_operand:SI 1 "register_operand" "%0") + (match_operand:SI 2 "register_operand" "l")))] + "" + "orr\\t%0, %0, %2") + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=l") + (xor:SI (match_operand:SI 1 "register_operand" "%0") + (match_operand:SI 2 "register_operand" "l")))] + "" + "eor\\t%0, %0, %2") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "=l") + (not:SI (match_operand:SI 1 "register_operand" "l")))] + "" + "mvn\\t%0, %1") + +;; Shift and rotation insns + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "=l,l") + (ashift:SI (match_operand:SI 1 "register_operand" "l,0") + (match_operand:SI 2 "nonmemory_operand" "N,l")))] + "" + "@ + lsl\\t%0, %1, %2 + lsl\\t%0, %0, %2") + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "=l,l") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "l,0") + (match_operand:SI 2 "nonmemory_operand" "N,l")))] + "" + "@ + asr\\t%0, %1, %2 + asr\\t%0, %0, %2") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=l,l") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "l,0") + (match_operand:SI 2 "nonmemory_operand" "N,l")))] + "" + "@ + lsr\\t%0, %1, %2 + lsr\\t%0, %0, %2") + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "register_operand" "=l") + (rotatert:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "register_operand" "l")))] + "" + "ror\\t%0, %0, %2") + +;; Comparison insns + +(define_expand "cmpsi" + [(set (cc0) (compare (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "nonmemory_operand" "")))] + "" + " + if (GET_CODE (operands[1]) != REG && GET_CODE (operands[1]) != SUBREG) + { + if (GET_CODE (operands[1]) != CONST_INT + || (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) >= 256) + { + if (GET_CODE (operands[1]) != CONST_INT + || INTVAL (operands[1]) < -255 + || INTVAL (operands[1]) > 0) + operands[1] = force_reg (SImode, operands[1]); + else + { + operands[1] = force_reg (SImode, + GEN_INT (- INTVAL (operands[1]))); + emit_insn (gen_cmnsi (operands[0], operands[1])); + DONE; + } + } + } +") + +(define_insn "*cmpsi_insn" + [(set (cc0) (compare (match_operand:SI 0 "register_operand" "l,*r,*h") + (match_operand:SI 1 "thumb_cmp_operand" "lI,*h,*r")))] + "" + "@ + cmp\\t%0, %1 + cmp\\t%0, %1 + cmp\\t%0, %1") + +(define_insn "tstsi" + [(set (cc0) (match_operand:SI 0 "register_operand" "l"))] + "" + "cmp\\t%0, #0") + +(define_insn "cmnsi" + [(set (cc0) (compare (match_operand:SI 0 "register_operand" "l") + (neg:SI (match_operand:SI 1 "register_operand" "l"))))] + "" + "cmn\\t%0, %1") + +;; Jump insns + +(define_insn "jump" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "" + "* + if (get_attr_length (insn) == 2) + return \"b\\t%l0\"; + return \"bl\\t%l0\\t%@ far jump\"; +"[(set (attr "far_jump") + (if_then_else (eq_attr "length" "4") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2048)) + (le (minus (match_dup 0) (pc)) (const_int 2044))) + (const_int 2) + (const_int 4)))]) + + +(define_expand "beq" + [(set (pc) (if_then_else (eq (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bne" + [(set (pc) (if_then_else (ne (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bge" + [(set (pc) (if_then_else (ge (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "ble" + [(set (pc) (if_then_else (le (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bgt" + [(set (pc) (if_then_else (gt (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "blt" + [(set (pc) (if_then_else (lt (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bgeu" + [(set (pc) (if_then_else (geu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bleu" + [(set (pc) (if_then_else (leu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bgtu" + [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "bltu" + [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_insn "*cond_branch" + [(set (pc) (if_then_else (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + switch (get_attr_length (insn)) + { + case 2: return \"b%d1\\t%l0\\t%@cond_branch\"; + case 4: return \"b%D1\\t.LCB%=\;b\\t%l0\\t%@long jump\\n.LCB%=:\"; + default: return \"b%D1\\t.LCB%=\;bl\\t%l0\\t%@far jump\\n.LCB%=:\"; + } +"[(set (attr "far_jump") + (if_then_else (eq_attr "length" "6") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 0) (pc)) (const_int -252)) + (le (minus (match_dup 0) (pc)) (const_int 254))) + (const_int 2) + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) + (le (minus (match_dup 0) (pc)) (const_int 2044))) + (const_int 4) + (const_int 6))))]) + +(define_insn "*cond_branch_reversed" + [(set (pc) (if_then_else (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + switch (get_attr_length (insn)) + { + case 2: return \"b%D1\\t%l0\\t%@cond_branch_reversed\"; + case 4: return \"b%d1\\t.LCBR%=\;b\\t%l0\\t%@long jump\\n.LCBR%=:\"; + default: return \"b%d1\\t.LCBR%=\;bl\\t%l0\\t%@far jump\\n.LCBR%=:\"; + } + return \"\"; +"[(set (attr "far_jump") + (if_then_else (eq_attr "length" "6") + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (and (ge (minus (match_dup 0) (pc)) (const_int -252)) + (le (minus (match_dup 0) (pc)) (const_int 254))) + (const_int 2) + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) + (le (minus (match_dup 0) (pc)) (const_int 2044))) + (const_int 4) + (const_int 6))))]) + +(define_insn "indirect_jump" + [(set (pc) (match_operand:SI 0 "register_operand" "l*r"))] + "" + "mov\\tpc, %0") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "register_operand" "l*r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "mov\\tpc, %0") + +(define_insn "return" + [(return)] + "USE_RETURN" + "* return output_return ();" +[(set_attr "length" "18")]) + +;; Call insns + +(define_expand "call" + [(call (match_operand:SI 0 "memory_operand" "") + (match_operand 1 "" ""))] + "" + "") + +(define_insn "*call_indirect" + [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) + (match_operand 1 "" ""))] + "! TARGET_CALLER_INTERWORKING" + "bl\\t%__call_via_%0" +[(set_attr "length" "4")]) +;; The non THUMB_INTERWORK, non TARGET_CALLER_INTERWORKING version +;; used to be: "mov\\tlr,pc\;bx\\t%0", but the mov does not set +;; the bottom bit of lr so that a function return (using bx) +;; would switch back into ARM mode... + +(define_insn "*call_indirect_interwork" + [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) + (match_operand 1 "" ""))] + "TARGET_CALLER_INTERWORKING" + "bl\\t%__interwork_call_via_%0" +[(set_attr "length" "4")]) + +(define_expand "call_value" + [(set (match_operand 0 "" "") + (call (match_operand 1 "memory_operand" "") + (match_operand 2 "" "")))] + "" + "") + +(define_insn "*call_value_indirect" + [(set (match_operand 0 "" "=l") + (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) + (match_operand 2 "" "")))] + "! TARGET_CALLER_INTERWORKING" + "bl\\t%__call_via_%1" +[(set_attr "length" "4")]) +;; See comment for call_indirect pattern + +(define_insn "*call_value_indirect_interwork" + [(set (match_operand 0 "" "=l") + (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) + (match_operand 2 "" "")))] + "TARGET_CALLER_INTERWORKING" + "bl\\t%__interwork_call_via_%1" +[(set_attr "length" "4")]) + + +(define_insn "*call_insn" + [(call (mem:SI (match_operand:SI 0 "" "i")) + (match_operand:SI 1 "" ""))] + "GET_CODE (operands[0]) == SYMBOL_REF" + "bl\\t%a0" +[(set_attr "length" "4")]) + +(define_insn "*call_value_insn" + [(set (match_operand 0 "register_operand" "=l") + (call (mem:SI (match_operand 1 "" "i")) + (match_operand 2 "" "")))] + "GET_CODE (operands[1]) == SYMBOL_REF" + "bl\\t%a1" +[(set_attr "length" "4")]) + +;; Untyped call not required, since all funcs return in r0 + +;; Miscellaneous patterns + +(define_insn "nop" + [(clobber (const_int 0))] + "" + "mov\\tr8, r8") + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] 0)] + "" + "" + [(set_attr "length" "0")]) + +(define_expand "prologue" + [(const_int 0)] + "" + " + thumb_expand_prologue (); + DONE; +") + +(define_expand "epilogue" + [(unspec_volatile [(const_int 0)] 1)] + "! thumb_trivial_epilogue ()" + " + thumb_expand_epilogue (); +") + +(define_insn "*epilogue_insns" + [(unspec_volatile [(const_int 0)] 1)] + "" + "* + return thumb_unexpanded_epilogue (); +" +[(set_attr "length" "42")]) + +;; Special patterns for dealing with the constant pool + +(define_insn "consttable_4" + [(unspec_volatile [(match_operand 0 "" "")] 2)] + "" + "* +{ + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) + { + case MODE_FLOAT: + { + union real_extract u; + bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); + assemble_real (u.d, GET_MODE (operands[0])); + break; + } + default: + assemble_integer (operands[0], 4, 1); + break; + } + return \"\"; +}" +[(set_attr "length" "4")]) + +(define_insn "consttable_8" + [(unspec_volatile [(match_operand 0 "" "")] 3)] + "" + "* +{ + switch (GET_MODE_CLASS (GET_MODE (operands[0]))) + { + case MODE_FLOAT: + { + union real_extract u; + bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); + assemble_real (u.d, GET_MODE (operands[0])); + break; + } + default: + assemble_integer (operands[0], 8, 1); + break; + } + return \"\"; +}" +[(set_attr "length" "8")]) + +(define_insn "consttable_end" + [(unspec_volatile [(const_int 0)] 4)] + "" + "* + /* Nothing to do (currently). */ + return \"\"; +") + +(define_insn "align_4" + [(unspec_volatile [(const_int 0)] 5)] + "" + "* + assemble_align (32); + return \"\"; +") diff --git a/gcc_arm/config/arm/tpe.h b/gcc_arm/config/arm/tpe.h new file mode 100755 index 0000000..8f4f35f --- /dev/null +++ b/gcc_arm/config/arm/tpe.h @@ -0,0 +1,427 @@ +/* CYGNUS LOCAL (entire file) nickc/thumb-pe */ +/* Definitions of target machine for GNU compiler, + for Thumb with PE object format. + Copyright (C) 1998 Free Software Foundation, Inc. + Derived from arm/coff.h and arm/pe.h originally by Doug Evans (evans@cygnus.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "arm/thumb.h" + +#define THUMB_PE 1 + +/* Run-time Target Specification. */ +#undef TARGET_VERSION +#define TARGET_VERSION fputs (" (Thumb/pe)", stderr) + +/* Support the __declspec keyword by turning them into attributes. + We currently only support: naked, dllimport, and dllexport. + Note that the current way we do this may result in a collision with + predefined attributes later on. This can be solved by using one attribute, + say __declspec__, and passing args to it. The problem with that approach + is that args are not accumulated: each new appearance would clobber any + existing args. */ +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "\ +-Dthumb -D__thumb -D__pe__ -Acpu(arm) -Amachine(arm) \ +-D__declspec(x)=__attribute__((x)) \ +" + +/* Experimental addition for pr 7885. + Ignore dllimport for functions. */ +#define ARM_FLAG_NOP_FUN_IMPORT 0x20000 +#define TARGET_NOP_FUN_DLLIMPORT (target_flags & ARM_FLAG_NOP_FUN_IMPORT) + +#undef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES \ +{ "nop-fun-dllimport", ARM_FLAG_NOP_FUN_IMPORT }, \ +{ "no-nop-fun-dllimport", -ARM_FLAG_NOP_FUN_IMPORT }, + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT ARM_FLAG_NOP_FUN_IMPORT + +#undef WCHAR_TYPE +#define WCHAR_TYPE "short unsigned int" +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 16 + +/* Setting this to 32 produces more efficient code, but the value set in previous + versions of this toolchain was 8, which produces more compact structures. The + command line option -mstructure_size_boundary= can be used to change this + value. */ +#undef STRUCTURE_SIZE_BOUNDARY +#define STRUCTURE_SIZE_BOUNDARY arm_structure_size_boundary + +extern int arm_structure_size_boundary; + +/* This is COFF, but prefer stabs. */ +#define SDB_DEBUGGING_INFO + +#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG + +#include "dbxcoff.h" + +/* Note - it is important that these definitions match those in semi.h for the ARM port. */ +#undef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "." + +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "_" + +/* A C statement to output assembler commands which will identify the + object file as having been compiled with GNU CC (or another GNU + compiler). */ +#define ASM_IDENTIFY_GCC(STREAM) \ + fprintf (STREAM, "%sgcc2_compiled.:\n%s", LOCAL_LABEL_PREFIX, ASM_APP_OFF ) + +#undef ASM_FILE_START +#define ASM_FILE_START(STREAM) \ +do { \ + extern char *version_string; \ + fprintf ((STREAM), "%s Generated by gcc %s for Thumb/coff\n", \ + ASM_COMMENT_START, version_string); \ + fprintf ((STREAM), ASM_APP_OFF); \ +} while (0) + +/* A C statement to output something to the assembler file to switch to section + NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or + NULL_TREE. Some target formats do not support arbitrary sections. Do not + define this macro in such cases. */ +#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ +do { \ + if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ + fprintf (STREAM, "\t.section %s,\"x\"\n", (NAME)); \ + else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ + fprintf (STREAM, "\t.section %s,\"\"\n", (NAME)); \ + else \ + fprintf (STREAM, "\t.section %s,\"w\"\n", (NAME)); \ +} while (0) + +/* Support the ctors/dtors and other sections. */ + +#undef INIT_SECTION_ASM_OP + +/* Define this macro if jump tables (for `tablejump' insns) should be + output in the text section, along with the assembler instructions. + Otherwise, the readonly data section is used. */ +#define JUMP_TABLES_IN_TEXT_SECTION 1 + +#undef READONLY_DATA_SECTION +#define READONLY_DATA_SECTION rdata_section +#undef RDATA_SECTION_ASM_OP +#define RDATA_SECTION_ASM_OP "\t.section .rdata" + +#undef CTORS_SECTION_ASM_OP +#define CTORS_SECTION_ASM_OP "\t.section .ctors,\"x\"" +#undef DTORS_SECTION_ASM_OP +#define DTORS_SECTION_ASM_OP "\t.section .dtors,\"x\"" + +/* A list of other sections which the compiler might be "in" at any + given time. */ + +#undef EXTRA_SECTIONS +#define EXTRA_SECTIONS SUBTARGET_EXTRA_SECTIONS in_rdata, in_ctors, in_dtors + +#define SUBTARGET_EXTRA_SECTIONS + +/* A list of extra section function definitions. */ + +#undef EXTRA_SECTION_FUNCTIONS +#define EXTRA_SECTION_FUNCTIONS \ + RDATA_SECTION_FUNCTION \ + CTORS_SECTION_FUNCTION \ + DTORS_SECTION_FUNCTION \ + SUBTARGET_EXTRA_SECTION_FUNCTIONS + +#define SUBTARGET_EXTRA_SECTION_FUNCTIONS + +#define RDATA_SECTION_FUNCTION \ +void \ +rdata_section () \ +{ \ + if (in_section != in_rdata) \ + { \ + fprintf (asm_out_file, "%s\n", RDATA_SECTION_ASM_OP); \ + in_section = in_rdata; \ + } \ +} + +#define CTORS_SECTION_FUNCTION \ +void \ +ctors_section () \ +{ \ + if (in_section != in_ctors) \ + { \ + fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \ + in_section = in_ctors; \ + } \ +} + +#define DTORS_SECTION_FUNCTION \ +void \ +dtors_section () \ +{ \ + if (in_section != in_dtors) \ + { \ + fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \ + in_section = in_dtors; \ + } \ +} + +/* Support the ctors/dtors sections for g++. */ + +#define INT_ASM_OP ".word" + +/* A C statement (sans semicolon) to output an element in the table of + global constructors. */ +#undef ASM_OUTPUT_CONSTRUCTOR +#define ASM_OUTPUT_CONSTRUCTOR(STREAM,NAME) \ +do { \ + ctors_section (); \ + fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} while (0) + +/* A C statement (sans semicolon) to output an element in the table of + global destructors. */ +#undef ASM_OUTPUT_DESTRUCTOR +#define ASM_OUTPUT_DESTRUCTOR(STREAM,NAME) \ +do { \ + dtors_section (); \ + fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} while (0) + +/* __CTOR_LIST__ and __DTOR_LIST__ must be defined by the linker script. */ +#define CTOR_LISTS_DEFINED_EXTERNALLY + +#undef DO_GLOBAL_CTORS_BODY +#undef DO_GLOBAL_DTORS_BODY + +/* The ARM development system has atexit and doesn't have _exit, + so define this for now. */ +#define HAVE_ATEXIT + +/* The ARM development system defines __main. */ +#define NAME__MAIN "__gccmain" +#define SYMBOL__MAIN __gccmain + +/* This is to better conform to the ARM PCS. + Richard Earnshaw hasn't put this into FSF sources yet so it's here. */ +#undef RETURN_IN_MEMORY +#define RETURN_IN_MEMORY(TYPE) \ + ((TYPE_MODE ((TYPE)) == BLKmode && ! TYPE_NO_FORCE_BLK (TYPE)) \ + || (AGGREGATE_TYPE_P ((TYPE)) && arm_pe_return_in_memory ((TYPE)))) + +/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS + is a valid machine specific attribute for DECL. + The attributes in ATTRIBUTES have previously been assigned to DECL. */ +extern int arm_pe_valid_machine_decl_attribute (); +extern int arm_valid_machine_decl_attribute (); +#undef VALID_MACHINE_DECL_ATTRIBUTE +#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \ + arm_pe_valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS) + +extern union tree_node * arm_pe_merge_machine_decl_attributes (); +#define MERGE_MACHINE_DECL_ATTRIBUTES(OLD, NEW) \ + arm_pe_merge_machine_decl_attributes ((OLD), (NEW)) + +/* In addition to the stuff done in arm.h, we must mark dll symbols specially. + Definitions of dllexport'd objects install some info in the .drectve + section. References to dllimport'd objects are fetched indirectly via + __imp_. If both are declared, dllexport overrides. + This is also needed to implement one-only vtables: they go into their own + section and we need to set DECL_SECTION_NAME so we do that here. + Note that we can be called twice on the same decl. */ +extern void arm_pe_encode_section_info (); +#undef ENCODE_SECTION_INFO +#define ENCODE_SECTION_INFO(DECL) \ + arm_pe_encode_section_info (DECL) + +#define REDO_SECTION_INFO_P(DECL) 1 + + /* Utility used only in this file. */ +#define ARM_STRIP_NAME_ENCODING(SYM_NAME) \ +((SYM_NAME) + ((SYM_NAME)[0] == '@' ? 3 : 0)) + +/* Strip any text from SYM_NAME added by ENCODE_SECTION_INFO and store + the result in VAR. */ +#undef STRIP_NAME_ENCODING +#define STRIP_NAME_ENCODING(VAR, SYM_NAME) \ +(VAR) = ARM_STRIP_NAME_ENCODING (SYM_NAME) + +/* Define this macro if in some cases global symbols from one translation + unit may not be bound to undefined symbols in another translation unit + without user intervention. For instance, under Microsoft Windows + symbols must be explicitly imported from shared libraries (DLLs). */ +#define MULTIPLE_SYMBOL_SPACES + +#define UNIQUE_SECTION_P(DECL) DECL_ONE_ONLY (DECL) +extern void arm_pe_unique_section (); +#define UNIQUE_SECTION(DECL,RELOC) arm_pe_unique_section (DECL, RELOC) + +#define SUPPORTS_ONE_ONLY 1 + +/* A C statement to output something to the assembler file to switch to section + NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or + NULL_TREE. Some target formats do not support arbitrary sections. Do not + define this macro in such cases. */ +#undef ASM_OUTPUT_SECTION_NAME +#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ +do { \ + if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ + fprintf (STREAM, "\t.section %s,\"x\"\n", (NAME)); \ + else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ + fprintf (STREAM, "\t.section %s,\"\"\n", (NAME)); \ + else \ + fprintf (STREAM, "\t.section %s,\"w\"\n", (NAME)); \ + /* Functions may have been compiled at various levels of \ + optimization so we can't use `same_size' here. Instead, \ + have the linker pick one. */ \ + if ((DECL) && DECL_ONE_ONLY (DECL)) \ + fprintf (STREAM, "\t.linkonce %s\n", \ + TREE_CODE (DECL) == FUNCTION_DECL \ + ? "discard" : "same_size"); \ +} while (0) + +/* This outputs a lot of .req's to define alias for various registers. + Let's try to avoid this. */ +#undef ASM_FILE_START +#define ASM_FILE_START(STREAM) \ +do { \ + extern char *version_string; \ + fprintf (STREAM, "%s Generated by gcc %s for ARM/pe\n", \ + ASM_COMMENT_START, version_string); \ + output_file_directive ((STREAM), main_input_filename); \ +} while (0) + +/* Output a reference to a label. */ +#undef ASM_OUTPUT_LABELREF +#define ASM_OUTPUT_LABELREF(STREAM, NAME) \ +fprintf (STREAM, "%s%s", USER_LABEL_PREFIX, ARM_STRIP_NAME_ENCODING (NAME)) + +/* Output a function definition label. */ +#undef ASM_DECLARE_FUNCTION_NAME +#define ASM_DECLARE_FUNCTION_NAME(STREAM, NAME, DECL) \ +do { \ + if (arm_dllexport_name_p (NAME)) \ + { \ + drectve_section (); \ + fprintf (STREAM, "\t.ascii \" -export:%s\"\n", \ + ARM_STRIP_NAME_ENCODING (NAME)); \ + function_section (DECL); \ + } \ + if (! is_called_in_ARM_mode (decl)) \ + fprintf (STREAM, "\t.thumb_func\n") ; \ + else \ + fprintf (STREAM, "\t.code\t32\n") ; \ + ASM_OUTPUT_LABEL ((STREAM), (NAME)); \ +} while (0) + +/* Output a common block. */ +#undef ASM_OUTPUT_COMMON +#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ +do { \ + if (arm_dllexport_name_p (NAME)) \ + { \ + drectve_section (); \ + fprintf ((STREAM), "\t.ascii \" -export:%s\"\n", \ + ARM_STRIP_NAME_ENCODING (NAME)); \ + } \ + if (! arm_dllimport_name_p (NAME)) \ + { \ + fprintf ((STREAM), "\t.comm\t"); \ + assemble_name ((STREAM), (NAME)); \ + fprintf ((STREAM), ", %d\t%s %d\n", \ + (ROUNDED), ASM_COMMENT_START, (SIZE)); \ + } \ +} while (0) + +/* Output the label for an initialized variable. */ +#undef ASM_DECLARE_OBJECT_NAME +#define ASM_DECLARE_OBJECT_NAME(STREAM, NAME, DECL) \ +do { \ + if (arm_dllexport_name_p (NAME)) \ + { \ + enum in_section save_section = in_section; \ + drectve_section (); \ + fprintf (STREAM, "\t.ascii \" -export:%s\"\n", \ + ARM_STRIP_NAME_ENCODING (NAME)); \ + switch_to_section (save_section, (DECL)); \ + } \ + ASM_OUTPUT_LABEL ((STREAM), (NAME)); \ +} while (0) + +/* Support the ctors/dtors and other sections. */ + +#define DRECTVE_SECTION_ASM_OP "\t.section .drectve" + +/* A list of other sections which the compiler might be "in" at any + given time. */ + +#undef SUBTARGET_EXTRA_SECTIONS +#define SUBTARGET_EXTRA_SECTIONS in_drectve, + +/* A list of extra section function definitions. */ + +#undef SUBTARGET_EXTRA_SECTION_FUNCTIONS +#define SUBTARGET_EXTRA_SECTION_FUNCTIONS \ + DRECTVE_SECTION_FUNCTION \ + SWITCH_TO_SECTION_FUNCTION + +#define DRECTVE_SECTION_FUNCTION \ +void \ +drectve_section () \ +{ \ + if (in_section != in_drectve) \ + { \ + fprintf (asm_out_file, "%s\n", DRECTVE_SECTION_ASM_OP); \ + in_section = in_drectve; \ + } \ +} + +/* Switch to SECTION (an `enum in_section'). + + ??? This facility should be provided by GCC proper. + The problem is that we want to temporarily switch sections in + ASM_DECLARE_OBJECT_NAME and then switch back to the original section + afterwards. */ +#define SWITCH_TO_SECTION_FUNCTION \ +void \ +switch_to_section (section, decl) \ + enum in_section section; \ + tree decl; \ +{ \ + switch (section) \ + { \ + case in_text: text_section (); break; \ + case in_data: data_section (); break; \ + case in_named: named_section (decl, NULL, 0); break; \ + case in_rdata: rdata_section (); break; \ + case in_ctors: ctors_section (); break; \ + case in_dtors: dtors_section (); break; \ + case in_drectve: drectve_section (); break; \ + default: abort (); break; \ + } \ +} + + + +extern int thumb_pe_valid_machine_decl_attribute (); diff --git a/gcc_arm/config/arm/unknown-elf-oabi.h b/gcc_arm/config/arm/unknown-elf-oabi.h new file mode 100755 index 0000000..22aacf6 --- /dev/null +++ b/gcc_arm/config/arm/unknown-elf-oabi.h @@ -0,0 +1,36 @@ +/* Definitions for non-Linux based ARM systems using ELF old abi + Copyright (C) 1998, 1999 Free Software Foundation, Inc. + Contributed by Catherine Moore + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Run-time Target Specification. */ +#ifndef TARGET_VERSION +#define TARGET_VERSION fputs (" (ARM/ELF non-Linux old abi)", stderr); +#endif + +#define CPP_PREDEFINES "-Darm_oabi -Darm -Darm_elf -Acpu(arm) -Amachine(arm) -D__ELF__" + +#ifndef ASM_SPEC +#define ASM_SPEC "-moabi %{mbig-endian:-EB} %{mcpu=*:-m%*} %{march=*:-m%*} \ + %{mapcs-*:-mapcs-%*} %{mthumb-interwork:-mthumb-interwork}" +#endif + +/* Now get the routine arm-elf definitions. */ +#include "arm/unknown-elf.h" +#include "arm/elf.h" diff --git a/gcc_arm/config/arm/unknown-elf.h b/gcc_arm/config/arm/unknown-elf.h new file mode 100755 index 0000000..53f9522 --- /dev/null +++ b/gcc_arm/config/arm/unknown-elf.h @@ -0,0 +1,166 @@ +/* Definitions for non-Linux based ARM systems using ELF + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Catherine Moore + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Run-time Target Specification. */ +#ifndef TARGET_VERSION +#define TARGET_VERSION fputs (" (ARM/ELF non-Linux)", stderr); +#endif + +/* If you don't define HAVE_ATEXIT, and the object file format/OS/whatever + does not support constructors/destructors, then gcc implements destructors + by defining its own exit function, which calls the destructors. This gcc + exit function overrides the C library's exit function, and this can cause + all kinds of havoc if the C library has a non-trivial exit function. You + really don't want to use the exit function in libgcc2.c. */ +#define HAVE_ATEXIT + +/* Default to using APCS-32 and software floating point. */ +#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32) + +/* Now we define the strings used to build the spec file. */ +#define STARTFILE_SPEC "crtbegin%O%s crt0%O%s" + +#define ENDFILE_SPEC "crtend%O%s" + +#define USER_LABEL_PREFIX "" +#define LOCAL_LABEL_PREFIX "." + +#define TEXT_SECTION " .text" + +#define INVOKE__main + +/* Debugging */ +#define DWARF_DEBUGGING_INFO +#define DWARF2_DEBUGGING_INFO +#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG + +/* Support for Constructors and Destrcutors . */ +#define READONLY_DATA_SECTION rdata_section + +/* A list of other sections which the compiler might be "in" at any + given time. */ +#define SUBTARGET_EXTRA_SECTIONS in_rdata, + +/* A list of extra section function definitions. */ +#define SUBTARGET_EXTRA_SECTION_FUNCTIONS RDATA_SECTION_FUNCTION + +#define RDATA_SECTION_ASM_OP "\t.section .rodata" + +#define RDATA_SECTION_FUNCTION \ +void \ +rdata_section () \ +{ \ + if (in_section != in_rdata) \ + { \ + fprintf (asm_out_file, "%s\n", RDATA_SECTION_ASM_OP); \ + in_section = in_rdata; \ + } \ +} + +#define CTOR_LIST_BEGIN \ +asm (CTORS_SECTION_ASM_OP); \ +func_ptr __CTOR_LIST__[1] = { (func_ptr) (-1) } + +#define CTOR_LIST_END \ +asm (CTORS_SECTION_ASM_OP); \ +func_ptr __CTOR_END__[1] = { (func_ptr) 0 }; + +#define DTOR_LIST_BEGIN \ +asm (DTORS_SECTION_ASM_OP); \ +func_ptr __DTOR_LIST__[1] = { (func_ptr) (-1) } + +#define DTOR_LIST_END \ +asm (DTORS_SECTION_ASM_OP); \ +func_ptr __DTOR_END__[1] = { (func_ptr) 0 }; + +/* A C statement to output something to the assembler file to switch to section + NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or + NULL_TREE. Some target formats do not support arbitrary sections. Do not + define this macro in such cases. */ +#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ +do { \ + if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ + fprintf (STREAM, "\t.section %s,\"ax\",%%progbits\n", (NAME)); \ + else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ + fprintf (STREAM, "\t.section %s,\"a\"\n", (NAME)); \ + else if (0 == strncmp((NAME), ".bss", sizeof(".bss") - 1)) \ + fprintf (STREAM, "\t.section %s,\"aw\",%%nobits\n", (NAME)); \ + else \ + fprintf (STREAM, "\t.section %s,\"aw\"\n", (NAME)); \ +} while (0) + +/* Don't know how to order these. UNALIGNED_WORD_ASM_OP is in + dwarf2.out. */ +#define UNALIGNED_WORD_ASM_OP ".4byte" + +#define ASM_OUTPUT_DWARF2_ADDR_CONST(FILE,ADDR) \ + fprintf ((FILE), "\t%s\t%s", UNALIGNED_WORD_ASM_OP, ADDR) + +#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,RTX) \ +do { \ + fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \ + output_addr_const ((FILE), (RTX)); \ + fputc ('\n', (FILE)); \ +} while (0) + + +/* The ARM development system defines __main. */ +#define NAME__MAIN "__gccmain" +#define SYMBOL__MAIN __gccmain + +#define MAKE_DECL_ONE_ONLY(DECL) (DECL_WEAK (DECL) = 1) +#define UNIQUE_SECTION_P(DECL) (DECL_ONE_ONLY (DECL)) +#define UNIQUE_SECTION(DECL,RELOC) \ +do { \ + int len; \ + char * name, * string, * prefix; \ + \ + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (DECL)); \ + \ + if (! DECL_ONE_ONLY (DECL)) \ + { \ + prefix = "."; \ + if (TREE_CODE (DECL) == FUNCTION_DECL) \ + prefix = ".text."; \ + else if (DECL_READONLY_SECTION (DECL, RELOC)) \ + prefix = ".rodata."; \ + else \ + prefix = ".data."; \ + } \ + else if (TREE_CODE (DECL) == FUNCTION_DECL) \ + prefix = ".gnu.linkonce.t."; \ + else if (DECL_READONLY_SECTION (DECL, RELOC)) \ + prefix = ".gnu.linkonce.r."; \ + else \ + prefix = ".gnu.linkonce.d."; \ + \ + len = strlen (name) + strlen (prefix); \ + string = alloca (len + 1); \ + sprintf (string, "%s%s", prefix, name); \ + \ + DECL_SECTION_NAME (DECL) = build_string (len, string); \ +} while (0) + +#define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__" +#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm7tdmi + +/* Now get the routine arm-elf definitions. */ +#include "arm/elf.h" diff --git a/gcc_arm/config/arm/unknown-elf_020422.h b/gcc_arm/config/arm/unknown-elf_020422.h new file mode 100755 index 0000000..3f6090c --- /dev/null +++ b/gcc_arm/config/arm/unknown-elf_020422.h @@ -0,0 +1,163 @@ +/* Definitions for non-Linux based ARM systems using ELF + Copyright (C) 1998, 2001 Free Software Foundation, Inc. + Contributed by Catherine Moore + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Run-time Target Specification. */ +#ifndef TARGET_VERSION +#define TARGET_VERSION fputs (" (ARM/ELF non-Linux)", stderr); +#endif + +/* If you don't define HAVE_ATEXIT, and the object file format/OS/whatever + does not support constructors/destructors, then gcc implements destructors + by defining its own exit function, which calls the destructors. This gcc + exit function overrides the C library's exit function, and this can cause + all kinds of havoc if the C library has a non-trivial exit function. You + really don't want to use the exit function in libgcc2.c. */ +#define HAVE_ATEXIT + +/* Default to using APCS-32 and software floating point. */ +#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32) + +/* Now we define the strings used to build the spec file. */ +#define STARTFILE_SPEC "crtbegin%O%s crt0%O%s" + +#define ENDFILE_SPEC "crtend%O%s" + +#define USER_LABEL_PREFIX "" +#define LOCAL_LABEL_PREFIX "." + +#define TEXT_SECTION " .text" + +#define INVOKE__main + +/* Debugging */ +#define DWARF_DEBUGGING_INFO +#define DWARF2_DEBUGGING_INFO +#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG + +/* Support for Constructors and Destrcutors . */ +#define READONLY_DATA_SECTION rdata_section + +/* A list of other sections which the compiler might be "in" at any + given time. */ +#define SUBTARGET_EXTRA_SECTIONS in_rdata, + +/* A list of extra section function definitions. */ +#define SUBTARGET_EXTRA_SECTION_FUNCTIONS RDATA_SECTION_FUNCTION + +#define RDATA_SECTION_ASM_OP "\t.section .rodata" + +#define RDATA_SECTION_FUNCTION \ +void \ +rdata_section () \ +{ \ + if (in_section != in_rdata) \ + { \ + fprintf (asm_out_file, "%s\n", RDATA_SECTION_ASM_OP); \ + in_section = in_rdata; \ + } \ +} + +#define CTOR_LIST_BEGIN \ +asm (CTORS_SECTION_ASM_OP); \ +func_ptr __CTOR_LIST__[1] = { (func_ptr) (-1) } + +#define CTOR_LIST_END \ +asm (CTORS_SECTION_ASM_OP); \ +func_ptr __CTOR_END__[1] = { (func_ptr) 0 }; + +#define DTOR_LIST_BEGIN \ +asm (DTORS_SECTION_ASM_OP); \ +func_ptr __DTOR_LIST__[1] = { (func_ptr) (-1) } + +#define DTOR_LIST_END \ +asm (DTORS_SECTION_ASM_OP); \ +func_ptr __DTOR_END__[1] = { (func_ptr) 0 }; + +/* A C statement to output something to the assembler file to switch to section + NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or + NULL_TREE. Some target formats do not support arbitrary sections. Do not + define this macro in such cases. */ +#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ +do { \ + if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ + fprintf (STREAM, "\t.section %s,\"ax\",%%progbits\n", (NAME)); \ + else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ + fprintf (STREAM, "\t.section %s,\"a\"\n", (NAME)); \ + else if (0 == strncmp((NAME), ".bss", sizeof(".bss") - 1)) \ + fprintf (STREAM, "\t.section %s,\"aw\",%%nobits\n", (NAME)); \ + else \ + fprintf (STREAM, "\t.section %s,\"aw\"\n", (NAME)); \ +} while (0) + +/* Don't know how to order these. UNALIGNED_WORD_ASM_OP is in + dwarf2.out. */ +#define UNALIGNED_WORD_ASM_OP ".4byte" + +#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,RTX) \ +do { \ + fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \ + output_addr_const ((FILE), (RTX)); \ + fputc ('\n', (FILE)); \ +} while (0) + + +/* The ARM development system defines __main. */ +#define NAME__MAIN "__gccmain" +#define SYMBOL__MAIN __gccmain + +#define MAKE_DECL_ONE_ONLY(DECL) (DECL_WEAK (DECL) = 1) +#define UNIQUE_SECTION_P(DECL) (DECL_ONE_ONLY (DECL)) +#define UNIQUE_SECTION(DECL,RELOC) \ +do { \ + int len; \ + char * name, * string, * prefix; \ + \ + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (DECL)); \ + \ + if (! DECL_ONE_ONLY (DECL)) \ + { \ + prefix = "."; \ + if (TREE_CODE (DECL) == FUNCTION_DECL) \ + prefix = ".text."; \ + else if (DECL_READONLY_SECTION (DECL, RELOC)) \ + prefix = ".rodata."; \ + else \ + prefix = ".data."; \ + } \ + else if (TREE_CODE (DECL) == FUNCTION_DECL) \ + prefix = ".gnu.linkonce.t."; \ + else if (DECL_READONLY_SECTION (DECL, RELOC)) \ + prefix = ".gnu.linkonce.r."; \ + else \ + prefix = ".gnu.linkonce.d."; \ + \ + len = strlen (name) + strlen (prefix); \ + string = alloca (len + 1); \ + sprintf (string, "%s%s", prefix, name); \ + \ + DECL_SECTION_NAME (DECL) = build_string (len, string); \ +} while (0) + +#define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__" +#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm7tdmi + +/* Now get the routine arm-elf definitions. */ +#include "arm/elf.h" diff --git a/gcc_arm/config/arm/x-riscix b/gcc_arm/config/arm/x-riscix new file mode 100755 index 0000000..4584f95 --- /dev/null +++ b/gcc_arm/config/arm/x-riscix @@ -0,0 +1,8 @@ +# Define new names for the getopt library, so that we don't have to statically +# link [un]protoize. We have dirent.h not sys/dir.h, so define POSIX. +X_CFLAGS= -DPOSIX -Dopterr=gcc_opterr -Doptind=gcc_optind \ + -Dgetopt=gcc_getopt -Doptarg=gcc_optarg +# Compile in BSD mode. +OLDCC=/usr/ucb/cc +CC=$(OLDCC) +FIXPROTO_DEFINES= -D_POSIX_SOURCE -D_XOPEN_C -D_BSD_C -D_XOPEN_SOURCE diff --git a/gcc_arm/config/arm/xm-arm.h b/gcc_arm/config/arm/xm-arm.h new file mode 100755 index 0000000..a6143fa --- /dev/null +++ b/gcc_arm/config/arm/xm-arm.h @@ -0,0 +1,68 @@ +/* Configuration for GNU C-compiler for Acorn RISC Machine. + Copyright (C) 1991, 1993 Free Software Foundation, Inc. + Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl) + and Martin Simmons (@harleqn.co.uk). + More major hacks by Richard Earnshaw (rwe11@cl.cam.ac.uk) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* This describes the machine the compiler is hosted on. */ +#define HOST_BITS_PER_CHAR 8 +#define HOST_BITS_PER_SHORT 16 +#define HOST_BITS_PER_INT 32 +#define HOST_BITS_PER_LONG 32 + +/* A code distinguishing the floating point format of the host + machine. There are three defined values: IEEE_FLOAT_FORMAT, + VAX_FLOAT_FORMAT, and UNKNOWN_FLOAT_FORMAT. */ + +#define HOST_FLOAT_FORMAT IEEE_FLOAT_FORMAT + +#define HOST_FLOAT_WORDS_BIG_ENDIAN 1 + +/* If not compiled with GNU C, use C alloca. */ +#ifndef __GNUC__ +#define USE_C_ALLOCA +#endif + +/* Define this to be 1 if you know the host compiler supports prototypes, even + if it doesn't define __STDC__, or define it to be 0 if you do not want any + prototypes when compiling GNU CC. */ +#define USE_PROTOTYPES 1 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.h" + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* If we have defined POSIX, but are compiling in the BSD environment, then + we need to define getcwd in terms of getwd. */ +#if defined (POSIX) && defined (_BSD_C) +#define HAVE_GETWD 1 +#endif + +/* EOF xm-arm.h */ + + diff --git a/gcc_arm/config/arm/xm-linux.h b/gcc_arm/config/arm/xm-linux.h new file mode 100755 index 0000000..ca120a9 --- /dev/null +++ b/gcc_arm/config/arm/xm-linux.h @@ -0,0 +1,24 @@ +/* Configuration for GCC for Intel i386 running Linux-based GNU systems./ + Copyright (C) 1993, 1994, 1995, 1997 Free Software Foundation, Inc. + Contributed by H.J. Lu (hjl@nynexst.com) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include +#include + diff --git a/gcc_arm/config/arm/xm-netbsd.h b/gcc_arm/config/arm/xm-netbsd.h new file mode 100755 index 0000000..ea9a64e --- /dev/null +++ b/gcc_arm/config/arm/xm-netbsd.h @@ -0,0 +1,7 @@ +/* Configuration for GCC for ARM running NetBSD as host. */ + +#include + +#ifndef SYS_SIGLIST_DECLARED +#define SYS_SIGLIST_DECLARED +#endif diff --git a/gcc_arm/config/arm/xm-thumb.h b/gcc_arm/config/arm/xm-thumb.h new file mode 100755 index 0000000..3356ae2 --- /dev/null +++ b/gcc_arm/config/arm/xm-thumb.h @@ -0,0 +1 @@ +#include diff --git a/gcc_arm/config/float-i64.h b/gcc_arm/config/float-i64.h new file mode 100755 index 0000000..7dbe4e9 --- /dev/null +++ b/gcc_arm/config/float-i64.h @@ -0,0 +1,96 @@ +/* float.h for target with IEEE 32 bit and 64 bit floating point formats */ +#ifndef _FLOAT_H_ +#define _FLOAT_H_ +/* Produced by enquire version 4.3, CWI, Amsterdam */ + + /* Radix of exponent representation */ +#undef FLT_RADIX +#define FLT_RADIX 2 + /* Number of base-FLT_RADIX digits in the significand of a float */ +#undef FLT_MANT_DIG +#define FLT_MANT_DIG 24 + /* Number of decimal digits of precision in a float */ +#undef FLT_DIG +#define FLT_DIG 6 + /* Addition rounds to 0: zero, 1: nearest, 2: +inf, 3: -inf, -1: unknown */ +#undef FLT_ROUNDS +#define FLT_ROUNDS 1 + /* Difference between 1.0 and the minimum float greater than 1.0 */ +#undef FLT_EPSILON +#define FLT_EPSILON 1.19209290e-07F + /* Minimum int x such that FLT_RADIX**(x-1) is a normalised float */ +#undef FLT_MIN_EXP +#define FLT_MIN_EXP (-125) + /* Minimum normalised float */ +#undef FLT_MIN +#define FLT_MIN 1.17549435e-38F + /* Minimum int x such that 10**x is a normalised float */ +#undef FLT_MIN_10_EXP +#define FLT_MIN_10_EXP (-37) + /* Maximum int x such that FLT_RADIX**(x-1) is a representable float */ +#undef FLT_MAX_EXP +#define FLT_MAX_EXP 128 + /* Maximum float */ +#undef FLT_MAX +#define FLT_MAX 3.40282347e+38F + /* Maximum int x such that 10**x is a representable float */ +#undef FLT_MAX_10_EXP +#define FLT_MAX_10_EXP 38 + + /* Number of base-FLT_RADIX digits in the significand of a double */ +#undef DBL_MANT_DIG +#define DBL_MANT_DIG 53 + /* Number of decimal digits of precision in a double */ +#undef DBL_DIG +#define DBL_DIG 15 + /* Difference between 1.0 and the minimum double greater than 1.0 */ +#undef DBL_EPSILON +#define DBL_EPSILON 2.2204460492503131e-16 + /* Minimum int x such that FLT_RADIX**(x-1) is a normalised double */ +#undef DBL_MIN_EXP +#define DBL_MIN_EXP (-1021) + /* Minimum normalised double */ +#undef DBL_MIN +#define DBL_MIN 2.2250738585072014e-308 + /* Minimum int x such that 10**x is a normalised double */ +#undef DBL_MIN_10_EXP +#define DBL_MIN_10_EXP (-307) + /* Maximum int x such that FLT_RADIX**(x-1) is a representable double */ +#undef DBL_MAX_EXP +#define DBL_MAX_EXP 1024 + /* Maximum double */ +#undef DBL_MAX +#define DBL_MAX 1.7976931348623157e+308 + /* Maximum int x such that 10**x is a representable double */ +#undef DBL_MAX_10_EXP +#define DBL_MAX_10_EXP 308 + + /* Number of base-FLT_RADIX digits in the significand of a long double */ +#undef LDBL_MANT_DIG +#define LDBL_MANT_DIG 53 + /* Number of decimal digits of precision in a long double */ +#undef LDBL_DIG +#define LDBL_DIG 15 + /* Difference between 1.0 and the minimum long double greater than 1.0 */ +#undef LDBL_EPSILON +#define LDBL_EPSILON 2.2204460492503131e-16L + /* Minimum int x such that FLT_RADIX**(x-1) is a normalised long double */ +#undef LDBL_MIN_EXP +#define LDBL_MIN_EXP (-1021) + /* Minimum normalised long double */ +#undef LDBL_MIN +#define LDBL_MIN 2.2250738585072014e-308L + /* Minimum int x such that 10**x is a normalised long double */ +#undef LDBL_MIN_10_EXP +#define LDBL_MIN_10_EXP (-307) + /* Maximum int x such that FLT_RADIX**(x-1) is a representable long double */ +#undef LDBL_MAX_EXP +#define LDBL_MAX_EXP 1024 + /* Maximum long double */ +#undef LDBL_MAX +#define LDBL_MAX 1.7976931348623157e+308L + /* Maximum int x such that 10**x is a representable long double */ +#undef LDBL_MAX_10_EXP +#define LDBL_MAX_10_EXP 308 + +#endif /* _FLOAT_H_ */ diff --git a/gcc_arm/config/fp-bit.c b/gcc_arm/config/fp-bit.c new file mode 100755 index 0000000..6b8bd70 --- /dev/null +++ b/gcc_arm/config/fp-bit.c @@ -0,0 +1,1507 @@ +/* This is a software floating point library which can be used instead of + the floating point routines in libgcc1.c for targets without hardware + floating point. + Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + +This file 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. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file with other programs, and to distribute +those programs without any restriction coming from the use of this +file. (The General Public License restrictions do apply in other +respects; for example, they cover modification of the file, and +distribution when not linked into another program.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with other files, + some of which are compiled with GCC, to produce an executable, + this library does not by itself cause the resulting executable + to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +/* This implements IEEE 754 format arithmetic, but does not provide a + mechanism for setting the rounding mode, or for generating or handling + exceptions. + + The original code by Steve Chamberlain, hacked by Mark Eichin and Jim + Wilson, all of Cygnus Support. */ + +/* The intended way to use this file is to make two copies, add `#define FLOAT' + to one copy, then compile both copies and add them to libgcc.a. */ + +/* Defining FINE_GRAINED_LIBRARIES allows one to select which routines + from this file are compiled via additional -D options. + + This avoids the need to pull in the entire fp emulation library + when only a small number of functions are needed. + + If FINE_GRAINED_LIBRARIES is not defined, then compile every + suitable routine. */ +#ifndef FINE_GRAINED_LIBRARIES +#define L_pack_df +#define L_unpack_df +#define L_pack_sf +#define L_unpack_sf +#define L_addsub_sf +#define L_addsub_df +#define L_mul_sf +#define L_mul_df +#define L_div_sf +#define L_div_df +#define L_fpcmp_parts_sf +#define L_fpcmp_parts_df +#define L_compare_sf +#define L_compare_df +#define L_eq_sf +#define L_eq_df +#define L_ne_sf +#define L_ne_df +#define L_gt_sf +#define L_gt_df +#define L_ge_sf +#define L_ge_df +#define L_lt_sf +#define L_lt_df +#define L_le_sf +#define L_le_df +#define L_si_to_sf +#define L_si_to_df +#define L_sf_to_si +#define L_df_to_si +#define L_f_to_usi +#define L_df_to_usi +#define L_negate_sf +#define L_negate_df +#define L_make_sf +#define L_make_df +#define L_sf_to_df +#define L_df_to_sf +#endif + +/* The following macros can be defined to change the behaviour of this file: + FLOAT: Implement a `float', aka SFmode, fp library. If this is not + defined, then this file implements a `double', aka DFmode, fp library. + FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e. + don't include float->double conversion which requires the double library. + This is useful only for machines which can't support doubles, e.g. some + 8-bit processors. + CMPtype: Specify the type that floating point compares should return. + This defaults to SItype, aka int. + US_SOFTWARE_GOFAST: This makes all entry points use the same names as the + US Software goFast library. If this is not defined, the entry points use + the same names as libgcc1.c. + _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding + two integers to the FLO_union_type. + NO_NANS: Disable nan and infinity handling + SMALL_MACHINE: Useful when operations on QIs and HIs are faster + than on an SI */ + +/* We don't currently support extended floats (long doubles) on machines + without hardware to deal with them. + + These stubs are just to keep the linker from complaining about unresolved + references which can be pulled in from libio & libstdc++, even if the + user isn't using long doubles. However, they may generate an unresolved + external to abort if abort is not used by the function, and the stubs + are referenced from within libc, since libgcc goes before and after the + system library. */ + +#ifdef EXTENDED_FLOAT_STUBS +__truncxfsf2 (){ abort(); } +__extendsfxf2 (){ abort(); } +__addxf3 (){ abort(); } +__divxf3 (){ abort(); } +__eqxf2 (){ abort(); } +__extenddfxf2 (){ abort(); } +__gtxf2 (){ abort(); } +__lexf2 (){ abort(); } +__ltxf2 (){ abort(); } +__mulxf3 (){ abort(); } +__negxf2 (){ abort(); } +__nexf2 (){ abort(); } +__subxf3 (){ abort(); } +__truncxfdf2 (){ abort(); } + +__trunctfsf2 (){ abort(); } +__extendsftf2 (){ abort(); } +__addtf3 (){ abort(); } +__divtf3 (){ abort(); } +__eqtf2 (){ abort(); } +__extenddftf2 (){ abort(); } +__gttf2 (){ abort(); } +__letf2 (){ abort(); } +__lttf2 (){ abort(); } +__multf3 (){ abort(); } +__negtf2 (){ abort(); } +__netf2 (){ abort(); } +__subtf3 (){ abort(); } +__trunctfdf2 (){ abort(); } +__gexf2 (){ abort(); } +__fixxfsi (){ abort(); } +__floatsixf (){ abort(); } +#else /* !EXTENDED_FLOAT_STUBS, rest of file */ + + +typedef float SFtype __attribute__ ((mode (SF))); +typedef float DFtype __attribute__ ((mode (DF))); + +typedef int HItype __attribute__ ((mode (HI))); +typedef int SItype __attribute__ ((mode (SI))); +typedef int DItype __attribute__ ((mode (DI))); + +/* The type of the result of a fp compare */ +#ifndef CMPtype +#define CMPtype SItype +#endif + +typedef unsigned int UHItype __attribute__ ((mode (HI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); +typedef unsigned int UDItype __attribute__ ((mode (DI))); + +#define MAX_SI_INT ((SItype) ((unsigned) (~0)>>1)) +#define MAX_USI_INT ((USItype) ~0) + + +#ifdef FLOAT_ONLY +#define NO_DI_MODE +#endif + +#ifdef FLOAT +# define NGARDS 7L +# define GARDROUND 0x3f +# define GARDMASK 0x7f +# define GARDMSB 0x40 +# define EXPBITS 8 +# define EXPBIAS 127 +# define FRACBITS 23 +# define EXPMAX (0xff) +# define QUIET_NAN 0x100000L +# define FRAC_NBITS 32 +# define FRACHIGH 0x80000000L +# define FRACHIGH2 0xc0000000L +# define pack_d __pack_f +# define unpack_d __unpack_f +# define __fpcmp_parts __fpcmp_parts_f + typedef USItype fractype; + typedef UHItype halffractype; + typedef SFtype FLO_type; + typedef SItype intfrac; + +#else +# define PREFIXFPDP dp +# define PREFIXSFDF df +# define NGARDS 8L +# define GARDROUND 0x7f +# define GARDMASK 0xff +# define GARDMSB 0x80 +# define EXPBITS 11 +# define EXPBIAS 1023 +# define FRACBITS 52 +# define EXPMAX (0x7ff) +# define QUIET_NAN 0x8000000000000LL +# define FRAC_NBITS 64 +# define FRACHIGH 0x8000000000000000LL +# define FRACHIGH2 0xc000000000000000LL +# define pack_d __pack_d +# define unpack_d __unpack_d +# define __fpcmp_parts __fpcmp_parts_d + typedef UDItype fractype; + typedef USItype halffractype; + typedef DFtype FLO_type; + typedef DItype intfrac; +#endif + +#ifdef US_SOFTWARE_GOFAST +# ifdef FLOAT +# define add fpadd +# define sub fpsub +# define multiply fpmul +# define divide fpdiv +# define compare fpcmp +# define si_to_float sitofp +# define float_to_si fptosi +# define float_to_usi fptoui +# define negate __negsf2 +# define sf_to_df fptodp +# define dptofp dptofp +#else +# define add dpadd +# define sub dpsub +# define multiply dpmul +# define divide dpdiv +# define compare dpcmp +# define si_to_float litodp +# define float_to_si dptoli +# define float_to_usi dptoul +# define negate __negdf2 +# define df_to_sf dptofp +#endif +#else +# ifdef FLOAT +# define add __addsf3 +# define sub __subsf3 +# define multiply __mulsf3 +# define divide __divsf3 +# define compare __cmpsf2 +# define _eq_f2 __eqsf2 +# define _ne_f2 __nesf2 +# define _gt_f2 __gtsf2 +# define _ge_f2 __gesf2 +# define _lt_f2 __ltsf2 +# define _le_f2 __lesf2 +# define si_to_float __floatsisf +# define float_to_si __fixsfsi +# define float_to_usi __fixunssfsi +# define negate __negsf2 +# define sf_to_df __extendsfdf2 +#else +# define add __adddf3 +# define sub __subdf3 +# define multiply __muldf3 +# define divide __divdf3 +# define compare __cmpdf2 +# define _eq_f2 __eqdf2 +# define _ne_f2 __nedf2 +# define _gt_f2 __gtdf2 +# define _ge_f2 __gedf2 +# define _lt_f2 __ltdf2 +# define _le_f2 __ledf2 +# define si_to_float __floatsidf +# define float_to_si __fixdfsi +# define float_to_usi __fixunsdfsi +# define negate __negdf2 +# define df_to_sf __truncdfsf2 +# endif +#endif + + +#ifndef INLINE +#define INLINE __inline__ +#endif + +/* Preserve the sticky-bit when shifting fractions to the right. */ +#define LSHIFT(a) { a = (a & 1) | (a >> 1); } + +/* numeric parameters */ +/* F_D_BITOFF is the number of bits offset between the MSB of the mantissa + of a float and of a double. Assumes there are only two float types. + (double::FRAC_BITS+double::NGARDS-(float::FRAC_BITS-float::NGARDS)) + */ +#define F_D_BITOFF (52+8-(23+7)) + + +#define NORMAL_EXPMIN (-(EXPBIAS)+1) +#define IMPLICIT_1 (1LL<<(FRACBITS+NGARDS)) +#define IMPLICIT_2 (1LL<<(FRACBITS+1+NGARDS)) + +/* common types */ + +typedef enum +{ + CLASS_SNAN, + CLASS_QNAN, + CLASS_ZERO, + CLASS_NUMBER, + CLASS_INFINITY +} fp_class_type; + +typedef struct +{ +#ifdef SMALL_MACHINE + char class; + unsigned char sign; + short normal_exp; +#else + fp_class_type class; + unsigned int sign; + int normal_exp; +#endif + + union + { + fractype ll; + halffractype l[2]; + } fraction; +} fp_number_type; + +typedef union +{ + FLO_type value; + fractype value_raw; + +#ifndef FLOAT + halffractype words[2]; +#endif + +#ifdef FLOAT_BIT_ORDER_MISMATCH + struct + { + fractype fraction:FRACBITS __attribute__ ((packed)); + unsigned int exp:EXPBITS __attribute__ ((packed)); + unsigned int sign:1 __attribute__ ((packed)); + } + bits; +#endif + +#ifdef _DEBUG_BITFLOAT + struct + { + unsigned int sign:1 __attribute__ ((packed)); + unsigned int exp:EXPBITS __attribute__ ((packed)); + fractype fraction:FRACBITS __attribute__ ((packed)); + } + bits_big_endian; + + struct + { + fractype fraction:FRACBITS __attribute__ ((packed)); + unsigned int exp:EXPBITS __attribute__ ((packed)); + unsigned int sign:1 __attribute__ ((packed)); + } + bits_little_endian; +#endif +} +FLO_union_type; + + +/* end of header */ + +/* IEEE "special" number predicates */ + +#ifdef NO_NANS + +#define nan() 0 +#define isnan(x) 0 +#define isinf(x) 0 +#else + +INLINE +static fp_number_type * +nan () +{ + static fp_number_type thenan; + + return &thenan; +} + +INLINE +static int +isnan ( fp_number_type * x) +{ + return x->class == CLASS_SNAN || x->class == CLASS_QNAN; +} + +INLINE +static int +isinf ( fp_number_type * x) +{ + return x->class == CLASS_INFINITY; +} + +#endif + +INLINE +static int +iszero ( fp_number_type * x) +{ + return x->class == CLASS_ZERO; +} + +INLINE +static void +flip_sign ( fp_number_type * x) +{ + x->sign = !x->sign; +} + +extern FLO_type pack_d ( fp_number_type * ); + +#if defined(L_pack_df) || defined(L_pack_sf) +FLO_type +pack_d ( fp_number_type * src) +{ + FLO_union_type dst; + fractype fraction = src->fraction.ll; /* wasn't unsigned before? */ + int sign = src->sign; + int exp = 0; + + if (isnan (src)) + { + exp = EXPMAX; + if (src->class == CLASS_QNAN || 1) + { + fraction |= QUIET_NAN; + } + } + else if (isinf (src)) + { + exp = EXPMAX; + fraction = 0; + } + else if (iszero (src)) + { + exp = 0; + fraction = 0; + } + else if (fraction == 0) + { + exp = 0; + } + else + { + if (src->normal_exp < NORMAL_EXPMIN) + { + /* This number's exponent is too low to fit into the bits + available in the number, so we'll store 0 in the exponent and + shift the fraction to the right to make up for it. */ + + int shift = NORMAL_EXPMIN - src->normal_exp; + + exp = 0; + + if (shift > FRAC_NBITS - NGARDS) + { + /* No point shifting, since it's more that 64 out. */ + fraction = 0; + } + else + { + /* Shift by the value */ + fraction >>= shift; + } + fraction >>= NGARDS; + } + else if (src->normal_exp > EXPBIAS) + { + exp = EXPMAX; + fraction = 0; + } + else + { + exp = src->normal_exp + EXPBIAS; + /* IF the gard bits are the all zero, but the first, then we're + half way between two numbers, choose the one which makes the + lsb of the answer 0. */ + if ((fraction & GARDMASK) == GARDMSB) + { + if (fraction & (1 << NGARDS)) + fraction += GARDROUND + 1; + } + else + { + /* Add a one to the guards to round up */ + fraction += GARDROUND; + } + if (fraction >= IMPLICIT_2) + { + fraction >>= 1; + exp += 1; + } + fraction >>= NGARDS; + } + } + + /* We previously used bitfields to store the number, but this doesn't + handle little/big endian systems conveniently, so use shifts and + masks */ +#ifdef FLOAT_BIT_ORDER_MISMATCH + dst.bits.fraction = fraction; + dst.bits.exp = exp; + dst.bits.sign = sign; +#else + dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1); + dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS; + dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS); +#endif + +#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) + { + halffractype tmp = dst.words[0]; + dst.words[0] = dst.words[1]; + dst.words[1] = tmp; + } +#endif + + return dst.value; +} +#endif + +extern void unpack_d (FLO_union_type *, fp_number_type *); + +#if defined(L_unpack_df) || defined(L_unpack_sf) +void +unpack_d (FLO_union_type * src, fp_number_type * dst) +{ + /* We previously used bitfields to store the number, but this doesn't + handle little/big endian systems conveniently, so use shifts and + masks */ + fractype fraction; + int exp; + int sign; + +#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) + FLO_union_type swapped; + + swapped.words[0] = src->words[1]; + swapped.words[1] = src->words[0]; + src = &swapped; +#endif + +#ifdef FLOAT_BIT_ORDER_MISMATCH + fraction = src->bits.fraction; + exp = src->bits.exp; + sign = src->bits.sign; +#else + fraction = src->value_raw & ((((fractype)1) << FRACBITS) - (fractype)1); + exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1); + sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1; +#endif + + dst->sign = sign; + if (exp == 0) + { + /* Hmm. Looks like 0 */ + if (fraction == 0) + { + /* tastes like zero */ + dst->class = CLASS_ZERO; + } + else + { + /* Zero exponent with non zero fraction - it's denormalized, + so there isn't a leading implicit one - we'll shift it so + it gets one. */ + dst->normal_exp = exp - EXPBIAS + 1; + fraction <<= NGARDS; + + dst->class = CLASS_NUMBER; +#if 1 + while (fraction < IMPLICIT_1) + { + fraction <<= 1; + dst->normal_exp--; + } +#endif + dst->fraction.ll = fraction; + } + } + else if (exp == EXPMAX) + { + /* Huge exponent*/ + if (fraction == 0) + { + /* Attached to a zero fraction - means infinity */ + dst->class = CLASS_INFINITY; + } + else + { + /* Non zero fraction, means nan */ + if (fraction & QUIET_NAN) + { + dst->class = CLASS_QNAN; + } + else + { + dst->class = CLASS_SNAN; + } + /* Keep the fraction part as the nan number */ + dst->fraction.ll = fraction; + } + } + else + { + /* Nothing strange about this number */ + dst->normal_exp = exp - EXPBIAS; + dst->class = CLASS_NUMBER; + dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1; + } +} +#endif + +#if defined(L_addsub_sf) || defined(L_addsub_df) +static fp_number_type * +_fpadd_parts (fp_number_type * a, + fp_number_type * b, + fp_number_type * tmp) +{ + intfrac tfraction; + + /* Put commonly used fields in local variables. */ + int a_normal_exp; + int b_normal_exp; + fractype a_fraction; + fractype b_fraction; + + if (isnan (a)) + { + return a; + } + if (isnan (b)) + { + return b; + } + if (isinf (a)) + { + /* Adding infinities with opposite signs yields a NaN. */ + if (isinf (b) && a->sign != b->sign) + return nan (); + return a; + } + if (isinf (b)) + { + return b; + } + if (iszero (b)) + { + if (iszero (a)) + { + *tmp = *a; + tmp->sign = a->sign & b->sign; + return tmp; + } + return a; + } + if (iszero (a)) + { + return b; + } + + /* Got two numbers. shift the smaller and increment the exponent till + they're the same */ + { + int diff; + + a_normal_exp = a->normal_exp; + b_normal_exp = b->normal_exp; + a_fraction = a->fraction.ll; + b_fraction = b->fraction.ll; + + diff = a_normal_exp - b_normal_exp; + + if (diff < 0) + diff = -diff; + if (diff < FRAC_NBITS) + { + /* ??? This does shifts one bit at a time. Optimize. */ + while (a_normal_exp > b_normal_exp) + { + b_normal_exp++; + LSHIFT (b_fraction); + } + while (b_normal_exp > a_normal_exp) + { + a_normal_exp++; + LSHIFT (a_fraction); + } + } + else + { + /* Somethings's up.. choose the biggest */ + if (a_normal_exp > b_normal_exp) + { + b_normal_exp = a_normal_exp; + b_fraction = 0; + } + else + { + a_normal_exp = b_normal_exp; + a_fraction = 0; + } + } + } + + if (a->sign != b->sign) + { + if (a->sign) + { + tfraction = -a_fraction + b_fraction; + } + else + { + tfraction = a_fraction - b_fraction; + } + if (tfraction >= 0) + { + tmp->sign = 0; + tmp->normal_exp = a_normal_exp; + tmp->fraction.ll = tfraction; + } + else + { + tmp->sign = 1; + tmp->normal_exp = a_normal_exp; + tmp->fraction.ll = -tfraction; + } + /* and renormalize it */ + + while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll) + { + tmp->fraction.ll <<= 1; + tmp->normal_exp--; + } + } + else + { + tmp->sign = a->sign; + tmp->normal_exp = a_normal_exp; + tmp->fraction.ll = a_fraction + b_fraction; + } + tmp->class = CLASS_NUMBER; + /* Now the fraction is added, we have to shift down to renormalize the + number */ + + if (tmp->fraction.ll >= IMPLICIT_2) + { + LSHIFT (tmp->fraction.ll); + tmp->normal_exp++; + } + return tmp; + +} + +FLO_type +add (FLO_type arg_a, FLO_type arg_b) +{ + fp_number_type a; + fp_number_type b; + fp_number_type tmp; + fp_number_type *res; + + unpack_d ((FLO_union_type *) & arg_a, &a); + unpack_d ((FLO_union_type *) & arg_b, &b); + + res = _fpadd_parts (&a, &b, &tmp); + + return pack_d (res); +} + +FLO_type +sub (FLO_type arg_a, FLO_type arg_b) +{ + fp_number_type a; + fp_number_type b; + fp_number_type tmp; + fp_number_type *res; + + unpack_d ((FLO_union_type *) & arg_a, &a); + unpack_d ((FLO_union_type *) & arg_b, &b); + + b.sign ^= 1; + + res = _fpadd_parts (&a, &b, &tmp); + + return pack_d (res); +} +#endif + +#if defined(L_mul_sf) || defined(L_mul_df) +static INLINE fp_number_type * +_fpmul_parts ( fp_number_type * a, + fp_number_type * b, + fp_number_type * tmp) +{ + fractype low = 0; + fractype high = 0; + + if (isnan (a)) + { + a->sign = a->sign != b->sign; + return a; + } + if (isnan (b)) + { + b->sign = a->sign != b->sign; + return b; + } + if (isinf (a)) + { + if (iszero (b)) + return nan (); + a->sign = a->sign != b->sign; + return a; + } + if (isinf (b)) + { + if (iszero (a)) + { + return nan (); + } + b->sign = a->sign != b->sign; + return b; + } + if (iszero (a)) + { + a->sign = a->sign != b->sign; + return a; + } + if (iszero (b)) + { + b->sign = a->sign != b->sign; + return b; + } + + /* Calculate the mantissa by multiplying both 64bit numbers to get a + 128 bit number */ + { +#if defined(NO_DI_MODE) + { + fractype x = a->fraction.ll; + fractype ylow = b->fraction.ll; + fractype yhigh = 0; + int bit; + + /* ??? This does multiplies one bit at a time. Optimize. */ + for (bit = 0; bit < FRAC_NBITS; bit++) + { + int carry; + + if (x & 1) + { + carry = (low += ylow) < ylow; + high += yhigh + carry; + } + yhigh <<= 1; + if (ylow & FRACHIGH) + { + yhigh |= 1; + } + ylow <<= 1; + x >>= 1; + } + } +#elif defined(FLOAT) + { + /* Multiplying two 32 bit numbers to get a 64 bit number on + a machine with DI, so we're safe */ + + DItype answer = (DItype)(a->fraction.ll) * (DItype)(b->fraction.ll); + + high = answer >> 32; + low = answer; + } +#else + /* Doing a 64*64 to 128 */ + { + UDItype nl = a->fraction.ll & 0xffffffff; + UDItype nh = a->fraction.ll >> 32; + UDItype ml = b->fraction.ll & 0xffffffff; + UDItype mh = b->fraction.ll >>32; + UDItype pp_ll = ml * nl; + UDItype pp_hl = mh * nl; + UDItype pp_lh = ml * nh; + UDItype pp_hh = mh * nh; + UDItype res2 = 0; + UDItype res0 = 0; + UDItype ps_hh__ = pp_hl + pp_lh; + if (ps_hh__ < pp_hl) + res2 += 0x100000000LL; + pp_hl = (ps_hh__ << 32) & 0xffffffff00000000LL; + res0 = pp_ll + pp_hl; + if (res0 < pp_ll) + res2++; + res2 += ((ps_hh__ >> 32) & 0xffffffffL) + pp_hh; + high = res2; + low = res0; + } +#endif + } + + tmp->normal_exp = a->normal_exp + b->normal_exp; + tmp->sign = a->sign != b->sign; +#ifdef FLOAT + tmp->normal_exp += 2; /* ??????????????? */ +#else + tmp->normal_exp += 4; /* ??????????????? */ +#endif + while (high >= IMPLICIT_2) + { + tmp->normal_exp++; + if (high & 1) + { + low >>= 1; + low |= FRACHIGH; + } + high >>= 1; + } + while (high < IMPLICIT_1) + { + tmp->normal_exp--; + + high <<= 1; + if (low & FRACHIGH) + high |= 1; + low <<= 1; + } + /* rounding is tricky. if we only round if it won't make us round later. */ +#if 0 + if (low & FRACHIGH2) + { + if (((high & GARDMASK) != GARDMSB) + && (((high + 1) & GARDMASK) == GARDMSB)) + { + /* don't round, it gets done again later. */ + } + else + { + high++; + } + } +#endif + if ((high & GARDMASK) == GARDMSB) + { + if (high & (1 << NGARDS)) + { + /* half way, so round to even */ + high += GARDROUND + 1; + } + else if (low) + { + /* but we really weren't half way */ + high += GARDROUND + 1; + } + } + tmp->fraction.ll = high; + tmp->class = CLASS_NUMBER; + return tmp; +} + +FLO_type +multiply (FLO_type arg_a, FLO_type arg_b) +{ + fp_number_type a; + fp_number_type b; + fp_number_type tmp; + fp_number_type *res; + + unpack_d ((FLO_union_type *) & arg_a, &a); + unpack_d ((FLO_union_type *) & arg_b, &b); + + res = _fpmul_parts (&a, &b, &tmp); + + return pack_d (res); +} +#endif + +#if defined(L_div_sf) || defined(L_div_df) +static INLINE fp_number_type * +_fpdiv_parts (fp_number_type * a, + fp_number_type * b) +{ + fractype bit; + fractype numerator; + fractype denominator; + fractype quotient; + + if (isnan (a)) + { + return a; + } + if (isnan (b)) + { + return b; + } + + a->sign = a->sign ^ b->sign; + + if (isinf (a) || iszero (a)) + { + if (a->class == b->class) + return nan (); + return a; + } + + if (isinf (b)) + { + a->fraction.ll = 0; + a->normal_exp = 0; + return a; + } + if (iszero (b)) + { + a->class = CLASS_INFINITY; + return a; + } + + /* Calculate the mantissa by multiplying both 64bit numbers to get a + 128 bit number */ + { + /* quotient = + ( numerator / denominator) * 2^(numerator exponent - denominator exponent) + */ + + a->normal_exp = a->normal_exp - b->normal_exp; + numerator = a->fraction.ll; + denominator = b->fraction.ll; + + if (numerator < denominator) + { + /* Fraction will be less than 1.0 */ + numerator *= 2; + a->normal_exp--; + } + bit = IMPLICIT_1; + quotient = 0; + /* ??? Does divide one bit at a time. Optimize. */ + while (bit) + { + if (numerator >= denominator) + { + quotient |= bit; + numerator -= denominator; + } + bit >>= 1; + numerator *= 2; + } + + if ((quotient & GARDMASK) == GARDMSB) + { + if (quotient & (1 << NGARDS)) + { + /* half way, so round to even */ + quotient += GARDROUND + 1; + } + else if (numerator) + { + /* but we really weren't half way, more bits exist */ + quotient += GARDROUND + 1; + } + } + + a->fraction.ll = quotient; + return (a); + } +} + +FLO_type +divide (FLO_type arg_a, FLO_type arg_b) +{ + fp_number_type a; + fp_number_type b; + fp_number_type *res; + + unpack_d ((FLO_union_type *) & arg_a, &a); + unpack_d ((FLO_union_type *) & arg_b, &b); + + res = _fpdiv_parts (&a, &b); + + return pack_d (res); +} +#endif + +int __fpcmp_parts (fp_number_type * a, fp_number_type *b); + +#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) +/* according to the demo, fpcmp returns a comparison with 0... thus + a -1 + a==b -> 0 + a>b -> +1 + */ + +int +__fpcmp_parts (fp_number_type * a, fp_number_type * b) +{ +#if 0 + /* either nan -> unordered. Must be checked outside of this routine. */ + if (isnan (a) && isnan (b)) + { + return 1; /* still unordered! */ + } +#endif + + if (isnan (a) || isnan (b)) + { + return 1; /* how to indicate unordered compare? */ + } + if (isinf (a) && isinf (b)) + { + /* +inf > -inf, but +inf != +inf */ + /* b \a| +inf(0)| -inf(1) + ______\+--------+-------- + +inf(0)| a==b(0)| ab(1) | a==b(0) + -------+--------+-------- + So since unordered must be non zero, just line up the columns... + */ + return b->sign - a->sign; + } + /* but not both... */ + if (isinf (a)) + { + return a->sign ? -1 : 1; + } + if (isinf (b)) + { + return b->sign ? 1 : -1; + } + if (iszero (a) && iszero (b)) + { + return 0; + } + if (iszero (a)) + { + return b->sign ? 1 : -1; + } + if (iszero (b)) + { + return a->sign ? -1 : 1; + } + /* now both are "normal". */ + if (a->sign != b->sign) + { + /* opposite signs */ + return a->sign ? -1 : 1; + } + /* same sign; exponents? */ + if (a->normal_exp > b->normal_exp) + { + return a->sign ? -1 : 1; + } + if (a->normal_exp < b->normal_exp) + { + return a->sign ? 1 : -1; + } + /* same exponents; check size. */ + if (a->fraction.ll > b->fraction.ll) + { + return a->sign ? -1 : 1; + } + if (a->fraction.ll < b->fraction.ll) + { + return a->sign ? 1 : -1; + } + /* after all that, they're equal. */ + return 0; +} +#endif + +#if defined(L_compare_sf) || defined(L_compare_df) +CMPtype +compare (FLO_type arg_a, FLO_type arg_b) +{ + fp_number_type a; + fp_number_type b; + + unpack_d ((FLO_union_type *) & arg_a, &a); + unpack_d ((FLO_union_type *) & arg_b, &b); + + return __fpcmp_parts (&a, &b); +} +#endif + +#ifndef US_SOFTWARE_GOFAST + +/* These should be optimized for their specific tasks someday. */ + +#if defined(L_eq_sf) || defined(L_eq_df) +CMPtype +_eq_f2 (FLO_type arg_a, FLO_type arg_b) +{ + fp_number_type a; + fp_number_type b; + + unpack_d ((FLO_union_type *) & arg_a, &a); + unpack_d ((FLO_union_type *) & arg_b, &b); + + if (isnan (&a) || isnan (&b)) + return 1; /* false, truth == 0 */ + + return __fpcmp_parts (&a, &b) ; +} +#endif + +#if defined(L_ne_sf) || defined(L_ne_df) +CMPtype +_ne_f2 (FLO_type arg_a, FLO_type arg_b) +{ + fp_number_type a; + fp_number_type b; + + unpack_d ((FLO_union_type *) & arg_a, &a); + unpack_d ((FLO_union_type *) & arg_b, &b); + + if (isnan (&a) || isnan (&b)) + return 1; /* true, truth != 0 */ + + return __fpcmp_parts (&a, &b) ; +} +#endif + +#if defined(L_gt_sf) || defined(L_gt_df) +CMPtype +_gt_f2 (FLO_type arg_a, FLO_type arg_b) +{ + fp_number_type a; + fp_number_type b; + + unpack_d ((FLO_union_type *) & arg_a, &a); + unpack_d ((FLO_union_type *) & arg_b, &b); + + if (isnan (&a) || isnan (&b)) + return -1; /* false, truth > 0 */ + + return __fpcmp_parts (&a, &b); +} +#endif + +#if defined(L_ge_sf) || defined(L_ge_df) +CMPtype +_ge_f2 (FLO_type arg_a, FLO_type arg_b) +{ + fp_number_type a; + fp_number_type b; + + unpack_d ((FLO_union_type *) & arg_a, &a); + unpack_d ((FLO_union_type *) & arg_b, &b); + + if (isnan (&a) || isnan (&b)) + return -1; /* false, truth >= 0 */ + return __fpcmp_parts (&a, &b) ; +} +#endif + +#if defined(L_lt_sf) || defined(L_lt_df) +CMPtype +_lt_f2 (FLO_type arg_a, FLO_type arg_b) +{ + fp_number_type a; + fp_number_type b; + + unpack_d ((FLO_union_type *) & arg_a, &a); + unpack_d ((FLO_union_type *) & arg_b, &b); + + if (isnan (&a) || isnan (&b)) + return 1; /* false, truth < 0 */ + + return __fpcmp_parts (&a, &b); +} +#endif + +#if defined(L_le_sf) || defined(L_le_df) +CMPtype +_le_f2 (FLO_type arg_a, FLO_type arg_b) +{ + fp_number_type a; + fp_number_type b; + + unpack_d ((FLO_union_type *) & arg_a, &a); + unpack_d ((FLO_union_type *) & arg_b, &b); + + if (isnan (&a) || isnan (&b)) + return 1; /* false, truth <= 0 */ + + return __fpcmp_parts (&a, &b) ; +} +#endif + +#endif /* ! US_SOFTWARE_GOFAST */ + +#if defined(L_si_to_sf) || defined(L_si_to_df) +FLO_type +si_to_float (SItype arg_a) +{ + fp_number_type in; + + in.class = CLASS_NUMBER; + in.sign = arg_a < 0; + if (!arg_a) + { + in.class = CLASS_ZERO; + } + else + { + in.normal_exp = FRACBITS + NGARDS; + if (in.sign) + { + /* Special case for minint, since there is no +ve integer + representation for it */ + if (arg_a == (SItype) 0x80000000) + { + return -2147483648.0; + } + in.fraction.ll = (-arg_a); + } + else + in.fraction.ll = arg_a; + + while (in.fraction.ll < (1LL << (FRACBITS + NGARDS))) + { + in.fraction.ll <<= 1; + in.normal_exp -= 1; + } + } + return pack_d (&in); +} +#endif + +#if defined(L_sf_to_si) || defined(L_df_to_si) +SItype +float_to_si (FLO_type arg_a) +{ + fp_number_type a; + SItype tmp; + + unpack_d ((FLO_union_type *) & arg_a, &a); + if (iszero (&a)) + return 0; + if (isnan (&a)) + return 0; + /* get reasonable MAX_SI_INT... */ + if (isinf (&a)) + return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; + /* it is a number, but a small one */ + if (a.normal_exp < 0) + return 0; + if (a.normal_exp > 30) + return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; + tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); + return a.sign ? (-tmp) : (tmp); +} +#endif + +#if defined(L_sf_to_usi) || defined(L_df_to_usi) +#ifdef US_SOFTWARE_GOFAST +/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines, + we also define them for GOFAST because the ones in libgcc2.c have the + wrong names and I'd rather define these here and keep GOFAST CYG-LOC's + out of libgcc2.c. We can't define these here if not GOFAST because then + there'd be duplicate copies. */ + +USItype +float_to_usi (FLO_type arg_a) +{ + fp_number_type a; + + unpack_d ((FLO_union_type *) & arg_a, &a); + if (iszero (&a)) + return 0; + if (isnan (&a)) + return 0; + /* it is a negative number */ + if (a.sign) + return 0; + /* get reasonable MAX_USI_INT... */ + if (isinf (&a)) + return MAX_USI_INT; + /* it is a number, but a small one */ + if (a.normal_exp < 0) + return 0; + if (a.normal_exp > 31) + return MAX_USI_INT; + else if (a.normal_exp > (FRACBITS + NGARDS)) + return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS)); + else + return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); +} +#endif +#endif + +#if defined(L_negate_sf) || defined(L_negate_df) +FLO_type +negate (FLO_type arg_a) +{ + fp_number_type a; + + unpack_d ((FLO_union_type *) & arg_a, &a); + flip_sign (&a); + return pack_d (&a); +} +#endif + +#ifdef FLOAT + +#if defined(L_make_sf) +SFtype +__make_fp(fp_class_type class, + unsigned int sign, + int exp, + USItype frac) +{ + fp_number_type in; + + in.class = class; + in.sign = sign; + in.normal_exp = exp; + in.fraction.ll = frac; + return pack_d (&in); +} +#endif + +#ifndef FLOAT_ONLY + +/* This enables one to build an fp library that supports float but not double. + Otherwise, we would get an undefined reference to __make_dp. + This is needed for some 8-bit ports that can't handle well values that + are 8-bytes in size, so we just don't support double for them at all. */ + +extern DFtype __make_dp (fp_class_type, unsigned int, int, UDItype frac); + +#if defined(L_sf_to_df) +DFtype +sf_to_df (SFtype arg_a) +{ + fp_number_type in; + + unpack_d ((FLO_union_type *) & arg_a, &in); + return __make_dp (in.class, in.sign, in.normal_exp, + ((UDItype) in.fraction.ll) << F_D_BITOFF); +} +#endif + +#endif +#endif + +#ifndef FLOAT + +extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype); + +#if defined(L_make_df) +DFtype +__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac) +{ + fp_number_type in; + + in.class = class; + in.sign = sign; + in.normal_exp = exp; + in.fraction.ll = frac; + return pack_d (&in); +} +#endif + +#if defined(L_df_to_sf) +SFtype +df_to_sf (DFtype arg_a) +{ + fp_number_type in; + USItype sffrac; + + unpack_d ((FLO_union_type *) & arg_a, &in); + + sffrac = in.fraction.ll >> F_D_BITOFF; + + /* We set the lowest guard bit in SFFRAC if we discarded any non + zero bits. */ + if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0) + sffrac |= 1; + + return __make_fp (in.class, in.sign, in.normal_exp, sffrac); +} +#endif + +#endif +#endif /* !EXTENDED_FLOAT_STUBS */ diff --git a/gcc_arm/config/i386/xm-i386.h b/gcc_arm/config/i386/xm-i386.h new file mode 100755 index 0000000..acc1657 --- /dev/null +++ b/gcc_arm/config/i386/xm-i386.h @@ -0,0 +1,43 @@ +/* Configuration for GNU C-compiler for Intel 80386. + Copyright (C) 1988, 1993 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifndef i386 +#define i386 +#endif + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* This describes the machine the compiler is hosted on. */ +#define HOST_BITS_PER_CHAR 8 +#define HOST_BITS_PER_SHORT 16 +#define HOST_BITS_PER_INT 32 +#define HOST_BITS_PER_LONG 32 +#define HOST_BITS_PER_LONGLONG 64 + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ + +#include "tm.h" diff --git a/gcc_arm/configure b/gcc_arm/configure new file mode 100755 index 0000000..05c0782 --- /dev/null +++ b/gcc_arm/configure @@ -0,0 +1,4478 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --with-gnu-ld arrange to work with GNU ld." +ac_help="$ac_help + --with-ld arrange to use the specified ld (full pathname)." +ac_help="$ac_help + --with-gnu-as arrange to work with GNU as." +ac_help="$ac_help + --with-as arrange to use the specified as (full pathname)." +ac_help="$ac_help + --with-stabs arrange to use stabs instead of host debug format." +ac_help="$ac_help + --with-elf arrange to use ELF instead of host debug format." +ac_help="$ac_help + --with-gxx-include-dir=DIR + specifies directory to put g++ header files." +ac_help="$ac_help + --enable-checking enable expensive run-time checks." +ac_help="$ac_help + --enable-cpplib use cpplib for the C preprocessor." +ac_help="$ac_help + --enable-c-cpplib link cpplib directly into C and C++ compilers + (implies --enable-cpplib)." +ac_help="$ac_help + --enable-c-mbchar enable multibyte characters for C and C++. + --disable-c-mbchar disable multibyte characters for C and C++. " +ac_help="$ac_help + --enable-haifa use the experimental scheduler. + --disable-haifa don't use the experimental scheduler for the + targets which normally enable it." +ac_help="$ac_help + --with-fast-fixincludes use a faster fixinclude program (experimental)" +ac_help="$ac_help + --enable-init-priority use attributes to assign initialization order + for static objects. + --disable-init-priority conform to ISO C++ rules for ordering static objects + (i.e. initialized in order of declaration). " +ac_help="$ac_help + --enable-threads enable thread usage for target GCC. + --enable-threads=LIB use LIB thread package for target GCC." +ac_help="$ac_help + --enable-objc-gc enable the use of Boehm's garbage collector with + the GNU Objective-C runtime." +ac_help="$ac_help + --enable-java-gc=TYPE choose garbage collector [boehm]" +ac_help="$ac_help + --enable-dwarf2 enable DWARF2 debugging as default." + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=tree.c + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + + +remove=rm +hard_link=ln +symbolic_link='ln -s' +copy=cp + +# Check for bogus environment variables. +# Test if LIBRARY_PATH contains the notation for the current directory +# since this would lead to problems installing/building glibc. +# LIBRARY_PATH contains the current directory if one of the following +# is true: +# - one of the terminals (":" and ";") is the first or last sign +# - two terminals occur directly after each other +# - the path contains an element with a dot in it +echo $ac_n "checking LIBRARY_PATH variable""... $ac_c" 1>&6 +echo "configure:587: checking LIBRARY_PATH variable" >&5 +case ${LIBRARY_PATH} in + [:\;]* | *[:\;] | *[:\;][:\;]* | *[:\;]. | .[:\;]*| . | *[:\;].[:\;]* ) + library_path_setting="contains current directory" + ;; + *) + library_path_setting="ok" + ;; +esac +echo "$ac_t""$library_path_setting" 1>&6 +if test "$library_path_setting" != "ok"; then +{ echo "configure: error: +*** LIBRARY_PATH shouldn't contain the current directory when +*** building egcs. Please change the environment variable +*** and run configure again." 1>&2; exit 1; } +fi + +# Test if GCC_EXEC_PREFIX contains the notation for the current directory +# since this would lead to problems installing/building glibc. +# GCC_EXEC_PREFIX contains the current directory if one of the following +# is true: +# - one of the terminals (":" and ";") is the first or last sign +# - two terminals occur directly after each other +# - the path contains an element with a dot in it +echo $ac_n "checking GCC_EXEC_PREFIX variable""... $ac_c" 1>&6 +echo "configure:612: checking GCC_EXEC_PREFIX variable" >&5 +case ${GCC_EXEC_PREFIX} in + [:\;]* | *[:\;] | *[:\;][:\;]* | *[:\;]. | .[:\;]*| . | *[:\;].[:\;]* ) + gcc_exec_prefix_setting="contains current directory" + ;; + *) + gcc_exec_prefix_setting="ok" + ;; +esac +echo "$ac_t""$gcc_exec_prefix_setting" 1>&6 +if test "$gcc_exec_prefix_setting" != "ok"; then +{ echo "configure: error: +*** GCC_EXEC_PREFIX shouldn't contain the current directory when +*** building egcs. Please change the environment variable +*** and run configure again." 1>&2; exit 1; } +fi + +# Check for additional parameters + +# With GNU ld +# Check whether --with-gnu-ld or --without-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval="$with_gnu_ld" + gnu_ld_flag="$with_gnu_ld" +else + gnu_ld_flag=no +fi + + +# With pre-defined ld +# Check whether --with-ld or --without-ld was given. +if test "${with_ld+set}" = set; then + withval="$with_ld" + DEFAULT_LINKER="$with_ld" +fi + +if test x"${DEFAULT_LINKER+set}" = x"set"; then + if test ! -x "$DEFAULT_LINKER"; then + echo "configure: warning: cannot execute: $DEFAULT_LINKER: check --with-ld or env. var. DEFAULT_LINKER" 1>&2 + elif test "GNU" = `$DEFAULT_LINKER -v &1 | sed '1s/^GNU.*/GNU/;q'`; then + gnu_ld_flag=yes + fi + cat >> confdefs.h <&2 + elif test "GNU" = `$DEFAULT_ASSEMBLER -v &1 | sed '1s/^GNU.*/GNU/;q'`; then + gas_flag=yes + fi + cat >> confdefs.h <&2; exit 1; } ;; +no) ;; +*) gcc_gxx_include_dir=$with_gxx_include_dir ;; +esac +fi + + +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/g++' + else + topsrcdir=${srcdir}/.. . ${srcdir}/../config.if + gcc_gxx_include_dir="\$(libsubdir)/\$(unlibsubdir)/..\`echo \$(exec_prefix) | sed -e 's|^\$(prefix)||' -e 's|/[^/]*|/..|g'\`/include/g++"-${libstdcxx_interface} + fi +fi + +# Enable expensive internal checks +# Check whether --enable-checking or --disable-checking was given. +if test "${enable_checking+set}" = set; then + enableval="$enable_checking" + case "${enableval}" in +yes) cat >> confdefs.h <<\EOF +#define ENABLE_CHECKING 1 +EOF + ;; +no) ;; +*) { echo "configure: error: bad value ${enableval} given for checking option" 1>&2; exit 1; } ;; +esac +fi + + +# Use cpplib+cppmain for the preprocessor, but don't link it with the compiler. +cpp_main=cccp +# Check whether --enable-cpplib or --disable-cpplib was given. +if test "${enable_cpplib+set}" = set; then + enableval="$enable_cpplib" + if test x$enable_cpplib != xno; then + cpp_main=cppmain +fi +fi + + +# Link cpplib into the compiler proper, for C/C++/ObjC. +# Check whether --enable-c-cpplib or --disable-c-cpplib was given. +if test "${enable_c_cpplib+set}" = set; then + enableval="$enable_c_cpplib" + if test x$enable_c_cpplib != xno; then + extra_c_objs="${extra_c_objs} libcpp.a" + extra_cxx_objs="${extra_cxx_objs} ../libcpp.a" + extra_c_flags="${extra_c_flags} -DUSE_CPPLIB=1" + cpp_main=cppmain +fi +fi + + +# CYGNUS LOCAL mbchar +# Enable Multibyte Characters for C/C++ +# Check whether --enable-c-mbchar or --disable-c-mbchar was given. +if test "${enable_c_mbchar+set}" = set; then + enableval="$enable_c_mbchar" + if test x$enable_c_mbchar != xno; then + extra_c_flags="${extra_c_flags} -DMULTIBYTE_CHARS=1" +fi +else + extra_c_flags="${extra_c_flags} -DMULTIBYTE_CHARS=1" + +fi + +# END CYGNUS LOCAL + +# Enable Haifa scheduler. +# Check whether --enable-haifa or --disable-haifa was given. +if test "${enable_haifa+set}" = set; then + enableval="$enable_haifa" + : +fi + +# Fast fixincludes +# +# This is a work in progress... +# Check whether --with-fast-fixincludes or --without-fast-fixincludes was given. +if test "${with_fast_fixincludes+set}" = set; then + withval="$with_fast_fixincludes" + fast_fixinc="$with_fast_fixincludes" +else + fast_fixinc=no +fi + + +# Enable init_priority. +# Check whether --enable-init-priority or --disable-init-priority was given. +if test "${enable_init_priority+set}" = set; then + enableval="$enable_init_priority" + if test x$enable_init_priority != xno; then + extra_c_flags="${extra_c_flags} -DUSE_INIT_PRIORITY" +fi +fi + + +# Enable threads +# Pass with no value to take the default +# Pass with a value to specify a thread package +# Check whether --enable-threads or --disable-threads was given. +if test "${enable_threads+set}" = set; then + enableval="$enable_threads" + if test x$enable_threads = xno; then + enable_threads='' +fi +else + enable_threads='' +fi + + +enable_threads_flag=$enable_threads +# Check if a valid thread package +case x${enable_threads_flag} in + x | xno) + # No threads + target_thread_file='single' + ;; + xyes) + # default + target_thread_file='' + ;; + # CYGNUS LOCAL java + xdecosf1 | xirix | xmach | xos2 | xposix | xpthreads | xsingle | \ + xsolaris | xwin32 | xdce | xvxworks | xqt) + target_thread_file=$enable_threads_flag + ;; + *) + echo "$enable_threads is an unknown thread package" 1>&2 + exit 1 + ;; +esac + +# Check whether --enable-objc-gc or --disable-objc-gc was given. +if test "${enable_objc_gc+set}" = set; then + enableval="$enable_objc_gc" + if [ x$enable_objc_gc = xno ]; then + objc_boehm_gc='' +else + objc_boehm_gc=1 +fi +else + objc_boehm_gc='' +fi + + +# Check whether --enable-java-gc or --disable-java-gc was given. +if test "${enable_java_gc+set}" = set; then + enableval="$enable_java_gc" + + JAVAGC=$enableval +else + JAVAGC=boehm +fi + + +# Check whether --with-dwarf2 or --without-dwarf2 was given. +if test "${with_dwarf2+set}" = set; then + withval="$with_dwarf2" + dwarf2="$with_dwarf2" +else + dwarf2=no +fi + + +# Determine the host, build, and target systems +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + + +# Do some error checking and defaulting for the host and target type. +# The inputs are: +# configure --host=HOST --target=TARGET --build=BUILD NONOPT +# +# The rules are: +# 1. You are not allowed to specify --host, --target, and nonopt at the +# same time. +# 2. Host defaults to nonopt. +# 3. If nonopt is not specified, then host defaults to the current host, +# as determined by config.guess. +# 4. Target and build default to nonopt. +# 5. If nonopt is not specified, then target and build default to host. + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +case $host---$target---$nonopt in +NONE---*---* | *---NONE---* | *---*---NONE) ;; +*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;; +esac + + +# Make sure we can run config.sub. +if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 +echo "configure:949: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + +echo $ac_n "checking target system type""... $ac_c" 1>&6 +echo "configure:970: checking target system type" >&5 + +target_alias=$target +case "$target_alias" in +NONE) + case $nonopt in + NONE) target_alias=$host_alias ;; + *) target_alias=$nonopt ;; + esac ;; +esac + +target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias` +target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$target" 1>&6 + +echo $ac_n "checking build system type""... $ac_c" 1>&6 +echo "configure:988: checking build system type" >&5 + +build_alias=$build +case "$build_alias" in +NONE) + case $nonopt in + NONE) build_alias=$host_alias ;; + *) build_alias=$nonopt ;; + esac ;; +esac + +build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias` +build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$build" 1>&6 + +test "$host_alias" != "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + +# Find the native compiler +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1015: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1045: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1096: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1128: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 1139 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:1144: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:1170: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:1175: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:1203: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +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'. +if test "x$GCC" = "xyes"; then + stage1_warn_cflags='$(WARN_CFLAGS)' +else + stage1_warn_cflags="" +fi + + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:1246: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + +echo $ac_n "checking whether a default assembler was specified""... $ac_c" 1>&6 +echo "configure:1274: checking whether a default assembler was specified" >&5 +if test x"${DEFAULT_ASSEMBLER+set}" = x"set"; then + if test x"$with_gas" = x"no"; then + echo "$ac_t""yes ($DEFAULT_ASSEMBLER)" 1>&6 + else + echo "$ac_t""yes ($DEFAULT_ASSEMBLER - GNU as)" 1>&6 + fi +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking whether a default linker was specified""... $ac_c" 1>&6 +echo "configure:1286: checking whether a default linker was specified" >&5 +if test x"${DEFAULT_LINKER+set}" = x"set"; then + if test x"$with_gnu_ld" = x"no"; then + echo "$ac_t""yes ($DEFAULT_LINKER)" 1>&6 + else + echo "$ac_t""yes ($DEFAULT_LINKER - GNU ld)" 1>&6 + fi +else + echo "$ac_t""no" 1>&6 +fi + +# Find some useful tools +for ac_prog in mawk gawk nawk awk +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1303: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AWK="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AWK="$ac_cv_prog_AWK" +if test -n "$AWK"; then + echo "$ac_t""$AWK" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$AWK" && break +done + +# Extract the first word of "flex", so it can be a program name with args. +set dummy flex; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1335: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LEX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$LEX"; then + ac_cv_prog_LEX="$LEX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_LEX="flex" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_LEX" && ac_cv_prog_LEX="lex" +fi +fi +LEX="$ac_cv_prog_LEX" +if test -n "$LEX"; then + echo "$ac_t""$LEX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$LEXLIB" +then + case "$LEX" in + flex*) ac_lib=fl ;; + *) ac_lib=l ;; + esac + echo $ac_n "checking for yywrap in -l$ac_lib""... $ac_c" 1>&6 +echo "configure:1369: checking for yywrap in -l$ac_lib" >&5 +ac_lib_var=`echo $ac_lib'_'yywrap | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-l$ac_lib $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LEXLIB="-l$ac_lib" +else + echo "$ac_t""no" 1>&6 +fi + +fi + +echo $ac_n "checking whether ln works""... $ac_c" 1>&6 +echo "configure:1411: checking whether ln works" >&5 +if eval "test \"`echo '$''{'gcc_cv_prog_LN'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + rm -f conftestdata_t +echo >conftestdata_f +if ln conftestdata_f conftestdata_t 2>/dev/null +then + gcc_cv_prog_LN="ln" +else + if ln -s conftestdata_f conftestdata_t 2>/dev/null + then + gcc_cv_prog_LN="ln -s" + else + gcc_cv_prog_LN=cp + fi +fi +rm -f conftestdata_f conftestdata_t + +fi +LN="$gcc_cv_prog_LN" +if test "$gcc_cv_prog_LN" = "ln"; then + echo "$ac_t""yes" 1>&6 +else + if test "$gcc_cv_prog_LN" = "ln -s"; then + echo "$ac_t""no, using ln -s" 1>&6 + else + echo "$ac_t""no, and neither does ln -s, so using cp" 1>&6 + fi +fi + +echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 +echo "configure:1443: checking whether ln -s works" >&5 +if eval "test \"`echo '$''{'gcc_cv_prog_LN_S'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + rm -f conftestdata_t +echo >conftestdata_f +if ln -s conftestdata_f conftestdata_t 2>/dev/null +then + gcc_cv_prog_LN_S="ln -s" +else + 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 +LN_S="$gcc_cv_prog_LN_S" +if test "$gcc_cv_prog_LN_S" = "ln -s"; then + echo "$ac_t""yes" 1>&6 +else + if test "$gcc_cv_prog_LN_S" = "ln"; then + echo "$ac_t""no, using ln" 1>&6 + else + echo "$ac_t""no, and neither does ln, so using cp" 1>&6 + fi +fi + +echo $ac_n "checking for volatile""... $ac_c" 1>&6 +echo "configure:1475: checking for volatile" >&5 +if eval "test \"`echo '$''{'gcc_cv_c_volatile'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + gcc_cv_c_volatile=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + gcc_cv_c_volatile=no +fi +rm -f conftest* +fi + +echo "$ac_t""$gcc_cv_c_volatile" 1>&6 +if test $gcc_cv_c_volatile = yes ; then + cat >> confdefs.h <<\EOF +#define HAVE_VOLATILE 1 +EOF + +fi + +# Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1510: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +for ac_prog in 'bison -y' byacc +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1542: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_YACC="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +YACC="$ac_cv_prog_YACC" +if test -n "$YACC"; then + echo "$ac_t""$YACC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + +# 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: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:1583: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + # OSF/1 installbsd also uses dspmsg, but is usable. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:1634: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1655: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1672: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1689: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:1714: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +#include +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1727: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + 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 < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + 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 < +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#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); } + +EOF +if { (eval echo configure:1794: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + +echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 +echo "configure:1818: checking whether time.h and sys/time.h may both be included" >&5 +if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +int main() { +struct tm *tp; +; return 0; } +EOF +if { (eval echo configure:1832: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_header_time=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_time=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_time" 1>&6 +if test $ac_cv_header_time = yes; then + cat >> confdefs.h <<\EOF +#define TIME_WITH_SYS_TIME 1 +EOF + +fi + +echo $ac_n "checking whether string.h and strings.h may both be included""... $ac_c" 1>&6 +echo "configure:1853: checking whether string.h and strings.h may both be included" >&5 +if eval "test \"`echo '$''{'gcc_cv_header_string'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { + +; return 0; } +EOF +if { (eval echo configure:1866: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + gcc_cv_header_string=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + gcc_cv_header_string=no +fi +rm -f conftest* +fi + +echo "$ac_t""$gcc_cv_header_string" 1>&6 +if test $gcc_cv_header_string = yes; then + cat >> confdefs.h <<\EOF +#define STRING_WITH_STRINGS 1 +EOF + +fi + +echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6 +echo "configure:1887: checking for sys/wait.h that is POSIX.1 compatible" >&5 +if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#ifndef WEXITSTATUS +#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif +#ifndef WIFEXITED +#define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif +int main() { +int s; +wait (&s); +s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; +; return 0; } +EOF +if { (eval echo configure:1908: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_header_sys_wait_h=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_sys_wait_h=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6 +if test $ac_cv_header_sys_wait_h = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_SYS_WAIT_H 1 +EOF + +fi + +for ac_hdr in limits.h stddef.h string.h strings.h stdlib.h time.h fcntl.h unistd.h stab.h sys/file.h sys/time.h sys/resource.h sys/param.h sys/times.h sys/stat.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:1932: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1942: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + + +# Check for thread headers. +ac_safe=`echo "thread.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for thread.h""... $ac_c" 1>&6 +echo "configure:1972: checking for thread.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1982: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + have_thread_h=yes +else + echo "$ac_t""no" 1>&6 +have_thread_h= +fi + +ac_safe=`echo "pthread.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for pthread.h""... $ac_c" 1>&6 +echo "configure:2006: checking for pthread.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2016: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + have_pthread_h=yes +else + echo "$ac_t""no" 1>&6 +have_pthread_h= +fi + + +# See if GNAT has been installed +# Extract the first word of "gnatbind", so it can be a program name with args. +set dummy gnatbind; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2043: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gnat'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$gnat"; then + ac_cv_prog_gnat="$gnat" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_gnat="yes" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_gnat" && ac_cv_prog_gnat="no" +fi +fi +gnat="$ac_cv_prog_gnat" +if test -n "$gnat"; then + echo "$ac_t""$gnat" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +# See if the system preprocessor understands the ANSI C preprocessor +# stringification operator. +echo $ac_n "checking whether cpp understands the stringify operator""... $ac_c" 1>&6 +echo "configure:2074: checking whether cpp understands the stringify operator" >&5 +if eval "test \"`echo '$''{'gcc_cv_c_have_stringify'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + gcc_cv_c_have_stringify=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + gcc_cv_c_have_stringify=no +fi +rm -f conftest* +fi + +echo "$ac_t""$gcc_cv_c_have_stringify" 1>&6 +if test $gcc_cv_c_have_stringify = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_CPP_STRINGIFY 1 +EOF + +fi + +# Use only if it exists, +# doesn't clash with , and declares intmax_t. +echo $ac_n "checking for inttypes.h""... $ac_c" 1>&6 +echo "configure:2110: checking for inttypes.h" >&5 +if eval "test \"`echo '$''{'gcc_cv_header_inttypes_h'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { +intmax_t i = -1; +; return 0; } +EOF +if { (eval echo configure:2123: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + gcc_cv_header_inttypes_h=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + gcc_cv_header_inttypes_h=no +fi +rm -f conftest* +fi + +echo "$ac_t""$gcc_cv_header_inttypes_h" 1>&6 +if test $gcc_cv_header_inttypes_h = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_INTTYPES_H 1 +EOF + +fi + +for ac_func in strtoul bsearch strerror putenv popen bcopy bzero bcmp \ + index rindex strchr strrchr kill getrlimit setrlimit atoll atoq \ + sysconf isascii gettimeofday strsignal putc_unlocked fputc_unlocked \ + fputs_unlocked +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2149: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* 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_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2177: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + +# Make sure wchar_t is available +#AC_CHECK_TYPE(wchar_t, unsigned int) + +echo $ac_n "checking for vprintf""... $ac_c" 1>&6 +echo "configure:2206: checking for vprintf" >&5 +if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char vprintf(); + +int main() { + +/* 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_vprintf) || defined (__stub___vprintf) +choke me +#else +vprintf(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2234: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_vprintf=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_vprintf=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_VPRINTF 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +if test "$ac_cv_func_vprintf" != yes; then +echo $ac_n "checking for _doprnt""... $ac_c" 1>&6 +echo "configure:2258: checking for _doprnt" >&5 +if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char _doprnt(); + +int main() { + +/* 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__doprnt) || defined (__stub____doprnt) +choke me +#else +_doprnt(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2286: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func__doprnt=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func__doprnt=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_DOPRNT 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +fi + +vfprintf= +doprint= +if test $ac_cv_func_vprintf != yes ; then + vfprintf=vfprintf.o + if test $ac_cv_func__doprnt != yes ; then + doprint=doprint.o + fi +fi + + + +echo $ac_n "checking whether the printf functions support %p""... $ac_c" 1>&6 +echo "configure:2322: checking whether the printf functions support %p" >&5 +if eval "test \"`echo '$''{'gcc_cv_func_printf_ptr'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + gcc_cv_func_printf_ptr=no +else + cat > conftest.$ac_ext < + +main() +{ + char buf[64]; + char *p = buf, *q = NULL; + sprintf(buf, "%p", p); + sscanf(buf, "%p", &q); + exit (p != q); +} +EOF +if { (eval echo configure:2343: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + gcc_cv_func_printf_ptr=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + gcc_cv_func_printf_ptr=no +fi +rm -fr conftest* +fi + +rm -f core core.* *.core +fi + +echo "$ac_t""$gcc_cv_func_printf_ptr" 1>&6 +if test $gcc_cv_func_printf_ptr = yes ; then + cat >> confdefs.h <<\EOF +#define HAVE_PRINTF_PTR 1 +EOF + +fi + +echo $ac_n "checking for pid_t""... $ac_c" 1>&6 +echo "configure:2367: checking for pid_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_pid_t=yes +else + rm -rf conftest* + ac_cv_type_pid_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_pid_t" 1>&6 +if test $ac_cv_type_pid_t = no; then + cat >> confdefs.h <<\EOF +#define pid_t int +EOF + +fi + +ac_safe=`echo "vfork.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for vfork.h""... $ac_c" 1>&6 +echo "configure:2401: checking for vfork.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2411: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_VFORK_H 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking for working vfork""... $ac_c" 1>&6 +echo "configure:2436: checking for working vfork" >&5 +if eval "test \"`echo '$''{'ac_cv_func_vfork_works'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + echo $ac_n "checking for vfork""... $ac_c" 1>&6 +echo "configure:2442: checking for vfork" >&5 +if eval "test \"`echo '$''{'ac_cv_func_vfork'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char vfork(); + +int main() { + +/* 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_vfork) || defined (__stub___vfork) +choke me +#else +vfork(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2470: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_vfork=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_vfork=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'vfork`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +fi + +ac_cv_func_vfork_works=$ac_cv_func_vfork +else + cat > conftest.$ac_ext < +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_VFORK_H +#include +#endif +/* On some sparc systems, changes by the child to local and incoming + argument registers are propagated back to the parent. + The compiler is told about this with #include , + but some compilers (e.g. gcc -O) don't grok . + Test for this by using a static variable whose address + is put into a register that is clobbered by the vfork. */ +static +#ifdef __cplusplus +sparc_address_test (int arg) +#else +sparc_address_test (arg) int arg; +#endif +{ + static pid_t child; + if (!child) { + child = vfork (); + if (child < 0) { + perror ("vfork"); + _exit(2); + } + if (!child) { + arg = getpid(); + write(-1, "", 0); + _exit (arg); + } + } +} +main() { + pid_t parent = getpid (); + pid_t child; + + sparc_address_test (); + + child = vfork (); + + if (child == 0) { + /* Here is another test for sparc vfork register problems. + This test uses lots of local variables, at least + as many local variables as main has allocated so far + including compiler temporaries. 4 locals are enough for + gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe. + A buggy compiler should reuse the register of parent + for one of the local variables, since it will think that + parent can't possibly be used any more in this routine. + Assigning to the local variable will thus munge parent + in the parent process. */ + pid_t + p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), + p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); + /* Convince the compiler that p..p7 are live; otherwise, it might + use the same hardware register for all 8 local variables. */ + if (p != p1 || p != p2 || p != p3 || p != p4 + || p != p5 || p != p6 || p != p7) + _exit(1); + + /* On some systems (e.g. IRIX 3.3), + vfork doesn't separate parent from child file descriptors. + If the child closes a descriptor before it execs or exits, + this munges the parent's descriptor as well. + Test for this by closing stdout in the child. */ + _exit(close(fileno(stdout)) != 0); + } else { + int status; + struct stat st; + + while (wait(&status) != child) + ; + exit( + /* Was there some problem with vforking? */ + child < 0 + + /* Did the child fail? (This shouldn't happen.) */ + || status + + /* Did the vfork/compiler bug occur? */ + || parent != getpid() + + /* Did the file descriptor bug occur? */ + || fstat(fileno(stdout), &st) != 0 + ); + } +} +EOF +if { (eval echo configure:2587: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_vfork_works=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_vfork_works=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_vfork_works" 1>&6 +if test $ac_cv_func_vfork_works = no; then + cat >> confdefs.h <<\EOF +#define vfork fork +EOF + +fi + + +for ac_func in malloc realloc calloc free bcopy bzero bcmp \ + index rindex getenv atol sbrk abort atof strerror getcwd getwd \ + strsignal +do +echo $ac_n "checking whether $ac_func must be declared""... $ac_c" 1>&6 +echo "configure:2615: checking whether $ac_func must be declared" >&5 +if eval "test \"`echo '$''{'gcc_cv_decl_needed_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#ifdef STRING_WITH_STRINGS +# include +# include +#else +# ifdef HAVE_STRING_H +# include +# else +# ifdef HAVE_STRINGS_H +# include +# endif +# endif +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifndef HAVE_RINDEX +#define rindex strrchr +#endif +#ifndef HAVE_INDEX +#define index strchr +#endif + +int main() { +char *(*pfn) = (char *(*)) $ac_func +; return 0; } +EOF +if { (eval echo configure:2653: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + eval "gcc_cv_decl_needed_$ac_func=no" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "gcc_cv_decl_needed_$ac_func=yes" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$gcc_cv_decl_needed_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + gcc_tr_decl=NEED_DECLARATION_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi + +done + + +for ac_func in getrlimit setrlimit +do +echo $ac_n "checking whether $ac_func must be declared""... $ac_c" 1>&6 +echo "configure:2682: checking whether $ac_func must be declared" >&5 +if eval "test \"`echo '$''{'gcc_cv_decl_needed_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#ifdef STRING_WITH_STRINGS +# include +# include +#else +# ifdef HAVE_STRING_H +# include +# else +# ifdef HAVE_STRINGS_H +# include +# endif +# endif +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifndef HAVE_RINDEX +#define rindex strrchr +#endif +#ifndef HAVE_INDEX +#define index strchr +#endif +#include +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif + +int main() { +char *(*pfn) = (char *(*)) $ac_func +; return 0; } +EOF +if { (eval echo configure:2724: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + eval "gcc_cv_decl_needed_$ac_func=no" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "gcc_cv_decl_needed_$ac_func=yes" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$gcc_cv_decl_needed_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + gcc_tr_decl=NEED_DECLARATION_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi + +done + + +echo $ac_n "checking for sys_siglist declaration in signal.h or unistd.h""... $ac_c" 1>&6 +echo "configure:2751: checking for sys_siglist declaration in signal.h or unistd.h" >&5 +if eval "test \"`echo '$''{'ac_cv_decl_sys_siglist'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +/* NetBSD declares sys_siglist in unistd.h. */ +#ifdef HAVE_UNISTD_H +#include +#endif +int main() { +char *msg = *(sys_siglist + 1); +; return 0; } +EOF +if { (eval echo configure:2768: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_decl_sys_siglist=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_decl_sys_siglist=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_decl_sys_siglist" 1>&6 +if test $ac_cv_decl_sys_siglist = yes; then + cat >> confdefs.h <<\EOF +#define SYS_SIGLIST_DECLARED 1 +EOF + +fi + + +# File extensions +manext='.1' +objext='.o' + + + +build_xm_file= +build_xm_defines= +build_install_headers_dir=install-headers-tar +build_exeext= +host_xm_file= +host_xm_defines= +host_xmake_file= +host_truncate_target= +host_exeext= + +# Decode the host machine, then the target machine. +# For the host machine, we save the xm_file variable as host_xm_file; +# then we decode the target machine and forget everything else +# that came from the host machine. +for machine in $build $host $target; do + + out_file= + xmake_file= + tmake_file= + extra_headers= + extra_passes= + extra_parts= + extra_programs= + extra_objs= + extra_host_objs= + extra_gcc_objs= + xm_defines= + float_format= + # Set this to override the default target model. + target_cpu_default= + # Set this to control which fixincludes program to use. + if test x$fast_fixinc != xyes; then + fixincludes=fixincludes + else fixincludes=fixinc.sh ; fi + # Set this to control how the header file directory is installed. + install_headers_dir=install-headers-tar + # Set this to a non-empty list of args to pass to cpp if the target + # wants its .md file passed through cpp. + md_cppflags= + # Set this if directory names should be truncated to 14 characters. + truncate_target= + # Set this if gdb needs a dir command with `dirname $out_file` + gdb_needs_out_file_path= + # Set this if the build machine requires executables to have a + # file name suffix. + exeext= + # Set this to control which thread package will be used. + thread_file= + # Reinitialize these from the flag values every loop pass, since some + # configure entries modify them. + gas="$gas_flag" + gnu_ld="$gnu_ld_flag" + enable_threads=$enable_threads_flag + + # Set default cpu_type, tm_file and xm_file so it can be updated in + # each machine entry. + cpu_type=`echo $machine | sed 's/-.*$//'` + case $machine in + alpha*-*-*) + cpu_type=alpha + ;; + arm*-*-*) + cpu_type=arm + ;; + c*-convex-*) + cpu_type=convex + ;; + i[34567]86-*-*) + cpu_type=i386 + ;; + hppa*-*-*) + cpu_type=pa + ;; + m68000-*-*) + cpu_type=m68k + ;; + mips*-*-*) + cpu_type=mips + ;; + powerpc*-*-*) + cpu_type=rs6000 + ;; + pyramid-*-*) + cpu_type=pyr + ;; + sparc*-*-*) + cpu_type=sparc + ;; + esac + + tm_file=${cpu_type}/${cpu_type}.h + xm_file=${cpu_type}/xm-${cpu_type}.h + + # Set the default macros to define for GNU/Linux systems. + case $machine in + *-*-linux-gnu*) + xm_defines="HAVE_ATEXIT POSIX BSTRING" + ;; + esac + + case $machine in + # Support site-specific machine types. + arm*-*-elf*) + tm_file=arm/unknown-elf.h + tmake_file=arm/t-arm-elf + ;; + thumb-*-elf*) + tm_file=arm/telf.h + out_file=arm/thumb.c + xm_file=arm/xm-thumb.h + md_file=arm/thumb.md + tmake_file=arm/t-thumb-elf + fixincludes=Makefile.in # There is nothing to fix + ;; + esac + + case $machine in + *-*-linux-gnu*) + ;; # Existing GNU/Linux systems do not use the GNU setup. + *-*-gnu*) + # On the GNU system, the setup is just about the same on + # each different CPU. The specific machines that GNU + # supports are matched above and just set $cpu_type. + xm_file="xm-gnu.h ${xm_file}" + tm_file=${cpu_type}/gnu.h + # GNU always uses ELF. + elf=yes + # GNU tools are the only tools. + gnu_ld=yes + gas=yes + # On GNU, the headers are already okay. + fixincludes=Makefile.in + xmake_file=x-linux # These details are the same as Linux. + tmake_file=t-gnu # These are not. + ;; + *-*-sysv4*) + fixincludes=fixinc.svr4 + xmake_try_sysv=x-sysv + install_headers_dir=install-headers-cpio + ;; + *-*-sysv*) + install_headers_dir=install-headers-cpio + ;; + esac + + # Distinguish i[34567]86 + # Also, do not run mips-tfile on MIPS if using gas. + # Process --with-cpu= for PowerPC/rs6000 + target_cpu_default2= + case $machine in + i486-*-*) + target_cpu_default2=1 + ;; + i586-*-*) + target_cpu_default2=2 + ;; + i686-*-* | i786-*-*) + target_cpu_default2=3 + ;; + alpha*-*-*) + case $machine in + alphaev6*) + target_cpu_default2="MASK_CPU_EV6|MASK_BWX|MASK_CIX|MASK_MAX" + ;; + alphapca56*) + target_cpu_default2="MASK_CPU_EV5|MASK_BWX|MASK_MAX" + ;; + alphaev56*) + target_cpu_default2="MASK_CPU_EV5|MASK_BWX" + ;; + alphaev5*) + target_cpu_default2="MASK_CPU_EV5" + ;; + esac + + if test x$gas = xyes + then + if test "$target_cpu_default2" = "" + then + target_cpu_default2="MASK_GAS" + else + target_cpu_default2="${target_cpu_default2}|MASK_GAS" + fi + fi + ;; + # CYGNUS LOCAL m68k embedded + m68*-*-*) + target_cpu_default2=M68K_CPU_"`echo $machine | sed 's/-.*$//'`" + ;; + # END CYGNUS LOCAL + arm*-*-*) + case "x$with_cpu" in + x) + # The most generic + target_cpu_default2="TARGET_CPU_generic" + ;; + + # Distinguish cores, and major variants + # arm7m doesn't exist, but D & I don't affect code + xarm[23678] | xarm250 | xarm[67][01]0 \ + | xarm7m | xarm7dm | xarm7dmi | xarm7tdmi \ + | xarm7100 | xarm7500 | xarm7500fe | xarm810 \ + | xstrongarm | xstrongarm110) + target_cpu_default2="TARGET_CPU_$with_cpu" + ;; + + xyes | xno) + echo "--with-cpu must be passed a value" 1>&2 + exit 1 + ;; + + *) + if test x$pass2done = xyes + then + echo "Unknown cpu used with --with-cpu=$with_cpu" 1>&2 + exit 1 + fi + ;; + esac + ;; + + mips*-*-ecoff* | mips*-*-elf*) + if test x$gas = xyes + then + if test x$gnu_ld = xyes + then + target_cpu_default2=20 + else + target_cpu_default2=16 + fi + fi + ;; + mips*-*-*) + if test x$gas = xyes + then + target_cpu_default2=16 + fi + ;; + powerpc*-*-* | rs6000-*-*) + case "x$with_cpu" in + x) + ;; + + xcommon | xpower | xpower2 | xpowerpc | xrios \ + | xrios1 | xrios2 | xrsc | xrsc1 \ + | x601 | x602 | x603 | x603e | x604 | x604e | x620 \ + | x403 | x505 | x801 | x821 | x823 | x860) + target_cpu_default2="\"$with_cpu\"" + ;; + + xyes | xno) + echo "--with-cpu must be passed a value" 1>&2 + exit 1 + ;; + + *) + if test x$pass2done = xyes + then + echo "Unknown cpu used with --with-cpu=$with_cpu" 1>&2 + exit 1 + fi + ;; + esac + ;; + sparc*-*-*) + case ".$with_cpu" in + .) + target_cpu_default2=TARGET_CPU_"`echo $machine | sed 's/-.*$//'`" + ;; + # CYGNUS LOCAL sp86 + .supersparc | .hypersparc | .ultrasparc \ + | .sparclite | .sparc86x | .v7 | .v8 | .v9) + target_cpu_default2="TARGET_CPU_$with_cpu" + ;; + *) + if test x$pass2done = xyes + then + echo "Unknown cpu used with --with-cpu=$with_cpu" 1>&2 + exit 1 + fi + ;; + esac + ;; + esac + + if test "$target_cpu_default2" != "" + then + if test "$target_cpu_default" != "" + then + target_cpu_default="(${target_cpu_default}|${target_cpu_default2})" + else + target_cpu_default=$target_cpu_default2 + fi + fi + +# Save data on machine being used to compile GCC in build_xm_file. +# Save data on host machine in vars host_xm_file and host_xmake_file. + if test x$pass1done = x + then + if test x"$xm_file" = x + then build_xm_file=$cpu_type/xm-$cpu_type.h + else build_xm_file=$xm_file + fi + build_xm_defines=$xm_defines + build_install_headers_dir=$install_headers_dir + build_exeext=$exeext + pass1done=yes + else + if test x$pass2done = x + then + if test x"$xm_file" = x + then host_xm_file=$cpu_type/xm-$cpu_type.h + else host_xm_file=$xm_file + fi + host_xm_defines=$xm_defines + if test x"$xmake_file" = x + then xmake_file=$cpu_type/x-$cpu_type + fi + host_xmake_file="$xmake_file" + host_truncate_target=$truncate_target + host_extra_gcc_objs=$extra_gcc_objs + host_extra_objs=$extra_host_objs + host_exeext=$exeext + pass2done=yes + fi + fi +done + +extra_objs="${host_extra_objs} ${extra_objs}" + +# Default the target-machine variables that were not explicitly set. +if test x"$tm_file" = x +then tm_file=$cpu_type/$cpu_type.h; fi + +if test x$extra_headers = x +then extra_headers=; fi + +if test x"$xm_file" = x +then xm_file=$cpu_type/xm-$cpu_type.h; fi + +if test x$md_file = x +then md_file=$cpu_type/$cpu_type.md; fi + +if test x$out_file = x +then out_file=$cpu_type/$cpu_type.c; fi + +if test x"$tmake_file" = x +then tmake_file=$cpu_type/t-$cpu_type +fi + +if test x"$dwarf2" = xyes +then tm_file="tm-dwarf2.h $tm_file" +fi + +if test x$float_format = x +then float_format=i64 +fi + +if test $float_format = none +then float_h_file=Makefile.in +else float_h_file=float-$float_format.h +fi + +if test x$enable_haifa = x +then + case $target in + alpha*-* | hppa*-* | powerpc*-* | rs6000-* | *sparc*-* | m32r*-*) + enable_haifa=yes;; + esac +fi + +# Say what files are being used for the output code and MD file. +echo "Using \`$srcdir/config/$out_file' to output insns." +echo "Using \`$srcdir/config/$md_file' as machine description file." + +count=a +for f in $tm_file; do + count=${count}x +done +if test $count = ax; then + echo "Using \`$srcdir/config/$tm_file' as target machine macro file." +else + echo "Using the following target machine macro files:" + for f in $tm_file; do + echo " $srcdir/config/$f" + done +fi + +count=a +for f in $host_xm_file; do + count=${count}x +done +if test $count = ax; then + echo "Using \`$srcdir/config/$host_xm_file' as host machine macro file." +else + echo "Using the following host machine macro files:" + for f in $host_xm_file; do + echo " $srcdir/config/$f" + done +fi + +if test "$host_xm_file" != "$build_xm_file"; then + count=a + for f in $build_xm_file; do + count=${count}x + done + if test $count = ax; then + echo "Using \`$srcdir/config/$build_xm_file' as build machine macro file." + else + echo "Using the following build machine macro files:" + for f in $build_xm_file; do + echo " $srcdir/config/$f" + done + fi +fi + +if test x$thread_file = x; then + if test x$target_thread_file != x; then + thread_file=$target_thread_file + else + thread_file='single' + fi +fi + +# Set up the header files. +# $links is the list of header files to create. +# $vars is the list of shell variables with file names to include. +# auto-host.h is the file containing items generated by autoconf and is +# the first file included by config.h. +null_defines= +host_xm_file="auto-host.h gansidecl.h ${host_xm_file}" + +# If host=build, it is correct to have hconfig include auto-host.h +# as well. If host!=build, we are in error and need to do more +# work to find out the build config parameters. +if test x$host = x$build +then + build_xm_file="auto-host.h gansidecl.h ${build_xm_file}" +else + # We create a subdir, then run autoconf in the subdir. + # To prevent recursion we set host and build for the new + # invocation of configure to the build for this invocation + # of configure. + tempdir=build.$$ + rm -rf $tempdir + mkdir $tempdir + cd $tempdir + case ${srcdir} in + /*) realsrcdir=${srcdir};; + *) realsrcdir=../${srcdir};; + esac + CC=${CC_FOR_BUILD} ${realsrcdir}/configure \ + --target=$target --host=$build --build=$build + + # We just finished tests for the build machine, so rename + # the file auto-build.h in the gcc directory. + mv auto-host.h ../auto-build.h + cd .. + rm -rf $tempdir + build_xm_file="auto-build.h gansidecl.h ${build_xm_file}" +fi + + +xm_file="gansidecl.h ${xm_file}" +tm_file="gansidecl.h ${tm_file}" + +vars="host_xm_file tm_file xm_file build_xm_file" +links="config.h tm.h tconfig.h hconfig.h" +defines="host_xm_defines null_defines xm_defines build_xm_defines" + +rm -f config.bak +if test -f config.status; then mv -f config.status config.bak; fi + +# Make the links. +while test -n "$vars" +do + set $vars; var=$1; shift; vars=$* + set $links; link=$1; shift; links=$* + set $defines; define=$1; shift; defines=$* + + rm -f $link + + # Define TARGET_CPU_DEFAULT if the system wants one. + # This substitutes for lots of *.h files. + if test "$target_cpu_default" != "" -a $link = tm.h + then + echo "#define TARGET_CPU_DEFAULT ($target_cpu_default)" >>$link + fi + + for file in `eval echo '$'$var`; do + echo "#include \"$file\"" >>$link + done + + for def in `eval echo '$'$define`; do + echo "#ifndef $def" >>$link + echo "#define $def" >>$link + echo "#endif" >>$link + done +done + +# Truncate the target if necessary +if test x$host_truncate_target != x; then + target=`echo $target | sed -e 's/\(..............\).*/\1/'` +fi + +# 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=`sed -e 's/.*\"\([^ \"]*\)[ \"].*/\1/' < ${gcc_version_trigger}` + +# Get an absolute path to the GCC top-level source directory +holddir=`pwd` +cd $srcdir +topdir=`pwd` +cd $holddir + +# Conditionalize the makefile for this host machine. +# Make-host contains the concatenation of all host makefile fragments +# [there can be more than one]. This file is built by configure.frag. +host_overrides=Make-host +dep_host_xmake_file= +for f in .. ${host_xmake_file} +do + if test -f ${srcdir}/config/$f + then + dep_host_xmake_file="${dep_host_xmake_file} ${srcdir}/config/$f" + fi +done + +# Conditionalize the makefile for this target machine. +# Make-target contains the concatenation of all host makefile fragments +# [there can be more than one]. This file is built by configure.frag. +target_overrides=Make-target +dep_tmake_file= +for f in .. ${tmake_file} +do + if test -f ${srcdir}/config/$f + then + dep_tmake_file="${dep_tmake_file} ${srcdir}/config/$f" + fi +done + +# 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 +if $symbolic_link $srcdir/gcc.c symtest.tem 2>/dev/null +then + cc_set_by_configure="\$(CC)" + 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\`" + 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= +for f in $tm_file; do + if test $f != "gansidecl.h" ; then + tm_file_list="${tm_file_list} \$(srcdir)/config/$f" + else + tm_file_list="${tm_file_list} $f" + fi +done + +host_xm_file_list= +for f in $host_xm_file; do + if test $f != "auto-host.h" -a $f != "gansidecl.h" ; then + host_xm_file_list="${host_xm_file_list} \$(srcdir)/config/$f" + else + host_xm_file_list="${host_xm_file_list} $f" + fi +done + +build_xm_file_list= +for f in $build_xm_file; do + if test $f != "auto-build.h" -a $f != "auto-host.h" -a $f != "gansidecl.h" ; then + build_xm_file_list="${build_xm_file_list} \$(srcdir)/config/$f" + else + build_xm_file_list="${build_xm_file_list} $f" + fi +done + +# Define macro CROSS_COMPILE in compilation +# if this is a cross-compiler. +# Also use all.cross instead of all.internal +# and add cross-make to Makefile. +cross_overrides="/dev/null" +if test x$host != x$target +then + cross_defines="CROSS=-DCROSS_COMPILE" + cross_overrides="${topdir}/cross-make" +fi + +# When building gcc with a cross-compiler, we need to fix a few things. +# This must come after cross-make as we want all.build to override +# all.cross. +build_overrides="/dev/null" +if test x$build != x$host +then + build_overrides="${topdir}/build-make" +fi + +# Expand extra_headers to include complete path. +# This substitutes for lots of t-* files. +extra_headers_list= +if test "x$extra_headers" = x +then true +else + # Prepend ${srcdir}/ginclude/ to every entry in extra_headers. + for file in $extra_headers; + do + extra_headers_list="${extra_headers_list} \$(srcdir)/ginclude/${file}" + done +fi + +# NEED TO CONVERT +# Set MD_DEPS if the real md file is in md.pre-cpp. +# Set MD_CPP to the cpp to pass the md file through. Md files use ';' +# for line oriented comments, so we must always use a GNU cpp. If +# building gcc with a cross compiler, use the cross compiler just +# built. Otherwise, we can use the cpp just built. +md_file_sub= +if test "x$md_cppflags" = x +then + md_file_sub=$srcdir/config/$md_file +else + md_file=md +fi + +# If we have gas in the build tree, make a link to it. +if test -f ../gas/Makefile; then + rm -f as; $symbolic_link ../gas/as-new$host_exeext as$host_exeext 2>/dev/null +fi + +# If we have nm in the build tree, make a link to it. +if test -f ../binutils/Makefile; then + rm -f nm; $symbolic_link ../binutils/nm-new$host_exeext nm$host_exeext 2>/dev/null +fi + +# If we have ld in the build tree, make a link to it. +if test -f ../ld/Makefile; then + rm -f ld; $symbolic_link ../ld/ld-new$host_exeext ld$host_exeext 2>/dev/null +fi + +# Figure out what assembler alignment features are present. +echo $ac_n "checking assembler alignment features""... $ac_c" 1>&6 +echo "configure:6324: checking assembler alignment features" >&5 +gcc_cv_as= +gcc_cv_as_alignment_features= +gcc_cv_as_gas_srcdir=`echo $srcdir | sed -e 's,/gcc$,,'`/gas +if test -x "$DEFAULT_ASSEMBLER"; then + gcc_cv_as="$DEFAULT_ASSEMBLER" +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$host_exeext +elif test -f $gcc_cv_as_gas_srcdir/configure.in -a -f ../gas/Makefile; then + # Single tree build which includes gas. + for f in $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=`grep '^VERSION=[0-9]*\.[0-9]*' $f` + if test x$gcc_cv_gas_version != x; then + break + fi + done + gcc_cv_gas_major_version=`expr "$gcc_cv_gas_version" : "VERSION=\([0-9]*\)"` + gcc_cv_gas_minor_version=`expr "$gcc_cv_gas_version" : "VERSION=[0-9]*\.\([0-9]*\)"` + if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x; then + # Gas version 2.6 and later support for .balign and .p2align. + # bytes to skip when using .p2align. + if test "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 6 -o "$gcc_cv_gas_major_version" -gt 2; then + gcc_cv_as_alignment_features=".balign and .p2align" + cat >> confdefs.h <<\EOF +#define HAVE_GAS_BALIGN_AND_P2ALIGN 1 +EOF + + fi + # Gas version 2.8 and later support specifying the maximum + # bytes to skip when using .p2align. + if test "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 8 -o "$gcc_cv_gas_major_version" -gt 2; then + gcc_cv_as_alignment_features=".p2align including maximum skip" + cat >> confdefs.h <<\EOF +#define HAVE_GAS_MAX_SKIP_P2ALIGN 1 +EOF + + fi + fi +elif test x$host = x$target; then + # Native build. + gcc_cv_as=as$host_exeext +fi +if test x$gcc_cv_as != x; then + # Check if we have .balign and .p2align + echo ".balign 4" > conftest.s + echo ".p2align 2" >> conftest.s + if $gcc_cv_as -o conftest.o conftest.s > /dev/null 2>&1; then + gcc_cv_as_alignment_features=".balign and .p2align" + cat >> confdefs.h <<\EOF +#define HAVE_GAS_BALIGN_AND_P2ALIGN 1 +EOF + + fi + rm -f conftest.s conftest.o + # Check if specifying the maximum bytes to skip when + # using .p2align is supported. + echo ".p2align 4,,7" > conftest.s + if $gcc_cv_as -o conftest.o conftest.s > /dev/null 2>&1; then + gcc_cv_as_alignment_features=".p2align including maximum skip" + cat >> confdefs.h <<\EOF +#define HAVE_GAS_MAX_SKIP_P2ALIGN 1 +EOF + + fi + rm -f conftest.s conftest.o +fi +echo "$ac_t""$gcc_cv_as_alignment_features" 1>&6 + +echo $ac_n "checking assembler subsection support""... $ac_c" 1>&6 +echo "configure:6397: checking assembler subsection support" >&5 +gcc_cv_as_subsections= +if test x$gcc_cv_as != x; then + # Check if we have .subsection + echo ".subsection 1" > conftest.s + if $gcc_cv_as -o conftest.o conftest.s > /dev/null 2>&1; then + gcc_cv_as_subsections=".subsection" + if test -x nm$host_exeext; then + gcc_cv_nm=./nm$host_exeext + elif test x$host = x$target; then + # Native build. + gcc_cv_nm=nm$host_exeext + fi + if test x$gcc_cv_nm != x; then + cat > conftest.s < /dev/null 2>&1; then + $gcc_cv_nm conftest.o | grep conftest_label1 > conftest.nm1 + $gcc_cv_nm conftest.o | grep conftest_label2 | sed -e 's/label2/label1/' > conftest.nm2 + if cmp conftest.nm1 conftest.nm2 > /dev/null 2>&1; then + : + else + gcc_cv_as_subsections="working .subsection -1" + cat >> confdefs.h <<\EOF +#define HAVE_GAS_SUBSECTION_ORDERING 1 +EOF + + fi + fi + fi + fi + rm -f conftest.s conftest.o conftest.nm1 conftest.nm2 +fi +echo "$ac_t""$gcc_cv_as_subsections" 1>&6 + +# 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. +if test x"${enable_languages+set}" != xset; then + if test x"${LANGUAGES+set}" = xset; then + enable_languages="`echo ${LANGUAGES} | tr ' ' ','`" + else + enable_languages=all + fi +fi +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) ;; + # CYGNUS LOCAL nofortran/law + ${srcdir}/f/config-lang.in) + if [ x$enable_fortran = xyes ]; then + subdirs="$subdirs `echo $lang | sed -e 's,^.*/\([^/]*\)/config-lang.in$,\1,'`" + fi + ;; + ${srcdir}/objc/config-lang.in) + if [ x$enable_objc = xyes ]; then + subdirs="$subdirs `echo $lang | sed -e 's,^.*/\([^/]*\)/config-lang.in$,\1,'`" + fi + ;; + ${srcdir}/ch/config-lang.in) + if [ x$enable_chill = xyes ]; then + subdirs="$subdirs `echo $lang | sed -e 's,^.*/\([^/]*\)/config-lang.in$,\1,'`" + fi + ;; + # END CYGNUS LOCAL + ${srcdir}/ada/config-lang.in) + if test x$gnat = xyes ; then + subdirs="$subdirs `echo $lang | sed -e 's,^.*/\([^/]*\)/config-lang.in$,\1,'`" + fi + ;; + *) + 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 + if test x"${enable_languages}" = xall; then + add_this_lang=yes + else + case "${enable_languages}" in + ${lang_alias} | "${lang_alias},"* | *",${lang_alias},"* | *",${lang_alias}" ) + add_this_lang=yes + ;; + * ) + add_this_lang=no + ;; + esac + fi + if test x"${add_this_lang}" = xyes; then + case $lang in + ${srcdir}/ada/config-lang.in) + if test x$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 + +# 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 +# CYGNUS LOCAL java quickthreads +# qt is a library we build. So if we're using for it, and it is in +# our source tree, then we must look there for includes. +if test $thread_file = qt && test -d $srcdir/../qthreads; then + gthread_flags="$gthread_flags -I\$(srcdir)/../qthreads" +fi +# END CYGNUS LOCAL + + +# 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. + +lang_specs_files= +lang_options_files= +lang_tree_files= +rm -f specs.h options.h gencheck.h +touch specs.h options.h gencheck.h +for subdir in . $subdirs +do + if test -f $srcdir/$subdir/lang-specs.h; then + echo "#include \"$subdir/lang-specs.h\"" >>specs.h + lang_specs_files="$lang_specs_files $srcdir/$subdir/lang-specs.h" + fi + if test -f $srcdir/$subdir/lang-options.h; then + echo "#include \"$subdir/lang-options.h\"" >>options.h + lang_options_files="$lang_options_files $srcdir/$subdir/lang-options.h" + fi + if test -f $srcdir/$subdir/$subdir-tree.def; then + echo "#include \"$subdir/$subdir-tree.def\"" >>gencheck.h + 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_diff_excludes= +all_outputs=Makefile +# List of language makefile fragments. +all_lang_makefiles= +all_headers= +all_lib2funcs= + +# 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. +# We accumulate them and plug them into the main Makefile. +# The other mechanism is a set of hooks for each of the main targets +# like `clean', `install', etc. + +language_fragments="Make-lang" +language_hooks="Make-hooks" +oldstyle_subdirs= + +for s in .. $subdirs +do + if test $s != ".." + then + language= + boot_language= + compilers= + stagestuff= + diff_excludes= + headers= + outputs= + lib2funcs= + . ${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_makefiles="$all_lang_makefiles ${srcdir}/$s/Make-lang.in ${srcdir}/$s/Makefile.in" + 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_diff_excludes="$all_diff_excludes $diff_excludes" + all_headers="$all_headers $headers" + all_outputs="$all_outputs $outputs" + if test x$outputs = x + then + oldstyle_subdirs="$oldstyle_subdirs $s" + fi + all_lib2funcs="$all_lib2funcs $lib2funcs" + fi +done + +# Since we can't use `::' targets, we link each language in +# with a set of hooks, reached indirectly via lang.${target}. + +rm -f Make-hooks +touch Make-hooks +target_list="all.build all.cross start.encap rest.encap \ + info dvi \ + install-normal install-common install-info install-man \ + uninstall distdir \ + mostlyclean clean distclean extraclean maintainer-clean \ + stage1 stage2 stage3 stage4" +for t in $target_list +do + x= + for l in .. $all_languages + do + if test $l != ".."; then + x="$x $l.$t" + fi + done + echo "lang.$t: $x" >> Make-hooks +done + +# If we're not building in srcdir, create .gdbinit. + +if test ! -f Makefile.in; then + echo "dir ." > .gdbinit + echo "dir ${srcdir}" >> .gdbinit + if test x$gdb_needs_out_file_path = xyes + then + echo "dir ${srcdir}/config/"`dirname ${out_file}` >> .gdbinit + fi + if test "x$subdirs" != x; then + for s in $subdirs + do + echo "dir ${srcdir}/$s" >> .gdbinit + done + fi + echo "source ${srcdir}/.gdbinit" >> .gdbinit +fi + +# Define variables host_canonical and build_canonical +# because some Cygnus local changes in the Makefile depend on them. +build_canonical=${build} +host_canonical=${host} +target_subdir= +if test "${host}" != "${target}" ; then + target_subdir=${target}/ +fi + + + + +# If this is using newlib, then define inhibit_libc in +# LIBGCC2_CFLAGS. This will cause __eprintf to be left out of +# libgcc.a, but that's OK because newib should have its own version of +# assert.h. +inhibit_libc= +if test x$with_newlib = xyes; then + inhibit_libc=-Dinhibit_libc +fi + + +# Override SCHED_OBJ and SCHED_CFLAGS to enable the Haifa scheduler. +sched_prefix= +sched_cflags= +if test x$enable_haifa = xyes; then + echo "Using the Haifa scheduler." + sched_prefix=haifa- + sched_cflags=-DHAIFA +fi + + +if test x$enable_haifa != x; then + # Explicitly remove files that need to be recompiled for the Haifa scheduler. + for x in genattrtab.o toplev.o loop.o unroll.o *sched.o; do + if test -f $x; then + echo "Removing $x" + rm -f $x + fi + done +fi + +# If $(exec_prefix) exists and is not the same as $(prefix), then compute an +# absolute path for gcc_tooldir based on inserting the number of up-directory +# movements required to get from $(exec_prefix) to $(prefix) into the basic +# $(libsubdir)/@(unlibsubdir) based path. +# Don't set gcc_tooldir to tooldir since that's only passed in by the toplevel +# make and thus we'd get different behavior depending on where we built the +# sources. +if test x$exec_prefix = xNONE -o x$exec_prefix = x$prefix; then + gcc_tooldir='$(libsubdir)/$(unlibsubdir)/../$(target_alias)' +else +# An explanation of the sed strings: +# -e 's|^\$(prefix)||' matches and eliminates 'prefix' from 'exec_prefix' +# -e 's|/$||' match a trailing forward slash and eliminates it +# -e 's|^[^/]|/|' forces the string to start with a forward slash (*) +# -e 's|/[^/]*|../|g' replaces each occurance of / with ../ +# +# (*) Note this pattern overwrites the first character of the string +# with a forward slash if one is not already present. This is not a +# problem because the exact names of the sub-directories concerned is +# unimportant, just the number of them matters. +# +# The practical upshot of these patterns is like this: +# +# prefix exec_prefix result +# ------ ----------- ------ +# /foo /foo/bar ../ +# /foo/ /foo/bar ../ +# /foo /foo/bar/ ../ +# /foo/ /foo/bar/ ../ +# /foo /foo/bar/ugg ../../ +# + dollar='$$' + gcc_tooldir="\$(libsubdir)/\$(unlibsubdir)/\`echo \$(exec_prefix) | sed -e 's|^\$(prefix)||' -e 's|/\$(dollar)||' -e 's|^[^/]|/|' -e 's|/[^/]*|../|g'\`\$(target_alias)" +fi + + + +# Warn if using init_priority. +echo $ac_n "checking whether to enable init_priority by default""... $ac_c" 1>&6 +echo "configure:6735: checking whether to enable init_priority by default" >&5 +if test x$enable_init_priority != xyes; then + enable_init_priority=no +fi +echo "$ac_t""$enable_init_priority" 1>&6 + +# Nothing to do for FLOAT_H, float_format already handled. +objdir=`pwd` + + +# Process the language and host/target makefile fragments. +${CONFIG_SHELL-/bin/sh} $srcdir/configure.frag $srcdir "$subdirs" "$dep_host_xmake_file" "$dep_tmake_file" + +# Substitute configuration variables + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# Echo that links are built +if test x$host = x$target +then + str1="native " +else + str1="cross-" + str2=" from $host" +fi + +if test x$host != x$build +then + str3=" on a $build system" +fi + +if test "x$str2" != x || test "x$str3" != x +then + str4= +fi + +echo "Links are now set up to build a ${str1}compiler for ${target}$str4" 1>&2 + +if test "x$str2" != x || test "x$str3" != x +then + echo " ${str2}${str3}." 1>&2 +fi + +# Truncate the target if necessary +if test x$host_truncate_target != x; then + target=`echo $target | sed -e 's/\(..............\).*/\1/'` +fi + +# Configure the subdirectories +# AC_CONFIG_SUBDIRS($subdirs) + +# Create the Makefile +# and configure language subdirectories +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir + +trap 'rm -fr `echo "$all_outputs auto-host.h:config.in" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@target@%$target%g +s%@target_alias@%$target_alias%g +s%@target_cpu@%$target_cpu%g +s%@target_vendor@%$target_vendor%g +s%@target_os@%$target_os%g +s%@build@%$build%g +s%@build_alias@%$build_alias%g +s%@build_cpu@%$build_cpu%g +s%@build_vendor@%$build_vendor%g +s%@build_os@%$build_os%g +s%@CC@%$CC%g +s%@stage1_warn_cflags@%$stage1_warn_cflags%g +s%@SET_MAKE@%$SET_MAKE%g +s%@AWK@%$AWK%g +s%@LEX@%$LEX%g +s%@LEXLIB@%$LEXLIB%g +s%@LN@%$LN%g +s%@LN_S@%$LN_S%g +s%@RANLIB@%$RANLIB%g +s%@YACC@%$YACC%g +s%@INSTALL@%$INSTALL%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@CPP@%$CPP%g +s%@gnat@%$gnat%g +s%@vfprintf@%$vfprintf%g +s%@doprint@%$doprint%g +s%@manext@%$manext%g +s%@objext@%$objext%g +s%@gthread_flags@%$gthread_flags%g +s%@build_canonical@%$build_canonical%g +s%@host_canonical@%$host_canonical%g +s%@target_subdir@%$target_subdir%g +s%@inhibit_libc@%$inhibit_libc%g +s%@sched_prefix@%$sched_prefix%g +s%@sched_cflags@%$sched_cflags%g +s%@gcc_tooldir@%$gcc_tooldir%g +s%@dollar@%$dollar%g +s%@objdir@%$objdir%g +s%@subdirs@%$subdirs%g +s%@all_languages@%$all_languages%g +s%@all_boot_languages@%$all_boot_languages%g +s%@all_compilers@%$all_compilers%g +s%@all_lang_makefiles@%$all_lang_makefiles%g +s%@all_stagestuff@%$all_stagestuff%g +s%@all_diff_excludes@%$all_diff_excludes%g +s%@all_lib2funcs@%$all_lib2funcs%g +s%@all_headers@%$all_headers%g +s%@cpp_main@%$cpp_main%g +s%@extra_passes@%$extra_passes%g +s%@extra_programs@%$extra_programs%g +s%@extra_parts@%$extra_parts%g +s%@extra_c_objs@%$extra_c_objs%g +s%@extra_cxx_objs@%$extra_cxx_objs%g +s%@extra_cpp_objs@%$extra_cpp_objs%g +s%@extra_c_flags@%$extra_c_flags%g +s%@extra_objs@%$extra_objs%g +s%@host_extra_gcc_objs@%$host_extra_gcc_objs%g +s%@extra_headers_list@%$extra_headers_list%g +s%@dep_host_xmake_file@%$dep_host_xmake_file%g +s%@dep_tmake_file@%$dep_tmake_file%g +s%@out_file@%$out_file%g +s%@out_object_file@%$out_object_file%g +s%@md_file@%$md_file%g +s%@tm_file_list@%$tm_file_list%g +s%@build_xm_file_list@%$build_xm_file_list%g +s%@host_xm_file_list@%$host_xm_file_list%g +s%@lang_specs_files@%$lang_specs_files%g +s%@lang_options_files@%$lang_options_files%g +s%@lang_tree_files@%$lang_tree_files%g +s%@thread_file@%$thread_file%g +s%@objc_boehm_gc@%$objc_boehm_gc%g +s%@JAVAGC@%$JAVAGC%g +s%@gcc_version@%$gcc_version%g +s%@gcc_version_trigger@%$gcc_version_trigger%g +s%@local_prefix@%$local_prefix%g +s%@gcc_gxx_include_dir@%$gcc_gxx_include_dir%g +s%@fixincludes@%$fixincludes%g +s%@build_install_headers_dir@%$build_install_headers_dir%g +s%@build_exeext@%$build_exeext%g +s%@host_exeext@%$host_exeext%g +s%@float_h_file@%$float_h_file%g +s%@cc_set_by_configure@%$cc_set_by_configure%g +s%@stage_prefix_set_by_configure@%$stage_prefix_set_by_configure%g +s%@install@%$install%g +s%@symbolic_link@%$symbolic_link%g +/@target_overrides@/r $target_overrides +s%@target_overrides@%%g +/@host_overrides@/r $host_overrides +s%@host_overrides@%%g +s%@cross_defines@%$cross_defines%g +/@cross_overrides@/r $cross_overrides +s%@cross_overrides@%%g +/@build_overrides@/r $build_overrides +s%@build_overrides@%%g +/@language_fragments@/r $language_fragments +s%@language_fragments@%%g +/@language_hooks@/r $language_hooks +s%@language_hooks@%%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF + +. $srcdir/configure.lang +case x$CONFIG_HEADERS in +xauto-host.h:config.in) +echo > cstamp-h ;; +esac +# If the host supports symlinks, point stage[1234] at ../stage[1234] so +# bootstrapping and the installation procedure can still use +# CC="stage1/xgcc -Bstage1/". If the host doesn't support symlinks, +# 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. +if test "$symbolic_link" = "ln -s"; then + for d in .. ${subdirs} ; do + if test $d != ..; then + STARTDIR=`pwd` + cd $d + for t in stage1 stage2 stage3 stage4 include + do + rm -f $t + $symbolic_link ../$t $t 2>/dev/null + done + cd $STARTDIR + fi + done +else true ; fi + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/gcc_arm/configure.bat b/gcc_arm/configure.bat new file mode 100755 index 0000000..612453b --- /dev/null +++ b/gcc_arm/configure.bat @@ -0,0 +1,21 @@ +@echo off +if %1.==go32. goto call_go32 +if %1.==winnt. goto call_winnt +echo Usage: configure go32 or configure winnt cpu +goto END + +:call_go32 +call config\msdos\configure %1 %2 %3 %4 +goto END + +:call_winnt +if %2.==i386. goto really_call_winnt +if %2.==alpha. goto really_call_winnt +echo Usage: configure winnt i386 or configure winnt alpha +goto END +:really_call_winnt +call config\winnt\config-nt %1 %2 %3 %4 +goto END + +:END + diff --git a/gcc_arm/configure.frag b/gcc_arm/configure.frag new file mode 100755 index 0000000..4bdac94 --- /dev/null +++ b/gcc_arm/configure.frag @@ -0,0 +1,77 @@ +# configure.frag for GNU CC +# Process the host/target/language Makefile fragments. + +# Copyright (C) 1997 Free Software Foundation, Inc. + +#This file is part of GNU CC. + +#GNU CC is free software; you can redistribute it and/or modify +#it under the terms of the GNU General Public License as published by +#the Free Software Foundation; either version 2, or (at your option) +#any later version. + +#GNU CC is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with GNU CC; see the file COPYING. If not, write to +#the Free Software Foundation, 59 Temple Place - Suite 330, +#Boston, MA 02111-1307, USA. + +# First parameter is the source directory, second is list of subdirectories, +# third is list of host makefile fragments, fourth is list of target makefile +# fragments. + +srcdir=$1 +subdirs=$2 +xmake_files=$3 +tmake_files=$4 + +# Copy all the host makefile fragments into Make-host. + +rm -f Make-host +touch Make-host +for f in .. $xmake_files +do + if [ -f $f ] + then + cat $f >> Make-host + fi +done + +# Copy all the target makefile fragments into Make-target. + +rm -f Make-target +touch Make-target +for f in .. $tmake_files +do + if [ -f $f ] + then + cat $f >> Make-target + fi +done + +# Ensure the language build subdirectories exist. + +for subdir in . $subdirs +do + if [ $subdir != . ] + then + test -d $subdir || mkdir $subdir + fi +done + +# Now copy each language's Make-lang.in file to Make-lang. + +rm -f Make-lang +touch Make-lang + +for subdir in . $subdirs +do + if [ $subdir != . ] + then + cat $srcdir/$subdir/Make-lang.in >> Make-lang + fi +done diff --git a/gcc_arm/configure.in b/gcc_arm/configure.in new file mode 100755 index 0000000..5d801fa --- /dev/null +++ b/gcc_arm/configure.in @@ -0,0 +1,1656 @@ +# configure.in for GNU CC +# Process this file with autoconf to generate a configuration script. + +# Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc. + +#This file is part of GNU CC. + +#GNU CC is free software; you can redistribute it and/or modify +#it under the terms of the GNU General Public License as published by +#the Free Software Foundation; either version 2, or (at your option) +#any later version. + +#GNU CC is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with GNU CC; see the file COPYING. If not, write to +#the Free Software Foundation, 59 Temple Place - Suite 330, +#Boston, MA 02111-1307, USA. + +# Initialization and defaults +AC_PREREQ(2.12.1) +AC_INIT(tree.c) +AC_CONFIG_HEADER(auto-host.h:config.in) + +remove=rm +hard_link=ln +symbolic_link='ln -s' +copy=cp + +# Check for bogus environment variables. +# Test if LIBRARY_PATH contains the notation for the current directory +# since this would lead to problems installing/building glibc. +# LIBRARY_PATH contains the current directory if one of the following +# is true: +# - one of the terminals (":" and ";") is the first or last sign +# - two terminals occur directly after each other +# - the path contains an element with a dot in it +AC_MSG_CHECKING(LIBRARY_PATH variable) +changequote(,)dnl +case ${LIBRARY_PATH} in + [:\;]* | *[:\;] | *[:\;][:\;]* | *[:\;]. | .[:\;]*| . | *[:\;].[:\;]* ) + library_path_setting="contains current directory" + ;; + *) + library_path_setting="ok" + ;; +esac +changequote([,])dnl +AC_MSG_RESULT($library_path_setting) +if test "$library_path_setting" != "ok"; then +AC_MSG_ERROR([ +*** LIBRARY_PATH shouldn't contain the current directory when +*** building egcs. Please change the environment variable +*** and run configure again.]) +fi + +# Test if GCC_EXEC_PREFIX contains the notation for the current directory +# since this would lead to problems installing/building glibc. +# GCC_EXEC_PREFIX contains the current directory if one of the following +# is true: +# - one of the terminals (":" and ";") is the first or last sign +# - two terminals occur directly after each other +# - the path contains an element with a dot in it +AC_MSG_CHECKING(GCC_EXEC_PREFIX variable) +changequote(,)dnl +case ${GCC_EXEC_PREFIX} in + [:\;]* | *[:\;] | *[:\;][:\;]* | *[:\;]. | .[:\;]*| . | *[:\;].[:\;]* ) + gcc_exec_prefix_setting="contains current directory" + ;; + *) + gcc_exec_prefix_setting="ok" + ;; +esac +changequote([,])dnl +AC_MSG_RESULT($gcc_exec_prefix_setting) +if test "$gcc_exec_prefix_setting" != "ok"; then +AC_MSG_ERROR([ +*** GCC_EXEC_PREFIX shouldn't contain the current directory when +*** building egcs. Please change the environment variable +*** and run configure again.]) +fi + +# Check for additional parameters + +# With GNU ld +AC_ARG_WITH(gnu-ld, +[ --with-gnu-ld arrange to work with GNU ld.], +gnu_ld_flag="$with_gnu_ld", +gnu_ld_flag=no) + +# With pre-defined ld +AC_ARG_WITH(ld, +[ --with-ld arrange to use the specified ld (full pathname).], +DEFAULT_LINKER="$with_ld") +if test x"${DEFAULT_LINKER+set}" = x"set"; then + if test ! -x "$DEFAULT_LINKER"; then + AC_MSG_WARN([cannot execute: $DEFAULT_LINKER: check --with-ld or env. var. DEFAULT_LINKER]) + elif test "GNU" = `$DEFAULT_LINKER -v &1 | sed '1s/^GNU.*/GNU/;q'`; then + gnu_ld_flag=yes + fi + AC_DEFINE_UNQUOTED(DEFAULT_LINKER,"$DEFAULT_LINKER") +fi + +# With GNU as +AC_ARG_WITH(gnu-as, +[ --with-gnu-as arrange to work with GNU as.], +gas_flag="$with_gnu_as", +gas_flag=no) + +AC_ARG_WITH(as, +[ --with-as arrange to use the specified as (full pathname).], +DEFAULT_ASSEMBLER="$with_as") +if test x"${DEFAULT_ASSEMBLER+set}" = x"set"; then + if test ! -x "$DEFAULT_ASSEMBLER"; then + AC_MSG_WARN([cannot execute: $DEFAULT_ASSEMBLER: check --with-as or env. var. DEFAULT_ASSEMBLER]) + elif test "GNU" = `$DEFAULT_ASSEMBLER -v &1 | sed '1s/^GNU.*/GNU/;q'`; then + gas_flag=yes + fi + AC_DEFINE_UNQUOTED(DEFAULT_ASSEMBLER,"$DEFAULT_ASSEMBLER") +fi + +# With stabs +AC_ARG_WITH(stabs, +[ --with-stabs arrange to use stabs instead of host debug format.], +stabs="$with_stabs", +stabs=no) + +# With ELF +AC_ARG_WITH(elf, +[ --with-elf arrange to use ELF instead of host debug format.], +elf="$with_elf", +elf=no) + +# CYGNUS LOCAL: local_prefix +#local_prefix= +#AC_ARG_WITH(local-prefix, +#[ --with-local-prefix=DIR specifies directory to put local include.], +#[case "${withval}" in +#yes) AC_MSG_ERROR(bad value ${withval} given for local include directory prefix) ;; +#no) ;; +#*) local_prefix=$with_local_prefix ;; +#esac]) +local_prefix='$(prefix)' +# END CYGNUS LOCAL + +# Default local prefix if it is empty +if test x$local_prefix = x; then + local_prefix=/usr/local +fi + +# Don't set gcc_gxx_include_dir to gxx_include_dir since that's only +# passed in by the toplevel make and thus we'd get different behavior +# depending on where we built the sources. +gcc_gxx_include_dir= +# Specify the g++ header file directory +AC_ARG_WITH(gxx-include-dir, +[ --with-gxx-include-dir=DIR + specifies directory to put g++ header files.], +[case "${withval}" in +yes) AC_MSG_ERROR(bad value ${withval} given for g++ include directory) ;; +no) ;; +*) gcc_gxx_include_dir=$with_gxx_include_dir ;; +esac]) + +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/g++' + else + topsrcdir=${srcdir}/.. . ${srcdir}/../config.if +changequote(<<, >>)dnl + gcc_gxx_include_dir="\$(libsubdir)/\$(unlibsubdir)/..\`echo \$(exec_prefix) | sed -e 's|^\$(prefix)||' -e 's|/[^/]*|/..|g'\`/include/g++"-${libstdcxx_interface} +changequote([, ])dnl + fi +fi + +# Enable expensive internal checks +AC_ARG_ENABLE(checking, +[ --enable-checking enable expensive run-time checks.], +[case "${enableval}" in +yes) AC_DEFINE(ENABLE_CHECKING) ;; +no) ;; +*) AC_MSG_ERROR(bad value ${enableval} given for checking option) ;; +esac]) + +# Use cpplib+cppmain for the preprocessor, but don't link it with the compiler. +cpp_main=cccp +AC_ARG_ENABLE(cpplib, +[ --enable-cpplib use cpplib for the C preprocessor.], +if test x$enable_cpplib != xno; then + cpp_main=cppmain +fi) + +# Link cpplib into the compiler proper, for C/C++/ObjC. +AC_ARG_ENABLE(c-cpplib, +[ --enable-c-cpplib link cpplib directly into C and C++ compilers + (implies --enable-cpplib).], +if test x$enable_c_cpplib != xno; then + extra_c_objs="${extra_c_objs} libcpp.a" + extra_cxx_objs="${extra_cxx_objs} ../libcpp.a" + extra_c_flags="${extra_c_flags} -DUSE_CPPLIB=1" + cpp_main=cppmain +fi) + +# CYGNUS LOCAL mbchar +# Enable Multibyte Characters for C/C++ +AC_ARG_ENABLE(c-mbchar, +[ --enable-c-mbchar enable multibyte characters for C and C++. + --disable-c-mbchar disable multibyte characters for C and C++. ], +if test x$enable_c_mbchar != xno; then + extra_c_flags="${extra_c_flags} -DMULTIBYTE_CHARS=1" +fi, +extra_c_flags="${extra_c_flags} -DMULTIBYTE_CHARS=1" +) +# END CYGNUS LOCAL + +# Enable Haifa scheduler. +AC_ARG_ENABLE(haifa, +[ --enable-haifa use the experimental scheduler. + --disable-haifa don't use the experimental scheduler for the + targets which normally enable it.]) +# Fast fixincludes +# +# This is a work in progress... +AC_ARG_WITH(fast-fixincludes, +[ --with-fast-fixincludes use a faster fixinclude program (experimental)], +fast_fixinc="$with_fast_fixincludes", +fast_fixinc=no) + +# Enable init_priority. +AC_ARG_ENABLE(init-priority, +[ --enable-init-priority use attributes to assign initialization order + for static objects. + --disable-init-priority conform to ISO C++ rules for ordering static objects + (i.e. initialized in order of declaration). ], +if test x$enable_init_priority != xno; then + extra_c_flags="${extra_c_flags} -DUSE_INIT_PRIORITY" +fi) + +# Enable threads +# Pass with no value to take the default +# Pass with a value to specify a thread package +AC_ARG_ENABLE(threads, +[ --enable-threads enable thread usage for target GCC. + --enable-threads=LIB use LIB thread package for target GCC.], +if test x$enable_threads = xno; then + enable_threads='' +fi, +enable_threads='') + +enable_threads_flag=$enable_threads +# Check if a valid thread package +case x${enable_threads_flag} in + x | xno) + # No threads + target_thread_file='single' + ;; + xyes) + # default + target_thread_file='' + ;; + # CYGNUS LOCAL java + xdecosf1 | xirix | xmach | xos2 | xposix | xpthreads | xsingle | \ + xsolaris | xwin32 | xdce | xvxworks | xqt) + target_thread_file=$enable_threads_flag + ;; + *) + echo "$enable_threads is an unknown thread package" 1>&2 + exit 1 + ;; +esac + +AC_ARG_ENABLE(objc-gc, +[ --enable-objc-gc enable the use of Boehm's garbage collector with + the GNU Objective-C runtime.], +if [[[ x$enable_objc_gc = xno ]]]; then + objc_boehm_gc='' +else + objc_boehm_gc=1 +fi, +objc_boehm_gc='') + +AC_ARG_ENABLE(java-gc, +changequote(<<,>>)dnl +<< --enable-java-gc=TYPE choose garbage collector [boehm]>>, +changequote([,]) + JAVAGC=$enableval, + JAVAGC=boehm) + +AC_ARG_WITH(dwarf2, +[ --enable-dwarf2 enable DWARF2 debugging as default.], +dwarf2="$with_dwarf2", +dwarf2=no) + +# Determine the host, build, and target systems +AC_CANONICAL_SYSTEM + +# Find the native compiler +AC_PROG_CC + +# 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'. +if test "x$GCC" = "xyes"; then + stage1_warn_cflags='$(WARN_CFLAGS)' +else + stage1_warn_cflags="" +fi +AC_SUBST(stage1_warn_cflags) + +AC_PROG_MAKE_SET + +AC_MSG_CHECKING([whether a default assembler was specified]) +if test x"${DEFAULT_ASSEMBLER+set}" = x"set"; then + if test x"$with_gas" = x"no"; then + AC_MSG_RESULT([yes ($DEFAULT_ASSEMBLER)]) + else + AC_MSG_RESULT([yes ($DEFAULT_ASSEMBLER - GNU as)]) + fi +else + AC_MSG_RESULT(no) +fi + +AC_MSG_CHECKING([whether a default linker was specified]) +if test x"${DEFAULT_LINKER+set}" = x"set"; then + if test x"$with_gnu_ld" = x"no"; then + AC_MSG_RESULT([yes ($DEFAULT_LINKER)]) + else + AC_MSG_RESULT([yes ($DEFAULT_LINKER - GNU ld)]) + fi +else + AC_MSG_RESULT(no) +fi + +# Find some useful tools +AC_PROG_AWK +AC_PROG_LEX +GCC_PROG_LN +GCC_PROG_LN_S +GCC_C_VOLATILE +AC_PROG_RANLIB +AC_PROG_YACC +EGCS_PROG_INSTALL + +AC_HEADER_STDC +AC_HEADER_TIME +GCC_HEADER_STRING +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS(limits.h stddef.h string.h strings.h stdlib.h time.h fcntl.h unistd.h stab.h sys/file.h sys/time.h sys/resource.h sys/param.h sys/times.h sys/stat.h) + +# Check for thread headers. +AC_CHECK_HEADER(thread.h, [have_thread_h=yes], [have_thread_h=]) +AC_CHECK_HEADER(pthread.h, [have_pthread_h=yes], [have_pthread_h=]) + +# See if GNAT has been installed +AC_CHECK_PROG(gnat, gnatbind, yes, no) + +# See if the system preprocessor understands the ANSI C preprocessor +# stringification operator. +AC_MSG_CHECKING(whether cpp understands the stringify operator) +AC_CACHE_VAL(gcc_cv_c_have_stringify, +[AC_TRY_COMPILE(, +[#define S(x) #x +char *test = S(foo);], +gcc_cv_c_have_stringify=yes, gcc_cv_c_have_stringify=no)]) +AC_MSG_RESULT($gcc_cv_c_have_stringify) +if test $gcc_cv_c_have_stringify = yes; then + AC_DEFINE(HAVE_CPP_STRINGIFY) +fi + +# Use only if it exists, +# doesn't clash with , and declares intmax_t. +AC_MSG_CHECKING(for inttypes.h) +AC_CACHE_VAL(gcc_cv_header_inttypes_h, +[AC_TRY_COMPILE( + [#include +#include ], + [intmax_t i = -1;], + [gcc_cv_header_inttypes_h=yes], + gcc_cv_header_inttypes_h=no)]) +AC_MSG_RESULT($gcc_cv_header_inttypes_h) +if test $gcc_cv_header_inttypes_h = yes; then + AC_DEFINE(HAVE_INTTYPES_H) +fi + +AC_CHECK_FUNCS(strtoul bsearch strerror putenv popen bcopy bzero bcmp \ + index rindex strchr strrchr kill getrlimit setrlimit atoll atoq \ + sysconf isascii gettimeofday strsignal putc_unlocked fputc_unlocked \ + fputs_unlocked) + +# Make sure wchar_t is available +#AC_CHECK_TYPE(wchar_t, unsigned int) + +GCC_FUNC_VFPRINTF_DOPRNT +GCC_FUNC_PRINTF_PTR +AC_FUNC_VFORK + +GCC_NEED_DECLARATIONS(malloc realloc calloc free bcopy bzero bcmp \ + index rindex getenv atol sbrk abort atof strerror getcwd getwd \ + strsignal) + +GCC_NEED_DECLARATIONS(getrlimit setrlimit, [ +#include +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif +]) + +AC_DECL_SYS_SIGLIST + +# File extensions +manext='.1' +objext='.o' +AC_SUBST(manext) +AC_SUBST(objext) + +build_xm_file= +build_xm_defines= +build_install_headers_dir=install-headers-tar +build_exeext= +host_xm_file= +host_xm_defines= +host_xmake_file= +host_truncate_target= +host_exeext= + +# Decode the host machine, then the target machine. +# For the host machine, we save the xm_file variable as host_xm_file; +# then we decode the target machine and forget everything else +# that came from the host machine. +for machine in $build $host $target; do + + out_file= + xmake_file= + tmake_file= + extra_headers= + extra_passes= + extra_parts= + extra_programs= + extra_objs= + extra_host_objs= + extra_gcc_objs= + xm_defines= + float_format= + # Set this to override the default target model. + target_cpu_default= + # Set this to control which fixincludes program to use. + if test x$fast_fixinc != xyes; then + fixincludes=fixincludes + else fixincludes=fixinc.sh ; fi + # Set this to control how the header file directory is installed. + install_headers_dir=install-headers-tar + # Set this to a non-empty list of args to pass to cpp if the target + # wants its .md file passed through cpp. + md_cppflags= + # Set this if directory names should be truncated to 14 characters. + truncate_target= + # Set this if gdb needs a dir command with `dirname $out_file` + gdb_needs_out_file_path= + # Set this if the build machine requires executables to have a + # file name suffix. + exeext= + # Set this to control which thread package will be used. + thread_file= + # Reinitialize these from the flag values every loop pass, since some + # configure entries modify them. + gas="$gas_flag" + gnu_ld="$gnu_ld_flag" + enable_threads=$enable_threads_flag + + # Set default cpu_type, tm_file and xm_file so it can be updated in + # each machine entry. + cpu_type=`echo $machine | sed 's/-.*$//'` + case $machine in + alpha*-*-*) + cpu_type=alpha + ;; + arm*-*-*) + cpu_type=arm + ;; + c*-convex-*) + cpu_type=convex + ;; +changequote(,)dnl + i[34567]86-*-*) +changequote([,])dnl + cpu_type=i386 + ;; + hppa*-*-*) + cpu_type=pa + ;; + m68000-*-*) + cpu_type=m68k + ;; + mips*-*-*) + cpu_type=mips + ;; + powerpc*-*-*) + cpu_type=rs6000 + ;; + pyramid-*-*) + cpu_type=pyr + ;; + sparc*-*-*) + cpu_type=sparc + ;; + esac + + tm_file=${cpu_type}/${cpu_type}.h + xm_file=${cpu_type}/xm-${cpu_type}.h + + # Set the default macros to define for GNU/Linux systems. + case $machine in + *-*-linux-gnu*) + xm_defines="HAVE_ATEXIT POSIX BSTRING" + ;; + esac + + case $machine in + # Support site-specific machine types. + arm*-*-elf) + tm_file=arm/unknown-elf.h + tmake_file=arm/t-arm-elf + ;; + + thumb-*-elf) + tm_file=arm/telf.h + out_file=arm/thumb.c + xm_file=arm/xm-thumb.h + md_file=arm/thumb.md + tmake_file=arm/t-thumb-elf + fixincludes=Makefile.in # There is nothing to fix + ;; + + *) + echo "Configuration $machine not supported" 1>&2 + exit 1 + ;; + esac + + case $machine in + *-*-linux-gnu*) + ;; # Existing GNU/Linux systems do not use the GNU setup. + *-*-gnu*) + # On the GNU system, the setup is just about the same on + # each different CPU. The specific machines that GNU + # supports are matched above and just set $cpu_type. + xm_file="xm-gnu.h ${xm_file}" + tm_file=${cpu_type}/gnu.h + extra_parts="crtbegin.o crtend.o crtbeginS.o crtendS.o" + # GNU always uses ELF. + elf=yes + # GNU tools are the only tools. + gnu_ld=yes + gas=yes + # On GNU, the headers are already okay. + fixincludes=Makefile.in + xmake_file=x-linux # These details are the same as Linux. + tmake_file=t-gnu # These are not. + ;; + *-*-sysv4*) + fixincludes=fixinc.svr4 + xmake_try_sysv=x-sysv + install_headers_dir=install-headers-cpio + ;; + *-*-sysv*) + install_headers_dir=install-headers-cpio + ;; + esac + + # Distinguish i[34567]86 + # Also, do not run mips-tfile on MIPS if using gas. + # Process --with-cpu= for PowerPC/rs6000 + target_cpu_default2= + case $machine in + i486-*-*) + target_cpu_default2=1 + ;; + i586-*-*) + target_cpu_default2=2 + ;; + i686-*-* | i786-*-*) + target_cpu_default2=3 + ;; + alpha*-*-*) + case $machine in + alphaev6*) + target_cpu_default2="MASK_CPU_EV6|MASK_BWX|MASK_CIX|MASK_MAX" + ;; + alphapca56*) + target_cpu_default2="MASK_CPU_EV5|MASK_BWX|MASK_MAX" + ;; + alphaev56*) + target_cpu_default2="MASK_CPU_EV5|MASK_BWX" + ;; + alphaev5*) + target_cpu_default2="MASK_CPU_EV5" + ;; + esac + + if test x$gas = xyes + then + if test "$target_cpu_default2" = "" + then + target_cpu_default2="MASK_GAS" + else + target_cpu_default2="${target_cpu_default2}|MASK_GAS" + fi + fi + ;; + # CYGNUS LOCAL m68k embedded + m68*-*-*) + target_cpu_default2=M68K_CPU_"`echo $machine | sed 's/-.*$//'`" + ;; + # END CYGNUS LOCAL + arm*-*-*) + case "x$with_cpu" in + x) + # The most generic + target_cpu_default2="TARGET_CPU_generic" + ;; + + # Distinguish cores, and major variants + # arm7m doesn't exist, but D & I don't affect code + xarm[[23678]] | xarm250 | xarm[[67]][[01]]0 \ + | xarm7m | xarm7dm | xarm7dmi | xarm7tdmi \ + | xarm7100 | xarm7500 | xarm7500fe | xarm810 \ + | xstrongarm | xstrongarm110) + target_cpu_default2="TARGET_CPU_$with_cpu" + ;; + + xyes | xno) + echo "--with-cpu must be passed a value" 1>&2 + exit 1 + ;; + + *) + if test x$pass2done = xyes + then + echo "Unknown cpu used with --with-cpu=$with_cpu" 1>&2 + exit 1 + fi + ;; + esac + ;; + + mips*-*-ecoff* | mips*-*-elf*) + if test x$gas = xyes + then + if test x$gnu_ld = xyes + then + target_cpu_default2=20 + else + target_cpu_default2=16 + fi + fi + ;; + mips*-*-*) + if test x$gas = xyes + then + target_cpu_default2=16 + fi + ;; + powerpc*-*-* | rs6000-*-*) + case "x$with_cpu" in + x) + ;; + + xcommon | xpower | xpower2 | xpowerpc | xrios \ + | xrios1 | xrios2 | xrsc | xrsc1 \ + | x601 | x602 | x603 | x603e | x604 | x604e | x620 \ + | x403 | x505 | x801 | x821 | x823 | x860) + target_cpu_default2="\"$with_cpu\"" + ;; + + xyes | xno) + echo "--with-cpu must be passed a value" 1>&2 + exit 1 + ;; + + *) + if test x$pass2done = xyes + then + echo "Unknown cpu used with --with-cpu=$with_cpu" 1>&2 + exit 1 + fi + ;; + esac + ;; + sparc*-*-*) + case ".$with_cpu" in + .) + target_cpu_default2=TARGET_CPU_"`echo $machine | sed 's/-.*$//'`" + ;; + # CYGNUS LOCAL sp86 + .supersparc | .hypersparc | .ultrasparc \ + | .sparclite | .sparc86x | .v7 | .v8 | .v9) + target_cpu_default2="TARGET_CPU_$with_cpu" + ;; + *) + if test x$pass2done = xyes + then + echo "Unknown cpu used with --with-cpu=$with_cpu" 1>&2 + exit 1 + fi + ;; + esac + ;; + esac + + if test "$target_cpu_default2" != "" + then + if test "$target_cpu_default" != "" + then + target_cpu_default="(${target_cpu_default}|${target_cpu_default2})" + else + target_cpu_default=$target_cpu_default2 + fi + fi + +# Save data on machine being used to compile GCC in build_xm_file. +# Save data on host machine in vars host_xm_file and host_xmake_file. + if test x$pass1done = x + then + if test x"$xm_file" = x + then build_xm_file=$cpu_type/xm-$cpu_type.h + else build_xm_file=$xm_file + fi + build_xm_defines=$xm_defines + build_install_headers_dir=$install_headers_dir + build_exeext=$exeext + pass1done=yes + else + if test x$pass2done = x + then + if test x"$xm_file" = x + then host_xm_file=$cpu_type/xm-$cpu_type.h + else host_xm_file=$xm_file + fi + host_xm_defines=$xm_defines + if test x"$xmake_file" = x + then xmake_file=$cpu_type/x-$cpu_type + fi + host_xmake_file="$xmake_file" + host_truncate_target=$truncate_target + host_extra_gcc_objs=$extra_gcc_objs + host_extra_objs=$extra_host_objs + host_exeext=$exeext + pass2done=yes + fi + fi +done + +extra_objs="${host_extra_objs} ${extra_objs}" + +# Default the target-machine variables that were not explicitly set. +if test x"$tm_file" = x +then tm_file=$cpu_type/$cpu_type.h; fi + +if test x$extra_headers = x +then extra_headers=; fi + +if test x"$xm_file" = x +then xm_file=$cpu_type/xm-$cpu_type.h; fi + +if test x$md_file = x +then md_file=$cpu_type/$cpu_type.md; fi + +if test x$out_file = x +then out_file=$cpu_type/$cpu_type.c; fi + +if test x"$tmake_file" = x +then tmake_file=$cpu_type/t-$cpu_type +fi + +if test x"$dwarf2" = xyes +then tm_file="tm-dwarf2.h $tm_file" +fi + +if test x$float_format = x +then float_format=i64 +fi + +if test $float_format = none +then float_h_file=Makefile.in +else float_h_file=float-$float_format.h +fi + +if test x$enable_haifa = x +then + case $target in + alpha*-* | hppa*-* | powerpc*-* | rs6000-* | *sparc*-* | m32r*-*) + enable_haifa=yes;; + esac +fi + +# Say what files are being used for the output code and MD file. +echo "Using \`$srcdir/config/$out_file' to output insns." +echo "Using \`$srcdir/config/$md_file' as machine description file." + +count=a +for f in $tm_file; do + count=${count}x +done +if test $count = ax; then + echo "Using \`$srcdir/config/$tm_file' as target machine macro file." +else + echo "Using the following target machine macro files:" + for f in $tm_file; do + echo " $srcdir/config/$f" + done +fi + +count=a +for f in $host_xm_file; do + count=${count}x +done +if test $count = ax; then + echo "Using \`$srcdir/config/$host_xm_file' as host machine macro file." +else + echo "Using the following host machine macro files:" + for f in $host_xm_file; do + echo " $srcdir/config/$f" + done +fi + +if test "$host_xm_file" != "$build_xm_file"; then + count=a + for f in $build_xm_file; do + count=${count}x + done + if test $count = ax; then + echo "Using \`$srcdir/config/$build_xm_file' as build machine macro file." + else + echo "Using the following build machine macro files:" + for f in $build_xm_file; do + echo " $srcdir/config/$f" + done + fi +fi + +if test x$thread_file = x; then + if test x$target_thread_file != x; then + thread_file=$target_thread_file + else + thread_file='single' + fi +fi + +# Set up the header files. +# $links is the list of header files to create. +# $vars is the list of shell variables with file names to include. +# auto-host.h is the file containing items generated by autoconf and is +# the first file included by config.h. +null_defines= +host_xm_file="auto-host.h gansidecl.h ${host_xm_file}" + +# If host=build, it is correct to have hconfig include auto-host.h +# as well. If host!=build, we are in error and need to do more +# work to find out the build config parameters. +if test x$host = x$build +then + build_xm_file="auto-host.h gansidecl.h ${build_xm_file}" +else + # We create a subdir, then run autoconf in the subdir. + # To prevent recursion we set host and build for the new + # invocation of configure to the build for this invocation + # of configure. + tempdir=build.$$ + rm -rf $tempdir + mkdir $tempdir + cd $tempdir + case ${srcdir} in + /*) realsrcdir=${srcdir};; + *) realsrcdir=../${srcdir};; + esac + CC=${CC_FOR_BUILD} ${realsrcdir}/configure \ + --target=$target --host=$build --build=$build + + # We just finished tests for the build machine, so rename + # the file auto-build.h in the gcc directory. + mv auto-host.h ../auto-build.h + cd .. + rm -rf $tempdir + build_xm_file="auto-build.h gansidecl.h ${build_xm_file}" +fi + + +xm_file="gansidecl.h ${xm_file}" +tm_file="gansidecl.h ${tm_file}" + +vars="host_xm_file tm_file xm_file build_xm_file" +links="config.h tm.h tconfig.h hconfig.h" +defines="host_xm_defines null_defines xm_defines build_xm_defines" + +rm -f config.bak +if test -f config.status; then mv -f config.status config.bak; fi + +# Make the links. +while test -n "$vars" +do + set $vars; var=$1; shift; vars=$* + set $links; link=$1; shift; links=$* + set $defines; define=$1; shift; defines=$* + + rm -f $link + + # Define TARGET_CPU_DEFAULT if the system wants one. + # This substitutes for lots of *.h files. + if test "$target_cpu_default" != "" -a $link = tm.h + then + echo "#define TARGET_CPU_DEFAULT ($target_cpu_default)" >>$link + fi + + for file in `eval echo '$'$var`; do + echo "#include \"$file\"" >>$link + done + + for def in `eval echo '$'$define`; do + echo "#ifndef $def" >>$link + echo "#define $def" >>$link + echo "#endif" >>$link + done +done + +# Truncate the target if necessary +if test x$host_truncate_target != x; then + target=`echo $target | sed -e 's/\(..............\).*/\1/'` +fi + +# 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 +changequote(,)dnl +gcc_version=`sed -e 's/.*\"\([^ \"]*\)[ \"].*/\1/' < ${gcc_version_trigger}` +changequote([,])dnl + +# Get an absolute path to the GCC top-level source directory +holddir=`pwd` +cd $srcdir +topdir=`pwd` +cd $holddir + +# Conditionalize the makefile for this host machine. +# Make-host contains the concatenation of all host makefile fragments +# [there can be more than one]. This file is built by configure.frag. +host_overrides=Make-host +dep_host_xmake_file= +for f in .. ${host_xmake_file} +do + if test -f ${srcdir}/config/$f + then + dep_host_xmake_file="${dep_host_xmake_file} ${srcdir}/config/$f" + fi +done + +# Conditionalize the makefile for this target machine. +# Make-target contains the concatenation of all host makefile fragments +# [there can be more than one]. This file is built by configure.frag. +target_overrides=Make-target +dep_tmake_file= +for f in .. ${tmake_file} +do + if test -f ${srcdir}/config/$f + then + dep_tmake_file="${dep_tmake_file} ${srcdir}/config/$f" + fi +done + +# 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 +if $symbolic_link $srcdir/gcc.c symtest.tem 2>/dev/null +then + cc_set_by_configure="\$(CC)" + 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\`" + 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= +for f in $tm_file; do + if test $f != "gansidecl.h" ; then + tm_file_list="${tm_file_list} \$(srcdir)/config/$f" + else + tm_file_list="${tm_file_list} $f" + fi +done + +host_xm_file_list= +for f in $host_xm_file; do + if test $f != "auto-host.h" -a $f != "gansidecl.h" ; then + host_xm_file_list="${host_xm_file_list} \$(srcdir)/config/$f" + else + host_xm_file_list="${host_xm_file_list} $f" + fi +done + +build_xm_file_list= +for f in $build_xm_file; do + if test $f != "auto-build.h" -a $f != "auto-host.h" -a $f != "gansidecl.h" ; then + build_xm_file_list="${build_xm_file_list} \$(srcdir)/config/$f" + else + build_xm_file_list="${build_xm_file_list} $f" + fi +done + +# Define macro CROSS_COMPILE in compilation +# if this is a cross-compiler. +# Also use all.cross instead of all.internal +# and add cross-make to Makefile. +cross_overrides="/dev/null" +if test x$host != x$target +then + cross_defines="CROSS=-DCROSS_COMPILE" + cross_overrides="${topdir}/cross-make" +fi + +# When building gcc with a cross-compiler, we need to fix a few things. +# This must come after cross-make as we want all.build to override +# all.cross. +build_overrides="/dev/null" +if test x$build != x$host +then + build_overrides="${topdir}/build-make" +fi + +# Expand extra_headers to include complete path. +# This substitutes for lots of t-* files. +extra_headers_list= +if test "x$extra_headers" = x +then true +else + # Prepend ${srcdir}/ginclude/ to every entry in extra_headers. + for file in $extra_headers; + do + extra_headers_list="${extra_headers_list} \$(srcdir)/ginclude/${file}" + done +fi + +# NEED TO CONVERT +# Set MD_DEPS if the real md file is in md.pre-cpp. +# Set MD_CPP to the cpp to pass the md file through. Md files use ';' +# for line oriented comments, so we must always use a GNU cpp. If +# building gcc with a cross compiler, use the cross compiler just +# built. Otherwise, we can use the cpp just built. +md_file_sub= +if test "x$md_cppflags" = x +then + md_file_sub=$srcdir/config/$md_file +else + md_file=md +fi + +# If we have gas in the build tree, make a link to it. +if test -f ../gas/Makefile; then + rm -f as; $symbolic_link ../gas/as-new$host_exeext as$host_exeext 2>/dev/null +fi + +# If we have nm in the build tree, make a link to it. +if test -f ../binutils/Makefile; then + rm -f nm; $symbolic_link ../binutils/nm-new$host_exeext nm$host_exeext 2>/dev/null +fi + +# If we have ld in the build tree, make a link to it. +if test -f ../ld/Makefile; then +# rm -f ld; $symbolic_link ../ld/ld-new$host_exeext ld$host_exeext 2>/dev/null +fi + +# Figure out what assembler alignment features are present. +AC_MSG_CHECKING(assembler alignment features) +gcc_cv_as= +gcc_cv_as_alignment_features= +gcc_cv_as_gas_srcdir=`echo $srcdir | sed -e 's,/gcc$,,'`/gas +if test -x "$DEFAULT_ASSEMBLER"; then + gcc_cv_as="$DEFAULT_ASSEMBLER" +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$host_exeext +elif test -f $gcc_cv_as_gas_srcdir/configure.in -a -f ../gas/Makefile; then + # Single tree build which includes gas. + for f in $gcc_cv_as_gas_srcdir/configure $gcc_cv_as_gas_srcdir/configure.in $gcc_cv_as_gas_srcdir/Makefile.in + do +changequote(,)dnl + gcc_cv_gas_version=`grep '^VERSION=[0-9]*\.[0-9]*' $f` +changequote([,])dnl + if test x$gcc_cv_gas_version != x; then + break + fi + done +changequote(,)dnl + gcc_cv_gas_major_version=`expr "$gcc_cv_gas_version" : "VERSION=\([0-9]*\)"` + gcc_cv_gas_minor_version=`expr "$gcc_cv_gas_version" : "VERSION=[0-9]*\.\([0-9]*\)"` +changequote([,])dnl + if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x; then + # Gas version 2.6 and later support for .balign and .p2align. + # bytes to skip when using .p2align. + if test "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 6 -o "$gcc_cv_gas_major_version" -gt 2; then + gcc_cv_as_alignment_features=".balign and .p2align" + AC_DEFINE(HAVE_GAS_BALIGN_AND_P2ALIGN) + fi + # Gas version 2.8 and later support specifying the maximum + # bytes to skip when using .p2align. + if test "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 8 -o "$gcc_cv_gas_major_version" -gt 2; then + gcc_cv_as_alignment_features=".p2align including maximum skip" + AC_DEFINE(HAVE_GAS_MAX_SKIP_P2ALIGN) + fi + fi +elif test x$host = x$target; then + # Native build. + gcc_cv_as=as$host_exeext +fi +if test x$gcc_cv_as != x; then + # Check if we have .balign and .p2align + echo ".balign 4" > conftest.s + echo ".p2align 2" >> conftest.s + if $gcc_cv_as -o conftest.o conftest.s > /dev/null 2>&1; then + gcc_cv_as_alignment_features=".balign and .p2align" + AC_DEFINE(HAVE_GAS_BALIGN_AND_P2ALIGN) + fi + rm -f conftest.s conftest.o + # Check if specifying the maximum bytes to skip when + # using .p2align is supported. + echo ".p2align 4,,7" > conftest.s + if $gcc_cv_as -o conftest.o conftest.s > /dev/null 2>&1; then + gcc_cv_as_alignment_features=".p2align including maximum skip" + AC_DEFINE(HAVE_GAS_MAX_SKIP_P2ALIGN) + fi + rm -f conftest.s conftest.o +fi +AC_MSG_RESULT($gcc_cv_as_alignment_features) + +AC_MSG_CHECKING(assembler subsection support) +gcc_cv_as_subsections= +if test x$gcc_cv_as != x; then + # Check if we have .subsection + echo ".subsection 1" > conftest.s + if $gcc_cv_as -o conftest.o conftest.s > /dev/null 2>&1; then + gcc_cv_as_subsections=".subsection" + if test -x nm$host_exeext; then + gcc_cv_nm=./nm$host_exeext + elif test x$host = x$target; then + # Native build. + gcc_cv_nm=nm$host_exeext + fi + if test x$gcc_cv_nm != x; then + cat > conftest.s < /dev/null 2>&1; then + $gcc_cv_nm conftest.o | grep conftest_label1 > conftest.nm1 + $gcc_cv_nm conftest.o | grep conftest_label2 | sed -e 's/label2/label1/' > conftest.nm2 + if cmp conftest.nm1 conftest.nm2 > /dev/null 2>&1; then + : + else + gcc_cv_as_subsections="working .subsection -1" + AC_DEFINE(HAVE_GAS_SUBSECTION_ORDERING) + fi + fi + fi + fi + rm -f conftest.s conftest.o conftest.nm1 conftest.nm2 +fi +AC_MSG_RESULT($gcc_cv_as_subsections) + +# 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. +if test x"${enable_languages+set}" != xset; then + if test x"${LANGUAGES+set}" = xset; then + enable_languages="`echo ${LANGUAGES} | tr ' ' ','`" + else + enable_languages=all + fi +fi +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) ;; + # CYGNUS LOCAL nofortran/law + ${srcdir}/f/config-lang.in) + if [[ x$enable_fortran = xyes ]]; then + subdirs="$subdirs `echo $lang | sed -e 's,^.*/\([[^/]]*\)/config-lang.in$,\1,'`" + fi + ;; + ${srcdir}/objc/config-lang.in) + if [[ x$enable_objc = xyes ]]; then + subdirs="$subdirs `echo $lang | sed -e 's,^.*/\([[^/]]*\)/config-lang.in$,\1,'`" + fi + ;; + ${srcdir}/ch/config-lang.in) + if [[ x$enable_chill = xyes ]]; then + subdirs="$subdirs `echo $lang | sed -e 's,^.*/\([[^/]]*\)/config-lang.in$,\1,'`" + fi + ;; + # END CYGNUS LOCAL +changequote(,)dnl + ${srcdir}/ada/config-lang.in) + if test x$gnat = xyes ; then + subdirs="$subdirs `echo $lang | sed -e 's,^.*/\([^/]*\)/config-lang.in$,\1,'`" + fi + ;; +changequote(,)dnl + *) + 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 + if test x"${enable_languages}" = xall; then + add_this_lang=yes + else + case "${enable_languages}" in + ${lang_alias} | "${lang_alias},"* | *",${lang_alias},"* | *",${lang_alias}" ) + add_this_lang=yes + ;; + * ) + add_this_lang=no + ;; + esac + fi + if test x"${add_this_lang}" = xyes; then + case $lang in + ${srcdir}/ada/config-lang.in) + if test x$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 + ;; +changequote([,])dnl + esac +done + +# 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 +# CYGNUS LOCAL java quickthreads +# qt is a library we build. So if we're using for it, and it is in +# our source tree, then we must look there for includes. +if test $thread_file = qt && test -d $srcdir/../qthreads; then + gthread_flags="$gthread_flags -I\$(srcdir)/../qthreads" +fi +# END CYGNUS LOCAL +AC_SUBST(gthread_flags) + +# 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. + +lang_specs_files= +lang_options_files= +lang_tree_files= +rm -f specs.h options.h gencheck.h +touch specs.h options.h gencheck.h +for subdir in . $subdirs +do + if test -f $srcdir/$subdir/lang-specs.h; then + echo "#include \"$subdir/lang-specs.h\"" >>specs.h + lang_specs_files="$lang_specs_files $srcdir/$subdir/lang-specs.h" + fi + if test -f $srcdir/$subdir/lang-options.h; then + echo "#include \"$subdir/lang-options.h\"" >>options.h + lang_options_files="$lang_options_files $srcdir/$subdir/lang-options.h" + fi + if test -f $srcdir/$subdir/$subdir-tree.def; then + echo "#include \"$subdir/$subdir-tree.def\"" >>gencheck.h + 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_diff_excludes= +all_outputs=Makefile +# List of language makefile fragments. +all_lang_makefiles= +all_headers= +all_lib2funcs= + +# 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. +# We accumulate them and plug them into the main Makefile. +# The other mechanism is a set of hooks for each of the main targets +# like `clean', `install', etc. + +language_fragments="Make-lang" +language_hooks="Make-hooks" +oldstyle_subdirs= + +for s in .. $subdirs +do + if test $s != ".." + then + language= + boot_language= + compilers= + stagestuff= + diff_excludes= + headers= + outputs= + lib2funcs= + . ${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_makefiles="$all_lang_makefiles ${srcdir}/$s/Make-lang.in ${srcdir}/$s/Makefile.in" + 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_diff_excludes="$all_diff_excludes $diff_excludes" + all_headers="$all_headers $headers" + all_outputs="$all_outputs $outputs" + if test x$outputs = x + then + oldstyle_subdirs="$oldstyle_subdirs $s" + fi + all_lib2funcs="$all_lib2funcs $lib2funcs" + fi +done + +# Since we can't use `::' targets, we link each language in +# with a set of hooks, reached indirectly via lang.${target}. + +rm -f Make-hooks +touch Make-hooks +target_list="all.build all.cross start.encap rest.encap \ + info dvi \ + install-normal install-common install-info install-man \ + uninstall distdir \ + mostlyclean clean distclean extraclean maintainer-clean \ + stage1 stage2 stage3 stage4" +for t in $target_list +do + x= + for l in .. $all_languages + do + if test $l != ".."; then + x="$x $l.$t" + fi + done + echo "lang.$t: $x" >> Make-hooks +done + +# If we're not building in srcdir, create .gdbinit. + +if test ! -f Makefile.in; then + echo "dir ." > .gdbinit + echo "dir ${srcdir}" >> .gdbinit + if test x$gdb_needs_out_file_path = xyes + then + echo "dir ${srcdir}/config/"`dirname ${out_file}` >> .gdbinit + fi + if test "x$subdirs" != x; then + for s in $subdirs + do + echo "dir ${srcdir}/$s" >> .gdbinit + done + fi + echo "source ${srcdir}/.gdbinit" >> .gdbinit +fi + +# Define variables host_canonical and build_canonical +# because some Cygnus local changes in the Makefile depend on them. +build_canonical=${build} +host_canonical=${host} +target_subdir= +if test "${host}" != "${target}" ; then + target_subdir=${target}/ +fi +AC_SUBST(build_canonical) +AC_SUBST(host_canonical) +AC_SUBST(target_subdir) + +# If this is using newlib, then define inhibit_libc in +# LIBGCC2_CFLAGS. This will cause __eprintf to be left out of +# libgcc.a, but that's OK because newib should have its own version of +# assert.h. +inhibit_libc= +if test x$with_newlib = xyes; then + inhibit_libc=-Dinhibit_libc +fi +AC_SUBST(inhibit_libc) + +# Override SCHED_OBJ and SCHED_CFLAGS to enable the Haifa scheduler. +sched_prefix= +sched_cflags= +if test x$enable_haifa = xyes; then + echo "Using the Haifa scheduler." + sched_prefix=haifa- + sched_cflags=-DHAIFA +fi +AC_SUBST(sched_prefix) +AC_SUBST(sched_cflags) +if test x$enable_haifa != x; then + # Explicitly remove files that need to be recompiled for the Haifa scheduler. + for x in genattrtab.o toplev.o loop.o unroll.o *sched.o; do + if test -f $x; then + echo "Removing $x" + rm -f $x + fi + done +fi + +# If $(exec_prefix) exists and is not the same as $(prefix), then compute an +# absolute path for gcc_tooldir based on inserting the number of up-directory +# movements required to get from $(exec_prefix) to $(prefix) into the basic +# $(libsubdir)/@(unlibsubdir) based path. +# Don't set gcc_tooldir to tooldir since that's only passed in by the toplevel +# make and thus we'd get different behavior depending on where we built the +# sources. +if test x$exec_prefix = xNONE -o x$exec_prefix = x$prefix; then + gcc_tooldir='$(libsubdir)/$(unlibsubdir)/../$(target_alias)' +else +changequote(<<, >>)dnl +# An explanation of the sed strings: +# -e 's|^\$(prefix)||' matches and eliminates 'prefix' from 'exec_prefix' +# -e 's|/$||' match a trailing forward slash and eliminates it +# -e 's|^[^/]|/|' forces the string to start with a forward slash (*) +# -e 's|/[^/]*|../|g' replaces each occurance of / with ../ +# +# (*) Note this pattern overwrites the first character of the string +# with a forward slash if one is not already present. This is not a +# problem because the exact names of the sub-directories concerned is +# unimportant, just the number of them matters. +# +# The practical upshot of these patterns is like this: +# +# prefix exec_prefix result +# ------ ----------- ------ +# /foo /foo/bar ../ +# /foo/ /foo/bar ../ +# /foo /foo/bar/ ../ +# /foo/ /foo/bar/ ../ +# /foo /foo/bar/ugg ../../ +# + dollar='$$' + gcc_tooldir="\$(libsubdir)/\$(unlibsubdir)/\`echo \$(exec_prefix) | sed -e 's|^\$(prefix)||' -e 's|/\$(dollar)||' -e 's|^[^/]|/|' -e 's|/[^/]*|../|g'\`\$(target_alias)" +changequote([, ])dnl +fi +AC_SUBST(gcc_tooldir) +AC_SUBST(dollar) + +# Warn if using init_priority. +AC_MSG_CHECKING(whether to enable init_priority by default) +if test x$enable_init_priority != xyes; then + enable_init_priority=no +fi +AC_MSG_RESULT($enable_init_priority) + +# Nothing to do for FLOAT_H, float_format already handled. +objdir=`pwd` +AC_SUBST(objdir) + +# Process the language and host/target makefile fragments. +${CONFIG_SHELL-/bin/sh} $srcdir/configure.frag $srcdir "$subdirs" "$dep_host_xmake_file" "$dep_tmake_file" + +# Substitute configuration variables +AC_SUBST(subdirs) +AC_SUBST(all_languages) +AC_SUBST(all_boot_languages) +AC_SUBST(all_compilers) +AC_SUBST(all_lang_makefiles) +AC_SUBST(all_stagestuff) +AC_SUBST(all_diff_excludes) +AC_SUBST(all_lib2funcs) +AC_SUBST(all_headers) +AC_SUBST(cpp_main) +AC_SUBST(extra_passes) +AC_SUBST(extra_programs) +AC_SUBST(extra_parts) +AC_SUBST(extra_c_objs) +AC_SUBST(extra_cxx_objs) +AC_SUBST(extra_cpp_objs) +AC_SUBST(extra_c_flags) +AC_SUBST(extra_objs) +AC_SUBST(host_extra_gcc_objs) +AC_SUBST(extra_headers_list) +AC_SUBST(dep_host_xmake_file) +AC_SUBST(dep_tmake_file) +AC_SUBST(out_file) +AC_SUBST(out_object_file) +AC_SUBST(md_file) +AC_SUBST(tm_file_list) +AC_SUBST(build_xm_file_list) +AC_SUBST(host_xm_file_list) +AC_SUBST(lang_specs_files) +AC_SUBST(lang_options_files) +AC_SUBST(lang_tree_files) +AC_SUBST(thread_file) +AC_SUBST(objc_boehm_gc) +AC_SUBST(JAVAGC) +AC_SUBST(gcc_version) +AC_SUBST(gcc_version_trigger) +AC_SUBST(local_prefix) +AC_SUBST(gcc_gxx_include_dir) +AC_SUBST(fixincludes) +AC_SUBST(build_install_headers_dir) +AC_SUBST(build_exeext) +AC_SUBST(host_exeext) +AC_SUBST(float_h_file) +AC_SUBST(cc_set_by_configure) +AC_SUBST(stage_prefix_set_by_configure) +AC_SUBST(install) +AC_SUBST(symbolic_link) + +AC_SUBST_FILE(target_overrides) +AC_SUBST_FILE(host_overrides) +AC_SUBST(cross_defines) +AC_SUBST_FILE(cross_overrides) +AC_SUBST_FILE(build_overrides) +AC_SUBST_FILE(language_fragments) +AC_SUBST_FILE(language_hooks) + +# Echo that links are built +if test x$host = x$target +then + str1="native " +else + str1="cross-" + str2=" from $host" +fi + +if test x$host != x$build +then + str3=" on a $build system" +fi + +if test "x$str2" != x || test "x$str3" != x +then + str4= +fi + +echo "Links are now set up to build a ${str1}compiler for ${target}$str4" 1>&2 + +if test "x$str2" != x || test "x$str3" != x +then + echo " ${str2}${str3}." 1>&2 +fi + +# Truncate the target if necessary +if test x$host_truncate_target != x; then + target=`echo $target | sed -e 's/\(..............\).*/\1/'` +fi + +# Configure the subdirectories +# AC_CONFIG_SUBDIRS($subdirs) + +# Create the Makefile +# and configure language subdirectories +AC_OUTPUT($all_outputs, +[ +. $srcdir/configure.lang +case x$CONFIG_HEADERS in +xauto-host.h:config.in) +echo > cstamp-h ;; +esac +# If the host supports symlinks, point stage[1234] at ../stage[1234] so +# bootstrapping and the installation procedure can still use +# CC="stage1/xgcc -Bstage1/". If the host doesn't support symlinks, +# 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. +if test "$symbolic_link" = "ln -s"; then + for d in .. ${subdirs} ; do + if test $d != ..; then + STARTDIR=`pwd` + cd $d + for t in stage1 stage2 stage3 stage4 include + do + rm -f $t + $symbolic_link ../$t $t 2>/dev/null + done + cd $STARTDIR + fi + done +else true ; fi +], +[ +host='${host}' +build='${build}' +target='${target}' +target_alias='${target_alias}' +srcdir='${srcdir}' +subdirs='${subdirs}' +oldstyle_subdirs='${oldstyle_subdirs}' +symbolic_link='${symbolic_link}' +program_transform_set='${program_transform_set}' +program_transform_name='${program_transform_name}' +dep_host_xmake_file='${dep_host_xmake_file}' +host_xmake_file='${host_xmake_file}' +dep_tmake_file='${dep_tmake_file}' +tmake_file='${tmake_file}' +thread_file='${thread_file}' +gcc_version='${gcc_version}' +gcc_version_trigger='${gcc_version_trigger}' +local_prefix='${local_prefix}' +build_install_headers_dir='${build_install_headers_dir}' +build_exeext='${build_exeext}' +host_exeext='${host_exeext}' +out_file='${out_file}' +gdb_needs_out_file_path='${gdb_needs_out_file_path}' +SET_MAKE='${SET_MAKE}' +target_list='${target_list}' +target_overrides='${target_overrides}' +host_overrides='${host_overrides}' +cross_defines='${cross_defines}' +cross_overrides='${cross_overrides}' +build_overrides='${build_overrides}' +]) diff --git a/gcc_arm/configure.lang b/gcc_arm/configure.lang new file mode 100755 index 0000000..d96b6d8 --- /dev/null +++ b/gcc_arm/configure.lang @@ -0,0 +1,233 @@ +# configure.lang for GNU CC +# This script is run by configure for configuration of language +# subdirectories which conform to the old GCC configure mechanism +# for such subdirectories. + +# Copyright (C) 1997, 1998 Free Software Foundation, Inc. + +#This file is part of GNU CC. + +#GNU CC is free software; you can redistribute it and/or modify +#it under the terms of the GNU General Public License as published by +#the Free Software Foundation; either version 2, or (at your option) +#any later version. + +#GNU CC is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with GNU CC; see the file COPYING. If not, write to +#the Free Software Foundation, 59 Temple Place - Suite 330, +#Boston, MA 02111-1307, USA. + +savesrcdir=$srcdir + +for subdir in . $oldstyle_subdirs +do + # We only want to do this in language subdirs, but we have to handle + # the case of $oldstyle_subdirs = "". + if [ $subdir = . ] + then + continue + fi + + oldsrcdir=$savesrcdir + + # Re-adjust the path + case $oldsrcdir in + /*) + srcdir=$oldsrcdir/$subdir + ;; + *) + oldsrcdir=../${oldsrcdir} + srcdir=$oldsrcdir/$subdir + ;; + esac + mainsrcdir=$oldsrcdir + STARTDIR=`pwd` + test -d $subdir || mkdir $subdir + cd $subdir + + # Create Makefile.tem from Makefile.in. + # Make it set VPATH if necessary so that the sources are found. + # Also change its value of srcdir. + # Also create a .gdbinit file which runs the one in srcdir + # and tells GDB to look there for source files. + case $srcdir in + . | ./$subdir | .././$subdir) + rm -f Makefile.tem + cp Makefile.in Makefile.tem + chmod +w Makefile.tem + ;; + *) + rm -f Makefile.tem + echo "VPATH = ${srcdir}" \ + | cat - ${srcdir}/Makefile.in \ + | sed "s@^srcdir = \.@srcdir = ${srcdir}@" > Makefile.tem + rm -f .gdbinit + echo "dir ." > .gdbinit + echo "dir ${srcdir}" >> .gdbinit + echo "dir ${mainsrcdir}" >> .gdbinit + if [ x$gdb_needs_out_file_path = xyes ] + then + echo "dir ${mainsrcdir}/config/"`dirname ${out_file}` >> .gdbinit + fi + echo "source ${mainsrcdir}/.gdbinit" >> .gdbinit + ;; + esac + + # Conditionalize the makefile for this host machine. + rm -f Makefile.xx Makefile.ll + merged_frags= + for f in .. ${host_xmake_file} + do + if [ -f ${mainsrcdir}/config/$f ] + then + cat ${mainsrcdir}/config/$f >> Makefile.ll + if [ x"${merged_frags}" != x ] + then + merged_frags="${merged_frags} and " + fi + merged_frags="${merged_frags}${f}" + fi + done + if [ x"${merged_frags}" != x ] + then + sed -e "/####host/ r Makefile.ll" Makefile.tem > Makefile.xx + echo "Merged ${merged_frags}." + rm -f Makefile.tem + mv Makefile.xx Makefile.tem + rm -f Makefile.ll + fi + + # Add a definition for MAKE if system wants one. + case "$SET_MAKE" in + ?*) + rm -f Makefile.xx + (echo "$SET_MAKE"; cat Makefile.tem) >Makefile.xx + rm -f Makefile.tem + mv Makefile.xx Makefile.tem + esac + + # Add a definition for INSTALL if system wants one. + # This substitutes for lots of x-* files. + if [ x$build_broken_install = x ] + then true + else + rm -f Makefile.xx + abssrcdir=`cd ${srcdir}; pwd` + sed "s|^INSTALL = .*|${INSTALL}|" Makefile.tem > Makefile.xx + rm -f Makefile.tem + mv Makefile.xx Makefile.tem + fi + + # If using -program-transform-name, override the installation names. + if [ "x${program_transform_set}" = "xyes" ] ; then + sed -e "s/^program_transform_name[ ]*=.*$/program_transform_name = +$program_transform_name/" \ + -e "s/^program_transform_cross_name[ +]*=.*$/program_transform_cross_name = $program_transform_name/" \ + Makefile.tem > Makefile.xx + rm -f Makefile.tem + mv Makefile.xx Makefile.tem + fi + + # Conditionalize the makefile for this target machine. + rm -f Makefile.xx Makefile.ll + merged_frags= + for f in .. ${tmake_file} + do + if [ -f ${mainsrcdir}/config/$f ] + then + cat ${mainsrcdir}/config/$f >> Makefile.ll + if [ x"${merged_frags}" != x ] + then + merged_frags="${merged_frags} and " + fi + merged_frags="${merged_frags}$f" + fi + done + if [ x"${merged_frags}" != x ] + then + sed -e "/####target/ r Makefile.ll" Makefile.tem > Makefile.xx + echo "Merged ${merged_frags}." + rm -f Makefile.tem + mv Makefile.xx Makefile.tem + rm -f Makefile.ll + fi + + # If the host supports + # symlinks, point stage[123] at ../stage[123] so bootstrapping and the + # installation procedure can still use CC="stage1/xgcc -Bstage1/". + # If the host doesn't support symlinks, FLAGS_TO_PASS has been + # modified to solve the problem there. + for t in stage1 stage2 stage3 stage4 include + do + rm -f $t + $symbolic_link ../$t $t 2>/dev/null + done + + # Remove all formfeeds, since some Makes get confused by them. + # Also arrange to give the variables `target', `target_alias', + # `host_xmake_file', `tmake_file', `prefix', `local_prefix', + # `exec_prefix', `INSTALL_HEADERS_DIR', `exeext' + # values in the Makefile from the values they have in this script. + rm -f Makefile.xx + # Create an empty Makefile.sed first, to work around a Nextstep 3.3 bug. + echo 's| ||' > Makefile.sed + rm Makefile.sed + echo 's| ||' > Makefile.sed + echo "s|^target=.*$|target=${target}|" >> Makefile.sed + echo "s|^target_alias=.*$|target_alias=${target_alias}|" >> Makefile.sed + echo "s|^xmake_file=.*$|xmake_file=${dep_host_xmake_file}|" >> Makefile.sed + echo "s|^tmake_file=.*$|tmake_file=${dep_tmake_file}|" >> Makefile.sed + echo "s|^version=.*$|version=${version}|" >> Makefile.sed + echo "s|^GCC_THREAD_FILE=.*$|GCC_THREAD_FILE=${thread_file}|" >> Makefile.sed + echo "s|^prefix[ ]*=.*|prefix = $prefix|" >> Makefile.sed + echo "s|^local_prefix[ ]*=.*|local_prefix = $local_prefix|" >> Makefile.sed + echo "s|^exec_prefix[ ]*=.*|exec_prefix = $exec_prefix|" >> Makefile.sed + echo "s|^INSTALL_HEADERS_DIR[ ]*=.*$|INSTALL_HEADERS_DIR = ${build_install_headers_dir}|" >> Makefile.sed + echo "s|^exeext[ ]*=.*$|exeext = ${build_exeext}|" >> Makefile.sed + sed -f Makefile.sed Makefile.tem > Makefile.xx + rm -f Makefile.tem Makefile.sed + mv Makefile.xx Makefile.tem + + # Install Makefile for real, after making final changes. + # Define macro CROSS_COMPILE in compilation + # if this is a cross-compiler. + # Also use all.cross instead of all.internal + # and add cross-make to Makefile. + if [ x$host != x$target ] + then + rm -f Makefile.xx + echo "CROSS=-DCROSS_COMPILE" > Makefile.xx + sed -e "/####cross/ r ${mainsrcdir}/cross-make" Makefile.tem >> Makefile.xx + rm -f Makefile.tem + mv Makefile.xx Makefile.tem + fi + + # When building gcc with a cross-compiler, we need to fix a few things. + # This must come after cross-make as we want all.build to override + # all.cross. + if [ x$build != x$host ] + then + rm -f Makefile.xx + echo "build= $build" > Makefile.xx + echo "host= $host" >> Makefile.xx + sed -e "s|objc-runtime$||" \ + -e "/####build/ r ${mainsrcdir}/build-make" Makefile.tem >> Makefile.xx + rm -f Makefile.tem + mv Makefile.xx Makefile.tem + fi + + rm -f Makefile + mv Makefile.tem Makefile + echo "Created \`$subdir/Makefile'." + + cd $STARTDIR +done # end of current-dir SUBDIRS loop + +# Restore this, remember we're invoked with `.'. +srcdir=$savesrcdir diff --git a/gcc_arm/convert.c b/gcc_arm/convert.c new file mode 100755 index 0000000..bfcb5db --- /dev/null +++ b/gcc_arm/convert.c @@ -0,0 +1,444 @@ +/* Utility routines for data type conversion for GNU C. + Copyright (C) 1987, 88, 91-95, 97, 1998 Free Software Foundation, Inc. + +This file is part of GNU C. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* These routines are somewhat language-independent utility function + intended to be called by the language-specific convert () functions. */ + +#include "config.h" +#include "tree.h" +#include "flags.h" +#include "convert.h" +#include "toplev.h" + +/* Convert EXPR to some pointer or reference type TYPE. + + EXPR must be pointer, reference, integer, enumeral, or literal zero; + in other cases error is called. */ + +tree +convert_to_pointer (type, expr) + tree type, expr; +{ + if (integer_zerop (expr)) + { + expr = build_int_2 (0, 0); + TREE_TYPE (expr) = type; + return expr; + } + + switch (TREE_CODE (TREE_TYPE (expr))) + { + case POINTER_TYPE: + case REFERENCE_TYPE: + return build1 (NOP_EXPR, type, expr); + + case INTEGER_TYPE: + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + case CHAR_TYPE: + if (TYPE_PRECISION (TREE_TYPE (expr)) == POINTER_SIZE) + return build1 (CONVERT_EXPR, type, expr); + + return + convert_to_pointer (type, + convert (type_for_size (POINTER_SIZE, 0), expr)); + + default: + error ("cannot convert to a pointer type"); + return convert_to_pointer (type, integer_zero_node); + } +} + +/* Convert EXPR to some floating-point type TYPE. + + EXPR must be float, integer, or enumeral; + in other cases error is called. */ + +tree +convert_to_real (type, expr) + tree type, expr; +{ + switch (TREE_CODE (TREE_TYPE (expr))) + { + case REAL_TYPE: + return build1 (flag_float_store ? CONVERT_EXPR : NOP_EXPR, + type, expr); + + case INTEGER_TYPE: + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + case CHAR_TYPE: + return build1 (FLOAT_EXPR, type, expr); + + case COMPLEX_TYPE: + return convert (type, + fold (build1 (REALPART_EXPR, + TREE_TYPE (TREE_TYPE (expr)), expr))); + + case POINTER_TYPE: + case REFERENCE_TYPE: + error ("pointer value used where a floating point value was expected"); + return convert_to_real (type, integer_zero_node); + + default: + error ("aggregate value used where a float was expected"); + return convert_to_real (type, integer_zero_node); + } +} + +/* Convert EXPR to some integer (or enum) type TYPE. + + EXPR must be pointer, integer, discrete (enum, char, or bool), or float; + in other cases error is called. + + The result of this is always supposed to be a newly created tree node + not in use in any existing structure. */ + +tree +convert_to_integer (type, expr) + tree type, expr; +{ + enum tree_code ex_form = TREE_CODE (expr); + tree intype = TREE_TYPE (expr); + int inprec = TYPE_PRECISION (intype); + int outprec = TYPE_PRECISION (type); + + /* An INTEGER_TYPE cannot be incomplete, but an ENUMERAL_TYPE can + be. Consider `enum E = { a, b = (enum E) 3 };'. */ + if (!TYPE_SIZE (type)) + { + error ("conversion to incomplete type"); + return error_mark_node; + } + + switch (TREE_CODE (intype)) + { + case POINTER_TYPE: + case REFERENCE_TYPE: + if (integer_zerop (expr)) + expr = integer_zero_node; + else + expr = fold (build1 (CONVERT_EXPR, + type_for_size (POINTER_SIZE, 0), expr)); + + return convert_to_integer (type, expr); + + case INTEGER_TYPE: + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + case CHAR_TYPE: + /* If this is a logical operation, which just returns 0 or 1, we can + change the type of the expression. For some logical operations, + we must also change the types of the operands to maintain type + correctness. */ + + if (TREE_CODE_CLASS (ex_form) == '<') + { + TREE_TYPE (expr) = type; + return expr; + } + + else if (ex_form == TRUTH_AND_EXPR || ex_form == TRUTH_ANDIF_EXPR + || ex_form == TRUTH_OR_EXPR || ex_form == TRUTH_ORIF_EXPR + || ex_form == TRUTH_XOR_EXPR) + { + TREE_OPERAND (expr, 0) = convert (type, TREE_OPERAND (expr, 0)); + TREE_OPERAND (expr, 1) = convert (type, TREE_OPERAND (expr, 1)); + TREE_TYPE (expr) = type; + return expr; + } + + else if (ex_form == TRUTH_NOT_EXPR) + { + TREE_OPERAND (expr, 0) = convert (type, TREE_OPERAND (expr, 0)); + TREE_TYPE (expr) = type; + return expr; + } + + /* If we are widening the type, put in an explicit conversion. + Similarly if we are not changing the width. After this, we know + we are truncating EXPR. */ + + else if (outprec >= inprec) + return build1 (NOP_EXPR, type, expr); + + /* If TYPE is an enumeral type or a type with a precision less + than the number of bits in its mode, do the conversion to the + type corresponding to its mode, then do a nop conversion + to TYPE. */ + else if (TREE_CODE (type) == ENUMERAL_TYPE + || outprec != GET_MODE_BITSIZE (TYPE_MODE (type))) + return build1 (NOP_EXPR, type, + convert (type_for_mode (TYPE_MODE (type), + TREE_UNSIGNED (type)), + expr)); + + /* Here detect when we can distribute the truncation down past some + arithmetic. For example, if adding two longs and converting to an + int, we can equally well convert both to ints and then add. + For the operations handled here, such truncation distribution + is always safe. + It is desirable in these cases: + 1) when truncating down to full-word from a larger size + 2) when truncating takes no work. + 3) when at least one operand of the arithmetic has been extended + (as by C's default conversions). In this case we need two conversions + if we do the arithmetic as already requested, so we might as well + truncate both and then combine. Perhaps that way we need only one. + + Note that in general we cannot do the arithmetic in a type + shorter than the desired result of conversion, even if the operands + are both extended from a shorter type, because they might overflow + if combined in that type. The exceptions to this--the times when + two narrow values can be combined in their narrow type even to + make a wider result--are handled by "shorten" in build_binary_op. */ + + switch (ex_form) + { + case RSHIFT_EXPR: + /* We can pass truncation down through right shifting + when the shift count is a nonpositive constant. */ + if (TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST + && tree_int_cst_lt (TREE_OPERAND (expr, 1), + convert (TREE_TYPE (TREE_OPERAND (expr, 1)), + integer_one_node))) + goto trunc1; + break; + + case LSHIFT_EXPR: + /* We can pass truncation down through left shifting + when the shift count is a nonnegative constant. */ + if (TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST + && tree_int_cst_sgn (TREE_OPERAND (expr, 1)) >= 0 + && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST) + { + /* If shift count is less than the width of the truncated type, + really shift. */ + if (tree_int_cst_lt (TREE_OPERAND (expr, 1), TYPE_SIZE (type))) + /* In this case, shifting is like multiplication. */ + goto trunc1; + else + { + /* If it is >= that width, result is zero. + Handling this with trunc1 would give the wrong result: + (int) ((long long) a << 32) is well defined (as 0) + but (int) a << 32 is undefined and would get a + warning. */ + + tree t = convert_to_integer (type, integer_zero_node); + + /* If the original expression had side-effects, we must + preserve it. */ + if (TREE_SIDE_EFFECTS (expr)) + return build (COMPOUND_EXPR, type, expr, t); + else + return t; + } + } + break; + + case MAX_EXPR: + case MIN_EXPR: + case MULT_EXPR: + { + tree arg0 = get_unwidened (TREE_OPERAND (expr, 0), type); + tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), type); + + /* Don't distribute unless the output precision is at least as big + as the actual inputs. Otherwise, the comparison of the + truncated values will be wrong. */ + if (outprec >= TYPE_PRECISION (TREE_TYPE (arg0)) + && outprec >= TYPE_PRECISION (TREE_TYPE (arg1)) + /* If signedness of arg0 and arg1 don't match, + we can't necessarily find a type to compare them in. */ + && (TREE_UNSIGNED (TREE_TYPE (arg0)) + == TREE_UNSIGNED (TREE_TYPE (arg1)))) + goto trunc1; + break; + } + + case PLUS_EXPR: + case MINUS_EXPR: + case BIT_AND_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case BIT_ANDTC_EXPR: + trunc1: + { + tree arg0 = get_unwidened (TREE_OPERAND (expr, 0), type); + tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), type); + + if (outprec >= BITS_PER_WORD + || TRULY_NOOP_TRUNCATION (outprec, inprec) + || inprec > TYPE_PRECISION (TREE_TYPE (arg0)) + || inprec > TYPE_PRECISION (TREE_TYPE (arg1))) + { + /* Do the arithmetic in type TYPEX, + then convert result to TYPE. */ + register tree typex = type; + + /* Can't do arithmetic in enumeral types + so use an integer type that will hold the values. */ + if (TREE_CODE (typex) == ENUMERAL_TYPE) + typex = type_for_size (TYPE_PRECISION (typex), + TREE_UNSIGNED (typex)); + + /* But now perhaps TYPEX is as wide as INPREC. + In that case, do nothing special here. + (Otherwise would recurse infinitely in convert. */ + if (TYPE_PRECISION (typex) != inprec) + { + /* Don't do unsigned arithmetic where signed was wanted, + or vice versa. + Exception: if either of the original operands were + unsigned then can safely do the work as unsigned. + And we may need to do it as unsigned + if we truncate to the original size. */ + typex = ((TREE_UNSIGNED (TREE_TYPE (expr)) + || TREE_UNSIGNED (TREE_TYPE (arg0)) + || TREE_UNSIGNED (TREE_TYPE (arg1))) + ? unsigned_type (typex) : signed_type (typex)); + return convert (type, + fold (build (ex_form, typex, + convert (typex, arg0), + convert (typex, arg1), + 0))); + } + } + } + break; + + case NEGATE_EXPR: + case BIT_NOT_EXPR: + /* This is not correct for ABS_EXPR, + since we must test the sign before truncation. */ + { + register tree typex = type; + + /* Can't do arithmetic in enumeral types + so use an integer type that will hold the values. */ + if (TREE_CODE (typex) == ENUMERAL_TYPE) + typex = type_for_size (TYPE_PRECISION (typex), + TREE_UNSIGNED (typex)); + + /* But now perhaps TYPEX is as wide as INPREC. + In that case, do nothing special here. + (Otherwise would recurse infinitely in convert. */ + if (TYPE_PRECISION (typex) != inprec) + { + /* Don't do unsigned arithmetic where signed was wanted, + or vice versa. */ + typex = (TREE_UNSIGNED (TREE_TYPE (expr)) + ? unsigned_type (typex) : signed_type (typex)); + return convert (type, + fold (build1 (ex_form, typex, + convert (typex, + TREE_OPERAND (expr, 0))))); + } + } + + case NOP_EXPR: + /* If truncating after truncating, might as well do all at once. + If truncating after extending, we may get rid of wasted work. */ + return convert (type, get_unwidened (TREE_OPERAND (expr, 0), type)); + + case COND_EXPR: + /* It is sometimes worthwhile to push the narrowing down through + the conditional and never loses. */ + return fold (build (COND_EXPR, type, TREE_OPERAND (expr, 0), + convert (type, TREE_OPERAND (expr, 1)), + convert (type, TREE_OPERAND (expr, 2)))); + + default: + break; + } + + return build1 (NOP_EXPR, type, expr); + + case REAL_TYPE: + return build1 (FIX_TRUNC_EXPR, type, expr); + + case COMPLEX_TYPE: + return convert (type, + fold (build1 (REALPART_EXPR, + TREE_TYPE (TREE_TYPE (expr)), expr))); + + default: + error ("aggregate value used where an integer was expected"); + return convert (type, integer_zero_node); + } +} + +/* Convert EXPR to the complex type TYPE in the usual ways. */ + +tree +convert_to_complex (type, expr) + tree type, expr; +{ + tree subtype = TREE_TYPE (type); + + switch (TREE_CODE (TREE_TYPE (expr))) + { + case REAL_TYPE: + case INTEGER_TYPE: + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + case CHAR_TYPE: + return build (COMPLEX_EXPR, type, convert (subtype, expr), + convert (subtype, integer_zero_node)); + + case COMPLEX_TYPE: + { + tree elt_type = TREE_TYPE (TREE_TYPE (expr)); + + if (TYPE_MAIN_VARIANT (elt_type) == TYPE_MAIN_VARIANT (subtype)) + return expr; + else if (TREE_CODE (expr) == COMPLEX_EXPR) + return fold (build (COMPLEX_EXPR, + type, + convert (subtype, TREE_OPERAND (expr, 0)), + convert (subtype, TREE_OPERAND (expr, 1)))); + else + { + expr = save_expr (expr); + return + fold (build (COMPLEX_EXPR, + type, convert (subtype, + fold (build1 (REALPART_EXPR, + TREE_TYPE (TREE_TYPE (expr)), + expr))), + convert (subtype, + fold (build1 (IMAGPART_EXPR, + TREE_TYPE (TREE_TYPE (expr)), + expr))))); + } + } + + case POINTER_TYPE: + case REFERENCE_TYPE: + error ("pointer value used where a complex was expected"); + return convert_to_complex (type, integer_zero_node); + + default: + error ("aggregate value used where a complex was expected"); + return convert_to_complex (type, integer_zero_node); + } +} diff --git a/gcc_arm/convert.h b/gcc_arm/convert.h new file mode 100755 index 0000000..4123874 --- /dev/null +++ b/gcc_arm/convert.h @@ -0,0 +1,24 @@ +/* Definition of functions in convert.c. + Copyright (C) 1993 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +extern tree convert_to_integer PROTO ((tree, tree)); +extern tree convert_to_pointer PROTO ((tree, tree)); +extern tree convert_to_real PROTO ((tree, tree)); +extern tree convert_to_complex PROTO ((tree, tree)); diff --git a/gcc_arm/cpp.1 b/gcc_arm/cpp.1 new file mode 100755 index 0000000..54c4dfb --- /dev/null +++ b/gcc_arm/cpp.1 @@ -0,0 +1 @@ +.so man1/cccp.1 diff --git a/gcc_arm/cpp.cps b/gcc_arm/cpp.cps new file mode 100755 index 0000000..63ca498 --- /dev/null +++ b/gcc_arm/cpp.cps @@ -0,0 +1,66 @@ +\initial {#} +\entry {\samp {##}}{18} +\initial {A} +\entry {arguments in macro definitions}{10} +\entry {assertions}{36} +\entry {assertions, undoing}{37} +\initial {B} +\entry {blank macro arguments}{12} +\initial {C} +\entry {cascaded macros}{29} +\entry {commands}{3} +\entry {commenting out code}{34} +\entry {computed \samp {#include}}{5} +\entry {concatenation}{18} +\entry {conditionals}{30} +\initial {E} +\entry {expansion of arguments}{26} +\initial {F} +\entry {function-like macro}{10} +\initial {H} +\entry {header file}{3} +\initial {I} +\entry {including just once}{6} +\entry {inheritance}{8} +\entry {invocation of the preprocessor}{41} +\initial {L} +\entry {line control}{39} +\initial {M} +\entry {macro argument expansion}{26} +\entry {macro body uses macro}{29} +\entry {macros with argument}{10} +\entry {manifest constant}{9} +\initial {N} +\entry {newlines in macro arguments}{30} +\entry {null command}{40} +\initial {O} +\entry {options}{41} +\entry {output format}{41} +\entry {overriding a header file}{8} +\initial {P} +\entry {parentheses in macro bodies}{22} +\entry {pitfalls of macros}{21} +\entry {predefined macros}{13} +\entry {predicates}{36} +\entry {preprocessor commands}{3} +\entry {prescan of macro arguments}{26} +\entry {problems with macros}{21} +\initial {R} +\entry {redefining macros}{20} +\entry {repeated inclusion}{6} +\entry {retracting assertions}{37} +\initial {S} +\entry {second include path}{45} +\entry {self-reference}{25} +\entry {semicolons (after macro calls)}{23} +\entry {side effects (in macro arguments)}{24} +\entry {simple macro}{9} +\entry {space as macro argument}{12} +\entry {standard predefined macros}{13} +\entry {stringification}{17} +\initial {T} +\entry {testing predicates}{36} +\initial {U} +\entry {unassert}{37} +\entry {undefining macros}{20} +\entry {unsafe macros}{24} diff --git a/gcc_arm/cpp.fns b/gcc_arm/cpp.fns new file mode 100755 index 0000000..849b4b2 --- /dev/null +++ b/gcc_arm/cpp.fns @@ -0,0 +1,94 @@ +\initial {#} +\entry {\code {#assert}}{37} +\entry {\code {#cpu}}{36} +\entry {\code {#define}}{10} +\entry {\code {#elif}}{33} +\entry {\code {#else}}{32} +\entry {\code {#error}}{38} +\entry {\code {#ident}}{40} +\entry {\code {#if}}{31} +\entry {\code {#ifdef}}{35} +\entry {\code {#ifndef}}{35} +\entry {\code {#import}}{7} +\entry {\code {#include}}{4} +\entry {\code {#include{\_}next}}{8} +\entry {\code {#line}}{39} +\entry {\code {#machine}}{36} +\entry {\code {#pragma}}{40} +\entry {\code {#pragma once}}{7} +\entry {\code {#system}}{36} +\entry {\code {#unassert}}{37} +\entry {\code {#warning}}{38} +\initial {-} +\entry {\code {-$}}{46} +\entry {\code {-A}}{44} +\entry {\code {-C}}{42} +\entry {\code {-D}}{43} +\entry {\code {-dD}}{44} +\entry {\code {-dM}}{44} +\entry {\code {-H}}{45} +\entry {\code {-I}}{43} +\entry {\code {-idirafter}}{45} +\entry {\code {-imacros}}{45} +\entry {\code {-include}}{45} +\entry {\code {-iprefix}}{45} +\entry {\code {-isystem}}{45} +\entry {\code {-iwithprefix}}{45} +\entry {\code {-lang-c}}{45} +\entry {\code {-lang-c{\tt\char43}{\tt\char43}}}{45} +\entry {\code {-lang-objc}}{45} +\entry {\code {-lang-objc{\tt\char43}{\tt\char43}}}{45} +\entry {\code {-M}}{44} +\entry {\code {-MD}}{44} +\entry {\code {-MM}}{44} +\entry {\code {-MMD}}{45} +\entry {\code {-nostdinc}}{43} +\entry {\code {-nostdinc{\tt\char43}{\tt\char43}}}{43} +\entry {\code {-P}}{42} +\entry {\code {-pedantic}}{43} +\entry {\code {-pedantic-errors}}{43} +\entry {\code {-traditional}}{42} +\entry {\code {-trigraphs}}{42} +\entry {\code {-U}}{44} +\entry {\code {-undef}}{44} +\entry {\code {-Wall}}{43} +\entry {\code {-Wcomment}}{43} +\entry {\code {-Wtraditional}}{43} +\entry {\code {-Wtrigraphs}}{43} +\initial {{\_}} +\entry {\code {{\_}{\_}BASE{\_}FILE{\_}{\_}}}{15} +\entry {\code {{\_}{\_}CHAR{\_}UNSIGNED{\_}{\_}}}{15} +\entry {\code {{\_}{\_}cplusplus}}{14} +\entry {\code {{\_}{\_}DATE{\_}{\_}}}{14} +\entry {\code {{\_}{\_}FILE{\_}{\_}}}{13} +\entry {\code {{\_}{\_}GNUC{\_}{\_}}}{14} +\entry {\code {{\_}{\_}GNUG{\_}{\_}}}{14} +\entry {\code {{\_}{\_}INCLUDE{\_}LEVEL{\_}}}{14} +\entry {\code {{\_}{\_}LINE{\_}{\_}}}{13} +\entry {\code {{\_}{\_}OPTIMIZE{\_}{\_}}}{15} +\entry {\code {{\_}{\_}STDC{\_}{\_}}}{14} +\entry {\code {{\_}{\_}STRICT{\_}ANSI{\_}{\_}}}{15} +\entry {\code {{\_}{\_}TIME{\_}{\_}}}{14} +\entry {\code {{\_}{\_}VERSION{\_}{\_}}}{15} +\entry {\code {{\_}AM29000}}{16} +\entry {\code {{\_}AM29K}}{16} +\initial {B} +\entry {\code {BSD}}{16} +\initial {D} +\entry {\code {defined}}{34} +\initial {M} +\entry {\code {M68020}}{16} +\entry {\code {m68k}}{16} +\entry {\code {mc68000}}{16} +\initial {N} +\entry {\code {ns32000}}{16} +\initial {P} +\entry {\code {pyr}}{16} +\initial {S} +\entry {\code {sequent}}{16} +\entry {\code {sun}}{16} +\entry {\code {system header files}}{4} +\initial {U} +\entry {\code {unix}}{16} +\initial {V} +\entry {\code {vax}}{16} diff --git a/gcc_arm/cpp.texi b/gcc_arm/cpp.texi new file mode 100755 index 0000000..315cfc7 --- /dev/null +++ b/gcc_arm/cpp.texi @@ -0,0 +1,2936 @@ +\input texinfo +@setfilename cpp.info +@settitle The C Preprocessor + +@c CYGNUS LOCAL doc +@c @ignore +@ifinfo +@dircategory Programming +@direntry +* Cpp: (cpp). The GNU C preprocessor. +@end direntry +@end ifinfo +@c CYGNUS LOCAL doc +@c @end ignore + +@c @smallbook +@c @cropmarks +@c CYGNUS LOCAL doc +@finalout +@setchapternewpage odd +@ifinfo +This file documents the GNU C Preprocessor. + +Copyright 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1997, 1998 Free Software +Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through Tex and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that +the entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@end ifinfo + +@titlepage +@c @finalout +@title The C Preprocessor +@subtitle Last revised September 1998 +@subtitle for GCC version 2 +@author Richard M. Stallman +@page +@vskip 2pc +This booklet is eventually intended to form the first chapter of a GNU +C Language manual. + +@vskip 0pt plus 1filll +Copyright @copyright{} 1987, 1989, 1991-1998 +Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that +the entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@end titlepage +@page + +@node Top, Global Actions,, (DIR) +@chapter The C Preprocessor + +The C preprocessor is a @dfn{macro processor} that is used automatically by +the C compiler to transform your program before actual compilation. It is +called a macro processor because it allows you to define @dfn{macros}, +which are brief abbreviations for longer constructs. + +The C preprocessor provides four separate facilities that you can use as +you see fit: + +@itemize @bullet +@item +Inclusion of header files. These are files of declarations that can be +substituted into your program. + +@item +Macro expansion. You can define @dfn{macros}, which are abbreviations +for arbitrary fragments of C code, and then the C preprocessor will +replace the macros with their definitions throughout the program. + +@item +Conditional compilation. Using special preprocessing directives, you +can include or exclude parts of the program according to various +conditions. + +@item +Line control. If you use a program to combine or rearrange source files into +an intermediate file which is then compiled, you can use line control +to inform the compiler of where each source line originally came from. +@end itemize + +C preprocessors vary in some details. This manual discusses the GNU C +preprocessor, the C Compatible Compiler Preprocessor. The GNU C +preprocessor provides a superset of the features of ANSI Standard C@. + +ANSI Standard C requires the rejection of many harmless constructs commonly +used by today's C programs. Such incompatibility would be inconvenient for +users, so the GNU C preprocessor is configured to accept these constructs +by default. Strictly speaking, to get ANSI Standard C, you must use the +options @samp{-trigraphs}, @samp{-undef} and @samp{-pedantic}, but in +practice the consequences of having strict ANSI Standard C make it +undesirable to do this. @xref{Invocation}. + +The C preprocessor is designed for C-like languages; you may run into +problems if you apply it to other kinds of languages, because it assumes +that it is dealing with C@. For example, the C preprocessor sometimes +outputs extra white space to avoid inadvertent C token concatenation, +and this may cause problems with other languages. + +@menu +* Global Actions:: Actions made uniformly on all input files. +* Directives:: General syntax of preprocessing directives. +* Header Files:: How and why to use header files. +* Macros:: How and why to use macros. +* Conditionals:: How and why to use conditionals. +* Combining Sources:: Use of line control when you combine source files. +* Other Directives:: Miscellaneous preprocessing directives. +* Output:: Format of output from the C preprocessor. +* Invocation:: How to invoke the preprocessor; command options. +* Concept Index:: Index of concepts and terms. +* Index:: Index of directives, predefined macros and options. +@end menu + +@node Global Actions, Directives, Top, Top +@section Transformations Made Globally + +Most C preprocessor features are inactive unless you give specific directives +to request their use. (Preprocessing directives are lines starting with +@samp{#}; @pxref{Directives}). But there are three transformations that the +preprocessor always makes on all the input it receives, even in the absence +of directives. + +@itemize @bullet +@item +All C comments are replaced with single spaces. + +@item +Backslash-Newline sequences are deleted, no matter where. This +feature allows you to break long lines for cosmetic purposes without +changing their meaning. + +@item +Predefined macro names are replaced with their expansions +(@pxref{Predefined}). +@end itemize + +The first two transformations are done @emph{before} nearly all other parsing +and before preprocessing directives are recognized. Thus, for example, you +can split a line cosmetically with Backslash-Newline anywhere (except +when trigraphs are in use; see below). + +@example +/* +*/ # /* +*/ defi\ +ne FO\ +O 10\ +20 +@end example + +@noindent +is equivalent into @samp{#define FOO 1020}. You can split even an escape +sequence with Backslash-Newline. For example, you can split @code{"foo\bar"} +between the @samp{\} and the @samp{b} to get + +@example +"foo\\ +bar" +@end example + +@noindent +This behavior is unclean: in all other contexts, a Backslash can be +inserted in a string constant as an ordinary character by writing a double +Backslash, and this creates an exception. But the ANSI C standard requires +it. (Strict ANSI C does not allow Newlines in string constants, so they +do not consider this a problem.) + +But there are a few exceptions to all three transformations. + +@itemize @bullet +@item +C comments and predefined macro names are not recognized inside a +@samp{#include} directive in which the file name is delimited with +@samp{<} and @samp{>}. + +@item +C comments and predefined macro names are never recognized within a +character or string constant. (Strictly speaking, this is the rule, +not an exception, but it is worth noting here anyway.) + +@item +Backslash-Newline may not safely be used within an ANSI ``trigraph''. +Trigraphs are converted before Backslash-Newline is deleted. If you +write what looks like a trigraph with a Backslash-Newline inside, the +Backslash-Newline is deleted as usual, but it is then too late to +recognize the trigraph. + +This exception is relevant only if you use the @samp{-trigraphs} +option to enable trigraph processing. @xref{Invocation}. +@end itemize + +@node Directives, Header Files, Global Actions, Top +@section Preprocessing Directives + +@cindex preprocessing directives +@cindex directives +Most preprocessor features are active only if you use preprocessing directives +to request their use. + +Preprocessing directives are lines in your program that start with @samp{#}. +The @samp{#} is followed by an identifier that is the @dfn{directive name}. +For example, @samp{#define} is the directive that defines a macro. +Whitespace is also allowed before and after the @samp{#}. + +The set of valid directive names is fixed. Programs cannot define new +preprocessing directives. + +Some directive names require arguments; these make up the rest of the directive +line and must be separated from the directive name by whitespace. For example, +@samp{#define} must be followed by a macro name and the intended expansion +of the macro. @xref{Simple Macros}. + +A preprocessing directive cannot be more than one line in normal circumstances. +It may be split cosmetically with Backslash-Newline, but that has no effect +on its meaning. Comments containing Newlines can also divide the +directive into multiple lines, but the comments are changed to Spaces +before the directive is interpreted. The only way a significant Newline +can occur in a preprocessing directive is within a string constant or +character constant. Note that +most C compilers that might be applied to the output from the preprocessor +do not accept string or character constants containing Newlines. + +The @samp{#} and the directive name cannot come from a macro expansion. For +example, if @samp{foo} is defined as a macro expanding to @samp{define}, +that does not make @samp{#foo} a valid preprocessing directive. + +@node Header Files, Macros, Directives, Top +@section Header Files + +@cindex header file +A header file is a file containing C declarations and macro definitions +(@pxref{Macros}) to be shared between several source files. You request +the use of a header file in your program with the C preprocessing directive +@samp{#include}. + +@menu +* Header Uses:: What header files are used for. +* Include Syntax:: How to write @samp{#include} directives. +* Include Operation:: What @samp{#include} does. +* Once-Only:: Preventing multiple inclusion of one header file. +* Inheritance:: Including one header file in another header file. +@end menu + +@node Header Uses, Include Syntax, Header Files, Header Files +@subsection Uses of Header Files + +Header files serve two kinds of purposes. + +@itemize @bullet +@item +@findex system header files +System header files declare the interfaces to parts of the operating +system. You include them in your program to supply the definitions and +declarations you need to invoke system calls and libraries. + +@item +Your own header files contain declarations for interfaces between the +source files of your program. Each time you have a group of related +declarations and macro definitions all or most of which are needed in +several different source files, it is a good idea to create a header +file for them. +@end itemize + +Including a header file produces the same results in C compilation as +copying the header file into each source file that needs it. But such +copying would be time-consuming and error-prone. With a header file, the +related declarations appear in only one place. If they need to be changed, +they can be changed in one place, and programs that include the header file +will automatically use the new version when next recompiled. The header +file eliminates the labor of finding and changing all the copies as well as +the risk that a failure to find one copy will result in inconsistencies +within a program. + +The usual convention is to give header files names that end with +@file{.h}. Avoid unusual characters in header file names, as they +reduce portability. + +@node Include Syntax, Include Operation, Header Uses, Header Files +@subsection The @samp{#include} Directive + +@findex #include +Both user and system header files are included using the preprocessing +directive @samp{#include}. It has three variants: + +@table @code +@item #include <@var{file}> +This variant is used for system header files. It searches for a file +named @var{file} in a list of directories specified by you, then in a +standard list of system directories. You specify directories to +search for header files with the command option @samp{-I} +(@pxref{Invocation}). The option @samp{-nostdinc} inhibits searching +the standard system directories; in this case only the directories +you specify are searched. + +The parsing of this form of @samp{#include} is slightly special +because comments are not recognized within the @samp{<@dots{}>}. +Thus, in @samp{#include } the @samp{/*} does not start a comment +and the directive specifies inclusion of a system header file named +@file{x/*y}. Of course, a header file with such a name is unlikely to +exist on Unix, where shell wildcard features would make it hard to +manipulate.@refill + +The argument @var{file} may not contain a @samp{>} character. It may, +however, contain a @samp{<} character. + +@item #include "@var{file}" +This variant is used for header files of your own program. It +searches for a file named @var{file} first in the current directory, +then in the same directories used for system header files. The +current directory is the directory of the current input file. It is +tried first because it is presumed to be the location of the files +that the current input file refers to. (If the @samp{-I-} option is +used, the special treatment of the current directory is inhibited.) + +The argument @var{file} may not contain @samp{"} characters. If +backslashes occur within @var{file}, they are considered ordinary text +characters, not escape characters. None of the character escape +sequences appropriate to string constants in C are processed. Thus, +@samp{#include "x\n\\y"} specifies a filename containing three +backslashes. It is not clear why this behavior is ever useful, but +the ANSI standard specifies it. + +@item #include @var{anything else} +@cindex computed @samp{#include} +This variant is called a @dfn{computed #include}. Any @samp{#include} +directive whose argument does not fit the above two forms is a computed +include. The text @var{anything else} is checked for macro calls, +which are expanded (@pxref{Macros}). When this is done, the result +must fit one of the above two variants---in particular, the expanded +text must in the end be surrounded by either quotes or angle braces. + +This feature allows you to define a macro which controls the file name +to be used at a later point in the program. One application of this is +to allow a site-specific configuration file for your program to specify +the names of the system include files to be used. This can help in +porting the program to various operating systems in which the necessary +system header files are found in different places. +@end table + +@node Include Operation, Once-Only, Include Syntax, Header Files +@subsection How @samp{#include} Works + +The @samp{#include} directive works by directing the C preprocessor to scan +the specified file as input before continuing with the rest of the current +file. The output from the preprocessor contains the output already +generated, followed by the output resulting from the included file, +followed by the output that comes from the text after the @samp{#include} +directive. For example, given a header file @file{header.h} as follows, + +@example +char *test (); +@end example + +@noindent +and a main program called @file{program.c} that uses the header file, +like this, + +@example +int x; +#include "header.h" + +main () +@{ + printf (test ()); +@} +@end example + +@noindent +the output generated by the C preprocessor for @file{program.c} as input +would be + +@example +int x; +char *test (); + +main () +@{ + printf (test ()); +@} +@end example + +Included files are not limited to declarations and macro definitions; those +are merely the typical uses. Any fragment of a C program can be included +from another file. The include file could even contain the beginning of a +statement that is concluded in the containing file, or the end of a +statement that was started in the including file. However, a comment or a +string or character constant may not start in the included file and finish +in the including file. An unterminated comment, string constant or +character constant in an included file is considered to end (with an error +message) at the end of the file. + +It is possible for a header file to begin or end a syntactic unit such +as a function definition, but that would be very confusing, so don't do +it. + +The line following the @samp{#include} directive is always treated as a +separate line by the C preprocessor even if the included file lacks a final +newline. + +@node Once-Only, Inheritance, Include Operation, Header Files +@subsection Once-Only Include Files +@cindex repeated inclusion +@cindex including just once + +Very often, one header file includes another. It can easily result that a +certain header file is included more than once. This may lead to errors, +if the header file defines structure types or typedefs, and is certainly +wasteful. Therefore, we often wish to prevent multiple inclusion of a +header file. + +The standard way to do this is to enclose the entire real contents of the +file in a conditional, like this: + +@example +#ifndef FILE_FOO_SEEN +#define FILE_FOO_SEEN + +@var{the entire file} + +#endif /* FILE_FOO_SEEN */ +@end example + +The macro @code{FILE_FOO_SEEN} indicates that the file has been included +once already. In a user header file, the macro name should not begin +with @samp{_}. In a system header file, this name should begin with +@samp{__} to avoid conflicts with user programs. In any kind of header +file, the macro name should contain the name of the file and some +additional text, to avoid conflicts with other header files. + +The GNU C preprocessor is programmed to notice when a header file uses +this particular construct and handle it efficiently. If a header file +is contained entirely in a @samp{#ifndef} conditional, then it records +that fact. If a subsequent @samp{#include} specifies the same file, +and the macro in the @samp{#ifndef} is already defined, then the file +is entirely skipped, without even reading it. + +@findex #pragma once +There is also an explicit directive to tell the preprocessor that it need +not include a file more than once. This is called @samp{#pragma once}, +and was used @emph{in addition to} the @samp{#ifndef} conditional around +the contents of the header file. @samp{#pragma once} is now obsolete +and should not be used at all. + +@findex #import +In the Objective C language, there is a variant of @samp{#include} +called @samp{#import} which includes a file, but does so at most once. +If you use @samp{#import} @emph{instead of} @samp{#include}, then you +don't need the conditionals inside the header file to prevent multiple +execution of the contents. + +@samp{#import} is obsolete because it is not a well designed feature. +It requires the users of a header file---the applications +programmers---to know that a certain header file should only be included +once. It is much better for the header file's implementor to write the +file so that users don't need to know this. Using @samp{#ifndef} +accomplishes this goal. + +@node Inheritance,, Once-Only, Header Files +@subsection Inheritance and Header Files +@cindex inheritance +@cindex overriding a header file + +@dfn{Inheritance} is what happens when one object or file derives some +of its contents by virtual copying from another object or file. In +the case of C header files, inheritance means that one header file +includes another header file and then replaces or adds something. + +If the inheriting header file and the base header file have different +names, then inheritance is straightforward: simply write @samp{#include +"@var{base}"} in the inheriting file. + +Sometimes it is necessary to give the inheriting file the same name as +the base file. This is less straightforward. + +For example, suppose an application program uses the system header +@file{sys/signal.h}, but the version of @file{/usr/include/sys/signal.h} +on a particular system doesn't do what the application program expects. +It might be convenient to define a ``local'' version, perhaps under the +name @file{/usr/local/include/sys/signal.h}, to override or add to the +one supplied by the system. + +You can do this by compiling with the option @samp{-I.}, and +writing a file @file{sys/signal.h} that does what the application +program expects. But making this file include the standard +@file{sys/signal.h} is not so easy---writing @samp{#include +} in that file doesn't work, because it includes your own +version of the file, not the standard system version. Used in that file +itself, this leads to an infinite recursion and a fatal error in +compilation. + +@samp{#include } would find the proper file, +but that is not clean, since it makes an assumption about where the +system header file is found. This is bad for maintenance, since it +means that any change in where the system's header files are kept +requires a change somewhere else. + +@findex #include_next +The clean way to solve this problem is to use +@samp{#include_next}, which means, ``Include the @emph{next} file with +this name.'' This directive works like @samp{#include} except in +searching for the specified file: it starts searching the list of header +file directories @emph{after} the directory in which the current file +was found. + +Suppose you specify @samp{-I /usr/local/include}, and the list of +directories to search also includes @file{/usr/include}; and suppose +both directories contain @file{sys/signal.h}. Ordinary +@samp{#include } finds the file under +@file{/usr/local/include}. If that file contains @samp{#include_next +}, it starts searching after that directory, and finds the +file in @file{/usr/include}. + +@node Macros, Conditionals, Header Files, Top +@section Macros + +A macro is a sort of abbreviation which you can define once and then +use later. There are many complicated features associated with macros +in the C preprocessor. + +@menu +* Simple Macros:: Macros that always expand the same way. +* Argument Macros:: Macros that accept arguments that are substituted + into the macro expansion. +* Predefined:: Predefined macros that are always available. +* Stringification:: Macro arguments converted into string constants. +* Concatenation:: Building tokens from parts taken from macro arguments. +* Undefining:: Cancelling a macro's definition. +* Redefining:: Changing a macro's definition. +* Macro Pitfalls:: Macros can confuse the unwary. Here we explain + several common problems and strange features. +@end menu + +@node Simple Macros, Argument Macros, Macros, Macros +@subsection Simple Macros +@cindex simple macro +@cindex manifest constant + +A @dfn{simple macro} is a kind of abbreviation. It is a name which +stands for a fragment of code. Some people refer to these as +@dfn{manifest constants}. + +Before you can use a macro, you must @dfn{define} it explicitly with the +@samp{#define} directive. @samp{#define} is followed by the name of the +macro and then the code it should be an abbreviation for. For example, + +@example +#define BUFFER_SIZE 1020 +@end example + +@noindent +defines a macro named @samp{BUFFER_SIZE} as an abbreviation for the text +@samp{1020}. If somewhere after this @samp{#define} directive there comes +a C statement of the form + +@example +foo = (char *) xmalloc (BUFFER_SIZE); +@end example + +@noindent +then the C preprocessor will recognize and @dfn{expand} the macro +@samp{BUFFER_SIZE}, resulting in + +@example +foo = (char *) xmalloc (1020); +@end example + +The use of all upper case for macro names is a standard convention. +Programs are easier to read when it is possible to tell at a glance which +names are macros. + +Normally, a macro definition must be a single line, like all C +preprocessing directives. (You can split a long macro definition +cosmetically with Backslash-Newline.) There is one exception: Newlines +can be included in the macro definition if within a string or character +constant. This is because it is not possible for a macro definition to +contain an unbalanced quote character; the definition automatically +extends to include the matching quote character that ends the string or +character constant. Comments within a macro definition may contain +Newlines, which make no difference since the comments are entirely +replaced with Spaces regardless of their contents. + +Aside from the above, there is no restriction on what can go in a macro +body. Parentheses need not balance. The body need not resemble valid C +code. (But if it does not, you may get error messages from the C +compiler when you use the macro.) + +The C preprocessor scans your program sequentially, so macro definitions +take effect at the place you write them. Therefore, the following input to +the C preprocessor + +@example +foo = X; +#define X 4 +bar = X; +@end example + +@noindent +produces as output + +@example +foo = X; + +bar = 4; +@end example + +After the preprocessor expands a macro name, the macro's definition body is +appended to the front of the remaining input, and the check for macro calls +continues. Therefore, the macro body can contain calls to other macros. +For example, after + +@example +#define BUFSIZE 1020 +#define TABLESIZE BUFSIZE +@end example + +@noindent +the name @samp{TABLESIZE} when used in the program would go through two +stages of expansion, resulting ultimately in @samp{1020}. + +This is not at all the same as defining @samp{TABLESIZE} to be @samp{1020}. +The @samp{#define} for @samp{TABLESIZE} uses exactly the body you +specify---in this case, @samp{BUFSIZE}---and does not check to see whether +it too is the name of a macro. It's only when you @emph{use} @samp{TABLESIZE} +that the result of its expansion is checked for more macro names. +@xref{Cascaded Macros}. + +@node Argument Macros, Predefined, Simple Macros, Macros +@subsection Macros with Arguments +@cindex macros with argument +@cindex arguments in macro definitions +@cindex function-like macro + +A simple macro always stands for exactly the same text, each time it is +used. Macros can be more flexible when they accept @dfn{arguments}. +Arguments are fragments of code that you supply each time the macro is +used. These fragments are included in the expansion of the macro +according to the directions in the macro definition. A macro that +accepts arguments is called a @dfn{function-like macro} because the +syntax for using it looks like a function call. + +@findex #define +To define a macro that uses arguments, you write a @samp{#define} directive +with a list of @dfn{argument names} in parentheses after the name of the +macro. The argument names may be any valid C identifiers, separated by +commas and optionally whitespace. The open-parenthesis must follow the +macro name immediately, with no space in between. + +For example, here is a macro that computes the minimum of two numeric +values, as it is defined in many C programs: + +@example +#define min(X, Y) ((X) < (Y) ? (X) : (Y)) +@end example + +@noindent +(This is not the best way to define a ``minimum'' macro in GNU C@. +@xref{Side Effects}, for more information.) + +To use a macro that expects arguments, you write the name of the macro +followed by a list of @dfn{actual arguments} in parentheses, separated by +commas. The number of actual arguments you give must match the number of +arguments the macro expects. Examples of use of the macro @samp{min} +include @samp{min (1, 2)} and @samp{min (x + 28, *p)}. + +The expansion text of the macro depends on the arguments you use. +Each of the argument names of the macro is replaced, throughout the +macro definition, with the corresponding actual argument. Using the +same macro @samp{min} defined above, @samp{min (1, 2)} expands into + +@example +((1) < (2) ? (1) : (2)) +@end example + +@noindent +where @samp{1} has been substituted for @samp{X} and @samp{2} for @samp{Y}. + +Likewise, @samp{min (x + 28, *p)} expands into + +@example +((x + 28) < (*p) ? (x + 28) : (*p)) +@end example + +Parentheses in the actual arguments must balance; a comma within +parentheses does not end an argument. However, there is no requirement +for brackets or braces to balance, and they do not prevent a comma from +separating arguments. Thus, + +@example +macro (array[x = y, x + 1]) +@end example + +@noindent +passes two arguments to @code{macro}: @samp{array[x = y} and @samp{x + +1]}. If you want to supply @samp{array[x = y, x + 1]} as an argument, +you must write it as @samp{array[(x = y, x + 1)]}, which is equivalent C +code. + +After the actual arguments are substituted into the macro body, the entire +result is appended to the front of the remaining input, and the check for +macro calls continues. Therefore, the actual arguments can contain calls +to other macros, either with or without arguments, or even to the same +macro. The macro body can also contain calls to other macros. For +example, @samp{min (min (a, b), c)} expands into this text: + +@example +((((a) < (b) ? (a) : (b))) < (c) + ? (((a) < (b) ? (a) : (b))) + : (c)) +@end example + +@noindent +(Line breaks shown here for clarity would not actually be generated.) + +@cindex blank macro arguments +@cindex space as macro argument +If a macro @code{foo} takes one argument, and you want to supply an +empty argument, you must write at least some whitespace between the +parentheses, like this: @samp{foo ( )}. Just @samp{foo ()} is providing +no arguments, which is an error if @code{foo} expects an argument. But +@samp{foo0 ()} is the correct way to call a macro defined to take zero +arguments, like this: + +@example +#define foo0() @dots{} +@end example + +If you use the macro name followed by something other than an +open-parenthesis (after ignoring any spaces, tabs and comments that +follow), it is not a call to the macro, and the preprocessor does not +change what you have written. Therefore, it is possible for the same name +to be a variable or function in your program as well as a macro, and you +can choose in each instance whether to refer to the macro (if an actual +argument list follows) or the variable or function (if an argument list +does not follow). + +Such dual use of one name could be confusing and should be avoided +except when the two meanings are effectively synonymous: that is, when the +name is both a macro and a function and the two have similar effects. You +can think of the name simply as a function; use of the name for purposes +other than calling it (such as, to take the address) will refer to the +function, while calls will expand the macro and generate better but +equivalent code. For example, you can use a function named @samp{min} in +the same source file that defines the macro. If you write @samp{&min} with +no argument list, you refer to the function. If you write @samp{min (x, +bb)}, with an argument list, the macro is expanded. If you write +@samp{(min) (a, bb)}, where the name @samp{min} is not followed by an +open-parenthesis, the macro is not expanded, so you wind up with a call to +the function @samp{min}. + +You may not define the same name as both a simple macro and a macro with +arguments. + +In the definition of a macro with arguments, the list of argument names +must follow the macro name immediately with no space in between. If there +is a space after the macro name, the macro is defined as taking no +arguments, and all the rest of the line is taken to be the expansion. The +reason for this is that it is often useful to define a macro that takes no +arguments and whose definition begins with an identifier in parentheses. +This rule about spaces makes it possible for you to do either this: + +@example +#define FOO(x) - 1 / (x) +@end example + +@noindent +(which defines @samp{FOO} to take an argument and expand into minus the +reciprocal of that argument) or this: + +@example +#define BAR (x) - 1 / (x) +@end example + +@noindent +(which defines @samp{BAR} to take no argument and always expand into +@samp{(x) - 1 / (x)}). + +Note that the @emph{uses} of a macro with arguments can have spaces before +the left parenthesis; it's the @emph{definition} where it matters whether +there is a space. + +@node Predefined, Stringification, Argument Macros, Macros +@subsection Predefined Macros + +@cindex predefined macros +Several simple macros are predefined. You can use them without giving +definitions for them. They fall into two classes: standard macros and +system-specific macros. + +@menu +* Standard Predefined:: Standard predefined macros. +* Nonstandard Predefined:: Nonstandard predefined macros. +@end menu + +@node Standard Predefined, Nonstandard Predefined, Predefined, Predefined +@subsubsection Standard Predefined Macros +@cindex standard predefined macros + +The standard predefined macros are available with the same meanings +regardless of the machine or operating system on which you are using GNU C@. +Their names all start and end with double underscores. Those preceding +@code{__GNUC__} in this table are standardized by ANSI C; the rest are +GNU C extensions. + +@table @code +@item __FILE__ +@findex __FILE__ +This macro expands to the name of the current input file, in the form of +a C string constant. The precise name returned is the one that was +specified in @samp{#include} or as the input file name argument. + +@item __LINE__ +@findex __LINE__ +This macro expands to the current input line number, in the form of a +decimal integer constant. While we call it a predefined macro, it's +a pretty strange macro, since its ``definition'' changes with each +new line of source code. + +This and @samp{__FILE__} are useful in generating an error message to +report an inconsistency detected by the program; the message can state +the source line at which the inconsistency was detected. For example, + +@smallexample +fprintf (stderr, "Internal error: " + "negative string length " + "%d at %s, line %d.", + length, __FILE__, __LINE__); +@end smallexample + +A @samp{#include} directive changes the expansions of @samp{__FILE__} +and @samp{__LINE__} to correspond to the included file. At the end of +that file, when processing resumes on the input file that contained +the @samp{#include} directive, the expansions of @samp{__FILE__} and +@samp{__LINE__} revert to the values they had before the +@samp{#include} (but @samp{__LINE__} is then incremented by one as +processing moves to the line after the @samp{#include}). + +The expansions of both @samp{__FILE__} and @samp{__LINE__} are altered +if a @samp{#line} directive is used. @xref{Combining Sources}. + +@item __DATE__ +@findex __DATE__ +This macro expands to a string constant that describes the date on +which the preprocessor is being run. The string constant contains +eleven characters and looks like @w{@samp{"Feb 1 1996"}}. +@c After reformatting the above, check that the date remains `Feb 1 1996', +@c all on one line, with two spaces between the `Feb' and the `1'. + +@item __TIME__ +@findex __TIME__ +This macro expands to a string constant that describes the time at +which the preprocessor is being run. The string constant contains +eight characters and looks like @samp{"23:59:01"}. + +@item __STDC__ +@findex __STDC__ +This macro expands to the constant 1, to signify that this is ANSI +Standard C@. (Whether that is actually true depends on what C compiler +will operate on the output from the preprocessor.) + +On some hosts, system include files use a different convention, where +@samp{__STDC__} is normally 0, but is 1 if the user specifies strict +conformance to the C Standard. The preprocessor follows the host convention +when processing system include files, but when processing user files it follows +the usual GNU C convention. + +This macro is not defined if the @samp{-traditional} option is used. + +@item __STDC_VERSION__ +@findex __STDC_VERSION__ +This macro expands to the C Standard's version number, +a long integer constant of the form @samp{@var{yyyy}@var{mm}L} +where @var{yyyy} and @var{mm} are the year and month of the Standard version. +This signifies which version of the C Standard the preprocessor conforms to. +Like @samp{__STDC__}, whether this version number is accurate +for the entire implementation depends on what C compiler +will operate on the output from the preprocessor. + +This macro is not defined if the @samp{-traditional} option is used. + +@item __GNUC__ +@findex __GNUC__ +This macro is defined if and only if this is GNU C@. This macro is +defined only when the entire GNU C compiler is in use; if you invoke the +preprocessor directly, @samp{__GNUC__} is undefined. The value +identifies the major version number of GNU CC (@samp{1} for GNU CC +version 1, which is now obsolete, and @samp{2} for version 2). + +@item __GNUC_MINOR__ +@findex __GNUC_MINOR__ +The macro contains the minor version number of the compiler. This can +be used to work around differences between different releases of the +compiler (for example, if gcc 2.6.3 is known to support a feature, you +can test for @code{__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 6)}). +The last number, @samp{3} in the +example above, denotes the bugfix level of the compiler; no macro +contains this value. + +@item __GNUG__ +@findex __GNUG__ +The GNU C compiler defines this when the compilation language is +C++; use @samp{__GNUG__} to distinguish between GNU C and GNU +C++. + +@item __cplusplus +@findex __cplusplus +The draft ANSI standard for C++ used to require predefining this +variable. Though it is no longer required, GNU C++ continues to define +it, as do other popular C++ compilers. You can use @samp{__cplusplus} +to test whether a header is compiled by a C compiler or a C++ compiler. + +@item __STRICT_ANSI__ +@findex __STRICT_ANSI__ +GNU C defines this macro if and only if the @samp{-ansi} switch was +specified when GNU C was invoked. Its definition is the null string. +This macro exists primarily to direct certain GNU header files not to +define certain traditional Unix constructs which are incompatible with +ANSI C@. + +@item __BASE_FILE__ +@findex __BASE_FILE__ +This macro expands to the name of the main input file, in the form +of a C string constant. This is the source file that was specified +as an argument when the C compiler was invoked. + +@item __INCLUDE_LEVEL__ +@findex __INCLUDE_LEVEL_ +This macro expands to a decimal integer constant that represents the +depth of nesting in include files. The value of this macro is +incremented on every @samp{#include} directive and decremented at every +end of file. For input files specified by command line arguments, +the nesting level is zero. + +@item __VERSION__ +@findex __VERSION__ +This macro expands to a string constant which describes the version number of +GNU C@. The string is normally a sequence of decimal numbers separated +by periods, such as @samp{"2.6.0"}. + +@item __OPTIMIZE__ +@findex __OPTIMIZE__ +GNU CC defines this macro in optimizing compilations. It causes certain +GNU header files to define alternative macro definitions for some system +library functions. You should not refer to or test the definition of +this macro unless you make very sure that programs will execute with the +same effect regardless. + +@item __CHAR_UNSIGNED__ +@findex __CHAR_UNSIGNED__ +GNU C defines this macro if and only if the data type @code{char} is +unsigned on the target machine. It exists to cause the standard header +file @file{limits.h} to work correctly. You should not refer to this +macro yourself; instead, refer to the standard macros defined in +@file{limits.h}. The preprocessor uses this macro to determine whether +or not to sign-extend large character constants written in octal; see +@ref{#if Directive,,The @samp{#if} Directive}. + +@item __REGISTER_PREFIX__ +@findex __REGISTER_PREFIX__ +This macro expands to a string (not a string constant) describing the +prefix applied to CPU registers in assembler code. You can use it to +write assembler code that is usable in multiple environments. For +example, in the @samp{m68k-aout} environment it expands to the null +string, but in the @samp{m68k-coff} environment it expands to the string +@samp{%}. + +@item __USER_LABEL_PREFIX__ +@findex __USER_LABEL_PREFIX__ +Similar to @code{__REGISTER_PREFIX__}, but describes the prefix applied +to user generated labels in assembler code. For example, in the +@samp{m68k-aout} environment it expands to the string @samp{_}, but in +the @samp{m68k-coff} environment it expands to the null string. This +does not work with the @samp{-mno-underscores} option that the i386 +OSF/rose and m88k targets provide nor with the @samp{-mcall*} options of +the rs6000 System V Release 4 target. +@end table + +@node Nonstandard Predefined,, Standard Predefined, Predefined +@subsubsection Nonstandard Predefined Macros + +The C preprocessor normally has several predefined macros that vary between +machines because their purpose is to indicate what type of system and +machine is in use. This manual, being for all systems and machines, cannot +tell you exactly what their names are; instead, we offer a list of some +typical ones. You can use @samp{cpp -dM} to see the values of +predefined macros; see @ref{Invocation}. + +Some nonstandard predefined macros describe the operating system in use, +with more or less specificity. For example, + +@table @code +@item unix +@findex unix +@samp{unix} is normally predefined on all Unix systems. + +@item BSD +@findex BSD +@samp{BSD} is predefined on recent versions of Berkeley Unix +(perhaps only in version 4.3). +@end table + +Other nonstandard predefined macros describe the kind of CPU, with more or +less specificity. For example, + +@table @code +@item vax +@findex vax +@samp{vax} is predefined on Vax computers. + +@item mc68000 +@findex mc68000 +@samp{mc68000} is predefined on most computers whose CPU is a Motorola +68000, 68010 or 68020. + +@item m68k +@findex m68k +@samp{m68k} is also predefined on most computers whose CPU is a 68000, +68010 or 68020; however, some makers use @samp{mc68000} and some use +@samp{m68k}. Some predefine both names. What happens in GNU C +depends on the system you are using it on. + +@item M68020 +@findex M68020 +@samp{M68020} has been observed to be predefined on some systems that +use 68020 CPUs---in addition to @samp{mc68000} and @samp{m68k}, which +are less specific. + +@item _AM29K +@findex _AM29K +@itemx _AM29000 +@findex _AM29000 +Both @samp{_AM29K} and @samp{_AM29000} are predefined for the AMD 29000 +CPU family. + +@item ns32000 +@findex ns32000 +@samp{ns32000} is predefined on computers which use the National +Semiconductor 32000 series CPU. +@end table + +Yet other nonstandard predefined macros describe the manufacturer of +the system. For example, + +@table @code +@item sun +@findex sun +@samp{sun} is predefined on all models of Sun computers. + +@item pyr +@findex pyr +@samp{pyr} is predefined on all models of Pyramid computers. + +@item sequent +@findex sequent +@samp{sequent} is predefined on all models of Sequent computers. +@end table + +These predefined symbols are not only nonstandard, they are contrary to the +ANSI standard because their names do not start with underscores. +Therefore, the option @samp{-ansi} inhibits the definition of these +symbols. + +This tends to make @samp{-ansi} useless, since many programs depend on the +customary nonstandard predefined symbols. Even system header files check +them and will generate incorrect declarations if they do not find the names +that are expected. You might think that the header files supplied for the +Uglix computer would not need to test what machine they are running on, +because they can simply assume it is the Uglix; but often they do, and they +do so using the customary names. As a result, very few C programs will +compile with @samp{-ansi}. We intend to avoid such problems on the GNU +system. + +What, then, should you do in an ANSI C program to test the type of machine +it will run on? + +GNU C offers a parallel series of symbols for this purpose, whose names +are made from the customary ones by adding @samp{__} at the beginning +and end. Thus, the symbol @code{__vax__} would be available on a Vax, +and so on. + +The set of nonstandard predefined names in the GNU C preprocessor is +controlled (when @code{cpp} is itself compiled) by the macro +@samp{CPP_PREDEFINES}, which should be a string containing @samp{-D} +options, separated by spaces. For example, on the Sun 3, we use the +following definition: + +@example +#define CPP_PREDEFINES "-Dmc68000 -Dsun -Dunix -Dm68k" +@end example + +@noindent +This macro is usually specified in @file{tm.h}. + +@node Stringification, Concatenation, Predefined, Macros +@subsection Stringification + +@cindex stringification +@dfn{Stringification} means turning a code fragment into a string constant +whose contents are the text for the code fragment. For example, +stringifying @samp{foo (z)} results in @samp{"foo (z)"}. + +In the C preprocessor, stringification is an option available when macro +arguments are substituted into the macro definition. In the body of the +definition, when an argument name appears, the character @samp{#} before +the name specifies stringification of the corresponding actual argument +when it is substituted at that point in the definition. The same argument +may be substituted in other places in the definition without +stringification if the argument name appears in those places with no +@samp{#}. + +Here is an example of a macro definition that uses stringification: + +@smallexample +@group +#define WARN_IF(EXP) \ +do @{ if (EXP) \ + fprintf (stderr, "Warning: " #EXP "\n"); @} \ +while (0) +@end group +@end smallexample + +@noindent +Here the actual argument for @samp{EXP} is substituted once as given, +into the @samp{if} statement, and once as stringified, into the +argument to @samp{fprintf}. The @samp{do} and @samp{while (0)} are +a kludge to make it possible to write @samp{WARN_IF (@var{arg});}, +which the resemblance of @samp{WARN_IF} to a function would make +C programmers want to do; see @ref{Swallow Semicolon}. + +The stringification feature is limited to transforming one macro argument +into one string constant: there is no way to combine the argument with +other text and then stringify it all together. But the example above shows +how an equivalent result can be obtained in ANSI Standard C using the +feature that adjacent string constants are concatenated as one string +constant. The preprocessor stringifies the actual value of @samp{EXP} +into a separate string constant, resulting in text like + +@smallexample +@group +do @{ if (x == 0) \ + fprintf (stderr, "Warning: " "x == 0" "\n"); @} \ +while (0) +@end group +@end smallexample + +@noindent +but the C compiler then sees three consecutive string constants and +concatenates them into one, producing effectively + +@smallexample +do @{ if (x == 0) \ + fprintf (stderr, "Warning: x == 0\n"); @} \ +while (0) +@end smallexample + +Stringification in C involves more than putting doublequote characters +around the fragment; it is necessary to put backslashes in front of all +doublequote characters, and all backslashes in string and character +constants, in order to get a valid C string constant with the proper +contents. Thus, stringifying @samp{p = "foo\n";} results in @samp{"p = +\"foo\\n\";"}. However, backslashes that are not inside of string or +character constants are not duplicated: @samp{\n} by itself stringifies to +@samp{"\n"}. + +Whitespace (including comments) in the text being stringified is handled +according to precise rules. All leading and trailing whitespace is ignored. +Any sequence of whitespace in the middle of the text is converted to +a single space in the stringified result. + +@node Concatenation, Undefining, Stringification, Macros +@subsection Concatenation +@cindex concatenation +@cindex @samp{##} +@dfn{Concatenation} means joining two strings into one. In the context +of macro expansion, concatenation refers to joining two lexical units +into one longer one. Specifically, an actual argument to the macro can be +concatenated with another actual argument or with fixed text to produce +a longer name. The longer name might be the name of a function, +variable or type, or a C keyword; it might even be the name of another +macro, in which case it will be expanded. + +When you define a macro, you request concatenation with the special +operator @samp{##} in the macro body. When the macro is called, +after actual arguments are substituted, all @samp{##} operators are +deleted, and so is any whitespace next to them (including whitespace +that was part of an actual argument). The result is to concatenate +the syntactic tokens on either side of the @samp{##}. + +Consider a C program that interprets named commands. There probably needs +to be a table of commands, perhaps an array of structures declared as +follows: + +@example +struct command +@{ + char *name; + void (*function) (); +@}; + +struct command commands[] = +@{ + @{ "quit", quit_command@}, + @{ "help", help_command@}, + @dots{} +@}; +@end example + +It would be cleaner not to have to give each command name twice, once in +the string constant and once in the function name. A macro which takes the +name of a command as an argument can make this unnecessary. The string +constant can be created with stringification, and the function name by +concatenating the argument with @samp{_command}. Here is how it is done: + +@example +#define COMMAND(NAME) @{ #NAME, NAME ## _command @} + +struct command commands[] = +@{ + COMMAND (quit), + COMMAND (help), + @dots{} +@}; +@end example + +The usual case of concatenation is concatenating two names (or a name and a +number) into a longer name. But this isn't the only valid case. It is +also possible to concatenate two numbers (or a number and a name, such as +@samp{1.5} and @samp{e3}) into a number. Also, multi-character operators +such as @samp{+=} can be formed by concatenation. In some cases it is even +possible to piece together a string constant. However, two pieces of text +that don't together form a valid lexical unit cannot be concatenated. For +example, concatenation with @samp{x} on one side and @samp{+} on the other +is not meaningful because those two characters can't fit together in any +lexical unit of C@. The ANSI standard says that such attempts at +concatenation are undefined, but in the GNU C preprocessor it is well +defined: it puts the @samp{x} and @samp{+} side by side with no particular +special results. + +Keep in mind that the C preprocessor converts comments to whitespace before +macros are even considered. Therefore, you cannot create a comment by +concatenating @samp{/} and @samp{*}: the @samp{/*} sequence that starts a +comment is not a lexical unit, but rather the beginning of a ``long'' space +character. Also, you can freely use comments next to a @samp{##} in a +macro definition, or in actual arguments that will be concatenated, because +the comments will be converted to spaces at first sight, and concatenation +will later discard the spaces. + +@node Undefining, Redefining, Concatenation, Macros +@subsection Undefining Macros + +@cindex undefining macros +To @dfn{undefine} a macro means to cancel its definition. This is done +with the @samp{#undef} directive. @samp{#undef} is followed by the macro +name to be undefined. + +Like definition, undefinition occurs at a specific point in the source +file, and it applies starting from that point. The name ceases to be a +macro name, and from that point on it is treated by the preprocessor as if +it had never been a macro name. + +For example, + +@example +#define FOO 4 +x = FOO; +#undef FOO +x = FOO; +@end example + +@noindent +expands into + +@example +x = 4; + +x = FOO; +@end example + +@noindent +In this example, @samp{FOO} had better be a variable or function as well +as (temporarily) a macro, in order for the result of the expansion to be +valid C code. + +The same form of @samp{#undef} directive will cancel definitions with +arguments or definitions that don't expect arguments. The @samp{#undef} +directive has no effect when used on a name not currently defined as a macro. + +@node Redefining, Macro Pitfalls, Undefining, Macros +@subsection Redefining Macros + +@cindex redefining macros +@dfn{Redefining} a macro means defining (with @samp{#define}) a name that +is already defined as a macro. + +A redefinition is trivial if the new definition is transparently identical +to the old one. You probably wouldn't deliberately write a trivial +redefinition, but they can happen automatically when a header file is +included more than once (@pxref{Header Files}), so they are accepted +silently and without effect. + +Nontrivial redefinition is considered likely to be an error, so +it provokes a warning message from the preprocessor. However, sometimes it +is useful to change the definition of a macro in mid-compilation. You can +inhibit the warning by undefining the macro with @samp{#undef} before the +second definition. + +In order for a redefinition to be trivial, the new definition must +exactly match the one already in effect, with two possible exceptions: + +@itemize @bullet +@item +Whitespace may be added or deleted at the beginning or the end. + +@item +Whitespace may be changed in the middle (but not inside strings). +However, it may not be eliminated entirely, and it may not be added +where there was no whitespace at all. +@end itemize + +Recall that a comment counts as whitespace. + +@node Macro Pitfalls,, Redefining, Macros +@subsection Pitfalls and Subtleties of Macros +@cindex problems with macros +@cindex pitfalls of macros + +In this section we describe some special rules that apply to macros and +macro expansion, and point out certain cases in which the rules have +counterintuitive consequences that you must watch out for. + +@menu +* Misnesting:: Macros can contain unmatched parentheses. +* Macro Parentheses:: Why apparently superfluous parentheses + may be necessary to avoid incorrect grouping. +* Swallow Semicolon:: Macros that look like functions + but expand into compound statements. +* Side Effects:: Unsafe macros that cause trouble when + arguments contain side effects. +* Self-Reference:: Macros whose definitions use the macros' own names. +* Argument Prescan:: Actual arguments are checked for macro calls + before they are substituted. +* Cascaded Macros:: Macros whose definitions use other macros. +* Newlines in Args:: Sometimes line numbers get confused. +@end menu + +@node Misnesting, Macro Parentheses, Macro Pitfalls, Macro Pitfalls +@subsubsection Improperly Nested Constructs + +Recall that when a macro is called with arguments, the arguments are +substituted into the macro body and the result is checked, together with +the rest of the input file, for more macro calls. + +It is possible to piece together a macro call coming partially from the +macro body and partially from the actual arguments. For example, + +@example +#define double(x) (2*(x)) +#define call_with_1(x) x(1) +@end example + +@noindent +would expand @samp{call_with_1 (double)} into @samp{(2*(1))}. + +Macro definitions do not have to have balanced parentheses. By writing an +unbalanced open parenthesis in a macro body, it is possible to create a +macro call that begins inside the macro body but ends outside of it. For +example, + +@example +#define strange(file) fprintf (file, "%s %d", +@dots{} +strange(stderr) p, 35) +@end example + +@noindent +This bizarre example expands to @samp{fprintf (stderr, "%s %d", p, 35)}! + +@node Macro Parentheses, Swallow Semicolon, Misnesting, Macro Pitfalls +@subsubsection Unintended Grouping of Arithmetic +@cindex parentheses in macro bodies + +You may have noticed that in most of the macro definition examples shown +above, each occurrence of a macro argument name had parentheses around it. +In addition, another pair of parentheses usually surround the entire macro +definition. Here is why it is best to write macros that way. + +Suppose you define a macro as follows, + +@example +#define ceil_div(x, y) (x + y - 1) / y +@end example + +@noindent +whose purpose is to divide, rounding up. (One use for this operation is +to compute how many @samp{int} objects are needed to hold a certain +number of @samp{char} objects.) Then suppose it is used as follows: + +@example +a = ceil_div (b & c, sizeof (int)); +@end example + +@noindent +This expands into + +@example +a = (b & c + sizeof (int) - 1) / sizeof (int); +@end example + +@noindent +which does not do what is intended. The operator-precedence rules of +C make it equivalent to this: + +@example +a = (b & (c + sizeof (int) - 1)) / sizeof (int); +@end example + +@noindent +But what we want is this: + +@example +a = ((b & c) + sizeof (int) - 1)) / sizeof (int); +@end example + +@noindent +Defining the macro as + +@example +#define ceil_div(x, y) ((x) + (y) - 1) / (y) +@end example + +@noindent +provides the desired result. + +Unintended grouping can result in another way. Consider +@samp{sizeof ceil_div(1, 2)}. That has the appearance of a C expression +that would compute the size of the type of @samp{ceil_div (1, 2)}, but in +fact it means something very different. Here is what it expands to: + +@example +sizeof ((1) + (2) - 1) / (2) +@end example + +@noindent +This would take the size of an integer and divide it by two. The precedence +rules have put the division outside the @samp{sizeof} when it was intended +to be inside. + +Parentheses around the entire macro definition can prevent such problems. +Here, then, is the recommended way to define @samp{ceil_div}: + +@example +#define ceil_div(x, y) (((x) + (y) - 1) / (y)) +@end example + +@node Swallow Semicolon, Side Effects, Macro Parentheses, Macro Pitfalls +@subsubsection Swallowing the Semicolon + +@cindex semicolons (after macro calls) +Often it is desirable to define a macro that expands into a compound +statement. Consider, for example, the following macro, that advances a +pointer (the argument @samp{p} says where to find it) across whitespace +characters: + +@example +#define SKIP_SPACES (p, limit) \ +@{ register char *lim = (limit); \ + while (p != lim) @{ \ + if (*p++ != ' ') @{ \ + p--; break; @}@}@} +@end example + +@noindent +Here Backslash-Newline is used to split the macro definition, which must +be a single line, so that it resembles the way such C code would be +laid out if not part of a macro definition. + +A call to this macro might be @samp{SKIP_SPACES (p, lim)}. Strictly +speaking, the call expands to a compound statement, which is a complete +statement with no need for a semicolon to end it. But it looks like a +function call. So it minimizes confusion if you can use it like a function +call, writing a semicolon afterward, as in @samp{SKIP_SPACES (p, lim);} + +But this can cause trouble before @samp{else} statements, because the +semicolon is actually a null statement. Suppose you write + +@example +if (*p != 0) + SKIP_SPACES (p, lim); +else @dots{} +@end example + +@noindent +The presence of two statements---the compound statement and a null +statement---in between the @samp{if} condition and the @samp{else} +makes invalid C code. + +The definition of the macro @samp{SKIP_SPACES} can be altered to solve +this problem, using a @samp{do @dots{} while} statement. Here is how: + +@example +#define SKIP_SPACES (p, limit) \ +do @{ register char *lim = (limit); \ + while (p != lim) @{ \ + if (*p++ != ' ') @{ \ + p--; break; @}@}@} \ +while (0) +@end example + +Now @samp{SKIP_SPACES (p, lim);} expands into + +@example +do @{@dots{}@} while (0); +@end example + +@noindent +which is one statement. + +@node Side Effects, Self-Reference, Swallow Semicolon, Macro Pitfalls +@subsubsection Duplication of Side Effects + +@cindex side effects (in macro arguments) +@cindex unsafe macros +Many C programs define a macro @samp{min}, for ``minimum'', like this: + +@example +#define min(X, Y) ((X) < (Y) ? (X) : (Y)) +@end example + +When you use this macro with an argument containing a side effect, +as shown here, + +@example +next = min (x + y, foo (z)); +@end example + +@noindent +it expands as follows: + +@example +next = ((x + y) < (foo (z)) ? (x + y) : (foo (z))); +@end example + +@noindent +where @samp{x + y} has been substituted for @samp{X} and @samp{foo (z)} +for @samp{Y}. + +The function @samp{foo} is used only once in the statement as it appears +in the program, but the expression @samp{foo (z)} has been substituted +twice into the macro expansion. As a result, @samp{foo} might be called +two times when the statement is executed. If it has side effects or +if it takes a long time to compute, the results might not be what you +intended. We say that @samp{min} is an @dfn{unsafe} macro. + +The best solution to this problem is to define @samp{min} in a way that +computes the value of @samp{foo (z)} only once. The C language offers no +standard way to do this, but it can be done with GNU C extensions as +follows: + +@example +#define min(X, Y) \ +(@{ typeof (X) __x = (X), __y = (Y); \ + (__x < __y) ? __x : __y; @}) +@end example + +If you do not wish to use GNU C extensions, the only solution is to be +careful when @emph{using} the macro @samp{min}. For example, you can +calculate the value of @samp{foo (z)}, save it in a variable, and use that +variable in @samp{min}: + +@example +#define min(X, Y) ((X) < (Y) ? (X) : (Y)) +@dots{} +@{ + int tem = foo (z); + next = min (x + y, tem); +@} +@end example + +@noindent +(where we assume that @samp{foo} returns type @samp{int}). + +@node Self-Reference, Argument Prescan, Side Effects, Macro Pitfalls +@subsubsection Self-Referential Macros + +@cindex self-reference +A @dfn{self-referential} macro is one whose name appears in its definition. +A special feature of ANSI Standard C is that the self-reference is not +considered a macro call. It is passed into the preprocessor output +unchanged. + +Let's consider an example: + +@example +#define foo (4 + foo) +@end example + +@noindent +where @samp{foo} is also a variable in your program. + +Following the ordinary rules, each reference to @samp{foo} will expand into +@samp{(4 + foo)}; then this will be rescanned and will expand into @samp{(4 ++ (4 + foo))}; and so on until it causes a fatal error (memory full) in the +preprocessor. + +However, the special rule about self-reference cuts this process short +after one step, at @samp{(4 + foo)}. Therefore, this macro definition +has the possibly useful effect of causing the program to add 4 to +the value of @samp{foo} wherever @samp{foo} is referred to. + +In most cases, it is a bad idea to take advantage of this feature. A +person reading the program who sees that @samp{foo} is a variable will +not expect that it is a macro as well. The reader will come across the +identifier @samp{foo} in the program and think its value should be that +of the variable @samp{foo}, whereas in fact the value is four greater. + +The special rule for self-reference applies also to @dfn{indirect} +self-reference. This is the case where a macro @var{x} expands to use a +macro @samp{y}, and the expansion of @samp{y} refers to the macro +@samp{x}. The resulting reference to @samp{x} comes indirectly from the +expansion of @samp{x}, so it is a self-reference and is not further +expanded. Thus, after + +@example +#define x (4 + y) +#define y (2 * x) +@end example + +@noindent +@samp{x} would expand into @samp{(4 + (2 * x))}. Clear? + +But suppose @samp{y} is used elsewhere, not from the definition of @samp{x}. +Then the use of @samp{x} in the expansion of @samp{y} is not a self-reference +because @samp{x} is not ``in progress''. So it does expand. However, +the expansion of @samp{x} contains a reference to @samp{y}, and that +is an indirect self-reference now because @samp{y} is ``in progress''. +The result is that @samp{y} expands to @samp{(2 * (4 + y))}. + +It is not clear that this behavior would ever be useful, but it is specified +by the ANSI C standard, so you may need to understand it. + +@node Argument Prescan, Cascaded Macros, Self-Reference, Macro Pitfalls +@subsubsection Separate Expansion of Macro Arguments +@cindex expansion of arguments +@cindex macro argument expansion +@cindex prescan of macro arguments + +We have explained that the expansion of a macro, including the substituted +actual arguments, is scanned over again for macro calls to be expanded. + +What really happens is more subtle: first each actual argument text is scanned +separately for macro calls. Then the results of this are substituted into +the macro body to produce the macro expansion, and the macro expansion +is scanned again for macros to expand. + +The result is that the actual arguments are scanned @emph{twice} to expand +macro calls in them. + +Most of the time, this has no effect. If the actual argument contained +any macro calls, they are expanded during the first scan. The result +therefore contains no macro calls, so the second scan does not change it. +If the actual argument were substituted as given, with no prescan, +the single remaining scan would find the same macro calls and produce +the same results. + +You might expect the double scan to change the results when a +self-referential macro is used in an actual argument of another macro +(@pxref{Self-Reference}): the self-referential macro would be expanded once +in the first scan, and a second time in the second scan. But this is not +what happens. The self-references that do not expand in the first scan are +marked so that they will not expand in the second scan either. + +The prescan is not done when an argument is stringified or concatenated. +Thus, + +@example +#define str(s) #s +#define foo 4 +str (foo) +@end example + +@noindent +expands to @samp{"foo"}. Once more, prescan has been prevented from +having any noticeable effect. + +More precisely, stringification and concatenation use the argument as +written, in un-prescanned form. The same actual argument would be used in +prescanned form if it is substituted elsewhere without stringification or +concatenation. + +@example +#define str(s) #s lose(s) +#define foo 4 +str (foo) +@end example + +expands to @samp{"foo" lose(4)}. + +You might now ask, ``Why mention the prescan, if it makes no difference? +And why not skip it and make the preprocessor faster?'' The answer is +that the prescan does make a difference in three special cases: + +@itemize @bullet +@item +Nested calls to a macro. + +@item +Macros that call other macros that stringify or concatenate. + +@item +Macros whose expansions contain unshielded commas. +@end itemize + +We say that @dfn{nested} calls to a macro occur when a macro's actual +argument contains a call to that very macro. For example, if @samp{f} +is a macro that expects one argument, @samp{f (f (1))} is a nested +pair of calls to @samp{f}. The desired expansion is made by +expanding @samp{f (1)} and substituting that into the definition of +@samp{f}. The prescan causes the expected result to happen. +Without the prescan, @samp{f (1)} itself would be substituted as +an actual argument, and the inner use of @samp{f} would appear +during the main scan as an indirect self-reference and would not +be expanded. Here, the prescan cancels an undesirable side effect +(in the medical, not computational, sense of the term) of the special +rule for self-referential macros. + +But prescan causes trouble in certain other cases of nested macro calls. +Here is an example: + +@example +#define foo a,b +#define bar(x) lose(x) +#define lose(x) (1 + (x)) + +bar(foo) +@end example + +@noindent +We would like @samp{bar(foo)} to turn into @samp{(1 + (foo))}, which +would then turn into @samp{(1 + (a,b))}. But instead, @samp{bar(foo)} +expands into @samp{lose(a,b)}, and you get an error because @code{lose} +requires a single argument. In this case, the problem is easily solved +by the same parentheses that ought to be used to prevent misnesting of +arithmetic operations: + +@example +#define foo (a,b) +#define bar(x) lose((x)) +@end example + +The problem is more serious when the operands of the macro are not +expressions; for example, when they are statements. Then parentheses +are unacceptable because they would make for invalid C code: + +@example +#define foo @{ int a, b; @dots{} @} +@end example + +@noindent +In GNU C you can shield the commas using the @samp{(@{@dots{}@})} +construct which turns a compound statement into an expression: + +@example +#define foo (@{ int a, b; @dots{} @}) +@end example + +Or you can rewrite the macro definition to avoid such commas: + +@example +#define foo @{ int a; int b; @dots{} @} +@end example + +There is also one case where prescan is useful. It is possible +to use prescan to expand an argument and then stringify it---if you use +two levels of macros. Let's add a new macro @samp{xstr} to the +example shown above: + +@example +#define xstr(s) str(s) +#define str(s) #s +#define foo 4 +xstr (foo) +@end example + +This expands into @samp{"4"}, not @samp{"foo"}. The reason for the +difference is that the argument of @samp{xstr} is expanded at prescan +(because @samp{xstr} does not specify stringification or concatenation of +the argument). The result of prescan then forms the actual argument for +@samp{str}. @samp{str} uses its argument without prescan because it +performs stringification; but it cannot prevent or undo the prescanning +already done by @samp{xstr}. + +@node Cascaded Macros, Newlines in Args, Argument Prescan, Macro Pitfalls +@subsubsection Cascaded Use of Macros + +@cindex cascaded macros +@cindex macro body uses macro +A @dfn{cascade} of macros is when one macro's body contains a reference +to another macro. This is very common practice. For example, + +@example +#define BUFSIZE 1020 +#define TABLESIZE BUFSIZE +@end example + +This is not at all the same as defining @samp{TABLESIZE} to be @samp{1020}. +The @samp{#define} for @samp{TABLESIZE} uses exactly the body you +specify---in this case, @samp{BUFSIZE}---and does not check to see whether +it too is the name of a macro. + +It's only when you @emph{use} @samp{TABLESIZE} that the result of its expansion +is checked for more macro names. + +This makes a difference if you change the definition of @samp{BUFSIZE} +at some point in the source file. @samp{TABLESIZE}, defined as shown, +will always expand using the definition of @samp{BUFSIZE} that is +currently in effect: + +@example +#define BUFSIZE 1020 +#define TABLESIZE BUFSIZE +#undef BUFSIZE +#define BUFSIZE 37 +@end example + +@noindent +Now @samp{TABLESIZE} expands (in two stages) to @samp{37}. (The +@samp{#undef} is to prevent any warning about the nontrivial +redefinition of @code{BUFSIZE}.) + +@node Newlines in Args,, Cascaded Macros, Macro Pitfalls +@subsection Newlines in Macro Arguments +@cindex newlines in macro arguments + +Traditional macro processing carries forward all newlines in macro +arguments into the expansion of the macro. This means that, if some of +the arguments are substituted more than once, or not at all, or out of +order, newlines can be duplicated, lost, or moved around within the +expansion. If the expansion consists of multiple statements, then the +effect is to distort the line numbers of some of these statements. The +result can be incorrect line numbers, in error messages or displayed in +a debugger. + +The GNU C preprocessor operating in ANSI C mode adjusts appropriately +for multiple use of an argument---the first use expands all the +newlines, and subsequent uses of the same argument produce no newlines. +But even in this mode, it can produce incorrect line numbering if +arguments are used out of order, or not used at all. + +Here is an example illustrating this problem: + +@example +#define ignore_second_arg(a,b,c) a; c + +ignore_second_arg (foo (), + ignored (), + syntax error); +@end example + +@noindent +The syntax error triggered by the tokens @samp{syntax error} results +in an error message citing line four, even though the statement text +comes from line five. + +@node Conditionals, Combining Sources, Macros, Top +@section Conditionals + +@cindex conditionals +In a macro processor, a @dfn{conditional} is a directive that allows a part +of the program to be ignored during compilation, on some conditions. +In the C preprocessor, a conditional can test either an arithmetic expression +or whether a name is defined as a macro. + +A conditional in the C preprocessor resembles in some ways an @samp{if} +statement in C, but it is important to understand the difference between +them. The condition in an @samp{if} statement is tested during the execution +of your program. Its purpose is to allow your program to behave differently +from run to run, depending on the data it is operating on. The condition +in a preprocessing conditional directive is tested when your program is compiled. +Its purpose is to allow different code to be included in the program depending +on the situation at the time of compilation. + +@menu +* Uses: Conditional Uses. What conditionals are for. +* Syntax: Conditional Syntax. How conditionals are written. +* Deletion: Deleted Code. Making code into a comment. +* Macros: Conditionals-Macros. Why conditionals are used with macros. +* Assertions:: How and why to use assertions. +* Errors: #error Directive. Detecting inconsistent compilation parameters. +@end menu + +@node Conditional Uses +@subsection Why Conditionals are Used + +Generally there are three kinds of reason to use a conditional. + +@itemize @bullet +@item +A program may need to use different code depending on the machine or +operating system it is to run on. In some cases the code for one +operating system may be erroneous on another operating system; for +example, it might refer to library routines that do not exist on the +other system. When this happens, it is not enough to avoid executing +the invalid code: merely having it in the program makes it impossible +to link the program and run it. With a preprocessing conditional, the +offending code can be effectively excised from the program when it is +not valid. + +@item +You may want to be able to compile the same source file into two +different programs. Sometimes the difference between the programs is +that one makes frequent time-consuming consistency checks on its +intermediate data, or prints the values of those data for debugging, +while the other does not. + +@item +A conditional whose condition is always false is a good way to exclude +code from the program but keep it as a sort of comment for future +reference. +@end itemize + +Most simple programs that are intended to run on only one machine will +not need to use preprocessing conditionals. + +@node Conditional Syntax +@subsection Syntax of Conditionals + +@findex #if +A conditional in the C preprocessor begins with a @dfn{conditional +directive}: @samp{#if}, @samp{#ifdef} or @samp{#ifndef}. +@xref{Conditionals-Macros}, for information on @samp{#ifdef} and +@samp{#ifndef}; only @samp{#if} is explained here. + +@menu +* If: #if Directive. Basic conditionals using @samp{#if} and @samp{#endif}. +* Else: #else Directive. Including some text if the condition fails. +* Elif: #elif Directive. Testing several alternative possibilities. +@end menu + +@node #if Directive +@subsubsection The @samp{#if} Directive + +The @samp{#if} directive in its simplest form consists of + +@example +#if @var{expression} +@var{controlled text} +#endif /* @var{expression} */ +@end example + +The comment following the @samp{#endif} is not required, but it is a good +practice because it helps people match the @samp{#endif} to the +corresponding @samp{#if}. Such comments should always be used, except in +short conditionals that are not nested. In fact, you can put anything at +all after the @samp{#endif} and it will be ignored by the GNU C preprocessor, +but only comments are acceptable in ANSI Standard C@. + +@var{expression} is a C expression of integer type, subject to stringent +restrictions. It may contain + +@itemize @bullet +@item +Integer constants, which are all regarded as @code{long} or +@code{unsigned long}. + +@item +Character constants, which are interpreted according to the character +set and conventions of the machine and operating system on which the +preprocessor is running. The GNU C preprocessor uses the C data type +@samp{char} for these character constants; therefore, whether some +character codes are negative is determined by the C compiler used to +compile the preprocessor. If it treats @samp{char} as signed, then +character codes large enough to set the sign bit will be considered +negative; otherwise, no character code is considered negative. + +@item +Arithmetic operators for addition, subtraction, multiplication, +division, bitwise operations, shifts, comparisons, and logical +operations (@samp{&&} and @samp{||}). + +@item +Identifiers that are not macros, which are all treated as zero(!). + +@item +Macro calls. All macro calls in the expression are expanded before +actual computation of the expression's value begins. +@end itemize + +Note that @samp{sizeof} operators and @code{enum}-type values are not allowed. +@code{enum}-type values, like all other identifiers that are not taken +as macro calls and expanded, are treated as zero. + +The @var{controlled text} inside of a conditional can include +preprocessing directives. Then the directives inside the conditional are +obeyed only if that branch of the conditional succeeds. The text can +also contain other conditional groups. However, the @samp{#if} and +@samp{#endif} directives must balance. + +@node #else Directive +@subsubsection The @samp{#else} Directive + +@findex #else +The @samp{#else} directive can be added to a conditional to provide +alternative text to be used if the condition is false. This is what +it looks like: + +@example +#if @var{expression} +@var{text-if-true} +#else /* Not @var{expression} */ +@var{text-if-false} +#endif /* Not @var{expression} */ +@end example + +If @var{expression} is nonzero, and thus the @var{text-if-true} is +active, then @samp{#else} acts like a failing conditional and the +@var{text-if-false} is ignored. Contrariwise, if the @samp{#if} +conditional fails, the @var{text-if-false} is considered included. + +@node #elif Directive +@subsubsection The @samp{#elif} Directive + +@findex #elif +One common case of nested conditionals is used to check for more than two +possible alternatives. For example, you might have + +@example +#if X == 1 +@dots{} +#else /* X != 1 */ +#if X == 2 +@dots{} +#else /* X != 2 */ +@dots{} +#endif /* X != 2 */ +#endif /* X != 1 */ +@end example + +Another conditional directive, @samp{#elif}, allows this to be abbreviated +as follows: + +@example +#if X == 1 +@dots{} +#elif X == 2 +@dots{} +#else /* X != 2 and X != 1*/ +@dots{} +#endif /* X != 2 and X != 1*/ +@end example + +@samp{#elif} stands for ``else if''. Like @samp{#else}, it goes in the +middle of a @samp{#if}-@samp{#endif} pair and subdivides it; it does not +require a matching @samp{#endif} of its own. Like @samp{#if}, the +@samp{#elif} directive includes an expression to be tested. + +The text following the @samp{#elif} is processed only if the original +@samp{#if}-condition failed and the @samp{#elif} condition succeeds. +More than one @samp{#elif} can go in the same @samp{#if}-@samp{#endif} +group. Then the text after each @samp{#elif} is processed only if the +@samp{#elif} condition succeeds after the original @samp{#if} and any +previous @samp{#elif} directives within it have failed. @samp{#else} is +equivalent to @samp{#elif 1}, and @samp{#else} is allowed after any +number of @samp{#elif} directives, but @samp{#elif} may not follow +@samp{#else}. + +@node Deleted Code +@subsection Keeping Deleted Code for Future Reference +@cindex commenting out code + +If you replace or delete a part of the program but want to keep the old +code around as a comment for future reference, the easy way to do this +is to put @samp{#if 0} before it and @samp{#endif} after it. This is +better than using comment delimiters @samp{/*} and @samp{*/} since those +won't work if the code already contains comments (C comments do not +nest). + +This works even if the code being turned off contains conditionals, but +they must be entire conditionals (balanced @samp{#if} and @samp{#endif}). + +Conversely, do not use @samp{#if 0} for comments which are not C code. +Use the comment delimiters @samp{/*} and @samp{*/} instead. The +interior of @samp{#if 0} must consist of complete tokens; in particular, +singlequote characters must balance. But comments often contain +unbalanced singlequote characters (known in English as apostrophes). +These confuse @samp{#if 0}. They do not confuse @samp{/*}. + +@node Conditionals-Macros +@subsection Conditionals and Macros + +Conditionals are useful in connection with macros or assertions, because +those are the only ways that an expression's value can vary from one +compilation to another. A @samp{#if} directive whose expression uses no +macros or assertions is equivalent to @samp{#if 1} or @samp{#if 0}; you +might as well determine which one, by computing the value of the +expression yourself, and then simplify the program. + +For example, here is a conditional that tests the expression +@samp{BUFSIZE == 1020}, where @samp{BUFSIZE} must be a macro. + +@example +#if BUFSIZE == 1020 + printf ("Large buffers!\n"); +#endif /* BUFSIZE is large */ +@end example + +(Programmers often wish they could test the size of a variable or data +type in @samp{#if}, but this does not work. The preprocessor does not +understand @code{sizeof}, or typedef names, or even the type keywords +such as @code{int}.) + +@findex defined +The special operator @samp{defined} is used in @samp{#if} expressions to +test whether a certain name is defined as a macro. Either @samp{defined +@var{name}} or @samp{defined (@var{name})} is an expression whose value +is 1 if @var{name} is defined as macro at the current point in the +program, and 0 otherwise. For the @samp{defined} operator it makes no +difference what the definition of the macro is; all that matters is +whether there is a definition. Thus, for example,@refill + +@example +#if defined (vax) || defined (ns16000) +@end example + +@noindent +would succeed if either of the names @samp{vax} and @samp{ns16000} is +defined as a macro. You can test the same condition using assertions +(@pxref{Assertions}), like this: + +@example +#if #cpu (vax) || #cpu (ns16000) +@end example + +If a macro is defined and later undefined with @samp{#undef}, +subsequent use of the @samp{defined} operator returns 0, because +the name is no longer defined. If the macro is defined again with +another @samp{#define}, @samp{defined} will recommence returning 1. + +@findex #ifdef +@findex #ifndef +Conditionals that test whether just one name is defined are very common, +so there are two special short conditional directives for this case. + +@table @code +@item #ifdef @var{name} +is equivalent to @samp{#if defined (@var{name})}. + +@item #ifndef @var{name} +is equivalent to @samp{#if ! defined (@var{name})}. +@end table + +Macro definitions can vary between compilations for several reasons. + +@itemize @bullet +@item +Some macros are predefined on each kind of machine. For example, on a +Vax, the name @samp{vax} is a predefined macro. On other machines, it +would not be defined. + +@item +Many more macros are defined by system header files. Different +systems and machines define different macros, or give them different +values. It is useful to test these macros with conditionals to avoid +using a system feature on a machine where it is not implemented. + +@item +Macros are a common way of allowing users to customize a program for +different machines or applications. For example, the macro +@samp{BUFSIZE} might be defined in a configuration file for your +program that is included as a header file in each source file. You +would use @samp{BUFSIZE} in a preprocessing conditional in order to +generate different code depending on the chosen configuration. + +@item +Macros can be defined or undefined with @samp{-D} and @samp{-U} +command options when you compile the program. You can arrange to +compile the same source file into two different programs by choosing +a macro name to specify which program you want, writing conditionals +to test whether or how this macro is defined, and then controlling +the state of the macro with compiler command options. +@xref{Invocation}. +@end itemize + +@ifinfo +Assertions are usually predefined, but can be defined with preprocessor +directives or command-line options. +@end ifinfo + +@node Assertions +@subsection Assertions + +@cindex assertions +@dfn{Assertions} are a more systematic alternative to macros in writing +conditionals to test what sort of computer or system the compiled +program will run on. Assertions are usually predefined, but you can +define them with preprocessing directives or command-line options. + +@cindex predicates +The macros traditionally used to describe the type of target are not +classified in any way according to which question they answer; they may +indicate a hardware architecture, a particular hardware model, an +operating system, a particular version of an operating system, or +specific configuration options. These are jumbled together in a single +namespace. In contrast, each assertion consists of a named question and +an answer. The question is usually called the @dfn{predicate}. +An assertion looks like this: + +@example +#@var{predicate} (@var{answer}) +@end example + +@noindent +You must use a properly formed identifier for @var{predicate}. The +value of @var{answer} can be any sequence of words; all characters are +significant except for leading and trailing whitespace, and differences +in internal whitespace sequences are ignored. Thus, @samp{x + y} is +different from @samp{x+y} but equivalent to @samp{x + y}. @samp{)} is +not allowed in an answer. + +@cindex testing predicates +Here is a conditional to test whether the answer @var{answer} is asserted +for the predicate @var{predicate}: + +@example +#if #@var{predicate} (@var{answer}) +@end example + +@noindent +There may be more than one answer asserted for a given predicate. If +you omit the answer, you can test whether @emph{any} answer is asserted +for @var{predicate}: + +@example +#if #@var{predicate} +@end example + +@findex #system +@findex #machine +@findex #cpu +Most of the time, the assertions you test will be predefined assertions. +GNU C provides three predefined predicates: @code{system}, @code{cpu}, +and @code{machine}. @code{system} is for assertions about the type of +software, @code{cpu} describes the type of computer architecture, and +@code{machine} gives more information about the computer. For example, +on a GNU system, the following assertions would be true: + +@example +#system (gnu) +#system (mach) +#system (mach 3) +#system (mach 3.@var{subversion}) +#system (hurd) +#system (hurd @var{version}) +@end example + +@noindent +and perhaps others. The alternatives with +more or less version information let you ask more or less detailed +questions about the type of system software. + +On a Unix system, you would find @code{#system (unix)} and perhaps one of: +@code{#system (aix)}, @code{#system (bsd)}, @code{#system (hpux)}, +@code{#system (lynx)}, @code{#system (mach)}, @code{#system (posix)}, +@code{#system (svr3)}, @code{#system (svr4)}, or @code{#system (xpg4)} +with possible version numbers following. + +Other values for @code{system} are @code{#system (mvs)} +and @code{#system (vms)}. + +@strong{Portability note:} Many Unix C compilers provide only one answer +for the @code{system} assertion: @code{#system (unix)}, if they support +assertions at all. This is less than useful. + +An assertion with a multi-word answer is completely different from several +assertions with individual single-word answers. For example, the presence +of @code{system (mach 3.0)} does not mean that @code{system (3.0)} is true. +It also does not directly imply @code{system (mach)}, but in GNU C, that +last will normally be asserted as well. + +The current list of possible assertion values for @code{cpu} is: +@code{#cpu (a29k)}, @code{#cpu (alpha)}, @code{#cpu (arm)}, @code{#cpu +(clipper)}, @code{#cpu (convex)}, @code{#cpu (elxsi)}, @code{#cpu +(tron)}, @code{#cpu (h8300)}, @code{#cpu (i370)}, @code{#cpu (i386)}, +@code{#cpu (i860)}, @code{#cpu (i960)}, @code{#cpu (m68k)}, @code{#cpu +(m88k)}, @code{#cpu (mips)}, @code{#cpu (ns32k)}, @code{#cpu (hppa)}, +@code{#cpu (pyr)}, @code{#cpu (ibm032)}, @code{#cpu (rs6000)}, +@code{#cpu (sh)}, @code{#cpu (sparc)}, @code{#cpu (spur)}, @code{#cpu +(tahoe)}, @code{#cpu (vax)}, @code{#cpu (we32000)}. + +@findex #assert +You can create assertions within a C program using @samp{#assert}, like +this: + +@example +#assert @var{predicate} (@var{answer}) +@end example + +@noindent +(Note the absence of a @samp{#} before @var{predicate}.) + +@cindex unassert +@cindex assertions, undoing +@cindex retracting assertions +@findex #unassert +Each time you do this, you assert a new true answer for @var{predicate}. +Asserting one answer does not invalidate previously asserted answers; +they all remain true. The only way to remove an assertion is with +@samp{#unassert}. @samp{#unassert} has the same syntax as +@samp{#assert}. You can also remove all assertions about +@var{predicate} like this: + +@example +#unassert @var{predicate} +@end example + +You can also add or cancel assertions using command options +when you run @code{gcc} or @code{cpp}. @xref{Invocation}. + +@node #error Directive +@subsection The @samp{#error} and @samp{#warning} Directives + +@findex #error +The directive @samp{#error} causes the preprocessor to report a fatal +error. The rest of the line that follows @samp{#error} is used as the +error message. The line must consist of complete tokens. + +You would use @samp{#error} inside of a conditional that detects a +combination of parameters which you know the program does not properly +support. For example, if you know that the program will not run +properly on a Vax, you might write + +@smallexample +@group +#ifdef __vax__ +#error "Won't work on Vaxen. See comments at get_last_object." +#endif +@end group +@end smallexample + +@noindent +@xref{Nonstandard Predefined}, for why this works. + +If you have several configuration parameters that must be set up by +the installation in a consistent way, you can use conditionals to detect +an inconsistency and report it with @samp{#error}. For example, + +@smallexample +#if HASH_TABLE_SIZE % 2 == 0 || HASH_TABLE_SIZE % 3 == 0 \ + || HASH_TABLE_SIZE % 5 == 0 +#error HASH_TABLE_SIZE should not be divisible by a small prime +#endif +@end smallexample + +@findex #warning +The directive @samp{#warning} is like the directive @samp{#error}, but causes +the preprocessor to issue a warning and continue preprocessing. The rest of +the line that follows @samp{#warning} is used as the warning message. + +You might use @samp{#warning} in obsolete header files, with a message +directing the user to the header file which should be used instead. + +@node Combining Sources, Other Directives, Conditionals, Top +@section Combining Source Files + +@cindex line control +One of the jobs of the C preprocessor is to inform the C compiler of where +each line of C code came from: which source file and which line number. + +C code can come from multiple source files if you use @samp{#include}; +both @samp{#include} and the use of conditionals and macros can cause +the line number of a line in the preprocessor output to be different +from the line's number in the original source file. You will appreciate +the value of making both the C compiler (in error messages) and symbolic +debuggers such as GDB use the line numbers in your source file. + +The C preprocessor builds on this feature by offering a directive by which +you can control the feature explicitly. This is useful when a file for +input to the C preprocessor is the output from another program such as the +@code{bison} parser generator, which operates on another file that is the +true source file. Parts of the output from @code{bison} are generated from +scratch, other parts come from a standard parser file. The rest are copied +nearly verbatim from the source file, but their line numbers in the +@code{bison} output are not the same as their original line numbers. +Naturally you would like compiler error messages and symbolic debuggers to +know the original source file and line number of each line in the +@code{bison} input. + +@findex #line +@code{bison} arranges this by writing @samp{#line} directives into the output +file. @samp{#line} is a directive that specifies the original line number +and source file name for subsequent input in the current preprocessor input +file. @samp{#line} has three variants: + +@table @code +@item #line @var{linenum} +Here @var{linenum} is a decimal integer constant. This specifies that +the line number of the following line of input, in its original source file, +was @var{linenum}. + +@item #line @var{linenum} @var{filename} +Here @var{linenum} is a decimal integer constant and @var{filename} +is a string constant. This specifies that the following line of input +came originally from source file @var{filename} and its line number there +was @var{linenum}. Keep in mind that @var{filename} is not just a +file name; it is surrounded by doublequote characters so that it looks +like a string constant. + +@item #line @var{anything else} +@var{anything else} is checked for macro calls, which are expanded. +The result should be a decimal integer constant followed optionally +by a string constant, as described above. +@end table + +@samp{#line} directives alter the results of the @samp{__FILE__} and +@samp{__LINE__} predefined macros from that point on. @xref{Standard +Predefined}. + +The output of the preprocessor (which is the input for the rest of the +compiler) contains directives that look much like @samp{#line} directives. +They start with just @samp{#} instead of @samp{#line}, but this is +followed by a line number and file name as in @samp{#line}. @xref{Output}. + +@node Other Directives, Output, Combining Sources, Top +@section Miscellaneous Preprocessing Directives + +@cindex null directive +This section describes three additional preprocessing directives. They are +not very useful, but are mentioned for completeness. + +The @dfn{null directive} consists of a @samp{#} followed by a Newline, with +only whitespace (including comments) in between. A null directive is +understood as a preprocessing directive but has no effect on the preprocessor +output. The primary significance of the existence of the null directive is +that an input line consisting of just a @samp{#} will produce no output, +rather than a line of output containing just a @samp{#}. Supposedly +some old C programs contain such lines. + +@findex #pragma +The ANSI standard specifies that the effect of the @samp{#pragma} +directive is implementation-defined. In the GNU C preprocessor, +@samp{#pragma} directives are not used, except for @samp{#pragma once} +(@pxref{Once-Only}). However, they are left in the preprocessor output, +so they are available to the compilation pass. + +@findex #ident +The @samp{#ident} directive is supported for compatibility with certain +other systems. It is followed by a line of text. On some systems, the +text is copied into a special place in the object file; on most systems, +the text is ignored and this directive has no effect. Typically +@samp{#ident} is only used in header files supplied with those systems +where it is meaningful. + +@node Output, Invocation, Other Directives, Top +@section C Preprocessor Output + +@cindex output format +The output from the C preprocessor looks much like the input, except +that all preprocessing directive lines have been replaced with blank lines +and all comments with spaces. Whitespace within a line is not altered; +however, unless @samp{-traditional} is used, spaces may be inserted into +the expansions of macro calls to prevent tokens from being concatenated. + +Source file name and line number information is conveyed by lines of +the form + +@example +# @var{linenum} @var{filename} @var{flags} +@end example + +@noindent +which are inserted as needed into the middle of the input (but never +within a string or character constant). Such a line means that the +following line originated in file @var{filename} at line @var{linenum}. + +After the file name comes zero or more flags, which are @samp{1}, +@samp{2}, @samp{3}, or @samp{4}. If there are multiple flags, spaces separate +them. Here is what the flags mean: + +@table @samp +@item 1 +This indicates the start of a new file. +@item 2 +This indicates returning to a file (after having included another file). +@item 3 +This indicates that the following text comes from a system header file, +so certain warnings should be suppressed. +@item 4 +This indicates that the following text should be treated as C@. +@c maybe cross reference NO_IMPLICIT_EXTERN_C +@end table + +@node Invocation, Concept Index, Output, Top +@section Invoking the C Preprocessor +@cindex invocation of the preprocessor + +Most often when you use the C preprocessor you will not have to invoke it +explicitly: the C compiler will do so automatically. However, the +preprocessor is sometimes useful on its own. + +The C preprocessor expects two file names as arguments, @var{infile} and +@var{outfile}. The preprocessor reads @var{infile} together with any other +files it specifies with @samp{#include}. All the output generated by the +combined input files is written in @var{outfile}. + +Either @var{infile} or @var{outfile} may be @samp{-}, which as @var{infile} +means to read from standard input and as @var{outfile} means to write to +standard output. Also, if @var{outfile} or both file names are omitted, +the standard output and standard input are used for the omitted file names. + +@cindex options +Here is a table of command options accepted by the C preprocessor. +These options can also be given when compiling a C program; they are +passed along automatically to the preprocessor when it is invoked by the +compiler. + +@table @samp +@item -P +@findex -P +Inhibit generation of @samp{#}-lines with line-number information in +the output from the preprocessor (@pxref{Output}). This might be +useful when running the preprocessor on something that is not C code +and will be sent to a program which might be confused by the +@samp{#}-lines. + +@item -C +@findex -C +Do not discard comments: pass them through to the output file. +Comments appearing in arguments of a macro call will be copied to the +output before the expansion of the macro call. + +@item -traditional +@findex -traditional +Try to imitate the behavior of old-fashioned C, as opposed to ANSI C@. + +@itemize @bullet +@item +Traditional macro expansion pays no attention to singlequote or +doublequote characters; macro argument symbols are replaced by the +argument values even when they appear within apparent string or +character constants. + +@item +Traditionally, it is permissible for a macro expansion to end in the +middle of a string or character constant. The constant continues into +the text surrounding the macro call. + +@item +However, traditionally the end of the line terminates a string or +character constant, with no error. + +@item +In traditional C, a comment is equivalent to no text at all. (In ANSI +C, a comment counts as whitespace.) + +@item +Traditional C does not have the concept of a ``preprocessing number''. +It considers @samp{1.0e+4} to be three tokens: @samp{1.0e}, @samp{+}, +and @samp{4}. + +@item +A macro is not suppressed within its own definition, in traditional C@. +Thus, any macro that is used recursively inevitably causes an error. + +@item +The character @samp{#} has no special meaning within a macro definition +in traditional C@. + +@item +In traditional C, the text at the end of a macro expansion can run +together with the text after the macro call, to produce a single token. +(This is impossible in ANSI C@.) + +@item +Traditionally, @samp{\} inside a macro argument suppresses the syntactic +significance of the following character. +@end itemize + +@cindex Fortran +@cindex unterminated +Use the @samp{-traditional} option when preprocessing Fortran code, +so that singlequotes and doublequotes +within Fortran comment lines +(which are generally not recognized as such by the preprocessor) +do not cause diagnostics +about unterminated character or string constants. + +However, this option does not prevent diagnostics +about unterminated comments +when a C-style comment appears to start, but not end, +within Fortran-style commentary. + +So, the following Fortran comment lines are accepted with +@samp{-traditional}: + +@smallexample +C This isn't an unterminated character constant +C Neither is "20000000000, an octal constant +C in some dialects of Fortran +@end smallexample + +However, this type of comment line will likely produce a diagnostic, +or at least unexpected output from the preprocessor, +due to the unterminated comment: + +@smallexample +C Some Fortran compilers accept /* as starting +C an inline comment. +@end smallexample + +@cindex g77 +Note that @code{g77} automatically supplies +the @samp{-traditional} option +when it invokes the preprocessor. +However, a future version of @code{g77} +might use a different, more-Fortran-aware preprocessor +in place of @code{cpp}. + +@item -trigraphs +@findex -trigraphs +Process ANSI standard trigraph sequences. These are three-character +sequences, all starting with @samp{??}, that are defined by ANSI C to +stand for single characters. For example, @samp{??/} stands for +@samp{\}, so @samp{'??/n'} is a character constant for a newline. +Strictly speaking, the GNU C preprocessor does not support all +programs in ANSI Standard C unless @samp{-trigraphs} is used, but if +you ever notice the difference it will be with relief. + +You don't want to know any more about trigraphs. + +@item -pedantic +@findex -pedantic +Issue warnings required by the ANSI C standard in certain cases such +as when text other than a comment follows @samp{#else} or @samp{#endif}. + +@item -pedantic-errors +@findex -pedantic-errors +Like @samp{-pedantic}, except that errors are produced rather than +warnings. + +@item -Wtrigraphs +@findex -Wtrigraphs +Warn if any trigraphs are encountered (assuming they are enabled). + +@item -Wcomment +@findex -Wcomment +@ignore +@c "Not worth documenting" both singular and plural forms of this +@c option, per RMS. But also unclear which is better; hence may need to +@c switch this at some future date. pesch@cygnus.com, 2jan92. +@itemx -Wcomments +(Both forms have the same effect). +@end ignore +Warn whenever a comment-start sequence @samp{/*} appears in a @samp{/*} +comment, or whenever a Backslash-Newline appears in a @samp{//} comment. + +@item -Wall +@findex -Wall +Requests both @samp{-Wtrigraphs} and @samp{-Wcomment} (but not +@samp{-Wtraditional} or @samp{-Wundef}). + +@item -Wtraditional +@findex -Wtraditional +Warn about certain constructs that behave differently in traditional and +ANSI C@. + +@item -Wundef +@findex -Wundef +Warn if an undefined identifier is evaluated in an @samp{#if} directive. + +@item -I @var{directory} +@findex -I +Add the directory @var{directory} to the head of the list of +directories to be searched for header files (@pxref{Include Syntax}). +This can be used to override a system header file, substituting your +own version, since these directories are searched before the system +header file directories. If you use more than one @samp{-I} option, +the directories are scanned in left-to-right order; the standard +system directories come after. + +@item -I- +Any directories specified with @samp{-I} options before the @samp{-I-} +option are searched only for the case of @samp{#include "@var{file}"}; +they are not searched for @samp{#include <@var{file}>}. + +If additional directories are specified with @samp{-I} options after +the @samp{-I-}, these directories are searched for all @samp{#include} +directives. + +In addition, the @samp{-I-} option inhibits the use of the current +directory as the first search directory for @samp{#include "@var{file}"}. +Therefore, the current directory is searched only if it is requested +explicitly with @samp{-I.}. Specifying both @samp{-I-} and @samp{-I.} +allows you to control precisely which directories are searched before +the current one and which are searched after. + +@item -nostdinc +@findex -nostdinc +Do not search the standard system directories for header files. +Only the directories you have specified with @samp{-I} options +(and the current directory, if appropriate) are searched. + +@item -nostdinc++ +@findex -nostdinc++ +Do not search for header files in the C++-specific standard directories, +but do still search the other standard directories. +(This option is used when building the C++ library.) + +@item -remap +@findex -remap +When searching for a header file in a directory, remap file names if a +file named @file{header.gcc} exists in that directory. This can be used +to work around limitations of file systems with file name restrictions. +The @file{header.gcc} file should contain a series of lines with two +tokens on each line: the first token is the name to map, and the second +token is the actual name to use. + +@item -D @var{name} +@findex -D +Predefine @var{name} as a macro, with definition @samp{1}. + +@item -D @var{name}=@var{definition} +Predefine @var{name} as a macro, with definition @var{definition}. +There are no restrictions on the contents of @var{definition}, but if +you are invoking the preprocessor from a shell or shell-like program you +may need to use the shell's quoting syntax to protect characters such as +spaces that have a meaning in the shell syntax. If you use more than +one @samp{-D} for the same @var{name}, the rightmost definition takes +effect. + +@item -U @var{name} +@findex -U +Do not predefine @var{name}. If both @samp{-U} and @samp{-D} are +specified for one name, the @samp{-U} beats the @samp{-D} and the name +is not predefined. + +@item -undef +@findex -undef +Do not predefine any nonstandard macros. + +@item -A @var{predicate}(@var{answer}) +@findex -A +Make an assertion with the predicate @var{predicate} and answer +@var{answer}. @xref{Assertions}. + +@noindent +You can use @samp{-A-} to disable all predefined assertions; it also +undefines all predefined macros that identify the type of target system. + +@item -dM +@findex -dM +Instead of outputting the result of preprocessing, output a list of +@samp{#define} directives for all the macros defined during the +execution of the preprocessor, including predefined macros. This gives +you a way of finding out what is predefined in your version of the +preprocessor; assuming you have no file @samp{foo.h}, the command + +@example +touch foo.h; cpp -dM foo.h +@end example + +@noindent +will show the values of any predefined macros. + +@item -dD +@findex -dD +Like @samp{-dM} except in two respects: it does @emph{not} include the +predefined macros, and it outputs @emph{both} the @samp{#define} +directives and the result of preprocessing. Both kinds of output go to +the standard output file. + +@item -dI +@findex -dI +Output @samp{#include} directives in addition to the result of preprocessing. + +@item -M [-MG] +@findex -M +Instead of outputting the result of preprocessing, output a rule +suitable for @code{make} describing the dependencies of the main +source file. The preprocessor outputs one @code{make} rule containing +the object file name for that source file, a colon, and the names of +all the included files. If there are many included files then the +rule is split into several lines using @samp{\}-newline. + +@samp{-MG} says to treat missing header files as generated files and assume +they live in the same directory as the source file. It must be specified +in addition to @samp{-M}. + +This feature is used in automatic updating of makefiles. + +@item -MM [-MG] +@findex -MM +Like @samp{-M} but mention only the files included with @samp{#include +"@var{file}"}. System header files included with @samp{#include +<@var{file}>} are omitted. + +@item -MD @var{file} +@findex -MD +Like @samp{-M} but the dependency information is written to @var{file}. +This is in addition to compiling the file as specified---@samp{-MD} does +not inhibit ordinary compilation the way @samp{-M} does. + +When invoking @code{gcc}, do not specify the @var{file} argument. +@code{gcc} will create file names made by replacing ".c" with ".d" at +the end of the input file names. + +In Mach, you can use the utility @code{md} to merge multiple dependency +files into a single dependency file suitable for using with the @samp{make} +command. + +@item -MMD @var{file} +@findex -MMD +Like @samp{-MD} except mention only user header files, not system +header files. + +@item -H +@findex -H +Print the name of each header file used, in addition to other normal +activities. + +@item -imacros @var{file} +@findex -imacros +Process @var{file} as input, discarding the resulting output, before +processing the regular input file. Because the output generated from +@var{file} is discarded, the only effect of @samp{-imacros @var{file}} +is to make the macros defined in @var{file} available for use in the +main input. + +@item -include @var{file} +@findex -include +Process @var{file} as input, and include all the resulting output, +before processing the regular input file. + +@item -idirafter @var{dir} +@findex -idirafter +@cindex second include path +Add the directory @var{dir} to the second include path. The directories +on the second include path are searched when a header file is not found +in any of the directories in the main include path (the one that +@samp{-I} adds to). + +@item -iprefix @var{prefix} +@findex -iprefix +Specify @var{prefix} as the prefix for subsequent @samp{-iwithprefix} +options. + +@item -iwithprefix @var{dir} +@findex -iwithprefix +Add a directory to the second include path. The directory's name is +made by concatenating @var{prefix} and @var{dir}, where @var{prefix} +was specified previously with @samp{-iprefix}. + +@item -isystem @var{dir} +@findex -isystem +Add a directory to the beginning of the second include path, marking it +as a system directory, so that it gets the same special treatment as +is applied to the standard system directories. + +@item -lang-c +@itemx -lang-c89 +@itemx -lang-c++ +@itemx -lang-objc +@itemx -lang-objc++ +@findex -lang-c +@findex -lang-c89 +@findex -lang-c++ +@findex -lang-objc +@findex -lang-objc++ +Specify the source language. @samp{-lang-c} is the default; it +allows recognition of C++ comments (comments that begin with +@samp{//} and end at end of line) and hexadecimal floating-point constants, +since these features will most likely appear in the next C standard. +@samp{-lang-c89} disables recognition of C++ comments and +hexadecimal floating-point constants. @samp{-lang-c++} +handles C++ comment syntax and includes extra default include +directories for C++. @samp{-lang-objc} enables the Objective C +@samp{#import} directive. @samp{-lang-objc++} enables both C++ and Objective C +extensions. + +These options are generated by the compiler driver @code{gcc}, but not +passed from the @samp{gcc} command line unless you use the driver's +@samp{-Wp} option. + +@item -lint +Look for commands to the program checker @code{lint} embedded in +comments, and emit them preceded by @samp{#pragma lint}. For example, +the comment @samp{/* NOTREACHED */} becomes @samp{#pragma lint +NOTREACHED}. + +This option is available only when you call @code{cpp} directly; +@code{gcc} will not pass it from its command line. + +@item -$ +@findex -$ +Forbid the use of @samp{$} in identifiers. This was formerly required +for strict conformance to the C Standard before the standard was +corrected. + +This option is available only when you call @code{cpp} directly; +@code{gcc} will not pass it from its command line. + +@end table + +@node Concept Index, Index, Invocation, Top +@unnumbered Concept Index +@printindex cp + +@node Index,, Concept Index, Top +@unnumbered Index of Directives, Macros and Options +@printindex fn + +@contents +@bye diff --git a/gcc_arm/cppalloc.c b/gcc_arm/cppalloc.c new file mode 100755 index 0000000..92fa2b9 --- /dev/null +++ b/gcc_arm/cppalloc.c @@ -0,0 +1,81 @@ +/* Part of CPP library. (memory allocation - xmalloc etc) + Copyright (C) 1986, 87, 89, 92 - 95, 1998 Free Software Foundation, Inc. + Written by Per Bothner, 1994. + Based on CCCP program by Paul Rubin, June 1986 + Adapted to ANSI C, Richard Stallman, Jan 1987 + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +#include "config.h" +#include "system.h" +#include "cpplib.h" + +static void memory_full PROTO ((void)) ATTRIBUTE_NORETURN; + +static void +memory_full () +{ + fprintf (stderr, "%s: Memory exhausted.\n", progname); + exit (FATAL_EXIT_CODE); +} + +PTR +xmalloc (size) + size_t size; +{ + register PTR ptr = (PTR) malloc (size); + if (ptr == 0) + memory_full (); + return ptr; +} + +PTR +xcalloc (number, size) + size_t number, size; +{ + register PTR ptr = (PTR) calloc (number, size); + if (ptr == 0) + memory_full (); + return ptr; +} + +PTR +xrealloc (old, size) + PTR old; + size_t size; +{ + register PTR ptr; + if (old) + ptr = (PTR) realloc (old, size); + else + ptr = (PTR) malloc (size); + if (ptr == 0) + memory_full (); + return ptr; +} + +char * +xstrdup (input) + const char *input; +{ + unsigned size = strlen (input); + char *output = xmalloc (size + 1); + strcpy (output, input); + return output; +} diff --git a/gcc_arm/cpperror.c b/gcc_arm/cpperror.c new file mode 100755 index 0000000..107dc54 --- /dev/null +++ b/gcc_arm/cpperror.c @@ -0,0 +1,171 @@ +/* Default error handlers for CPP Library. + Copyright (C) 1986, 87, 89, 92 - 95, 1998 Free Software Foundation, Inc. + Written by Per Bothner, 1994. + Based on CCCP program by Paul Rubin, June 1986 + Adapted to ANSI C, Richard Stallman, Jan 1987 + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +#ifndef EMACS +#include "config.h" +#include "system.h" +#else +#include +#endif /* not EMACS */ + +#include "cpplib.h" + +/* Print the file names and line numbers of the #include + commands which led to the current file. */ + +void +cpp_print_containing_files (pfile) + cpp_reader *pfile; +{ + cpp_buffer *ip; + int first = 1; + + /* If stack of files hasn't changed since we last printed + this info, don't repeat it. */ + if (pfile->input_stack_listing_current) + return; + + ip = cpp_file_buffer (pfile); + + /* Give up if we don't find a source file. */ + if (ip == NULL) + return; + + /* Find the other, outer source files. */ + while ((ip = CPP_PREV_BUFFER (ip)), ip != CPP_NULL_BUFFER (pfile)) + { + long line, col; + cpp_buf_line_and_col (ip, &line, &col); + if (ip->fname != NULL) + { + if (first) + { + first = 0; + fprintf (stderr, "In file included"); + } + else + fprintf (stderr, ",\n "); + } + + fprintf (stderr, " from %s:%ld", ip->nominal_fname, line); + } + if (! first) + fprintf (stderr, ":\n"); + + /* Record we have printed the status as of this time. */ + pfile->input_stack_listing_current = 1; +} + +void +cpp_file_line_for_message (pfile, filename, line, column) + cpp_reader *pfile ATTRIBUTE_UNUSED; + char *filename; + int line, column; +{ + if (column > 0) + fprintf (stderr, "%s:%d:%d: ", filename, line, column); + else + fprintf (stderr, "%s:%d: ", filename, line); +} + +/* IS_ERROR is 2 for "fatal" error, 1 for error, 0 for warning */ + +void +v_cpp_message (pfile, is_error, msg, ap) + cpp_reader * pfile; + int is_error; + const char *msg; + va_list ap; +{ + if (!is_error) + fprintf (stderr, "warning: "); + else if (is_error == 2) + pfile->errors = CPP_FATAL_LIMIT; + else if (pfile->errors < CPP_FATAL_LIMIT) + pfile->errors++; + vfprintf (stderr, msg, ap); + fprintf (stderr, "\n"); +} + +void +cpp_message VPROTO ((cpp_reader *pfile, int is_error, const char *msg, ...)) +{ +#ifndef ANSI_PROTOTYPES + cpp_reader *pfile; + int is_error; + const char *msg; +#endif + va_list ap; + + VA_START (ap, msg); + +#ifndef ANSI_PROTOTYPES + pfile = va_arg (ap, cpp_reader *); + is_error = va_arg (ap, int); + msg = va_arg (ap, const char *); +#endif + + v_cpp_message(pfile, is_error, msg, ap); + va_end(ap); +} + +/* Same as cpp_error, except we consider the error to be "fatal", + such as inconsistent options. I.e. there is little point in continuing. + (We do not exit, to support use of cpplib as a library. + Instead, it is the caller's responsibility to check + CPP_FATAL_ERRORS. */ + +void +cpp_fatal VPROTO ((cpp_reader *pfile, const char *str, ...)) +{ +#ifndef ANSI_PROTOTYPES + cpp_reader *pfile; + const char *str; +#endif + va_list ap; + + VA_START (ap, str); + +#ifndef ANSI_PROTOTYPES + pfile = va_arg (ap, cpp_reader *); + str = va_arg (ap, const char *); +#endif + + fprintf (stderr, "%s: ", progname); + v_cpp_message (pfile, 2, str, ap); + va_end(ap); +} + +void +cpp_pfatal_with_name (pfile, name) + cpp_reader *pfile; + const char *name; +{ + cpp_perror_with_name (pfile, name); +#ifdef VMS + exit (vaxc$errno); +#else + exit (FATAL_EXIT_CODE); +#endif +} diff --git a/gcc_arm/cppexp.c b/gcc_arm/cppexp.c new file mode 100755 index 0000000..bd8e663 --- /dev/null +++ b/gcc_arm/cppexp.c @@ -0,0 +1,1026 @@ +/* Parse C expressions for CCCP. + Copyright (C) 1987, 1992, 1994, 1995, 1997, 1998 Free Software Foundation. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! + +Written by Per Bothner 1994. */ + +/* Parse a C expression from text in a string */ + +#include "config.h" +#include "system.h" +#include "cpplib.h" + +#ifdef MULTIBYTE_CHARS +#include +#endif + +/* This is used for communicating lists of keywords with cccp.c. */ +struct arglist { + struct arglist *next; + U_CHAR *name; + int length; + int argno; +}; + +#ifndef CHAR_TYPE_SIZE +#define CHAR_TYPE_SIZE BITS_PER_UNIT +#endif + +#ifndef INT_TYPE_SIZE +#define INT_TYPE_SIZE BITS_PER_WORD +#endif + +#ifndef LONG_TYPE_SIZE +#define LONG_TYPE_SIZE BITS_PER_WORD +#endif + +#ifndef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE INT_TYPE_SIZE +#endif + +#ifndef MAX_CHAR_TYPE_SIZE +#define MAX_CHAR_TYPE_SIZE CHAR_TYPE_SIZE +#endif + +#ifndef MAX_INT_TYPE_SIZE +#define MAX_INT_TYPE_SIZE INT_TYPE_SIZE +#endif + +#ifndef MAX_LONG_TYPE_SIZE +#define MAX_LONG_TYPE_SIZE LONG_TYPE_SIZE +#endif + +#ifndef MAX_WCHAR_TYPE_SIZE +#define MAX_WCHAR_TYPE_SIZE WCHAR_TYPE_SIZE +#endif + +#define MAX_CHAR_TYPE_MASK (MAX_CHAR_TYPE_SIZE < HOST_BITS_PER_WIDE_INT \ + ? (~ (~ (HOST_WIDE_INT) 0 << MAX_CHAR_TYPE_SIZE)) \ + : ~ (HOST_WIDE_INT) 0) + +#define MAX_WCHAR_TYPE_MASK (MAX_WCHAR_TYPE_SIZE < HOST_BITS_PER_WIDE_INT \ + ? ~ (~ (HOST_WIDE_INT) 0 << MAX_WCHAR_TYPE_SIZE) \ + : ~ (HOST_WIDE_INT) 0) + +/* Yield nonzero if adding two numbers with A's and B's signs can yield a + number with SUM's sign, where A, B, and SUM are all C integers. */ +#define possible_sum_sign(a, b, sum) ((((a) ^ (b)) | ~ ((a) ^ (sum))) < 0) + +static void integer_overflow PARAMS ((cpp_reader *)); +static long left_shift PARAMS ((cpp_reader *, long, int, unsigned long)); +static long right_shift PARAMS ((cpp_reader *, long, int, unsigned long)); + +#define ERROR 299 +#define OROR 300 +#define ANDAND 301 +#define EQUAL 302 +#define NOTEQUAL 303 +#define LEQ 304 +#define GEQ 305 +#define LSH 306 +#define RSH 307 +#define NAME 308 +#define INT 309 +#define CHAR 310 + +#define LEFT_OPERAND_REQUIRED 1 +#define RIGHT_OPERAND_REQUIRED 2 +#define HAVE_VALUE 4 +/* SKIP_OPERAND is set for '&&' '||' '?' and ':' when the + following operand should be short-circuited instead of evaluated. */ +#define SKIP_OPERAND 8 +/*#define UNSIGNEDP 16*/ + +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif + +#ifndef HOST_BITS_PER_WIDE_INT +#define HOST_BITS_PER_WIDE_INT (CHAR_BIT * sizeof (HOST_WIDE_INT)) +#endif + +struct operation { + short op; + char rprio; /* Priority of op (relative to it right operand). */ + char flags; + char unsignedp; /* true if value should be treated as unsigned */ + HOST_WIDE_INT value; /* The value logically "right" of op. */ +}; + +/* Take care of parsing a number (anything that starts with a digit). + LEN is the number of characters in it. */ + +/* maybe needs to actually deal with floating point numbers */ + +struct operation +parse_number (pfile, start, olen) + cpp_reader *pfile; + char *start; + int olen; +{ + struct operation op; + register char *p = start; + register int c; + register unsigned long n = 0, nd, ULONG_MAX_over_base; + register int base = 10; + register int len = olen; + register int overflow = 0; + register int digit, largest_digit = 0; + int spec_long = 0; + + op.unsignedp = 0; + + for (c = 0; c < len; c++) + if (p[c] == '.') { + /* It's a float since it contains a point. */ + cpp_error (pfile, + "floating point numbers not allowed in #if expressions"); + op.op = ERROR; + return op; + } + + if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) { + p += 2; + base = 16; + len -= 2; + } + else if (*p == '0') + base = 8; + + /* Some buggy compilers (e.g. MPW C) seem to need both casts. */ + ULONG_MAX_over_base = ((unsigned long) -1) / ((unsigned long) base); + + for (; len > 0; len--) { + c = *p++; + + if (c >= '0' && c <= '9') + digit = c - '0'; + else if (base == 16 && c >= 'a' && c <= 'f') + digit = c - 'a' + 10; + else if (base == 16 && c >= 'A' && c <= 'F') + digit = c - 'A' + 10; + else { + /* `l' means long, and `u' means unsigned. */ + while (1) { + if (c == 'l' || c == 'L') + { + if (spec_long) + cpp_error (pfile, "two `l's in integer constant"); + spec_long = 1; + } + else if (c == 'u' || c == 'U') + { + if (op.unsignedp) + cpp_error (pfile, "two `u's in integer constant"); + op.unsignedp = 1; + } + else + break; + + if (--len == 0) + break; + c = *p++; + } + /* Don't look for any more digits after the suffixes. */ + break; + } + if (largest_digit < digit) + largest_digit = digit; + nd = n * base + digit; + overflow |= ULONG_MAX_over_base < n || nd < n; + n = nd; + } + + if (len != 0) + { + cpp_error (pfile, "Invalid number in #if expression"); + op.op = ERROR; + return op; + } + + if (base <= largest_digit) + cpp_pedwarn (pfile, "integer constant contains digits beyond the radix"); + + if (overflow) + cpp_pedwarn (pfile, "integer constant out of range"); + + /* If too big to be signed, consider it unsigned. */ + if ((long) n < 0 && ! op.unsignedp) + { + if (base == 10) + cpp_warning (pfile, "integer constant is so large that it is unsigned"); + op.unsignedp = 1; + } + + op.value = n; + op.op = INT; + return op; +} + +struct token { + char *operator; + int token; +}; + +static struct token tokentab2[] = { + {"&&", ANDAND}, + {"||", OROR}, + {"<<", LSH}, + {">>", RSH}, + {"==", EQUAL}, + {"!=", NOTEQUAL}, + {"<=", LEQ}, + {">=", GEQ}, + {"++", ERROR}, + {"--", ERROR}, + {NULL, ERROR} +}; + +/* This is used to accumulate the value of a character literal. It is static + so that it only gets allocated once per compilation. */ +static char *token_buffer = NULL; + +/* Read one token. */ + +struct operation +cpp_lex (pfile, skip_evaluation) + cpp_reader *pfile; + int skip_evaluation; +{ + register HOST_WIDE_INT c; + register struct token *toktab; + enum cpp_token token; + struct operation op; + U_CHAR *tok_start, *tok_end; + int old_written; + + retry: + + old_written = CPP_WRITTEN (pfile); + cpp_skip_hspace (pfile); + c = CPP_BUF_PEEK (CPP_BUFFER (pfile)); + if (c == '#') + { + op.op = INT; + op.value = cpp_read_check_assertion (pfile); + return op; + } + + if (c == '\n') + { + op.op = 0; + return op; + } + + token = cpp_get_token (pfile); + tok_start = pfile->token_buffer + old_written; + tok_end = CPP_PWRITTEN (pfile); + pfile->limit = tok_start; + switch (token) + { + case CPP_EOF: /* Should not happen ... */ + case CPP_VSPACE: + op.op = 0; + return op; + case CPP_POP: + if (CPP_BUFFER (pfile)->fname != NULL) + { + op.op = 0; + return op; + } + cpp_pop_buffer (pfile); + goto retry; + case CPP_HSPACE: case CPP_COMMENT: + goto retry; + case CPP_NUMBER: + return parse_number (pfile, tok_start, tok_end - tok_start); + case CPP_STRING: + cpp_error (pfile, "string constants not allowed in #if expressions"); + op.op = ERROR; + return op; + case CPP_CHAR: + /* This code for reading a character constant + handles multicharacter constants and wide characters. + It is mostly copied from c-lex.c. */ + { + register int result = 0; + register int num_chars = 0; + unsigned width = MAX_CHAR_TYPE_SIZE; + int wide_flag = 0; + int max_chars; + U_CHAR *ptr = tok_start; + + /* We need to allocate this buffer dynamically since the size is not + a constant expression on all platforms. */ + if (token_buffer == NULL) + { +#ifdef MULTIBYTE_CHARS + token_buffer = xmalloc (MAX_LONG_TYPE_SIZE/MAX_CHAR_TYPE_SIZE + + MB_CUR_MAX); +#else + token_buffer = xmalloc (MAX_LONG_TYPE_SIZE/MAX_CHAR_TYPE_SIZE + 1); +#endif + } + + if (*ptr == 'L') + { + ptr++; + wide_flag = 1; + width = MAX_WCHAR_TYPE_SIZE; +#ifdef MULTIBYTE_CHARS + max_chars = MB_CUR_MAX; +#else + max_chars = 1; +#endif + } + else + max_chars = MAX_LONG_TYPE_SIZE / width; + + ++ptr; + while (ptr < tok_end && ((c = *ptr++) != '\'')) + { + if (c == '\\') + { + c = cpp_parse_escape (pfile, (char **) &ptr, + wide_flag ? MAX_WCHAR_TYPE_MASK + : MAX_CHAR_TYPE_MASK); + if (width < HOST_BITS_PER_INT + && (unsigned) c >= (unsigned)(1 << width)) + cpp_pedwarn (pfile, + "escape sequence out of range for character"); + } + + num_chars++; + + /* Merge character into result; ignore excess chars. */ + if (num_chars < max_chars + 1) + { + if (width < HOST_BITS_PER_INT) + result = (result << width) | (c & ((1 << width) - 1)); + else + result = c; + token_buffer[num_chars - 1] = c; + } + } + + token_buffer[num_chars] = 0; + + if (c != '\'') + cpp_error (pfile, "malformatted character constant"); + else if (num_chars == 0) + cpp_error (pfile, "empty character constant"); + else if (num_chars > max_chars) + { + num_chars = max_chars; + cpp_error (pfile, "character constant too long"); + } + else if (num_chars != 1 && ! CPP_TRADITIONAL (pfile)) + cpp_warning (pfile, "multi-character character constant"); + + /* If char type is signed, sign-extend the constant. */ + if (! wide_flag) + { + int num_bits = num_chars * width; + + if (cpp_lookup (pfile, (U_CHAR *)"__CHAR_UNSIGNED__", + sizeof ("__CHAR_UNSIGNED__")-1, -1) + || ((result >> (num_bits - 1)) & 1) == 0) + op.value + = result & ((unsigned long) ~0 >> (HOST_BITS_PER_LONG - num_bits)); + else + op.value + = result | ~((unsigned long) ~0 >> (HOST_BITS_PER_LONG - num_bits)); + } + else + { +#ifdef MULTIBYTE_CHARS + /* Set the initial shift state and convert the next sequence. */ + result = 0; + /* In all locales L'\0' is zero and mbtowc will return zero, + so don't use it. */ + if (num_chars > 1 + || (num_chars == 1 && token_buffer[0] != '\0')) + { + wchar_t wc; + (void) mbtowc (NULL_PTR, NULL_PTR, 0); + if (mbtowc (& wc, token_buffer, num_chars) == num_chars) + result = wc; + else + cpp_pedwarn (pfile,"Ignoring invalid multibyte character"); + } +#endif + op.value = result; + } + } + + /* This is always a signed type. */ + op.unsignedp = 0; + op.op = CHAR; + + return op; + + case CPP_NAME: + if (CPP_WARN_UNDEF (pfile) && !skip_evaluation) + cpp_warning (pfile, "`%.*s' is not defined", + (int) (tok_end - tok_start), tok_start); + return parse_number (pfile, "0", 0); + + case CPP_OTHER: + /* See if it is a special token of length 2. */ + if (tok_start + 2 == tok_end) + { + for (toktab = tokentab2; toktab->operator != NULL; toktab++) + if (tok_start[0] == toktab->operator[0] + && tok_start[1] == toktab->operator[1]) + break; + if (toktab->token == ERROR) + { + char *buf = (char *) alloca (40); + sprintf (buf, "`%s' not allowed in operand of `#if'", tok_start); + cpp_error (pfile, buf); + } + op.op = toktab->token; + return op; + } + /* fall through */ + default: + op.op = *tok_start; + return op; + } +} + + +/* Parse a C escape sequence. STRING_PTR points to a variable + containing a pointer to the string to parse. That pointer + is updated past the characters we use. The value of the + escape sequence is returned. + + A negative value means the sequence \ newline was seen, + which is supposed to be equivalent to nothing at all. + + If \ is followed by a null character, we return a negative + value and leave the string pointer pointing at the null character. + + If \ is followed by 000, we return 0 and leave the string pointer + after the zeros. A value of 0 does not mean end of string. */ + +HOST_WIDE_INT +cpp_parse_escape (pfile, string_ptr, result_mask) + cpp_reader *pfile; + char **string_ptr; + HOST_WIDE_INT result_mask; +{ + register int c = *(*string_ptr)++; + switch (c) + { + case 'a': + return TARGET_BELL; + case 'b': + return TARGET_BS; + case 'e': + case 'E': + if (CPP_OPTIONS (pfile)->pedantic) + cpp_pedwarn (pfile, "non-ANSI-standard escape sequence, `\\%c'", c); + return 033; + case 'f': + return TARGET_FF; + case 'n': + return TARGET_NEWLINE; + case 'r': + return TARGET_CR; + case 't': + return TARGET_TAB; + case 'v': + return TARGET_VT; + case '\n': + return -2; + case 0: + (*string_ptr)--; + return 0; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + register HOST_WIDE_INT i = c - '0'; + register int count = 0; + while (++count < 3) + { + c = *(*string_ptr)++; + if (c >= '0' && c <= '7') + i = (i << 3) + c - '0'; + else + { + (*string_ptr)--; + break; + } + } + if (i != (i & result_mask)) + { + i &= result_mask; + cpp_pedwarn (pfile, "octal escape sequence out of range"); + } + return i; + } + case 'x': + { + register unsigned HOST_WIDE_INT i = 0, overflow = 0; + register int digits_found = 0, digit; + for (;;) + { + c = *(*string_ptr)++; + if (c >= '0' && c <= '9') + digit = c - '0'; + else if (c >= 'a' && c <= 'f') + digit = c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + digit = c - 'A' + 10; + else + { + (*string_ptr)--; + break; + } + overflow |= i ^ (i << 4 >> 4); + i = (i << 4) + digit; + digits_found = 1; + } + if (!digits_found) + cpp_error (pfile, "\\x used with no following hex digits"); + if (overflow | (i != (i & result_mask))) + { + i &= result_mask; + cpp_pedwarn (pfile, "hex escape sequence out of range"); + } + return i; + } + default: + return c; + } +} + +static void +integer_overflow (pfile) + cpp_reader *pfile; +{ + if (CPP_PEDANTIC (pfile)) + cpp_pedwarn (pfile, "integer overflow in preprocessor expression"); +} + +static long +left_shift (pfile, a, unsignedp, b) + cpp_reader *pfile; + long a; + int unsignedp; + unsigned long b; +{ + if (b >= HOST_BITS_PER_LONG) + { + if (! unsignedp && a != 0) + integer_overflow (pfile); + return 0; + } + else if (unsignedp) + return (unsigned long) a << b; + else + { + long l = a << b; + if (l >> b != a) + integer_overflow (pfile); + return l; + } +} + +static long +right_shift (pfile, a, unsignedp, b) + cpp_reader *pfile ATTRIBUTE_UNUSED; + long a; + int unsignedp; + unsigned long b; +{ + if (b >= HOST_BITS_PER_LONG) + return unsignedp ? 0 : a >> (HOST_BITS_PER_LONG - 1); + else if (unsignedp) + return (unsigned long) a >> b; + else + return a >> b; +} + +/* These priorities are all even, so we can handle associatively. */ +#define PAREN_INNER_PRIO 0 +#define COMMA_PRIO 4 +#define COND_PRIO (COMMA_PRIO+2) +#define OROR_PRIO (COND_PRIO+2) +#define ANDAND_PRIO (OROR_PRIO+2) +#define OR_PRIO (ANDAND_PRIO+2) +#define XOR_PRIO (OR_PRIO+2) +#define AND_PRIO (XOR_PRIO+2) +#define EQUAL_PRIO (AND_PRIO+2) +#define LESS_PRIO (EQUAL_PRIO+2) +#define SHIFT_PRIO (LESS_PRIO+2) +#define PLUS_PRIO (SHIFT_PRIO+2) +#define MUL_PRIO (PLUS_PRIO+2) +#define UNARY_PRIO (MUL_PRIO+2) +#define PAREN_OUTER_PRIO (UNARY_PRIO+2) + +#define COMPARE(OP) \ + top->unsignedp = 0;\ + top->value = (unsigned1 || unsigned2) \ + ? (unsigned long) v1 OP (unsigned long) v2 : (v1 OP v2) + +/* Parse and evaluate a C expression, reading from PFILE. + Returns the value of the expression. */ + +HOST_WIDE_INT +cpp_parse_expr (pfile) + cpp_reader *pfile; +{ + /* The implementation is an operator precedence parser, + i.e. a bottom-up parser, using a stack for not-yet-reduced tokens. + + The stack base is 'stack', and the current stack pointer is 'top'. + There is a stack element for each operator (only), + and the most recently pushed operator is 'top->op'. + An operand (value) is stored in the 'value' field of the stack + element of the operator that precedes it. + In that case the 'flags' field has the HAVE_VALUE flag set. */ + +#define INIT_STACK_SIZE 20 + struct operation init_stack[INIT_STACK_SIZE]; + struct operation *stack = init_stack; + struct operation *limit = stack + INIT_STACK_SIZE; + register struct operation *top = stack; + int lprio, rprio; + int skip_evaluation = 0; + + top->rprio = 0; + top->flags = 0; + for (;;) + { + struct operation op; + char flags = 0; + + /* Read a token */ + op = cpp_lex (pfile, skip_evaluation); + + /* See if the token is an operand, in which case go to set_value. + If the token is an operator, figure out its left and right + priorities, and then goto maybe_reduce. */ + + switch (op.op) + { + case NAME: + abort (); + case INT: case CHAR: + top->value = op.value; + top->unsignedp = op.unsignedp; + goto set_value; + case 0: + lprio = 0; goto maybe_reduce; + case '+': case '-': + /* Is this correct if unary ? FIXME */ + flags = RIGHT_OPERAND_REQUIRED; + lprio = PLUS_PRIO; rprio = lprio + 1; goto maybe_reduce; + case '!': case '~': + flags = RIGHT_OPERAND_REQUIRED; + rprio = UNARY_PRIO; lprio = rprio + 1; goto maybe_reduce; + case '*': case '/': case '%': + lprio = MUL_PRIO; goto binop; + case '<': case '>': case LEQ: case GEQ: + lprio = LESS_PRIO; goto binop; + case EQUAL: case NOTEQUAL: + lprio = EQUAL_PRIO; goto binop; + case LSH: case RSH: + lprio = SHIFT_PRIO; goto binop; + case '&': lprio = AND_PRIO; goto binop; + case '^': lprio = XOR_PRIO; goto binop; + case '|': lprio = OR_PRIO; goto binop; + case ANDAND: lprio = ANDAND_PRIO; goto binop; + case OROR: lprio = OROR_PRIO; goto binop; + case ',': + lprio = COMMA_PRIO; goto binop; + case '(': + lprio = PAREN_OUTER_PRIO; rprio = PAREN_INNER_PRIO; + goto maybe_reduce; + case ')': + lprio = PAREN_INNER_PRIO; rprio = PAREN_OUTER_PRIO; + goto maybe_reduce; + case ':': + lprio = COND_PRIO; rprio = COND_PRIO; + goto maybe_reduce; + case '?': + lprio = COND_PRIO + 1; rprio = COND_PRIO; + goto maybe_reduce; + binop: + flags = LEFT_OPERAND_REQUIRED|RIGHT_OPERAND_REQUIRED; + rprio = lprio + 1; + goto maybe_reduce; + default: + cpp_error (pfile, "invalid character in #if"); + goto syntax_error; + } + + set_value: + /* Push a value onto the stack. */ + if (top->flags & HAVE_VALUE) + { + cpp_error (pfile, "syntax error in #if"); + goto syntax_error; + } + top->flags |= HAVE_VALUE; + continue; + + maybe_reduce: + /* Push an operator, and check if we can reduce now. */ + while (top->rprio > lprio) + { + long v1 = top[-1].value, v2 = top[0].value; + int unsigned1 = top[-1].unsignedp, unsigned2 = top[0].unsignedp; + top--; + if ((top[1].flags & LEFT_OPERAND_REQUIRED) + && ! (top[0].flags & HAVE_VALUE)) + { + cpp_error (pfile, "syntax error - missing left operand"); + goto syntax_error; + } + if ((top[1].flags & RIGHT_OPERAND_REQUIRED) + && ! (top[1].flags & HAVE_VALUE)) + { + cpp_error (pfile, "syntax error - missing right operand"); + goto syntax_error; + } + /* top[0].value = (top[1].op)(v1, v2);*/ + switch (top[1].op) + { + case '+': + if (!(top->flags & HAVE_VALUE)) + { /* Unary '+' */ + top->value = v2; + top->unsignedp = unsigned2; + top->flags |= HAVE_VALUE; + } + else + { + top->value = v1 + v2; + top->unsignedp = unsigned1 || unsigned2; + if (! top->unsignedp && ! skip_evaluation + && ! possible_sum_sign (v1, v2, top->value)) + integer_overflow (pfile); + } + break; + case '-': + if (!(top->flags & HAVE_VALUE)) + { /* Unary '-' */ + top->value = - v2; + if (!skip_evaluation && (top->value & v2) < 0 && !unsigned2) + integer_overflow (pfile); + top->unsignedp = unsigned2; + top->flags |= HAVE_VALUE; + } + else + { /* Binary '-' */ + top->value = v1 - v2; + top->unsignedp = unsigned1 || unsigned2; + if (! top->unsignedp && ! skip_evaluation + && ! possible_sum_sign (top->value, v2, v1)) + integer_overflow (pfile); + } + break; + case '*': + top->unsignedp = unsigned1 || unsigned2; + if (top->unsignedp) + top->value = (unsigned long) v1 * v2; + else if (!skip_evaluation) + { + top->value = v1 * v2; + if (v1 + && (top->value / v1 != v2 + || (top->value & v1 & v2) < 0)) + integer_overflow (pfile); + } + break; + case '/': + if (skip_evaluation) + break; + if (v2 == 0) + { + cpp_error (pfile, "division by zero in #if"); + v2 = 1; + } + top->unsignedp = unsigned1 || unsigned2; + if (top->unsignedp) + top->value = (unsigned long) v1 / v2; + else + { + top->value = v1 / v2; + if ((top->value & v1 & v2) < 0) + integer_overflow (pfile); + } + break; + case '%': + if (skip_evaluation) + break; + if (v2 == 0) + { + cpp_error (pfile, "division by zero in #if"); + v2 = 1; + } + top->unsignedp = unsigned1 || unsigned2; + if (top->unsignedp) + top->value = (unsigned long) v1 % v2; + else + top->value = v1 % v2; + break; + case '!': + if (top->flags & HAVE_VALUE) + { + cpp_error (pfile, "syntax error"); + goto syntax_error; + } + top->value = ! v2; + top->unsignedp = 0; + top->flags |= HAVE_VALUE; + break; + case '~': + if (top->flags & HAVE_VALUE) + { + cpp_error (pfile, "syntax error"); + goto syntax_error; + } + top->value = ~ v2; + top->unsignedp = unsigned2; + top->flags |= HAVE_VALUE; + break; + case '<': COMPARE(<); break; + case '>': COMPARE(>); break; + case LEQ: COMPARE(<=); break; + case GEQ: COMPARE(>=); break; + case EQUAL: + top->value = (v1 == v2); + top->unsignedp = 0; + break; + case NOTEQUAL: + top->value = (v1 != v2); + top->unsignedp = 0; + break; + case LSH: + if (skip_evaluation) + break; + top->unsignedp = unsigned1; + if (v2 < 0 && ! unsigned2) + top->value = right_shift (pfile, v1, unsigned1, -v2); + else + top->value = left_shift (pfile, v1, unsigned1, v2); + break; + case RSH: + if (skip_evaluation) + break; + top->unsignedp = unsigned1; + if (v2 < 0 && ! unsigned2) + top->value = left_shift (pfile, v1, unsigned1, -v2); + else + top->value = right_shift (pfile, v1, unsigned1, v2); + break; +#define LOGICAL(OP) \ + top->value = v1 OP v2;\ + top->unsignedp = unsigned1 || unsigned2; + case '&': LOGICAL(&); break; + case '^': LOGICAL(^); break; + case '|': LOGICAL(|); break; + case ANDAND: + top->value = v1 && v2; top->unsignedp = 0; + if (!v1) skip_evaluation--; + break; + case OROR: + top->value = v1 || v2; top->unsignedp = 0; + if (v1) skip_evaluation--; + break; + case ',': + if (CPP_PEDANTIC (pfile)) + cpp_pedwarn (pfile, "comma operator in operand of `#if'"); + top->value = v2; + top->unsignedp = unsigned2; + break; + case '(': case '?': + cpp_error (pfile, "syntax error in #if"); + goto syntax_error; + case ':': + if (top[0].op != '?') + { + cpp_error (pfile, + "syntax error ':' without preceding '?'"); + goto syntax_error; + } + else if (! (top[1].flags & HAVE_VALUE) + || !(top[-1].flags & HAVE_VALUE) + || !(top[0].flags & HAVE_VALUE)) + { + cpp_error (pfile, "bad syntax for ?: operator"); + goto syntax_error; + } + else + { + top--; + if (top->value) skip_evaluation--; + top->value = top->value ? v1 : v2; + top->unsignedp = unsigned1 || unsigned2; + } + break; + case ')': + if ((top[1].flags & HAVE_VALUE) + || ! (top[0].flags & HAVE_VALUE) + || top[0].op != '(' + || (top[-1].flags & HAVE_VALUE)) + { + cpp_error (pfile, "mismatched parentheses in #if"); + goto syntax_error; + } + else + { + top--; + top->value = v1; + top->unsignedp = unsigned1; + top->flags |= HAVE_VALUE; + } + break; + default: + fprintf (stderr, + top[1].op >= ' ' && top[1].op <= '~' + ? "unimplemented operator '%c'\n" + : "unimplemented operator '\\%03o'\n", + top[1].op); + } + } + if (op.op == 0) + { + if (top != stack) + cpp_error (pfile, "internal error in #if expression"); + if (stack != init_stack) + free (stack); + return top->value; + } + top++; + + /* Check for and handle stack overflow. */ + if (top == limit) + { + struct operation *new_stack; + int old_size = (char *) limit - (char *) stack; + int new_size = 2 * old_size; + if (stack != init_stack) + new_stack = (struct operation *) xrealloc (stack, new_size); + else + { + new_stack = (struct operation *) xmalloc (new_size); + bcopy ((char *) stack, (char *) new_stack, old_size); + } + stack = new_stack; + top = (struct operation *) ((char *) new_stack + old_size); + limit = (struct operation *) ((char *) new_stack + new_size); + } + + top->flags = flags; + top->rprio = rprio; + top->op = op.op; + if ((op.op == OROR && top[-1].value) + || (op.op == ANDAND && !top[-1].value) + || (op.op == '?' && !top[-1].value)) + { + skip_evaluation++; + } + else if (op.op == ':') + { + if (top[-2].value) /* Was condition true? */ + skip_evaluation++; + else + skip_evaluation--; + } + } + syntax_error: + if (stack != init_stack) + free (stack); + skip_rest_of_line (pfile); + return 0; +} diff --git a/gcc_arm/cppfiles.c b/gcc_arm/cppfiles.c new file mode 100755 index 0000000..7e1c0bb --- /dev/null +++ b/gcc_arm/cppfiles.c @@ -0,0 +1,1348 @@ +/* Part of CPP library. (include file handling) + Copyright (C) 1986, 87, 89, 92 - 95, 98, 1999 Free Software Foundation, Inc. + Written by Per Bothner, 1994. + Based on CCCP program by Paul Rubin, June 1986 + Adapted to ANSI C, Richard Stallman, Jan 1987 + Split out of cpplib.c, Zack Weinberg, Oct 1998 + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +#include "config.h" +#include "system.h" +#include "cpplib.h" + +/* The entry points to this file are: find_include_file, finclude, + include_hash, append_include_chain, deps_output, and file_cleanup. + file_cleanup is only called through CPP_BUFFER(pfile)->cleanup, + so it's static anyway. */ + +/* CYGNUS LOCAL - obscured headers */ +static int open_include_file_name PARAMS ((cpp_reader*, char *)); +/* END CYGNUS LOCAL - obscured headers */ +static struct include_hash *redundant_include_p + PROTO ((cpp_reader *, + struct include_hash *, + struct file_name_list *)); +static struct file_name_map *read_name_map PROTO ((cpp_reader *, + const char *)); +static char *read_filename_string PROTO ((int, FILE *)); +static char *remap_filename PROTO ((cpp_reader *, char *, + struct file_name_list *)); +static long safe_read PROTO ((int, char *, int)); +static void simplify_pathname PROTO ((char *)); +static struct file_name_list *actual_directory PROTO ((cpp_reader *, char *)); + +#if 0 +static void hack_vms_include_specification PROTO ((char *)); +#endif + +/* Windows does not natively support inodes, and neither does MSDOS. + VMS has non-numeric inodes. */ +#ifdef VMS +#define INO_T_EQ(a, b) (!bcmp((char *) &(a), (char *) &(b), sizeof (a))) +#elif (defined _WIN32 && !defined CYGWIN) || defined __MSDOS__ +#define INO_T_EQ(a, b) 0 +#else +#define INO_T_EQ(a, b) ((a) == (b)) +#endif + +/* Append an entry for dir DIR to list LIST, simplifying it if + possible. SYS says whether this is a system include directory. + *** DIR is modified in place. It must be writable and permanently + allocated. LIST is a pointer to the head pointer, because we actually + *prepend* the dir, and reverse the list later (in merge_include_chains). */ +void +append_include_chain (pfile, list, dir, sysp) + cpp_reader *pfile; + struct file_name_list **list; + const char *dir; + int sysp; +{ + struct file_name_list *new; + struct stat st; + unsigned int len; + char * newdir = xstrdup (dir); + + simplify_pathname (newdir); + if (stat (newdir, &st)) + { + /* Dirs that don't exist are silently ignored. */ + if (errno != ENOENT) + cpp_perror_with_name (pfile, newdir); + return; + } + + if (!S_ISDIR (st.st_mode)) + { + cpp_message (pfile, 1, "%s: %s: Not a directory", progname, newdir); + return; + } + + len = strlen(newdir); + if (len > pfile->max_include_len) + pfile->max_include_len = len; + + new = (struct file_name_list *)xmalloc (sizeof (struct file_name_list)); + new->name = newdir; + new->nlen = len; + new->next = *list; + new->ino = st.st_ino; + new->dev = st.st_dev; + new->sysp = sysp; + new->name_map = NULL; + + *list = new; +} + +/* Merge the four include chains together in the order quote, bracket, + system, after. Remove duplicate dirs (as determined by + INO_T_EQ()). The system_include and after_include chains are never + referred to again after this function; all access is through the + bracket_include path. + + For the future: Check if the directory is empty (but + how?) and possibly preload the include hash. */ + +void +merge_include_chains (opts) + struct cpp_options *opts; +{ + struct file_name_list *prev, *next, *cur, *other; + struct file_name_list *quote, *brack, *systm, *after; + struct file_name_list *qtail, *btail, *stail, *atail; + + qtail = opts->quote_include; + btail = opts->bracket_include; + stail = opts->system_include; + atail = opts->after_include; + + /* Nreverse the four lists. */ + prev = 0; + for (cur = qtail; cur; cur = next) + { + next = cur->next; + cur->next = prev; + prev = cur; + } + quote = prev; + + prev = 0; + for (cur = btail; cur; cur = next) + { + next = cur->next; + cur->next = prev; + prev = cur; + } + brack = prev; + + prev = 0; + for (cur = stail; cur; cur = next) + { + next = cur->next; + cur->next = prev; + prev = cur; + } + systm = prev; + + prev = 0; + for (cur = atail; cur; cur = next) + { + next = cur->next; + cur->next = prev; + prev = cur; + } + after = prev; + + /* Paste together bracket, system, and after include chains. */ + if (stail) + stail->next = after; + else + systm = after; + if (btail) + btail->next = systm; + else + brack = systm; + + /* This is a bit tricky. + First we drop dupes from the quote-include list. + Then we drop dupes from the bracket-include list. + Finally, if qtail and brack are the same directory, + we cut out qtail. + + We can't just merge the lists and then uniquify them because + then we may lose directories from the <> search path that should + be there; consider -Ifoo -Ibar -I- -Ifoo -Iquux. It is however + safe to treat -Ibar -Ifoo -I- -Ifoo -Iquux as if written + -Ibar -I- -Ifoo -Iquux. */ + + for (cur = quote; cur; cur = cur->next) + { + for (other = quote; other != cur; other = other->next) + if (INO_T_EQ (cur->ino, other->ino) + && cur->dev == other->dev) + { + prev->next = cur->next; + free (cur->name); + free (cur); + cur = prev; + break; + } + prev = cur; + } + qtail = prev; + + for (cur = brack; cur; cur = cur->next) + { + for (other = brack; other != cur; other = other->next) + if (INO_T_EQ (cur->ino, other->ino) + && cur->dev == other->dev) + { + prev->next = cur->next; + free (cur->name); + free (cur); + cur = prev; + break; + } + prev = cur; + } + + if (quote) + { + if (INO_T_EQ (qtail->ino, brack->ino) && qtail->dev == brack->dev) + { + if (quote == qtail) + { + free (quote->name); + free (quote); + quote = brack; + } + else + { + cur = quote; + while (cur->next != qtail) + cur = cur->next; + cur->next = brack; + free (qtail->name); + free (qtail); + } + } + else + qtail->next = brack; + } + else + quote = brack; + + opts->quote_include = quote; + opts->bracket_include = brack; + opts->system_include = NULL; + opts->after_include = NULL; +} + +/* Look up or add an entry to the table of all includes. This table + is indexed by the name as it appears in the #include line. The + ->next_this_file chain stores all different files with the same + #include name (there are at least three ways this can happen). The + hash function could probably be improved a bit. */ + +struct include_hash * +include_hash (pfile, fname, add) + cpp_reader *pfile; + char *fname; + int add; +{ + unsigned int hash = 0; + struct include_hash *l, *m; + char *f = fname; + + while (*f) + hash += *f++; + + l = pfile->all_include_files[hash % ALL_INCLUDE_HASHSIZE]; + m = 0; + for (; l; m = l, l = l->next) + if (!strcmp (l->nshort, fname)) + return l; + + if (!add) + return 0; + + l = (struct include_hash *) xmalloc (sizeof (struct include_hash)); + l->next = NULL; + l->next_this_file = NULL; + l->foundhere = NULL; + l->buf = NULL; + l->limit = NULL; + if (m) + m->next = l; + else + pfile->all_include_files[hash % ALL_INCLUDE_HASHSIZE] = l; + + return l; +} + +/* Return 0 if the file pointed to by IHASH has never been included before, + -1 if it has been included before and need not be again, + or a pointer to an IHASH entry which is the file to be reread. + "Never before" is with respect to the position in ILIST. + + This will not detect redundancies involving odd uses of the + `current directory' rule for "" includes. They aren't quite + pathological, but I think they are rare enough not to worry about. + The simplest example is: + + top.c: + #include "a/a.h" + #include "b/b.h" + + a/a.h: + #include "../b/b.h" + + and the problem is that for `current directory' includes, + ihash->foundhere is not on any of the global include chains, + so the test below (i->foundhere == l) may be false even when + the directories are in fact the same. */ + +static struct include_hash * +redundant_include_p (pfile, ihash, ilist) + cpp_reader *pfile; + struct include_hash *ihash; + struct file_name_list *ilist; +{ + struct file_name_list *l; + struct include_hash *i; + + if (! ihash->foundhere) + return 0; + + for (i = ihash; i; i = i->next_this_file) + for (l = ilist; l; l = l->next) + if (i->foundhere == l) + /* The control_macro works like this: If it's NULL, the file + is to be included again. If it's "", the file is never to + be included again. If it's a string, the file is not to be + included again if the string is the name of a defined macro. */ + return (i->control_macro + && (i->control_macro[0] == '\0' + || cpp_lookup (pfile, i->control_macro, -1, -1))) + ? (struct include_hash *)-1 : i; + + return 0; +} + +static int +file_cleanup (pbuf, pfile) + cpp_buffer *pbuf; + cpp_reader *pfile; +{ + if (pbuf->buf) + { + free (pbuf->buf); + pbuf->buf = 0; + } + if (pfile->system_include_depth) + pfile->system_include_depth--; + return 0; +} + +/* Search for include file FNAME in the include chain starting at + SEARCH_START. Return -2 if this file doesn't need to be included + (because it was included already and it's marked idempotent), + -1 if an error occurred, or a file descriptor open on the file. + *IHASH is set to point to the include hash entry for this file, and + *BEFORE is 1 if the file was included before (but needs to be read + again). */ +int +find_include_file (pfile, fname, search_start, ihash, before) + cpp_reader *pfile; + char *fname; + struct file_name_list *search_start; + struct include_hash **ihash; + int *before; +{ + struct file_name_list *l; + struct include_hash *ih, *jh; + int f, len; + char *name; + + ih = include_hash (pfile, fname, 1); + jh = redundant_include_p (pfile, ih, + fname[0] == '/' ? ABSOLUTE_PATH : search_start); + + if (jh != 0) + { + *before = 1; + *ihash = jh; + + if (jh == (struct include_hash *)-1) + return -2; + else + { + /* CYGNUS LOCAL - obscured headers */ + return open_include_file_name (pfile, jh->name); + /* END CYGNUS LOCAL - obscured headers */ + } + } + + if (ih->foundhere) + /* A file is already known by this name, but it's not the same file. + Allocate another include_hash block and add it to the next_this_file + chain. */ + { + jh = (struct include_hash *)xmalloc (sizeof (struct include_hash)); + while (ih->next_this_file) ih = ih->next_this_file; + + ih->next_this_file = jh; + jh = ih; + ih = ih->next_this_file; + + ih->next = NULL; + ih->next_this_file = NULL; + ih->buf = NULL; + ih->limit = NULL; + } + *before = 0; + *ihash = ih; + ih->nshort = xstrdup (fname); + ih->control_macro = NULL; + + /* If the pathname is absolute, just open it. */ + if (fname[0] == '/') + { + ih->foundhere = ABSOLUTE_PATH; + ih->name = ih->nshort; + /* CYGNUS LOCAL - obscured headers */ + return open_include_file_name (pfile, ih->name); + /* END CYGNUS LOCAL - obscured headers */ + } + + /* Search directory path, trying to open the file. */ + + len = strlen (fname); + name = xmalloc (len + pfile->max_include_len + 2 + INCLUDE_LEN_FUDGE); + + for (l = search_start; l; l = l->next) + { + bcopy (l->name, name, l->nlen); + name[l->nlen] = '/'; + strcpy (&name[l->nlen+1], fname); + simplify_pathname (name); + if (CPP_OPTIONS (pfile)->remap) + name = remap_filename (pfile, name, l); + + /* CYGNUS LOCAL - obscured headers */ + f = open_include_file_name (pfile, name); + /* END CYGNUS LOCAL - obscured headers */ +#ifdef EACCES + if (f == -1 && errno == EACCES) + { + cpp_error(pfile, "included file `%s' exists but is not readable", + name); + return -1; + } +#endif + + if (f >= 0) + { + ih->foundhere = l; + ih->name = xrealloc (name, strlen (name)+1); + return f; + } + } + + if (jh) + { + jh->next_this_file = NULL; + free (ih); + } + free (name); + *ihash = (struct include_hash *)-1; + return -1; +} + +/* The file_name_map structure holds a mapping of file names for a + particular directory. This mapping is read from the file named + FILE_NAME_MAP_FILE in that directory. Such a file can be used to + map filenames on a file system with severe filename restrictions, + such as DOS. The format of the file name map file is just a series + of lines with two tokens on each line. The first token is the name + to map, and the second token is the actual name to use. */ + +struct file_name_map +{ + struct file_name_map *map_next; + char *map_from; + char *map_to; +}; + +#define FILE_NAME_MAP_FILE "header.gcc" + +/* Read a space delimited string of unlimited length from a stdio + file. */ + +static char * +read_filename_string (ch, f) + int ch; + FILE *f; +{ + char *alloc, *set; + int len; + + len = 20; + set = alloc = xmalloc (len + 1); + if (! is_space[ch]) + { + *set++ = ch; + while ((ch = getc (f)) != EOF && ! is_space[ch]) + { + if (set - alloc == len) + { + len *= 2; + alloc = xrealloc (alloc, len + 1); + set = alloc + len / 2; + } + *set++ = ch; + } + } + *set = '\0'; + ungetc (ch, f); + return alloc; +} + +/* This structure holds a linked list of file name maps, one per directory. */ + +struct file_name_map_list +{ + struct file_name_map_list *map_list_next; + char *map_list_name; + struct file_name_map *map_list_map; +}; + +/* Read the file name map file for DIRNAME. */ + +static struct file_name_map * +read_name_map (pfile, dirname) + cpp_reader *pfile; + const char *dirname; +{ + register struct file_name_map_list *map_list_ptr; + char *name; + FILE *f; + + for (map_list_ptr = CPP_OPTIONS (pfile)->map_list; map_list_ptr; + map_list_ptr = map_list_ptr->map_list_next) + if (! strcmp (map_list_ptr->map_list_name, dirname)) + return map_list_ptr->map_list_map; + + map_list_ptr = ((struct file_name_map_list *) + xmalloc (sizeof (struct file_name_map_list))); + map_list_ptr->map_list_name = xstrdup (dirname); + + name = (char *) alloca (strlen (dirname) + strlen (FILE_NAME_MAP_FILE) + 2); + strcpy (name, dirname); + if (*dirname) + strcat (name, "/"); + strcat (name, FILE_NAME_MAP_FILE); + f = fopen (name, "r"); + if (!f) + map_list_ptr->map_list_map = (struct file_name_map *)-1; + else + { + int ch; + int dirlen = strlen (dirname); + + while ((ch = getc (f)) != EOF) + { + char *from, *to; + struct file_name_map *ptr; + + if (is_space[ch]) + continue; + from = read_filename_string (ch, f); + while ((ch = getc (f)) != EOF && is_hor_space[ch]) + ; + to = read_filename_string (ch, f); + + ptr = ((struct file_name_map *) + xmalloc (sizeof (struct file_name_map))); + ptr->map_from = from; + + /* Make the real filename absolute. */ + if (*to == '/') + ptr->map_to = to; + else + { + ptr->map_to = xmalloc (dirlen + strlen (to) + 2); + strcpy (ptr->map_to, dirname); + ptr->map_to[dirlen] = '/'; + strcpy (ptr->map_to + dirlen + 1, to); + free (to); + } + + ptr->map_next = map_list_ptr->map_list_map; + map_list_ptr->map_list_map = ptr; + + while ((ch = getc (f)) != '\n') + if (ch == EOF) + break; + } + fclose (f); + } + + map_list_ptr->map_list_next = CPP_OPTIONS (pfile)->map_list; + CPP_OPTIONS (pfile)->map_list = map_list_ptr; + + return map_list_ptr->map_list_map; +} + +/* Remap NAME based on the file_name_map (if any) for LOC. */ + +static char * +remap_filename (pfile, name, loc) + cpp_reader *pfile; + char *name; + struct file_name_list *loc; +{ + struct file_name_map *map; + const char *from, *p, *dir; + + if (! loc->name_map) + loc->name_map = read_name_map (pfile, + loc->name + ? loc->name : "."); + + if (loc->name_map == (struct file_name_map *)-1) + return name; + + from = name + strlen (loc->name) + 1; + + for (map = loc->name_map; map; map = map->map_next) + if (!strcmp (map->map_from, from)) + return map->map_to; + + /* Try to find a mapping file for the particular directory we are + looking in. Thus #include will look up sys/types.h + in /usr/include/header.gcc and look up types.h in + /usr/include/sys/header.gcc. */ + p = rindex (name, '/'); + if (!p) + p = name; + if (loc && loc->name + && strlen (loc->name) == (size_t) (p - name) + && !strncmp (loc->name, name, p - name)) + /* FILENAME is in SEARCHPTR, which we've already checked. */ + return name; + + if (p == name) + { + dir = "."; + from = name; + } + else + { + char * newdir = (char *) alloca (p - name + 1); + bcopy (name, newdir, p - name); + newdir[p - name] = '\0'; + dir = newdir; + from = p + 1; + } + + for (map = read_name_map (pfile, dir); map; map = map->map_next) + if (! strcmp (map->map_from, name)) + return map->map_to; + + return name; +} + +/* CYGNUS LOCAL - obscured headers */ +static int +open_include_file_name (pfile, filename) + cpp_reader *pfile; + char *filename; +{ + return open (filename, O_RDONLY, 0666); +} +/* END CYGNUS LOCAL - obscured headers */ + +/* Read the contents of FD into the buffer on the top of PFILE's stack. + IHASH points to the include hash entry for the file associated with + FD. + + The caller is responsible for the cpp_push_buffer. */ + +int +finclude (pfile, fd, ihash) + cpp_reader *pfile; + int fd; + struct include_hash *ihash; +{ + struct stat st; + size_t st_size; + long i, length; + cpp_buffer *fp; +#if 0 + int missing_newline = 0; +#endif + + if (fstat (fd, &st) < 0) + goto perror_fail; + + fp = CPP_BUFFER (pfile); + fp->nominal_fname = fp->fname = ihash->name; + fp->ihash = ihash; + fp->system_header_p = (ihash->foundhere != ABSOLUTE_PATH + && ihash->foundhere->sysp); + fp->lineno = 1; + fp->colno = 1; + fp->cleanup = file_cleanup; + + /* The ->actual_dir field is only used when ignore_srcdir is not in effect; + see do_include */ + if (!CPP_OPTIONS (pfile)->ignore_srcdir) + fp->actual_dir = actual_directory (pfile, fp->fname); + + if (S_ISREG (st.st_mode)) + { + st_size = (size_t) st.st_size; + if (st_size != st.st_size || st_size + 2 < st_size) + { + cpp_error (pfile, "file `%s' too large", ihash->name); + goto fail; + } + fp->buf = (U_CHAR *) xmalloc (st_size + 2); + fp->alimit = fp->buf + st_size + 2; + fp->cur = fp->buf; + + /* Read the file contents, knowing that st_size is an upper bound + on the number of bytes we can read. */ + length = safe_read (fd, fp->buf, st_size); + fp->rlimit = fp->buf + length; + if (length < 0) + goto perror_fail; + } + else if (S_ISDIR (st.st_mode)) + { + cpp_pop_buffer (pfile); + cpp_error (pfile, "directory `%s' specified in #include", ihash->name); + goto fail; + } + else + { + /* Cannot count its file size before reading. + First read the entire file into heap and + copy them into buffer on stack. */ + + size_t bsize = 2000; + + st_size = 0; + fp->buf = (U_CHAR *) xmalloc (bsize + 2); + + for (;;) + { + i = safe_read (fd, fp->buf + st_size, bsize - st_size); + if (i < 0) + goto perror_fail; + st_size += i; + if (st_size != bsize) + break; /* End of file */ + bsize *= 2; + fp->buf = (U_CHAR *) xrealloc (fp->buf, bsize + 2); + } + fp->cur = fp->buf; + length = st_size; + } + + /* FIXME: Broken in presence of trigraphs (consider ??/) + and doesn't warn about a missing newline. */ + if ((length > 0 && fp->buf[length - 1] != '\n') + || (length > 1 && fp->buf[length - 2] == '\\')) + fp->buf[length++] = '\n'; + + fp->buf[length] = '\0'; + fp->rlimit = fp->buf + length; + + close (fd); + pfile->input_stack_listing_current = 0; + +#if 0 + if (!no_trigraphs) + trigraph_pcp (fp); +#endif + return 1; + + perror_fail: + cpp_pop_buffer (pfile); + cpp_error_from_errno (pfile, ihash->name); + fail: + close (fd); + return 0; +} + +static struct file_name_list * +actual_directory (pfile, fname) + cpp_reader *pfile; + char *fname; +{ + char *last_slash, *dir; + size_t dlen; + struct file_name_list *x; + + dir = xstrdup (fname); + last_slash = rindex (dir, '/'); + if (last_slash) + { + if (last_slash == dir) + { + dlen = 1; + last_slash[1] = '\0'; + } + else + { + dlen = last_slash - dir; + *last_slash = '\0'; + } + } + else + { + dir[0] = '.'; + dir[1] = '\0'; + dlen = 1; + } + + if (dlen > pfile->max_include_len) + pfile->max_include_len = dlen; + + for (x = pfile->actual_dirs; x; x = x->alloc) + if (!strcmp (x->name, dir)) + { + free (dir); + return x; + } + + /* Not found, make a new one. */ + x = (struct file_name_list *) xmalloc (sizeof (struct file_name_list)); + x->name = dir; + x->nlen = dlen; + x->next = CPP_OPTIONS (pfile)->quote_include; + x->alloc = pfile->actual_dirs; + x->sysp = 0; + x->name_map = NULL; + + pfile->actual_dirs = x; + return x; +} + +/* Read LEN bytes at PTR from descriptor DESC, for file FILENAME, + retrying if necessary. If MAX_READ_LEN is defined, read at most + that bytes at a time. Return a negative value if an error occurs, + otherwise return the actual number of bytes read, + which must be LEN unless end-of-file was reached. */ + +static long +safe_read (desc, ptr, len) + int desc; + char *ptr; + int len; +{ + int left, rcount, nchars; + + left = len; + while (left > 0) { + rcount = left; +#ifdef MAX_READ_LEN + if (rcount > MAX_READ_LEN) + rcount = MAX_READ_LEN; +#endif + nchars = read (desc, ptr, rcount); + if (nchars < 0) + { +#ifdef EINTR + if (errno == EINTR) + continue; +#endif + return nchars; + } + if (nchars == 0) + break; + ptr += nchars; + left -= nchars; + } + return len - left; +} + +/* Add output to `deps_buffer' for the -M switch. + STRING points to the text to be output. + SPACER is ':' for targets, ' ' for dependencies, zero for text + to be inserted literally. */ + +void +deps_output (pfile, string, spacer) + cpp_reader *pfile; + char *string; + int spacer; +{ + int size; + int cr = 0; + + if (!*string) + return; + + size = strlen (string); + +#ifndef MAX_OUTPUT_COLUMNS +#define MAX_OUTPUT_COLUMNS 72 +#endif + if (pfile->deps_column > 0 + && (pfile->deps_column + size) > MAX_OUTPUT_COLUMNS) + { + size += 5; + cr = 1; + pfile->deps_column = 0; + } + + if (pfile->deps_size + size + 8 > pfile->deps_allocated_size) + { + pfile->deps_allocated_size = (pfile->deps_size + size + 50) * 2; + pfile->deps_buffer = (char *) xrealloc (pfile->deps_buffer, + pfile->deps_allocated_size); + } + + if (cr) + { + bcopy (" \\\n ", &pfile->deps_buffer[pfile->deps_size], 5); + pfile->deps_size += 5; + } + + if (spacer == ' ' && pfile->deps_column > 0) + pfile->deps_buffer[pfile->deps_size++] = ' '; + bcopy (string, &pfile->deps_buffer[pfile->deps_size], size); + pfile->deps_size += size; + pfile->deps_column += size; + if (spacer == ':') + pfile->deps_buffer[pfile->deps_size++] = ':'; + pfile->deps_buffer[pfile->deps_size] = 0; +} + +/* Simplify a path name in place, deleting redundant components. This + reduces OS overhead and guarantees that equivalent paths compare + the same (modulo symlinks). + + Transforms made: + foo/bar/../quux foo/quux + foo/./bar foo/bar + foo//bar foo/bar + /../quux /quux + //quux //quux (POSIX allows leading // as a namespace escape) + + Guarantees no trailing slashes. All transforms reduce the length + of the string. + */ +static void +simplify_pathname (path) + char *path; +{ + char *from, *to; + char *base; + int absolute = 0; + +#if defined _WIN32 || defined __MSDOS__ + /* Convert all backslashes to slashes. */ + for (from = path; *from; from++) + if (*from == '\\') *from = '/'; + + /* Skip over leading drive letter if present. */ + if (ISALPHA (path[0]) && path[1] == ':') + from = to = &path[2]; + else + from = to = path; +#else + from = to = path; +#endif + + /* Remove redundant initial /s. */ + if (*from == '/') + { + absolute = 1; + to++; + from++; + if (*from == '/') + { + if (*++from == '/') + /* 3 or more initial /s are equivalent to 1 /. */ + while (*++from == '/'); + else + /* On some hosts // differs from /; Posix allows this. */ + to++; + } + } + base = to; + + for (;;) + { + while (*from == '/') + from++; + + if (from[0] == '.' && from[1] == '/') + from += 2; + else if (from[0] == '.' && from[1] == '\0') + goto done; + else if (from[0] == '.' && from[1] == '.' && from[2] == '/') + { + if (base == to) + { + if (absolute) + from += 3; + else + { + *to++ = *from++; + *to++ = *from++; + *to++ = *from++; + base = to; + } + } + else + { + to -= 2; + while (to > base && *to != '/') to--; + if (*to == '/') + to++; + from += 3; + } + } + else if (from[0] == '.' && from[1] == '.' && from[2] == '\0') + { + if (base == to) + { + if (!absolute) + { + *to++ = *from++; + *to++ = *from++; + } + } + else + { + to -= 2; + while (to > base && *to != '/') to--; + if (*to == '/') + to++; + } + goto done; + } + else + /* Copy this component and trailing /, if any. */ + while ((*to++ = *from++) != '/') + { + if (!to[-1]) + { + to--; + goto done; + } + } + + } + + done: + /* Trim trailing slash */ + if (to[0] == '/' && (!absolute || to > path+1)) + to--; + + /* Change the empty string to "." so that stat() on the result + will always work. */ + if (to == path) + *to++ = '.'; + + *to = '\0'; + + return; +} + +/* It is not clear when this should be used if at all, so I've + disabled it until someone who understands VMS can look at it. */ +#if 0 + +/* Under VMS we need to fix up the "include" specification filename. + + Rules for possible conversions + + fullname tried paths + + name name + ./dir/name [.dir]name + /dir/name dir:name + /name [000000]name, name + dir/name dir:[000000]name, dir:name, dir/name + dir1/dir2/name dir1:[dir2]name, dir1:[000000.dir2]name + path:/name path:[000000]name, path:name + path:/dir/name path:[000000.dir]name, path:[dir]name + path:dir/name path:[dir]name + [path]:[dir]name [path.dir]name + path/[dir]name [path.dir]name + + The path:/name input is constructed when expanding <> includes. */ + + +static void +hack_vms_include_specification (fullname) + char *fullname; +{ + register char *basename, *unixname, *local_ptr, *first_slash; + int f, check_filename_before_returning, must_revert; + char Local[512]; + + check_filename_before_returning = 0; + must_revert = 0; + /* See if we can find a 1st slash. If not, there's no path information. */ + first_slash = index (fullname, '/'); + if (first_slash == 0) + return 0; /* Nothing to do!!! */ + + /* construct device spec if none given. */ + + if (index (fullname, ':') == 0) + { + + /* If fullname has a slash, take it as device spec. */ + + if (first_slash == fullname) + { + first_slash = index (fullname+1, '/'); /* 2nd slash ? */ + if (first_slash) + *first_slash = ':'; /* make device spec */ + for (basename = fullname; *basename != 0; basename++) + *basename = *(basename+1); /* remove leading slash */ + } + else if ((first_slash[-1] != '.') /* keep ':/', './' */ + && (first_slash[-1] != ':') + && (first_slash[-1] != ']')) /* or a vms path */ + { + *first_slash = ':'; + } + else if ((first_slash[1] == '[') /* skip './' in './[dir' */ + && (first_slash[-1] == '.')) + fullname += 2; + } + + /* Get part after first ':' (basename[-1] == ':') + or last '/' (basename[-1] == '/'). */ + + basename = base_name (fullname); + + local_ptr = Local; /* initialize */ + + /* We are trying to do a number of things here. First of all, we are + trying to hammer the filenames into a standard format, such that later + processing can handle them. + + If the file name contains something like [dir.], then it recognizes this + as a root, and strips the ".]". Later processing will add whatever is + needed to get things working properly. + + If no device is specified, then the first directory name is taken to be + a device name (or a rooted logical). */ + + /* Point to the UNIX filename part (which needs to be fixed!) + but skip vms path information. + [basename != fullname since first_slash != 0]. */ + + if ((basename[-1] == ':') /* vms path spec. */ + || (basename[-1] == ']') + || (basename[-1] == '>')) + unixname = basename; + else + unixname = fullname; + + if (*unixname == '/') + unixname++; + + /* If the directory spec is not rooted, we can just copy + the UNIX filename part and we are done. */ + + if (((basename - fullname) > 1) + && ( (basename[-1] == ']') + || (basename[-1] == '>'))) + { + if (basename[-2] != '.') + { + + /* The VMS part ends in a `]', and the preceding character is not a `.'. + -> PATH]:/name (basename = '/name', unixname = 'name') + We strip the `]', and then splice the two parts of the name in the + usual way. Given the default locations for include files in cccp.c, + we will only use this code if the user specifies alternate locations + with the /include (-I) switch on the command line. */ + + basename -= 1; /* Strip "]" */ + unixname--; /* backspace */ + } + else + { + + /* The VMS part has a ".]" at the end, and this will not do. Later + processing will add a second directory spec, and this would be a syntax + error. Thus we strip the ".]", and thus merge the directory specs. + We also backspace unixname, so that it points to a '/'. This inhibits the + generation of the 000000 root directory spec (which does not belong here + in this case). */ + + basename -= 2; /* Strip ".]" */ + unixname--; /* backspace */ + } + } + + else + + { + + /* We drop in here if there is no VMS style directory specification yet. + If there is no device specification either, we make the first dir a + device and try that. If we do not do this, then we will be essentially + searching the users default directory (as if they did a #include "asdf.h"). + + Then all we need to do is to push a '[' into the output string. Later + processing will fill this in, and close the bracket. */ + + if ((unixname != fullname) /* vms path spec found. */ + && (basename[-1] != ':')) + *local_ptr++ = ':'; /* dev not in spec. take first dir */ + + *local_ptr++ = '['; /* Open the directory specification */ + } + + if (unixname == fullname) /* no vms dir spec. */ + { + must_revert = 1; + if ((first_slash != 0) /* unix dir spec. */ + && (*unixname != '/') /* not beginning with '/' */ + && (*unixname != '.')) /* or './' or '../' */ + *local_ptr++ = '.'; /* dir is local ! */ + } + + /* at this point we assume that we have the device spec, and (at least + the opening "[" for a directory specification. We may have directories + specified already. + + If there are no other slashes then the filename will be + in the "root" directory. Otherwise, we need to add + directory specifications. */ + + if (index (unixname, '/') == 0) + { + /* if no directories specified yet and none are following. */ + if (local_ptr[-1] == '[') + { + /* Just add "000000]" as the directory string */ + strcpy (local_ptr, "000000]"); + local_ptr += strlen (local_ptr); + check_filename_before_returning = 1; /* we might need to fool with this later */ + } + } + else + { + + /* As long as there are still subdirectories to add, do them. */ + while (index (unixname, '/') != 0) + { + /* If this token is "." we can ignore it + if it's not at the beginning of a path. */ + if ((unixname[0] == '.') && (unixname[1] == '/')) + { + /* remove it at beginning of path. */ + if ( ((unixname == fullname) /* no device spec */ + && (fullname+2 != basename)) /* starts with ./ */ + /* or */ + || ((basename[-1] == ':') /* device spec */ + && (unixname-1 == basename))) /* and ./ afterwards */ + *local_ptr++ = '.'; /* make '[.' start of path. */ + unixname += 2; + continue; + } + + /* Add a subdirectory spec. Do not duplicate "." */ + if ( local_ptr[-1] != '.' + && local_ptr[-1] != '[' + && local_ptr[-1] != '<') + *local_ptr++ = '.'; + + /* If this is ".." then the spec becomes "-" */ + if ( (unixname[0] == '.') + && (unixname[1] == '.') + && (unixname[2] == '/')) + { + /* Add "-" and skip the ".." */ + if ((local_ptr[-1] == '.') + && (local_ptr[-2] == '[')) + local_ptr--; /* prevent [.- */ + *local_ptr++ = '-'; + unixname += 3; + continue; + } + + /* Copy the subdirectory */ + while (*unixname != '/') + *local_ptr++= *unixname++; + + unixname++; /* Skip the "/" */ + } + + /* Close the directory specification */ + if (local_ptr[-1] == '.') /* no trailing periods */ + local_ptr--; + + if (local_ptr[-1] == '[') /* no dir needed */ + local_ptr--; + else + *local_ptr++ = ']'; + } + + /* Now add the filename. */ + + while (*unixname) + *local_ptr++ = *unixname++; + *local_ptr = 0; + + /* Now append it to the original VMS spec. */ + + strcpy ((must_revert==1)?fullname:basename, Local); + + /* If we put a [000000] in the filename, try to open it first. If this fails, + remove the [000000], and return that name. This provides flexibility + to the user in that they can use both rooted and non-rooted logical names + to point to the location of the file. */ + + if (check_filename_before_returning) + { + f = open (fullname, O_RDONLY, 0666); + if (f >= 0) + { + /* The file name is OK as it is, so return it as is. */ + close (f); + return 1; + } + + /* The filename did not work. Try to remove the [000000] from the name, + and return it. */ + + basename = index (fullname, '['); + local_ptr = index (fullname, ']') + 1; + strcpy (basename, local_ptr); /* this gets rid of it */ + + } + + return 1; +} +#endif /* VMS */ diff --git a/gcc_arm/cpphash.c b/gcc_arm/cpphash.c new file mode 100755 index 0000000..2ce8a3c --- /dev/null +++ b/gcc_arm/cpphash.c @@ -0,0 +1,200 @@ +/* Part of CPP library. (Macro hash table support.) + Copyright (C) 1986, 87, 89, 92-95, 1996, 1998 Free Software Foundation, Inc. + Written by Per Bothner, 1994. + Based on CCCP program by Paul Rubin, June 1986 + Adapted to ANSI C, Richard Stallman, Jan 1987 + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +#include "config.h" +#include "system.h" +#include "cpplib.h" +#include "cpphash.h" + +static HASHNODE *hashtab[HASHSIZE]; + +/* Return hash function on name. must be compatible with the one + computed a step at a time, elsewhere */ + +int +hashf (name, len, hashsize) + register const U_CHAR *name; + register int len; + int hashsize; +{ + register int r = 0; + + while (len--) + r = HASHSTEP (r, *name++); + + return MAKE_POS (r) % hashsize; +} + +/* Find the most recent hash node for name "name" (ending with first + non-identifier char) installed by install + + If LEN is >= 0, it is the length of the name. + Otherwise, compute the length by scanning the entire name. + + If HASH is >= 0, it is the precomputed hash code. + Otherwise, compute the hash code. */ + +HASHNODE * +cpp_lookup (pfile, name, len, hash) + cpp_reader *pfile ATTRIBUTE_UNUSED; + const U_CHAR *name; + int len; + int hash; +{ + register const U_CHAR *bp; + register HASHNODE *bucket; + + if (len < 0) + { + for (bp = name; is_idchar[*bp]; bp++) ; + len = bp - name; + } + + if (hash < 0) + hash = hashf (name, len, HASHSIZE); + + bucket = hashtab[hash]; + while (bucket) { + if (bucket->length == len && strncmp (bucket->name, name, len) == 0) + return bucket; + bucket = bucket->next; + } + return (HASHNODE *) 0; +} + +/* + * Delete a hash node. Some weirdness to free junk from macros. + * More such weirdness will have to be added if you define more hash + * types that need it. + */ + +/* Note that the DEFINITION of a macro is removed from the hash table + but its storage is not freed. This would be a storage leak + except that it is not reasonable to keep undefining and redefining + large numbers of macros many times. + In any case, this is necessary, because a macro can be #undef'd + in the middle of reading the arguments to a call to it. + If #undef freed the DEFINITION, that would crash. */ + +void +delete_macro (hp) + HASHNODE *hp; +{ + + if (hp->prev != NULL) + hp->prev->next = hp->next; + if (hp->next != NULL) + hp->next->prev = hp->prev; + + /* make sure that the bucket chain header that + the deleted guy was on points to the right thing afterwards. */ + if (hp == *hp->bucket_hdr) + *hp->bucket_hdr = hp->next; + + if (hp->type == T_MACRO) + { + DEFINITION *d = hp->value.defn; + struct reflist *ap, *nextap; + + for (ap = d->pattern; ap != NULL; ap = nextap) + { + nextap = ap->next; + free (ap); + } + if (d->nargs >= 0) + free (d->args.argnames); + free (d); + } + + free (hp); +} + +/* Install a name in the main hash table, even if it is already there. + name stops with first non alphanumeric, except leading '#'. + caller must check against redefinition if that is desired. + delete_macro () removes things installed by install () in fifo order. + this is important because of the `defined' special symbol used + in #if, and also if pushdef/popdef directives are ever implemented. + + If LEN is >= 0, it is the length of the name. + Otherwise, compute the length by scanning the entire name. + + If HASH is >= 0, it is the precomputed hash code. + Otherwise, compute the hash code. */ + +HASHNODE * +install (name, len, type, ivalue, value, hash) + U_CHAR *name; + int len; + enum node_type type; + int ivalue; + char *value; + int hash; +{ + register HASHNODE *hp; + register int i, bucket; + register U_CHAR *p; + + if (len < 0) { + p = name; + while (is_idchar[*p]) + p++; + len = p - name; + } + + if (hash < 0) + hash = hashf (name, len, HASHSIZE); + + i = sizeof (HASHNODE) + len + 1; + hp = (HASHNODE *) xmalloc (i); + bucket = hash; + hp->bucket_hdr = &hashtab[bucket]; + hp->next = hashtab[bucket]; + hashtab[bucket] = hp; + hp->prev = NULL; + if (hp->next != NULL) + hp->next->prev = hp; + hp->type = type; + hp->length = len; + if (hp->type == T_CONST) + hp->value.ival = ivalue; + else + hp->value.cpval = value; + hp->name = ((U_CHAR *) hp) + sizeof (HASHNODE); + bcopy (name, hp->name, len); + hp->name[len] = 0; + return hp; +} + +void +cpp_hash_cleanup (pfile) + cpp_reader *pfile ATTRIBUTE_UNUSED; +{ + register int i; + for (i = HASHSIZE; --i >= 0; ) + { + while (hashtab[i]) + delete_macro (hashtab[i]); + } +} diff --git a/gcc_arm/cpphash.h b/gcc_arm/cpphash.h new file mode 100755 index 0000000..0f37b56 --- /dev/null +++ b/gcc_arm/cpphash.h @@ -0,0 +1,54 @@ +/* Part of CPP library. (Macro hash table support.) + Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* different kinds of things that can appear in the value field + of a hash node. Actually, this may be useless now. */ +union hashval { + int ival; + char *cpval; + DEFINITION *defn; + struct hashnode *aschain; /* for #assert */ +}; + +struct hashnode { + struct hashnode *next; /* double links for easy deletion */ + struct hashnode *prev; + struct hashnode **bucket_hdr; /* also, a back pointer to this node's hash + chain is kept, in case the node is the head + of the chain and gets deleted. */ + enum node_type type; /* type of special token */ + int length; /* length of token, for quick comparison */ + U_CHAR *name; /* the actual name */ + union hashval value; /* pointer to expansion, or whatever */ +}; + +typedef struct hashnode HASHNODE; + +/* Some definitions for the hash table. The hash function MUST be + computed as shown in hashf () below. That is because the rescan + loop computes the hash value `on the fly' for most tokens, + in order to avoid the overhead of a lot of procedure calls to + the hashf () function. Hashf () only exists for the sake of + politeness, for use when speed isn't so important. */ + +#define HASHSIZE 1403 +#define HASHSTEP(old, c) ((old << 2) + c) +#define MAKE_POS(v) (v & 0x7fffffff) /* make number positive */ + +extern HASHNODE *install PARAMS ((U_CHAR *,int,enum node_type, int,char *,int)); +extern int hashf PARAMS ((const U_CHAR *, int, int)); +extern void delete_macro PARAMS ((HASHNODE *)); diff --git a/gcc_arm/cpplib.c b/gcc_arm/cpplib.c new file mode 100755 index 0000000..c151fbf --- /dev/null +++ b/gcc_arm/cpplib.c @@ -0,0 +1,6588 @@ +/* CPP Library. + Copyright (C) 1986, 87, 89, 92-98, 1999 Free Software Foundation, Inc. + Contributed by Per Bothner, 1994-95. + Based on CCCP program by Paul Rubin, June 1986 + Adapted to ANSI C, Richard Stallman, Jan 1987 + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" + +#ifndef STDC_VALUE +#define STDC_VALUE 1 +#endif + +#include + +#ifdef HAVE_SYS_TIMES_H +#include +#endif + +#ifdef HAVE_SYS_RESOURCE_H +# include +#endif + +#include "cpplib.h" +#include "cpphash.h" +#include "output.h" +#include "prefix.h" + +#ifndef GET_ENV_PATH_LIST +#define GET_ENV_PATH_LIST(VAR,NAME) do { (VAR) = getenv (NAME); } while (0) +#endif + +/* By default, colon separates directories in a path. */ +#ifndef PATH_SEPARATOR +#define PATH_SEPARATOR ':' +#endif + +#ifndef STANDARD_INCLUDE_DIR +#define STANDARD_INCLUDE_DIR "/usr/include" +#endif + +/* Symbols to predefine. */ + +#ifdef CPP_PREDEFINES +static char *predefs = CPP_PREDEFINES; +#else +static char *predefs = ""; +#endif + +/* We let tm.h override the types used here, to handle trivial differences + such as the choice of unsigned int or long unsigned int for size_t. + When machines start needing nontrivial differences in the size type, + it would be best to do something here to figure out automatically + from other information what type to use. */ + +/* The string value for __SIZE_TYPE__. */ + +#ifndef SIZE_TYPE +#define SIZE_TYPE "long unsigned int" +#endif + +/* The string value for __PTRDIFF_TYPE__. */ + +#ifndef PTRDIFF_TYPE +#define PTRDIFF_TYPE "long int" +#endif + +/* The string value for __WCHAR_TYPE__. */ + +/* CYGNUS LOCAL vmakarov */ +#ifndef NO_BUILTIN_WCHAR_TYPE +/* END CYGNUS LOCAL */ +#ifndef WCHAR_TYPE +#define WCHAR_TYPE "int" +#endif +#define CPP_WCHAR_TYPE(PFILE) \ + (CPP_OPTIONS (PFILE)->cplusplus ? "__wchar_t" : WCHAR_TYPE) +/* CYGNUS LOCAL vmakarov */ +#endif +/* END CYGNUS LOCAL */ + +/* The string value for __USER_LABEL_PREFIX__ */ + +#ifndef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "" +#endif + +/* The string value for __REGISTER_PREFIX__ */ + +#ifndef REGISTER_PREFIX +#define REGISTER_PREFIX "" +#endif + +#define SKIP_WHITE_SPACE(p) do { while (is_hor_space[*p]) p++; } while (0) +#define SKIP_ALL_WHITE_SPACE(p) do { while (is_space[*p]) p++; } while (0) + +#define PEEKN(N) (CPP_BUFFER (pfile)->rlimit - CPP_BUFFER (pfile)->cur >= (N) ? CPP_BUFFER (pfile)->cur[N] : EOF) +#define FORWARD(N) CPP_FORWARD (CPP_BUFFER (pfile), (N)) +#define GETC() CPP_BUF_GET (CPP_BUFFER (pfile)) +#define PEEKC() CPP_BUF_PEEK (CPP_BUFFER (pfile)) +/* CPP_IS_MACRO_BUFFER is true if the buffer contains macro expansion. + (Note that it is false while we're expanding marco *arguments*.) */ +#define CPP_IS_MACRO_BUFFER(PBUF) ((PBUF)->cleanup == macro_cleanup) + +/* Move all backslash-newline pairs out of embarrassing places. + Exchange all such pairs following BP + with any potentially-embarrassing characters that follow them. + Potentially-embarrassing characters are / and * + (because a backslash-newline inside a comment delimiter + would cause it not to be recognized). */ + +#define NEWLINE_FIX \ + do {while (PEEKC() == '\\' && PEEKN(1) == '\n') FORWARD(2); } while(0) + +/* Same, but assume we've already read the potential '\\' into C. */ +#define NEWLINE_FIX1(C) do { \ + while ((C) == '\\' && PEEKC() == '\n') { FORWARD(1); (C) = GETC(); }\ + } while(0) + +struct cpp_pending { + struct cpp_pending *next; + char *cmd; + char *arg; +}; + +/* Forward declarations. */ + +extern void cpp_hash_cleanup PARAMS ((cpp_reader *)); + +static char *my_strerror PROTO ((int)); +static void make_assertion PROTO ((cpp_reader *, char *, U_CHAR *)); +static void path_include PROTO ((cpp_reader *, char *)); +static void initialize_builtins PROTO ((cpp_reader *)); +static void initialize_char_syntax PROTO ((void)); +#if 0 +static void trigraph_pcp (); +#endif +static void validate_else PROTO ((cpp_reader *, char *)); +static int comp_def_part PROTO ((int, U_CHAR *, int, U_CHAR *, + int, int)); +#ifdef abort +extern void fancy_abort (); +#endif +/* CYGNUS LOCAL - obscured headers */ +static int open_include_file_name PARAMS ((cpp_reader*, char *)); +/* END CYGNUS LOCAL - obscured headers */ +static int check_macro_name PROTO ((cpp_reader *, U_CHAR *, char *)); +static int compare_defs PROTO ((cpp_reader *, + DEFINITION *, DEFINITION *)); +static HOST_WIDE_INT eval_if_expression PROTO ((cpp_reader *)); +static int change_newlines PROTO ((U_CHAR *, int)); +static void push_macro_expansion PARAMS ((cpp_reader *, + U_CHAR *, int, HASHNODE *)); +static struct cpp_pending *nreverse_pending PARAMS ((struct cpp_pending *)); + +static void conditional_skip PROTO ((cpp_reader *, int, + enum node_type, U_CHAR *)); +static void skip_if_group PROTO ((cpp_reader *)); +static int parse_name PARAMS ((cpp_reader *, int)); +static void print_help PROTO ((void)); + +/* Last arg to output_line_command. */ +enum file_change_code {same_file, enter_file, leave_file}; + +/* External declarations. */ + +extern HOST_WIDE_INT cpp_parse_expr PARAMS ((cpp_reader *)); + +extern char *version_string; +extern struct tm *localtime (); + + +/* #include "file" looks in source file dir, then stack. */ +/* #include just looks in the stack. */ +/* -I directories are added to the end, then the defaults are added. */ +/* The */ +static struct default_include { + char *fname; /* The name of the directory. */ + char *component; /* The component containing the directory */ + int cplusplus; /* Only look here if we're compiling C++. */ + int cxx_aware; /* Includes in this directory don't need to + be wrapped in extern "C" when compiling + C++. */ +} include_defaults_array[] +#ifdef INCLUDE_DEFAULTS + = INCLUDE_DEFAULTS; +#else + = { + /* Pick up GNU C++ specific include files. */ + { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1 }, +#ifdef CROSS_COMPILE + /* This is the dir for fixincludes. Put it just before + the files that we fix. */ + { GCC_INCLUDE_DIR, "GCC", 0, 0 }, + /* For cross-compilation, this dir name is generated + automatically in Makefile.in. */ + { CROSS_INCLUDE_DIR, "GCC",0, 0 }, +#ifdef TOOL_INCLUDE_DIR + /* This is another place that the target system's headers might be. */ + { TOOL_INCLUDE_DIR, "BINUTILS", 0, 1 }, +#endif +#else /* not CROSS_COMPILE */ +#ifdef LOCAL_INCLUDE_DIR + /* This should be /usr/local/include and should come before + the fixincludes-fixed header files. */ + { LOCAL_INCLUDE_DIR, 0, 0, 1 }, +#endif +#ifdef TOOL_INCLUDE_DIR + /* This is here ahead of GCC_INCLUDE_DIR because assert.h goes here. + Likewise, behind LOCAL_INCLUDE_DIR, where glibc puts its assert.h. */ + { TOOL_INCLUDE_DIR, "BINUTILS", 0, 1 }, +#endif + /* This is the dir for fixincludes. Put it just before + the files that we fix. */ + { GCC_INCLUDE_DIR, "GCC", 0, 0 }, + /* Some systems have an extra dir of include files. */ +#ifdef SYSTEM_INCLUDE_DIR + { SYSTEM_INCLUDE_DIR, 0, 0, 0 }, +#endif +#ifndef STANDARD_INCLUDE_COMPONENT +#define STANDARD_INCLUDE_COMPONENT 0 +#endif + { STANDARD_INCLUDE_DIR, STANDARD_INCLUDE_COMPONENT, 0, 0 }, +#endif /* not CROSS_COMPILE */ + { 0, 0, 0, 0 } + }; +#endif /* no INCLUDE_DEFAULTS */ + +/* `struct directive' defines one #-directive, including how to handle it. */ + +struct directive { + int length; /* Length of name */ + int (*func) /* Function to handle directive */ + PARAMS ((cpp_reader *, struct directive *)); + char *name; /* Name of directive */ + enum node_type type; /* Code which describes which directive. */ +}; + +/* These functions are declared to return int instead of void since they + are going to be placed in a table and some old compilers have trouble with + pointers to functions returning void. */ + +static int do_define PARAMS ((cpp_reader *, struct directive *)); +static int do_line PARAMS ((cpp_reader *, struct directive *)); +static int do_include PARAMS ((cpp_reader *, struct directive *)); +static int do_undef PARAMS ((cpp_reader *, struct directive *)); +static int do_error PARAMS ((cpp_reader *, struct directive *)); +static int do_pragma PARAMS ((cpp_reader *, struct directive *)); +static int do_ident PARAMS ((cpp_reader *, struct directive *)); +static int do_if PARAMS ((cpp_reader *, struct directive *)); +static int do_xifdef PARAMS ((cpp_reader *, struct directive *)); +static int do_else PARAMS ((cpp_reader *, struct directive *)); +static int do_elif PARAMS ((cpp_reader *, struct directive *)); +static int do_endif PARAMS ((cpp_reader *, struct directive *)); +#ifdef SCCS_DIRECTIVE +static int do_sccs PARAMS ((cpp_reader *, struct directive *)); +#endif +static int do_assert PARAMS ((cpp_reader *, struct directive *)); +static int do_unassert PARAMS ((cpp_reader *, struct directive *)); +static int do_warning PARAMS ((cpp_reader *, struct directive *)); + +#define IS_INCLUDE_DIRECTIVE_TYPE(t) \ +((int) T_INCLUDE <= (int) (t) && (int) (t) <= (int) T_IMPORT) + +/* Here is the actual list of #-directives, most-often-used first. + The initialize_builtins function assumes #define is the very first. */ + +static struct directive directive_table[] = { + { 6, do_define, "define", T_DEFINE }, + { 5, do_xifdef, "ifdef", T_IFDEF }, + { 6, do_xifdef, "ifndef", T_IFNDEF }, + { 7, do_include, "include", T_INCLUDE }, + { 12, do_include, "include_next", T_INCLUDE_NEXT }, + { 6, do_include, "import", T_IMPORT }, + { 5, do_endif, "endif", T_ENDIF }, + { 4, do_else, "else", T_ELSE }, + { 2, do_if, "if", T_IF }, + { 4, do_elif, "elif", T_ELIF }, + { 5, do_undef, "undef", T_UNDEF }, + { 5, do_error, "error", T_ERROR }, + { 7, do_warning, "warning", T_WARNING }, + { 6, do_pragma, "pragma", T_PRAGMA }, + { 4, do_line, "line", T_LINE }, + { 5, do_ident, "ident", T_IDENT }, +#ifdef SCCS_DIRECTIVE + { 4, do_sccs, "sccs", T_SCCS }, +#endif + { 6, do_assert, "assert", T_ASSERT }, + { 8, do_unassert, "unassert", T_UNASSERT }, + { -1, 0, "", T_UNUSED } +}; + +/* table to tell if char can be part of a C identifier. */ +U_CHAR is_idchar[256] = { 0 }; +/* table to tell if char can be first char of a c identifier. */ +U_CHAR is_idstart[256] = { 0 }; +/* table to tell if c is horizontal space. */ +U_CHAR is_hor_space[256] = { 0 }; +/* table to tell if c is horizontal or vertical space. */ +U_CHAR is_space[256] = { 0 }; + +/* Initialize syntactic classifications of characters. */ +static void +initialize_char_syntax () +{ + register int i; + + /* + * Set up is_idchar and is_idstart tables. These should be + * faster than saying (is_alpha (c) || c == '_'), etc. + * Set up these things before calling any routines tthat + * refer to them. + * XXX We should setlocale(LC_CTYPE, "C") here for safety. + */ + for (i = 0; i < 256; i++) + { + is_idchar[i] = ISALNUM (i); + is_idstart[i] = ISALPHA (i); + } + + is_idchar['_'] = 1; + is_idstart['_'] = 1; + + /* These will be reset later if -$ is in effect. */ + is_idchar['$'] = 1; + is_idstart['$'] = 1; + + /* horizontal space table */ + is_hor_space[' '] = 1; + is_hor_space['\t'] = 1; + is_hor_space['\v'] = 1; + is_hor_space['\f'] = 1; + is_hor_space['\r'] = 1; + + is_space[' '] = 1; + is_space['\t'] = 1; + is_space['\v'] = 1; + is_space['\f'] = 1; + is_space['\n'] = 1; + is_space['\r'] = 1; +} + + +/* Place into PFILE a quoted string representing the string SRC. + Caller must reserve enough space in pfile->token_buffer. */ + +static void +quote_string (pfile, src) + cpp_reader *pfile; + char *src; +{ + U_CHAR c; + + CPP_PUTC_Q (pfile, '\"'); + for (;;) + switch ((c = *src++)) + { + default: + if (ISPRINT (c)) + CPP_PUTC_Q (pfile, c); + else + { + sprintf ((char *)CPP_PWRITTEN (pfile), "\\%03o", c); + CPP_ADJUST_WRITTEN (pfile, 4); + } + break; + + case '\"': + case '\\': + CPP_PUTC_Q (pfile, '\\'); + CPP_PUTC_Q (pfile, c); + break; + + case '\0': + CPP_PUTC_Q (pfile, '\"'); + CPP_NUL_TERMINATE_Q (pfile); + return; + } +} + +/* Re-allocates PFILE->token_buffer so it will hold at least N more chars. */ + +void +cpp_grow_buffer (pfile, n) + cpp_reader *pfile; + long n; +{ + long old_written = CPP_WRITTEN (pfile); + pfile->token_buffer_size = n + 2 * pfile->token_buffer_size; + pfile->token_buffer = (U_CHAR *) + xrealloc(pfile->token_buffer, pfile->token_buffer_size); + CPP_SET_WRITTEN (pfile, old_written); +} + + +/* + * process a given definition string, for initialization + * If STR is just an identifier, define it with value 1. + * If STR has anything after the identifier, then it should + * be identifier=definition. + */ + +void +cpp_define (pfile, str) + cpp_reader *pfile; + U_CHAR *str; +{ + U_CHAR *buf, *p; + + buf = str; + p = str; + if (!is_idstart[*p]) + { + cpp_error (pfile, "malformed option `-D %s'", str); + return; + } + while (is_idchar[*++p]) + ; + if (*p == '(') { + while (is_idchar[*++p] || *p == ',' || is_hor_space[*p]) + ; + if (*p++ != ')') + p = (U_CHAR *) str; /* Error */ + } + if (*p == 0) + { + buf = (U_CHAR *) alloca (p - buf + 4); + strcpy ((char *)buf, str); + strcat ((char *)buf, " 1"); + } + else if (*p != '=') + { + cpp_error (pfile, "malformed option `-D %s'", str); + return; + } + else + { + U_CHAR *q; + /* Copy the entire option so we can modify it. */ + buf = (U_CHAR *) alloca (2 * strlen (str) + 1); + strncpy (buf, str, p - str); + /* Change the = to a space. */ + buf[p - str] = ' '; + /* Scan for any backslash-newline and remove it. */ + p++; + q = &buf[p - str]; + while (*p) + { + if (*p == '\\' && p[1] == '\n') + p += 2; + else + *q++ = *p++; + } + *q = 0; + } + + if (cpp_push_buffer (pfile, buf, strlen (buf)) != NULL) + { + do_define (pfile, NULL); + cpp_pop_buffer (pfile); + } +} + +/* Process the string STR as if it appeared as the body of a #assert. + OPTION is the option name for which STR was the argument. */ + +static void +make_assertion (pfile, option, str) + cpp_reader *pfile; + char *option; + U_CHAR *str; +{ + U_CHAR *buf, *p, *q; + + /* Copy the entire option so we can modify it. */ + buf = (U_CHAR *) alloca (strlen (str) + 1); + strcpy ((char *) buf, str); + /* Scan for any backslash-newline and remove it. */ + p = q = buf; + while (*p) { +#if 0 + if (*p == '\\' && p[1] == '\n') + p += 2; + else +#endif + *q++ = *p++; + } + *q = 0; + + p = buf; + if (!is_idstart[*p]) { + cpp_error (pfile, "malformed option `%s %s'", option, str); + return; + } + while (is_idchar[*++p]) + ; + while (*p == ' ' || *p == '\t') p++; + if (! (*p == 0 || *p == '(')) { + cpp_error (pfile, "malformed option `%s %s'", option, str); + return; + } + + if (cpp_push_buffer (pfile, buf, strlen (buf)) != NULL) + { + do_assert (pfile, NULL); + cpp_pop_buffer (pfile); + } +} + +/* Given a colon-separated list of file names PATH, + add all the names to the search path for include files. */ + +static void +path_include (pfile, path) + cpp_reader *pfile; + char *path; +{ + char *p; + + p = path; + + if (*p) + while (1) { + char *q = p; + char *name; + + /* Find the end of this name. */ + while (*q != 0 && *q != PATH_SEPARATOR) q++; + if (p == q) { + /* An empty name in the path stands for the current directory. */ + name = (char *) xmalloc (2); + name[0] = '.'; + name[1] = 0; + } else { + /* Otherwise use the directory that is named. */ + name = (char *) xmalloc (q - p + 1); + bcopy (p, name, q - p); + name[q - p] = 0; + } + + append_include_chain (pfile, + &(CPP_OPTIONS (pfile)->bracket_include), name, 0); + + /* Advance past this name. */ + p = q; + if (*p == 0) + break; + /* Skip the colon. */ + p++; + } +} + +void +cpp_options_init (opts) + cpp_options *opts; +{ + bzero ((char *) opts, sizeof *opts); + opts->in_fname = NULL; + opts->out_fname = NULL; + + opts->dollars_in_ident = 1; + initialize_char_syntax (); + + opts->no_line_commands = 0; + opts->no_trigraphs = 1; + opts->put_out_comments = 0; + opts->print_include_names = 0; + opts->dump_macros = dump_none; + opts->no_output = 0; + opts->remap = 0; + opts->cplusplus = 0; + opts->cplusplus_comments = 1; + + opts->verbose = 0; + opts->objc = 0; + opts->lang_asm = 0; + opts->for_lint = 0; + opts->chill = 0; + opts->pedantic_errors = 0; + opts->inhibit_warnings = 0; + opts->warn_comments = 0; + opts->warn_import = 1; + opts->warnings_are_errors = 0; +} + +enum cpp_token +null_underflow (pfile) + cpp_reader *pfile ATTRIBUTE_UNUSED; +{ + return CPP_EOF; +} + +int +null_cleanup (pbuf, pfile) + cpp_buffer *pbuf ATTRIBUTE_UNUSED; + cpp_reader *pfile ATTRIBUTE_UNUSED; +{ + return 0; +} + +int +macro_cleanup (pbuf, pfile) + cpp_buffer *pbuf; + cpp_reader *pfile ATTRIBUTE_UNUSED; +{ + HASHNODE *macro = (HASHNODE *) pbuf->data; + if (macro->type == T_DISABLED) + macro->type = T_MACRO; + if (macro->type != T_MACRO || pbuf->buf != macro->value.defn->expansion) + free (pbuf->buf); + return 0; +} + +/* Assuming we have read '/'. + If this is the start of a comment (followed by '*' or '/'), + skip to the end of the comment, and return ' '. + Return EOF if we reached the end of file before the end of the comment. + If not the start of a comment, return '/'. */ + +static int +skip_comment (pfile, linep) + cpp_reader *pfile; + long *linep; +{ + int c = 0; + while (PEEKC() == '\\' && PEEKN(1) == '\n') + { + if (linep) + (*linep)++; + FORWARD(2); + } + if (PEEKC() == '*') + { + FORWARD(1); + for (;;) + { + int prev_c = c; + c = GETC (); + if (c == EOF) + return EOF; + while (c == '\\' && PEEKC() == '\n') + { + if (linep) + (*linep)++; + FORWARD(1), c = GETC(); + } + if (prev_c == '*' && c == '/') + return ' '; + if (c == '\n' && linep) + (*linep)++; + } + } + else if (PEEKC() == '/' && CPP_OPTIONS (pfile)->cplusplus_comments) + { + FORWARD(1); + for (;;) + { + c = GETC (); + if (c == EOF) + return ' '; /* Allow // to be terminated by EOF. */ + while (c == '\\' && PEEKC() == '\n') + { + FORWARD(1); + c = GETC(); + if (linep) + (*linep)++; + } + if (c == '\n') + { + /* Don't consider final '\n' to be part of comment. */ + FORWARD(-1); + return ' '; + } + } + } + else + return '/'; +} + +/* Skip whitespace \-newline and comments. Does not macro-expand. */ + +void +cpp_skip_hspace (pfile) + cpp_reader *pfile; +{ + while (1) + { + int c = PEEKC(); + if (c == EOF) + return; /* FIXME */ + if (is_hor_space[c]) + { + if ((c == '\f' || c == '\v') && CPP_PEDANTIC (pfile)) + cpp_pedwarn (pfile, "%s in preprocessing directive", + c == '\f' ? "formfeed" : "vertical tab"); + FORWARD(1); + } + else if (c == '/') + { + FORWARD (1); + c = skip_comment (pfile, NULL); + if (c == '/') + FORWARD(-1); + if (c == EOF || c == '/') + return; + } + else if (c == '\\' && PEEKN(1) == '\n') { + FORWARD(2); + } + else if (c == '@' && CPP_BUFFER (pfile)->has_escapes + && is_hor_space[PEEKN(1)]) + FORWARD(2); + else return; + } +} + +/* Read the rest of the current line. + The line is appended to PFILE's output buffer. */ + +static void +copy_rest_of_line (pfile) + cpp_reader *pfile; +{ + struct cpp_options *opts = CPP_OPTIONS (pfile); + for (;;) + { + int c = GETC(); + int nextc; + switch (c) + { + case EOF: + goto end_directive; + case '\\': + if (PEEKC() == '\n') + { + FORWARD (1); + continue; + } + case '\'': + case '\"': + goto scan_directive_token; + break; + case '/': + nextc = PEEKC(); + if (nextc == '*' || (opts->cplusplus_comments && nextc == '/')) + goto scan_directive_token; + break; + case '\f': + case '\v': + if (CPP_PEDANTIC (pfile)) + cpp_pedwarn (pfile, "%s in preprocessing directive", + c == '\f' ? "formfeed" : "vertical tab"); + break; + + case '\n': + FORWARD(-1); + goto end_directive; + scan_directive_token: + FORWARD(-1); + cpp_get_token (pfile); + continue; + } + CPP_PUTC (pfile, c); + } + end_directive: ; + CPP_NUL_TERMINATE (pfile); +} + +void +skip_rest_of_line (pfile) + cpp_reader *pfile; +{ + long old = CPP_WRITTEN (pfile); + copy_rest_of_line (pfile); + CPP_SET_WRITTEN (pfile, old); +} + +/* Handle a possible # directive. + '#' has already been read. */ + +int +handle_directive (pfile) + cpp_reader *pfile; +{ int c; + register struct directive *kt; + int ident_length; + U_CHAR *ident; + long old_written = CPP_WRITTEN (pfile); + + cpp_skip_hspace (pfile); + + c = PEEKC (); + if (c >= '0' && c <= '9') + { + /* Handle # followed by a line number. */ + if (CPP_PEDANTIC (pfile)) + cpp_pedwarn (pfile, "`#' followed by integer"); + do_line (pfile, NULL); + goto done_a_directive; + } + + /* Now find the directive name. */ + CPP_PUTC (pfile, '#'); + parse_name (pfile, GETC()); + ident = pfile->token_buffer + old_written + 1; + ident_length = CPP_PWRITTEN (pfile) - ident; + if (ident_length == 0 && PEEKC() == '\n') + { + /* A line of just `#' becomes blank. */ + goto done_a_directive; + } + +#if 0 + if (ident_length == 0 || !is_idstart[*ident]) { + U_CHAR *p = ident; + while (is_idchar[*p]) { + if (*p < '0' || *p > '9') + break; + p++; + } + /* Avoid error for `###' and similar cases unless -pedantic. */ + if (p == ident) { + while (*p == '#' || is_hor_space[*p]) p++; + if (*p == '\n') { + if (pedantic && !lang_asm) + cpp_warning (pfile, "invalid preprocessor directive"); + return 0; + } + } + + if (!lang_asm) + cpp_error (pfile, "invalid preprocessor directive name"); + + return 0; + } +#endif + /* + * Decode the keyword and call the appropriate expansion + * routine, after moving the input pointer up to the next line. + */ + for (kt = directive_table; ; kt++) { + if (kt->length <= 0) + goto not_a_directive; + if (kt->length == ident_length + && !strncmp (kt->name, ident, ident_length)) + break; + } + + /* We may want to pass through #define, #pragma, and #include. + Other directives may create output, but we don't want the directive + itself out, so we pop it now. For example conditionals may emit + #failed ... #endfailed stuff. */ + + if (! (kt->type == T_DEFINE + || kt->type == T_PRAGMA + || (IS_INCLUDE_DIRECTIVE_TYPE (kt->type) + && CPP_OPTIONS (pfile)->dump_includes))) + CPP_SET_WRITTEN (pfile, old_written); + + (*kt->func) (pfile, kt); + + if (kt->type == T_DEFINE) + { + if (CPP_OPTIONS (pfile)->dump_macros == dump_names) + { + /* Skip "#define". */ + U_CHAR *p = pfile->token_buffer + old_written + 7; + + SKIP_WHITE_SPACE (p); + while (is_idchar[*p]) p++; + pfile->limit = p; + CPP_PUTC (pfile, '\n'); + } + else if (CPP_OPTIONS (pfile)->dump_macros != dump_definitions) + CPP_SET_WRITTEN (pfile, old_written); + } + + done_a_directive: + return 1; + + not_a_directive: + return 0; +} + +/* Pass a directive through to the output file. + BUF points to the contents of the directive, as a contiguous string. +m LIMIT points to the first character past the end of the directive. + KEYWORD is the keyword-table entry for the directive. */ + +static void +pass_thru_directive (buf, limit, pfile, keyword) + U_CHAR *buf, *limit; + cpp_reader *pfile; + struct directive *keyword; +{ + register unsigned keyword_length = keyword->length; + + CPP_RESERVE (pfile, 1 + keyword_length + (limit - buf)); + CPP_PUTC_Q (pfile, '#'); + CPP_PUTS_Q (pfile, keyword->name, keyword_length); + if (limit != buf && buf[0] != ' ') + CPP_PUTC_Q (pfile, ' '); + CPP_PUTS_Q (pfile, buf, limit - buf); +#if 0 + CPP_PUTS_Q (pfile, '\n'); + /* Count the line we have just made in the output, + to get in sync properly. */ + pfile->lineno++; +#endif +} + +/* The arglist structure is built by do_define to tell + collect_definition where the argument names begin. That + is, for a define like "#define f(x,y,z) foo+x-bar*y", the arglist + would contain pointers to the strings x, y, and z. + Collect_definition would then build a DEFINITION node, + with reflist nodes pointing to the places x, y, and z had + appeared. So the arglist is just convenience data passed + between these two routines. It is not kept around after + the current #define has been processed and entered into the + hash table. */ + +struct arglist { + struct arglist *next; + U_CHAR *name; + int length; + int argno; + char rest_args; +}; + +/* Read a replacement list for a macro with parameters. + Build the DEFINITION structure. + Reads characters of text starting at BUF until END. + ARGLIST specifies the formal parameters to look for + in the text of the definition; NARGS is the number of args + in that list, or -1 for a macro name that wants no argument list. + MACRONAME is the macro name itself (so we can avoid recursive expansion) + and NAMELEN is its length in characters. + + Note that comments, backslash-newlines, and leading white space + have already been deleted from the argument. */ + +static DEFINITION * +collect_expansion (pfile, buf, limit, nargs, arglist) + cpp_reader *pfile; + U_CHAR *buf, *limit; + int nargs; + struct arglist *arglist; +{ + DEFINITION *defn; + register U_CHAR *p, *lastp, *exp_p; + struct reflist *endpat = NULL; + /* Pointer to first nonspace after last ## seen. */ + U_CHAR *concat = 0; + /* Pointer to first nonspace after last single-# seen. */ + U_CHAR *stringify = 0; + int maxsize; + int expected_delimiter = '\0'; + + /* Scan thru the replacement list, ignoring comments and quoted + strings, picking up on the macro calls. It does a linear search + thru the arg list on every potential symbol. Profiling might say + that something smarter should happen. */ + + if (limit < buf) + abort (); + + /* Find the beginning of the trailing whitespace. */ + p = buf; + while (p < limit && is_space[limit[-1]]) limit--; + + /* Allocate space for the text in the macro definition. + Leading and trailing whitespace chars need 2 bytes each. + Each other input char may or may not need 1 byte, + so this is an upper bound. The extra 5 are for invented + leading and trailing newline-marker and final null. */ + maxsize = (sizeof (DEFINITION) + + (limit - p) + 5); + /* Occurrences of '@' get doubled, so allocate extra space for them. */ + while (p < limit) + if (*p++ == '@') + maxsize++; + defn = (DEFINITION *) xcalloc (1, maxsize); + + defn->nargs = nargs; + exp_p = defn->expansion = (U_CHAR *) defn + sizeof (DEFINITION); + lastp = exp_p; + + p = buf; + + /* Add one initial space escape-marker to prevent accidental + token-pasting (often removed by macroexpand). */ + *exp_p++ = '@'; + *exp_p++ = ' '; + + if (limit - p >= 2 && p[0] == '#' && p[1] == '#') { + cpp_error (pfile, "`##' at start of macro definition"); + p += 2; + } + + /* Process the main body of the definition. */ + while (p < limit) { + int skipped_arg = 0; + register U_CHAR c = *p++; + + *exp_p++ = c; + + if (!CPP_TRADITIONAL (pfile)) { + switch (c) { + case '\'': + case '\"': + if (expected_delimiter != '\0') { + if (c == expected_delimiter) + expected_delimiter = '\0'; + } else + expected_delimiter = c; + break; + + case '\\': + if (p < limit && expected_delimiter) { + /* In a string, backslash goes through + and makes next char ordinary. */ + *exp_p++ = *p++; + } + break; + + case '@': + /* An '@' in a string or character constant stands for itself, + and does not need to be escaped. */ + if (!expected_delimiter) + *exp_p++ = c; + break; + + case '#': + /* # is ordinary inside a string. */ + if (expected_delimiter) + break; + if (p < limit && *p == '#') { + /* ##: concatenate preceding and following tokens. */ + /* Take out the first #, discard preceding whitespace. */ + exp_p--; + while (exp_p > lastp && is_hor_space[exp_p[-1]]) + --exp_p; + /* Skip the second #. */ + p++; + /* Discard following whitespace. */ + SKIP_WHITE_SPACE (p); + concat = p; + if (p == limit) + cpp_error (pfile, "`##' at end of macro definition"); + } else if (nargs >= 0) { + /* Single #: stringify following argument ref. + Don't leave the # in the expansion. */ + exp_p--; + SKIP_WHITE_SPACE (p); + if (p == limit || ! is_idstart[*p] + || (*p == 'L' && p + 1 < limit && (p[1] == '\'' || p[1] == '"'))) + cpp_error (pfile, + "`#' operator is not followed by a macro argument name"); + else + stringify = p; + } + break; + } + } else { + /* In -traditional mode, recognize arguments inside strings and + character constants, and ignore special properties of #. + Arguments inside strings are considered "stringified", but no + extra quote marks are supplied. */ + switch (c) { + case '\'': + case '\"': + if (expected_delimiter != '\0') { + if (c == expected_delimiter) + expected_delimiter = '\0'; + } else + expected_delimiter = c; + break; + + case '\\': + /* Backslash quotes delimiters and itself, but not macro args. */ + if (expected_delimiter != 0 && p < limit + && (*p == expected_delimiter || *p == '\\')) { + *exp_p++ = *p++; + continue; + } + break; + + case '/': + if (expected_delimiter != '\0') /* No comments inside strings. */ + break; + if (*p == '*') { + /* If we find a comment that wasn't removed by handle_directive, + this must be -traditional. So replace the comment with + nothing at all. */ + exp_p--; + p += 1; + while (p < limit && !(p[-2] == '*' && p[-1] == '/')) + p++; +#if 0 + /* Mark this as a concatenation-point, as if it had been ##. */ + concat = p; +#endif + } + break; + } + } + + /* Handle the start of a symbol. */ + if (is_idchar[c] && nargs > 0) { + U_CHAR *id_beg = p - 1; + int id_len; + + --exp_p; + while (p != limit && is_idchar[*p]) p++; + id_len = p - id_beg; + + if (is_idstart[c] + && ! (id_len == 1 && c == 'L' && (*p == '\'' || *p == '"'))) { + register struct arglist *arg; + + for (arg = arglist; arg != NULL; arg = arg->next) { + struct reflist *tpat; + + if (arg->name[0] == c + && arg->length == id_len + && strncmp (arg->name, id_beg, id_len) == 0) { + if (expected_delimiter && CPP_OPTIONS (pfile)->warn_stringify) { + if (CPP_TRADITIONAL (pfile)) { + cpp_warning (pfile, "macro argument `%.*s' is stringified.", + id_len, arg->name); + } else { + cpp_warning (pfile, + "macro arg `%.*s' would be stringified with -traditional.", + id_len, arg->name); + } + } + /* If ANSI, don't actually substitute inside a string. */ + if (!CPP_TRADITIONAL (pfile) && expected_delimiter) + break; + /* make a pat node for this arg and append it to the end of + the pat list */ + tpat = (struct reflist *) xmalloc (sizeof (struct reflist)); + tpat->next = NULL; + tpat->raw_before = concat == id_beg; + tpat->raw_after = 0; + tpat->rest_args = arg->rest_args; + tpat->stringify = (CPP_TRADITIONAL (pfile) + ? expected_delimiter != '\0' + : stringify == id_beg); + + if (endpat == NULL) + defn->pattern = tpat; + else + endpat->next = tpat; + endpat = tpat; + + tpat->argno = arg->argno; + tpat->nchars = exp_p - lastp; + { + register U_CHAR *p1 = p; + SKIP_WHITE_SPACE (p1); + if (p1 + 2 <= limit && p1[0] == '#' && p1[1] == '#') + tpat->raw_after = 1; + } + lastp = exp_p; /* place to start copying from next time */ + skipped_arg = 1; + break; + } + } + } + + /* If this was not a macro arg, copy it into the expansion. */ + if (! skipped_arg) { + register U_CHAR *lim1 = p; + p = id_beg; + while (p != lim1) + *exp_p++ = *p++; + if (stringify == id_beg) + cpp_error (pfile, + "`#' operator should be followed by a macro argument name"); + } + } + } + + if (!CPP_TRADITIONAL (pfile) && expected_delimiter == 0) + { + /* If ANSI, put in a "@ " marker to prevent token pasting. + But not if "inside a string" (which in ANSI mode + happens only for -D option). */ + *exp_p++ = '@'; + *exp_p++ = ' '; + } + + *exp_p = '\0'; + + defn->length = exp_p - defn->expansion; + + /* Crash now if we overrun the allocated size. */ + if (defn->length + 1 > maxsize) + abort (); + +#if 0 +/* This isn't worth the time it takes. */ + /* give back excess storage */ + defn->expansion = (U_CHAR *) xrealloc (defn->expansion, defn->length + 1); +#endif + + return defn; +} + +/* + * special extension string that can be added to the last macro argument to + * allow it to absorb the "rest" of the arguments when expanded. Ex: + * #define wow(a, b...) process (b, a, b) + * { wow (1, 2, 3); } -> { process (2, 3, 1, 2, 3); } + * { wow (one, two); } -> { process (two, one, two); } + * if this "rest_arg" is used with the concat token '##' and if it is not + * supplied then the token attached to with ## will not be outputted. Ex: + * #define wow (a, b...) process (b ## , a, ## b) + * { wow (1, 2); } -> { process (2, 1, 2); } + * { wow (one); } -> { process (one); { + */ +static char rest_extension[] = "..."; +#define REST_EXTENSION_LENGTH (sizeof (rest_extension) - 1) + +/* Create a DEFINITION node from a #define directive. Arguments are + as for do_define. */ + +static MACRODEF +create_definition (buf, limit, pfile, predefinition) + U_CHAR *buf, *limit; + cpp_reader *pfile; + int predefinition; +{ + U_CHAR *bp; /* temp ptr into input buffer */ + U_CHAR *symname; /* remember where symbol name starts */ + int sym_length; /* and how long it is */ + int rest_args = 0; + long line, col; + char *file = CPP_BUFFER (pfile) ? CPP_BUFFER (pfile)->nominal_fname : ""; + DEFINITION *defn; + int arglengths = 0; /* Accumulate lengths of arg names + plus number of args. */ + MACRODEF mdef; + cpp_buf_line_and_col (CPP_BUFFER (pfile), &line, &col); + + bp = buf; + + while (is_hor_space[*bp]) + bp++; + + symname = bp; /* remember where it starts */ + + sym_length = check_macro_name (pfile, bp, "macro"); + bp += sym_length; + + /* Lossage will occur if identifiers or control keywords are broken + across lines using backslash. This is not the right place to take + care of that. */ + + if (*bp == '(') { + struct arglist *arg_ptrs = NULL; + int argno = 0; + + bp++; /* skip '(' */ + SKIP_WHITE_SPACE (bp); + + /* Loop over macro argument names. */ + while (*bp != ')') { + struct arglist *temp; + + temp = (struct arglist *) alloca (sizeof (struct arglist)); + temp->name = bp; + temp->next = arg_ptrs; + temp->argno = argno++; + temp->rest_args = 0; + arg_ptrs = temp; + + if (rest_args) + cpp_pedwarn (pfile, "another parameter follows `%s'", rest_extension); + + if (!is_idstart[*bp]) + cpp_pedwarn (pfile, "invalid character in macro parameter name"); + + /* Find the end of the arg name. */ + while (is_idchar[*bp]) { + bp++; + /* do we have a "special" rest-args extension here? */ + if ((size_t)(limit - bp) > REST_EXTENSION_LENGTH + && strncmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0) { + rest_args = 1; + temp->rest_args = 1; + break; + } + } + temp->length = bp - temp->name; + if (rest_args == 1) + bp += REST_EXTENSION_LENGTH; + arglengths += temp->length + 2; + SKIP_WHITE_SPACE (bp); + if (temp->length == 0 || (*bp != ',' && *bp != ')')) { + cpp_error (pfile, "badly punctuated parameter list in `#define'"); + goto nope; + } + if (*bp == ',') { + bp++; + SKIP_WHITE_SPACE (bp); + } + if (bp >= limit) { + cpp_error (pfile, "unterminated parameter list in `#define'"); + goto nope; + } + { + struct arglist *otemp; + + for (otemp = temp->next; otemp != NULL; otemp = otemp->next) + if (temp->length == otemp->length + && strncmp (temp->name, otemp->name, temp->length) == 0) { + U_CHAR *name; + + name = (U_CHAR *) alloca (temp->length + 1); + (void) strncpy (name, temp->name, temp->length); + name[temp->length] = '\0'; + cpp_error (pfile, + "duplicate argument name `%s' in `#define'", name); + goto nope; + } + } + } + + ++bp; /* skip paren */ + SKIP_WHITE_SPACE (bp); + /* now everything from bp before limit is the definition. */ + defn = collect_expansion (pfile, bp, limit, argno, arg_ptrs); + defn->rest_args = rest_args; + + /* Now set defn->args.argnames to the result of concatenating + the argument names in reverse order + with comma-space between them. */ + defn->args.argnames = (U_CHAR *) xmalloc (arglengths + 1); + { + struct arglist *temp; + int i = 0; + for (temp = arg_ptrs; temp; temp = temp->next) { + bcopy (temp->name, &defn->args.argnames[i], temp->length); + i += temp->length; + if (temp->next != 0) { + defn->args.argnames[i++] = ','; + defn->args.argnames[i++] = ' '; + } + } + defn->args.argnames[i] = 0; + } + } else { + /* Simple expansion or empty definition. */ + + if (bp < limit) + { + if (is_hor_space[*bp]) { + bp++; + SKIP_WHITE_SPACE (bp); + } else { + switch (*bp) { + case '!': case '"': case '#': case '%': case '&': case '\'': + case ')': case '*': case '+': case ',': case '-': case '.': + case '/': case ':': case ';': case '<': case '=': case '>': + case '?': case '[': case '\\': case ']': case '^': case '{': + case '|': case '}': case '~': + cpp_warning (pfile, "missing white space after `#define %.*s'", + sym_length, symname); + break; + + default: + cpp_pedwarn (pfile, "missing white space after `#define %.*s'", + sym_length, symname); + break; + } + } + } + /* now everything from bp before limit is the definition. */ + defn = collect_expansion (pfile, bp, limit, -1, NULL_PTR); + defn->args.argnames = (U_CHAR *) ""; + } + + defn->line = line; + defn->file = file; + + /* OP is null if this is a predefinition */ + defn->predefined = predefinition; + mdef.defn = defn; + mdef.symnam = symname; + mdef.symlen = sym_length; + + return mdef; + + nope: + mdef.defn = 0; + return mdef; +} + +/* Check a purported macro name SYMNAME, and yield its length. + USAGE is the kind of name this is intended for. */ + +static int +check_macro_name (pfile, symname, usage) + cpp_reader *pfile; + U_CHAR *symname; + char *usage; +{ + U_CHAR *p; + int sym_length; + + for (p = symname; is_idchar[*p]; p++) + ; + sym_length = p - symname; + if (sym_length == 0 + || (sym_length == 1 && *symname == 'L' && (*p == '\'' || *p == '"'))) + cpp_error (pfile, "invalid %s name", usage); + else if (!is_idstart[*symname]) { + U_CHAR *msg; /* what pain... */ + msg = (U_CHAR *) alloca (sym_length + 1); + bcopy (symname, msg, sym_length); + msg[sym_length] = 0; + cpp_error (pfile, "invalid %s name `%s'", usage, msg); + } else { + if (! strncmp (symname, "defined", 7) && sym_length == 7) + cpp_error (pfile, "invalid %s name `defined'", usage); + } + return sym_length; +} + +/* Return zero if two DEFINITIONs are isomorphic. */ + +static int +compare_defs (pfile, d1, d2) + cpp_reader *pfile; + DEFINITION *d1, *d2; +{ + register struct reflist *a1, *a2; + register U_CHAR *p1 = d1->expansion; + register U_CHAR *p2 = d2->expansion; + int first = 1; + + if (d1->nargs != d2->nargs) + return 1; + if (CPP_PEDANTIC (pfile) + && strcmp ((char *)d1->args.argnames, (char *)d2->args.argnames)) + return 1; + for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2; + a1 = a1->next, a2 = a2->next) { + if (!((a1->nchars == a2->nchars && ! strncmp (p1, p2, a1->nchars)) + || ! comp_def_part (first, p1, a1->nchars, p2, a2->nchars, 0)) + || a1->argno != a2->argno + || a1->stringify != a2->stringify + || a1->raw_before != a2->raw_before + || a1->raw_after != a2->raw_after) + return 1; + first = 0; + p1 += a1->nchars; + p2 += a2->nchars; + } + if (a1 != a2) + return 1; + if (comp_def_part (first, p1, d1->length - (p1 - d1->expansion), + p2, d2->length - (p2 - d2->expansion), 1)) + return 1; + return 0; +} + +/* Return 1 if two parts of two macro definitions are effectively different. + One of the parts starts at BEG1 and has LEN1 chars; + the other has LEN2 chars at BEG2. + Any sequence of whitespace matches any other sequence of whitespace. + FIRST means these parts are the first of a macro definition; + so ignore leading whitespace entirely. + LAST means these parts are the last of a macro definition; + so ignore trailing whitespace entirely. */ + +static int +comp_def_part (first, beg1, len1, beg2, len2, last) + int first; + U_CHAR *beg1, *beg2; + int len1, len2; + int last; +{ + register U_CHAR *end1 = beg1 + len1; + register U_CHAR *end2 = beg2 + len2; + if (first) { + while (beg1 != end1 && is_space[*beg1]) beg1++; + while (beg2 != end2 && is_space[*beg2]) beg2++; + } + if (last) { + while (beg1 != end1 && is_space[end1[-1]]) end1--; + while (beg2 != end2 && is_space[end2[-1]]) end2--; + } + while (beg1 != end1 && beg2 != end2) { + if (is_space[*beg1] && is_space[*beg2]) { + while (beg1 != end1 && is_space[*beg1]) beg1++; + while (beg2 != end2 && is_space[*beg2]) beg2++; + } else if (*beg1 == *beg2) { + beg1++; beg2++; + } else break; + } + return (beg1 != end1) || (beg2 != end2); +} + +/* Process a #define command. +KEYWORD is the keyword-table entry for #define, +or NULL for a "predefined" macro. */ + +static int +do_define (pfile, keyword) + cpp_reader *pfile; + struct directive *keyword; +{ + int hashcode; + MACRODEF mdef; + HASHNODE *hp; + int save_put_out_comments; + long here; + U_CHAR *macro, *buf, *end; + + here = CPP_WRITTEN (pfile); + + save_put_out_comments = CPP_OPTIONS (pfile)->put_out_comments; + CPP_OPTIONS (pfile)->put_out_comments = CPP_TRADITIONAL (pfile); + copy_rest_of_line (pfile); + CPP_OPTIONS (pfile)->put_out_comments = save_put_out_comments; + + /* Copy out the line so we can pop the token buffer. */ + buf = pfile->token_buffer + here; + end = CPP_PWRITTEN (pfile); + macro = alloca (end - buf + 1); + bcopy (buf, macro, end - buf + 1); + end = macro + (end - buf); + + CPP_SET_WRITTEN (pfile, here); + +#if 0 + /* If this is a precompiler run (with -pcp) pass thru #define commands. */ + if (pcp_outfile && keyword) + pass_thru_directive (macro, end, pfile, keyword); +#endif + + mdef = create_definition (macro, end, pfile, keyword == NULL); + if (mdef.defn == 0) + goto nope; + + hashcode = hashf (mdef.symnam, mdef.symlen, HASHSIZE); + + if ((hp = cpp_lookup (pfile, mdef.symnam, mdef.symlen, hashcode)) != NULL) + { + int ok = 0; + /* Redefining a precompiled key is ok. */ + if (hp->type == T_PCSTRING) + ok = 1; + /* Redefining a macro is ok if the definitions are the same. */ + else if (hp->type == T_MACRO) + ok = ! compare_defs (pfile, mdef.defn, hp->value.defn); + /* Redefining a constant is ok with -D. */ + else if (hp->type == T_CONST) + ok = ! CPP_OPTIONS (pfile)->done_initializing; + /* Print the warning if it's not ok. */ + if (!ok) + { + U_CHAR *msg; /* what pain... */ + + /* If we are passing through #define and #undef directives, do + that for this re-definition now. */ + if (CPP_OPTIONS (pfile)->debug_output && keyword) + pass_thru_directive (macro, end, pfile, keyword); + + msg = (U_CHAR *) alloca (mdef.symlen + 22); + *msg = '`'; + bcopy (mdef.symnam, msg + 1, mdef.symlen); + strcpy ((char *) (msg + mdef.symlen + 1), "' redefined"); + cpp_pedwarn (pfile, msg); + if (hp->type == T_MACRO) + cpp_pedwarn_with_file_and_line (pfile, hp->value.defn->file, hp->value.defn->line, + "this is the location of the previous definition"); + } + /* Replace the old definition. */ + hp->type = T_MACRO; + hp->value.defn = mdef.defn; + } + else + { + /* If we are passing through #define and #undef directives, do + that for this new definition now. */ + if (CPP_OPTIONS (pfile)->debug_output && keyword) + pass_thru_directive (macro, end, pfile, keyword); + install (mdef.symnam, mdef.symlen, T_MACRO, 0, + (char *) mdef.defn, hashcode); + } + + return 0; + +nope: + + return 1; +} + +/* This structure represents one parsed argument in a macro call. + `raw' points to the argument text as written (`raw_length' is its length). + `expanded' points to the argument's macro-expansion + (its length is `expand_length'). + `stringified_length' is the length the argument would have + if stringified. + `use_count' is the number of times this macro arg is substituted + into the macro. If the actual use count exceeds 10, + the value stored is 10. */ + +/* raw and expanded are relative to ARG_BASE */ +#define ARG_BASE ((pfile)->token_buffer) + +struct argdata { + /* Strings relative to pfile->token_buffer */ + long raw, expanded, stringified; + int raw_length, expand_length; + int stringified_length; + char newlines; + char use_count; +}; + +/* Allocate a new cpp_buffer for PFILE, and push it on the input buffer stack. + If BUFFER != NULL, then use the LENGTH characters in BUFFER + as the new input buffer. + Return the new buffer, or NULL on failure. */ + +cpp_buffer * +cpp_push_buffer (pfile, buffer, length) + cpp_reader *pfile; + U_CHAR *buffer; + long length; +{ + register cpp_buffer *buf = CPP_BUFFER (pfile); + if (buf == pfile->buffer_stack) + { + cpp_fatal (pfile, "%s: macro or `#include' recursion too deep", + buf->fname); + return NULL; + } + buf--; + bzero ((char *) buf, sizeof (cpp_buffer)); + CPP_BUFFER (pfile) = buf; + buf->if_stack = pfile->if_stack; + buf->cleanup = null_cleanup; + buf->underflow = null_underflow; + buf->buf = buf->cur = buffer; + buf->alimit = buf->rlimit = buffer + length; + + return buf; +} + +cpp_buffer * +cpp_pop_buffer (pfile) + cpp_reader *pfile; +{ + cpp_buffer *buf = CPP_BUFFER (pfile); + (*buf->cleanup) (buf, pfile); + return ++CPP_BUFFER (pfile); +} + +/* Scan until CPP_BUFFER (PFILE) is exhausted into PFILE->token_buffer. + Pop the buffer when done. */ + +void +cpp_scan_buffer (pfile) + cpp_reader *pfile; +{ + cpp_buffer *buffer = CPP_BUFFER (pfile); + for (;;) + { + enum cpp_token token = cpp_get_token (pfile); + if (token == CPP_EOF) /* Should not happen ... */ + break; + if (token == CPP_POP && CPP_BUFFER (pfile) == buffer) + { + cpp_pop_buffer (pfile); + break; + } + } +} + +/* + * Rescan a string (which may have escape marks) into pfile's buffer. + * Place the result in pfile->token_buffer. + * + * The input is copied before it is scanned, so it is safe to pass + * it something from the token_buffer that will get overwritten + * (because it follows CPP_WRITTEN). This is used by do_include. + */ + +static void +cpp_expand_to_buffer (pfile, buf, length) + cpp_reader *pfile; + U_CHAR *buf; + int length; +{ + register cpp_buffer *ip; +#if 0 + cpp_buffer obuf; +#endif + U_CHAR *limit = buf + length; + U_CHAR *buf1; +#if 0 + int odepth = indepth; +#endif + + if (length < 0) + abort (); + + /* Set up the input on the input stack. */ + + buf1 = (U_CHAR *) alloca (length + 1); + { + register U_CHAR *p1 = buf; + register U_CHAR *p2 = buf1; + + while (p1 != limit) + *p2++ = *p1++; + } + buf1[length] = 0; + + ip = cpp_push_buffer (pfile, buf1, length); + if (ip == NULL) + return; + ip->has_escapes = 1; +#if 0 + ip->lineno = obuf.lineno = 1; +#endif + + /* Scan the input, create the output. */ + cpp_scan_buffer (pfile); + +#if 0 + if (indepth != odepth) + abort (); +#endif + + CPP_NUL_TERMINATE (pfile); +} + + +static void +adjust_position (buf, limit, linep, colp) + U_CHAR *buf; + U_CHAR *limit; + long *linep; + long *colp; +{ + while (buf < limit) + { + U_CHAR ch = *buf++; + if (ch == '\n') + (*linep)++, (*colp) = 1; + else + (*colp)++; + } +} + +/* Move line_base forward, updating lineno and colno. */ + +static void +update_position (pbuf) + register cpp_buffer *pbuf; +{ + unsigned char *old_pos = pbuf->buf + pbuf->line_base; + unsigned char *new_pos = pbuf->cur; + register struct parse_marker *mark; + for (mark = pbuf->marks; mark != NULL; mark = mark->next) + { + if (pbuf->buf + mark->position < new_pos) + new_pos = pbuf->buf + mark->position; + } + pbuf->line_base += new_pos - old_pos; + adjust_position (old_pos, new_pos, &pbuf->lineno, &pbuf->colno); +} + +void +cpp_buf_line_and_col (pbuf, linep, colp) + register cpp_buffer *pbuf; + long *linep, *colp; +{ + long dummy; + if (colp == NULL) + colp = &dummy; + if (pbuf) + { + *linep = pbuf->lineno; + *colp = pbuf->colno; + adjust_position (pbuf->buf + pbuf->line_base, pbuf->cur, linep, colp); + } + else + { + *linep = 0; + *colp = 0; + } +} + +/* Return the cpp_buffer that corresponds to a file (not a macro). */ + +cpp_buffer * +cpp_file_buffer (pfile) + cpp_reader *pfile; +{ + cpp_buffer *ip = CPP_BUFFER (pfile); + + for ( ; ip != CPP_NULL_BUFFER (pfile); ip = CPP_PREV_BUFFER (ip)) + if (ip->fname != NULL) + return ip; + return NULL; +} + +static long +count_newlines (buf, limit) + register U_CHAR *buf; + register U_CHAR *limit; +{ + register long count = 0; + while (buf < limit) + { + U_CHAR ch = *buf++; + if (ch == '\n') + count++; + } + return count; +} + +/* + * write out a #line command, for instance, after an #include file. + * If CONDITIONAL is nonzero, we can omit the #line if it would + * appear to be a no-op, and we can output a few newlines instead + * if we want to increase the line number by a small amount. + * FILE_CHANGE says whether we are entering a file, leaving, or neither. + */ + +static void +output_line_command (pfile, conditional, file_change) + cpp_reader *pfile; + int conditional; + enum file_change_code file_change; +{ + long line, col; + cpp_buffer *ip = CPP_BUFFER (pfile); + + if (ip->fname == NULL) + return; + + update_position (ip); + + if (CPP_OPTIONS (pfile)->no_line_commands + || CPP_OPTIONS (pfile)->no_output) + return; + + line = CPP_BUFFER (pfile)->lineno; + col = CPP_BUFFER (pfile)->colno; + adjust_position (CPP_LINE_BASE (ip), ip->cur, &line, &col); + + if (CPP_OPTIONS (pfile)->no_line_commands) + return; + + if (conditional) { + if (line == pfile->lineno) + return; + + /* If the inherited line number is a little too small, + output some newlines instead of a #line command. */ + if (line > pfile->lineno && line < pfile->lineno + 8) { + CPP_RESERVE (pfile, 20); + while (line > pfile->lineno) { + CPP_PUTC_Q (pfile, '\n'); + pfile->lineno++; + } + return; + } + } + +#if 0 + /* Don't output a line number of 0 if we can help it. */ + if (ip->lineno == 0 && ip->bufp - ip->buf < ip->length + && *ip->bufp == '\n') { + ip->lineno++; + ip->bufp++; + } +#endif + + CPP_RESERVE (pfile, 4 * strlen (ip->nominal_fname) + 50); + { +#ifdef OUTPUT_LINE_COMMANDS + static char sharp_line[] = "#line "; +#else + static char sharp_line[] = "# "; +#endif + CPP_PUTS_Q (pfile, sharp_line, sizeof(sharp_line)-1); + } + + sprintf ((char *) CPP_PWRITTEN (pfile), "%ld ", line); + CPP_ADJUST_WRITTEN (pfile, strlen (CPP_PWRITTEN (pfile))); + + quote_string (pfile, ip->nominal_fname); + if (file_change != same_file) { + CPP_PUTC_Q (pfile, ' '); + CPP_PUTC_Q (pfile, file_change == enter_file ? '1' : '2'); + } + /* Tell cc1 if following text comes from a system header file. */ + if (ip->system_header_p) { + CPP_PUTC_Q (pfile, ' '); + CPP_PUTC_Q (pfile, '3'); + } +#ifndef NO_IMPLICIT_EXTERN_C + /* Tell cc1plus if following text should be treated as C. */ + if (ip->system_header_p == 2 && CPP_OPTIONS (pfile)->cplusplus) { + CPP_PUTC_Q (pfile, ' '); + CPP_PUTC_Q (pfile, '4'); + } +#endif + CPP_PUTC_Q (pfile, '\n'); + pfile->lineno = line; +} + +/* + * Parse a macro argument and append the info on PFILE's token_buffer. + * REST_ARGS means to absorb the rest of the args. + * Return nonzero to indicate a syntax error. + */ + +static enum cpp_token +macarg (pfile, rest_args) + cpp_reader *pfile; + int rest_args; +{ + int paren = 0; + enum cpp_token token; + char save_put_out_comments = CPP_OPTIONS (pfile)->put_out_comments; + CPP_OPTIONS (pfile)->put_out_comments = 0; + + /* Try to parse as much of the argument as exists at this + input stack level. */ + pfile->no_macro_expand++; + for (;;) + { + token = cpp_get_token (pfile); + switch (token) + { + case CPP_EOF: + goto done; + case CPP_POP: + /* If we've hit end of file, it's an error (reported by caller). + Ditto if it's the end of cpp_expand_to_buffer text. + If we've hit end of macro, just continue. */ + if (! CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile))) + goto done; + break; + case CPP_LPAREN: + paren++; + break; + case CPP_RPAREN: + if (--paren < 0) + goto found; + break; + case CPP_COMMA: + /* if we've returned to lowest level and + we aren't absorbing all args */ + if (paren == 0 && rest_args == 0) + goto found; + break; + found: + /* Remove ',' or ')' from argument buffer. */ + CPP_ADJUST_WRITTEN (pfile, -1); + goto done; + default: ; + } + } + + done: + CPP_OPTIONS (pfile)->put_out_comments = save_put_out_comments; + pfile->no_macro_expand--; + + return token; +} + +/* Turn newlines to spaces in the string of length LENGTH at START, + except inside of string constants. + The string is copied into itself with its beginning staying fixed. */ + +static int +change_newlines (start, length) + U_CHAR *start; + int length; +{ + register U_CHAR *ibp; + register U_CHAR *obp; + register U_CHAR *limit; + register int c; + + ibp = start; + limit = start + length; + obp = start; + + while (ibp < limit) { + *obp++ = c = *ibp++; + switch (c) { + + case '\'': + case '\"': + /* Notice and skip strings, so that we don't delete newlines in them. */ + { + int quotec = c; + while (ibp < limit) { + *obp++ = c = *ibp++; + if (c == quotec) + break; + if (c == '\n' && quotec == '\'') + break; + } + } + break; + } + } + + return obp - start; +} + + +static struct tm * +timestamp (pfile) + cpp_reader *pfile; +{ + if (!pfile->timebuf) { + time_t t = time ((time_t *) 0); + pfile->timebuf = localtime (&t); + } + return pfile->timebuf; +} + +static char *monthnames[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + }; + +/* + * expand things like __FILE__. Place the expansion into the output + * buffer *without* rescanning. + */ + +static void +special_symbol (hp, pfile) + HASHNODE *hp; + cpp_reader *pfile; +{ + char *buf; + int len; + int true_indepth; + cpp_buffer *ip = NULL; + struct tm *timebuf; + + int paren = 0; /* For special `defined' keyword */ + +#if 0 + if (pcp_outfile && pcp_inside_if + && hp->type != T_SPEC_DEFINED && hp->type != T_CONST) + cpp_error (pfile, + "Predefined macro `%s' used inside `#if' during precompilation", + hp->name); +#endif + + for (ip = CPP_BUFFER (pfile); ; ip = CPP_PREV_BUFFER (ip)) + { + if (ip == CPP_NULL_BUFFER (pfile)) + { + cpp_error (pfile, "cccp error: not in any file?!"); + return; /* the show must go on */ + } + if (ip->fname != NULL) + break; + } + + switch (hp->type) + { + case T_FILE: + case T_BASE_FILE: + { + char *string; + if (hp->type == T_BASE_FILE) + { + while (CPP_PREV_BUFFER (ip) != CPP_NULL_BUFFER (pfile)) + ip = CPP_PREV_BUFFER (ip); + } + string = ip->nominal_fname; + + if (!string) + string = ""; + CPP_RESERVE (pfile, 3 + 4 * strlen (string)); + quote_string (pfile, string); + return; + } + + case T_INCLUDE_LEVEL: + true_indepth = 0; + ip = CPP_BUFFER (pfile); + for (; ip != CPP_NULL_BUFFER (pfile); ip = CPP_PREV_BUFFER (ip)) + if (ip->fname != NULL) + true_indepth++; + + buf = (char *) alloca (8); /* Eight bytes ought to be more than enough */ + sprintf (buf, "%d", true_indepth - 1); + break; + + case T_VERSION: + buf = (char *) alloca (3 + strlen (version_string)); + sprintf (buf, "\"%s\"", version_string); + break; + +#ifndef NO_BUILTIN_SIZE_TYPE + case T_SIZE_TYPE: + buf = SIZE_TYPE; + break; +#endif + +#ifndef NO_BUILTIN_PTRDIFF_TYPE + case T_PTRDIFF_TYPE: + buf = PTRDIFF_TYPE; + break; +#endif + +/* CYGNUS LOCAL vmakarov */ +#ifndef NO_BUILTIN_WCHAR_TYPE +/* END CYGNUS LOCAL */ + case T_WCHAR_TYPE: + buf = CPP_WCHAR_TYPE (pfile); + break; +/* CYGNUS LOCAL vmakarov */ +#endif +/* END CYGNUS LOCAL */ + + case T_USER_LABEL_PREFIX_TYPE: + buf = user_label_prefix; + break; + + case T_REGISTER_PREFIX_TYPE: + buf = REGISTER_PREFIX; + break; + + case T_CONST: + buf = (char *) alloca (4 * sizeof (int)); + sprintf (buf, "%d", hp->value.ival); +#ifdef STDC_0_IN_SYSTEM_HEADERS + if (ip->system_header_p + && hp->length == 8 && bcmp (hp->name, "__STDC__", 8) == 0 + && ! cpp_lookup (pfile, (U_CHAR *) "__STRICT_ANSI__", -1, -1)) + strcpy (buf, "0"); +#endif +#if 0 + if (pcp_inside_if && pcp_outfile) + /* Output a precondition for this macro use */ + fprintf (pcp_outfile, "#define %s %d\n", hp->name, hp->value.ival); +#endif + break; + + case T_SPECLINE: + { + long line = ip->lineno; + long col = ip->colno; + adjust_position (CPP_LINE_BASE (ip), ip->cur, &line, &col); + + buf = (char *) alloca (10); + sprintf (buf, "%ld", line); + } + break; + + case T_DATE: + case T_TIME: + buf = (char *) alloca (20); + timebuf = timestamp (pfile); + if (hp->type == T_DATE) + sprintf (buf, "\"%s %2d %4d\"", monthnames[timebuf->tm_mon], + timebuf->tm_mday, timebuf->tm_year + 1900); + else + sprintf (buf, "\"%02d:%02d:%02d\"", timebuf->tm_hour, timebuf->tm_min, + timebuf->tm_sec); + break; + + case T_SPEC_DEFINED: + buf = " 0 "; /* Assume symbol is not defined */ + ip = CPP_BUFFER (pfile); + SKIP_WHITE_SPACE (ip->cur); + if (*ip->cur == '(') + { + paren++; + ip->cur++; /* Skip over the paren */ + SKIP_WHITE_SPACE (ip->cur); + } + + if (!is_idstart[*ip->cur]) + goto oops; + if (ip->cur[0] == 'L' && (ip->cur[1] == '\'' || ip->cur[1] == '"')) + goto oops; + if ((hp = cpp_lookup (pfile, ip->cur, -1, -1))) + { +#if 0 + if (pcp_outfile && pcp_inside_if + && (hp->type == T_CONST + || (hp->type == T_MACRO && hp->value.defn->predefined))) + /* Output a precondition for this macro use. */ + fprintf (pcp_outfile, "#define %s\n", hp->name); +#endif + buf = " 1 "; + } +#if 0 + else + if (pcp_outfile && pcp_inside_if) + { + /* Output a precondition for this macro use */ + U_CHAR *cp = ip->bufp; + fprintf (pcp_outfile, "#undef "); + while (is_idchar[*cp]) /* Ick! */ + fputc (*cp++, pcp_outfile); + putc ('\n', pcp_outfile); + } +#endif + while (is_idchar[*ip->cur]) + ++ip->cur; + SKIP_WHITE_SPACE (ip->cur); + if (paren) + { + if (*ip->cur != ')') + goto oops; + ++ip->cur; + } + break; + + oops: + + cpp_error (pfile, "`defined' without an identifier"); + break; + + default: + cpp_error (pfile, "cccp error: invalid special hash type"); /* time for gdb */ + abort (); + } + len = strlen (buf); + CPP_RESERVE (pfile, len + 1); + CPP_PUTS_Q (pfile, buf, len); + CPP_NUL_TERMINATE_Q (pfile); + + return; +} + +/* Write out a #define command for the special named MACRO_NAME + to PFILE's token_buffer. */ + +static void +dump_special_to_buffer (pfile, macro_name) + cpp_reader *pfile; + char *macro_name; +{ + static char define_directive[] = "#define "; + int macro_name_length = strlen (macro_name); + output_line_command (pfile, 0, same_file); + CPP_RESERVE (pfile, sizeof(define_directive) + macro_name_length); + CPP_PUTS_Q (pfile, define_directive, sizeof(define_directive)-1); + CPP_PUTS_Q (pfile, macro_name, macro_name_length); + CPP_PUTC_Q (pfile, ' '); + cpp_expand_to_buffer (pfile, macro_name, macro_name_length); + CPP_PUTC (pfile, '\n'); +} + +/* Initialize the built-in macros. */ + +static void +initialize_builtins (pfile) + cpp_reader *pfile; +{ + install ((U_CHAR *)"__LINE__", -1, T_SPECLINE, 0, 0, -1); + install ((U_CHAR *)"__DATE__", -1, T_DATE, 0, 0, -1); + install ((U_CHAR *)"__FILE__", -1, T_FILE, 0, 0, -1); + install ((U_CHAR *)"__BASE_FILE__", -1, T_BASE_FILE, 0, 0, -1); + install ((U_CHAR *)"__INCLUDE_LEVEL__", -1, T_INCLUDE_LEVEL, 0, 0, -1); + install ((U_CHAR *)"__VERSION__", -1, T_VERSION, 0, 0, -1); +#ifndef NO_BUILTIN_SIZE_TYPE + install ((U_CHAR *)"__SIZE_TYPE__", -1, T_SIZE_TYPE, 0, 0, -1); +#endif +#ifndef NO_BUILTIN_PTRDIFF_TYPE + install ((U_CHAR *)"__PTRDIFF_TYPE__ ", -1, T_PTRDIFF_TYPE, 0, 0, -1); +#endif +/* CYGNUS LOCAL vmakarov */ +#ifndef NO_BUILTIN_WCHAR_TYPE +/* END CYGNUS LOCAL */ + install ((U_CHAR *)"__WCHAR_TYPE__", -1, T_WCHAR_TYPE, 0, 0, -1); +/* CYGNUS LOCAL vmakarov */ +#endif +/* END CYGNUS LOCAL */ + install ((U_CHAR *)"__USER_LABEL_PREFIX__", -1, T_USER_LABEL_PREFIX_TYPE, 0, 0, -1); + install ((U_CHAR *)"__REGISTER_PREFIX__", -1, T_REGISTER_PREFIX_TYPE, 0, 0, -1); + install ((U_CHAR *)"__TIME__", -1, T_TIME, 0, 0, -1); + if (!CPP_TRADITIONAL (pfile)) + install ((U_CHAR *)"__STDC__", -1, T_CONST, STDC_VALUE, 0, -1); + if (CPP_OPTIONS (pfile)->objc) + install ((U_CHAR *)"__OBJC__", -1, T_CONST, 1, 0, -1); +/* This is supplied using a -D by the compiler driver + so that it is present only when truly compiling with GNU C. */ +/* install ("__GNUC__", -1, T_CONST, 2, 0, -1); */ + + if (CPP_OPTIONS (pfile)->debug_output) + { + dump_special_to_buffer (pfile, "__BASE_FILE__"); + dump_special_to_buffer (pfile, "__VERSION__"); +#ifndef NO_BUILTIN_SIZE_TYPE + dump_special_to_buffer (pfile, "__SIZE_TYPE__"); +#endif +#ifndef NO_BUILTIN_PTRDIFF_TYPE + dump_special_to_buffer (pfile, "__PTRDIFF_TYPE__"); +#endif +/* CYGNUS LOCAL vmakarov */ +#ifndef NO_BUILTIN_WCHAR_TYPE +/* END CYGNUS LOCAL */ + dump_special_to_buffer (pfile, "__WCHAR_TYPE__"); +/* CYGNUS LOCAL vmakarov */ +#endif +/* END CYGNUS LOCAL */ + dump_special_to_buffer (pfile, "__DATE__"); + dump_special_to_buffer (pfile, "__TIME__"); + if (!CPP_TRADITIONAL (pfile)) + dump_special_to_buffer (pfile, "__STDC__"); + if (CPP_OPTIONS (pfile)->objc) + dump_special_to_buffer (pfile, "__OBJC__"); + } +} + +/* Return 1 iff a token ending in C1 followed directly by a token C2 + could cause mis-tokenization. */ + +static int +unsafe_chars (c1, c2) + int c1, c2; +{ + switch (c1) + { + case '+': case '-': + if (c2 == c1 || c2 == '=') + return 1; + goto letter; + case '.': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case 'e': case 'E': case 'p': case 'P': + if (c2 == '-' || c2 == '+') + return 1; /* could extend a pre-processing number */ + goto letter; + case 'L': + if (c2 == '\'' || c2 == '\"') + return 1; /* Could turn into L"xxx" or L'xxx'. */ + goto letter; + letter: + case '_': + case 'a': case 'b': case 'c': case 'd': case 'f': + case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': + case 'm': case 'n': case 'o': case 'q': case 'r': + case 's': case 't': case 'u': case 'v': case 'w': case 'x': + case 'y': case 'z': + case 'A': case 'B': case 'C': case 'D': case 'F': + case 'G': case 'H': case 'I': case 'J': case 'K': + case 'M': case 'N': case 'O': case 'Q': case 'R': + case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': + case 'Y': case 'Z': + /* We're in the middle of either a name or a pre-processing number. */ + return (is_idchar[c2] || c2 == '.'); + case '<': case '>': case '!': case '%': case '#': case ':': + case '^': case '&': case '|': case '*': case '/': case '=': + return (c2 == c1 || c2 == '='); + } + return 0; +} + +/* Expand a macro call. + HP points to the symbol that is the macro being called. + Put the result of expansion onto the input stack + so that subsequent input by our caller will use it. + + If macro wants arguments, caller has already verified that + an argument list follows; arguments come from the input stack. */ + +static void +macroexpand (pfile, hp) + cpp_reader *pfile; + HASHNODE *hp; +{ + int nargs; + DEFINITION *defn = hp->value.defn; + register U_CHAR *xbuf; + long start_line, start_column; + int xbuf_len; + struct argdata *args; + long old_written = CPP_WRITTEN (pfile); +#if 0 + int start_line = instack[indepth].lineno; +#endif + int rest_args, rest_zero; + register int i; + +#if 0 + CHECK_DEPTH (return;); +#endif + +#if 0 + /* This macro is being used inside a #if, which means it must be */ + /* recorded as a precondition. */ + if (pcp_inside_if && pcp_outfile && defn->predefined) + dump_single_macro (hp, pcp_outfile); +#endif + + pfile->output_escapes++; + cpp_buf_line_and_col (cpp_file_buffer (pfile), &start_line, &start_column); + + nargs = defn->nargs; + + if (nargs >= 0) + { + enum cpp_token token; + + args = (struct argdata *) alloca ((nargs + 1) * sizeof (struct argdata)); + + for (i = 0; i < nargs; i++) + { + args[i].raw = args[i].expanded = 0; + args[i].raw_length = 0; + args[i].expand_length = args[i].stringified_length = -1; + args[i].use_count = 0; + } + + /* Parse all the macro args that are supplied. I counts them. + The first NARGS args are stored in ARGS. + The rest are discarded. If rest_args is set then we assume + macarg absorbed the rest of the args. */ + i = 0; + rest_args = 0; + rest_args = 0; + FORWARD(1); /* Discard the open-parenthesis before the first arg. */ + do + { + if (rest_args) + continue; + if (i < nargs || (nargs == 0 && i == 0)) + { + /* if we are working on last arg which absorbs rest of args... */ + if (i == nargs - 1 && defn->rest_args) + rest_args = 1; + args[i].raw = CPP_WRITTEN (pfile); + token = macarg (pfile, rest_args); + args[i].raw_length = CPP_WRITTEN (pfile) - args[i].raw; + args[i].newlines = 0; /* FIXME */ + } + else + token = macarg (pfile, 0); + if (token == CPP_EOF || token == CPP_POP) + { + cpp_error_with_line (pfile, start_line, start_column, + "unterminated macro call"); + return; + } + i++; + } while (token == CPP_COMMA); + + /* If we got one arg but it was just whitespace, call that 0 args. */ + if (i == 1) + { + register U_CHAR *bp = ARG_BASE + args[0].raw; + register U_CHAR *lim = bp + args[0].raw_length; + /* cpp.texi says for foo ( ) we provide one argument. + However, if foo wants just 0 arguments, treat this as 0. */ + if (nargs == 0) + while (bp != lim && is_space[*bp]) bp++; + if (bp == lim) + i = 0; + } + + /* Don't output an error message if we have already output one for + a parse error above. */ + rest_zero = 0; + if (nargs == 0 && i > 0) + { + cpp_error (pfile, "arguments given to macro `%s'", hp->name); + } + else if (i < nargs) + { + /* traditional C allows foo() if foo wants one argument. */ + if (nargs == 1 && i == 0 && CPP_TRADITIONAL (pfile)) + ; + /* the rest args token is allowed to absorb 0 tokens */ + else if (i == nargs - 1 && defn->rest_args) + rest_zero = 1; + else if (i == 0) + cpp_error (pfile, "macro `%s' used without args", hp->name); + else if (i == 1) + cpp_error (pfile, "macro `%s' used with just one arg", hp->name); + else + cpp_error (pfile, "macro `%s' used with only %d args", + hp->name, i); + } + else if (i > nargs) + { + cpp_error (pfile, + "macro `%s' used with too many (%d) args", hp->name, i); + } + } + + /* If macro wants zero args, we parsed the arglist for checking only. + Read directly from the macro definition. */ + if (nargs <= 0) + { + xbuf = defn->expansion; + xbuf_len = defn->length; + } + else + { + register U_CHAR *exp = defn->expansion; + register int offset; /* offset in expansion, + copied a piece at a time */ + register int totlen; /* total amount of exp buffer filled so far */ + + register struct reflist *ap, *last_ap; + + /* Macro really takes args. Compute the expansion of this call. */ + + /* Compute length in characters of the macro's expansion. + Also count number of times each arg is used. */ + xbuf_len = defn->length; + for (ap = defn->pattern; ap != NULL; ap = ap->next) + { + if (ap->stringify) + { + register struct argdata *arg = &args[ap->argno]; + /* Stringify if it hasn't already been */ + if (arg->stringified_length < 0) + { + int arglen = arg->raw_length; + int escaped = 0; + int in_string = 0; + int c; + /* Initially need_space is -1. Otherwise, 1 means the + previous character was a space, but we suppressed it; + 0 means the previous character was a non-space. */ + int need_space = -1; + i = 0; + arg->stringified = CPP_WRITTEN (pfile); + if (!CPP_TRADITIONAL (pfile)) + CPP_PUTC (pfile, '\"'); /* insert beginning quote */ + for (; i < arglen; i++) + { + c = (ARG_BASE + arg->raw)[i]; + + if (! in_string) + { + /* Internal sequences of whitespace are replaced by + one space except within an string or char token.*/ + if (is_space[c]) + { + if (CPP_WRITTEN (pfile) > (unsigned)arg->stringified + && (CPP_PWRITTEN (pfile))[-1] == '@') + { + /* "@ " escape markers are removed */ + CPP_ADJUST_WRITTEN (pfile, -1); + continue; + } + if (need_space == 0) + need_space = 1; + continue; + } + else if (need_space > 0) + CPP_PUTC (pfile, ' '); + need_space = 0; + } + + if (escaped) + escaped = 0; + else + { + if (c == '\\') + escaped = 1; + if (in_string) + { + if (c == in_string) + in_string = 0; + } + else if (c == '\"' || c == '\'') + in_string = c; + } + + /* Escape these chars */ + if (c == '\"' || (in_string && c == '\\')) + CPP_PUTC (pfile, '\\'); + if (ISPRINT (c)) + CPP_PUTC (pfile, c); + else + { + CPP_RESERVE (pfile, 4); + sprintf ((char *)CPP_PWRITTEN (pfile), "\\%03o", + (unsigned int) c); + CPP_ADJUST_WRITTEN (pfile, 4); + } + } + if (!CPP_TRADITIONAL (pfile)) + CPP_PUTC (pfile, '\"'); /* insert ending quote */ + arg->stringified_length + = CPP_WRITTEN (pfile) - arg->stringified; + } + xbuf_len += args[ap->argno].stringified_length; + } + else if (ap->raw_before || ap->raw_after || CPP_TRADITIONAL (pfile)) + /* Add 4 for two newline-space markers to prevent + token concatenation. */ + xbuf_len += args[ap->argno].raw_length + 4; + else + { + /* We have an ordinary (expanded) occurrence of the arg. + So compute its expansion, if we have not already. */ + if (args[ap->argno].expand_length < 0) + { + args[ap->argno].expanded = CPP_WRITTEN (pfile); + cpp_expand_to_buffer (pfile, + ARG_BASE + args[ap->argno].raw, + args[ap->argno].raw_length); + + args[ap->argno].expand_length + = CPP_WRITTEN (pfile) - args[ap->argno].expanded; + } + + /* Add 4 for two newline-space markers to prevent + token concatenation. */ + xbuf_len += args[ap->argno].expand_length + 4; + } + if (args[ap->argno].use_count < 10) + args[ap->argno].use_count++; + } + + xbuf = (U_CHAR *) xmalloc (xbuf_len + 1); + + /* Generate in XBUF the complete expansion + with arguments substituted in. + TOTLEN is the total size generated so far. + OFFSET is the index in the definition + of where we are copying from. */ + offset = totlen = 0; + for (last_ap = NULL, ap = defn->pattern; ap != NULL; + last_ap = ap, ap = ap->next) + { + register struct argdata *arg = &args[ap->argno]; + int count_before = totlen; + + /* Add chars to XBUF. */ + for (i = 0; i < ap->nchars; i++, offset++) + xbuf[totlen++] = exp[offset]; + + /* If followed by an empty rest arg with concatenation, + delete the last run of nonwhite chars. */ + if (rest_zero && totlen > count_before + && ((ap->rest_args && ap->raw_before) + || (last_ap != NULL && last_ap->rest_args + && last_ap->raw_after))) + { + /* Delete final whitespace. */ + while (totlen > count_before && is_space[xbuf[totlen - 1]]) + totlen--; + + /* Delete the nonwhites before them. */ + while (totlen > count_before && ! is_space[xbuf[totlen - 1]]) + totlen--; + } + + if (ap->stringify != 0) + { + bcopy (ARG_BASE + arg->stringified, + xbuf + totlen, arg->stringified_length); + totlen += arg->stringified_length; + } + else if (ap->raw_before || ap->raw_after || CPP_TRADITIONAL (pfile)) + { + U_CHAR *p1 = ARG_BASE + arg->raw; + U_CHAR *l1 = p1 + arg->raw_length; + if (ap->raw_before) + { + while (p1 != l1 && is_space[*p1]) p1++; + while (p1 != l1 && is_idchar[*p1]) + xbuf[totlen++] = *p1++; + } + if (ap->raw_after) + { + /* Arg is concatenated after: delete trailing whitespace, + whitespace markers, and no-reexpansion markers. */ + while (p1 != l1) + { + if (is_space[l1[-1]]) l1--; + else if (l1[-1] == '@') + { + U_CHAR *p2 = l1 - 1; + /* If whitespace is preceded by an odd number + of `@' signs, the last `@' was a whitespace + marker; drop it too. */ + while (p2 != p1 && p2[0] == '@') p2--; + if ((l1 - p2) & 1) + l1--; + break; + } + else if (l1[-1] == '-') + { + U_CHAR *p2 = l1 - 1; + /* If a `-' is preceded by an odd number of + `@' signs then it and the last `@' are + a no-reexpansion marker. */ + while (p2 != p1 && p2[0] == '@') p2--; + if ((l1 - p2) & 1) + l1 -= 2; + else + break; + } + else break; + } + } + + /* Delete any no-reexpansion marker that precedes + an identifier at the beginning of the argument. */ + if (p1[0] == '@' && p1[1] == '-') + p1 += 2; + + bcopy (p1, xbuf + totlen, l1 - p1); + totlen += l1 - p1; + } + else + { + U_CHAR *expanded = ARG_BASE + arg->expanded; + if (!ap->raw_before && totlen > 0 && arg->expand_length + && !CPP_TRADITIONAL(pfile) + && unsafe_chars (xbuf[totlen-1], expanded[0])) + { + xbuf[totlen++] = '@'; + xbuf[totlen++] = ' '; + } + + bcopy (expanded, xbuf + totlen, arg->expand_length); + totlen += arg->expand_length; + + if (!ap->raw_after && totlen > 0 && offset < defn->length + && !CPP_TRADITIONAL(pfile) + && unsafe_chars (xbuf[totlen-1], exp[offset])) + { + xbuf[totlen++] = '@'; + xbuf[totlen++] = ' '; + } + + /* If a macro argument with newlines is used multiple times, + then only expand the newlines once. This avoids creating + output lines which don't correspond to any input line, + which confuses gdb and gcov. */ + if (arg->use_count > 1 && arg->newlines > 0) + { + /* Don't bother doing change_newlines for subsequent + uses of arg. */ + arg->use_count = 1; + arg->expand_length + = change_newlines (expanded, arg->expand_length); + } + } + + if (totlen > xbuf_len) + abort (); + } + + /* if there is anything left of the definition + after handling the arg list, copy that in too. */ + + for (i = offset; i < defn->length; i++) + { + /* if we've reached the end of the macro */ + if (exp[i] == ')') + rest_zero = 0; + if (! (rest_zero && last_ap != NULL && last_ap->rest_args + && last_ap->raw_after)) + xbuf[totlen++] = exp[i]; + } + + xbuf[totlen] = 0; + xbuf_len = totlen; + + } + + pfile->output_escapes--; + + /* Now put the expansion on the input stack + so our caller will commence reading from it. */ + push_macro_expansion (pfile, xbuf, xbuf_len, hp); + CPP_BUFFER (pfile)->has_escapes = 1; + + /* Pop the space we've used in the token_buffer for argument expansion. */ + CPP_SET_WRITTEN (pfile, old_written); + + /* Recursive macro use sometimes works traditionally. + #define foo(x,y) bar (x (y,0), y) + foo (foo, baz) */ + + if (!CPP_TRADITIONAL (pfile)) + hp->type = T_DISABLED; +} + +static void +push_macro_expansion (pfile, xbuf, xbuf_len, hp) + cpp_reader *pfile; + register U_CHAR *xbuf; + int xbuf_len; + HASHNODE *hp; +{ + register cpp_buffer *mbuf = cpp_push_buffer (pfile, xbuf, xbuf_len); + if (mbuf == NULL) + return; + mbuf->cleanup = macro_cleanup; + mbuf->data = hp; + + /* The first chars of the expansion should be a "@ " added by + collect_expansion. This is to prevent accidental token-pasting + between the text preceding the macro invocation, and the macro + expansion text. + + We would like to avoid adding unneeded spaces (for the sake of + tools that use cpp, such as imake). In some common cases we can + tell that it is safe to omit the space. + + The character before the macro invocation cannot have been an + idchar (or else it would have been pasted with the idchars of + the macro name). Therefore, if the first non-space character + of the expansion is an idchar, we do not need the extra space + to prevent token pasting. + + Also, we don't need the extra space if the first char is '(', + or some other (less common) characters. */ + + if (xbuf[0] == '@' && xbuf[1] == ' ' + && (is_idchar[xbuf[2]] || xbuf[2] == '(' || xbuf[2] == '\'' + || xbuf[2] == '\"')) + mbuf->cur += 2; +} + +/* Like cpp_get_token, except that it does not read past end-of-line. + Also, horizontal space is skipped, and macros are popped. */ + +static enum cpp_token +get_directive_token (pfile) + cpp_reader *pfile; +{ + for (;;) + { + long old_written = CPP_WRITTEN (pfile); + enum cpp_token token; + cpp_skip_hspace (pfile); + if (PEEKC () == '\n') + return CPP_VSPACE; + token = cpp_get_token (pfile); + switch (token) + { + case CPP_POP: + if (! CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile))) + return token; + /* ... else fall though ... */ + case CPP_HSPACE: case CPP_COMMENT: + CPP_SET_WRITTEN (pfile, old_written); + break; + default: + return token; + } + } +} + +/* Handle #include and #import. + This function expects to see "fname" or on the input. + + The input is normally in part of the output_buffer following + CPP_WRITTEN, and will get overwritten by output_line_command. + I.e. in input file specification has been popped by handle_directive. + This is safe. */ + +static int +do_include (pfile, keyword) + cpp_reader *pfile; + struct directive *keyword; +{ + int importing = (keyword->type == T_IMPORT); + int skip_dirs = (keyword->type == T_INCLUDE_NEXT); + int angle_brackets = 0; /* 0 for "...", 1 for <...> */ + int before; /* included before? */ + long flen; + char *fbeg, *fend; + cpp_buffer *fp; + + enum cpp_token token; + + /* Chain of dirs to search */ + struct include_hash *ihash; + struct file_name_list *search_start; + + long old_written = CPP_WRITTEN (pfile); + + int fd; + + if (CPP_PEDANTIC (pfile) && !CPP_BUFFER (pfile)->system_header_p) + { + if (importing) + cpp_pedwarn (pfile, "ANSI C does not allow `#import'"); + if (skip_dirs) + cpp_pedwarn (pfile, "ANSI C does not allow `#include_next'"); + } + + if (importing && CPP_OPTIONS (pfile)->warn_import + && !CPP_OPTIONS (pfile)->inhibit_warnings + && !CPP_BUFFER (pfile)->system_header_p && !pfile->import_warning) + { + pfile->import_warning = 1; + cpp_warning (pfile, "`#import' is obsolete, use an #ifdef wrapper in the header file"); + } + + pfile->parsing_include_directive++; + token = get_directive_token (pfile); + pfile->parsing_include_directive--; + + if (token == CPP_STRING) + { + fbeg = pfile->token_buffer + old_written + 1; + fend = CPP_PWRITTEN (pfile) - 1; + *fend = '\0'; + if (fbeg[-1] == '<') + angle_brackets = 1; + } +#ifdef VMS + else if (token == CPP_NAME) + { + /* Support '#include xyz' like VAX-C to allow for easy use of + * all the decwindow include files. It defaults to '#include + * ' and generates a warning. */ + cpp_warning (pfile, + "VAX-C-style include specification found, use '#include ' !"); + angle_brackets = 1; + + /* Append the missing `.h' to the name. */ + CPP_PUTS (pfile, ".h", 3) + CPP_NUL_TERMINATE_Q (pfile); + + fbeg = pfile->token_buffer + old_written; + fend = CPP_PWRITTEN (pfile); + } +#endif + else + { + cpp_error (pfile, + "`#%s' expects \"FILENAME\" or ", keyword->name); + CPP_SET_WRITTEN (pfile, old_written); + skip_rest_of_line (pfile); + return 0; + } + + token = get_directive_token (pfile); + if (token != CPP_VSPACE) + { + cpp_error (pfile, "junk at end of `#include'"); + skip_rest_of_line (pfile); + } + + CPP_SET_WRITTEN (pfile, old_written); + + flen = fend - fbeg; + + if (flen == 0) + { + cpp_error (pfile, "empty file name in `#%s'", keyword->name); + return 0; + } + + search_start = 0; + + for (fp = CPP_BUFFER (pfile); + fp != CPP_NULL_BUFFER (pfile); + fp = CPP_PREV_BUFFER (fp)) + if (fp->fname != NULL) + break; + + if (fp == CPP_NULL_BUFFER (pfile)) + { + cpp_fatal (pfile, "cpp internal error: fp == NULL_BUFFER in do_include"); + return 1; + } + + /* For #include_next, skip in the search path past the dir in which the + containing file was found. Treat files specified using an absolute path + as if there are no more directories to search. Treat the primary source + file like any other included source, but generate a warning. */ + if (skip_dirs && CPP_PREV_BUFFER(fp) != CPP_NULL_BUFFER (pfile)) + { + if (fp->ihash->foundhere != ABSOLUTE_PATH) + search_start = fp->ihash->foundhere->next; + } + else + { + if (skip_dirs) + cpp_warning (pfile, "#include_next in primary source file"); + + if (angle_brackets) + search_start = CPP_OPTIONS (pfile)->bracket_include; + else + { + if (!CPP_OPTIONS (pfile)->ignore_srcdir) + { + if (fp) + search_start = fp->actual_dir; + } + else + search_start = CPP_OPTIONS (pfile)->quote_include; + } + } + + if (!search_start) + { + cpp_error (pfile, "No include path in which to find %s", fbeg); + return 0; + } + + fd = find_include_file (pfile, fbeg, search_start, &ihash, &before); + + if (fd == -2) + return 0; + + if (fd == -1) + { + if (CPP_OPTIONS (pfile)->print_deps_missing_files + && CPP_PRINT_DEPS (pfile) > (angle_brackets || + (pfile->system_include_depth > 0))) + { + if (!angle_brackets) + deps_output (pfile, fbeg, ' '); + else + { + char *p; + struct file_name_list *ptr; + /* If requested as a system header, assume it belongs in + the first system header directory. */ + if (CPP_OPTIONS (pfile)->bracket_include) + ptr = CPP_OPTIONS (pfile)->bracket_include; + else + ptr = CPP_OPTIONS (pfile)->quote_include; + + p = (char *) alloca (strlen (ptr->name) + + strlen (fbeg) + 2); + if (*ptr->name != '\0') + { + strcpy (p, ptr->name); + strcat (p, "/"); + } + strcat (p, fbeg); + deps_output (pfile, p, ' '); + } + } + /* If -M was specified, and this header file won't be added to + the dependency list, then don't count this as an error, + because we can still produce correct output. Otherwise, we + can't produce correct output, because there may be + dependencies we need inside the missing file, and we don't + know what directory this missing file exists in. */ + else if (CPP_PRINT_DEPS (pfile) + && (CPP_PRINT_DEPS (pfile) + <= (angle_brackets || (pfile->system_include_depth > 0)))) + cpp_warning (pfile, "No include path in which to find %s", fbeg); + else + cpp_error_from_errno (pfile, fbeg); + + return 0; + } + + /* For -M, add the file to the dependencies on its first inclusion. */ + if (!before && (CPP_PRINT_DEPS (pfile) + > (angle_brackets || (pfile->system_include_depth > 0)))) + deps_output (pfile, ihash->name, ' '); + + /* Handle -H option. */ + if (CPP_OPTIONS(pfile)->print_include_names) + { + fp = CPP_BUFFER (pfile); + while ((fp = CPP_PREV_BUFFER (fp)) != CPP_NULL_BUFFER (pfile)) + putc ('.', stderr); + fprintf (stderr, " %s\n", ihash->name); + } + + /* Actually process the file */ + + if (importing) + ihash->control_macro = ""; + + if (cpp_push_buffer (pfile, NULL, 0) == NULL) + { + close (fd); + return 0; + } + + if (angle_brackets) + pfile->system_include_depth++; /* Decremented in file_cleanup. */ + + if (finclude (pfile, fd, ihash)) + { + output_line_command (pfile, 0, enter_file); + pfile->only_seen_white = 2; + } + + return 0; +} + + +/* Convert a character string literal into a nul-terminated string. + The input string is [IN ... LIMIT). + The result is placed in RESULT. RESULT can be the same as IN. + The value returned in the end of the string written to RESULT, + or NULL on error. */ + +static U_CHAR * +convert_string (pfile, result, in, limit, handle_escapes) + cpp_reader *pfile; + register U_CHAR *result, *in, *limit; + int handle_escapes; +{ + U_CHAR c; + c = *in++; + if (c != '\"') + return NULL; + while (in < limit) + { + U_CHAR c = *in++; + switch (c) + { + case '\0': + return NULL; + case '\"': + limit = in; + break; + case '\\': + if (handle_escapes) + { + char *bpc = (char *) in; + int i = (U_CHAR) cpp_parse_escape (pfile, &bpc, 0x00ff); + in = (U_CHAR *) bpc; + if (i >= 0) + *result++ = (U_CHAR)c; + break; + } + /* else fall through */ + default: + *result++ = c; + } + } + *result = 0; + return result; +} + +/* + * interpret #line command. Remembers previously seen fnames + * in its very own hash table. + */ +#define FNAME_HASHSIZE 37 + +static int +do_line (pfile, keyword) + cpp_reader *pfile; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + cpp_buffer *ip = CPP_BUFFER (pfile); + int new_lineno; + long old_written = CPP_WRITTEN (pfile); + enum file_change_code file_change = same_file; + enum cpp_token token; + + token = get_directive_token (pfile); + + if (token != CPP_NUMBER + || !ISDIGIT(pfile->token_buffer[old_written])) + { + cpp_error (pfile, "invalid format `#line' command"); + goto bad_line_directive; + } + + /* The Newline at the end of this line remains to be processed. + To put the next line at the specified line number, + we must store a line number now that is one less. */ + new_lineno = atoi ((char *)(pfile->token_buffer + old_written)) - 1; + CPP_SET_WRITTEN (pfile, old_written); + + /* NEW_LINENO is one less than the actual line number here. */ + if (CPP_PEDANTIC (pfile) && new_lineno < 0) + cpp_pedwarn (pfile, "line number out of range in `#line' command"); + +#if 0 /* #line 10"foo.c" is supposed to be allowed. */ + if (PEEKC() && !is_space[PEEKC()]) { + cpp_error (pfile, "invalid format `#line' command"); + goto bad_line_directive; + } +#endif + + token = get_directive_token (pfile); + + if (token == CPP_STRING) { + U_CHAR *fname = pfile->token_buffer + old_written; + U_CHAR *end_name; + static HASHNODE *fname_table[FNAME_HASHSIZE]; + HASHNODE *hp, **hash_bucket; + U_CHAR *p; + long num_start; + int fname_length; + + /* Turn the file name, which is a character string literal, + into a null-terminated string. Do this in place. */ + end_name = convert_string (pfile, fname, fname, CPP_PWRITTEN (pfile), 1); + if (end_name == NULL) + { + cpp_error (pfile, "invalid format `#line' command"); + goto bad_line_directive; + } + + fname_length = end_name - fname; + + num_start = CPP_WRITTEN (pfile); + token = get_directive_token (pfile); + if (token != CPP_VSPACE && token != CPP_EOF && token != CPP_POP) { + p = pfile->token_buffer + num_start; + if (CPP_PEDANTIC (pfile)) + cpp_pedwarn (pfile, "garbage at end of `#line' command"); + + if (token != CPP_NUMBER || *p < '0' || *p > '4' || p[1] != '\0') + { + cpp_error (pfile, "invalid format `#line' command"); + goto bad_line_directive; + } + if (*p == '1') + file_change = enter_file; + else if (*p == '2') + file_change = leave_file; + else if (*p == '3') + ip->system_header_p = 1; + else /* if (*p == '4') */ + ip->system_header_p = 2; + + CPP_SET_WRITTEN (pfile, num_start); + token = get_directive_token (pfile); + p = pfile->token_buffer + num_start; + if (token == CPP_NUMBER && p[1] == '\0' && (*p == '3' || *p== '4')) { + ip->system_header_p = *p == '3' ? 1 : 2; + token = get_directive_token (pfile); + } + if (token != CPP_VSPACE) { + cpp_error (pfile, "invalid format `#line' command"); + goto bad_line_directive; + } + } + + hash_bucket = &fname_table[hashf (fname, fname_length, FNAME_HASHSIZE)]; + for (hp = *hash_bucket; hp != NULL; hp = hp->next) + if (hp->length == fname_length + && strncmp (hp->value.cpval, fname, fname_length) == 0) { + ip->nominal_fname = hp->value.cpval; + break; + } + if (hp == 0) { + /* Didn't find it; cons up a new one. */ + hp = (HASHNODE *) xcalloc (1, sizeof (HASHNODE) + fname_length + 1); + hp->next = *hash_bucket; + *hash_bucket = hp; + + hp->length = fname_length; + ip->nominal_fname = hp->value.cpval = ((char *) hp) + sizeof (HASHNODE); + bcopy (fname, hp->value.cpval, fname_length); + } + } + else if (token != CPP_VSPACE && token != CPP_EOF) { + cpp_error (pfile, "invalid format `#line' command"); + goto bad_line_directive; + } + + ip->lineno = new_lineno; + bad_line_directive: + skip_rest_of_line (pfile); + CPP_SET_WRITTEN (pfile, old_written); + output_line_command (pfile, 0, file_change); + return 0; +} + +/* + * remove the definition of a symbol from the symbol table. + * according to un*x /lib/cpp, it is not an error to undef + * something that has no definitions, so it isn't one here either. + */ + +static int +do_undef (pfile, keyword) + cpp_reader *pfile; + struct directive *keyword; +{ + int sym_length; + HASHNODE *hp; + U_CHAR *buf, *name, *limit; + int c; + long here = CPP_WRITTEN (pfile); + enum cpp_token token; + + cpp_skip_hspace (pfile); + c = GETC(); + if (! is_idstart[c]) + { + cpp_error (pfile, "token after #undef is not an identifier"); + skip_rest_of_line (pfile); + return 1; + } + + parse_name (pfile, c); + buf = pfile->token_buffer + here; + limit = CPP_PWRITTEN(pfile); + + /* Copy out the token so we can pop the token buffer. */ + name = alloca (limit - buf + 1); + bcopy(buf, name, limit - buf); + name[limit - buf] = '\0'; + + token = get_directive_token (pfile); + if (token != CPP_VSPACE && token != CPP_POP) + { + cpp_pedwarn (pfile, "junk on line after #undef"); + skip_rest_of_line (pfile); + } + + CPP_SET_WRITTEN (pfile, here); + +#if 0 + /* If this is a precompiler run (with -pcp) pass thru #undef commands. */ + if (pcp_outfile && keyword) + pass_thru_directive (buf, limit, pfile, keyword); +#endif + + sym_length = check_macro_name (pfile, name, "macro"); + + while ((hp = cpp_lookup (pfile, name, sym_length, -1)) != NULL) + { + /* If we are generating additional info for debugging (with -g) we + need to pass through all effective #undef commands. */ + if (CPP_OPTIONS (pfile)->debug_output && keyword) + pass_thru_directive (name, name+sym_length, pfile, keyword); + if (hp->type != T_MACRO) + cpp_warning (pfile, "undefining `%s'", hp->name); + delete_macro (hp); + } + + return 0; +} + +/* Wrap do_undef for -U processing. */ +static void +cpp_undef (pfile, macro) + cpp_reader *pfile; + U_CHAR *macro; +{ + if (cpp_push_buffer (pfile, macro, strlen(macro))) + { + do_undef (pfile, NULL); + cpp_pop_buffer (pfile); + } +} + + +/* + * Report an error detected by the program we are processing. + * Use the text of the line in the error message. + * (We use error because it prints the filename & line#.) + */ + +static int +do_error (pfile, keyword) + cpp_reader *pfile; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + long here = CPP_WRITTEN (pfile); + U_CHAR *text; + copy_rest_of_line (pfile); + text = pfile->token_buffer + here; + SKIP_WHITE_SPACE(text); + + cpp_error (pfile, "#error %s", text); + CPP_SET_WRITTEN (pfile, here); + return 0; +} + +/* + * Report a warning detected by the program we are processing. + * Use the text of the line in the warning message, then continue. + */ + +static int +do_warning (pfile, keyword) + cpp_reader *pfile; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + U_CHAR *text; + long here = CPP_WRITTEN(pfile); + copy_rest_of_line (pfile); + text = pfile->token_buffer + here; + SKIP_WHITE_SPACE(text); + + if (CPP_PEDANTIC (pfile) && !CPP_BUFFER (pfile)->system_header_p) + cpp_pedwarn (pfile, "ANSI C does not allow `#warning'"); + + /* Use `pedwarn' not `warning', because #warning isn't in the C Standard; + if -pedantic-errors is given, #warning should cause an error. */ + cpp_pedwarn (pfile, "#warning %s", text); + CPP_SET_WRITTEN (pfile, here); + return 0; +} + +/* Report program identification. */ + +static int +do_ident (pfile, keyword) + cpp_reader *pfile; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + /* Allow #ident in system headers, since that's not user's fault. */ + if (CPP_PEDANTIC (pfile) && !CPP_BUFFER (pfile)->system_header_p) + cpp_pedwarn (pfile, "ANSI C does not allow `#ident'"); + + skip_rest_of_line (pfile); /* Correct? Appears to match cccp. */ + + return 0; +} + +/* Just check for some recognized pragmas that need validation here, + and leave the text in the token buffer to be output. */ + +static int +do_pragma (pfile, keyword) + cpp_reader *pfile; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + long here = CPP_WRITTEN (pfile); + U_CHAR *buf; + + copy_rest_of_line (pfile); + buf = pfile->token_buffer + here; + SKIP_WHITE_SPACE (buf); + + if (!strncmp (buf, "once", 4)) + { + cpp_buffer *ip = NULL; + + /* Allow #pragma once in system headers, since that's not the user's + fault. */ + if (!CPP_BUFFER (pfile)->system_header_p) + cpp_warning (pfile, "`#pragma once' is obsolete"); + + for (ip = CPP_BUFFER (pfile); ; ip = CPP_PREV_BUFFER (ip)) + { + if (ip == CPP_NULL_BUFFER (pfile)) + return 0; + if (ip->fname != NULL) + break; + } + + if (CPP_PREV_BUFFER (ip) == CPP_NULL_BUFFER (pfile)) + cpp_warning (pfile, "`#pragma once' outside include file"); + else + ip->ihash->control_macro = ""; /* never repeat */ + } + + if (!strncmp (buf, "implementation", 14)) + { + /* Be quiet about `#pragma implementation' for a file only if it hasn't + been included yet. */ + struct include_hash *ptr; + U_CHAR *p = buf + 14, *fname, *fcopy; + SKIP_WHITE_SPACE (p); + if (*p == '\n' || *p != '\"') + return 0; + + fname = p + 1; + p = (U_CHAR *) index (fname, '\"'); + + fcopy = alloca (p - fname + 1); + bcopy (fname, fcopy, p - fname); + fcopy[p-fname] = '\0'; + + ptr = include_hash (pfile, fcopy, 0); + if (ptr) + cpp_warning (pfile, + "`#pragma implementation' for `%s' appears after file is included", + fcopy); + } + + return 0; +} + +#ifdef SCCS_DIRECTIVE +/* Just ignore #sccs, on systems where we define it at all. */ + +static int +do_sccs (pfile, keyword) + cpp_reader *pfile; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + if (CPP_PEDANTIC (pfile)) + cpp_pedwarn (pfile, "ANSI C does not allow `#sccs'"); + skip_rest_of_line (pfile); + return 0; +} +#endif + +/* + * handle #if command by + * 1) inserting special `defined' keyword into the hash table + * that gets turned into 0 or 1 by special_symbol (thus, + * if the luser has a symbol called `defined' already, it won't + * work inside the #if command) + * 2) rescan the input into a temporary output buffer + * 3) pass the output buffer to the yacc parser and collect a value + * 4) clean up the mess left from steps 1 and 2. + * 5) call conditional_skip to skip til the next #endif (etc.), + * or not, depending on the value from step 3. + */ + +static int +do_if (pfile, keyword) + cpp_reader *pfile; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + HOST_WIDE_INT value = eval_if_expression (pfile); + conditional_skip (pfile, value == 0, T_IF, NULL_PTR); + return 0; +} + +/* + * handle a #elif directive by not changing if_stack either. + * see the comment above do_else. + */ + +static int +do_elif (pfile, keyword) + cpp_reader *pfile; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack) { + cpp_error (pfile, "`#elif' not within a conditional"); + return 0; + } else { + if (pfile->if_stack->type != T_IF && pfile->if_stack->type != T_ELIF) { + cpp_error (pfile, "`#elif' after `#else'"); +#if 0 + fprintf (stderr, " (matches line %d", pfile->if_stack->lineno); +#endif + if (pfile->if_stack->fname != NULL && CPP_BUFFER (pfile)->fname != NULL + && strcmp (pfile->if_stack->fname, + CPP_BUFFER (pfile)->nominal_fname) != 0) + fprintf (stderr, ", file %s", pfile->if_stack->fname); + fprintf (stderr, ")\n"); + } + pfile->if_stack->type = T_ELIF; + } + + if (pfile->if_stack->if_succeeded) + skip_if_group (pfile); + else { + HOST_WIDE_INT value = eval_if_expression (pfile); + if (value == 0) + skip_if_group (pfile); + else { + ++pfile->if_stack->if_succeeded; /* continue processing input */ + output_line_command (pfile, 1, same_file); + } + } + return 0; +} + +/* + * evaluate a #if expression in BUF, of length LENGTH, + * then parse the result as a C expression and return the value as an int. + */ + +static HOST_WIDE_INT +eval_if_expression (pfile) + cpp_reader *pfile; +{ + HASHNODE *save_defined; + HOST_WIDE_INT value; + long old_written = CPP_WRITTEN (pfile); + + save_defined = install ((U_CHAR *)"defined", -1, T_SPEC_DEFINED, 0, 0, -1); + pfile->pcp_inside_if = 1; + + value = cpp_parse_expr (pfile); + pfile->pcp_inside_if = 0; + delete_macro (save_defined); /* clean up special symbol */ + + CPP_SET_WRITTEN (pfile, old_written); /* Pop */ + + return value; +} + +/* + * routine to handle ifdef/ifndef. Try to look up the symbol, + * then do or don't skip to the #endif/#else/#elif depending + * on what directive is actually being processed. + */ + +static int +do_xifdef (pfile, keyword) + cpp_reader *pfile; + struct directive *keyword; +{ + int skip; + cpp_buffer *ip = CPP_BUFFER (pfile); + U_CHAR *ident; + int ident_length; + enum cpp_token token; + int start_of_file = 0; + U_CHAR *control_macro = 0; + int old_written = CPP_WRITTEN (pfile); + + /* Detect a #ifndef at start of file (not counting comments). */ + if (ip->fname != 0 && keyword->type == T_IFNDEF) + start_of_file = pfile->only_seen_white == 2; + + pfile->no_macro_expand++; + token = get_directive_token (pfile); + pfile->no_macro_expand--; + + ident = pfile->token_buffer + old_written; + ident_length = CPP_WRITTEN (pfile) - old_written; + CPP_SET_WRITTEN (pfile, old_written); /* Pop */ + + if (token == CPP_VSPACE || token == CPP_POP || token == CPP_EOF) + { + skip = (keyword->type == T_IFDEF); + if (! CPP_TRADITIONAL (pfile)) + cpp_pedwarn (pfile, "`#%s' with no argument", keyword->name); + } + else if (token == CPP_NAME) + { + HASHNODE *hp = cpp_lookup (pfile, ident, ident_length, -1); + skip = (hp == NULL) ^ (keyword->type == T_IFNDEF); + if (start_of_file && !skip) + { + control_macro = (U_CHAR *) xmalloc (ident_length + 1); + bcopy (ident, control_macro, ident_length + 1); + } + } + else + { + skip = (keyword->type == T_IFDEF); + if (! CPP_TRADITIONAL (pfile)) + cpp_error (pfile, "`#%s' with invalid argument", keyword->name); + } + + if (!CPP_TRADITIONAL (pfile)) + { int c; + cpp_skip_hspace (pfile); + c = PEEKC (); + if (c != EOF && c != '\n') + cpp_pedwarn (pfile, "garbage at end of `#%s' argument", keyword->name); + } + skip_rest_of_line (pfile); + +#if 0 + if (pcp_outfile) { + /* Output a precondition for this macro. */ + if (hp && hp->value.defn->predefined) + fprintf (pcp_outfile, "#define %s\n", hp->name); + else { + U_CHAR *cp = buf; + fprintf (pcp_outfile, "#undef "); + while (is_idchar[*cp]) /* Ick! */ + fputc (*cp++, pcp_outfile); + putc ('\n', pcp_outfile); + } +#endif + + conditional_skip (pfile, skip, T_IF, control_macro); + return 0; +} + +/* Push TYPE on stack; then, if SKIP is nonzero, skip ahead. + If this is a #ifndef starting at the beginning of a file, + CONTROL_MACRO is the macro name tested by the #ifndef. + Otherwise, CONTROL_MACRO is 0. */ + +static void +conditional_skip (pfile, skip, type, control_macro) + cpp_reader *pfile; + int skip; + enum node_type type; + U_CHAR *control_macro; +{ + IF_STACK_FRAME *temp; + + temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME)); + temp->fname = CPP_BUFFER (pfile)->nominal_fname; +#if 0 + temp->lineno = CPP_BUFFER (pfile)->lineno; +#endif + temp->next = pfile->if_stack; + temp->control_macro = control_macro; + pfile->if_stack = temp; + + pfile->if_stack->type = type; + + if (skip != 0) { + skip_if_group (pfile); + return; + } else { + ++pfile->if_stack->if_succeeded; + output_line_command (pfile, 1, same_file); + } +} + +/* Subroutine of skip_if_group. Examine one preprocessing directive and + return 0 if skipping should continue, 1 if it should halt. Also + adjusts the if_stack as appropriate. + The `#' has been read, but not the identifier. */ + +static int +consider_directive_while_skipping (pfile, stack) + cpp_reader *pfile; + IF_STACK_FRAME *stack; +{ + long ident_len, ident; + struct directive *kt; + IF_STACK_FRAME *temp; + + cpp_skip_hspace (pfile); + + ident = CPP_WRITTEN (pfile); + parse_name (pfile, GETC()); + ident_len = CPP_WRITTEN (pfile) - ident; + + CPP_SET_WRITTEN (pfile, ident); + + for (kt = directive_table; kt->length >= 0; kt++) + if (kt->length == ident_len + && strncmp (pfile->token_buffer + ident, kt->name, kt->length) == 0) + switch (kt->type) + { + case T_IF: + case T_IFDEF: + case T_IFNDEF: + temp = (IF_STACK_FRAME *) xmalloc (sizeof (IF_STACK_FRAME)); + temp->next = pfile->if_stack; + pfile->if_stack = temp; + temp->fname = CPP_BUFFER(pfile)->nominal_fname; + temp->type = kt->type; + return 0; + + case T_ELSE: + if (CPP_PEDANTIC (pfile) && pfile->if_stack != stack) + validate_else (pfile, "#else"); + /* fall through */ + case T_ELIF: + if (pfile->if_stack->type == T_ELSE) + cpp_error (pfile, "`%s' after `#else'", kt->name); + + if (pfile->if_stack == stack) + return 1; + else + { + pfile->if_stack->type = kt->type; + return 0; + } + + case T_ENDIF: + if (CPP_PEDANTIC (pfile) && pfile->if_stack != stack) + validate_else (pfile, "#endif"); + + if (pfile->if_stack == stack) + return 1; + + temp = pfile->if_stack; + pfile->if_stack = temp->next; + free (temp); + return 0; + + default: + return 0; + } + + /* Don't let erroneous code go by. */ + if (!CPP_OPTIONS (pfile)->lang_asm && CPP_PEDANTIC (pfile)) + cpp_pedwarn (pfile, "invalid preprocessor directive name"); + return 0; +} + +/* skip to #endif, #else, or #elif. adjust line numbers, etc. + * leaves input ptr at the sharp sign found. + */ +static void +skip_if_group (pfile) + cpp_reader *pfile; +{ + int c; + IF_STACK_FRAME *save_if_stack = pfile->if_stack; /* don't pop past here */ + U_CHAR *beg_of_line; + long old_written; + + if (CPP_OPTIONS (pfile)->output_conditionals) + { + CPP_PUTS (pfile, "#failed\n", 8); + pfile->lineno++; + output_line_command (pfile, 1, same_file); + } + + old_written = CPP_WRITTEN (pfile); + + for (;;) + { + beg_of_line = CPP_BUFFER (pfile)->cur; + + if (! CPP_TRADITIONAL (pfile)) + cpp_skip_hspace (pfile); + c = GETC(); + if (c == '\n') + { + if (CPP_OPTIONS (pfile)->output_conditionals) + CPP_PUTC (pfile, c); + continue; + } + else if (c == '#') + { + if (consider_directive_while_skipping (pfile, save_if_stack)) + break; + } + else if (c == EOF) + return; /* Caller will issue error. */ + + FORWARD(-1); + if (CPP_OPTIONS (pfile)->output_conditionals) + { + CPP_PUTS (pfile, beg_of_line, CPP_BUFFER (pfile)->cur - beg_of_line); + copy_rest_of_line (pfile); + } + else + { + copy_rest_of_line (pfile); + CPP_SET_WRITTEN (pfile, old_written); /* discard it */ + } + + c = GETC(); + if (c == EOF) + return; /* Caller will issue error. */ + else + { + /* \n */ + if (CPP_OPTIONS (pfile)->output_conditionals) + CPP_PUTC (pfile, c); + } + } + + /* Back up to the beginning of this line. Caller will process the + directive. */ + CPP_BUFFER (pfile)->cur = beg_of_line; + pfile->only_seen_white = 1; + if (CPP_OPTIONS (pfile)->output_conditionals) + { + CPP_PUTS (pfile, "#endfailed\n", 11); + pfile->lineno++; + } +} + +/* + * handle a #else directive. Do this by just continuing processing + * without changing if_stack ; this is so that the error message + * for missing #endif's etc. will point to the original #if. It + * is possible that something different would be better. + */ + +static int +do_else (pfile, keyword) + cpp_reader *pfile; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + cpp_buffer *ip = CPP_BUFFER (pfile); + + if (CPP_PEDANTIC (pfile)) + validate_else (pfile, "#else"); + skip_rest_of_line (pfile); + + if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack) { + cpp_error (pfile, "`#else' not within a conditional"); + return 0; + } else { + /* #ifndef can't have its special treatment for containing the whole file + if it has a #else clause. */ + pfile->if_stack->control_macro = 0; + + if (pfile->if_stack->type != T_IF && pfile->if_stack->type != T_ELIF) { + cpp_error (pfile, "`#else' after `#else'"); + fprintf (stderr, " (matches line %d", pfile->if_stack->lineno); + if (strcmp (pfile->if_stack->fname, ip->nominal_fname) != 0) + fprintf (stderr, ", file %s", pfile->if_stack->fname); + fprintf (stderr, ")\n"); + } + pfile->if_stack->type = T_ELSE; + } + + if (pfile->if_stack->if_succeeded) + skip_if_group (pfile); + else { + ++pfile->if_stack->if_succeeded; /* continue processing input */ + output_line_command (pfile, 1, same_file); + } + return 0; +} + +/* + * unstack after #endif command + */ + +static int +do_endif (pfile, keyword) + cpp_reader *pfile; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + if (CPP_PEDANTIC (pfile)) + validate_else (pfile, "#endif"); + skip_rest_of_line (pfile); + + if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack) + cpp_error (pfile, "unbalanced `#endif'"); + else + { + IF_STACK_FRAME *temp = pfile->if_stack; + pfile->if_stack = temp->next; + if (temp->control_macro != 0) + { + /* This #endif matched a #ifndef at the start of the file. + See if it is at the end of the file. */ + struct parse_marker start_mark; + int c; + + parse_set_mark (&start_mark, pfile); + + for (;;) + { + cpp_skip_hspace (pfile); + c = GETC (); + if (c != '\n') + break; + } + parse_goto_mark (&start_mark, pfile); + parse_clear_mark (&start_mark); + + if (c == EOF) + { + /* This #endif ends a #ifndef + that contains all of the file (aside from whitespace). + Arrange not to include the file again + if the macro that was tested is defined. */ + struct cpp_buffer *ip; + for (ip = CPP_BUFFER (pfile); ; ip = CPP_PREV_BUFFER (ip)) + if (ip->fname != NULL) + break; + ip->ihash->control_macro = temp->control_macro; + } + } + free (temp); + output_line_command (pfile, 1, same_file); + } + return 0; +} + +/* When an #else or #endif is found while skipping failed conditional, + if -pedantic was specified, this is called to warn about text after + the command name. P points to the first char after the command name. */ + +static void +validate_else (pfile, directive) + cpp_reader *pfile; + char *directive; +{ + int c; + cpp_skip_hspace (pfile); + c = PEEKC (); + if (c != EOF && c != '\n') + cpp_pedwarn (pfile, + "text following `%s' violates ANSI standard", directive); +} + +/* Get the next token, and add it to the text in pfile->token_buffer. + Return the kind of token we got. */ + +enum cpp_token +cpp_get_token (pfile) + cpp_reader *pfile; +{ + register int c, c2, c3; + long old_written; + long start_line, start_column; + enum cpp_token token; + struct cpp_options *opts = CPP_OPTIONS (pfile); + CPP_BUFFER (pfile)->prev = CPP_BUFFER (pfile)->cur; + get_next: + c = GETC(); + if (c == EOF) + { + handle_eof: + if (CPP_BUFFER (pfile)->seen_eof) + { + if (cpp_pop_buffer (pfile) != CPP_NULL_BUFFER (pfile)) + goto get_next; + else + return CPP_EOF; + } + else + { + cpp_buffer *next_buf + = CPP_PREV_BUFFER (CPP_BUFFER (pfile)); + CPP_BUFFER (pfile)->seen_eof = 1; + if (CPP_BUFFER (pfile)->nominal_fname + && next_buf != CPP_NULL_BUFFER (pfile)) + { + /* We're about to return from an #include file. + Emit #line information now (as part of the CPP_POP) result. + But the #line refers to the file we will pop to. */ + cpp_buffer *cur_buffer = CPP_BUFFER (pfile); + CPP_BUFFER (pfile) = next_buf; + pfile->input_stack_listing_current = 0; + output_line_command (pfile, 0, leave_file); + CPP_BUFFER (pfile) = cur_buffer; + } + return CPP_POP; + } + } + else + { + switch (c) + { + long newlines; + struct parse_marker start_mark; + case '/': + if (PEEKC () == '=') + goto op2; + if (opts->put_out_comments) + parse_set_mark (&start_mark, pfile); + newlines = 0; + cpp_buf_line_and_col (cpp_file_buffer (pfile), + &start_line, &start_column); + c = skip_comment (pfile, &newlines); + if (opts->put_out_comments && (c == '/' || c == EOF)) + parse_clear_mark (&start_mark); + if (c == '/') + goto randomchar; + if (c == EOF) + { + cpp_error_with_line (pfile, start_line, start_column, + "unterminated comment"); + goto handle_eof; + } + c = '/'; /* Initial letter of comment. */ + return_comment: + /* Comments are equivalent to spaces. + For -traditional, a comment is equivalent to nothing. */ + if (opts->put_out_comments) + { + cpp_buffer *pbuf = CPP_BUFFER (pfile); + U_CHAR *start = pbuf->buf + start_mark.position; + int len = pbuf->cur - start; + CPP_RESERVE(pfile, 1 + len); + CPP_PUTC_Q (pfile, c); + CPP_PUTS_Q (pfile, start, len); + pfile->lineno += newlines; + parse_clear_mark (&start_mark); + return CPP_COMMENT; + } + else if (CPP_TRADITIONAL (pfile)) + { + return CPP_COMMENT; + } + else + { +#if 0 + /* This may not work if cpp_get_token is called recursively, + since many places look for horizontal space. */ + if (newlines) + { + /* Copy the newlines into the output buffer, in order to + avoid the pain of a #line every time a multiline comment + is seen. */ + CPP_RESERVE(pfile, newlines); + while (--newlines >= 0) + { + CPP_PUTC_Q (pfile, '\n'); + pfile->lineno++; + } + return CPP_VSPACE; + } +#endif + CPP_RESERVE(pfile, 1); + CPP_PUTC_Q (pfile, ' '); + return CPP_HSPACE; + } +#if 0 + if (opts->for_lint) { + U_CHAR *argbp; + int cmdlen, arglen; + char *lintcmd = get_lintcmd (ibp, limit, &argbp, &arglen, &cmdlen); + + if (lintcmd != NULL) { + /* I believe it is always safe to emit this newline: */ + obp[-1] = '\n'; + bcopy ("#pragma lint ", (char *) obp, 13); + obp += 13; + bcopy (lintcmd, (char *) obp, cmdlen); + obp += cmdlen; + + if (arglen != 0) { + *(obp++) = ' '; + bcopy (argbp, (char *) obp, arglen); + obp += arglen; + } + + /* OK, now bring us back to the state we were in before we entered + this branch. We need #line because the newline for the pragma + could mess things up. */ + output_line_command (pfile, 0, same_file); + *(obp++) = ' '; /* just in case, if comments are copied thru */ + *(obp++) = '/'; + } + } +#endif + + case '#': +#if 0 + /* If this is expanding a macro definition, don't recognize + preprocessor directives. */ + if (ip->macro != 0) + goto randomchar; + /* If this is expand_into_temp_buffer, recognize them + only after an actual newline at this level, + not at the beginning of the input level. */ + if (ip->fname == 0 && beg_of_line == ip->buf) + goto randomchar; + if (ident_length) + goto specialchar; +#endif + + if (!pfile->only_seen_white) + goto randomchar; + if (handle_directive (pfile)) + return CPP_DIRECTIVE; + pfile->only_seen_white = 0; + return CPP_OTHER; + + case '\"': + case '\'': + /* A single quoted string is treated like a double -- some + programs (e.g., troff) are perverse this way */ + cpp_buf_line_and_col (cpp_file_buffer (pfile), + &start_line, &start_column); + old_written = CPP_WRITTEN (pfile); + string: + CPP_PUTC (pfile, c); + while (1) + { + int cc = GETC(); + if (cc == EOF) + { + if (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile))) + { + /* try harder: this string crosses a macro expansion + boundary. This can happen naturally if -traditional. + Otherwise, only -D can make a macro with an unmatched + quote. */ + cpp_buffer *next_buf + = CPP_PREV_BUFFER (CPP_BUFFER (pfile)); + (*CPP_BUFFER (pfile)->cleanup) + (CPP_BUFFER (pfile), pfile); + CPP_BUFFER (pfile) = next_buf; + continue; + } + if (!CPP_TRADITIONAL (pfile)) + { + cpp_error_with_line (pfile, start_line, start_column, + "unterminated string or character constant"); + if (pfile->multiline_string_line != start_line + && pfile->multiline_string_line != 0) + cpp_error_with_line (pfile, + pfile->multiline_string_line, -1, + "possible real start of unterminated constant"); + pfile->multiline_string_line = 0; + } + break; + } + CPP_PUTC (pfile, cc); + switch (cc) + { + case '\n': + /* Traditionally, end of line ends a string constant with + no error. So exit the loop and record the new line. */ + if (CPP_TRADITIONAL (pfile)) + goto while2end; + if (c == '\'') + { + cpp_error_with_line (pfile, start_line, start_column, + "unterminated character constant"); + goto while2end; + } + if (CPP_PEDANTIC (pfile) + && pfile->multiline_string_line == 0) + { + cpp_pedwarn_with_line (pfile, start_line, start_column, + "string constant runs past end of line"); + } + if (pfile->multiline_string_line == 0) + pfile->multiline_string_line = start_line; + break; + + case '\\': + cc = GETC(); + if (cc == '\n') + { + /* Backslash newline is replaced by nothing at all. */ + CPP_ADJUST_WRITTEN (pfile, -1); + pfile->lineno++; + } + else + { + /* ANSI stupidly requires that in \\ the second \ + is *not* prevented from combining with a newline. */ + NEWLINE_FIX1(cc); + if (cc != EOF) + CPP_PUTC (pfile, cc); + } + break; + + case '\"': + case '\'': + if (cc == c) + goto while2end; + break; + } + } + while2end: + pfile->lineno += count_newlines (pfile->token_buffer + old_written, + CPP_PWRITTEN (pfile)); + pfile->only_seen_white = 0; + return c == '\'' ? CPP_CHAR : CPP_STRING; + + case '$': + if (!opts->dollars_in_ident) + goto randomchar; + goto letter; + + case ':': + if (opts->cplusplus && PEEKC () == ':') + goto op2; + goto randomchar; + + case '&': + case '+': + case '|': + NEWLINE_FIX; + c2 = PEEKC (); + if (c2 == c || c2 == '=') + goto op2; + goto randomchar; + + case '*': + case '!': + case '%': + case '=': + case '^': + NEWLINE_FIX; + if (PEEKC () == '=') + goto op2; + goto randomchar; + + case '-': + NEWLINE_FIX; + c2 = PEEKC (); + if (c2 == '-' && opts->chill) + { + /* Chill style comment */ + if (opts->put_out_comments) + parse_set_mark (&start_mark, pfile); + FORWARD(1); /* Skip second '-'. */ + for (;;) + { + c = GETC (); + if (c == EOF) + break; + if (c == '\n') + { + /* Don't consider final '\n' to be part of comment. */ + FORWARD(-1); + break; + } + } + c = '-'; + goto return_comment; + } + if (c2 == '-' || c2 == '=' || c2 == '>') + goto op2; + goto randomchar; + + case '<': + if (pfile->parsing_include_directive) + { + for (;;) + { + CPP_PUTC (pfile, c); + if (c == '>') + break; + c = GETC (); + NEWLINE_FIX1 (c); + if (c == '\n' || c == EOF) + { + cpp_error (pfile, + "missing '>' in `#include '"); + break; + } + } + return CPP_STRING; + } + /* else fall through */ + case '>': + NEWLINE_FIX; + c2 = PEEKC (); + if (c2 == '=') + goto op2; + if (c2 != c) + goto randomchar; + FORWARD(1); + CPP_RESERVE (pfile, 4); + CPP_PUTC (pfile, c); + CPP_PUTC (pfile, c2); + NEWLINE_FIX; + c3 = PEEKC (); + if (c3 == '=') + CPP_PUTC_Q (pfile, GETC ()); + CPP_NUL_TERMINATE_Q (pfile); + pfile->only_seen_white = 0; + return CPP_OTHER; + + case '@': + if (CPP_BUFFER (pfile)->has_escapes) + { + c = GETC (); + if (c == '-') + { + if (pfile->output_escapes) + CPP_PUTS (pfile, "@-", 2); + parse_name (pfile, GETC ()); + return CPP_NAME; + } + else if (is_space [c]) + { + CPP_RESERVE (pfile, 2); + if (pfile->output_escapes) + CPP_PUTC_Q (pfile, '@'); + CPP_PUTC_Q (pfile, c); + return CPP_HSPACE; + } + } + if (pfile->output_escapes) + { + CPP_PUTS (pfile, "@@", 2); + return CPP_OTHER; + } + goto randomchar; + + case '.': + NEWLINE_FIX; + c2 = PEEKC (); + if (ISDIGIT(c2)) + { + CPP_RESERVE(pfile, 2); + CPP_PUTC_Q (pfile, '.'); + c = GETC (); + goto number; + } + /* FIXME - misses the case "..\\\n." */ + if (c2 == '.' && PEEKN(1) == '.') + { + CPP_RESERVE(pfile, 4); + CPP_PUTC_Q (pfile, '.'); + CPP_PUTC_Q (pfile, '.'); + CPP_PUTC_Q (pfile, '.'); + FORWARD (2); + CPP_NUL_TERMINATE_Q (pfile); + pfile->only_seen_white = 0; + return CPP_3DOTS; + } + goto randomchar; + + op2: + token = CPP_OTHER; + pfile->only_seen_white = 0; + op2any: + CPP_RESERVE(pfile, 3); + CPP_PUTC_Q (pfile, c); + CPP_PUTC_Q (pfile, GETC ()); + CPP_NUL_TERMINATE_Q (pfile); + return token; + + case 'L': + NEWLINE_FIX; + c2 = PEEKC (); + if ((c2 == '\'' || c2 == '\"') && !CPP_TRADITIONAL (pfile)) + { + CPP_PUTC (pfile, c); + c = GETC (); + goto string; + } + goto letter; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + number: + c2 = '.'; + for (;;) + { + CPP_RESERVE (pfile, 2); + CPP_PUTC_Q (pfile, c); + NEWLINE_FIX; + c = PEEKC (); + if (c == EOF) + break; + if (!is_idchar[c] && c != '.' + && ((c2 != 'e' && c2 != 'E' + && ((c2 != 'p' && c2 != 'P') || CPP_C89 (pfile))) + || (c != '+' && c != '-'))) + break; + FORWARD(1); + c2= c; + } + CPP_NUL_TERMINATE_Q (pfile); + pfile->only_seen_white = 0; + return CPP_NUMBER; + case 'b': case 'c': case 'd': case 'h': case 'o': + case 'B': case 'C': case 'D': case 'H': case 'O': + if (opts->chill && PEEKC () == '\'') + { + pfile->only_seen_white = 0; + CPP_RESERVE (pfile, 2); + CPP_PUTC_Q (pfile, c); + CPP_PUTC_Q (pfile, '\''); + FORWARD(1); + for (;;) + { + c = GETC(); + if (c == EOF) + goto chill_number_eof; + if (!is_idchar[c]) + { + if (c == '\\' && PEEKC() == '\n') + { + FORWARD(2); + continue; + } + break; + } + CPP_PUTC (pfile, c); + } + if (c == '\'') + { + CPP_RESERVE (pfile, 2); + CPP_PUTC_Q (pfile, c); + CPP_NUL_TERMINATE_Q (pfile); + return CPP_STRING; + } + else + { + FORWARD(-1); + chill_number_eof: + CPP_NUL_TERMINATE (pfile); + return CPP_NUMBER; + } + } + else + goto letter; + case '_': + case 'a': case 'e': case 'f': case 'g': case 'i': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'p': case 'q': + case 'r': case 's': case 't': case 'u': case 'v': case 'w': + case 'x': case 'y': case 'z': + case 'A': case 'E': case 'F': case 'G': case 'I': case 'J': + case 'K': case 'M': case 'N': case 'P': case 'Q': case 'R': + case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': + case 'Y': case 'Z': + letter: + { + HASHNODE *hp; + unsigned char *ident; + int before_name_written = CPP_WRITTEN (pfile); + int ident_len; + parse_name (pfile, c); + pfile->only_seen_white = 0; + if (pfile->no_macro_expand) + return CPP_NAME; + ident = pfile->token_buffer + before_name_written; + ident_len = CPP_PWRITTEN (pfile) - ident; + hp = cpp_lookup (pfile, ident, ident_len, -1); + if (!hp) + return CPP_NAME; + if (hp->type == T_DISABLED) + { + if (pfile->output_escapes) + { /* Return "@-IDENT", followed by '\0'. */ + int i; + CPP_RESERVE (pfile, 3); + ident = pfile->token_buffer + before_name_written; + CPP_ADJUST_WRITTEN (pfile, 2); + for (i = ident_len; i >= 0; i--) ident[i+2] = ident[i]; + ident[0] = '@'; + ident[1] = '-'; + } + return CPP_NAME; + } + + /* If macro wants an arglist, verify that a '(' follows. + first skip all whitespace, copying it to the output + after the macro name. Then, if there is no '(', + decide this is not a macro call and leave things that way. */ + if (hp->type == T_MACRO && hp->value.defn->nargs >= 0) + { + struct parse_marker macro_mark; + int is_macro_call, macbuf_whitespace = 0; + + parse_set_mark (¯o_mark, pfile); + for (;;) + { + cpp_skip_hspace (pfile); + c = PEEKC (); + is_macro_call = c == '('; + if (c != EOF) + { + if (c != '\n') + break; + FORWARD (1); + } + else + { + if (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile))) + { + if (macro_mark.position != + (CPP_BUFFER (pfile)->cur + - CPP_BUFFER (pfile)->buf)) + macbuf_whitespace = 1; + + parse_clear_mark (¯o_mark); + cpp_pop_buffer (pfile); + parse_set_mark (¯o_mark, pfile); + } + else + break; + } + } + if (!is_macro_call) + { + parse_goto_mark (¯o_mark, pfile); + if (macbuf_whitespace) + CPP_PUTC (pfile, ' '); + } + parse_clear_mark (¯o_mark); + if (!is_macro_call) + return CPP_NAME; + } + /* This is now known to be a macro call. */ + + /* it might not actually be a macro. */ + if (hp->type != T_MACRO) { + int xbuf_len; U_CHAR *xbuf; + CPP_SET_WRITTEN (pfile, before_name_written); + special_symbol (hp, pfile); + xbuf_len = CPP_WRITTEN (pfile) - before_name_written; + xbuf = (U_CHAR *) xmalloc (xbuf_len + 1); + CPP_SET_WRITTEN (pfile, before_name_written); + bcopy (CPP_PWRITTEN (pfile), xbuf, xbuf_len + 1); + push_macro_expansion (pfile, xbuf, xbuf_len, hp); + } + else + { + /* Expand the macro, reading arguments as needed, + and push the expansion on the input stack. */ + macroexpand (pfile, hp); + CPP_SET_WRITTEN (pfile, before_name_written); + } + + /* An extra "@ " is added to the end of a macro expansion + to prevent accidental token pasting. We prefer to avoid + unneeded extra spaces (for the sake of cpp-using tools like + imake). Here we remove the space if it is safe to do so. */ + if (pfile->buffer->rlimit - pfile->buffer->cur >= 3 + && pfile->buffer->rlimit[-2] == '@' + && pfile->buffer->rlimit[-1] == ' ') + { + int c1 = pfile->buffer->rlimit[-3]; + int c2 = CPP_BUF_PEEK (CPP_PREV_BUFFER (CPP_BUFFER (pfile))); + if (c2 == EOF || ! unsafe_chars (c1, c2)) + pfile->buffer->rlimit -= 2; + } + } + goto get_next; + + case ' ': case '\t': case '\v': case '\r': + for (;;) + { + CPP_PUTC (pfile, c); + c = PEEKC (); + if (c == EOF || !is_hor_space[c]) + break; + FORWARD(1); + } + return CPP_HSPACE; + + case '\\': + c2 = PEEKC (); + if (c2 != '\n') + goto randomchar; + token = CPP_HSPACE; + goto op2any; + + case '\n': + CPP_PUTC (pfile, c); + if (pfile->only_seen_white == 0) + pfile->only_seen_white = 1; + pfile->lineno++; + output_line_command (pfile, 1, same_file); + return CPP_VSPACE; + + case '(': token = CPP_LPAREN; goto char1; + case ')': token = CPP_RPAREN; goto char1; + case '{': token = CPP_LBRACE; goto char1; + case '}': token = CPP_RBRACE; goto char1; + case ',': token = CPP_COMMA; goto char1; + case ';': token = CPP_SEMICOLON; goto char1; + + randomchar: + default: + token = CPP_OTHER; + char1: + pfile->only_seen_white = 0; + CPP_PUTC (pfile, c); + return token; + } + } +} + +/* Like cpp_get_token, but skip spaces and comments. */ + +enum cpp_token +cpp_get_non_space_token (pfile) + cpp_reader *pfile; +{ + int old_written = CPP_WRITTEN (pfile); + for (;;) + { + enum cpp_token token = cpp_get_token (pfile); + if (token != CPP_COMMENT && token != CPP_POP + && token != CPP_HSPACE && token != CPP_VSPACE) + return token; + CPP_SET_WRITTEN (pfile, old_written); + } +} + +/* Parse an identifier starting with C. */ + +static int +parse_name (pfile, c) + cpp_reader *pfile; int c; +{ + for (;;) + { + if (! is_idchar[c]) + { + if (c == '\\' && PEEKC() == '\n') + { + FORWARD(2); + continue; + } + FORWARD (-1); + break; + } + + if (c == '$' && CPP_PEDANTIC (pfile)) + cpp_pedwarn (pfile, "`$' in identifier"); + + CPP_RESERVE(pfile, 2); /* One more for final NUL. */ + CPP_PUTC_Q (pfile, c); + c = GETC(); + if (c == EOF) + break; + } + CPP_NUL_TERMINATE_Q (pfile); + return 1; +} + +/* This is called after options have been processed. + * Check options for consistency, and setup for processing input + * from the file named FNAME. (Use standard input if FNAME==NULL.) + * Return 1 on success, 0 on failure. + */ + +int +cpp_start_read (pfile, fname) + cpp_reader *pfile; + char *fname; +{ + struct cpp_options *opts = CPP_OPTIONS (pfile); + struct cpp_pending *pend; + char *p; + int f; + cpp_buffer *fp; + struct include_hash *ih_fake; + + /* The code looks at the defaults through this pointer, rather than through + the constant structure above. This pointer gets changed if an environment + variable specifies other defaults. */ + struct default_include *include_defaults = include_defaults_array; + + /* Now that we know dollars_in_ident for real, + reset is_idchar/is_idstart. */ + is_idchar['$'] = opts->dollars_in_ident; + is_idstart['$'] = opts->dollars_in_ident; + + /* Add dirs from CPATH after dirs from -I. */ + /* There seems to be confusion about what CPATH should do, + so for the moment it is not documented. */ + /* Some people say that CPATH should replace the standard include dirs, + but that seems pointless: it comes before them, so it overrides them + anyway. */ + GET_ENV_PATH_LIST (p, "CPATH"); + if (p != 0 && ! opts->no_standard_includes) + path_include (pfile, p); + + /* Do partial setup of input buffer for the sake of generating + early #line directives (when -g is in effect). */ + fp = cpp_push_buffer (pfile, NULL, 0); + if (!fp) + return 0; + if (opts->in_fname == NULL || *opts->in_fname == 0) + { + opts->in_fname = fname; + if (opts->in_fname == NULL) + opts->in_fname = ""; + } + fp->nominal_fname = fp->fname = opts->in_fname; + fp->lineno = 0; + + /* Install __LINE__, etc. Must follow initialize_char_syntax + and option processing. */ + initialize_builtins (pfile); + + /* Do standard #defines and assertions + that identify system and machine type. */ + + if (!opts->inhibit_predefs) { + char *p = (char *) alloca (strlen (predefs) + 1); + strcpy (p, predefs); + while (*p) { + char *q; + while (*p == ' ' || *p == '\t') + p++; + /* Handle -D options. */ + if (p[0] == '-' && p[1] == 'D') { + q = &p[2]; + while (*p && *p != ' ' && *p != '\t') + p++; + if (*p != 0) + *p++= 0; + if (opts->debug_output) + output_line_command (pfile, 0, same_file); + cpp_define (pfile, q); + while (*p == ' ' || *p == '\t') + p++; + } else if (p[0] == '-' && p[1] == 'A') { + /* Handle -A options (assertions). */ + char *assertion; + char *past_name; + char *value; + char *past_value; + char *termination; + int save_char; + + assertion = &p[2]; + past_name = assertion; + /* Locate end of name. */ + while (*past_name && *past_name != ' ' + && *past_name != '\t' && *past_name != '(') + past_name++; + /* Locate `(' at start of value. */ + value = past_name; + while (*value && (*value == ' ' || *value == '\t')) + value++; + if (*value++ != '(') + abort (); + while (*value && (*value == ' ' || *value == '\t')) + value++; + past_value = value; + /* Locate end of value. */ + while (*past_value && *past_value != ' ' + && *past_value != '\t' && *past_value != ')') + past_value++; + termination = past_value; + while (*termination && (*termination == ' ' || *termination == '\t')) + termination++; + if (*termination++ != ')') + abort (); + if (*termination && *termination != ' ' && *termination != '\t') + abort (); + /* Temporarily null-terminate the value. */ + save_char = *termination; + *termination = '\0'; + /* Install the assertion. */ + make_assertion (pfile, "-A", assertion); + *termination = (char) save_char; + p = termination; + while (*p == ' ' || *p == '\t') + p++; + } else { + abort (); + } + } + } + + /* Now handle the command line options. */ + + /* Do -U's, -D's and -A's in the order they were seen. */ + /* First reverse the list. */ + opts->pending = nreverse_pending (opts->pending); + + for (pend = opts->pending; pend; pend = pend->next) + { + if (pend->cmd != NULL && pend->cmd[0] == '-') + { + switch (pend->cmd[1]) + { + case 'U': + if (opts->debug_output) + output_line_command (pfile, 0, same_file); + cpp_undef (pfile, pend->arg); + break; + case 'D': + if (opts->debug_output) + output_line_command (pfile, 0, same_file); + cpp_define (pfile, pend->arg); + break; + case 'A': + make_assertion (pfile, "-A", pend->arg); + break; + } + } + } + + opts->done_initializing = 1; + + { /* Read the appropriate environment variable and if it exists + replace include_defaults with the listed path. */ + char *epath = 0; + switch ((opts->objc << 1) + opts->cplusplus) + { + case 0: + GET_ENV_PATH_LIST (epath, "C_INCLUDE_PATH"); + break; + case 1: + GET_ENV_PATH_LIST (epath, "CPLUS_INCLUDE_PATH"); + break; + case 2: + GET_ENV_PATH_LIST (epath, "OBJC_INCLUDE_PATH"); + break; + case 3: + GET_ENV_PATH_LIST (epath, "OBJCPLUS_INCLUDE_PATH"); + break; + } + /* If the environment var for this language is set, + add to the default list of include directories. */ + if (epath) { + char *nstore = (char *) alloca (strlen (epath) + 2); + int num_dirs; + char *startp, *endp; + + for (num_dirs = 1, startp = epath; *startp; startp++) + if (*startp == PATH_SEPARATOR) + num_dirs++; + include_defaults + = (struct default_include *) xmalloc ((num_dirs + * sizeof (struct default_include)) + + sizeof (include_defaults_array)); + startp = endp = epath; + num_dirs = 0; + while (1) { + /* Handle cases like c:/usr/lib:d:/gcc/lib */ + if ((*endp == PATH_SEPARATOR) + || *endp == 0) { + strncpy (nstore, startp, endp-startp); + if (endp == startp) + strcpy (nstore, "."); + else + nstore[endp-startp] = '\0'; + + include_defaults[num_dirs].fname = xstrdup (nstore); + include_defaults[num_dirs].component = 0; + include_defaults[num_dirs].cplusplus = opts->cplusplus; + include_defaults[num_dirs].cxx_aware = 1; + num_dirs++; + if (*endp == '\0') + break; + endp = startp = endp + 1; + } else + endp++; + } + /* Put the usual defaults back in at the end. */ + bcopy ((char *) include_defaults_array, + (char *) &include_defaults[num_dirs], + sizeof (include_defaults_array)); + } + } + + /* Unless -fnostdinc, + tack on the standard include file dirs to the specified list */ + if (!opts->no_standard_includes) { + struct default_include *p = include_defaults; + char *specd_prefix = opts->include_prefix; + char *default_prefix = xstrdup (GCC_INCLUDE_DIR); + int default_len = 0; + /* Remove the `include' from /usr/local/lib/gcc.../include. */ + if (!strcmp (default_prefix + strlen (default_prefix) - 8, "/include")) { + default_len = strlen (default_prefix) - 7; + default_prefix[default_len] = 0; + } + /* Search "translated" versions of GNU directories. + These have /usr/local/lib/gcc... replaced by specd_prefix. */ + if (specd_prefix != 0 && default_len != 0) + for (p = include_defaults; p->fname; p++) { + /* Some standard dirs are only for C++. */ + if (!p->cplusplus + || (opts->cplusplus && !opts->no_standard_cplusplus_includes)) { + /* Does this dir start with the prefix? */ + if (!strncmp (p->fname, default_prefix, default_len)) { + /* Yes; change prefix and add to search list. */ + int this_len = strlen (specd_prefix) + + strlen (p->fname) - default_len; + char *str = (char *) xmalloc (this_len + 1); + strcpy (str, specd_prefix); + strcat (str, p->fname + default_len); + + append_include_chain (pfile, &opts->system_include, + str, !p->cxx_aware); + } + } + } + /* Search ordinary names for GNU include directories. */ + for (p = include_defaults; p->fname; p++) { + /* Some standard dirs are only for C++. */ + if (!p->cplusplus + || (opts->cplusplus && !opts->no_standard_cplusplus_includes)) { + const char *str = update_path (p->fname, p->component); + append_include_chain (pfile, &opts->system_include, + str, !p->cxx_aware); + } + } + } + + merge_include_chains (opts); + + /* With -v, print the list of dirs to search. */ + if (opts->verbose) { + struct file_name_list *p; + fprintf (stderr, "#include \"...\" search starts here:\n"); + for (p = opts->quote_include; p; p = p->next) { + if (p == opts->bracket_include) + fprintf (stderr, "#include <...> search starts here:\n"); + fprintf (stderr, " %s\n", p->name); + } + fprintf (stderr, "End of search list.\n"); + } + + /* Copy the entire contents of the main input file into + the stacked input buffer previously allocated for it. */ + if (fname == NULL || *fname == 0) { + fname = ""; + f = 0; + } else if ((f = open (fname, O_RDONLY, 0666)) < 0) + cpp_pfatal_with_name (pfile, fname); + + /* -MG doesn't select the form of output and must be specified with one of + -M or -MM. -MG doesn't make sense with -MD or -MMD since they don't + inhibit compilation. */ + if (opts->print_deps_missing_files + && (opts->print_deps == 0 || !opts->no_output)) + { + cpp_fatal (pfile, "-MG must be specified with one of -M or -MM"); + return 0; + } + + /* Either of two environment variables can specify output of deps. + Its value is either "OUTPUT_FILE" or "OUTPUT_FILE DEPS_TARGET", + where OUTPUT_FILE is the file to write deps info to + and DEPS_TARGET is the target to mention in the deps. */ + + if (opts->print_deps == 0 + && (getenv ("SUNPRO_DEPENDENCIES") != 0 + || getenv ("DEPENDENCIES_OUTPUT") != 0)) { + char *spec = getenv ("DEPENDENCIES_OUTPUT"); + char *s; + char *output_file; + + if (spec == 0) + { + spec = getenv ("SUNPRO_DEPENDENCIES"); + opts->print_deps = 2; + } + else + opts->print_deps = 1; + + s = spec; + /* Find the space before the DEPS_TARGET, if there is one. */ + /* This should use index. (mrs) */ + while (*s != 0 && *s != ' ') s++; + if (*s != 0) + { + opts->deps_target = s + 1; + output_file = (char *) xmalloc (s - spec + 1); + bcopy (spec, output_file, s - spec); + output_file[s - spec] = 0; + } + else + { + opts->deps_target = 0; + output_file = spec; + } + + opts->deps_file = output_file; + opts->print_deps_append = 1; + } + + /* For -M, print the expected object file name + as the target of this Make-rule. */ + if (opts->print_deps) + { + pfile->deps_allocated_size = 200; + pfile->deps_buffer = (char *) xmalloc (pfile->deps_allocated_size); + pfile->deps_buffer[0] = 0; + pfile->deps_size = 0; + pfile->deps_column = 0; + + if (opts->deps_target) + deps_output (pfile, opts->deps_target, ':'); + else if (*opts->in_fname == 0) + deps_output (pfile, "-", ':'); + else + { + char *p, *q, *r; + int len, x; + static char *known_suffixes[] = { ".c", ".C", ".s", ".S", ".m", + ".cc", ".cxx", ".cpp", ".cp", + ".c++", 0 + }; + + /* Discard all directory prefixes from filename. */ + if ((q = rindex (opts->in_fname, '/')) != NULL +#ifdef DIR_SEPARATOR + && (q = rindex (opts->in_fname, DIR_SEPARATOR)) != NULL +#endif + ) + ++q; + else + q = opts->in_fname; + + /* Copy remainder to mungable area. */ + p = (char *) alloca (strlen(q) + 8); + strcpy (p, q); + + /* Output P, but remove known suffixes. */ + len = strlen (p); + q = p + len; + /* Point to the filename suffix. */ + r = rindex (p, '.'); + /* Compare against the known suffixes. */ + x = 0; + while (known_suffixes[x] != 0) + { + if (strncmp (known_suffixes[x], r, q - r) == 0) + { + /* Make q point to the bit we're going to overwrite + with an object suffix. */ + q = r; + break; + } + x++; + } + + /* Supply our own suffix. */ +#ifndef VMS + strcpy (q, ".o"); +#else + strcpy (q, ".obj"); +#endif + + deps_output (pfile, p, ':'); + deps_output (pfile, opts->in_fname, ' '); + } + } + +#if 0 + /* Make sure data ends with a newline. And put a null after it. */ + + if ((fp->length > 0 && fp->buf[fp->length - 1] != '\n') + /* Backslash-newline at end is not good enough. */ + || (fp->length > 1 && fp->buf[fp->length - 2] == '\\')) { + fp->buf[fp->length++] = '\n'; + missing_newline = 1; + } + fp->buf[fp->length] = '\0'; + + /* Unless inhibited, convert trigraphs in the input. */ + + if (!no_trigraphs) + trigraph_pcp (fp); +#endif + + /* Must call finclude() on the main input before processing + -include switches; otherwise the -included text winds up + after the main input. */ + ih_fake = (struct include_hash *) xmalloc (sizeof (struct include_hash)); + ih_fake->next = 0; + ih_fake->next_this_file = 0; + ih_fake->foundhere = ABSOLUTE_PATH; /* well sort of ... */ + ih_fake->name = fname; + ih_fake->control_macro = 0; + ih_fake->buf = (char *)-1; + ih_fake->limit = 0; + if (!finclude (pfile, f, ih_fake)) + return 0; + output_line_command (pfile, 0, same_file); + pfile->only_seen_white = 2; + + /* The -imacros files can be scanned now, but the -include files + have to be pushed onto the include stack and processed later, + in the main loop calling cpp_get_token. That means the -include + files have to be processed in reverse order of the pending list, + which means the pending list has to be reversed again, which + means the -imacros files have to be done separately and first. */ + + pfile->no_record_file++; + opts->no_output++; + for (pend = opts->pending; pend; pend = pend->next) + { + if (pend->cmd != NULL) + { + if (strcmp (pend->cmd, "-imacros") == 0) + { + int fd = open (pend->arg, O_RDONLY, 0666); + if (fd < 0) + { + cpp_perror_with_name (pfile, pend->arg); + return 0; + } + if (!cpp_push_buffer (pfile, NULL, 0)) + return 0; + + ih_fake = (struct include_hash *) + xmalloc (sizeof (struct include_hash)); + ih_fake->next = 0; + ih_fake->next_this_file = 0; + ih_fake->foundhere = ABSOLUTE_PATH; /* well sort of ... */ + ih_fake->name = pend->arg; + ih_fake->control_macro = 0; + ih_fake->buf = (char *)-1; + ih_fake->limit = 0; + if (!finclude (pfile, fd, ih_fake)) + cpp_scan_buffer (pfile); + free (ih_fake); + } + } + } + opts->no_output--; + opts->pending = nreverse_pending (opts->pending); + for (pend = opts->pending; pend; pend = pend->next) + { + if (pend->cmd != NULL) + { + if (strcmp (pend->cmd, "-include") == 0) + { + int fd = open (pend->arg, O_RDONLY, 0666); + if (fd < 0) + { + cpp_perror_with_name (pfile, pend->arg); + return 0; + } + if (!cpp_push_buffer (pfile, NULL, 0)) + return 0; + + ih_fake = (struct include_hash *) + xmalloc (sizeof (struct include_hash)); + ih_fake->next = 0; + ih_fake->next_this_file = 0; + ih_fake->foundhere = ABSOLUTE_PATH; /* well sort of ... */ + ih_fake->name = pend->arg; + ih_fake->control_macro = 0; + ih_fake->buf = (char *)-1; + ih_fake->limit = 0; + if (finclude (pfile, fd, ih_fake)) + output_line_command (pfile, 0, enter_file); + } + } + } + pfile->no_record_file--; + + /* Free the pending list. */ + for (pend = opts->pending; pend; ) + { + struct cpp_pending *next = pend->next; + free (pend); + pend = next; + } + opts->pending = NULL; + + + return 1; +} + +void +cpp_reader_init (pfile) + cpp_reader *pfile; +{ + bzero ((char *) pfile, sizeof (cpp_reader)); + pfile->get_token = cpp_get_token; + + pfile->token_buffer_size = 200; + pfile->token_buffer = (U_CHAR *) xmalloc (pfile->token_buffer_size); + CPP_SET_WRITTEN (pfile, 0); + + pfile->timebuf = NULL; + pfile->only_seen_white = 1; + pfile->buffer = CPP_NULL_BUFFER(pfile); + pfile->actual_dirs = NULL; +} + +static struct cpp_pending * +nreverse_pending (list) + struct cpp_pending *list; + +{ + register struct cpp_pending *prev = 0, *next, *pend; + for (pend = list; pend; pend = next) + { + next = pend->next; + pend->next = prev; + prev = pend; + } + return prev; +} + +static void +push_pending (pfile, cmd, arg) + cpp_reader *pfile; + char *cmd; + char *arg; +{ + struct cpp_pending *pend + = (struct cpp_pending *) xmalloc (sizeof (struct cpp_pending)); + pend->cmd = cmd; + pend->arg = arg; + pend->next = CPP_OPTIONS (pfile)->pending; + CPP_OPTIONS (pfile)->pending = pend; +} + + +static void +print_help () +{ + printf ("Usage: %s [switches] input output\n", progname); + printf ("Switches:\n"); + printf (" -include Include the contents of before other files\n"); + printf (" -imacros Accept definition of marcos in \n"); + printf (" -iprefix Specify as a prefix for next two options\n"); + printf (" -iwithprefix Add to the end of the system include paths\n"); + printf (" -iwithprefixbefore Add to the end of the main include paths\n"); + printf (" -isystem Add to the start of the system include paths\n"); + printf (" -idirafter Add to the end of the system include paths\n"); + printf (" -I Add to the end of the main include paths\n"); + printf (" -nostdinc Do not search the system include directories\n"); + printf (" -nostdinc++ Do not search the system include directories for C++\n"); + printf (" -o Put output into \n"); + printf (" -pedantic Issue all warnings demanded by strict ANSI C\n"); + printf (" -traditional Follow K&R pre-processor behaviour\n"); + printf (" -trigraphs Support ANSI C trigraphs\n"); + printf (" -lang-c Assume that the input sources are in C\n"); + printf (" -lang-c89 Assume that the input sources are in C89\n"); + printf (" -lang-c++ Assume that the input sources are in C++\n"); + printf (" -lang-objc Assume that the input sources are in ObjectiveC\n"); + printf (" -lang-objc++ Assume that the input sources are in ObjectiveC++\n"); + printf (" -lang-asm Assume that the input sources are in assembler\n"); + printf (" -lang-chill Assume that the input sources are in Chill\n"); + printf (" -+ Allow parsing of C++ style features\n"); + printf (" -w Inhibit warning messages\n"); + printf (" -Wtrigraphs Warn if trigraphs are encountered\n"); + printf (" -Wno-trigraphs Do not warn about trigraphs\n"); + printf (" -Wcomment{s} Warn if one comment starts inside another\n"); + printf (" -Wno-comment{s} Do not warn about comments\n"); + printf (" -Wtraditional Warn if a macro argument is/would be turned into\n"); + printf (" a string if -tradtional is specified\n"); + printf (" -Wno-traditional Do not warn about stringification\n"); + printf (" -Wundef Warn if an undefined macro is used by #if\n"); + printf (" -Wno-undef Do not warn about testing udefined macros\n"); + printf (" -Wimport Warn about the use of the #import directive\n"); + printf (" -Wno-import Do not warn about the use of #import\n"); + printf (" -Werror Treat all warnings as errors\n"); + printf (" -Wno-error Do not treat warnings as errors\n"); + printf (" -Wall Enable all preprocessor warnings\n"); + printf (" -M Generate make dependencies\n"); + printf (" -MM As -M, but ignore system header files\n"); + printf (" -MD As -M, but put output in a .d file\n"); + printf (" -MMD As -MD, but ignore system header files\n"); + printf (" -MG Treat missing header file as generated files\n"); + printf (" -g Include #define and #undef directives in the output\n"); + printf (" -D Define a with string '1' as its value\n"); + printf (" -D= Define a with as its value\n"); + printf (" -A () Assert the to \n"); + printf (" -U Undefine \n"); + printf (" -u or -undef Do not predefine any macros\n"); + printf (" -v Display the version number\n"); + printf (" -H Print the name of header files as they are used\n"); + printf (" -C Do not discard comments\n"); + printf (" -dM Display a list of macro definitions active at end\n"); + printf (" -dD Preserve macro definitions in output\n"); + printf (" -dN As -dD except that only the names are preserved\n"); + printf (" -dI Include #include directives in the output\n"); + printf (" -ifoutput Describe skipped code blocks in output \n"); + printf (" -P Do not generate #line directives\n"); + printf (" -$ Do not include '$' in identifiers\n"); + printf (" -remap Remap file names when including files.\n"); + printf (" -h or --help Display this information\n"); +} + + +/* Handle one command-line option in (argc, argv). + Can be called multiple times, to handle multiple sets of options. + Returns number of strings consumed. */ +int +cpp_handle_option (pfile, argc, argv) + cpp_reader *pfile; + int argc; + char **argv; +{ + struct cpp_options *opts = CPP_OPTIONS (pfile); + int i = 0; + + if (user_label_prefix == NULL) + user_label_prefix = USER_LABEL_PREFIX; + + if (argv[i][0] != '-') { + if (opts->out_fname != NULL) + { + print_help (); + cpp_fatal (pfile, "Too many arguments"); + } + else if (opts->in_fname != NULL) + opts->out_fname = argv[i]; + else + opts->in_fname = argv[i]; + } else { + switch (argv[i][1]) { + + missing_filename: + cpp_fatal (pfile, "Filename missing after `%s' option", argv[i]); + return argc; + missing_dirname: + cpp_fatal (pfile, "Directory name missing after `%s' option", argv[i]); + return argc; + + case 'f': + if (!strcmp (argv[i], "-fleading-underscore")) + user_label_prefix = "_"; + else if (!strcmp (argv[i], "-fno-leading-underscore")) + user_label_prefix = ""; + + break; + + case 'I': /* Add directory to path for includes. */ + if (!strcmp (argv[i] + 2, "-")) + { + if (! opts->ignore_srcdir) + { + opts->ignore_srcdir = 1; + /* Don't use any preceding -I directories for #include <...>. */ + opts->quote_include = opts->bracket_include; + opts->bracket_include = 0; + } + } + else + { + char *fname; + if (argv[i][2] != 0) + fname = argv[i] + 2; + else if (i + 1 == argc) + goto missing_dirname; + else + fname = argv[++i]; + append_include_chain (pfile, &opts->bracket_include, fname, 0); + } + break; + + case 'i': + /* Add directory to beginning of system include path, as a system + include directory. */ + if (!strcmp (argv[i], "-isystem")) + { + if (i + 1 == argc) + goto missing_filename; + append_include_chain (pfile, &opts->system_include, argv[++i], 1); + } + /* Add directory to end of path for includes, + with the default prefix at the front of its name. */ + else if (!strcmp (argv[i], "-iwithprefix")) + { + char *fname; + if (i + 1 == argc) + goto missing_dirname; + ++i; + + if (opts->include_prefix != 0) + { + fname = xmalloc (strlen (opts->include_prefix) + + strlen (argv[i]) + 1); + strcpy (fname, opts->include_prefix); + strcat (fname, argv[i]); + } + else + { + fname = xmalloc (strlen (GCC_INCLUDE_DIR) + + strlen (argv[i]) + 1); + strcpy (fname, GCC_INCLUDE_DIR); + /* Remove the `include' from /usr/local/lib/gcc.../include. */ + if (!strcmp (fname + strlen (fname) - 8, "/include")) + fname[strlen (fname) - 7] = 0; + strcat (fname, argv[i]); + } + + append_include_chain (pfile, &opts->system_include, fname, 0); + } + /* Add directory to main path for includes, + with the default prefix at the front of its name. */ + else if (!strcmp (argv[i], "-iwithprefix")) + { + char *fname; + if (i + 1 == argc) + goto missing_dirname; + ++i; + + if (opts->include_prefix != 0) + { + fname = xmalloc (strlen (opts->include_prefix) + + strlen (argv[i]) + 1); + strcpy (fname, opts->include_prefix); + strcat (fname, argv[i]); + } + else + { + fname = xmalloc (strlen (GCC_INCLUDE_DIR) + + strlen (argv[i]) + 1); + strcpy (fname, GCC_INCLUDE_DIR); + /* Remove the `include' from /usr/local/lib/gcc.../include. */ + if (!strcmp (fname + strlen (fname) - 8, "/include")) + fname[strlen (fname) - 7] = 0; + strcat (fname, argv[i]); + } + + append_include_chain (pfile, &opts->bracket_include, fname, 0); + } + /* Add directory to end of path for includes. */ + else if (!strcmp (argv[i], "-idirafter")) + { + if (i + 1 == argc) + goto missing_dirname; + append_include_chain (pfile, &opts->after_include, argv[++i], 0); + } + else if (!strcmp (argv[i], "-include") || !strcmp (argv[i], "-imacros")) + { + if (i + 1 == argc) + goto missing_filename; + else + push_pending (pfile, argv[i], argv[i+1]), i++; + } + else if (!strcmp (argv[i], "-iprefix")) + { + if (i + 1 == argc) + goto missing_filename; + else + opts->include_prefix = argv[++i]; + } + else if (!strcmp (argv[i], "-ifoutput")) + opts->output_conditionals = 1; + + break; + + case 'o': + if (opts->out_fname != NULL) + { + cpp_fatal (pfile, "Output filename specified twice"); + return argc; + } + if (i + 1 == argc) + goto missing_filename; + opts->out_fname = argv[++i]; + if (!strcmp (opts->out_fname, "-")) + opts->out_fname = ""; + break; + + case 'p': + if (!strcmp (argv[i], "-pedantic")) + CPP_PEDANTIC (pfile) = 1; + else if (!strcmp (argv[i], "-pedantic-errors")) { + CPP_PEDANTIC (pfile) = 1; + opts->pedantic_errors = 1; + } +#if 0 + else if (!strcmp (argv[i], "-pcp")) { + char *pcp_fname = argv[++i]; + pcp_outfile = ((pcp_fname[0] != '-' || pcp_fname[1] != '\0') + ? fopen (pcp_fname, "w") + : fdopen (dup (fileno (stdout)), "w")); + if (pcp_outfile == 0) + cpp_pfatal_with_name (pfile, pcp_fname); + no_precomp = 1; + } +#endif + break; + + case 't': + if (!strcmp (argv[i], "-traditional")) { + opts->traditional = 1; + opts->cplusplus_comments = 0; + } else if (!strcmp (argv[i], "-trigraphs")) { + if (!opts->chill) + opts->no_trigraphs = 0; + } + break; + + case 'l': + if (! strcmp (argv[i], "-lang-c")) + opts->cplusplus = 0, opts->cplusplus_comments = 1, opts->c89 = 0, + opts->objc = 0; + if (! strcmp (argv[i], "-lang-c89")) + opts->cplusplus = 0, opts->cplusplus_comments = 0, opts->c89 = 1, + opts->objc = 0; + if (! strcmp (argv[i], "-lang-c++")) + opts->cplusplus = 1, opts->cplusplus_comments = 1, opts->c89 = 0, + opts->objc = 0; + if (! strcmp (argv[i], "-lang-objc")) + opts->cplusplus = 0, opts->cplusplus_comments = 1, opts->c89 = 0, + opts->objc = 1; + if (! strcmp (argv[i], "-lang-objc++")) + opts->cplusplus = 1, opts->cplusplus_comments = 1, opts->c89 = 0, + opts->objc = 1; + if (! strcmp (argv[i], "-lang-asm")) + opts->lang_asm = 1; + if (! strcmp (argv[i], "-lint")) + opts->for_lint = 1; + if (! strcmp (argv[i], "-lang-chill")) + opts->objc = 0, opts->cplusplus = 0, opts->chill = 1, + opts->traditional = 1, opts->no_trigraphs = 1, + opts->traditional = 1, opts->cplusplus_comments = 0; + break; + + case '+': + opts->cplusplus = 1, opts->cplusplus_comments = 1; + break; + + case 'w': + opts->inhibit_warnings = 1; + break; + + case 'W': + if (!strcmp (argv[i], "-Wtrigraphs")) + opts->warn_trigraphs = 1; + else if (!strcmp (argv[i], "-Wno-trigraphs")) + opts->warn_trigraphs = 0; + else if (!strcmp (argv[i], "-Wcomment")) + opts->warn_comments = 1; + else if (!strcmp (argv[i], "-Wno-comment")) + opts->warn_comments = 0; + else if (!strcmp (argv[i], "-Wcomments")) + opts->warn_comments = 1; + else if (!strcmp (argv[i], "-Wno-comments")) + opts->warn_comments = 0; + else if (!strcmp (argv[i], "-Wtraditional")) + opts->warn_stringify = 1; + else if (!strcmp (argv[i], "-Wno-traditional")) + opts->warn_stringify = 0; + else if (!strcmp (argv[i], "-Wundef")) + opts->warn_undef = 1; + else if (!strcmp (argv[i], "-Wno-undef")) + opts->warn_undef = 0; + else if (!strcmp (argv[i], "-Wimport")) + opts->warn_import = 1; + else if (!strcmp (argv[i], "-Wno-import")) + opts->warn_import = 0; + else if (!strcmp (argv[i], "-Werror")) + opts->warnings_are_errors = 1; + else if (!strcmp (argv[i], "-Wno-error")) + opts->warnings_are_errors = 0; + else if (!strcmp (argv[i], "-Wall")) + { + opts->warn_trigraphs = 1; + opts->warn_comments = 1; + } + break; + + case 'M': + /* The style of the choices here is a bit mixed. + The chosen scheme is a hybrid of keeping all options in one string + and specifying each option in a separate argument: + -M|-MM|-MD file|-MMD file [-MG]. An alternative is: + -M|-MM|-MD file|-MMD file|-MG|-MMG; or more concisely: + -M[M][G][D file]. This is awkward to handle in specs, and is not + as extensible. */ + /* ??? -MG must be specified in addition to one of -M or -MM. + This can be relaxed in the future without breaking anything. + The converse isn't true. */ + + /* -MG isn't valid with -MD or -MMD. This is checked for later. */ + if (!strcmp (argv[i], "-MG")) + { + opts->print_deps_missing_files = 1; + break; + } + if (!strcmp (argv[i], "-M")) + opts->print_deps = 2; + else if (!strcmp (argv[i], "-MM")) + opts->print_deps = 1; + else if (!strcmp (argv[i], "-MD")) + opts->print_deps = 2; + else if (!strcmp (argv[i], "-MMD")) + opts->print_deps = 1; + /* For -MD and -MMD options, write deps on file named by next arg. */ + if (!strcmp (argv[i], "-MD") || !strcmp (argv[i], "-MMD")) + { + if (i+1 == argc) + goto missing_filename; + opts->deps_file = argv[++i]; + } + else + { + /* For -M and -MM, write deps on standard output + and suppress the usual output. */ + opts->no_output = 1; + } + break; + + case 'd': + { + char *p = argv[i] + 2; + char c; + while ((c = *p++) != 0) { + /* Arg to -d specifies what parts of macros to dump */ + switch (c) { + case 'M': + opts->dump_macros = dump_only; + opts->no_output = 1; + break; + case 'N': + opts->dump_macros = dump_names; + break; + case 'D': + opts->dump_macros = dump_definitions; + break; + case 'I': + opts->dump_includes = 1; + break; + } + } + } + break; + + case 'g': + if (argv[i][2] == '3') + opts->debug_output = 1; + break; + + case '-': + if (strcmp (argv[i], "--help") != 0) + return i; + print_help (); + break; + + case 'v': + fprintf (stderr, "GNU CPP version %s", version_string); +#ifdef TARGET_VERSION + TARGET_VERSION; +#endif + fprintf (stderr, "\n"); + opts->verbose = 1; + break; + + case 'H': + opts->print_include_names = 1; + break; + + case 'D': + if (argv[i][2] != 0) + push_pending (pfile, "-D", argv[i] + 2); + else if (i + 1 == argc) + { + cpp_fatal (pfile, "Macro name missing after -D option"); + return argc; + } + else + i++, push_pending (pfile, "-D", argv[i]); + break; + + case 'A': + { + char *p; + + if (argv[i][2] != 0) + p = argv[i] + 2; + else if (i + 1 == argc) + { + cpp_fatal (pfile, "Assertion missing after -A option"); + return argc; + } + else + p = argv[++i]; + + if (!strcmp (p, "-")) { + struct cpp_pending **ptr; + /* -A- eliminates all predefined macros and assertions. + Let's include also any that were specified earlier + on the command line. That way we can get rid of any + that were passed automatically in from GCC. */ + opts->inhibit_predefs = 1; + for (ptr = &opts->pending; *ptr != NULL; ) + { + struct cpp_pending *pend = *ptr; + if (pend->cmd && pend->cmd[0] == '-' + && (pend->cmd[1] == 'D' || pend->cmd[1] == 'A')) + { + *ptr = pend->next; + free (pend); + } + else + ptr = &pend->next; + } + } else { + push_pending (pfile, "-A", p); + } + } + break; + + case 'U': /* JF #undef something */ + if (argv[i][2] != 0) + push_pending (pfile, "-U", argv[i] + 2); + else if (i + 1 == argc) + { + cpp_fatal (pfile, "Macro name missing after -U option"); + return argc; + } + else + push_pending (pfile, "-U", argv[i+1]), i++; + break; + + case 'C': + opts->put_out_comments = 1; + break; + + case 'E': /* -E comes from cc -E; ignore it. */ + break; + + case 'P': + opts->no_line_commands = 1; + break; + + case '$': /* Don't include $ in identifiers. */ + opts->dollars_in_ident = 0; + break; + + case 'n': + if (!strcmp (argv[i], "-nostdinc")) + /* -nostdinc causes no default include directories. + You must specify all include-file directories with -I. */ + opts->no_standard_includes = 1; + else if (!strcmp (argv[i], "-nostdinc++")) + /* -nostdinc++ causes no default C++-specific include directories. */ + opts->no_standard_cplusplus_includes = 1; +#if 0 + else if (!strcmp (argv[i], "-noprecomp")) + no_precomp = 1; +#endif + break; + + case 'r': + if (!strcmp (argv[i], "-remap")) + opts->remap = 1; + break; + + case 'u': + /* Sun compiler passes undocumented switch "-undef". + Let's assume it means to inhibit the predefined symbols. */ + opts->inhibit_predefs = 1; + break; + + case '\0': /* JF handle '-' as file name meaning stdin or stdout */ + if (opts->in_fname == NULL) { + opts->in_fname = ""; + break; + } else if (opts->out_fname == NULL) { + opts->out_fname = ""; + break; + } /* else fall through into error */ + + default: + return i; + } + } + + return i + 1; +} + +/* Handle command-line options in (argc, argv). + Can be called multiple times, to handle multiple sets of options. + Returns if an unrecognized option is seen. + Returns number of strings consumed. */ + +int +cpp_handle_options (pfile, argc, argv) + cpp_reader *pfile; + int argc; + char **argv; +{ + int i; + int strings_processed; + for (i = 0; i < argc; i += strings_processed) + { + strings_processed = cpp_handle_option (pfile, argc - i, argv + i); + if (strings_processed == 0) + break; + } + return i; +} + +void +cpp_finish (pfile) + cpp_reader *pfile; +{ + struct cpp_options *opts = CPP_OPTIONS (pfile); + + if (opts->print_deps) + { + /* Stream on which to print the dependency information. */ + FILE *deps_stream; + + /* Don't actually write the deps file if compilation has failed. */ + if (pfile->errors == 0) + { + char *deps_mode = opts->print_deps_append ? "a" : "w"; + if (opts->deps_file == 0) + deps_stream = stdout; + else if ((deps_stream = fopen (opts->deps_file, deps_mode)) == 0) + cpp_pfatal_with_name (pfile, opts->deps_file); + fputs (pfile->deps_buffer, deps_stream); + putc ('\n', deps_stream); + if (opts->deps_file) + { + if (ferror (deps_stream) || fclose (deps_stream) != 0) + cpp_fatal (pfile, "I/O error on output"); + } + } + } + +#if 0 + /* Debugging: dump statistics on the include hash table. */ + { + struct include_hash *x; + int i, j; + + for(i = 0; i < ALL_INCLUDE_HASHSIZE; i++) + { + x = pfile->all_include_files[i]; + j = 0; + while(x) + { + j++; + x = x->next; + } + fprintf(stderr, "%d/%d ", i, j); + } + fputc('\n', stderr); + } +#endif + +} + +/* Free resources used by PFILE. + This is the cpp_reader 'finalizer' or 'destructor' (in C++ terminology). */ + +void +cpp_cleanup (pfile) + cpp_reader *pfile; +{ + int i; + while ( CPP_BUFFER (pfile) != CPP_NULL_BUFFER (pfile)) + cpp_pop_buffer (pfile); + + if (pfile->token_buffer) + { + free (pfile->token_buffer); + pfile->token_buffer = NULL; + } + + if (pfile->deps_buffer) + { + free (pfile->deps_buffer); + pfile->deps_buffer = NULL; + pfile->deps_allocated_size = 0; + } + + while (pfile->if_stack) + { + IF_STACK_FRAME *temp = pfile->if_stack; + pfile->if_stack = temp->next; + free (temp); + } + + for (i = ALL_INCLUDE_HASHSIZE; --i >= 0; ) + { + struct include_hash *imp = pfile->all_include_files[i]; + while (imp) + { + struct include_hash *next = imp->next; +#if 0 + /* This gets freed elsewhere - I think. */ + free (imp->name); +#endif + free (imp); + imp = next; + } + pfile->all_include_files[i] = 0; + } + + cpp_hash_cleanup (pfile); +} + +/* Read an assertion into the token buffer, converting to + canonical form: `#predicate(a n swe r)' The next non-whitespace + character to read should be the first letter of the predicate. + Returns 0 for syntax error, 1 for bare predicate, 2 for predicate + with answer (see callers for why). In case of 0, an error has been + printed. */ +static int +parse_assertion (pfile) + cpp_reader *pfile; +{ + int c, dropwhite; + cpp_skip_hspace (pfile); + c = PEEKC(); + if (! is_idstart[c]) + { + cpp_error (pfile, "assertion predicate is not an identifier"); + return 0; + } + CPP_PUTC(pfile, '#'); + FORWARD(1); + parse_name(pfile, c); + + c = PEEKC(); + if (c != '(') + { + if (is_hor_space[c]) + cpp_skip_hspace (pfile); + c = PEEKC(); + } + if (c != '(') + return 1; + + CPP_PUTC(pfile, '('); + FORWARD(1); + dropwhite = 1; + while ((c = GETC()) != ')') + { + if (is_hor_space[c]) + { + if (! dropwhite) + { + CPP_PUTC(pfile, ' '); + dropwhite = 1; + } + } + else if (c == '\\' && PEEKC() == '\n') + FORWARD(1); + else if (c == '\n' || c == EOF) + { + if (c == '\n') FORWARD(-1); + cpp_error (pfile, "un-terminated assertion answer"); + return 0; + } + else + { + CPP_PUTC(pfile, c); + dropwhite = 0; + } + } + + if (pfile->limit[-1] == ' ') + pfile->limit[-1] = ')'; + else if (pfile->limit[-1] == '(') + { + cpp_error (pfile, "empty token sequence in assertion"); + return 0; + } + else + CPP_PUTC(pfile, ')'); + + CPP_NUL_TERMINATE(pfile); + return 2; +} + +static int +do_assert (pfile, keyword) + cpp_reader *pfile; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + char *sym; + int ret, c; + HASHNODE *base, *this; + int baselen, thislen; + + if (CPP_PEDANTIC (pfile) && CPP_OPTIONS (pfile)->done_initializing + && !CPP_BUFFER (pfile)->system_header_p) + cpp_pedwarn (pfile, "ANSI C does not allow `#assert'"); + + cpp_skip_hspace (pfile); + sym = CPP_PWRITTEN (pfile); /* remember where it starts */ + ret = parse_assertion (pfile); + if (ret == 0) + goto error; + else if (ret == 1) + { + cpp_error (pfile, "missing token-sequence in `#assert'"); + goto error; + } + + cpp_skip_hspace (pfile); + c = PEEKC(); + if (c != EOF && c != '\n') + { + cpp_error (pfile, "junk at end of `#assert'"); + goto error; + } + + thislen = strlen (sym); + baselen = index (sym, '(') - sym; + this = cpp_lookup (pfile, sym, thislen, -1); + if (this) + { + cpp_warning (pfile, "`%s' re-asserted", sym); + goto error; + } + + base = cpp_lookup (pfile, sym, baselen, -1); + if (! base) + base = install (sym, baselen, T_ASSERT, 0, 0, -1); + else if (base->type != T_ASSERT) + { + /* Token clash - but with what?! */ + cpp_fatal (pfile, + "cpp internal error: base->type != T_ASSERT in do_assert"); + goto error; + } + + this = install (sym, thislen, T_ASSERT, 0, + (char *)base->value.aschain, -1); + base->value.aschain = this; + + pfile->limit = sym; /* Pop */ + return 0; + + error: + pfile->limit = sym; /* Pop */ + skip_rest_of_line (pfile); + return 1; +} + +static int +do_unassert (pfile, keyword) + cpp_reader *pfile; + struct directive *keyword ATTRIBUTE_UNUSED; +{ + int c, ret; + char *sym; + long baselen, thislen; + HASHNODE *base, *this, *next; + + if (CPP_PEDANTIC (pfile) && CPP_OPTIONS (pfile)->done_initializing + && !CPP_BUFFER (pfile)->system_header_p) + cpp_pedwarn (pfile, "ANSI C does not allow `#unassert'"); + + cpp_skip_hspace (pfile); + + sym = CPP_PWRITTEN (pfile); /* remember where it starts */ + ret = parse_assertion (pfile); + if (ret == 0) + goto error; + + cpp_skip_hspace (pfile); + c = PEEKC (); + if (c != EOF && c != '\n') + cpp_error (pfile, "junk at end of `#unassert'"); + + thislen = strlen (sym); + if (ret == 1) + { + base = cpp_lookup (pfile, sym, thislen, -1); + if (! base) + goto error; /* It isn't an error to #undef what isn't #defined, + so it isn't an error to #unassert what isn't + #asserted either. */ + + for (this = base->value.aschain; this; this = next) + { + next = this->value.aschain; + delete_macro (this); + } + delete_macro (base); + } + else + { + baselen = index (sym, '(') - sym; + base = cpp_lookup (pfile, sym, baselen, -1); + if (! base) goto error; + this = cpp_lookup (pfile, sym, thislen, -1); + if (! this) goto error; + + next = base; + while (next->value.aschain != this) + next = next->value.aschain; + + next->value.aschain = this->value.aschain; + delete_macro (this); + + if (base->value.aschain == NULL) + delete_macro (base); /* Last answer for this predicate deleted. */ + } + + pfile->limit = sym; /* Pop */ + return 0; + error: + pfile->limit = sym; /* Pop */ + skip_rest_of_line (pfile); + return 1; +} + +int +cpp_read_check_assertion (pfile) + cpp_reader *pfile; +{ + char *name = CPP_PWRITTEN (pfile); + int result; + HASHNODE *hp; + + FORWARD (1); /* Skip '#' */ + cpp_skip_hspace (pfile); + if (! parse_assertion (pfile)) + result = 0; + else + { + hp = cpp_lookup (pfile, name, (char *)CPP_PWRITTEN (pfile) - name, -1); + result = (hp != 0); + } + + pfile->limit = name; + return result; +} + +/* Initialize PMARK to remember the current position of PFILE. */ + +void +parse_set_mark (pmark, pfile) + struct parse_marker *pmark; + cpp_reader *pfile; +{ + cpp_buffer *pbuf = CPP_BUFFER (pfile); + pmark->next = pbuf->marks; + pbuf->marks = pmark; + pmark->buf = pbuf; + pmark->position = pbuf->cur - pbuf->buf; +} + +/* Cleanup PMARK - we no longer need it. */ + +void +parse_clear_mark (pmark) + struct parse_marker *pmark; +{ + struct parse_marker **pp = &pmark->buf->marks; + for (; ; pp = &(*pp)->next) { + if (*pp == NULL) abort (); + if (*pp == pmark) break; + } + *pp = pmark->next; +} + +/* Backup the current position of PFILE to that saved in PMARK. */ + +void +parse_goto_mark (pmark, pfile) + struct parse_marker *pmark; + cpp_reader *pfile; +{ + cpp_buffer *pbuf = CPP_BUFFER (pfile); + if (pbuf != pmark->buf) + cpp_fatal (pfile, "internal error %s", "parse_goto_mark"); + pbuf->cur = pbuf->buf + pmark->position; +} + +/* Reset PMARK to point to the current position of PFILE. (Same + as parse_clear_mark (PMARK), parse_set_mark (PMARK, PFILE) but faster. */ + +void +parse_move_mark (pmark, pfile) + struct parse_marker *pmark; + cpp_reader *pfile; +{ + cpp_buffer *pbuf = CPP_BUFFER (pfile); + if (pbuf != pmark->buf) + cpp_fatal (pfile, "internal error %s", "parse_move_mark"); + pmark->position = pbuf->cur - pbuf->buf; +} + + +void +cpp_print_file_and_line (pfile) + cpp_reader *pfile; +{ + cpp_buffer *ip = cpp_file_buffer (pfile); + + if (ip != NULL) + { + long line, col; + cpp_buf_line_and_col (ip, &line, &col); + cpp_file_line_for_message (pfile, ip->nominal_fname, + line, pfile->show_column ? col : -1); + } +} + +static void +v_cpp_error (pfile, msg, ap) + cpp_reader *pfile; + const char *msg; + va_list ap; +{ + cpp_print_containing_files (pfile); + cpp_print_file_and_line (pfile); + v_cpp_message (pfile, 1, msg, ap); +} + +void +cpp_error VPROTO ((cpp_reader * pfile, const char *msg, ...)) +{ +#ifndef ANSI_PROTOTYPES + cpp_reader *pfile; + const char *msg; +#endif + va_list ap; + + VA_START(ap, msg); + +#ifndef ANSI_PROTOTYPES + pfile = va_arg (ap, cpp_reader *); + msg = va_arg (ap, const char *); +#endif + + v_cpp_error (pfile, msg, ap); + va_end(ap); +} + +/* Print error message but don't count it. */ + +static void +v_cpp_warning (pfile, msg, ap) + cpp_reader *pfile; + const char *msg; + va_list ap; +{ + if (CPP_OPTIONS (pfile)->inhibit_warnings) + return; + + if (CPP_OPTIONS (pfile)->warnings_are_errors) + pfile->errors++; + + cpp_print_containing_files (pfile); + cpp_print_file_and_line (pfile); + v_cpp_message (pfile, 0, msg, ap); +} + +void +cpp_warning VPROTO ((cpp_reader * pfile, const char *msg, ...)) +{ +#ifndef ANSI_PROTOTYPES + cpp_reader *pfile; + const char *msg; +#endif + va_list ap; + + VA_START (ap, msg); + +#ifndef ANSI_PROTOTYPES + pfile = va_arg (ap, cpp_reader *); + msg = va_arg (ap, const char *); +#endif + + v_cpp_warning (pfile, msg, ap); + va_end(ap); +} + +/* Print an error message and maybe count it. */ + +void +cpp_pedwarn VPROTO ((cpp_reader * pfile, const char *msg, ...)) +{ +#ifndef ANSI_PROTOTYPES + cpp_reader *pfile; + const char *msg; +#endif + va_list ap; + + VA_START (ap, msg); + +#ifndef ANSI_PROTOTYPES + pfile = va_arg (ap, cpp_reader *); + msg = va_arg (ap, const char *); +#endif + + if (CPP_OPTIONS (pfile)->pedantic_errors) + v_cpp_error (pfile, msg, ap); + else + v_cpp_warning (pfile, msg, ap); + va_end(ap); +} + +static void +v_cpp_error_with_line (pfile, line, column, msg, ap) + cpp_reader * pfile; + int line; + int column; + const char * msg; + va_list ap; +{ + cpp_buffer *ip = cpp_file_buffer (pfile); + + cpp_print_containing_files (pfile); + + if (ip != NULL) + cpp_file_line_for_message (pfile, ip->nominal_fname, line, column); + + v_cpp_message (pfile, 1, msg, ap); +} + +void +cpp_error_with_line VPROTO ((cpp_reader * pfile, int line, int column, const char *msg, ...)) +{ +#ifndef ANSI_PROTOTYPES + cpp_reader *pfile; + int line; + int column; + const char *msg; +#endif + va_list ap; + + VA_START (ap, msg); + +#ifndef ANSI_PROTOTYPES + pfile = va_arg (ap, cpp_reader *); + line = va_arg (ap, int); + column = va_arg (ap, int); + msg = va_arg (ap, const char *); +#endif + + v_cpp_error_with_line(pfile, line, column, msg, ap); + va_end(ap); +} + +static void +v_cpp_warning_with_line (pfile, line, column, msg, ap) + cpp_reader * pfile; + int line; + int column; + const char *msg; + va_list ap; +{ + cpp_buffer *ip; + + if (CPP_OPTIONS (pfile)->inhibit_warnings) + return; + + if (CPP_OPTIONS (pfile)->warnings_are_errors) + pfile->errors++; + + cpp_print_containing_files (pfile); + + ip = cpp_file_buffer (pfile); + + if (ip != NULL) + cpp_file_line_for_message (pfile, ip->nominal_fname, line, column); + + v_cpp_message (pfile, 0, msg, ap); +} + +#if 0 +static void +cpp_warning_with_line VPROTO ((cpp_reader * pfile, int line, int column, const char *msg, ...)) +{ +#ifndef ANSI_PROTOTYPES + cpp_reader *pfile; + int line; + int column; + const char *msg; +#endif + va_list ap; + + VA_START (ap, msg); + +#ifndef ANSI_PROTOTYPES + pfile = va_arg (ap, cpp_reader *); + line = va_arg (ap, int); + column = va_arg (ap, int); + msg = va_arg (ap, const char *); +#endif + + v_cpp_warning_with_line (pfile, line, column, msg, ap); + va_end(ap); +} +#endif + +void +cpp_pedwarn_with_line VPROTO ((cpp_reader * pfile, int line, int column, const char *msg, ...)) +{ +#ifndef ANSI_PROTOTYPES + cpp_reader *pfile; + int line; + int column; + const char *msg; +#endif + va_list ap; + + VA_START (ap, msg); + +#ifndef ANSI_PROTOTYPES + pfile = va_arg (ap, cpp_reader *); + line = va_arg (ap, int); + column = va_arg (ap, int); + msg = va_arg (ap, const char *); +#endif + + if (CPP_OPTIONS (pfile)->pedantic_errors) + v_cpp_error_with_line (pfile, column, line, msg, ap); + else + v_cpp_warning_with_line (pfile, line, column, msg, ap); + va_end(ap); +} + +/* Report a warning (or an error if pedantic_errors) + giving specified file name and line number, not current. */ + +void +cpp_pedwarn_with_file_and_line VPROTO ((cpp_reader *pfile, char *file, int line, const char *msg, ...)) +{ +#ifndef ANSI_PROTOTYPES + cpp_reader *pfile; + char *file; + int line; + const char *msg; +#endif + va_list ap; + + VA_START (ap, msg); + +#ifndef ANSI_PROTOTYPES + pfile = va_arg (ap, cpp_reader *); + file = va_arg (ap, char *); + line = va_arg (ap, int); + msg = va_arg (ap, const char *); +#endif + + if (!CPP_OPTIONS (pfile)->pedantic_errors + && CPP_OPTIONS (pfile)->inhibit_warnings) + return; + if (file != NULL) + cpp_file_line_for_message (pfile, file, line, -1); + v_cpp_message (pfile, CPP_OPTIONS (pfile)->pedantic_errors, msg, ap); + va_end(ap); +} + +/* my_strerror - return the descriptive text associated with an + `errno' code. */ + +static char * +my_strerror (errnum) + int errnum; +{ + char *result; + +#ifndef VMS +#ifndef HAVE_STRERROR + result = (char *) ((errnum < sys_nerr) ? sys_errlist[errnum] : 0); +#else + result = strerror (errnum); +#endif +#else /* VMS */ + /* VAXCRTL's strerror() takes an optional second argument, which only + matters when the first argument is EVMSERR. However, it's simplest + just to pass it unconditionally. `vaxc$errno' is declared in + , and maintained by the library in parallel with `errno'. + We assume that caller's `errnum' either matches the last setting of + `errno' by the library or else does not have the value `EVMSERR'. */ + + result = strerror (errnum, vaxc$errno); +#endif + + if (!result) + result = "undocumented I/O error"; + + return result; +} + +/* Error including a message from `errno'. */ + +void +cpp_error_from_errno (pfile, name) + cpp_reader *pfile; + const char *name; +{ + cpp_message_from_errno (pfile, 1, name); +} + +void +cpp_message_from_errno (pfile, is_error, name) + cpp_reader *pfile; + int is_error; + const char *name; +{ + int e = errno; + cpp_buffer *ip = cpp_file_buffer (pfile); + + cpp_print_containing_files (pfile); + + if (ip != NULL) + cpp_file_line_for_message (pfile, ip->nominal_fname, ip->lineno, -1); + + cpp_message (pfile, is_error, "%s: %s", name, my_strerror (e)); +} + +void +cpp_perror_with_name (pfile, name) + cpp_reader *pfile; + const char *name; +{ + cpp_message (pfile, 1, "%s: %s: %s", progname, name, my_strerror (errno)); +} + +/* TODO: + * No pre-compiled header file support. + * + * Possibly different enum token codes for each C/C++ token. + * + * Find and cleanup remaining uses of static variables, + * + * Support for trigraphs. + * + * Support -dM flag (dump_all_macros). + * + * Support for_lint flag. + */ diff --git a/gcc_arm/cpplib.h b/gcc_arm/cpplib.h new file mode 100755 index 0000000..182246b --- /dev/null +++ b/gcc_arm/cpplib.h @@ -0,0 +1,738 @@ +/* Definitions for CPP library. + Copyright (C) 1995, 96-98, 1999 Free Software Foundation, Inc. + Written by Per Bothner, 1994-95. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ +#ifndef __GCC_CPPLIB__ +#define __GCC_CPPLIB__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned char U_CHAR; + +typedef struct cpp_reader cpp_reader; +typedef struct cpp_buffer cpp_buffer; +typedef struct cpp_options cpp_options; +typedef struct hashnode cpp_hashnode; + +enum cpp_token { + CPP_EOF = -1, + CPP_OTHER = 0, + CPP_COMMENT = 1, + CPP_HSPACE, + CPP_VSPACE, /* newlines and #line directives */ + CPP_NAME, + CPP_NUMBER, + CPP_CHAR, + CPP_STRING, + CPP_DIRECTIVE, + CPP_LPAREN, /* "(" */ + CPP_RPAREN, /* ")" */ + CPP_LBRACE, /* "{" */ + CPP_RBRACE, /* "}" */ + CPP_COMMA, /* "," */ + CPP_SEMICOLON,/* ";" */ + CPP_3DOTS, /* "..." */ +#if 0 + CPP_ANDAND, /* "&&" */ + CPP_OROR, /* "||" */ + CPP_LSH, /* "<<" */ + CPP_RSH, /* ">>" */ + CPP_EQL, /* "==" */ + CPP_NEQ, /* "!=" */ + CPP_LEQ, /* "<=" */ + CPP_GEQ, /* ">=" */ + CPP_PLPL, /* "++" */ + CPP_MINMIN, /* "--" */ +#endif + /* POP_TOKEN is returned when we've popped a cpp_buffer. */ + CPP_POP +}; + +typedef enum cpp_token (*parse_underflow_t) PARAMS((cpp_reader *)); +typedef int (*parse_cleanup_t) PARAMS((cpp_buffer *, cpp_reader *)); + +/* A parse_marker indicates a previous position, + which we can backtrack to. */ + +struct parse_marker { + cpp_buffer *buf; + struct parse_marker *next; + int position; +}; + +extern void parse_set_mark PARAMS ((struct parse_marker *, cpp_reader *)); +extern void parse_clear_mark PARAMS ((struct parse_marker *)); +extern void parse_goto_mark PARAMS((struct parse_marker *, cpp_reader *)); +extern void parse_move_mark PARAMS((struct parse_marker *, cpp_reader *)); + +extern int cpp_handle_option PARAMS ((cpp_reader *, int, char **)); +extern int cpp_handle_options PARAMS ((cpp_reader *, int, char **)); +extern enum cpp_token cpp_get_token PARAMS ((cpp_reader *)); +extern void cpp_skip_hspace PARAMS((cpp_reader *)); +extern enum cpp_token cpp_get_non_space_token PARAMS ((cpp_reader *)); + +/* This frees resources used by PFILE. */ +extern void cpp_cleanup PARAMS ((cpp_reader *PFILE)); + +/* If we have a huge buffer, may need to cache more recent counts */ +#define CPP_LINE_BASE(BUF) ((BUF)->buf + (BUF)->line_base) + +struct cpp_buffer { + unsigned char *buf; + unsigned char *cur; + unsigned char *rlimit; /* end of valid data */ + unsigned char *alimit; /* end of allocated buffer */ + unsigned char *prev; /* start of current token */ + + char *fname; + /* Filename specified with #line command. */ + char *nominal_fname; + /* Actual directory of this file, used only for "" includes */ + struct file_name_list *actual_dir; + + /* Pointer into the include hash table. Used for include_next and + to record control macros. + ->fname is an alias to ->ihash->fname. */ + struct include_hash *ihash; + + long line_base; + long lineno; /* Line number at CPP_LINE_BASE. */ + long colno; /* Column number at CPP_LINE_BASE. */ + parse_underflow_t underflow; + parse_cleanup_t cleanup; + void *data; + struct parse_marker *marks; + /* Value of if_stack at start of this file. + Used to prohibit unmatched #endif (etc) in an include file. */ + struct if_stack *if_stack; + + + /* True if this is a header file included using . */ + char system_header_p; + char seen_eof; + + /* True if buffer contains escape sequences. + Currently there are three kinds: + "@-" means following identifier should not be macro-expanded. + "@ " means a token-separator. This turns into " " in final output + if not stringizing and needed to separate tokens; otherwise nothing. + "@@" means a normal '@'. + (An '@' inside a string stands for itself and is never an escape.) */ + char has_escapes; +}; + +struct cpp_pending; /* Forward declaration - for C++. */ +struct file_name_map_list; + +/* Maximum nesting of cpp_buffers. We use a static limit, partly for + efficiency, and partly to limit runaway recursion. */ +#define CPP_STACK_MAX 200 + +/* A cpp_reader encapsulates the "state" of a pre-processor run. + Applying cpp_get_token repeatedly yields a stream of pre-processor + tokens. Usually, there is only one cpp_reader object active. */ + +struct cpp_reader +{ + parse_underflow_t get_token; + cpp_buffer *buffer; + cpp_options *opts; + + /* A buffer used for both for cpp_get_token's output, and also internally. */ + unsigned char *token_buffer; + /* Allocated size of token_buffer. CPP_RESERVE allocates space. */ + unsigned int token_buffer_size; + /* End of the written part of token_buffer. */ + unsigned char *limit; + + /* Error counter for exit code */ + int errors; + + /* Line where a newline was first seen in a string constant. */ + int multiline_string_line; + + /* Current depth in #include directives that use <...>. */ + int system_include_depth; + + /* Hash table of other included files. See cppfiles.c */ +#define ALL_INCLUDE_HASHSIZE 71 + struct include_hash *all_include_files[ALL_INCLUDE_HASHSIZE]; + + /* Chain of `actual directory' file_name_list entries, + for "" inclusion. */ + struct file_name_list *actual_dirs; + + /* Current maximum length of directory names in the search path + for include files. (Altered as we get more of them.) */ + unsigned int max_include_len; + + struct if_stack *if_stack; + + /* Nonzero means we are inside an IF during a -pcp run. In this mode + macro expansion is done, and preconditions are output for all macro + uses requiring them. */ + char pcp_inside_if; + + /* Nonzero means we have printed (while error reporting) a list of + containing files that matches the current status. */ + char input_stack_listing_current; + + /* If non-zero, macros are not expanded. */ + char no_macro_expand; + + /* Print column number in error messages. */ + char show_column; + + /* We're printed a warning recommending against using #import. */ + char import_warning; + + /* If true, character between '<' and '>' are a single (string) token. */ + char parsing_include_directive; + + /* True if escape sequences (as described for has_escapes in + parse_buffer) should be emitted. */ + char output_escapes; + + /* 0: Have seen non-white-space on this line. + 1: Only seen white space so far on this line. + 2: Only seen white space so far in this file. */ + char only_seen_white; + + /* Nonzero means this file was included with a -imacros or -include + command line and should not be recorded as an include file. */ + + int no_record_file; + + long lineno; + + struct tm *timebuf; + + /* Buffer of -M output. */ + char *deps_buffer; + + /* Number of bytes allocated in above. */ + int deps_allocated_size; + + /* Number of bytes used. */ + int deps_size; + + /* Number of bytes since the last newline. */ + int deps_column; + +#ifdef __cplusplus + ~cpp_reader () { cpp_cleanup (this); } +#endif + + cpp_buffer buffer_stack[CPP_STACK_MAX]; +}; + +#define CPP_FATAL_LIMIT 1000 +/* True if we have seen a "fatal" error. */ +#define CPP_FATAL_ERRORS(READER) ((READER)->errors >= CPP_FATAL_LIMIT) + +#define CPP_BUF_PEEK(BUFFER) \ + ((BUFFER)->cur < (BUFFER)->rlimit ? *(BUFFER)->cur : EOF) +#define CPP_BUF_GET(BUFFER) \ + ((BUFFER)->cur < (BUFFER)->rlimit ? *(BUFFER)->cur++ : EOF) +#define CPP_FORWARD(BUFFER, N) ((BUFFER)->cur += (N)) + +/* Macros for manipulating the token_buffer. */ + +#define CPP_OUT_BUFFER(PFILE) ((PFILE)->token_buffer) + +/* Number of characters currently in PFILE's output buffer. */ +#define CPP_WRITTEN(PFILE) ((size_t)((PFILE)->limit - (PFILE)->token_buffer)) +#define CPP_PWRITTEN(PFILE) ((PFILE)->limit) + +/* Make sure PFILE->token_buffer has space for at least N more characters. */ +#define CPP_RESERVE(PFILE, N) \ + (CPP_WRITTEN (PFILE) + (size_t)(N) > (PFILE)->token_buffer_size \ + && (cpp_grow_buffer (PFILE, N), 0)) + +/* Append string STR (of length N) to PFILE's output buffer. + Assume there is enough space. */ +#define CPP_PUTS_Q(PFILE, STR, N) \ + (bcopy (STR, (PFILE)->limit, (N)), (PFILE)->limit += (N)) +/* Append string STR (of length N) to PFILE's output buffer. Make space. */ +#define CPP_PUTS(PFILE, STR, N) CPP_RESERVE(PFILE, N), CPP_PUTS_Q(PFILE, STR,N) +/* Append character CH to PFILE's output buffer. Assume sufficient space. */ +#define CPP_PUTC_Q(PFILE, CH) (*(PFILE)->limit++ = (CH)) +/* Append character CH to PFILE's output buffer. Make space if need be. */ +#define CPP_PUTC(PFILE, CH) (CPP_RESERVE (PFILE, 1), CPP_PUTC_Q (PFILE, CH)) +/* Make sure PFILE->limit is followed by '\0'. */ +#define CPP_NUL_TERMINATE_Q(PFILE) (*(PFILE)->limit = 0) +#define CPP_NUL_TERMINATE(PFILE) (CPP_RESERVE(PFILE, 1), *(PFILE)->limit = 0) +#define CPP_ADJUST_WRITTEN(PFILE,DELTA) ((PFILE)->limit += (DELTA)) +#define CPP_SET_WRITTEN(PFILE,N) ((PFILE)->limit = (PFILE)->token_buffer + (N)) + +#define CPP_OPTIONS(PFILE) ((PFILE)->opts) + +#define CPP_BUFFER(PFILE) ((PFILE)->buffer) +#define CPP_PREV_BUFFER(BUFFER) ((BUFFER)+1) +/* The bottom of the buffer stack. */ +#define CPP_NULL_BUFFER(PFILE) (&(PFILE)->buffer_stack[CPP_STACK_MAX]) + +/* Pointed to by cpp_reader.opts. */ +struct cpp_options { + char *in_fname; + + /* Name of output file, for error messages. */ + char *out_fname; + + struct file_name_map_list *map_list; + + /* Non-0 means -v, so print the full set of include dirs. */ + char verbose; + + /* Nonzero means use extra default include directories for C++. */ + + char cplusplus; + + /* Nonzero means handle cplusplus style comments */ + + char cplusplus_comments; + + /* Nonzero means handle #import, for objective C. */ + + char objc; + + /* Nonzero means this is an assembly file, and allow + unknown directives, which could be comments. */ + + int lang_asm; + + /* Nonzero means turn NOTREACHED into #pragma NOTREACHED etc */ + + char for_lint; + + /* Nonzero means handle CHILL comment syntax + and output CHILL string delimiter for __DATE___ etc. */ + + char chill; + + /* Nonzero means copy comments into the output file. */ + + char put_out_comments; + + /* Nonzero means don't process the ANSI trigraph sequences. */ + + char no_trigraphs; + + /* Nonzero means print the names of included files rather than + the preprocessed output. 1 means just the #include "...", + 2 means #include <...> as well. */ + + char print_deps; + + /* Nonzero if missing .h files in -M output are assumed to be generated + files and not errors. */ + + char print_deps_missing_files; + + /* If true, fopen (deps_file, "a") else fopen (deps_file, "w"). */ + char print_deps_append; + + /* Nonzero means print names of header files (-H). */ + + char print_include_names; + + /* Nonzero means try to make failure to fit ANSI C an error. */ + + char pedantic_errors; + + /* Nonzero means don't print warning messages. -w. */ + + char inhibit_warnings; + + /* Nonzero means warn if slash-star appears in a comment. */ + + char warn_comments; + + /* Nonzero means warn if there are any trigraphs. */ + + char warn_trigraphs; + + /* Nonzero means warn if #import is used. */ + + char warn_import; + + /* Nonzero means warn if a macro argument is (or would be) + stringified with -traditional. */ + + char warn_stringify; + + /* Nonzero means turn warnings into errors. */ + + char warnings_are_errors; + + /* Nonzero causes output not to be done, + but directives such as #define that have side effects + are still obeyed. */ + + char no_output; + + /* Nonzero means we should look for header.gcc files that remap file + names. */ + char remap; + + /* Nonzero means don't output line number information. */ + + char no_line_commands; + +/* Nonzero means output the text in failing conditionals, + inside #failed ... #endfailed. */ + + char output_conditionals; + + /* Nonzero means -I- has been seen, + so don't look for #include "foo" the source-file directory. */ + char ignore_srcdir; + + /* Zero means dollar signs are punctuation. + This used to be needed for conformance to the C Standard, + before the C Standard was corrected. */ + char dollars_in_ident; + + /* Nonzero means try to imitate old fashioned non-ANSI preprocessor. */ + char traditional; + + /* Nonzero means warn if undefined identifiers are evaluated in an #if. */ + char warn_undef; + + /* Nonzero for the 1989 C Standard, including corrigenda and amendments. */ + char c89; + + /* Nonzero means give all the error messages the ANSI standard requires. */ + char pedantic; + + char done_initializing; + + /* Search paths for include files. system_include, after_include are + only used during option parsing. */ + struct file_name_list *quote_include; /* First dir to search for "file" */ + struct file_name_list *bracket_include;/* First dir to search for */ + struct file_name_list *system_include; /* First dir with system headers */ + struct file_name_list *after_include; /* Headers to search after system */ + + /* Directory prefix that should replace `/usr' in the standard + include file directories. */ + char *include_prefix; + + char inhibit_predefs; + char no_standard_includes; + char no_standard_cplusplus_includes; + +/* dump_only means inhibit output of the preprocessed text + and instead output the definitions of all user-defined + macros in a form suitable for use as input to cccp. + dump_names means pass #define and the macro name through to output. + dump_definitions means pass the whole definition (plus #define) through +*/ + + enum {dump_none = 0, dump_only, dump_names, dump_definitions} + dump_macros; + +/* Nonzero means pass all #define and #undef directives which we actually + process through to the output stream. This feature is used primarily + to allow cc1 to record the #defines and #undefs for the sake of + debuggers which understand about preprocessor macros, but it may + also be useful with -E to figure out how symbols are defined, and + where they are defined. */ + int debug_output; + + /* Nonzero means pass #include lines through to the output, + even if they are ifdefed out. */ + int dump_includes; + + /* Pending -D, -U and -A options, in reverse order. */ + struct cpp_pending *pending; + + /* File name which deps are being written to. + This is 0 if deps are being written to stdout. */ + char *deps_file; + + /* Target-name to write with the dependency information. */ + char *deps_target; +}; + +#define CPP_TRADITIONAL(PFILE) (CPP_OPTIONS(PFILE)-> traditional) +#define CPP_WARN_UNDEF(PFILE) (CPP_OPTIONS(PFILE)->warn_undef) +#define CPP_C89(PFILE) (CPP_OPTIONS(PFILE)->c89) +#define CPP_PEDANTIC(PFILE) (CPP_OPTIONS (PFILE)->pedantic) +#define CPP_PRINT_DEPS(PFILE) (CPP_OPTIONS (PFILE)->print_deps) + +/* List of directories to look for include files in. */ +struct file_name_list +{ + struct file_name_list *next; + struct file_name_list *alloc; /* for the cache of + current directory entries */ + char *name; + unsigned int nlen; + /* We use these to tell if the directory mentioned here is a duplicate + of an earlier directory on the search path. */ + ino_t ino; + dev_t dev; + /* If the following is nonzero, it is a C-language system include + directory. */ + int sysp; + /* Mapping of file names for this directory. + Only used on MS-DOS and related platforms. */ + struct file_name_map *name_map; +}; +#define ABSOLUTE_PATH ((struct file_name_list *)-1) + +/* This structure is used for the table of all includes. It is + indexed by the `short name' (the name as it appeared in the + #include statement) which is stored in *nshort. */ +struct include_hash +{ + struct include_hash *next; + /* Next file with the same short name but a + different (partial) pathname). */ + struct include_hash *next_this_file; + + /* Location of the file in the include search path. + Used for include_next */ + struct file_name_list *foundhere; + char *name; /* (partial) pathname of file */ + char *nshort; /* name of file as referenced in #include */ + char *control_macro; /* macro, if any, preventing reinclusion - see + redundant_include_p */ + char *buf, *limit; /* for file content cache, not yet implemented */ +}; + +/* If a buffer's dir field is SELF_DIR_DUMMY, it means the file was found + via the same directory as the file that #included it. */ +#define SELF_DIR_DUMMY ((struct file_name_list *) (~0)) + + +/* Name under which this program was invoked. */ + +extern char *progname; + +/* The structure of a node in the hash table. The hash table + has entries for all tokens defined by #define commands (type T_MACRO), + plus some special tokens like __LINE__ (these each have their own + type, and the appropriate code is run when that type of node is seen. + It does not contain control words like "#define", which are recognized + by a separate piece of code. */ + +/* different flavors of hash nodes --- also used in keyword table */ +enum node_type { + T_DEFINE = 1, /* the `#define' keyword */ + T_INCLUDE, /* the `#include' keyword */ + T_INCLUDE_NEXT, /* the `#include_next' keyword */ + T_IMPORT, /* the `#import' keyword */ + T_IFDEF, /* the `#ifdef' keyword */ + T_IFNDEF, /* the `#ifndef' keyword */ + T_IF, /* the `#if' keyword */ + T_ELSE, /* `#else' */ + T_PRAGMA, /* `#pragma' */ + T_ELIF, /* `#elif' */ + T_UNDEF, /* `#undef' */ + T_LINE, /* `#line' */ + T_ERROR, /* `#error' */ + T_WARNING, /* `#warning' */ + T_ENDIF, /* `#endif' */ + T_SCCS, /* `#sccs', used on system V. */ + T_IDENT, /* `#ident', used on system V. */ + T_ASSERT, /* `#assert', taken from system V. */ + T_UNASSERT, /* `#unassert', taken from system V. */ + T_SPECLINE, /* special symbol `__LINE__' */ + T_DATE, /* `__DATE__' */ + T_FILE, /* `__FILE__' */ + T_BASE_FILE, /* `__BASE_FILE__' */ + T_INCLUDE_LEVEL, /* `__INCLUDE_LEVEL__' */ + T_VERSION, /* `__VERSION__' */ + T_SIZE_TYPE, /* `__SIZE_TYPE__' */ + T_PTRDIFF_TYPE, /* `__PTRDIFF_TYPE__' */ + T_WCHAR_TYPE, /* `__WCHAR_TYPE__' */ + T_USER_LABEL_PREFIX_TYPE, /* `__USER_LABEL_PREFIX__' */ + T_REGISTER_PREFIX_TYPE, /* `__REGISTER_PREFIX__' */ + T_TIME, /* `__TIME__' */ + T_CONST, /* Constant value, used by `__STDC__' */ + T_MACRO, /* macro defined by `#define' */ + T_DISABLED, /* macro temporarily turned off for rescan */ + T_SPEC_DEFINED, /* special `defined' macro for use in #if statements */ + T_PCSTRING, /* precompiled string (hashval is KEYDEF *) */ + T_UNUSED /* Used for something not defined. */ + }; + +/* Structure returned by create_definition */ +typedef struct macrodef MACRODEF; +struct macrodef +{ + struct definition *defn; + unsigned char *symnam; + int symlen; +}; + +/* Structure allocated for every #define. For a simple replacement + such as + #define foo bar , + nargs = -1, the `pattern' list is null, and the expansion is just + the replacement text. Nargs = 0 means a functionlike macro with no args, + e.g., + #define getchar() getc (stdin) . + When there are args, the expansion is the replacement text with the + args squashed out, and the reflist is a list describing how to + build the output from the input: e.g., "3 chars, then the 1st arg, + then 9 chars, then the 3rd arg, then 0 chars, then the 2nd arg". + The chars here come from the expansion. Whatever is left of the + expansion after the last arg-occurrence is copied after that arg. + Note that the reflist can be arbitrarily long--- + its length depends on the number of times the arguments appear in + the replacement text, not how many args there are. Example: + #define f(x) x+x+x+x+x+x+x would have replacement text "++++++" and + pattern list + { (0, 1), (1, 1), (1, 1), ..., (1, 1), NULL } + where (x, y) means (nchars, argno). */ + +typedef struct definition DEFINITION; +struct definition { + int nargs; + int length; /* length of expansion string */ + int predefined; /* True if the macro was builtin or */ + /* came from the command line */ + unsigned char *expansion; + int line; /* Line number of definition */ + char *file; /* File of definition */ + char rest_args; /* Nonzero if last arg. absorbs the rest */ + struct reflist { + struct reflist *next; + char stringify; /* nonzero if this arg was preceded by a + # operator. */ + char raw_before; /* Nonzero if a ## operator before arg. */ + char raw_after; /* Nonzero if a ## operator after arg. */ + char rest_args; /* Nonzero if this arg. absorbs the rest */ + int nchars; /* Number of literal chars to copy before + this arg occurrence. */ + int argno; /* Number of arg to substitute (origin-0) */ + } *pattern; + union { + /* Names of macro args, concatenated in reverse order + with comma-space between them. + The only use of this is that we warn on redefinition + if this differs between the old and new definitions. */ + unsigned char *argnames; + } args; +}; + +extern unsigned char is_idchar[256]; +extern unsigned char is_hor_space[256]; +extern unsigned char is_space[256]; + +/* Stack of conditionals currently in progress + (including both successful and failing conditionals). */ + +struct if_stack { + struct if_stack *next; /* for chaining to the next stack frame */ + char *fname; /* copied from input when frame is made */ + int lineno; /* similarly */ + int if_succeeded; /* true if a leg of this if-group + has been passed through rescan */ + unsigned char *control_macro; /* For #ifndef at start of file, + this is the macro name tested. */ + enum node_type type; /* type of last directive seen in this group */ +}; +typedef struct if_stack IF_STACK_FRAME; + +/* Find the largest host integer type and set its size and type. + Watch out: on some crazy hosts `long' is shorter than `int'. */ + +#ifndef HOST_WIDE_INT +#include "machmode.h" +#endif + +extern void cpp_buf_line_and_col PARAMS((cpp_buffer *, long *, long *)); +extern cpp_buffer* cpp_file_buffer PARAMS((cpp_reader *)); +extern void cpp_define PARAMS ((cpp_reader*, unsigned char *)); + +extern void cpp_error PVPROTO ((cpp_reader *, const char *, ...)) + ATTRIBUTE_PRINTF_2; +extern void cpp_warning PVPROTO ((cpp_reader *, const char *, ...)) + ATTRIBUTE_PRINTF_2; +extern void cpp_pedwarn PVPROTO ((cpp_reader *, const char *, ...)) + ATTRIBUTE_PRINTF_2; +extern void cpp_error_with_line PVPROTO ((cpp_reader *, int, int, const char *, ...)) + ATTRIBUTE_PRINTF_4; +extern void cpp_pedwarn_with_line PVPROTO ((cpp_reader *, int, int, const char *, ...)) + ATTRIBUTE_PRINTF_4; +extern void cpp_pedwarn_with_file_and_line PVPROTO ((cpp_reader *, char *, int, const char *, ...)) + ATTRIBUTE_PRINTF_4; +extern void cpp_message_from_errno PROTO ((cpp_reader *, int, const char *)); +extern void cpp_error_from_errno PROTO ((cpp_reader *, const char *)); +extern void cpp_perror_with_name PROTO ((cpp_reader *, const char *)); +extern void v_cpp_message PROTO ((cpp_reader *, int, const char *, va_list)); + +extern void cpp_grow_buffer PARAMS ((cpp_reader *, long)); +extern HOST_WIDE_INT cpp_parse_escape PARAMS ((cpp_reader *, char **, HOST_WIDE_INT)); +extern cpp_buffer *cpp_push_buffer PARAMS ((cpp_reader *, + unsigned char *, long)); +extern cpp_buffer *cpp_pop_buffer PARAMS ((cpp_reader *)); + +extern cpp_hashnode *cpp_lookup PARAMS ((cpp_reader *, const unsigned char *, + int, int)); +extern void cpp_reader_init PARAMS ((cpp_reader *)); +extern void cpp_options_init PARAMS ((cpp_options *)); +extern int cpp_start_read PARAMS ((cpp_reader *, char *)); +extern int cpp_read_check_assertion PARAMS ((cpp_reader *)); +extern int scan_decls PARAMS ((cpp_reader *, int, char **)); +extern void skip_rest_of_line PARAMS ((cpp_reader *)); +extern void cpp_finish PARAMS ((cpp_reader *)); + +/* From cpperror.c */ +extern void cpp_fatal PVPROTO ((cpp_reader *, const char *, ...)) + ATTRIBUTE_PRINTF_2; +extern void cpp_message PVPROTO ((cpp_reader *, int, const char *, ...)) + ATTRIBUTE_PRINTF_3; +extern void cpp_pfatal_with_name PROTO ((cpp_reader *, const char *)); +extern void cpp_file_line_for_message PROTO ((cpp_reader *, char *, int, int)); +extern void cpp_print_containing_files PROTO ((cpp_reader *)); + +/* In cppfiles.c */ +extern void append_include_chain PROTO ((cpp_reader *, + struct file_name_list **, + const char *, int)); +extern void merge_include_chains PROTO ((struct cpp_options *)); +extern int find_include_file PROTO ((cpp_reader *, char *, + struct file_name_list *, + struct include_hash **, + int *)); +extern int finclude PROTO ((cpp_reader *, int, + struct include_hash *)); +extern void deps_output PROTO ((cpp_reader *, char *, int)); +extern struct include_hash *include_hash PROTO ((cpp_reader *, char *, int)); + +#ifndef INCLUDE_LEN_FUDGE +#define INCLUDE_LEN_FUDGE 0 +#endif + + +#ifdef __cplusplus +} +#endif +#endif /* __GCC_CPPLIB__ */ + diff --git a/gcc_arm/cppmain.c b/gcc_arm/cppmain.c new file mode 100755 index 0000000..672c0f4 --- /dev/null +++ b/gcc_arm/cppmain.c @@ -0,0 +1,112 @@ +/* CPP main program, using CPP Library. + Copyright (C) 1995, 1997, 1998 Free Software Foundation, Inc. + Written by Per Bothner, 1994-95. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +#ifndef EMACS +#include "config.h" +#include "system.h" +#else +#include + +extern char *getenv (); +#endif /* not EMACS */ + +#include "cpplib.h" + +char *progname; + +cpp_reader parse_in; +cpp_options options; + +#ifdef abort +/* More 'friendly' abort that prints the line and file. + config.h can #define abort fancy_abort if you like that sort of thing. */ +void +fatal (s) + char *s; +{ + fputs (s, stderr); + exit (FATAL_EXIT_CODE); +} + +void +fancy_abort () +{ + fatal ("Internal gcc abort."); +} +#endif + + +int +main (argc, argv) + int argc; + char **argv; +{ + char *p; + int argi = 1; /* Next argument to handle. */ + struct cpp_options *opts = &options; + + p = argv[0] + strlen (argv[0]); + while (p != argv[0] && p[-1] != '/') --p; + progname = p; + + cpp_reader_init (&parse_in); + parse_in.opts = opts; + + cpp_options_init (opts); + + argi += cpp_handle_options (&parse_in, argc - argi , argv + argi); + if (argi < argc && ! CPP_FATAL_ERRORS (&parse_in)) + cpp_fatal (&parse_in, "Invalid option `%s'", argv[argi]); + if (CPP_FATAL_ERRORS (&parse_in)) + exit (FATAL_EXIT_CODE); + + parse_in.show_column = 1; + + if (! cpp_start_read (&parse_in, opts->in_fname)) + exit (FATAL_EXIT_CODE); + + /* Now that we know the input file is valid, open the output. */ + + if (!opts->out_fname || !strcmp (opts->out_fname, "")) + opts->out_fname = "stdout"; + else if (! freopen (opts->out_fname, "w", stdout)) + cpp_pfatal_with_name (&parse_in, opts->out_fname); + + for (;;) + { + enum cpp_token kind; + if (! opts->no_output) + { + fwrite (parse_in.token_buffer, 1, CPP_WRITTEN (&parse_in), stdout); + } + CPP_SET_WRITTEN (&parse_in, 0); + kind = cpp_get_token (&parse_in); + if (kind == CPP_EOF) + break; + } + + cpp_finish (&parse_in); + + if (parse_in.errors) + exit (FATAL_EXIT_CODE); + exit (SUCCESS_EXIT_CODE); +} diff --git a/gcc_arm/cppulp.c b/gcc_arm/cppulp.c new file mode 100755 index 0000000..eb6e7f6 --- /dev/null +++ b/gcc_arm/cppulp.c @@ -0,0 +1,26 @@ +/* CPP Library. + Copyright (C) 1986, 87, 89, 92-97, 1998 Free Software Foundation, Inc. + Contributed by Per Bothner, 1994-95. + Based on CCCP program by Paul Rubin, June 1986 + Adapted to ANSI C, Richard Stallman, Jan 1987 + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" + +#include "output.h" + +char *user_label_prefix = 0; diff --git a/gcc_arm/cross-make b/gcc_arm/cross-make new file mode 100755 index 0000000..84be67f --- /dev/null +++ b/gcc_arm/cross-make @@ -0,0 +1,14 @@ +# Build libgcc1.a for a cross-compiler. +# By default this expects the user to provide libgcc1.a, +# and gives up immediately if the user has not done so. +LIBGCC1 = $(CROSS_LIBGCC1) + +# Dir to search for system headers. Normally /usr/include. +# Use CROSS_INCLUDE_DIR not TOOL_INCLUDE_DIR for other vendor's headers. +SYSTEM_HEADER_DIR = $(tooldir)/sys-include + +# Don't try to compile the things we can't compile. +ALL = all.cross + +# Don't install assert.h in /usr/local/include. +assertdir = $(tooldir)/include diff --git a/gcc_arm/cse.c b/gcc_arm/cse.c new file mode 100755 index 0000000..95b56ea --- /dev/null +++ b/gcc_arm/cse.c @@ -0,0 +1,9170 @@ +/* Common subexpression elimination for GNU compiler. + Copyright (C) 1987, 88, 89, 92-7, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include "config.h" +/* stdio.h must precede rtl.h for FFS. */ +#include "system.h" +#include + +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "flags.h" +#include "real.h" +#include "insn-config.h" +#include "recog.h" +#include "expr.h" +#include "toplev.h" +#include "output.h" + +/* The basic idea of common subexpression elimination is to go + through the code, keeping a record of expressions that would + have the same value at the current scan point, and replacing + expressions encountered with the cheapest equivalent expression. + + It is too complicated to keep track of the different possibilities + when control paths merge; so, at each label, we forget all that is + known and start fresh. This can be described as processing each + basic block separately. Note, however, that these are not quite + the same as the basic blocks found by a later pass and used for + data flow analysis and register packing. We do not need to start fresh + after a conditional jump instruction if there is no label there. + + We use two data structures to record the equivalent expressions: + a hash table for most expressions, and several vectors together + with "quantity numbers" to record equivalent (pseudo) registers. + + The use of the special data structure for registers is desirable + because it is faster. It is possible because registers references + contain a fairly small number, the register number, taken from + a contiguously allocated series, and two register references are + identical if they have the same number. General expressions + do not have any such thing, so the only way to retrieve the + information recorded on an expression other than a register + is to keep it in a hash table. + +Registers and "quantity numbers": + + At the start of each basic block, all of the (hardware and pseudo) + registers used in the function are given distinct quantity + numbers to indicate their contents. During scan, when the code + copies one register into another, we copy the quantity number. + When a register is loaded in any other way, we allocate a new + quantity number to describe the value generated by this operation. + `reg_qty' records what quantity a register is currently thought + of as containing. + + All real quantity numbers are greater than or equal to `max_reg'. + If register N has not been assigned a quantity, reg_qty[N] will equal N. + + Quantity numbers below `max_reg' do not exist and none of the `qty_...' + variables should be referenced with an index below `max_reg'. + + We also maintain a bidirectional chain of registers for each + quantity number. `qty_first_reg', `qty_last_reg', + `reg_next_eqv' and `reg_prev_eqv' hold these chains. + + The first register in a chain is the one whose lifespan is least local. + Among equals, it is the one that was seen first. + We replace any equivalent register with that one. + + If two registers have the same quantity number, it must be true that + REG expressions with `qty_mode' must be in the hash table for both + registers and must be in the same class. + + The converse is not true. Since hard registers may be referenced in + any mode, two REG expressions might be equivalent in the hash table + but not have the same quantity number if the quantity number of one + of the registers is not the same mode as those expressions. + +Constants and quantity numbers + + When a quantity has a known constant value, that value is stored + in the appropriate element of qty_const. This is in addition to + putting the constant in the hash table as is usual for non-regs. + + Whether a reg or a constant is preferred is determined by the configuration + macro CONST_COSTS and will often depend on the constant value. In any + event, expressions containing constants can be simplified, by fold_rtx. + + When a quantity has a known nearly constant value (such as an address + of a stack slot), that value is stored in the appropriate element + of qty_const. + + Integer constants don't have a machine mode. However, cse + determines the intended machine mode from the destination + of the instruction that moves the constant. The machine mode + is recorded in the hash table along with the actual RTL + constant expression so that different modes are kept separate. + +Other expressions: + + To record known equivalences among expressions in general + we use a hash table called `table'. It has a fixed number of buckets + that contain chains of `struct table_elt' elements for expressions. + These chains connect the elements whose expressions have the same + hash codes. + + Other chains through the same elements connect the elements which + currently have equivalent values. + + Register references in an expression are canonicalized before hashing + the expression. This is done using `reg_qty' and `qty_first_reg'. + The hash code of a register reference is computed using the quantity + number, not the register number. + + When the value of an expression changes, it is necessary to remove from the + hash table not just that expression but all expressions whose values + could be different as a result. + + 1. If the value changing is in memory, except in special cases + ANYTHING referring to memory could be changed. That is because + nobody knows where a pointer does not point. + The function `invalidate_memory' removes what is necessary. + + The special cases are when the address is constant or is + a constant plus a fixed register such as the frame pointer + or a static chain pointer. When such addresses are stored in, + we can tell exactly which other such addresses must be invalidated + due to overlap. `invalidate' does this. + All expressions that refer to non-constant + memory addresses are also invalidated. `invalidate_memory' does this. + + 2. If the value changing is a register, all expressions + containing references to that register, and only those, + must be removed. + + Because searching the entire hash table for expressions that contain + a register is very slow, we try to figure out when it isn't necessary. + Precisely, this is necessary only when expressions have been + entered in the hash table using this register, and then the value has + changed, and then another expression wants to be added to refer to + the register's new value. This sequence of circumstances is rare + within any one basic block. + + The vectors `reg_tick' and `reg_in_table' are used to detect this case. + reg_tick[i] is incremented whenever a value is stored in register i. + reg_in_table[i] holds -1 if no references to register i have been + entered in the table; otherwise, it contains the value reg_tick[i] had + when the references were entered. If we want to enter a reference + and reg_in_table[i] != reg_tick[i], we must scan and remove old references. + Until we want to enter a new entry, the mere fact that the two vectors + don't match makes the entries be ignored if anyone tries to match them. + + Registers themselves are entered in the hash table as well as in + the equivalent-register chains. However, the vectors `reg_tick' + and `reg_in_table' do not apply to expressions which are simple + register references. These expressions are removed from the table + immediately when they become invalid, and this can be done even if + we do not immediately search for all the expressions that refer to + the register. + + A CLOBBER rtx in an instruction invalidates its operand for further + reuse. A CLOBBER or SET rtx whose operand is a MEM:BLK + invalidates everything that resides in memory. + +Related expressions: + + Constant expressions that differ only by an additive integer + are called related. When a constant expression is put in + the table, the related expression with no constant term + is also entered. These are made to point at each other + so that it is possible to find out if there exists any + register equivalent to an expression related to a given expression. */ + +/* One plus largest register number used in this function. */ + +static int max_reg; + +/* One plus largest instruction UID used in this function at time of + cse_main call. */ + +static int max_insn_uid; + +/* Length of vectors indexed by quantity number. + We know in advance we will not need a quantity number this big. */ + +static int max_qty; + +/* Next quantity number to be allocated. + This is 1 + the largest number needed so far. */ + +static int next_qty; + +/* Indexed by quantity number, gives the first (or last) register + in the chain of registers that currently contain this quantity. */ + +static int *qty_first_reg; +static int *qty_last_reg; + +/* Index by quantity number, gives the mode of the quantity. */ + +static enum machine_mode *qty_mode; + +/* Indexed by quantity number, gives the rtx of the constant value of the + quantity, or zero if it does not have a known value. + A sum of the frame pointer (or arg pointer) plus a constant + can also be entered here. */ + +static rtx *qty_const; + +/* Indexed by qty number, gives the insn that stored the constant value + recorded in `qty_const'. */ + +static rtx *qty_const_insn; + +/* The next three variables are used to track when a comparison between a + quantity and some constant or register has been passed. In that case, we + know the results of the comparison in case we see it again. These variables + record a comparison that is known to be true. */ + +/* Indexed by qty number, gives the rtx code of a comparison with a known + result involving this quantity. If none, it is UNKNOWN. */ +static enum rtx_code *qty_comparison_code; + +/* Indexed by qty number, gives the constant being compared against in a + comparison of known result. If no such comparison, it is undefined. + If the comparison is not with a constant, it is zero. */ + +static rtx *qty_comparison_const; + +/* Indexed by qty number, gives the quantity being compared against in a + comparison of known result. If no such comparison, if it undefined. + If the comparison is not with a register, it is -1. */ + +static int *qty_comparison_qty; + +#ifdef HAVE_cc0 +/* For machines that have a CC0, we do not record its value in the hash + table since its use is guaranteed to be the insn immediately following + its definition and any other insn is presumed to invalidate it. + + Instead, we store below the value last assigned to CC0. If it should + happen to be a constant, it is stored in preference to the actual + assigned value. In case it is a constant, we store the mode in which + the constant should be interpreted. */ + +static rtx prev_insn_cc0; +static enum machine_mode prev_insn_cc0_mode; +#endif + +/* Previous actual insn. 0 if at first insn of basic block. */ + +static rtx prev_insn; + +/* Insn being scanned. */ + +static rtx this_insn; + +/* Index by register number, gives the quantity number + of the register's current contents. */ + +static int *reg_qty; + +/* Index by register number, gives the number of the next (or + previous) register in the chain of registers sharing the same + value. + + Or -1 if this register is at the end of the chain. + + If reg_qty[N] == N, reg_next_eqv[N] is undefined. */ + +static int *reg_next_eqv; +static int *reg_prev_eqv; + +/* Index by register number, gives the number of times + that register has been altered in the current basic block. */ + +static int *reg_tick; + +/* Index by register number, gives the reg_tick value at which + rtx's containing this register are valid in the hash table. + If this does not equal the current reg_tick value, such expressions + existing in the hash table are invalid. + If this is -1, no expressions containing this register have been + entered in the table. */ + +static int *reg_in_table; + +/* A HARD_REG_SET containing all the hard registers for which there is + currently a REG expression in the hash table. Note the difference + from the above variables, which indicate if the REG is mentioned in some + expression in the table. */ + +static HARD_REG_SET hard_regs_in_table; + +/* A HARD_REG_SET containing all the hard registers that are invalidated + by a CALL_INSN. */ + +static HARD_REG_SET regs_invalidated_by_call; + +/* Two vectors of ints: + one containing max_reg -1's; the other max_reg + 500 (an approximation + for max_qty) elements where element i contains i. + These are used to initialize various other vectors fast. */ + +static int *all_minus_one; +static int *consec_ints; + +/* CUID of insn that starts the basic block currently being cse-processed. */ + +static int cse_basic_block_start; + +/* CUID of insn that ends the basic block currently being cse-processed. */ + +static int cse_basic_block_end; + +/* Vector mapping INSN_UIDs to cuids. + The cuids are like uids but increase monotonically always. + We use them to see whether a reg is used outside a given basic block. */ + +static int *uid_cuid; + +/* Highest UID in UID_CUID. */ +static int max_uid; + +/* Get the cuid of an insn. */ + +#define INSN_CUID(INSN) (uid_cuid[INSN_UID (INSN)]) + +/* Nonzero if cse has altered conditional jump insns + in such a way that jump optimization should be redone. */ + +static int cse_jumps_altered; + +/* Nonzero if we put a LABEL_REF into the hash table. Since we may have put + it into an INSN without a REG_LABEL, we have to rerun jump after CSE + to put in the note. */ +static int recorded_label_ref; + +/* canon_hash stores 1 in do_not_record + if it notices a reference to CC0, PC, or some other volatile + subexpression. */ + +static int do_not_record; + +#ifdef LOAD_EXTEND_OP + +/* Scratch rtl used when looking for load-extended copy of a MEM. */ +static rtx memory_extend_rtx; +#endif + +/* canon_hash stores 1 in hash_arg_in_memory + if it notices a reference to memory within the expression being hashed. */ + +static int hash_arg_in_memory; + +/* canon_hash stores 1 in hash_arg_in_struct + if it notices a reference to memory that's part of a structure. */ + +static int hash_arg_in_struct; + +/* The hash table contains buckets which are chains of `struct table_elt's, + each recording one expression's information. + That expression is in the `exp' field. + + Those elements with the same hash code are chained in both directions + through the `next_same_hash' and `prev_same_hash' fields. + + Each set of expressions with equivalent values + are on a two-way chain through the `next_same_value' + and `prev_same_value' fields, and all point with + the `first_same_value' field at the first element in + that chain. The chain is in order of increasing cost. + Each element's cost value is in its `cost' field. + + The `in_memory' field is nonzero for elements that + involve any reference to memory. These elements are removed + whenever a write is done to an unidentified location in memory. + To be safe, we assume that a memory address is unidentified unless + the address is either a symbol constant or a constant plus + the frame pointer or argument pointer. + + The `in_struct' field is nonzero for elements that + involve any reference to memory inside a structure or array. + + The `related_value' field is used to connect related expressions + (that differ by adding an integer). + The related expressions are chained in a circular fashion. + `related_value' is zero for expressions for which this + chain is not useful. + + The `cost' field stores the cost of this element's expression. + + The `is_const' flag is set if the element is a constant (including + a fixed address). + + The `flag' field is used as a temporary during some search routines. + + The `mode' field is usually the same as GET_MODE (`exp'), but + if `exp' is a CONST_INT and has no machine mode then the `mode' + field is the mode it was being used as. Each constant is + recorded separately for each mode it is used with. */ + + +struct table_elt +{ + rtx exp; + struct table_elt *next_same_hash; + struct table_elt *prev_same_hash; + struct table_elt *next_same_value; + struct table_elt *prev_same_value; + struct table_elt *first_same_value; + struct table_elt *related_value; + int cost; + enum machine_mode mode; + char in_memory; + char in_struct; + char is_const; + char flag; +}; + +/* We don't want a lot of buckets, because we rarely have very many + things stored in the hash table, and a lot of buckets slows + down a lot of loops that happen frequently. */ +#define NBUCKETS 31 + +/* Compute hash code of X in mode M. Special-case case where X is a pseudo + register (hard registers may require `do_not_record' to be set). */ + +#define HASH(X, M) \ + (GET_CODE (X) == REG && REGNO (X) >= FIRST_PSEUDO_REGISTER \ + ? (((unsigned) REG << 7) + (unsigned) reg_qty[REGNO (X)]) % NBUCKETS \ + : canon_hash (X, M) % NBUCKETS) + +/* Determine whether register number N is considered a fixed register for CSE. + It is desirable to replace other regs with fixed regs, to reduce need for + non-fixed hard regs. + A reg wins if it is either the frame pointer or designated as fixed, + but not if it is an overlapping register. */ +#ifdef OVERLAPPING_REGNO_P +#define FIXED_REGNO_P(N) \ + (((N) == FRAME_POINTER_REGNUM || (N) == HARD_FRAME_POINTER_REGNUM \ + || fixed_regs[N] || global_regs[N]) \ + && ! OVERLAPPING_REGNO_P ((N))) +#else +#define FIXED_REGNO_P(N) \ + ((N) == FRAME_POINTER_REGNUM || (N) == HARD_FRAME_POINTER_REGNUM \ + || fixed_regs[N] || global_regs[N]) +#endif + +/* Compute cost of X, as stored in the `cost' field of a table_elt. Fixed + hard registers and pointers into the frame are the cheapest with a cost + of 0. Next come pseudos with a cost of one and other hard registers with + a cost of 2. Aside from these special cases, call `rtx_cost'. */ + +#define CHEAP_REGNO(N) \ + ((N) == FRAME_POINTER_REGNUM || (N) == HARD_FRAME_POINTER_REGNUM \ + || (N) == STACK_POINTER_REGNUM || (N) == ARG_POINTER_REGNUM \ + || ((N) >= FIRST_VIRTUAL_REGISTER && (N) <= LAST_VIRTUAL_REGISTER) \ + || ((N) < FIRST_PSEUDO_REGISTER \ + && FIXED_REGNO_P (N) && REGNO_REG_CLASS (N) != NO_REGS)) + +/* A register is cheap if it is a user variable assigned to the register + or if its register number always corresponds to a cheap register. */ + +#define CHEAP_REG(N) \ + ((REG_USERVAR_P (N) && REGNO (N) < FIRST_PSEUDO_REGISTER) \ + || CHEAP_REGNO (REGNO (N))) + +#define COST(X) \ + (GET_CODE (X) == REG \ + ? (CHEAP_REG (X) ? 0 \ + : REGNO (X) >= FIRST_PSEUDO_REGISTER ? 1 \ + : 2) \ + : notreg_cost(X)) + +/* Determine if the quantity number for register X represents a valid index + into the `qty_...' variables. */ + +#define REGNO_QTY_VALID_P(N) (reg_qty[N] != (N)) + +#ifdef ADDRESS_COST +/* The ADDRESS_COST macro does not deal with ADDRESSOF nodes. But, + during CSE, such nodes are present. Using an ADDRESSOF node which + refers to the address of a REG is a good thing because we can then + turn (MEM (ADDRESSSOF (REG))) into just plain REG. */ +#define CSE_ADDRESS_COST(RTX) \ + ((GET_CODE (RTX) == ADDRESSOF && REG_P (XEXP ((RTX), 0))) \ + ? -1 : ADDRESS_COST(RTX)) +#endif + +static struct table_elt *table[NBUCKETS]; + +/* Chain of `struct table_elt's made so far for this function + but currently removed from the table. */ + +static struct table_elt *free_element_chain; + +/* Number of `struct table_elt' structures made so far for this function. */ + +static int n_elements_made; + +/* Maximum value `n_elements_made' has had so far in this compilation + for functions previously processed. */ + +static int max_elements_made; + +/* Surviving equivalence class when two equivalence classes are merged + by recording the effects of a jump in the last insn. Zero if the + last insn was not a conditional jump. */ + +static struct table_elt *last_jump_equiv_class; + +/* Set to the cost of a constant pool reference if one was found for a + symbolic constant. If this was found, it means we should try to + convert constants into constant pool entries if they don't fit in + the insn. */ + +static int constant_pool_entries_cost; + +/* Define maximum length of a branch path. */ + +#define PATHLENGTH 10 + +/* This data describes a block that will be processed by cse_basic_block. */ + +struct cse_basic_block_data { + /* Lowest CUID value of insns in block. */ + int low_cuid; + /* Highest CUID value of insns in block. */ + int high_cuid; + /* Total number of SETs in block. */ + int nsets; + /* Last insn in the block. */ + rtx last; + /* Size of current branch path, if any. */ + int path_size; + /* Current branch path, indicating which branches will be taken. */ + struct branch_path { + /* The branch insn. */ + rtx branch; + /* Whether it should be taken or not. AROUND is the same as taken + except that it is used when the destination label is not preceded + by a BARRIER. */ + enum taken {TAKEN, NOT_TAKEN, AROUND} status; + } path[PATHLENGTH]; +}; + +/* Nonzero if X has the form (PLUS frame-pointer integer). We check for + virtual regs here because the simplify_*_operation routines are called + by integrate.c, which is called before virtual register instantiation. */ + +#define FIXED_BASE_PLUS_P(X) \ + ((X) == frame_pointer_rtx || (X) == hard_frame_pointer_rtx \ + || (X) == arg_pointer_rtx \ + || (X) == virtual_stack_vars_rtx \ + || (X) == virtual_incoming_args_rtx \ + || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (XEXP (X, 0) == frame_pointer_rtx \ + || XEXP (X, 0) == hard_frame_pointer_rtx \ + || XEXP (X, 0) == arg_pointer_rtx \ + || XEXP (X, 0) == virtual_stack_vars_rtx \ + || XEXP (X, 0) == virtual_incoming_args_rtx)) \ + || GET_CODE (X) == ADDRESSOF) + +/* Similar, but also allows reference to the stack pointer. + + This used to include FIXED_BASE_PLUS_P, however, we can't assume that + arg_pointer_rtx by itself is nonzero, because on at least one machine, + the i960, the arg pointer is zero when it is unused. */ + +#define NONZERO_BASE_PLUS_P(X) \ + ((X) == frame_pointer_rtx || (X) == hard_frame_pointer_rtx \ + || (X) == virtual_stack_vars_rtx \ + || (X) == virtual_incoming_args_rtx \ + || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (XEXP (X, 0) == frame_pointer_rtx \ + || XEXP (X, 0) == hard_frame_pointer_rtx \ + || XEXP (X, 0) == arg_pointer_rtx \ + || XEXP (X, 0) == virtual_stack_vars_rtx \ + || XEXP (X, 0) == virtual_incoming_args_rtx)) \ + || (X) == stack_pointer_rtx \ + || (X) == virtual_stack_dynamic_rtx \ + || (X) == virtual_outgoing_args_rtx \ + || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (XEXP (X, 0) == stack_pointer_rtx \ + || XEXP (X, 0) == virtual_stack_dynamic_rtx \ + || XEXP (X, 0) == virtual_outgoing_args_rtx)) \ + || GET_CODE (X) == ADDRESSOF) + +static int notreg_cost PROTO((rtx)); +static void new_basic_block PROTO((void)); +static void make_new_qty PROTO((int)); +static void make_regs_eqv PROTO((int, int)); +static void delete_reg_equiv PROTO((int)); +static int mention_regs PROTO((rtx)); +static int insert_regs PROTO((rtx, struct table_elt *, int)); +static void free_element PROTO((struct table_elt *)); +static void remove_from_table PROTO((struct table_elt *, unsigned)); +static struct table_elt *get_element PROTO((void)); +static struct table_elt *lookup PROTO((rtx, unsigned, enum machine_mode)), + *lookup_for_remove PROTO((rtx, unsigned, enum machine_mode)); +static rtx lookup_as_function PROTO((rtx, enum rtx_code)); +static struct table_elt *insert PROTO((rtx, struct table_elt *, unsigned, + enum machine_mode)); +static void merge_equiv_classes PROTO((struct table_elt *, + struct table_elt *)); +static void invalidate PROTO((rtx, enum machine_mode)); +static int cse_rtx_varies_p PROTO((rtx)); +static void remove_invalid_refs PROTO((int)); +static void remove_invalid_subreg_refs PROTO((int, int, enum machine_mode)); +static void rehash_using_reg PROTO((rtx)); +static void invalidate_memory PROTO((void)); +static void invalidate_for_call PROTO((void)); +static rtx use_related_value PROTO((rtx, struct table_elt *)); +static unsigned canon_hash PROTO((rtx, enum machine_mode)); +static unsigned safe_hash PROTO((rtx, enum machine_mode)); +static int exp_equiv_p PROTO((rtx, rtx, int, int)); +static void set_nonvarying_address_components PROTO((rtx, int, rtx *, + HOST_WIDE_INT *, + HOST_WIDE_INT *)); +static int refers_to_p PROTO((rtx, rtx)); +static rtx canon_reg PROTO((rtx, rtx)); +static void find_best_addr PROTO((rtx, rtx *)); +static enum rtx_code find_comparison_args PROTO((enum rtx_code, rtx *, rtx *, + enum machine_mode *, + enum machine_mode *)); +static rtx cse_gen_binary PROTO((enum rtx_code, enum machine_mode, + rtx, rtx)); +static rtx simplify_plus_minus PROTO((enum rtx_code, enum machine_mode, + rtx, rtx)); +static rtx fold_rtx PROTO((rtx, rtx)); +static rtx equiv_constant PROTO((rtx)); +static void record_jump_equiv PROTO((rtx, int)); +static void record_jump_cond PROTO((enum rtx_code, enum machine_mode, + rtx, rtx, int)); +static void cse_insn PROTO((rtx, rtx)); +static int note_mem_written PROTO((rtx)); +static void invalidate_from_clobbers PROTO((rtx)); +static rtx cse_process_notes PROTO((rtx, rtx)); +static void cse_around_loop PROTO((rtx)); +static void invalidate_skipped_set PROTO((rtx, rtx)); +static void invalidate_skipped_block PROTO((rtx)); +static void cse_check_loop_start PROTO((rtx, rtx)); +static void cse_set_around_loop PROTO((rtx, rtx, rtx)); +static rtx cse_basic_block PROTO((rtx, rtx, struct branch_path *, int)); +static void count_reg_usage PROTO((rtx, int *, rtx, int)); + +extern int rtx_equal_function_value_matters; + +/* Return an estimate of the cost of computing rtx X. + One use is in cse, to decide which expression to keep in the hash table. + Another is in rtl generation, to pick the cheapest way to multiply. + Other uses like the latter are expected in the future. */ + +/* Internal function, to compute cost when X is not a register; called + from COST macro to keep it simple. */ + +static int +notreg_cost (x) + rtx x; +{ + return ((GET_CODE (x) == SUBREG + && GET_CODE (SUBREG_REG (x)) == REG + && GET_MODE_CLASS (GET_MODE (x)) == MODE_INT + && GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_INT + && (GET_MODE_SIZE (GET_MODE (x)) + < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) + && subreg_lowpart_p (x) + && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE (x)), + GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))))) + ? (CHEAP_REG (SUBREG_REG (x)) ? 0 + : (REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER ? 1 + : 2)) + : rtx_cost (x, SET) * 2); +} + +/* Return the right cost to give to an operation + to make the cost of the corresponding register-to-register instruction + N times that of a fast register-to-register instruction. */ + +#define COSTS_N_INSNS(N) ((N) * 4 - 2) + +int +rtx_cost (x, outer_code) + rtx x; + enum rtx_code outer_code ATTRIBUTE_UNUSED; +{ + register int i, j; + register enum rtx_code code; + register char *fmt; + register int total; + + if (x == 0) + return 0; + + /* Compute the default costs of certain things. + Note that RTX_COSTS can override the defaults. */ + + code = GET_CODE (x); + switch (code) + { + case MULT: + /* Count multiplication by 2**n as a shift, + because if we are considering it, we would output it as a shift. */ + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && exact_log2 (INTVAL (XEXP (x, 1))) >= 0) + total = 2; + else + total = COSTS_N_INSNS (5); + break; + case DIV: + case UDIV: + case MOD: + case UMOD: + total = COSTS_N_INSNS (7); + break; + case USE: + /* Used in loop.c and combine.c as a marker. */ + total = 0; + break; + case ASM_OPERANDS: + /* We don't want these to be used in substitutions because + we have no way of validating the resulting insn. So assign + anything containing an ASM_OPERANDS a very high cost. */ + total = 1000; + break; + default: + total = 2; + } + + switch (code) + { + case REG: + return ! CHEAP_REG (x); + + case SUBREG: + /* If we can't tie these modes, make this expensive. The larger + the mode, the more expensive it is. */ + if (! MODES_TIEABLE_P (GET_MODE (x), GET_MODE (SUBREG_REG (x)))) + return COSTS_N_INSNS (2 + + GET_MODE_SIZE (GET_MODE (x)) / UNITS_PER_WORD); + return 2; +#ifdef RTX_COSTS + RTX_COSTS (x, code, outer_code); +#endif +#ifdef CONST_COSTS + CONST_COSTS (x, code, outer_code); +#endif + + default: +#ifdef DEFAULT_RTX_COSTS + DEFAULT_RTX_COSTS(x, code, outer_code); +#endif + break; + } + + /* Sum the costs of the sub-rtx's, plus cost of this operation, + which is already in total. */ + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + if (fmt[i] == 'e') + total += rtx_cost (XEXP (x, i), code); + else if (fmt[i] == 'E') + for (j = 0; j < XVECLEN (x, i); j++) + total += rtx_cost (XVECEXP (x, i, j), code); + + return total; +} + +/* Clear the hash table and initialize each register with its own quantity, + for a new basic block. */ + +static void +new_basic_block () +{ + register int i; + + next_qty = max_reg; + + bzero ((char *) reg_tick, max_reg * sizeof (int)); + + bcopy ((char *) all_minus_one, (char *) reg_in_table, + max_reg * sizeof (int)); + bcopy ((char *) consec_ints, (char *) reg_qty, max_reg * sizeof (int)); + CLEAR_HARD_REG_SET (hard_regs_in_table); + + /* The per-quantity values used to be initialized here, but it is + much faster to initialize each as it is made in `make_new_qty'. */ + + for (i = 0; i < NBUCKETS; i++) + { + register struct table_elt *this, *next; + for (this = table[i]; this; this = next) + { + next = this->next_same_hash; + free_element (this); + } + } + + bzero ((char *) table, sizeof table); + + prev_insn = 0; + +#ifdef HAVE_cc0 + prev_insn_cc0 = 0; +#endif +} + +/* Say that register REG contains a quantity not in any register before + and initialize that quantity. */ + +static void +make_new_qty (reg) + register int reg; +{ + register int q; + + if (next_qty >= max_qty) + abort (); + + q = reg_qty[reg] = next_qty++; + qty_first_reg[q] = reg; + qty_last_reg[q] = reg; + qty_const[q] = qty_const_insn[q] = 0; + qty_comparison_code[q] = UNKNOWN; + + reg_next_eqv[reg] = reg_prev_eqv[reg] = -1; +} + +/* Make reg NEW equivalent to reg OLD. + OLD is not changing; NEW is. */ + +static void +make_regs_eqv (new, old) + register int new, old; +{ + register int lastr, firstr; + register int q = reg_qty[old]; + + /* Nothing should become eqv until it has a "non-invalid" qty number. */ + if (! REGNO_QTY_VALID_P (old)) + abort (); + + reg_qty[new] = q; + firstr = qty_first_reg[q]; + lastr = qty_last_reg[q]; + + /* Prefer fixed hard registers to anything. Prefer pseudo regs to other + hard regs. Among pseudos, if NEW will live longer than any other reg + of the same qty, and that is beyond the current basic block, + make it the new canonical replacement for this qty. */ + if (! (firstr < FIRST_PSEUDO_REGISTER && FIXED_REGNO_P (firstr)) + /* Certain fixed registers might be of the class NO_REGS. This means + that not only can they not be allocated by the compiler, but + they cannot be used in substitutions or canonicalizations + either. */ + && (new >= FIRST_PSEUDO_REGISTER || REGNO_REG_CLASS (new) != NO_REGS) + && ((new < FIRST_PSEUDO_REGISTER && FIXED_REGNO_P (new)) + || (new >= FIRST_PSEUDO_REGISTER + && (firstr < FIRST_PSEUDO_REGISTER + || ((uid_cuid[REGNO_LAST_UID (new)] > cse_basic_block_end + || (uid_cuid[REGNO_FIRST_UID (new)] + < cse_basic_block_start)) + && (uid_cuid[REGNO_LAST_UID (new)] + > uid_cuid[REGNO_LAST_UID (firstr)])))))) + { + reg_prev_eqv[firstr] = new; + reg_next_eqv[new] = firstr; + reg_prev_eqv[new] = -1; + qty_first_reg[q] = new; + } + else + { + /* If NEW is a hard reg (known to be non-fixed), insert at end. + Otherwise, insert before any non-fixed hard regs that are at the + end. Registers of class NO_REGS cannot be used as an + equivalent for anything. */ + while (lastr < FIRST_PSEUDO_REGISTER && reg_prev_eqv[lastr] >= 0 + && (REGNO_REG_CLASS (lastr) == NO_REGS || ! FIXED_REGNO_P (lastr)) + && new >= FIRST_PSEUDO_REGISTER) + lastr = reg_prev_eqv[lastr]; + reg_next_eqv[new] = reg_next_eqv[lastr]; + if (reg_next_eqv[lastr] >= 0) + reg_prev_eqv[reg_next_eqv[lastr]] = new; + else + qty_last_reg[q] = new; + reg_next_eqv[lastr] = new; + reg_prev_eqv[new] = lastr; + } +} + +/* Remove REG from its equivalence class. */ + +static void +delete_reg_equiv (reg) + register int reg; +{ + register int q = reg_qty[reg]; + register int p, n; + + /* If invalid, do nothing. */ + if (q == reg) + return; + + p = reg_prev_eqv[reg]; + n = reg_next_eqv[reg]; + + if (n != -1) + reg_prev_eqv[n] = p; + else + qty_last_reg[q] = p; + if (p != -1) + reg_next_eqv[p] = n; + else + qty_first_reg[q] = n; + + reg_qty[reg] = reg; +} + +/* Remove any invalid expressions from the hash table + that refer to any of the registers contained in expression X. + + Make sure that newly inserted references to those registers + as subexpressions will be considered valid. + + mention_regs is not called when a register itself + is being stored in the table. + + Return 1 if we have done something that may have changed the hash code + of X. */ + +static int +mention_regs (x) + rtx x; +{ + register enum rtx_code code; + register int i, j; + register char *fmt; + register int changed = 0; + + if (x == 0) + return 0; + + code = GET_CODE (x); + if (code == REG) + { + register int regno = REGNO (x); + register int endregno + = regno + (regno >= FIRST_PSEUDO_REGISTER ? 1 + : HARD_REGNO_NREGS (regno, GET_MODE (x))); + int i; + + for (i = regno; i < endregno; i++) + { + if (reg_in_table[i] >= 0 && reg_in_table[i] != reg_tick[i]) + remove_invalid_refs (i); + + reg_in_table[i] = reg_tick[i]; + } + + return 0; + } + + /* If this is a SUBREG, we don't want to discard other SUBREGs of the same + pseudo if they don't use overlapping words. We handle only pseudos + here for simplicity. */ + if (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG + && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER) + { + int i = REGNO (SUBREG_REG (x)); + + if (reg_in_table[i] >= 0 && reg_in_table[i] != reg_tick[i]) + { + /* If reg_tick has been incremented more than once since + reg_in_table was last set, that means that the entire + register has been set before, so discard anything memorized + for the entrire register, including all SUBREG expressions. */ + if (reg_in_table[i] != reg_tick[i] - 1) + remove_invalid_refs (i); + else + remove_invalid_subreg_refs (i, SUBREG_WORD (x), GET_MODE (x)); + } + + reg_in_table[i] = reg_tick[i]; + return 0; + } + + /* If X is a comparison or a COMPARE and either operand is a register + that does not have a quantity, give it one. This is so that a later + call to record_jump_equiv won't cause X to be assigned a different + hash code and not found in the table after that call. + + It is not necessary to do this here, since rehash_using_reg can + fix up the table later, but doing this here eliminates the need to + call that expensive function in the most common case where the only + use of the register is in the comparison. */ + + if (code == COMPARE || GET_RTX_CLASS (code) == '<') + { + if (GET_CODE (XEXP (x, 0)) == REG + && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 0)))) + if (insert_regs (XEXP (x, 0), NULL_PTR, 0)) + { + rehash_using_reg (XEXP (x, 0)); + changed = 1; + } + + if (GET_CODE (XEXP (x, 1)) == REG + && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 1)))) + if (insert_regs (XEXP (x, 1), NULL_PTR, 0)) + { + rehash_using_reg (XEXP (x, 1)); + changed = 1; + } + } + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + if (fmt[i] == 'e') + changed |= mention_regs (XEXP (x, i)); + else if (fmt[i] == 'E') + for (j = 0; j < XVECLEN (x, i); j++) + changed |= mention_regs (XVECEXP (x, i, j)); + + return changed; +} + +/* Update the register quantities for inserting X into the hash table + with a value equivalent to CLASSP. + (If the class does not contain a REG, it is irrelevant.) + If MODIFIED is nonzero, X is a destination; it is being modified. + Note that delete_reg_equiv should be called on a register + before insert_regs is done on that register with MODIFIED != 0. + + Nonzero value means that elements of reg_qty have changed + so X's hash code may be different. */ + +static int +insert_regs (x, classp, modified) + rtx x; + struct table_elt *classp; + int modified; +{ + if (GET_CODE (x) == REG) + { + register int regno = REGNO (x); + + /* If REGNO is in the equivalence table already but is of the + wrong mode for that equivalence, don't do anything here. */ + + if (REGNO_QTY_VALID_P (regno) + && qty_mode[reg_qty[regno]] != GET_MODE (x)) + return 0; + + if (modified || ! REGNO_QTY_VALID_P (regno)) + { + if (classp) + for (classp = classp->first_same_value; + classp != 0; + classp = classp->next_same_value) + if (GET_CODE (classp->exp) == REG + && GET_MODE (classp->exp) == GET_MODE (x)) + { + make_regs_eqv (regno, REGNO (classp->exp)); + return 1; + } + + make_new_qty (regno); + qty_mode[reg_qty[regno]] = GET_MODE (x); + return 1; + } + + return 0; + } + + /* If X is a SUBREG, we will likely be inserting the inner register in the + table. If that register doesn't have an assigned quantity number at + this point but does later, the insertion that we will be doing now will + not be accessible because its hash code will have changed. So assign + a quantity number now. */ + + else if (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == REG + && ! REGNO_QTY_VALID_P (REGNO (SUBREG_REG (x)))) + { + int regno = REGNO (SUBREG_REG (x)); + + insert_regs (SUBREG_REG (x), NULL_PTR, 0); + /* Mention_regs checks if REG_TICK is exactly one larger than + REG_IN_TABLE to find out if there was only a single preceding + invalidation - for the SUBREG - or another one, which would be + for the full register. Since we don't invalidate the SUBREG + here first, we might have to bump up REG_TICK so that mention_regs + will do the right thing. */ + if (reg_in_table[regno] >= 0 + && reg_tick[regno] == reg_in_table[regno] + 1) + reg_tick[regno]++; + mention_regs (x); + return 1; + } + else + return mention_regs (x); +} + +/* Look in or update the hash table. */ + +/* Put the element ELT on the list of free elements. */ + +static void +free_element (elt) + struct table_elt *elt; +{ + elt->next_same_hash = free_element_chain; + free_element_chain = elt; +} + +/* Return an element that is free for use. */ + +static struct table_elt * +get_element () +{ + struct table_elt *elt = free_element_chain; + if (elt) + { + free_element_chain = elt->next_same_hash; + return elt; + } + n_elements_made++; + return (struct table_elt *) oballoc (sizeof (struct table_elt)); +} + +/* Remove table element ELT from use in the table. + HASH is its hash code, made using the HASH macro. + It's an argument because often that is known in advance + and we save much time not recomputing it. */ + +static void +remove_from_table (elt, hash) + register struct table_elt *elt; + unsigned hash; +{ + if (elt == 0) + return; + + /* Mark this element as removed. See cse_insn. */ + elt->first_same_value = 0; + + /* Remove the table element from its equivalence class. */ + + { + register struct table_elt *prev = elt->prev_same_value; + register struct table_elt *next = elt->next_same_value; + + if (next) next->prev_same_value = prev; + + if (prev) + prev->next_same_value = next; + else + { + register struct table_elt *newfirst = next; + while (next) + { + next->first_same_value = newfirst; + next = next->next_same_value; + } + } + } + + /* Remove the table element from its hash bucket. */ + + { + register struct table_elt *prev = elt->prev_same_hash; + register struct table_elt *next = elt->next_same_hash; + + if (next) next->prev_same_hash = prev; + + if (prev) + prev->next_same_hash = next; + else if (table[hash] == elt) + table[hash] = next; + else + { + /* This entry is not in the proper hash bucket. This can happen + when two classes were merged by `merge_equiv_classes'. Search + for the hash bucket that it heads. This happens only very + rarely, so the cost is acceptable. */ + for (hash = 0; hash < NBUCKETS; hash++) + if (table[hash] == elt) + table[hash] = next; + } + } + + /* Remove the table element from its related-value circular chain. */ + + if (elt->related_value != 0 && elt->related_value != elt) + { + register struct table_elt *p = elt->related_value; + while (p->related_value != elt) + p = p->related_value; + p->related_value = elt->related_value; + if (p->related_value == p) + p->related_value = 0; + } + + free_element (elt); +} + +/* Look up X in the hash table and return its table element, + or 0 if X is not in the table. + + MODE is the machine-mode of X, or if X is an integer constant + with VOIDmode then MODE is the mode with which X will be used. + + Here we are satisfied to find an expression whose tree structure + looks like X. */ + +static struct table_elt * +lookup (x, hash, mode) + rtx x; + unsigned hash; + enum machine_mode mode; +{ + register struct table_elt *p; + + for (p = table[hash]; p; p = p->next_same_hash) + if (mode == p->mode && ((x == p->exp && GET_CODE (x) == REG) + || exp_equiv_p (x, p->exp, GET_CODE (x) != REG, 0))) + return p; + + return 0; +} + +/* Like `lookup' but don't care whether the table element uses invalid regs. + Also ignore discrepancies in the machine mode of a register. */ + +static struct table_elt * +lookup_for_remove (x, hash, mode) + rtx x; + unsigned hash; + enum machine_mode mode; +{ + register struct table_elt *p; + + if (GET_CODE (x) == REG) + { + int regno = REGNO (x); + /* Don't check the machine mode when comparing registers; + invalidating (REG:SI 0) also invalidates (REG:DF 0). */ + for (p = table[hash]; p; p = p->next_same_hash) + if (GET_CODE (p->exp) == REG + && REGNO (p->exp) == regno) + return p; + } + else + { + for (p = table[hash]; p; p = p->next_same_hash) + if (mode == p->mode && (x == p->exp || exp_equiv_p (x, p->exp, 0, 0))) + return p; + } + + return 0; +} + +/* Look for an expression equivalent to X and with code CODE. + If one is found, return that expression. */ + +static rtx +lookup_as_function (x, code) + rtx x; + enum rtx_code code; +{ + register struct table_elt *p = lookup (x, safe_hash (x, VOIDmode) % NBUCKETS, + GET_MODE (x)); + /* If we are looking for a CONST_INT, the mode doesn't really matter, as + long as we are narrowing. So if we looked in vain for a mode narrower + than word_mode before, look for word_mode now. */ + if (p == 0 && code == CONST_INT + && GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (word_mode)) + { + x = copy_rtx (x); + PUT_MODE (x, word_mode); + p = lookup (x, safe_hash (x, VOIDmode) % NBUCKETS, word_mode); + } + + if (p == 0) + return 0; + + for (p = p->first_same_value; p; p = p->next_same_value) + { + if (GET_CODE (p->exp) == code + /* Make sure this is a valid entry in the table. */ + && exp_equiv_p (p->exp, p->exp, 1, 0)) + return p->exp; + } + + return 0; +} + +/* Insert X in the hash table, assuming HASH is its hash code + and CLASSP is an element of the class it should go in + (or 0 if a new class should be made). + It is inserted at the proper position to keep the class in + the order cheapest first. + + MODE is the machine-mode of X, or if X is an integer constant + with VOIDmode then MODE is the mode with which X will be used. + + For elements of equal cheapness, the most recent one + goes in front, except that the first element in the list + remains first unless a cheaper element is added. The order of + pseudo-registers does not matter, as canon_reg will be called to + find the cheapest when a register is retrieved from the table. + + The in_memory field in the hash table element is set to 0. + The caller must set it nonzero if appropriate. + + You should call insert_regs (X, CLASSP, MODIFY) before calling here, + and if insert_regs returns a nonzero value + you must then recompute its hash code before calling here. + + If necessary, update table showing constant values of quantities. */ + +#define CHEAPER(X,Y) ((X)->cost < (Y)->cost) + +static struct table_elt * +insert (x, classp, hash, mode) + register rtx x; + register struct table_elt *classp; + unsigned hash; + enum machine_mode mode; +{ + register struct table_elt *elt; + + /* If X is a register and we haven't made a quantity for it, + something is wrong. */ + if (GET_CODE (x) == REG && ! REGNO_QTY_VALID_P (REGNO (x))) + abort (); + + /* If X is a hard register, show it is being put in the table. */ + if (GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER) + { + int regno = REGNO (x); + int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x)); + int i; + + for (i = regno; i < endregno; i++) + SET_HARD_REG_BIT (hard_regs_in_table, i); + } + + /* If X is a label, show we recorded it. */ + if (GET_CODE (x) == LABEL_REF + || (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS + && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF)) + recorded_label_ref = 1; + + /* Put an element for X into the right hash bucket. */ + + elt = get_element (); + elt->exp = x; + elt->cost = COST (x); + elt->next_same_value = 0; + elt->prev_same_value = 0; + elt->next_same_hash = table[hash]; + elt->prev_same_hash = 0; + elt->related_value = 0; + elt->in_memory = 0; + elt->mode = mode; + elt->is_const = (CONSTANT_P (x) + /* GNU C++ takes advantage of this for `this' + (and other const values). */ + || (RTX_UNCHANGING_P (x) + && GET_CODE (x) == REG + && REGNO (x) >= FIRST_PSEUDO_REGISTER) + || FIXED_BASE_PLUS_P (x)); + + if (table[hash]) + table[hash]->prev_same_hash = elt; + table[hash] = elt; + + /* Put it into the proper value-class. */ + if (classp) + { + classp = classp->first_same_value; + if (CHEAPER (elt, classp)) + /* Insert at the head of the class */ + { + register struct table_elt *p; + elt->next_same_value = classp; + classp->prev_same_value = elt; + elt->first_same_value = elt; + + for (p = classp; p; p = p->next_same_value) + p->first_same_value = elt; + } + else + { + /* Insert not at head of the class. */ + /* Put it after the last element cheaper than X. */ + register struct table_elt *p, *next; + for (p = classp; (next = p->next_same_value) && CHEAPER (next, elt); + p = next); + /* Put it after P and before NEXT. */ + elt->next_same_value = next; + if (next) + next->prev_same_value = elt; + elt->prev_same_value = p; + p->next_same_value = elt; + elt->first_same_value = classp; + } + } + else + elt->first_same_value = elt; + + /* If this is a constant being set equivalent to a register or a register + being set equivalent to a constant, note the constant equivalence. + + If this is a constant, it cannot be equivalent to a different constant, + and a constant is the only thing that can be cheaper than a register. So + we know the register is the head of the class (before the constant was + inserted). + + If this is a register that is not already known equivalent to a + constant, we must check the entire class. + + If this is a register that is already known equivalent to an insn, + update `qty_const_insn' to show that `this_insn' is the latest + insn making that quantity equivalent to the constant. */ + + if (elt->is_const && classp && GET_CODE (classp->exp) == REG + && GET_CODE (x) != REG) + { + qty_const[reg_qty[REGNO (classp->exp)]] + = gen_lowpart_if_possible (qty_mode[reg_qty[REGNO (classp->exp)]], x); + qty_const_insn[reg_qty[REGNO (classp->exp)]] = this_insn; + } + + else if (GET_CODE (x) == REG && classp && ! qty_const[reg_qty[REGNO (x)]] + && ! elt->is_const) + { + register struct table_elt *p; + + for (p = classp; p != 0; p = p->next_same_value) + { + if (p->is_const && GET_CODE (p->exp) != REG) + { + qty_const[reg_qty[REGNO (x)]] + = gen_lowpart_if_possible (GET_MODE (x), p->exp); + qty_const_insn[reg_qty[REGNO (x)]] = this_insn; + break; + } + } + } + + else if (GET_CODE (x) == REG && qty_const[reg_qty[REGNO (x)]] + && GET_MODE (x) == qty_mode[reg_qty[REGNO (x)]]) + qty_const_insn[reg_qty[REGNO (x)]] = this_insn; + + /* If this is a constant with symbolic value, + and it has a term with an explicit integer value, + link it up with related expressions. */ + if (GET_CODE (x) == CONST) + { + rtx subexp = get_related_value (x); + unsigned subhash; + struct table_elt *subelt, *subelt_prev; + + if (subexp != 0) + { + /* Get the integer-free subexpression in the hash table. */ + subhash = safe_hash (subexp, mode) % NBUCKETS; + subelt = lookup (subexp, subhash, mode); + if (subelt == 0) + subelt = insert (subexp, NULL_PTR, subhash, mode); + /* Initialize SUBELT's circular chain if it has none. */ + if (subelt->related_value == 0) + subelt->related_value = subelt; + /* Find the element in the circular chain that precedes SUBELT. */ + subelt_prev = subelt; + while (subelt_prev->related_value != subelt) + subelt_prev = subelt_prev->related_value; + /* Put new ELT into SUBELT's circular chain just before SUBELT. + This way the element that follows SUBELT is the oldest one. */ + elt->related_value = subelt_prev->related_value; + subelt_prev->related_value = elt; + } + } + + return elt; +} + +/* Given two equivalence classes, CLASS1 and CLASS2, put all the entries from + CLASS2 into CLASS1. This is done when we have reached an insn which makes + the two classes equivalent. + + CLASS1 will be the surviving class; CLASS2 should not be used after this + call. + + Any invalid entries in CLASS2 will not be copied. */ + +static void +merge_equiv_classes (class1, class2) + struct table_elt *class1, *class2; +{ + struct table_elt *elt, *next, *new; + + /* Ensure we start with the head of the classes. */ + class1 = class1->first_same_value; + class2 = class2->first_same_value; + + /* If they were already equal, forget it. */ + if (class1 == class2) + return; + + for (elt = class2; elt; elt = next) + { + unsigned hash; + rtx exp = elt->exp; + enum machine_mode mode = elt->mode; + + next = elt->next_same_value; + + /* Remove old entry, make a new one in CLASS1's class. + Don't do this for invalid entries as we cannot find their + hash code (it also isn't necessary). */ + if (GET_CODE (exp) == REG || exp_equiv_p (exp, exp, 1, 0)) + { + hash_arg_in_memory = 0; + hash_arg_in_struct = 0; + hash = HASH (exp, mode); + + if (GET_CODE (exp) == REG) + delete_reg_equiv (REGNO (exp)); + + remove_from_table (elt, hash); + + if (insert_regs (exp, class1, 0)) + { + rehash_using_reg (exp); + hash = HASH (exp, mode); + } + new = insert (exp, class1, hash, mode); + new->in_memory = hash_arg_in_memory; + new->in_struct = hash_arg_in_struct; + } + } +} + +/* Remove from the hash table, or mark as invalid, + all expressions whose values could be altered by storing in X. + X is a register, a subreg, or a memory reference with nonvarying address + (because, when a memory reference with a varying address is stored in, + all memory references are removed by invalidate_memory + so specific invalidation is superfluous). + FULL_MODE, if not VOIDmode, indicates that this much should be invalidated + instead of just the amount indicated by the mode of X. This is only used + for bitfield stores into memory. + + A nonvarying address may be just a register or just + a symbol reference, or it may be either of those plus + a numeric offset. */ + +static void +invalidate (x, full_mode) + rtx x; + enum machine_mode full_mode; +{ + register int i; + register struct table_elt *p; + + /* If X is a register, dependencies on its contents + are recorded through the qty number mechanism. + Just change the qty number of the register, + mark it as invalid for expressions that refer to it, + and remove it itself. */ + + if (GET_CODE (x) == REG) + { + register int regno = REGNO (x); + register unsigned hash = HASH (x, GET_MODE (x)); + + /* Remove REGNO from any quantity list it might be on and indicate + that its value might have changed. If it is a pseudo, remove its + entry from the hash table. + + For a hard register, we do the first two actions above for any + additional hard registers corresponding to X. Then, if any of these + registers are in the table, we must remove any REG entries that + overlap these registers. */ + + delete_reg_equiv (regno); + reg_tick[regno]++; + + if (regno >= FIRST_PSEUDO_REGISTER) + { + /* Because a register can be referenced in more than one mode, + we might have to remove more than one table entry. */ + + struct table_elt *elt; + + while ((elt = lookup_for_remove (x, hash, GET_MODE (x)))) + remove_from_table (elt, hash); + } + else + { + HOST_WIDE_INT in_table + = TEST_HARD_REG_BIT (hard_regs_in_table, regno); + int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x)); + int tregno, tendregno; + register struct table_elt *p, *next; + + CLEAR_HARD_REG_BIT (hard_regs_in_table, regno); + + for (i = regno + 1; i < endregno; i++) + { + in_table |= TEST_HARD_REG_BIT (hard_regs_in_table, i); + CLEAR_HARD_REG_BIT (hard_regs_in_table, i); + delete_reg_equiv (i); + reg_tick[i]++; + } + + if (in_table) + for (hash = 0; hash < NBUCKETS; hash++) + for (p = table[hash]; p; p = next) + { + next = p->next_same_hash; + + if (GET_CODE (p->exp) != REG + || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER) + continue; + + tregno = REGNO (p->exp); + tendregno + = tregno + HARD_REGNO_NREGS (tregno, GET_MODE (p->exp)); + if (tendregno > regno && tregno < endregno) + remove_from_table (p, hash); + } + } + + return; + } + + if (GET_CODE (x) == SUBREG) + { + if (GET_CODE (SUBREG_REG (x)) != REG) + abort (); + invalidate (SUBREG_REG (x), VOIDmode); + return; + } + + /* If X is a parallel, invalidate all of its elements. */ + + if (GET_CODE (x) == PARALLEL) + { + for (i = XVECLEN (x, 0) - 1; i >= 0 ; --i) + invalidate (XVECEXP (x, 0, i), VOIDmode); + return; + } + + /* If X is an expr_list, this is part of a disjoint return value; + extract the location in question ignoring the offset. */ + + if (GET_CODE (x) == EXPR_LIST) + { + invalidate (XEXP (x, 0), VOIDmode); + return; + } + + /* X is not a register; it must be a memory reference with + a nonvarying address. Remove all hash table elements + that refer to overlapping pieces of memory. */ + + if (GET_CODE (x) != MEM) + abort (); + + if (full_mode == VOIDmode) + full_mode = GET_MODE (x); + + for (i = 0; i < NBUCKETS; i++) + { + register struct table_elt *next; + for (p = table[i]; p; p = next) + { + next = p->next_same_hash; + /* Invalidate ASM_OPERANDS which reference memory (this is easier + than checking all the aliases). */ + if (p->in_memory + && (GET_CODE (p->exp) != MEM + || true_dependence (x, full_mode, p->exp, cse_rtx_varies_p))) + remove_from_table (p, i); + } + } +} + +/* Remove all expressions that refer to register REGNO, + since they are already invalid, and we are about to + mark that register valid again and don't want the old + expressions to reappear as valid. */ + +static void +remove_invalid_refs (regno) + int regno; +{ + register int i; + register struct table_elt *p, *next; + + for (i = 0; i < NBUCKETS; i++) + for (p = table[i]; p; p = next) + { + next = p->next_same_hash; + if (GET_CODE (p->exp) != REG + && refers_to_regno_p (regno, regno + 1, p->exp, NULL_PTR)) + remove_from_table (p, i); + } +} + +/* Likewise for a subreg with subreg_reg WORD and mode MODE. */ +static void +remove_invalid_subreg_refs (regno, word, mode) + int regno; + int word; + enum machine_mode mode; +{ + register int i; + register struct table_elt *p, *next; + int end = word + (GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD; + + for (i = 0; i < NBUCKETS; i++) + for (p = table[i]; p; p = next) + { + rtx exp; + next = p->next_same_hash; + + exp = p->exp; + if (GET_CODE (p->exp) != REG + && (GET_CODE (exp) != SUBREG + || GET_CODE (SUBREG_REG (exp)) != REG + || REGNO (SUBREG_REG (exp)) != regno + || (((SUBREG_WORD (exp) + + (GET_MODE_SIZE (GET_MODE (exp)) - 1) / UNITS_PER_WORD) + >= word) + && SUBREG_WORD (exp) <= end)) + && refers_to_regno_p (regno, regno + 1, p->exp, NULL_PTR)) + remove_from_table (p, i); + } +} + +/* Recompute the hash codes of any valid entries in the hash table that + reference X, if X is a register, or SUBREG_REG (X) if X is a SUBREG. + + This is called when we make a jump equivalence. */ + +static void +rehash_using_reg (x) + rtx x; +{ + unsigned int i; + struct table_elt *p, *next; + unsigned hash; + + if (GET_CODE (x) == SUBREG) + x = SUBREG_REG (x); + + /* If X is not a register or if the register is known not to be in any + valid entries in the table, we have no work to do. */ + + if (GET_CODE (x) != REG + || reg_in_table[REGNO (x)] < 0 + || reg_in_table[REGNO (x)] != reg_tick[REGNO (x)]) + return; + + /* Scan all hash chains looking for valid entries that mention X. + If we find one and it is in the wrong hash chain, move it. We can skip + objects that are registers, since they are handled specially. */ + + for (i = 0; i < NBUCKETS; i++) + for (p = table[i]; p; p = next) + { + next = p->next_same_hash; + if (GET_CODE (p->exp) != REG && reg_mentioned_p (x, p->exp) + && exp_equiv_p (p->exp, p->exp, 1, 0) + && i != (hash = safe_hash (p->exp, p->mode) % NBUCKETS)) + { + if (p->next_same_hash) + p->next_same_hash->prev_same_hash = p->prev_same_hash; + + if (p->prev_same_hash) + p->prev_same_hash->next_same_hash = p->next_same_hash; + else + table[i] = p->next_same_hash; + + p->next_same_hash = table[hash]; + p->prev_same_hash = 0; + if (table[hash]) + table[hash]->prev_same_hash = p; + table[hash] = p; + } + } +} + +/* Remove from the hash table any expression that is a call-clobbered + register. Also update their TICK values. */ + +static void +invalidate_for_call () +{ + int regno, endregno; + int i; + unsigned hash; + struct table_elt *p, *next; + int in_table = 0; + + /* Go through all the hard registers. For each that is clobbered in + a CALL_INSN, remove the register from quantity chains and update + reg_tick if defined. Also see if any of these registers is currently + in the table. */ + + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno)) + { + delete_reg_equiv (regno); + if (reg_tick[regno] >= 0) + reg_tick[regno]++; + + in_table |= (TEST_HARD_REG_BIT (hard_regs_in_table, regno) != 0); + } + + /* In the case where we have no call-clobbered hard registers in the + table, we are done. Otherwise, scan the table and remove any + entry that overlaps a call-clobbered register. */ + + if (in_table) + for (hash = 0; hash < NBUCKETS; hash++) + for (p = table[hash]; p; p = next) + { + next = p->next_same_hash; + + if (p->in_memory) + { + remove_from_table (p, hash); + continue; + } + + if (GET_CODE (p->exp) != REG + || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER) + continue; + + regno = REGNO (p->exp); + endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (p->exp)); + + for (i = regno; i < endregno; i++) + if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i)) + { + remove_from_table (p, hash); + break; + } + } +} + +/* Given an expression X of type CONST, + and ELT which is its table entry (or 0 if it + is not in the hash table), + return an alternate expression for X as a register plus integer. + If none can be found, return 0. */ + +static rtx +use_related_value (x, elt) + rtx x; + struct table_elt *elt; +{ + register struct table_elt *relt = 0; + register struct table_elt *p, *q; + HOST_WIDE_INT offset; + + /* First, is there anything related known? + If we have a table element, we can tell from that. + Otherwise, must look it up. */ + + if (elt != 0 && elt->related_value != 0) + relt = elt; + else if (elt == 0 && GET_CODE (x) == CONST) + { + rtx subexp = get_related_value (x); + if (subexp != 0) + relt = lookup (subexp, + safe_hash (subexp, GET_MODE (subexp)) % NBUCKETS, + GET_MODE (subexp)); + } + + if (relt == 0) + return 0; + + /* Search all related table entries for one that has an + equivalent register. */ + + p = relt; + while (1) + { + /* This loop is strange in that it is executed in two different cases. + The first is when X is already in the table. Then it is searching + the RELATED_VALUE list of X's class (RELT). The second case is when + X is not in the table. Then RELT points to a class for the related + value. + + Ensure that, whatever case we are in, that we ignore classes that have + the same value as X. */ + + if (rtx_equal_p (x, p->exp)) + q = 0; + else + for (q = p->first_same_value; q; q = q->next_same_value) + if (GET_CODE (q->exp) == REG) + break; + + if (q) + break; + + p = p->related_value; + + /* We went all the way around, so there is nothing to be found. + Alternatively, perhaps RELT was in the table for some other reason + and it has no related values recorded. */ + if (p == relt || p == 0) + break; + } + + if (q == 0) + return 0; + + offset = (get_integer_term (x) - get_integer_term (p->exp)); + /* Note: OFFSET may be 0 if P->xexp and X are related by commutativity. */ + return plus_constant (q->exp, offset); +} + +/* Hash an rtx. We are careful to make sure the value is never negative. + Equivalent registers hash identically. + MODE is used in hashing for CONST_INTs only; + otherwise the mode of X is used. + + Store 1 in do_not_record if any subexpression is volatile. + + Store 1 in hash_arg_in_memory if X contains a MEM rtx + which does not have the RTX_UNCHANGING_P bit set. + In this case, also store 1 in hash_arg_in_struct + if there is a MEM rtx which has the MEM_IN_STRUCT_P bit set. + + Note that cse_insn knows that the hash code of a MEM expression + is just (int) MEM plus the hash code of the address. */ + +static unsigned +canon_hash (x, mode) + rtx x; + enum machine_mode mode; +{ + register int i, j; + register unsigned hash = 0; + register enum rtx_code code; + register char *fmt; + + /* repeat is used to turn tail-recursion into iteration. */ + repeat: + if (x == 0) + return hash; + + code = GET_CODE (x); + switch (code) + { + case REG: + { + register int regno = REGNO (x); + + /* On some machines, we can't record any non-fixed hard register, + because extending its life will cause reload problems. We + consider ap, fp, and sp to be fixed for this purpose. + On all machines, we can't record any global registers. */ + + if (regno < FIRST_PSEUDO_REGISTER + && (global_regs[regno] + || (SMALL_REGISTER_CLASSES + && ! fixed_regs[regno] + && regno != FRAME_POINTER_REGNUM + && regno != HARD_FRAME_POINTER_REGNUM + && regno != ARG_POINTER_REGNUM + && regno != STACK_POINTER_REGNUM))) + { + do_not_record = 1; + return 0; + } + hash += ((unsigned) REG << 7) + (unsigned) reg_qty[regno]; + return hash; + } + + /* We handle SUBREG of a REG specially because the underlying + reg changes its hash value with every value change; we don't + want to have to forget unrelated subregs when one subreg changes. */ + case SUBREG: + { + if (GET_CODE (SUBREG_REG (x)) == REG) + { + hash += (((unsigned) SUBREG << 7) + + REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)); + return hash; + } + break; + } + + case CONST_INT: + { + unsigned HOST_WIDE_INT tem = INTVAL (x); + hash += ((unsigned) CONST_INT << 7) + (unsigned) mode + tem; + return hash; + } + + case CONST_DOUBLE: + /* This is like the general case, except that it only counts + the integers representing the constant. */ + hash += (unsigned) code + (unsigned) GET_MODE (x); + if (GET_MODE (x) != VOIDmode) + for (i = 2; i < GET_RTX_LENGTH (CONST_DOUBLE); i++) + { + unsigned tem = XINT (x, i); + hash += tem; + } + else + hash += ((unsigned) CONST_DOUBLE_LOW (x) + + (unsigned) CONST_DOUBLE_HIGH (x)); + return hash; + + /* Assume there is only one rtx object for any given label. */ + case LABEL_REF: + hash + += ((unsigned) LABEL_REF << 7) + (unsigned long) XEXP (x, 0); + return hash; + + case SYMBOL_REF: + hash + += ((unsigned) SYMBOL_REF << 7) + (unsigned long) XSTR (x, 0); + return hash; + + case MEM: + if (MEM_VOLATILE_P (x)) + { + do_not_record = 1; + return 0; + } + if (! RTX_UNCHANGING_P (x) || FIXED_BASE_PLUS_P (XEXP (x, 0))) + { + hash_arg_in_memory = 1; + if (MEM_IN_STRUCT_P (x)) hash_arg_in_struct = 1; + } + /* Now that we have already found this special case, + might as well speed it up as much as possible. */ + hash += (unsigned) MEM; + x = XEXP (x, 0); + goto repeat; + + case PRE_DEC: + case PRE_INC: + case POST_DEC: + case POST_INC: + case PC: + case CC0: + case CALL: + case UNSPEC_VOLATILE: + do_not_record = 1; + return 0; + + case ASM_OPERANDS: + if (MEM_VOLATILE_P (x)) + { + do_not_record = 1; + return 0; + } + break; + + default: + break; + } + + i = GET_RTX_LENGTH (code) - 1; + hash += (unsigned) code + (unsigned) GET_MODE (x); + fmt = GET_RTX_FORMAT (code); + for (; i >= 0; i--) + { + if (fmt[i] == 'e') + { + rtx tem = XEXP (x, i); + + /* If we are about to do the last recursive call + needed at this level, change it into iteration. + This function is called enough to be worth it. */ + if (i == 0) + { + x = tem; + goto repeat; + } + hash += canon_hash (tem, 0); + } + else if (fmt[i] == 'E') + for (j = 0; j < XVECLEN (x, i); j++) + hash += canon_hash (XVECEXP (x, i, j), 0); + else if (fmt[i] == 's') + { + register unsigned char *p = (unsigned char *) XSTR (x, i); + if (p) + while (*p) + hash += *p++; + } + else if (fmt[i] == 'i') + { + register unsigned tem = XINT (x, i); + hash += tem; + } + else if (fmt[i] == '0') + /* unused */; + else + abort (); + } + return hash; +} + +/* Like canon_hash but with no side effects. */ + +static unsigned +safe_hash (x, mode) + rtx x; + enum machine_mode mode; +{ + int save_do_not_record = do_not_record; + int save_hash_arg_in_memory = hash_arg_in_memory; + int save_hash_arg_in_struct = hash_arg_in_struct; + unsigned hash = canon_hash (x, mode); + hash_arg_in_memory = save_hash_arg_in_memory; + hash_arg_in_struct = save_hash_arg_in_struct; + do_not_record = save_do_not_record; + return hash; +} + +/* Return 1 iff X and Y would canonicalize into the same thing, + without actually constructing the canonicalization of either one. + If VALIDATE is nonzero, + we assume X is an expression being processed from the rtl + and Y was found in the hash table. We check register refs + in Y for being marked as valid. + + If EQUAL_VALUES is nonzero, we allow a register to match a constant value + that is known to be in the register. Ordinarily, we don't allow them + to match, because letting them match would cause unpredictable results + in all the places that search a hash table chain for an equivalent + for a given value. A possible equivalent that has different structure + has its hash code computed from different data. Whether the hash code + is the same as that of the given value is pure luck. */ + +static int +exp_equiv_p (x, y, validate, equal_values) + rtx x, y; + int validate; + int equal_values; +{ + register int i, j; + register enum rtx_code code; + register char *fmt; + + /* Note: it is incorrect to assume an expression is equivalent to itself + if VALIDATE is nonzero. */ + if (x == y && !validate) + return 1; + if (x == 0 || y == 0) + return x == y; + + code = GET_CODE (x); + if (code != GET_CODE (y)) + { + if (!equal_values) + return 0; + + /* If X is a constant and Y is a register or vice versa, they may be + equivalent. We only have to validate if Y is a register. */ + if (CONSTANT_P (x) && GET_CODE (y) == REG + && REGNO_QTY_VALID_P (REGNO (y)) + && GET_MODE (y) == qty_mode[reg_qty[REGNO (y)]] + && rtx_equal_p (x, qty_const[reg_qty[REGNO (y)]]) + && (! validate || reg_in_table[REGNO (y)] == reg_tick[REGNO (y)])) + return 1; + + if (CONSTANT_P (y) && code == REG + && REGNO_QTY_VALID_P (REGNO (x)) + && GET_MODE (x) == qty_mode[reg_qty[REGNO (x)]] + && rtx_equal_p (y, qty_const[reg_qty[REGNO (x)]])) + return 1; + + return 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 PC: + case CC0: + return x == y; + + case CONST_INT: + return INTVAL (x) == INTVAL (y); + + case LABEL_REF: + return XEXP (x, 0) == XEXP (y, 0); + + case SYMBOL_REF: + return XSTR (x, 0) == XSTR (y, 0); + + case REG: + { + int regno = REGNO (y); + int endregno + = regno + (regno >= FIRST_PSEUDO_REGISTER ? 1 + : HARD_REGNO_NREGS (regno, GET_MODE (y))); + int i; + + /* If the quantities are not the same, the expressions are not + equivalent. If there are and we are not to validate, they + are equivalent. Otherwise, ensure all regs are up-to-date. */ + + if (reg_qty[REGNO (x)] != reg_qty[regno]) + return 0; + + if (! validate) + return 1; + + for (i = regno; i < endregno; i++) + if (reg_in_table[i] != reg_tick[i]) + return 0; + + return 1; + } + + /* For commutative operations, check both orders. */ + case PLUS: + case MULT: + case AND: + case IOR: + case XOR: + case NE: + case EQ: + return ((exp_equiv_p (XEXP (x, 0), XEXP (y, 0), validate, equal_values) + && exp_equiv_p (XEXP (x, 1), XEXP (y, 1), + validate, equal_values)) + || (exp_equiv_p (XEXP (x, 0), XEXP (y, 1), + validate, equal_values) + && exp_equiv_p (XEXP (x, 1), XEXP (y, 0), + validate, equal_values))); + + default: + break; + } + + /* Compare the elements. If any pair of corresponding elements + fail to match, return 0 for the whole things. */ + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + switch (fmt[i]) + { + case 'e': + if (! exp_equiv_p (XEXP (x, i), XEXP (y, i), validate, equal_values)) + return 0; + break; + + case 'E': + if (XVECLEN (x, i) != XVECLEN (y, i)) + return 0; + for (j = 0; j < XVECLEN (x, i); j++) + if (! exp_equiv_p (XVECEXP (x, i, j), XVECEXP (y, i, j), + validate, equal_values)) + return 0; + break; + + case 's': + if (strcmp (XSTR (x, i), XSTR (y, i))) + return 0; + break; + + case 'i': + if (XINT (x, i) != XINT (y, i)) + return 0; + break; + + case 'w': + if (XWINT (x, i) != XWINT (y, i)) + return 0; + break; + + case '0': + break; + + default: + abort (); + } + } + + return 1; +} + +/* Return 1 iff any subexpression of X matches Y. + Here we do not require that X or Y be valid (for registers referred to) + for being in the hash table. */ + +static int +refers_to_p (x, y) + rtx x, y; +{ + register int i; + register enum rtx_code code; + register char *fmt; + + repeat: + if (x == y) + return 1; + if (x == 0 || y == 0) + return 0; + + code = GET_CODE (x); + /* If X as a whole has the same code as Y, they may match. + If so, return 1. */ + if (code == GET_CODE (y)) + { + if (exp_equiv_p (x, y, 0, 1)) + return 1; + } + + /* X does not match, so try its subexpressions. */ + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + if (fmt[i] == 'e') + { + if (i == 0) + { + x = XEXP (x, 0); + goto repeat; + } + else + if (refers_to_p (XEXP (x, i), y)) + return 1; + } + else if (fmt[i] == 'E') + { + int j; + for (j = 0; j < XVECLEN (x, i); j++) + if (refers_to_p (XVECEXP (x, i, j), y)) + return 1; + } + + return 0; +} + +/* Given ADDR and SIZE (a memory address, and the size of the memory reference), + set PBASE, PSTART, and PEND which correspond to the base of the address, + the starting offset, and ending offset respectively. + + ADDR is known to be a nonvarying address. */ + +/* ??? Despite what the comments say, this function is in fact frequently + passed varying addresses. This does not appear to cause any problems. */ + +static void +set_nonvarying_address_components (addr, size, pbase, pstart, pend) + rtx addr; + int size; + rtx *pbase; + HOST_WIDE_INT *pstart, *pend; +{ + rtx base; + HOST_WIDE_INT start, end; + + base = addr; + start = 0; + end = 0; + + if (flag_pic && GET_CODE (base) == PLUS + && XEXP (base, 0) == pic_offset_table_rtx) + base = XEXP (base, 1); + + /* Registers with nonvarying addresses usually have constant equivalents; + but the frame pointer register is also possible. */ + if (GET_CODE (base) == REG + && qty_const != 0 + && REGNO_QTY_VALID_P (REGNO (base)) + && qty_mode[reg_qty[REGNO (base)]] == GET_MODE (base) + && qty_const[reg_qty[REGNO (base)]] != 0) + base = qty_const[reg_qty[REGNO (base)]]; + else if (GET_CODE (base) == PLUS + && GET_CODE (XEXP (base, 1)) == CONST_INT + && GET_CODE (XEXP (base, 0)) == REG + && qty_const != 0 + && REGNO_QTY_VALID_P (REGNO (XEXP (base, 0))) + && (qty_mode[reg_qty[REGNO (XEXP (base, 0))]] + == GET_MODE (XEXP (base, 0))) + && qty_const[reg_qty[REGNO (XEXP (base, 0))]]) + { + start = INTVAL (XEXP (base, 1)); + base = qty_const[reg_qty[REGNO (XEXP (base, 0))]]; + } + /* This can happen as the result of virtual register instantiation, + if the initial offset is too large to be a valid address. */ + else if (GET_CODE (base) == PLUS + && GET_CODE (XEXP (base, 0)) == REG + && GET_CODE (XEXP (base, 1)) == REG + && qty_const != 0 + && REGNO_QTY_VALID_P (REGNO (XEXP (base, 0))) + && (qty_mode[reg_qty[REGNO (XEXP (base, 0))]] + == GET_MODE (XEXP (base, 0))) + && qty_const[reg_qty[REGNO (XEXP (base, 0))]] + && REGNO_QTY_VALID_P (REGNO (XEXP (base, 1))) + && (qty_mode[reg_qty[REGNO (XEXP (base, 1))]] + == GET_MODE (XEXP (base, 1))) + && qty_const[reg_qty[REGNO (XEXP (base, 1))]]) + { + rtx tem = qty_const[reg_qty[REGNO (XEXP (base, 1))]]; + base = qty_const[reg_qty[REGNO (XEXP (base, 0))]]; + + /* One of the two values must be a constant. */ + if (GET_CODE (base) != CONST_INT) + { + if (GET_CODE (tem) != CONST_INT) + abort (); + start = INTVAL (tem); + } + else + { + start = INTVAL (base); + base = tem; + } + } + + /* Handle everything that we can find inside an address that has been + viewed as constant. */ + + while (1) + { + /* If no part of this switch does a "continue", the code outside + will exit this loop. */ + + switch (GET_CODE (base)) + { + case LO_SUM: + /* By definition, operand1 of a LO_SUM is the associated constant + address. Use the associated constant address as the base + instead. */ + base = XEXP (base, 1); + continue; + + case CONST: + /* Strip off CONST. */ + base = XEXP (base, 0); + continue; + + case PLUS: + if (GET_CODE (XEXP (base, 1)) == CONST_INT) + { + start += INTVAL (XEXP (base, 1)); + base = XEXP (base, 0); + continue; + } + break; + + case AND: + /* Handle the case of an AND which is the negative of a power of + two. This is used to represent unaligned memory operations. */ + if (GET_CODE (XEXP (base, 1)) == CONST_INT + && exact_log2 (- INTVAL (XEXP (base, 1))) > 0) + { + set_nonvarying_address_components (XEXP (base, 0), size, + pbase, pstart, pend); + + /* Assume the worst misalignment. START is affected, but not + END, so compensate but adjusting SIZE. Don't lose any + constant we already had. */ + + size = *pend - *pstart - INTVAL (XEXP (base, 1)) - 1; + start += *pstart + INTVAL (XEXP (base, 1)) + 1; + end += *pend; + base = *pbase; + } + break; + + default: + break; + } + + break; + } + + if (GET_CODE (base) == CONST_INT) + { + start += INTVAL (base); + base = const0_rtx; + } + + end = start + size; + + /* Set the return values. */ + *pbase = base; + *pstart = start; + *pend = end; +} + +/* Return 1 if X has a value that can vary even between two + executions of the program. 0 means X can be compared reliably + against certain constants or near-constants. */ + +static int +cse_rtx_varies_p (x) + register rtx x; +{ + /* We need not check for X and the equivalence class being of the same + mode because if X is equivalent to a constant in some mode, it + doesn't vary in any mode. */ + + if (GET_CODE (x) == REG + && REGNO_QTY_VALID_P (REGNO (x)) + && GET_MODE (x) == qty_mode[reg_qty[REGNO (x)]] + && qty_const[reg_qty[REGNO (x)]] != 0) + return 0; + + if (GET_CODE (x) == PLUS + && GET_CODE (XEXP (x, 1)) == CONST_INT + && GET_CODE (XEXP (x, 0)) == REG + && REGNO_QTY_VALID_P (REGNO (XEXP (x, 0))) + && (GET_MODE (XEXP (x, 0)) + == qty_mode[reg_qty[REGNO (XEXP (x, 0))]]) + && qty_const[reg_qty[REGNO (XEXP (x, 0))]]) + return 0; + + /* This can happen as the result of virtual register instantiation, if + the initial constant is too large to be a valid address. This gives + us a three instruction sequence, load large offset into a register, + load fp minus a constant into a register, then a MEM which is the + sum of the two `constant' registers. */ + if (GET_CODE (x) == PLUS + && GET_CODE (XEXP (x, 0)) == REG + && GET_CODE (XEXP (x, 1)) == REG + && REGNO_QTY_VALID_P (REGNO (XEXP (x, 0))) + && (GET_MODE (XEXP (x, 0)) + == qty_mode[reg_qty[REGNO (XEXP (x, 0))]]) + && qty_const[reg_qty[REGNO (XEXP (x, 0))]] + && REGNO_QTY_VALID_P (REGNO (XEXP (x, 1))) + && (GET_MODE (XEXP (x, 1)) + == qty_mode[reg_qty[REGNO (XEXP (x, 1))]]) + && qty_const[reg_qty[REGNO (XEXP (x, 1))]]) + return 0; + + return rtx_varies_p (x); +} + +/* Canonicalize an expression: + replace each register reference inside it + with the "oldest" equivalent register. + + If INSN is non-zero and we are replacing a pseudo with a hard register + or vice versa, validate_change is used to ensure that INSN remains valid + after we make our substitution. The calls are made with IN_GROUP non-zero + so apply_change_group must be called upon the outermost return from this + function (unless INSN is zero). The result of apply_change_group can + generally be discarded since the changes we are making are optional. */ + +static rtx +canon_reg (x, insn) + rtx x; + rtx insn; +{ + register int i; + register enum rtx_code code; + register char *fmt; + + if (x == 0) + return x; + + code = GET_CODE (x); + switch (code) + { + case PC: + case CC0: + case CONST: + case CONST_INT: + case CONST_DOUBLE: + case SYMBOL_REF: + case LABEL_REF: + case ADDR_VEC: + case ADDR_DIFF_VEC: + return x; + + case REG: + { + register int first; + + /* Never replace a hard reg, because hard regs can appear + in more than one machine mode, and we must preserve the mode + of each occurrence. Also, some hard regs appear in + MEMs that are shared and mustn't be altered. Don't try to + replace any reg that maps to a reg of class NO_REGS. */ + if (REGNO (x) < FIRST_PSEUDO_REGISTER + || ! REGNO_QTY_VALID_P (REGNO (x))) + return x; + + first = qty_first_reg[reg_qty[REGNO (x)]]; + return (first >= FIRST_PSEUDO_REGISTER ? regno_reg_rtx[first] + : REGNO_REG_CLASS (first) == NO_REGS ? x + : gen_rtx_REG (qty_mode[reg_qty[REGNO (x)]], first)); + } + + default: + break; + } + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + register int j; + + if (fmt[i] == 'e') + { + rtx new = canon_reg (XEXP (x, i), insn); + int insn_code; + + /* If replacing pseudo with hard reg or vice versa, ensure the + insn remains valid. Likewise if the insn has MATCH_DUPs. */ + if (insn != 0 && new != 0 + && GET_CODE (new) == REG && GET_CODE (XEXP (x, i)) == REG + && (((REGNO (new) < FIRST_PSEUDO_REGISTER) + != (REGNO (XEXP (x, i)) < FIRST_PSEUDO_REGISTER)) + || (insn_code = recog_memoized (insn)) < 0 + || insn_n_dups[insn_code] > 0)) + validate_change (insn, &XEXP (x, i), new, 1); + else + XEXP (x, i) = new; + } + else if (fmt[i] == 'E') + for (j = 0; j < XVECLEN (x, i); j++) + XVECEXP (x, i, j) = canon_reg (XVECEXP (x, i, j), insn); + } + + return x; +} + +/* LOC is a location within INSN that is an operand address (the contents of + a MEM). Find the best equivalent address to use that is valid for this + insn. + + On most CISC machines, complicated address modes are costly, and rtx_cost + is a good approximation for that cost. However, most RISC machines have + only a few (usually only one) memory reference formats. If an address is + valid at all, it is often just as cheap as any other address. Hence, for + RISC machines, we use the configuration macro `ADDRESS_COST' to compare the + costs of various addresses. For two addresses of equal cost, choose the one + with the highest `rtx_cost' value as that has the potential of eliminating + the most insns. For equal costs, we choose the first in the equivalence + class. Note that we ignore the fact that pseudo registers are cheaper + than hard registers here because we would also prefer the pseudo registers. + */ + +static void +find_best_addr (insn, loc) + rtx insn; + rtx *loc; +{ + struct table_elt *elt; + rtx addr = *loc; +#ifdef ADDRESS_COST + struct table_elt *p; + int found_better = 1; +#endif + int save_do_not_record = do_not_record; + int save_hash_arg_in_memory = hash_arg_in_memory; + int save_hash_arg_in_struct = hash_arg_in_struct; + int addr_volatile; + int regno; + unsigned hash; + + /* Do not try to replace constant addresses or addresses of local and + argument slots. These MEM expressions are made only once and inserted + in many instructions, as well as being used to control symbol table + output. It is not safe to clobber them. + + There are some uncommon cases where the address is already in a register + for some reason, but we cannot take advantage of that because we have + no easy way to unshare the MEM. In addition, looking up all stack + addresses is costly. */ + if ((GET_CODE (addr) == PLUS + && GET_CODE (XEXP (addr, 0)) == REG + && GET_CODE (XEXP (addr, 1)) == CONST_INT + && (regno = REGNO (XEXP (addr, 0)), + regno == FRAME_POINTER_REGNUM || regno == HARD_FRAME_POINTER_REGNUM + || regno == ARG_POINTER_REGNUM)) + || (GET_CODE (addr) == REG + && (regno = REGNO (addr), regno == FRAME_POINTER_REGNUM + || regno == HARD_FRAME_POINTER_REGNUM + || regno == ARG_POINTER_REGNUM)) + || GET_CODE (addr) == ADDRESSOF + || CONSTANT_ADDRESS_P (addr)) + return; + + /* If this address is not simply a register, try to fold it. This will + sometimes simplify the expression. Many simplifications + will not be valid, but some, usually applying the associative rule, will + be valid and produce better code. */ + if (GET_CODE (addr) != REG) + { + rtx folded = fold_rtx (copy_rtx (addr), NULL_RTX); + + if (1 +#ifdef ADDRESS_COST + && (CSE_ADDRESS_COST (folded) < CSE_ADDRESS_COST (addr) + || (CSE_ADDRESS_COST (folded) == CSE_ADDRESS_COST (addr) + && rtx_cost (folded, MEM) > rtx_cost (addr, MEM))) +#else + && rtx_cost (folded, MEM) < rtx_cost (addr, MEM) +#endif + && validate_change (insn, loc, folded, 0)) + addr = folded; + } + + /* If this address is not in the hash table, we can't look for equivalences + of the whole address. Also, ignore if volatile. */ + + do_not_record = 0; + hash = HASH (addr, Pmode); + addr_volatile = do_not_record; + do_not_record = save_do_not_record; + hash_arg_in_memory = save_hash_arg_in_memory; + hash_arg_in_struct = save_hash_arg_in_struct; + + if (addr_volatile) + return; + + elt = lookup (addr, hash, Pmode); + +#ifndef ADDRESS_COST + if (elt) + { + int our_cost = elt->cost; + + /* Find the lowest cost below ours that works. */ + for (elt = elt->first_same_value; elt; elt = elt->next_same_value) + if (elt->cost < our_cost + && (GET_CODE (elt->exp) == REG + || exp_equiv_p (elt->exp, elt->exp, 1, 0)) + && validate_change (insn, loc, + canon_reg (copy_rtx (elt->exp), NULL_RTX), 0)) + return; + } +#else + + if (elt) + { + /* We need to find the best (under the criteria documented above) entry + in the class that is valid. We use the `flag' field to indicate + choices that were invalid and iterate until we can't find a better + one that hasn't already been tried. */ + + for (p = elt->first_same_value; p; p = p->next_same_value) + p->flag = 0; + + while (found_better) + { + int best_addr_cost = CSE_ADDRESS_COST (*loc); + int best_rtx_cost = (elt->cost + 1) >> 1; + struct table_elt *best_elt = elt; + + found_better = 0; + for (p = elt->first_same_value; p; p = p->next_same_value) + if (! p->flag) + { + if ((GET_CODE (p->exp) == REG + || exp_equiv_p (p->exp, p->exp, 1, 0)) + && (CSE_ADDRESS_COST (p->exp) < best_addr_cost + || (CSE_ADDRESS_COST (p->exp) == best_addr_cost + && (p->cost + 1) >> 1 > best_rtx_cost))) + { + found_better = 1; + best_addr_cost = CSE_ADDRESS_COST (p->exp); + best_rtx_cost = (p->cost + 1) >> 1; + best_elt = p; + } + } + + if (found_better) + { + if (validate_change (insn, loc, + canon_reg (copy_rtx (best_elt->exp), + NULL_RTX), 0)) + return; + else + best_elt->flag = 1; + } + } + } + + /* If the address is a binary operation with the first operand a register + and the second a constant, do the same as above, but looking for + equivalences of the register. Then try to simplify before checking for + the best address to use. This catches a few cases: First is when we + have REG+const and the register is another REG+const. We can often merge + the constants and eliminate one insn and one register. It may also be + that a machine has a cheap REG+REG+const. Finally, this improves the + code on the Alpha for unaligned byte stores. */ + + if (flag_expensive_optimizations + && (GET_RTX_CLASS (GET_CODE (*loc)) == '2' + || GET_RTX_CLASS (GET_CODE (*loc)) == 'c') + && GET_CODE (XEXP (*loc, 0)) == REG + && GET_CODE (XEXP (*loc, 1)) == CONST_INT) + { + rtx c = XEXP (*loc, 1); + + do_not_record = 0; + hash = HASH (XEXP (*loc, 0), Pmode); + do_not_record = save_do_not_record; + hash_arg_in_memory = save_hash_arg_in_memory; + hash_arg_in_struct = save_hash_arg_in_struct; + + elt = lookup (XEXP (*loc, 0), hash, Pmode); + if (elt == 0) + return; + + /* We need to find the best (under the criteria documented above) entry + in the class that is valid. We use the `flag' field to indicate + choices that were invalid and iterate until we can't find a better + one that hasn't already been tried. */ + + for (p = elt->first_same_value; p; p = p->next_same_value) + p->flag = 0; + + while (found_better) + { + int best_addr_cost = CSE_ADDRESS_COST (*loc); + int best_rtx_cost = (COST (*loc) + 1) >> 1; + struct table_elt *best_elt = elt; + rtx best_rtx = *loc; + int count; + + /* This is at worst case an O(n^2) algorithm, so limit our search + to the first 32 elements on the list. This avoids trouble + compiling code with very long basic blocks that can easily + call cse_gen_binary so many times that we run out of memory. */ + + found_better = 0; + for (p = elt->first_same_value, count = 0; + p && count < 32; + p = p->next_same_value, count++) + if (! p->flag + && (GET_CODE (p->exp) == REG + || exp_equiv_p (p->exp, p->exp, 1, 0))) + { + rtx new = cse_gen_binary (GET_CODE (*loc), Pmode, p->exp, c); + + if ((CSE_ADDRESS_COST (new) < best_addr_cost + || (CSE_ADDRESS_COST (new) == best_addr_cost + && (COST (new) + 1) >> 1 > best_rtx_cost))) + { + found_better = 1; + best_addr_cost = CSE_ADDRESS_COST (new); + best_rtx_cost = (COST (new) + 1) >> 1; + best_elt = p; + best_rtx = new; + } + } + + if (found_better) + { + if (validate_change (insn, loc, + canon_reg (copy_rtx (best_rtx), + NULL_RTX), 0)) + return; + else + best_elt->flag = 1; + } + } + } +#endif +} + +/* Given an operation (CODE, *PARG1, *PARG2), where code is a comparison + operation (EQ, NE, GT, etc.), follow it back through the hash table and + what values are being compared. + + *PARG1 and *PARG2 are updated to contain the rtx representing the values + actually being compared. For example, if *PARG1 was (cc0) and *PARG2 + was (const_int 0), *PARG1 and *PARG2 will be set to the objects that were + compared to produce cc0. + + The return value is the comparison operator and is either the code of + A or the code corresponding to the inverse of the comparison. */ + +static enum rtx_code +find_comparison_args (code, parg1, parg2, pmode1, pmode2) + enum rtx_code code; + rtx *parg1, *parg2; + enum machine_mode *pmode1, *pmode2; +{ + rtx arg1, arg2; + + arg1 = *parg1, arg2 = *parg2; + + /* If ARG2 is const0_rtx, see what ARG1 is equivalent to. */ + + while (arg2 == CONST0_RTX (GET_MODE (arg1))) + { + /* Set non-zero when we find something of interest. */ + rtx x = 0; + int reverse_code = 0; + struct table_elt *p = 0; + + /* If arg1 is a COMPARE, extract the comparison arguments from it. + On machines with CC0, this is the only case that can occur, since + fold_rtx will return the COMPARE or item being compared with zero + when given CC0. */ + + if (GET_CODE (arg1) == COMPARE && arg2 == const0_rtx) + x = arg1; + + /* If ARG1 is a comparison operator and CODE is testing for + STORE_FLAG_VALUE, get the inner arguments. */ + + else if (GET_RTX_CLASS (GET_CODE (arg1)) == '<') + { + if (code == NE + || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_INT + && code == LT && STORE_FLAG_VALUE == -1) +#ifdef FLOAT_STORE_FLAG_VALUE + || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_FLOAT + && FLOAT_STORE_FLAG_VALUE < 0) +#endif + ) + x = arg1; + else if (code == EQ + || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_INT + && code == GE && STORE_FLAG_VALUE == -1) +#ifdef FLOAT_STORE_FLAG_VALUE + || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_FLOAT + && FLOAT_STORE_FLAG_VALUE < 0) +#endif + ) + x = arg1, reverse_code = 1; + } + + /* ??? We could also check for + + (ne (and (eq (...) (const_int 1))) (const_int 0)) + + and related forms, but let's wait until we see them occurring. */ + + if (x == 0) + /* Look up ARG1 in the hash table and see if it has an equivalence + that lets us see what is being compared. */ + p = lookup (arg1, safe_hash (arg1, GET_MODE (arg1)) % NBUCKETS, + GET_MODE (arg1)); + if (p) p = p->first_same_value; + + for (; p; p = p->next_same_value) + { + enum machine_mode inner_mode = GET_MODE (p->exp); + + /* If the entry isn't valid, skip it. */ + if (! exp_equiv_p (p->exp, p->exp, 1, 0)) + continue; + + if (GET_CODE (p->exp) == COMPARE + /* Another possibility is that this machine has a compare insn + that includes the comparison code. In that case, ARG1 would + be equivalent to a comparison operation that would set ARG1 to + either STORE_FLAG_VALUE or zero. If this is an NE operation, + ORIG_CODE is the actual comparison being done; if it is an EQ, + we must reverse ORIG_CODE. On machine with a negative value + for STORE_FLAG_VALUE, also look at LT and GE operations. */ + || ((code == NE + || (code == LT + && GET_MODE_CLASS (inner_mode) == MODE_INT + && (GET_MODE_BITSIZE (inner_mode) + <= HOST_BITS_PER_WIDE_INT) + && (STORE_FLAG_VALUE + & ((HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (inner_mode) - 1)))) +#ifdef FLOAT_STORE_FLAG_VALUE + || (code == LT + && GET_MODE_CLASS (inner_mode) == MODE_FLOAT + && FLOAT_STORE_FLAG_VALUE < 0) +#endif + ) + && GET_RTX_CLASS (GET_CODE (p->exp)) == '<')) + { + x = p->exp; + break; + } + else if ((code == EQ + || (code == GE + && GET_MODE_CLASS (inner_mode) == MODE_INT + && (GET_MODE_BITSIZE (inner_mode) + <= HOST_BITS_PER_WIDE_INT) + && (STORE_FLAG_VALUE + & ((HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (inner_mode) - 1)))) +#ifdef FLOAT_STORE_FLAG_VALUE + || (code == GE + && GET_MODE_CLASS (inner_mode) == MODE_FLOAT + && FLOAT_STORE_FLAG_VALUE < 0) +#endif + ) + && GET_RTX_CLASS (GET_CODE (p->exp)) == '<') + { + reverse_code = 1; + x = p->exp; + break; + } + + /* If this is fp + constant, the equivalent is a better operand since + it may let us predict the value of the comparison. */ + else if (NONZERO_BASE_PLUS_P (p->exp)) + { + arg1 = p->exp; + continue; + } + } + + /* If we didn't find a useful equivalence for ARG1, we are done. + Otherwise, set up for the next iteration. */ + if (x == 0) + break; + + arg1 = XEXP (x, 0), arg2 = XEXP (x, 1); + if (GET_RTX_CLASS (GET_CODE (x)) == '<') + code = GET_CODE (x); + + if (reverse_code) + code = reverse_condition (code); + } + + /* Return our results. Return the modes from before fold_rtx + because fold_rtx might produce const_int, and then it's too late. */ + *pmode1 = GET_MODE (arg1), *pmode2 = GET_MODE (arg2); + *parg1 = fold_rtx (arg1, 0), *parg2 = fold_rtx (arg2, 0); + + return code; +} + +/* Try to simplify a unary operation CODE whose output mode is to be + MODE with input operand OP whose mode was originally OP_MODE. + Return zero if no simplification can be made. */ + +rtx +simplify_unary_operation (code, mode, op, op_mode) + enum rtx_code code; + enum machine_mode mode; + rtx op; + enum machine_mode op_mode; +{ + register int width = GET_MODE_BITSIZE (mode); + + /* The order of these tests is critical so that, for example, we don't + check the wrong mode (input vs. output) for a conversion operation, + such as FIX. At some point, this should be simplified. */ + +#if !defined(REAL_IS_NOT_DOUBLE) || defined(REAL_ARITHMETIC) + + if (code == FLOAT && GET_MODE (op) == VOIDmode + && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT)) + { + HOST_WIDE_INT hv, lv; + REAL_VALUE_TYPE d; + + if (GET_CODE (op) == CONST_INT) + lv = INTVAL (op), hv = INTVAL (op) < 0 ? -1 : 0; + else + lv = CONST_DOUBLE_LOW (op), hv = CONST_DOUBLE_HIGH (op); + +#ifdef REAL_ARITHMETIC + REAL_VALUE_FROM_INT (d, lv, hv, mode); +#else + if (hv < 0) + { + d = (double) (~ hv); + d *= ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)) + * (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))); + d += (double) (unsigned HOST_WIDE_INT) (~ lv); + d = (- d - 1.0); + } + else + { + d = (double) hv; + d *= ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)) + * (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))); + d += (double) (unsigned HOST_WIDE_INT) lv; + } +#endif /* REAL_ARITHMETIC */ + d = real_value_truncate (mode, d); + return CONST_DOUBLE_FROM_REAL_VALUE (d, mode); + } + else if (code == UNSIGNED_FLOAT && GET_MODE (op) == VOIDmode + && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT)) + { + HOST_WIDE_INT hv, lv; + REAL_VALUE_TYPE d; + + if (GET_CODE (op) == CONST_INT) + lv = INTVAL (op), hv = INTVAL (op) < 0 ? -1 : 0; + else + lv = CONST_DOUBLE_LOW (op), hv = CONST_DOUBLE_HIGH (op); + + if (op_mode == VOIDmode) + { + /* We don't know how to interpret negative-looking numbers in + this case, so don't try to fold those. */ + if (hv < 0) + return 0; + } + else if (GET_MODE_BITSIZE (op_mode) >= HOST_BITS_PER_WIDE_INT * 2) + ; + else + hv = 0, lv &= GET_MODE_MASK (op_mode); + +#ifdef REAL_ARITHMETIC + REAL_VALUE_FROM_UNSIGNED_INT (d, lv, hv, mode); +#else + + d = (double) (unsigned HOST_WIDE_INT) hv; + d *= ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)) + * (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))); + d += (double) (unsigned HOST_WIDE_INT) lv; +#endif /* REAL_ARITHMETIC */ + d = real_value_truncate (mode, d); + return CONST_DOUBLE_FROM_REAL_VALUE (d, mode); + } +#endif + + if (GET_CODE (op) == CONST_INT + && width <= HOST_BITS_PER_WIDE_INT && width > 0) + { + register HOST_WIDE_INT arg0 = INTVAL (op); + register HOST_WIDE_INT val; + + switch (code) + { + case NOT: + val = ~ arg0; + break; + + case NEG: + val = - arg0; + break; + + case ABS: + val = (arg0 >= 0 ? arg0 : - arg0); + break; + + case FFS: + /* Don't use ffs here. Instead, get low order bit and then its + number. If arg0 is zero, this will return 0, as desired. */ + arg0 &= GET_MODE_MASK (mode); + val = exact_log2 (arg0 & (- arg0)) + 1; + break; + + case TRUNCATE: + val = arg0; + break; + + case ZERO_EXTEND: + if (op_mode == VOIDmode) + op_mode = mode; + if (GET_MODE_BITSIZE (op_mode) == HOST_BITS_PER_WIDE_INT) + { + /* If we were really extending the mode, + we would have to distinguish between zero-extension + and sign-extension. */ + if (width != GET_MODE_BITSIZE (op_mode)) + abort (); + val = arg0; + } + else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT) + val = arg0 & ~((HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (op_mode)); + else + return 0; + break; + + case SIGN_EXTEND: + if (op_mode == VOIDmode) + op_mode = mode; + if (GET_MODE_BITSIZE (op_mode) == HOST_BITS_PER_WIDE_INT) + { + /* If we were really extending the mode, + we would have to distinguish between zero-extension + and sign-extension. */ + if (width != GET_MODE_BITSIZE (op_mode)) + abort (); + val = arg0; + } + else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT) + { + val + = arg0 & ~((HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (op_mode)); + if (val + & ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (op_mode) - 1))) + val -= (HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode); + } + else + return 0; + break; + + case SQRT: + return 0; + + default: + abort (); + } + + /* Clear the bits that don't belong in our 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. */ + if (width < HOST_BITS_PER_WIDE_INT + && ((val & ((HOST_WIDE_INT) (-1) << (width - 1))) + != ((HOST_WIDE_INT) (-1) << (width - 1)))) + val &= ((HOST_WIDE_INT) 1 << width) - 1; + + /* 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 later confuses the sparc backend. */ + + if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width + && (val & ((HOST_WIDE_INT) 1 << (width - 1)))) + val |= ((HOST_WIDE_INT) (-1) << width); + + return GEN_INT (val); + } + + /* We can do some operations on integer CONST_DOUBLEs. Also allow + for a DImode operation on a CONST_INT. */ + else if (GET_MODE (op) == VOIDmode && width <= HOST_BITS_PER_INT * 2 + && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT)) + { + HOST_WIDE_INT l1, h1, lv, hv; + + if (GET_CODE (op) == CONST_DOUBLE) + l1 = CONST_DOUBLE_LOW (op), h1 = CONST_DOUBLE_HIGH (op); + else + l1 = INTVAL (op), h1 = l1 < 0 ? -1 : 0; + + switch (code) + { + case NOT: + lv = ~ l1; + hv = ~ h1; + break; + + case NEG: + neg_double (l1, h1, &lv, &hv); + break; + + case ABS: + if (h1 < 0) + neg_double (l1, h1, &lv, &hv); + else + lv = l1, hv = h1; + break; + + case FFS: + hv = 0; + if (l1 == 0) + lv = HOST_BITS_PER_WIDE_INT + exact_log2 (h1 & (-h1)) + 1; + else + lv = exact_log2 (l1 & (-l1)) + 1; + break; + + case TRUNCATE: + /* This is just a change-of-mode, so do nothing. */ + lv = l1, hv = h1; + break; + + case ZERO_EXTEND: + if (op_mode == VOIDmode + || GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT) + return 0; + + hv = 0; + lv = l1 & GET_MODE_MASK (op_mode); + break; + + case SIGN_EXTEND: + if (op_mode == VOIDmode + || GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT) + return 0; + else + { + lv = l1 & GET_MODE_MASK (op_mode); + if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT + && (lv & ((HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (op_mode) - 1))) != 0) + lv -= (HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode); + + hv = (lv < 0) ? ~ (HOST_WIDE_INT) 0 : 0; + } + break; + + case SQRT: + return 0; + + default: + return 0; + } + + return immed_double_const (lv, hv, mode); + } + +#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) + else if (GET_CODE (op) == CONST_DOUBLE + && GET_MODE_CLASS (mode) == MODE_FLOAT) + { + REAL_VALUE_TYPE d; + jmp_buf handler; + rtx x; + + if (setjmp (handler)) + /* There used to be a warning here, but that is inadvisable. + People may want to cause traps, and the natural way + to do it should not get a warning. */ + return 0; + + set_float_handler (handler); + + REAL_VALUE_FROM_CONST_DOUBLE (d, op); + + switch (code) + { + case NEG: + d = REAL_VALUE_NEGATE (d); + break; + + case ABS: + if (REAL_VALUE_NEGATIVE (d)) + d = REAL_VALUE_NEGATE (d); + break; + + case FLOAT_TRUNCATE: + d = real_value_truncate (mode, d); + break; + + case FLOAT_EXTEND: + /* All this does is change the mode. */ + break; + + case FIX: + d = REAL_VALUE_RNDZINT (d); + break; + + case UNSIGNED_FIX: + d = REAL_VALUE_UNSIGNED_RNDZINT (d); + break; + + case SQRT: + return 0; + + default: + abort (); + } + + x = CONST_DOUBLE_FROM_REAL_VALUE (d, mode); + set_float_handler (NULL_PTR); + return x; + } + + else if (GET_CODE (op) == CONST_DOUBLE + && GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT + && GET_MODE_CLASS (mode) == MODE_INT + && width <= HOST_BITS_PER_WIDE_INT && width > 0) + { + REAL_VALUE_TYPE d; + jmp_buf handler; + HOST_WIDE_INT val; + + if (setjmp (handler)) + return 0; + + set_float_handler (handler); + + REAL_VALUE_FROM_CONST_DOUBLE (d, op); + + switch (code) + { + case FIX: + val = REAL_VALUE_FIX (d); + break; + + case UNSIGNED_FIX: + val = REAL_VALUE_UNSIGNED_FIX (d); + break; + + default: + abort (); + } + + set_float_handler (NULL_PTR); + + /* Clear the bits that don't belong in our 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. */ + if (width < HOST_BITS_PER_WIDE_INT + && ((val & ((HOST_WIDE_INT) (-1) << (width - 1))) + != ((HOST_WIDE_INT) (-1) << (width - 1)))) + val &= ((HOST_WIDE_INT) 1 << width) - 1; + + /* 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 later confuses the sparc backend. */ + + if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width + && (val & ((HOST_WIDE_INT) 1 << (width - 1)))) + val |= ((HOST_WIDE_INT) (-1) << width); + + return GEN_INT (val); + } +#endif + /* This was formerly used only for non-IEEE float. + eggert@twinsun.com says it is safe for IEEE also. */ + else + { + /* There are some simplifications we can do even if the operands + aren't constant. */ + switch (code) + { + case NEG: + case NOT: + /* (not (not X)) == X, similarly for NEG. */ + if (GET_CODE (op) == code) + return XEXP (op, 0); + break; + + case SIGN_EXTEND: + /* (sign_extend (truncate (minus (label_ref L1) (label_ref L2)))) + becomes just the MINUS if its mode is MODE. This allows + folding switch statements on machines using casesi (such as + the Vax). */ + if (GET_CODE (op) == TRUNCATE + && GET_MODE (XEXP (op, 0)) == mode + && GET_CODE (XEXP (op, 0)) == MINUS + && GET_CODE (XEXP (XEXP (op, 0), 0)) == LABEL_REF + && GET_CODE (XEXP (XEXP (op, 0), 1)) == LABEL_REF) + return XEXP (op, 0); + +#ifdef POINTERS_EXTEND_UNSIGNED + if (! POINTERS_EXTEND_UNSIGNED + && mode == Pmode && GET_MODE (op) == ptr_mode + && CONSTANT_P (op)) + return convert_memory_address (Pmode, op); +#endif + break; + +#ifdef POINTERS_EXTEND_UNSIGNED + case ZERO_EXTEND: + if (POINTERS_EXTEND_UNSIGNED + && mode == Pmode && GET_MODE (op) == ptr_mode + && CONSTANT_P (op)) + return convert_memory_address (Pmode, op); + break; +#endif + + default: + break; + } + + return 0; + } +} + +/* Simplify a binary operation CODE with result mode MODE, operating on OP0 + and OP1. Return 0 if no simplification is possible. + + Don't use this for relational operations such as EQ or LT. + Use simplify_relational_operation instead. */ + +rtx +simplify_binary_operation (code, mode, op0, op1) + enum rtx_code code; + enum machine_mode mode; + rtx op0, op1; +{ + register HOST_WIDE_INT arg0, arg1, arg0s, arg1s; + HOST_WIDE_INT val; + int width = GET_MODE_BITSIZE (mode); + rtx tem; + + /* Relational operations don't work here. We must know the mode + of the operands in order to do the comparison correctly. + Assuming a full word can give incorrect results. + Consider comparing 128 with -128 in QImode. */ + + if (GET_RTX_CLASS (code) == '<') + abort (); + +#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) + if (GET_MODE_CLASS (mode) == MODE_FLOAT + && GET_CODE (op0) == CONST_DOUBLE && GET_CODE (op1) == CONST_DOUBLE + && mode == GET_MODE (op0) && mode == GET_MODE (op1)) + { + REAL_VALUE_TYPE f0, f1, value; + jmp_buf handler; + + if (setjmp (handler)) + return 0; + + set_float_handler (handler); + + REAL_VALUE_FROM_CONST_DOUBLE (f0, op0); + REAL_VALUE_FROM_CONST_DOUBLE (f1, op1); + f0 = real_value_truncate (mode, f0); + f1 = real_value_truncate (mode, f1); + +#ifdef REAL_ARITHMETIC +#ifndef REAL_INFINITY + if (code == DIV && REAL_VALUES_EQUAL (f1, dconst0)) + return 0; +#endif + REAL_ARITHMETIC (value, rtx_to_tree_code (code), f0, f1); +#else + switch (code) + { + case PLUS: + value = f0 + f1; + break; + case MINUS: + value = f0 - f1; + break; + case MULT: + value = f0 * f1; + break; + case DIV: +#ifndef REAL_INFINITY + if (f1 == 0) + return 0; +#endif + value = f0 / f1; + break; + case SMIN: + value = MIN (f0, f1); + break; + case SMAX: + value = MAX (f0, f1); + break; + default: + abort (); + } +#endif + + value = real_value_truncate (mode, value); + set_float_handler (NULL_PTR); + return CONST_DOUBLE_FROM_REAL_VALUE (value, mode); + } +#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */ + + /* We can fold some multi-word operations. */ + if (GET_MODE_CLASS (mode) == MODE_INT + && width == HOST_BITS_PER_WIDE_INT * 2 + && (GET_CODE (op0) == CONST_DOUBLE || GET_CODE (op0) == CONST_INT) + && (GET_CODE (op1) == CONST_DOUBLE || GET_CODE (op1) == CONST_INT)) + { + HOST_WIDE_INT l1, l2, h1, h2, lv, hv; + + if (GET_CODE (op0) == CONST_DOUBLE) + l1 = CONST_DOUBLE_LOW (op0), h1 = CONST_DOUBLE_HIGH (op0); + else + l1 = INTVAL (op0), h1 = l1 < 0 ? -1 : 0; + + if (GET_CODE (op1) == CONST_DOUBLE) + l2 = CONST_DOUBLE_LOW (op1), h2 = CONST_DOUBLE_HIGH (op1); + else + l2 = INTVAL (op1), h2 = l2 < 0 ? -1 : 0; + + switch (code) + { + case MINUS: + /* A - B == A + (-B). */ + neg_double (l2, h2, &lv, &hv); + l2 = lv, h2 = hv; + + /* .. fall through ... */ + + case PLUS: + add_double (l1, h1, l2, h2, &lv, &hv); + break; + + case MULT: + mul_double (l1, h1, l2, h2, &lv, &hv); + break; + + case DIV: case MOD: case UDIV: case UMOD: + /* We'd need to include tree.h to do this and it doesn't seem worth + it. */ + return 0; + + case AND: + lv = l1 & l2, hv = h1 & h2; + break; + + case IOR: + lv = l1 | l2, hv = h1 | h2; + break; + + case XOR: + lv = l1 ^ l2, hv = h1 ^ h2; + break; + + case SMIN: + if (h1 < h2 + || (h1 == h2 + && ((unsigned HOST_WIDE_INT) l1 + < (unsigned HOST_WIDE_INT) l2))) + lv = l1, hv = h1; + else + lv = l2, hv = h2; + break; + + case SMAX: + if (h1 > h2 + || (h1 == h2 + && ((unsigned HOST_WIDE_INT) l1 + > (unsigned HOST_WIDE_INT) l2))) + lv = l1, hv = h1; + else + lv = l2, hv = h2; + break; + + case UMIN: + if ((unsigned HOST_WIDE_INT) h1 < (unsigned HOST_WIDE_INT) h2 + || (h1 == h2 + && ((unsigned HOST_WIDE_INT) l1 + < (unsigned HOST_WIDE_INT) l2))) + lv = l1, hv = h1; + else + lv = l2, hv = h2; + break; + + case UMAX: + if ((unsigned HOST_WIDE_INT) h1 > (unsigned HOST_WIDE_INT) h2 + || (h1 == h2 + && ((unsigned HOST_WIDE_INT) l1 + > (unsigned HOST_WIDE_INT) l2))) + lv = l1, hv = h1; + else + lv = l2, hv = h2; + break; + + case LSHIFTRT: case ASHIFTRT: + case ASHIFT: + case ROTATE: case ROTATERT: +#ifdef SHIFT_COUNT_TRUNCATED + if (SHIFT_COUNT_TRUNCATED) + l2 &= (GET_MODE_BITSIZE (mode) - 1), h2 = 0; +#endif + + if (h2 != 0 || l2 < 0 || l2 >= GET_MODE_BITSIZE (mode)) + return 0; + + if (code == LSHIFTRT || code == ASHIFTRT) + rshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv, + code == ASHIFTRT); + else if (code == ASHIFT) + lshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv, 1); + else if (code == ROTATE) + lrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv); + else /* code == ROTATERT */ + rrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv); + break; + + default: + return 0; + } + + return immed_double_const (lv, hv, mode); + } + + if (GET_CODE (op0) != CONST_INT || GET_CODE (op1) != CONST_INT + || width > HOST_BITS_PER_WIDE_INT || width == 0) + { + /* Even if we can't compute a constant result, + there are some cases worth simplifying. */ + + switch (code) + { + case PLUS: + /* In IEEE floating point, x+0 is not the same as x. Similarly + for the other optimizations below. */ + if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT + && FLOAT_MODE_P (mode) && ! flag_fast_math) + break; + + if (op1 == CONST0_RTX (mode)) + return op0; + + /* ((-a) + b) -> (b - a) and similarly for (a + (-b)) */ + if (GET_CODE (op0) == NEG) + return cse_gen_binary (MINUS, mode, op1, XEXP (op0, 0)); + else if (GET_CODE (op1) == NEG) + return cse_gen_binary (MINUS, mode, op0, XEXP (op1, 0)); + + /* Handle both-operands-constant cases. We can only add + CONST_INTs to constants since the sum of relocatable symbols + can't be handled by most assemblers. Don't add CONST_INT + to CONST_INT since overflow won't be computed properly if wider + than HOST_BITS_PER_WIDE_INT. */ + + if (CONSTANT_P (op0) && GET_MODE (op0) != VOIDmode + && GET_CODE (op1) == CONST_INT) + return plus_constant (op0, INTVAL (op1)); + else if (CONSTANT_P (op1) && GET_MODE (op1) != VOIDmode + && GET_CODE (op0) == CONST_INT) + return plus_constant (op1, INTVAL (op0)); + + /* See if this is something like X * C - X or vice versa or + if the multiplication is written as a shift. If so, we can + distribute and make a new multiply, shift, or maybe just + have X (if C is 2 in the example above). But don't make + real multiply if we didn't have one before. */ + + if (! FLOAT_MODE_P (mode)) + { + HOST_WIDE_INT coeff0 = 1, coeff1 = 1; + rtx lhs = op0, rhs = op1; + int had_mult = 0; + + if (GET_CODE (lhs) == NEG) + coeff0 = -1, lhs = XEXP (lhs, 0); + else if (GET_CODE (lhs) == MULT + && GET_CODE (XEXP (lhs, 1)) == CONST_INT) + { + coeff0 = INTVAL (XEXP (lhs, 1)), lhs = XEXP (lhs, 0); + had_mult = 1; + } + else if (GET_CODE (lhs) == ASHIFT + && GET_CODE (XEXP (lhs, 1)) == CONST_INT + && INTVAL (XEXP (lhs, 1)) >= 0 + && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT) + { + coeff0 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1)); + lhs = XEXP (lhs, 0); + } + + if (GET_CODE (rhs) == NEG) + coeff1 = -1, rhs = XEXP (rhs, 0); + else if (GET_CODE (rhs) == MULT + && GET_CODE (XEXP (rhs, 1)) == CONST_INT) + { + coeff1 = INTVAL (XEXP (rhs, 1)), rhs = XEXP (rhs, 0); + had_mult = 1; + } + else if (GET_CODE (rhs) == ASHIFT + && GET_CODE (XEXP (rhs, 1)) == CONST_INT + && INTVAL (XEXP (rhs, 1)) >= 0 + && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT) + { + coeff1 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1)); + rhs = XEXP (rhs, 0); + } + + if (rtx_equal_p (lhs, rhs)) + { + tem = cse_gen_binary (MULT, mode, lhs, + GEN_INT (coeff0 + coeff1)); + return (GET_CODE (tem) == MULT && ! had_mult) ? 0 : tem; + } + } + + /* If one of the operands is a PLUS or a MINUS, see if we can + simplify this by the associative law. + Don't use the associative law for floating point. + The inaccuracy makes it nonassociative, + and subtle programs can break if operations are associated. */ + + if (INTEGRAL_MODE_P (mode) + && (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS + || GET_CODE (op1) == PLUS || GET_CODE (op1) == MINUS) + && (tem = simplify_plus_minus (code, mode, op0, op1)) != 0) + return tem; + break; + + case COMPARE: +#ifdef HAVE_cc0 + /* Convert (compare FOO (const_int 0)) to FOO unless we aren't + using cc0, in which case we want to leave it as a COMPARE + so we can distinguish it from a register-register-copy. + + In IEEE floating point, x-0 is not the same as x. */ + + if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT + || ! FLOAT_MODE_P (mode) || flag_fast_math) + && op1 == CONST0_RTX (mode)) + return op0; +#else + /* Do nothing here. */ +#endif + break; + + case MINUS: + /* None of these optimizations can be done for IEEE + floating point. */ + if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT + && FLOAT_MODE_P (mode) && ! flag_fast_math) + break; + + /* We can't assume x-x is 0 even with non-IEEE floating point, + but since it is zero except in very strange circumstances, we + will treat it as zero with -ffast-math. */ + if (rtx_equal_p (op0, op1) + && ! side_effects_p (op0) + && (! FLOAT_MODE_P (mode) || flag_fast_math)) + return CONST0_RTX (mode); + + /* Change subtraction from zero into negation. */ + if (op0 == CONST0_RTX (mode)) + return gen_rtx_NEG (mode, op1); + + /* (-1 - a) is ~a. */ + if (op0 == constm1_rtx) + return gen_rtx_NOT (mode, op1); + + /* Subtracting 0 has no effect. */ + if (op1 == CONST0_RTX (mode)) + return op0; + + /* See if this is something like X * C - X or vice versa or + if the multiplication is written as a shift. If so, we can + distribute and make a new multiply, shift, or maybe just + have X (if C is 2 in the example above). But don't make + real multiply if we didn't have one before. */ + + if (! FLOAT_MODE_P (mode)) + { + HOST_WIDE_INT coeff0 = 1, coeff1 = 1; + rtx lhs = op0, rhs = op1; + int had_mult = 0; + + if (GET_CODE (lhs) == NEG) + coeff0 = -1, lhs = XEXP (lhs, 0); + else if (GET_CODE (lhs) == MULT + && GET_CODE (XEXP (lhs, 1)) == CONST_INT) + { + coeff0 = INTVAL (XEXP (lhs, 1)), lhs = XEXP (lhs, 0); + had_mult = 1; + } + else if (GET_CODE (lhs) == ASHIFT + && GET_CODE (XEXP (lhs, 1)) == CONST_INT + && INTVAL (XEXP (lhs, 1)) >= 0 + && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT) + { + coeff0 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1)); + lhs = XEXP (lhs, 0); + } + + if (GET_CODE (rhs) == NEG) + coeff1 = - 1, rhs = XEXP (rhs, 0); + else if (GET_CODE (rhs) == MULT + && GET_CODE (XEXP (rhs, 1)) == CONST_INT) + { + coeff1 = INTVAL (XEXP (rhs, 1)), rhs = XEXP (rhs, 0); + had_mult = 1; + } + else if (GET_CODE (rhs) == ASHIFT + && GET_CODE (XEXP (rhs, 1)) == CONST_INT + && INTVAL (XEXP (rhs, 1)) >= 0 + && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT) + { + coeff1 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1)); + rhs = XEXP (rhs, 0); + } + + if (rtx_equal_p (lhs, rhs)) + { + tem = cse_gen_binary (MULT, mode, lhs, + GEN_INT (coeff0 - coeff1)); + return (GET_CODE (tem) == MULT && ! had_mult) ? 0 : tem; + } + } + + /* (a - (-b)) -> (a + b). */ + if (GET_CODE (op1) == NEG) + return cse_gen_binary (PLUS, mode, op0, XEXP (op1, 0)); + + /* If one of the operands is a PLUS or a MINUS, see if we can + simplify this by the associative law. + Don't use the associative law for floating point. + The inaccuracy makes it nonassociative, + and subtle programs can break if operations are associated. */ + + if (INTEGRAL_MODE_P (mode) + && (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS + || GET_CODE (op1) == PLUS || GET_CODE (op1) == MINUS) + && (tem = simplify_plus_minus (code, mode, op0, op1)) != 0) + return tem; + + /* Don't let a relocatable value get a negative coeff. */ + if (GET_CODE (op1) == CONST_INT && GET_MODE (op0) != VOIDmode) + return plus_constant (op0, - INTVAL (op1)); + + /* (x - (x & y)) -> (x & ~y) */ + if (GET_CODE (op1) == AND) + { + if (rtx_equal_p (op0, XEXP (op1, 0))) + return cse_gen_binary (AND, mode, op0, gen_rtx_NOT (mode, XEXP (op1, 1))); + if (rtx_equal_p (op0, XEXP (op1, 1))) + return cse_gen_binary (AND, mode, op0, gen_rtx_NOT (mode, XEXP (op1, 0))); + } + break; + + case MULT: + if (op1 == constm1_rtx) + { + tem = simplify_unary_operation (NEG, mode, op0, mode); + + return tem ? tem : gen_rtx_NEG (mode, op0); + } + + /* In IEEE floating point, x*0 is not always 0. */ + if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT + || ! FLOAT_MODE_P (mode) || flag_fast_math) + && op1 == CONST0_RTX (mode) + && ! side_effects_p (op0)) + return op1; + + /* In IEEE floating point, x*1 is not equivalent to x for nans. + However, ANSI says we can drop signals, + so we can do this anyway. */ + if (op1 == CONST1_RTX (mode)) + return op0; + + /* Convert multiply by constant power of two into shift unless + we are still generating RTL. This test is a kludge. */ + if (GET_CODE (op1) == CONST_INT + && (val = exact_log2 (INTVAL (op1))) >= 0 + /* If the mode is larger than the host word size, and the + uppermost bit is set, then this isn't a power of two due + to implicit sign extension. */ + && (width <= HOST_BITS_PER_WIDE_INT + || val != HOST_BITS_PER_WIDE_INT - 1) + && ! rtx_equal_function_value_matters) + return gen_rtx_ASHIFT (mode, op0, GEN_INT (val)); + + if (GET_CODE (op1) == CONST_DOUBLE + && GET_MODE_CLASS (GET_MODE (op1)) == MODE_FLOAT) + { + REAL_VALUE_TYPE d; + jmp_buf handler; + int op1is2, op1ism1; + + if (setjmp (handler)) + return 0; + + set_float_handler (handler); + REAL_VALUE_FROM_CONST_DOUBLE (d, op1); + op1is2 = REAL_VALUES_EQUAL (d, dconst2); + op1ism1 = REAL_VALUES_EQUAL (d, dconstm1); + set_float_handler (NULL_PTR); + + /* x*2 is x+x and x*(-1) is -x */ + if (op1is2 && GET_MODE (op0) == mode) + return gen_rtx_PLUS (mode, op0, copy_rtx (op0)); + + else if (op1ism1 && GET_MODE (op0) == mode) + return gen_rtx_NEG (mode, op0); + } + break; + + case IOR: + if (op1 == const0_rtx) + return op0; + if (GET_CODE (op1) == CONST_INT + && (INTVAL (op1) & GET_MODE_MASK (mode)) == GET_MODE_MASK (mode)) + return op1; + if (rtx_equal_p (op0, op1) && ! side_effects_p (op0)) + return op0; + /* A | (~A) -> -1 */ + if (((GET_CODE (op0) == NOT && rtx_equal_p (XEXP (op0, 0), op1)) + || (GET_CODE (op1) == NOT && rtx_equal_p (XEXP (op1, 0), op0))) + && ! side_effects_p (op0) + && GET_MODE_CLASS (mode) != MODE_CC) + return constm1_rtx; + break; + + case XOR: + if (op1 == const0_rtx) + return op0; + if (GET_CODE (op1) == CONST_INT + && (INTVAL (op1) & GET_MODE_MASK (mode)) == GET_MODE_MASK (mode)) + return gen_rtx_NOT (mode, op0); + if (op0 == op1 && ! side_effects_p (op0) + && GET_MODE_CLASS (mode) != MODE_CC) + return const0_rtx; + break; + + case AND: + if (op1 == const0_rtx && ! side_effects_p (op0)) + return const0_rtx; + if (GET_CODE (op1) == CONST_INT + && (INTVAL (op1) & GET_MODE_MASK (mode)) == GET_MODE_MASK (mode)) + return op0; + if (op0 == op1 && ! side_effects_p (op0) + && GET_MODE_CLASS (mode) != MODE_CC) + return op0; + /* A & (~A) -> 0 */ + if (((GET_CODE (op0) == NOT && rtx_equal_p (XEXP (op0, 0), op1)) + || (GET_CODE (op1) == NOT && rtx_equal_p (XEXP (op1, 0), op0))) + && ! side_effects_p (op0) + && GET_MODE_CLASS (mode) != MODE_CC) + return const0_rtx; + break; + + case UDIV: + /* Convert divide by power of two into shift (divide by 1 handled + below). */ + if (GET_CODE (op1) == CONST_INT + && (arg1 = exact_log2 (INTVAL (op1))) > 0) + return gen_rtx_LSHIFTRT (mode, op0, GEN_INT (arg1)); + + /* ... fall through ... */ + + case DIV: + if (op1 == CONST1_RTX (mode)) + return op0; + + /* In IEEE floating point, 0/x is not always 0. */ + if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT + || ! FLOAT_MODE_P (mode) || flag_fast_math) + && op0 == CONST0_RTX (mode) + && ! side_effects_p (op1)) + return op0; + +#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) + /* Change division by a constant into multiplication. Only do + this with -ffast-math until an expert says it is safe in + general. */ + else if (GET_CODE (op1) == CONST_DOUBLE + && GET_MODE_CLASS (GET_MODE (op1)) == MODE_FLOAT + && op1 != CONST0_RTX (mode) + && flag_fast_math) + { + REAL_VALUE_TYPE d; + REAL_VALUE_FROM_CONST_DOUBLE (d, op1); + + if (! REAL_VALUES_EQUAL (d, dconst0)) + { +#if defined (REAL_ARITHMETIC) + REAL_ARITHMETIC (d, rtx_to_tree_code (DIV), dconst1, d); + return gen_rtx_MULT (mode, op0, + CONST_DOUBLE_FROM_REAL_VALUE (d, mode)); +#else + return gen_rtx_MULT (mode, op0, + CONST_DOUBLE_FROM_REAL_VALUE (1./d, mode)); +#endif + } + } +#endif + break; + + case UMOD: + /* Handle modulus by power of two (mod with 1 handled below). */ + if (GET_CODE (op1) == CONST_INT + && exact_log2 (INTVAL (op1)) > 0) + return gen_rtx_AND (mode, op0, GEN_INT (INTVAL (op1) - 1)); + + /* ... fall through ... */ + + case MOD: + if ((op0 == const0_rtx || op1 == const1_rtx) + && ! side_effects_p (op0) && ! side_effects_p (op1)) + return const0_rtx; + break; + + case ROTATERT: + case ROTATE: + /* Rotating ~0 always results in ~0. */ + if (GET_CODE (op0) == CONST_INT && width <= HOST_BITS_PER_WIDE_INT + && INTVAL (op0) == GET_MODE_MASK (mode) + && ! side_effects_p (op1)) + return op0; + + /* ... fall through ... */ + + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + if (op1 == const0_rtx) + return op0; + if (op0 == const0_rtx && ! side_effects_p (op1)) + return op0; + break; + + case SMIN: + if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (op1) == CONST_INT + && INTVAL (op1) == (HOST_WIDE_INT) 1 << (width -1) + && ! side_effects_p (op0)) + return op1; + else if (rtx_equal_p (op0, op1) && ! side_effects_p (op0)) + return op0; + break; + + case SMAX: + if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (op1) == CONST_INT + && (INTVAL (op1) + == (unsigned HOST_WIDE_INT) GET_MODE_MASK (mode) >> 1) + && ! side_effects_p (op0)) + return op1; + else if (rtx_equal_p (op0, op1) && ! side_effects_p (op0)) + return op0; + break; + + case UMIN: + if (op1 == const0_rtx && ! side_effects_p (op0)) + return op1; + else if (rtx_equal_p (op0, op1) && ! side_effects_p (op0)) + return op0; + break; + + case UMAX: + if (op1 == constm1_rtx && ! side_effects_p (op0)) + return op1; + else if (rtx_equal_p (op0, op1) && ! side_effects_p (op0)) + return op0; + break; + + default: + abort (); + } + + return 0; + } + + /* Get the integer argument values in two forms: + zero-extended in ARG0, ARG1 and sign-extended in ARG0S, ARG1S. */ + + arg0 = INTVAL (op0); + arg1 = INTVAL (op1); + + if (width < HOST_BITS_PER_WIDE_INT) + { + arg0 &= ((HOST_WIDE_INT) 1 << width) - 1; + arg1 &= ((HOST_WIDE_INT) 1 << width) - 1; + + arg0s = arg0; + if (arg0s & ((HOST_WIDE_INT) 1 << (width - 1))) + arg0s |= ((HOST_WIDE_INT) (-1) << width); + + arg1s = arg1; + if (arg1s & ((HOST_WIDE_INT) 1 << (width - 1))) + arg1s |= ((HOST_WIDE_INT) (-1) << width); + } + else + { + arg0s = arg0; + arg1s = arg1; + } + + /* Compute the value of the arithmetic. */ + + switch (code) + { + case PLUS: + val = arg0s + arg1s; + break; + + case MINUS: + val = arg0s - arg1s; + break; + + case MULT: + val = arg0s * arg1s; + break; + + case DIV: + if (arg1s == 0) + return 0; + val = arg0s / arg1s; + break; + + case MOD: + if (arg1s == 0) + return 0; + val = arg0s % arg1s; + break; + + case UDIV: + if (arg1 == 0) + return 0; + val = (unsigned HOST_WIDE_INT) arg0 / arg1; + break; + + case UMOD: + if (arg1 == 0) + return 0; + val = (unsigned HOST_WIDE_INT) arg0 % arg1; + break; + + case AND: + val = arg0 & arg1; + break; + + case IOR: + val = arg0 | arg1; + break; + + case XOR: + val = arg0 ^ arg1; + break; + + case LSHIFTRT: + /* If shift count is undefined, don't fold it; let the machine do + what it wants. But truncate it if the machine will do that. */ + if (arg1 < 0) + return 0; + +#ifdef SHIFT_COUNT_TRUNCATED + if (SHIFT_COUNT_TRUNCATED) + arg1 %= width; +#endif + + val = ((unsigned HOST_WIDE_INT) arg0) >> arg1; + break; + + case ASHIFT: + if (arg1 < 0) + return 0; + +#ifdef SHIFT_COUNT_TRUNCATED + if (SHIFT_COUNT_TRUNCATED) + arg1 %= width; +#endif + + val = ((unsigned HOST_WIDE_INT) arg0) << arg1; + break; + + case ASHIFTRT: + if (arg1 < 0) + return 0; + +#ifdef SHIFT_COUNT_TRUNCATED + if (SHIFT_COUNT_TRUNCATED) + arg1 %= width; +#endif + + val = arg0s >> arg1; + + /* Bootstrap compiler may not have sign extended the right shift. + Manually extend the sign to insure bootstrap cc matches gcc. */ + if (arg0s < 0 && arg1 > 0) + val |= ((HOST_WIDE_INT) -1) << (HOST_BITS_PER_WIDE_INT - arg1); + + break; + + case ROTATERT: + if (arg1 < 0) + return 0; + + arg1 %= width; + val = ((((unsigned HOST_WIDE_INT) arg0) << (width - arg1)) + | (((unsigned HOST_WIDE_INT) arg0) >> arg1)); + break; + + case ROTATE: + if (arg1 < 0) + return 0; + + arg1 %= width; + val = ((((unsigned HOST_WIDE_INT) arg0) << arg1) + | (((unsigned HOST_WIDE_INT) arg0) >> (width - arg1))); + break; + + case COMPARE: + /* Do nothing here. */ + return 0; + + case SMIN: + val = arg0s <= arg1s ? arg0s : arg1s; + break; + + case UMIN: + val = ((unsigned HOST_WIDE_INT) arg0 + <= (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1); + break; + + case SMAX: + val = arg0s > arg1s ? arg0s : arg1s; + break; + + case UMAX: + val = ((unsigned HOST_WIDE_INT) arg0 + > (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1); + break; + + default: + abort (); + } + + /* Clear the bits that don't belong in our 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. */ + if (width < HOST_BITS_PER_WIDE_INT + && ((val & ((HOST_WIDE_INT) (-1) << (width - 1))) + != ((HOST_WIDE_INT) (-1) << (width - 1)))) + val &= ((HOST_WIDE_INT) 1 << width) - 1; + + /* 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 later confuses the sparc backend. */ + + if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width + && (val & ((HOST_WIDE_INT) 1 << (width - 1)))) + val |= ((HOST_WIDE_INT) (-1) << width); + + return GEN_INT (val); +} + +/* Simplify a PLUS or MINUS, at least one of whose operands may be another + PLUS or MINUS. + + Rather than test for specific case, we do this by a brute-force method + and do all possible simplifications until no more changes occur. Then + we rebuild the operation. */ + +static rtx +simplify_plus_minus (code, mode, op0, op1) + enum rtx_code code; + enum machine_mode mode; + rtx op0, op1; +{ + rtx ops[8]; + int negs[8]; + rtx result, tem; + int n_ops = 2, input_ops = 2, input_consts = 0, n_consts = 0; + int first = 1, negate = 0, changed; + int i, j; + + bzero ((char *) ops, sizeof ops); + + /* Set up the two operands and then expand them until nothing has been + changed. If we run out of room in our array, give up; this should + almost never happen. */ + + ops[0] = op0, ops[1] = op1, negs[0] = 0, negs[1] = (code == MINUS); + + changed = 1; + while (changed) + { + changed = 0; + + for (i = 0; i < n_ops; i++) + switch (GET_CODE (ops[i])) + { + case PLUS: + case MINUS: + if (n_ops == 7) + return 0; + + ops[n_ops] = XEXP (ops[i], 1); + negs[n_ops++] = GET_CODE (ops[i]) == MINUS ? !negs[i] : negs[i]; + ops[i] = XEXP (ops[i], 0); + input_ops++; + changed = 1; + break; + + case NEG: + ops[i] = XEXP (ops[i], 0); + negs[i] = ! negs[i]; + changed = 1; + break; + + case CONST: + ops[i] = XEXP (ops[i], 0); + input_consts++; + changed = 1; + break; + + case NOT: + /* ~a -> (-a - 1) */ + if (n_ops != 7) + { + ops[n_ops] = constm1_rtx; + negs[n_ops++] = negs[i]; + ops[i] = XEXP (ops[i], 0); + negs[i] = ! negs[i]; + changed = 1; + } + break; + + case CONST_INT: + if (negs[i]) + ops[i] = GEN_INT (- INTVAL (ops[i])), negs[i] = 0, changed = 1; + break; + + default: + break; + } + } + + /* If we only have two operands, we can't do anything. */ + if (n_ops <= 2) + return 0; + + /* Now simplify each pair of operands until nothing changes. The first + time through just simplify constants against each other. */ + + changed = 1; + while (changed) + { + changed = first; + + for (i = 0; i < n_ops - 1; i++) + for (j = i + 1; j < n_ops; j++) + if (ops[i] != 0 && ops[j] != 0 + && (! first || (CONSTANT_P (ops[i]) && CONSTANT_P (ops[j])))) + { + rtx lhs = ops[i], rhs = ops[j]; + enum rtx_code ncode = PLUS; + + if (negs[i] && ! negs[j]) + lhs = ops[j], rhs = ops[i], ncode = MINUS; + else if (! negs[i] && negs[j]) + ncode = MINUS; + + tem = simplify_binary_operation (ncode, mode, lhs, rhs); + if (tem) + { + ops[i] = tem, ops[j] = 0; + negs[i] = negs[i] && negs[j]; + if (GET_CODE (tem) == NEG) + ops[i] = XEXP (tem, 0), negs[i] = ! negs[i]; + + if (GET_CODE (ops[i]) == CONST_INT && negs[i]) + ops[i] = GEN_INT (- INTVAL (ops[i])), negs[i] = 0; + changed = 1; + } + } + + first = 0; + } + + /* Pack all the operands to the lower-numbered entries and give up if + we didn't reduce the number of operands we had. Make sure we + count a CONST as two operands. If we have the same number of + operands, but have made more CONSTs than we had, this is also + an improvement, so accept it. */ + + for (i = 0, j = 0; j < n_ops; j++) + if (ops[j] != 0) + { + ops[i] = ops[j], negs[i++] = negs[j]; + if (GET_CODE (ops[j]) == CONST) + n_consts++; + } + + if (i + n_consts > input_ops + || (i + n_consts == input_ops && n_consts <= input_consts)) + return 0; + + n_ops = i; + + /* If we have a CONST_INT, put it last. */ + for (i = 0; i < n_ops - 1; i++) + if (GET_CODE (ops[i]) == CONST_INT) + { + tem = ops[n_ops - 1], ops[n_ops - 1] = ops[i] , ops[i] = tem; + j = negs[n_ops - 1], negs[n_ops - 1] = negs[i], negs[i] = j; + } + + /* Put a non-negated operand first. If there aren't any, make all + operands positive and negate the whole thing later. */ + for (i = 0; i < n_ops && negs[i]; i++) + ; + + if (i == n_ops) + { + for (i = 0; i < n_ops; i++) + negs[i] = 0; + negate = 1; + } + else if (i != 0) + { + tem = ops[0], ops[0] = ops[i], ops[i] = tem; + j = negs[0], negs[0] = negs[i], negs[i] = j; + } + + /* Now make the result by performing the requested operations. */ + result = ops[0]; + for (i = 1; i < n_ops; i++) + result = cse_gen_binary (negs[i] ? MINUS : PLUS, mode, result, ops[i]); + + return negate ? gen_rtx_NEG (mode, result) : result; +} + +/* Make a binary operation by properly ordering the operands and + seeing if the expression folds. */ + +static rtx +cse_gen_binary (code, mode, op0, op1) + enum rtx_code code; + enum machine_mode mode; + rtx op0, op1; +{ + rtx tem; + + /* Put complex operands first and constants second if commutative. */ + if (GET_RTX_CLASS (code) == 'c' + && ((CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT) + || (GET_RTX_CLASS (GET_CODE (op0)) == 'o' + && GET_RTX_CLASS (GET_CODE (op1)) != 'o') + || (GET_CODE (op0) == SUBREG + && GET_RTX_CLASS (GET_CODE (SUBREG_REG (op0))) == 'o' + && GET_RTX_CLASS (GET_CODE (op1)) != 'o'))) + tem = op0, op0 = op1, op1 = tem; + + /* If this simplifies, do it. */ + tem = simplify_binary_operation (code, mode, op0, op1); + + if (tem) + return tem; + + /* Handle addition and subtraction of CONST_INT specially. Otherwise, + just form the operation. */ + + if (code == PLUS && GET_CODE (op1) == CONST_INT + && GET_MODE (op0) != VOIDmode) + return plus_constant (op0, INTVAL (op1)); + else if (code == MINUS && GET_CODE (op1) == CONST_INT + && GET_MODE (op0) != VOIDmode) + return plus_constant (op0, - INTVAL (op1)); + else + return gen_rtx_fmt_ee (code, mode, op0, op1); +} + +/* Like simplify_binary_operation except used for relational operators. + MODE is the mode of the operands, not that of the result. If MODE + is VOIDmode, both operands must also be VOIDmode and we compare the + operands in "infinite precision". + + If no simplification is possible, this function returns zero. Otherwise, + it returns either const_true_rtx or const0_rtx. */ + +rtx +simplify_relational_operation (code, mode, op0, op1) + enum rtx_code code; + enum machine_mode mode; + rtx op0, op1; +{ + int equal, op0lt, op0ltu, op1lt, op1ltu; + rtx tem; + + /* If op0 is a compare, extract the comparison arguments from it. */ + if (GET_CODE (op0) == COMPARE && op1 == const0_rtx) + op1 = XEXP (op0, 1), op0 = XEXP (op0, 0); + + /* We can't simplify MODE_CC values since we don't know what the + actual comparison is. */ + if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC +#ifdef HAVE_cc0 + || op0 == cc0_rtx +#endif + ) + return 0; + + /* For integer comparisons of A and B maybe we can simplify A - B and can + then simplify a comparison of that with zero. If A and B are both either + a register or a CONST_INT, this can't help; testing for these cases will + prevent infinite recursion here and speed things up. + + If CODE is an unsigned comparison, then we can never do this optimization, + because it gives an incorrect result if the subtraction wraps around zero. + ANSI C defines unsigned operations such that they never overflow, and + thus such cases can not be ignored. */ + + if (INTEGRAL_MODE_P (mode) && op1 != const0_rtx + && ! ((GET_CODE (op0) == REG || GET_CODE (op0) == CONST_INT) + && (GET_CODE (op1) == REG || GET_CODE (op1) == CONST_INT)) + && 0 != (tem = simplify_binary_operation (MINUS, mode, op0, op1)) + && code != GTU && code != GEU && code != LTU && code != LEU) + return simplify_relational_operation (signed_condition (code), + mode, tem, const0_rtx); + + /* For non-IEEE floating-point, if the two operands are equal, we know the + result. */ + if (rtx_equal_p (op0, op1) + && (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT + || ! FLOAT_MODE_P (GET_MODE (op0)) || flag_fast_math)) + equal = 1, op0lt = 0, op0ltu = 0, op1lt = 0, op1ltu = 0; + + /* If the operands are floating-point constants, see if we can fold + the result. */ +#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) + else if (GET_CODE (op0) == CONST_DOUBLE && GET_CODE (op1) == CONST_DOUBLE + && GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT) + { + REAL_VALUE_TYPE d0, d1; + jmp_buf handler; + + if (setjmp (handler)) + return 0; + + set_float_handler (handler); + REAL_VALUE_FROM_CONST_DOUBLE (d0, op0); + REAL_VALUE_FROM_CONST_DOUBLE (d1, op1); + equal = REAL_VALUES_EQUAL (d0, d1); + op0lt = op0ltu = REAL_VALUES_LESS (d0, d1); + op1lt = op1ltu = REAL_VALUES_LESS (d1, d0); + set_float_handler (NULL_PTR); + } +#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */ + + /* Otherwise, see if the operands are both integers. */ + else if ((GET_MODE_CLASS (mode) == MODE_INT || mode == VOIDmode) + && (GET_CODE (op0) == CONST_DOUBLE || GET_CODE (op0) == CONST_INT) + && (GET_CODE (op1) == CONST_DOUBLE || GET_CODE (op1) == CONST_INT)) + { + int width = GET_MODE_BITSIZE (mode); + HOST_WIDE_INT l0s, h0s, l1s, h1s; + unsigned HOST_WIDE_INT l0u, h0u, l1u, h1u; + + /* Get the two words comprising each integer constant. */ + if (GET_CODE (op0) == CONST_DOUBLE) + { + l0u = l0s = CONST_DOUBLE_LOW (op0); + h0u = h0s = CONST_DOUBLE_HIGH (op0); + } + else + { + l0u = l0s = INTVAL (op0); + h0u = h0s = l0s < 0 ? -1 : 0; + } + + if (GET_CODE (op1) == CONST_DOUBLE) + { + l1u = l1s = CONST_DOUBLE_LOW (op1); + h1u = h1s = CONST_DOUBLE_HIGH (op1); + } + else + { + l1u = l1s = INTVAL (op1); + h1u = h1s = l1s < 0 ? -1 : 0; + } + + /* If WIDTH is nonzero and smaller than HOST_BITS_PER_WIDE_INT, + we have to sign or zero-extend the values. */ + if (width != 0 && width <= HOST_BITS_PER_WIDE_INT) + h0u = h1u = 0, h0s = l0s < 0 ? -1 : 0, h1s = l1s < 0 ? -1 : 0; + + if (width != 0 && width < HOST_BITS_PER_WIDE_INT) + { + l0u &= ((HOST_WIDE_INT) 1 << width) - 1; + l1u &= ((HOST_WIDE_INT) 1 << width) - 1; + + if (l0s & ((HOST_WIDE_INT) 1 << (width - 1))) + l0s |= ((HOST_WIDE_INT) (-1) << width); + + if (l1s & ((HOST_WIDE_INT) 1 << (width - 1))) + l1s |= ((HOST_WIDE_INT) (-1) << width); + } + + equal = (h0u == h1u && l0u == l1u); + op0lt = (h0s < h1s || (h0s == h1s && l0s < l1s)); + op1lt = (h1s < h0s || (h1s == h0s && l1s < l0s)); + op0ltu = (h0u < h1u || (h0u == h1u && l0u < l1u)); + op1ltu = (h1u < h0u || (h1u == h0u && l1u < l0u)); + } + + /* Otherwise, there are some code-specific tests we can make. */ + else + { + switch (code) + { + case EQ: + /* References to the frame plus a constant or labels cannot + be zero, but a SYMBOL_REF can due to #pragma weak. */ + if (((NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx) + || GET_CODE (op0) == LABEL_REF) +#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM + /* On some machines, the ap reg can be 0 sometimes. */ + && op0 != arg_pointer_rtx +#endif + ) + return const0_rtx; + break; + + case NE: + if (((NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx) + || GET_CODE (op0) == LABEL_REF) +#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM + && op0 != arg_pointer_rtx +#endif + ) + return const_true_rtx; + break; + + case GEU: + /* Unsigned values are never negative. */ + if (op1 == const0_rtx) + return const_true_rtx; + break; + + case LTU: + if (op1 == const0_rtx) + return const0_rtx; + break; + + case LEU: + /* Unsigned values are never greater than the largest + unsigned value. */ + if (GET_CODE (op1) == CONST_INT + && INTVAL (op1) == GET_MODE_MASK (mode) + && INTEGRAL_MODE_P (mode)) + return const_true_rtx; + break; + + case GTU: + if (GET_CODE (op1) == CONST_INT + && INTVAL (op1) == GET_MODE_MASK (mode) + && INTEGRAL_MODE_P (mode)) + return const0_rtx; + break; + + default: + break; + } + + return 0; + } + + /* If we reach here, EQUAL, OP0LT, OP0LTU, OP1LT, and OP1LTU are set + as appropriate. */ + switch (code) + { + case EQ: + return equal ? const_true_rtx : const0_rtx; + case NE: + return ! equal ? const_true_rtx : const0_rtx; + case LT: + return op0lt ? const_true_rtx : const0_rtx; + case GT: + return op1lt ? const_true_rtx : const0_rtx; + case LTU: + return op0ltu ? const_true_rtx : const0_rtx; + case GTU: + return op1ltu ? const_true_rtx : const0_rtx; + case LE: + return equal || op0lt ? const_true_rtx : const0_rtx; + case GE: + return equal || op1lt ? const_true_rtx : const0_rtx; + case LEU: + return equal || op0ltu ? const_true_rtx : const0_rtx; + case GEU: + return equal || op1ltu ? const_true_rtx : const0_rtx; + default: + abort (); + } +} + +/* Simplify CODE, an operation with result mode MODE and three operands, + OP0, OP1, and OP2. OP0_MODE was the mode of OP0 before it became + a constant. Return 0 if no simplifications is possible. */ + +rtx +simplify_ternary_operation (code, mode, op0_mode, op0, op1, op2) + enum rtx_code code; + enum machine_mode mode, op0_mode; + rtx op0, op1, op2; +{ + int width = GET_MODE_BITSIZE (mode); + + /* VOIDmode means "infinite" precision. */ + if (width == 0) + width = HOST_BITS_PER_WIDE_INT; + + switch (code) + { + case SIGN_EXTRACT: + case ZERO_EXTRACT: + if (GET_CODE (op0) == CONST_INT + && GET_CODE (op1) == CONST_INT + && GET_CODE (op2) == CONST_INT + && INTVAL (op1) + INTVAL (op2) <= GET_MODE_BITSIZE (op0_mode) + && width <= HOST_BITS_PER_WIDE_INT) + { + /* Extracting a bit-field from a constant */ + HOST_WIDE_INT val = INTVAL (op0); + + if (BITS_BIG_ENDIAN) + val >>= (GET_MODE_BITSIZE (op0_mode) + - INTVAL (op2) - INTVAL (op1)); + else + val >>= INTVAL (op2); + + if (HOST_BITS_PER_WIDE_INT != INTVAL (op1)) + { + /* First zero-extend. */ + val &= ((HOST_WIDE_INT) 1 << INTVAL (op1)) - 1; + /* If desired, propagate sign bit. */ + if (code == SIGN_EXTRACT + && (val & ((HOST_WIDE_INT) 1 << (INTVAL (op1) - 1)))) + val |= ~ (((HOST_WIDE_INT) 1 << INTVAL (op1)) - 1); + } + + /* Clear the bits that don't belong in our 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. */ + if (width < HOST_BITS_PER_WIDE_INT + && ((val & ((HOST_WIDE_INT) (-1) << (width - 1))) + != ((HOST_WIDE_INT) (-1) << (width - 1)))) + val &= ((HOST_WIDE_INT) 1 << width) - 1; + + return GEN_INT (val); + } + break; + + case IF_THEN_ELSE: + if (GET_CODE (op0) == CONST_INT) + return op0 != const0_rtx ? op1 : op2; + + /* Convert a == b ? b : a to "a". */ + if (GET_CODE (op0) == NE && ! side_effects_p (op0) + && rtx_equal_p (XEXP (op0, 0), op1) + && rtx_equal_p (XEXP (op0, 1), op2)) + return op1; + else if (GET_CODE (op0) == EQ && ! side_effects_p (op0) + && rtx_equal_p (XEXP (op0, 1), op1) + && rtx_equal_p (XEXP (op0, 0), op2)) + return op2; + else if (GET_RTX_CLASS (GET_CODE (op0)) == '<' && ! side_effects_p (op0)) + { + rtx temp; + temp = simplify_relational_operation (GET_CODE (op0), op0_mode, + XEXP (op0, 0), XEXP (op0, 1)); + /* See if any simplifications were possible. */ + if (temp == const0_rtx) + return op2; + else if (temp == const1_rtx) + return op1; + } + break; + + default: + abort (); + } + + return 0; +} + +/* If X is a nontrivial arithmetic operation on an argument + for which a constant value can be determined, return + the result of operating on that value, as a constant. + Otherwise, return X, possibly with one or more operands + modified by recursive calls to this function. + + If X is a register whose contents are known, we do NOT + return those contents here. equiv_constant is called to + perform that task. + + INSN is the insn that we may be modifying. If it is 0, make a copy + of X before modifying it. */ + +static rtx +fold_rtx (x, insn) + rtx x; + rtx insn; +{ + register enum rtx_code code; + register enum machine_mode mode; + register char *fmt; + register int i; + rtx new = 0; + int copied = 0; + int must_swap = 0; + + /* Folded equivalents of first two operands of X. */ + rtx folded_arg0; + rtx folded_arg1; + + /* Constant equivalents of first three operands of X; + 0 when no such equivalent is known. */ + rtx const_arg0; + rtx const_arg1; + rtx const_arg2; + + /* The mode of the first operand of X. We need this for sign and zero + extends. */ + enum machine_mode mode_arg0; + + if (x == 0) + return x; + + mode = GET_MODE (x); + code = GET_CODE (x); + switch (code) + { + case CONST: + /* If the operand is a CONSTANT_P_RTX, see if what's inside it + is known to be constant and replace the whole thing with a + CONST_INT of either zero or one. Note that this code assumes + that an insn that recognizes a CONST will also recognize a + CONST_INT, but that seems to be a safe assumption. */ + if (GET_CODE (XEXP (x, 0)) == CONSTANT_P_RTX) + { + x = equiv_constant (fold_rtx (XEXP (XEXP (x, 0), 0), 0)); + return (x != 0 && (GET_CODE (x) == CONST_INT + || GET_CODE (x) == CONST_DOUBLE) + ? const1_rtx : const0_rtx); + } + + /* ... fall through ... */ + + case CONST_INT: + case CONST_DOUBLE: + case SYMBOL_REF: + case LABEL_REF: + case REG: + /* No use simplifying an EXPR_LIST + since they are used only for lists of args + in a function call's REG_EQUAL note. */ + case EXPR_LIST: + /* Changing anything inside an ADDRESSOF is incorrect; we don't + want to (e.g.,) make (addressof (const_int 0)) just because + the location is known to be zero. */ + case ADDRESSOF: + return x; + +#ifdef HAVE_cc0 + case CC0: + return prev_insn_cc0; +#endif + + case PC: + /* If the next insn is a CODE_LABEL followed by a jump table, + PC's value is a LABEL_REF pointing to that label. That + lets us fold switch statements on the Vax. */ + if (insn && GET_CODE (insn) == JUMP_INSN) + { + rtx next = next_nonnote_insn (insn); + + if (next && GET_CODE (next) == CODE_LABEL + && NEXT_INSN (next) != 0 + && GET_CODE (NEXT_INSN (next)) == JUMP_INSN + && (GET_CODE (PATTERN (NEXT_INSN (next))) == ADDR_VEC + || GET_CODE (PATTERN (NEXT_INSN (next))) == ADDR_DIFF_VEC)) + return gen_rtx_LABEL_REF (Pmode, next); + } + break; + + case SUBREG: + /* See if we previously assigned a constant value to this SUBREG. */ + if ((new = lookup_as_function (x, CONST_INT)) != 0 + || (new = lookup_as_function (x, CONST_DOUBLE)) != 0) + return new; + + /* If this is a paradoxical SUBREG, we have no idea what value the + extra bits would have. However, if the operand is equivalent + to a SUBREG whose operand is the same as our mode, and all the + modes are within a word, we can just use the inner operand + because these SUBREGs just say how to treat the register. + + Similarly if we find an integer constant. */ + + if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) + { + enum machine_mode imode = GET_MODE (SUBREG_REG (x)); + struct table_elt *elt; + + if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD + && GET_MODE_SIZE (imode) <= UNITS_PER_WORD + && (elt = lookup (SUBREG_REG (x), HASH (SUBREG_REG (x), imode), + imode)) != 0) + for (elt = elt->first_same_value; + elt; elt = elt->next_same_value) + { + if (CONSTANT_P (elt->exp) + && GET_MODE (elt->exp) == VOIDmode) + return elt->exp; + + if (GET_CODE (elt->exp) == SUBREG + && GET_MODE (SUBREG_REG (elt->exp)) == mode + && exp_equiv_p (elt->exp, elt->exp, 1, 0)) + return copy_rtx (SUBREG_REG (elt->exp)); + } + + return x; + } + + /* Fold SUBREG_REG. If it changed, see if we can simplify the SUBREG. + We might be able to if the SUBREG is extracting a single word in an + integral mode or extracting the low part. */ + + folded_arg0 = fold_rtx (SUBREG_REG (x), insn); + const_arg0 = equiv_constant (folded_arg0); + if (const_arg0) + folded_arg0 = const_arg0; + + if (folded_arg0 != SUBREG_REG (x)) + { + new = 0; + + if (GET_MODE_CLASS (mode) == MODE_INT + && GET_MODE_SIZE (mode) == UNITS_PER_WORD + && GET_MODE (SUBREG_REG (x)) != VOIDmode) + new = operand_subword (folded_arg0, SUBREG_WORD (x), 0, + GET_MODE (SUBREG_REG (x))); + if (new == 0 && subreg_lowpart_p (x)) + new = gen_lowpart_if_possible (mode, folded_arg0); + if (new) + return new; + } + + /* If this is a narrowing SUBREG and our operand is a REG, see if + we can find an equivalence for REG that is an arithmetic operation + in a wider mode where both operands are paradoxical SUBREGs + from objects of our result mode. In that case, we couldn't report + an equivalent value for that operation, since we don't know what the + extra bits will be. But we can find an equivalence for this SUBREG + by folding that operation is the narrow mode. This allows us to + fold arithmetic in narrow modes when the machine only supports + word-sized arithmetic. + + Also look for a case where we have a SUBREG whose operand is the + same as our result. If both modes are smaller than a word, we + are simply interpreting a register in different modes and we + can use the inner value. */ + + if (GET_CODE (folded_arg0) == REG + && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (folded_arg0)) + && subreg_lowpart_p (x)) + { + struct table_elt *elt; + + /* We can use HASH here since we know that canon_hash won't be + called. */ + elt = lookup (folded_arg0, + HASH (folded_arg0, GET_MODE (folded_arg0)), + GET_MODE (folded_arg0)); + + if (elt) + elt = elt->first_same_value; + + for (; elt; elt = elt->next_same_value) + { + enum rtx_code eltcode = GET_CODE (elt->exp); + + /* Just check for unary and binary operations. */ + if (GET_RTX_CLASS (GET_CODE (elt->exp)) == '1' + && GET_CODE (elt->exp) != SIGN_EXTEND + && GET_CODE (elt->exp) != ZERO_EXTEND + && GET_CODE (XEXP (elt->exp, 0)) == SUBREG + && GET_MODE (SUBREG_REG (XEXP (elt->exp, 0))) == mode) + { + rtx op0 = SUBREG_REG (XEXP (elt->exp, 0)); + + if (GET_CODE (op0) != REG && ! CONSTANT_P (op0)) + op0 = fold_rtx (op0, NULL_RTX); + + op0 = equiv_constant (op0); + if (op0) + new = simplify_unary_operation (GET_CODE (elt->exp), mode, + op0, mode); + } + else if ((GET_RTX_CLASS (GET_CODE (elt->exp)) == '2' + || GET_RTX_CLASS (GET_CODE (elt->exp)) == 'c') + && eltcode != DIV && eltcode != MOD + && eltcode != UDIV && eltcode != UMOD + && eltcode != ASHIFTRT && eltcode != LSHIFTRT + && eltcode != ROTATE && eltcode != ROTATERT + && ((GET_CODE (XEXP (elt->exp, 0)) == SUBREG + && (GET_MODE (SUBREG_REG (XEXP (elt->exp, 0))) + == mode)) + || CONSTANT_P (XEXP (elt->exp, 0))) + && ((GET_CODE (XEXP (elt->exp, 1)) == SUBREG + && (GET_MODE (SUBREG_REG (XEXP (elt->exp, 1))) + == mode)) + || CONSTANT_P (XEXP (elt->exp, 1)))) + { + rtx op0 = gen_lowpart_common (mode, XEXP (elt->exp, 0)); + rtx op1 = gen_lowpart_common (mode, XEXP (elt->exp, 1)); + + if (op0 && GET_CODE (op0) != REG && ! CONSTANT_P (op0)) + op0 = fold_rtx (op0, NULL_RTX); + + if (op0) + op0 = equiv_constant (op0); + + if (op1 && GET_CODE (op1) != REG && ! CONSTANT_P (op1)) + op1 = fold_rtx (op1, NULL_RTX); + + if (op1) + op1 = equiv_constant (op1); + + /* If we are looking for the low SImode part of + (ashift:DI c (const_int 32)), it doesn't work + to compute that in SImode, because a 32-bit shift + in SImode is unpredictable. We know the value is 0. */ + if (op0 && op1 + && GET_CODE (elt->exp) == ASHIFT + && GET_CODE (op1) == CONST_INT + && INTVAL (op1) >= GET_MODE_BITSIZE (mode)) + { + if (INTVAL (op1) < GET_MODE_BITSIZE (GET_MODE (elt->exp))) + + /* If the count fits in the inner mode's width, + but exceeds the outer mode's width, + the value will get truncated to 0 + by the subreg. */ + new = const0_rtx; + else + /* If the count exceeds even the inner mode's width, + don't fold this expression. */ + new = 0; + } + else if (op0 && op1) + new = simplify_binary_operation (GET_CODE (elt->exp), mode, + op0, op1); + } + + else if (GET_CODE (elt->exp) == SUBREG + && GET_MODE (SUBREG_REG (elt->exp)) == mode + && (GET_MODE_SIZE (GET_MODE (folded_arg0)) + <= UNITS_PER_WORD) + && exp_equiv_p (elt->exp, elt->exp, 1, 0)) + new = copy_rtx (SUBREG_REG (elt->exp)); + + if (new) + return new; + } + } + + return x; + + case NOT: + case NEG: + /* If we have (NOT Y), see if Y is known to be (NOT Z). + If so, (NOT Y) simplifies to Z. Similarly for NEG. */ + new = lookup_as_function (XEXP (x, 0), code); + if (new) + return fold_rtx (copy_rtx (XEXP (new, 0)), insn); + break; + + case MEM: + /* If we are not actually processing an insn, don't try to find the + best address. Not only don't we care, but we could modify the + MEM in an invalid way since we have no insn to validate against. */ + if (insn != 0) + find_best_addr (insn, &XEXP (x, 0)); + + { + /* Even if we don't fold in the insn itself, + we can safely do so here, in hopes of getting a constant. */ + rtx addr = fold_rtx (XEXP (x, 0), NULL_RTX); + rtx base = 0; + HOST_WIDE_INT offset = 0; + + if (GET_CODE (addr) == REG + && REGNO_QTY_VALID_P (REGNO (addr)) + && GET_MODE (addr) == qty_mode[reg_qty[REGNO (addr)]] + && qty_const[reg_qty[REGNO (addr)]] != 0) + addr = qty_const[reg_qty[REGNO (addr)]]; + + /* If address is constant, split it into a base and integer offset. */ + if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF) + base = addr; + else if (GET_CODE (addr) == CONST && GET_CODE (XEXP (addr, 0)) == PLUS + && GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT) + { + base = XEXP (XEXP (addr, 0), 0); + offset = INTVAL (XEXP (XEXP (addr, 0), 1)); + } + else if (GET_CODE (addr) == LO_SUM + && GET_CODE (XEXP (addr, 1)) == SYMBOL_REF) + base = XEXP (addr, 1); + else if (GET_CODE (addr) == ADDRESSOF) + return change_address (x, VOIDmode, addr); + + /* If this is a constant pool reference, we can fold it into its + constant to allow better value tracking. */ + if (base && GET_CODE (base) == SYMBOL_REF + && CONSTANT_POOL_ADDRESS_P (base)) + { + rtx constant = get_pool_constant (base); + enum machine_mode const_mode = get_pool_mode (base); + rtx new; + + if (CONSTANT_P (constant) && GET_CODE (constant) != CONST_INT) + constant_pool_entries_cost = COST (constant); + + /* If we are loading the full constant, we have an equivalence. */ + if (offset == 0 && mode == const_mode) + return constant; + + /* If this actually isn't a constant (weird!), we can't do + anything. Otherwise, handle the two most common cases: + extracting a word from a multi-word constant, and extracting + the low-order bits. Other cases don't seem common enough to + worry about. */ + if (! CONSTANT_P (constant)) + return x; + + if (GET_MODE_CLASS (mode) == MODE_INT + && GET_MODE_SIZE (mode) == UNITS_PER_WORD + && offset % UNITS_PER_WORD == 0 + && (new = operand_subword (constant, + offset / UNITS_PER_WORD, + 0, const_mode)) != 0) + return new; + + if (((BYTES_BIG_ENDIAN + && offset == GET_MODE_SIZE (GET_MODE (constant)) - 1) + || (! BYTES_BIG_ENDIAN && offset == 0)) + && (new = gen_lowpart_if_possible (mode, constant)) != 0) + return new; + } + + /* If this is a reference to a label at a known position in a jump + table, we also know its value. */ + if (base && GET_CODE (base) == LABEL_REF) + { + rtx label = XEXP (base, 0); + rtx table_insn = NEXT_INSN (label); + + if (table_insn && GET_CODE (table_insn) == JUMP_INSN + && GET_CODE (PATTERN (table_insn)) == ADDR_VEC) + { + rtx table = PATTERN (table_insn); + + if (offset >= 0 + && (offset / GET_MODE_SIZE (GET_MODE (table)) + < XVECLEN (table, 0))) + return XVECEXP (table, 0, + offset / GET_MODE_SIZE (GET_MODE (table))); + } + if (table_insn && GET_CODE (table_insn) == JUMP_INSN + && GET_CODE (PATTERN (table_insn)) == ADDR_DIFF_VEC) + { + rtx table = PATTERN (table_insn); + + if (offset >= 0 + && (offset / GET_MODE_SIZE (GET_MODE (table)) + < XVECLEN (table, 1))) + { + offset /= GET_MODE_SIZE (GET_MODE (table)); + new = gen_rtx_MINUS (Pmode, XVECEXP (table, 1, offset), + XEXP (table, 0)); + + if (GET_MODE (table) != Pmode) + new = gen_rtx_TRUNCATE (GET_MODE (table), new); + + /* Indicate this is a constant. This isn't a + valid form of CONST, but it will only be used + to fold the next insns and then discarded, so + it should be safe. */ + return gen_rtx_CONST (GET_MODE (new), new); + } + } + } + + return x; + } + + case ASM_OPERANDS: + for (i = XVECLEN (x, 3) - 1; i >= 0; i--) + validate_change (insn, &XVECEXP (x, 3, i), + fold_rtx (XVECEXP (x, 3, i), insn), 0); + break; + + default: + break; + } + + const_arg0 = 0; + const_arg1 = 0; + const_arg2 = 0; + mode_arg0 = VOIDmode; + + /* Try folding our operands. + Then see which ones have constant values known. */ + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + if (fmt[i] == 'e') + { + rtx arg = XEXP (x, i); + rtx folded_arg = arg, const_arg = 0; + enum machine_mode mode_arg = GET_MODE (arg); + rtx cheap_arg, expensive_arg; + rtx replacements[2]; + int j; + + /* Most arguments are cheap, so handle them specially. */ + switch (GET_CODE (arg)) + { + case REG: + /* This is the same as calling equiv_constant; it is duplicated + here for speed. */ + if (REGNO_QTY_VALID_P (REGNO (arg)) + && qty_const[reg_qty[REGNO (arg)]] != 0 + && GET_CODE (qty_const[reg_qty[REGNO (arg)]]) != REG + && GET_CODE (qty_const[reg_qty[REGNO (arg)]]) != PLUS) + const_arg + = gen_lowpart_if_possible (GET_MODE (arg), + qty_const[reg_qty[REGNO (arg)]]); + break; + + case CONST: + case CONST_INT: + case SYMBOL_REF: + case LABEL_REF: + case CONST_DOUBLE: + const_arg = arg; + break; + +#ifdef HAVE_cc0 + case CC0: + folded_arg = prev_insn_cc0; + mode_arg = prev_insn_cc0_mode; + const_arg = equiv_constant (folded_arg); + break; +#endif + + default: + folded_arg = fold_rtx (arg, insn); + const_arg = equiv_constant (folded_arg); + } + + /* For the first three operands, see if the operand + is constant or equivalent to a constant. */ + switch (i) + { + case 0: + folded_arg0 = folded_arg; + const_arg0 = const_arg; + mode_arg0 = mode_arg; + break; + case 1: + folded_arg1 = folded_arg; + const_arg1 = const_arg; + break; + case 2: + const_arg2 = const_arg; + break; + } + + /* Pick the least expensive of the folded argument and an + equivalent constant argument. */ + if (const_arg == 0 || const_arg == folded_arg + || COST (const_arg) > COST (folded_arg)) + cheap_arg = folded_arg, expensive_arg = const_arg; + else + cheap_arg = const_arg, expensive_arg = folded_arg; + + /* Try to replace the operand with the cheapest of the two + possibilities. If it doesn't work and this is either of the first + two operands of a commutative operation, try swapping them. + If THAT fails, try the more expensive, provided it is cheaper + than what is already there. */ + + if (cheap_arg == XEXP (x, i)) + continue; + + if (insn == 0 && ! copied) + { + x = copy_rtx (x); + copied = 1; + } + + replacements[0] = cheap_arg, replacements[1] = expensive_arg; + for (j = 0; + j < 2 && replacements[j] + && COST (replacements[j]) < COST (XEXP (x, i)); + j++) + { + if (validate_change (insn, &XEXP (x, i), replacements[j], 0)) + break; + + if (code == NE || code == EQ || GET_RTX_CLASS (code) == 'c') + { + validate_change (insn, &XEXP (x, i), XEXP (x, 1 - i), 1); + validate_change (insn, &XEXP (x, 1 - i), replacements[j], 1); + + if (apply_change_group ()) + { + /* Swap them back to be invalid so that this loop can + continue and flag them to be swapped back later. */ + rtx tem; + + tem = XEXP (x, 0); XEXP (x, 0) = XEXP (x, 1); + XEXP (x, 1) = tem; + must_swap = 1; + break; + } + } + } + } + + else + { + if (fmt[i] == 'E') + /* Don't try to fold inside of a vector of expressions. + Doing nothing is harmless. */ + {;} + } + + /* If a commutative operation, place a constant integer as the second + operand unless the first operand is also a constant integer. Otherwise, + place any constant second unless the first operand is also a constant. */ + + if (code == EQ || code == NE || GET_RTX_CLASS (code) == 'c') + { + if (must_swap || (const_arg0 + && (const_arg1 == 0 + || (GET_CODE (const_arg0) == CONST_INT + && GET_CODE (const_arg1) != CONST_INT)))) + { + register rtx tem = XEXP (x, 0); + + if (insn == 0 && ! copied) + { + x = copy_rtx (x); + copied = 1; + } + + validate_change (insn, &XEXP (x, 0), XEXP (x, 1), 1); + validate_change (insn, &XEXP (x, 1), tem, 1); + if (apply_change_group ()) + { + tem = const_arg0, const_arg0 = const_arg1, const_arg1 = tem; + tem = folded_arg0, folded_arg0 = folded_arg1, folded_arg1 = tem; + } + } + } + + /* If X is an arithmetic operation, see if we can simplify it. */ + + switch (GET_RTX_CLASS (code)) + { + case '1': + { + int is_const = 0; + + /* We can't simplify extension ops unless we know the + original mode. */ + if ((code == ZERO_EXTEND || code == SIGN_EXTEND) + && mode_arg0 == VOIDmode) + break; + + /* If we had a CONST, strip it off and put it back later if we + fold. */ + if (const_arg0 != 0 && GET_CODE (const_arg0) == CONST) + is_const = 1, const_arg0 = XEXP (const_arg0, 0); + + new = simplify_unary_operation (code, mode, + const_arg0 ? const_arg0 : folded_arg0, + mode_arg0); + if (new != 0 && is_const) + new = gen_rtx_CONST (mode, new); + } + break; + + case '<': + /* See what items are actually being compared and set FOLDED_ARG[01] + to those values and CODE to the actual comparison code. If any are + constant, set CONST_ARG0 and CONST_ARG1 appropriately. We needn't + do anything if both operands are already known to be constant. */ + + if (const_arg0 == 0 || const_arg1 == 0) + { + struct table_elt *p0, *p1; + rtx true = const_true_rtx, false = const0_rtx; + enum machine_mode mode_arg1; + +#ifdef FLOAT_STORE_FLAG_VALUE + if (GET_MODE_CLASS (mode) == MODE_FLOAT) + { + true = CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE, + mode); + false = CONST0_RTX (mode); + } +#endif + + code = find_comparison_args (code, &folded_arg0, &folded_arg1, + &mode_arg0, &mode_arg1); + const_arg0 = equiv_constant (folded_arg0); + const_arg1 = equiv_constant (folded_arg1); + + /* If the mode is VOIDmode or a MODE_CC mode, we don't know + what kinds of things are being compared, so we can't do + anything with this comparison. */ + + if (mode_arg0 == VOIDmode || GET_MODE_CLASS (mode_arg0) == MODE_CC) + break; + + /* If we do not now have two constants being compared, see + if we can nevertheless deduce some things about the + comparison. */ + if (const_arg0 == 0 || const_arg1 == 0) + { + /* Is FOLDED_ARG0 frame-pointer plus a constant? Or + non-explicit constant? These aren't zero, but we + don't know their sign. */ + if (const_arg1 == const0_rtx + && (NONZERO_BASE_PLUS_P (folded_arg0) +#if 0 /* Sad to say, on sysvr4, #pragma weak can make a symbol address + come out as 0. */ + || GET_CODE (folded_arg0) == SYMBOL_REF +#endif + || GET_CODE (folded_arg0) == LABEL_REF + || GET_CODE (folded_arg0) == CONST)) + { + if (code == EQ) + return false; + else if (code == NE) + return true; + } + + /* See if the two operands are the same. We don't do this + for IEEE floating-point since we can't assume x == x + since x might be a NaN. */ + + if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT + || ! FLOAT_MODE_P (mode_arg0) || flag_fast_math) + && (folded_arg0 == folded_arg1 + || (GET_CODE (folded_arg0) == REG + && GET_CODE (folded_arg1) == REG + && (reg_qty[REGNO (folded_arg0)] + == reg_qty[REGNO (folded_arg1)])) + || ((p0 = lookup (folded_arg0, + (safe_hash (folded_arg0, mode_arg0) + % NBUCKETS), mode_arg0)) + && (p1 = lookup (folded_arg1, + (safe_hash (folded_arg1, mode_arg0) + % NBUCKETS), mode_arg0)) + && p0->first_same_value == p1->first_same_value))) + return ((code == EQ || code == LE || code == GE + || code == LEU || code == GEU) + ? true : false); + + /* If FOLDED_ARG0 is a register, see if the comparison we are + doing now is either the same as we did before or the reverse + (we only check the reverse if not floating-point). */ + else if (GET_CODE (folded_arg0) == REG) + { + int qty = reg_qty[REGNO (folded_arg0)]; + + if (REGNO_QTY_VALID_P (REGNO (folded_arg0)) + && (comparison_dominates_p (qty_comparison_code[qty], code) + || (comparison_dominates_p (qty_comparison_code[qty], + reverse_condition (code)) + && ! FLOAT_MODE_P (mode_arg0))) + && (rtx_equal_p (qty_comparison_const[qty], folded_arg1) + || (const_arg1 + && rtx_equal_p (qty_comparison_const[qty], + const_arg1)) + || (GET_CODE (folded_arg1) == REG + && (reg_qty[REGNO (folded_arg1)] + == qty_comparison_qty[qty])))) + return (comparison_dominates_p (qty_comparison_code[qty], + code) + ? true : false); + } + } + } + + /* If we are comparing against zero, see if the first operand is + equivalent to an IOR with a constant. If so, we may be able to + determine the result of this comparison. */ + + if (const_arg1 == const0_rtx) + { + rtx y = lookup_as_function (folded_arg0, IOR); + rtx inner_const; + + if (y != 0 + && (inner_const = equiv_constant (XEXP (y, 1))) != 0 + && GET_CODE (inner_const) == CONST_INT + && INTVAL (inner_const) != 0) + { + int sign_bitnum = GET_MODE_BITSIZE (mode_arg0) - 1; + int has_sign = (HOST_BITS_PER_WIDE_INT >= sign_bitnum + && (INTVAL (inner_const) + & ((HOST_WIDE_INT) 1 << sign_bitnum))); + rtx true = const_true_rtx, false = const0_rtx; + +#ifdef FLOAT_STORE_FLAG_VALUE + if (GET_MODE_CLASS (mode) == MODE_FLOAT) + { + true = CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE, + mode); + false = CONST0_RTX (mode); + } +#endif + + switch (code) + { + case EQ: + return false; + case NE: + return true; + case LT: case LE: + if (has_sign) + return true; + break; + case GT: case GE: + if (has_sign) + return false; + break; + default: + break; + } + } + } + + new = simplify_relational_operation (code, mode_arg0, + const_arg0 ? const_arg0 : folded_arg0, + const_arg1 ? const_arg1 : folded_arg1); +#ifdef FLOAT_STORE_FLAG_VALUE + if (new != 0 && GET_MODE_CLASS (mode) == MODE_FLOAT) + new = ((new == const0_rtx) ? CONST0_RTX (mode) + : CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE, mode)); +#endif + break; + + case '2': + case 'c': + switch (code) + { + case PLUS: + /* If the second operand is a LABEL_REF, see if the first is a MINUS + with that LABEL_REF as its second operand. If so, the result is + the first operand of that MINUS. This handles switches with an + ADDR_DIFF_VEC table. */ + if (const_arg1 && GET_CODE (const_arg1) == LABEL_REF) + { + rtx y + = GET_CODE (folded_arg0) == MINUS ? folded_arg0 + : lookup_as_function (folded_arg0, MINUS); + + if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF + && XEXP (XEXP (y, 1), 0) == XEXP (const_arg1, 0)) + return XEXP (y, 0); + + /* Now try for a CONST of a MINUS like the above. */ + if ((y = (GET_CODE (folded_arg0) == CONST ? folded_arg0 + : lookup_as_function (folded_arg0, CONST))) != 0 + && GET_CODE (XEXP (y, 0)) == MINUS + && GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF + && XEXP (XEXP (XEXP (y, 0),1), 0) == XEXP (const_arg1, 0)) + return XEXP (XEXP (y, 0), 0); + } + + /* Likewise if the operands are in the other order. */ + if (const_arg0 && GET_CODE (const_arg0) == LABEL_REF) + { + rtx y + = GET_CODE (folded_arg1) == MINUS ? folded_arg1 + : lookup_as_function (folded_arg1, MINUS); + + if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF + && XEXP (XEXP (y, 1), 0) == XEXP (const_arg0, 0)) + return XEXP (y, 0); + + /* Now try for a CONST of a MINUS like the above. */ + if ((y = (GET_CODE (folded_arg1) == CONST ? folded_arg1 + : lookup_as_function (folded_arg1, CONST))) != 0 + && GET_CODE (XEXP (y, 0)) == MINUS + && GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF + && XEXP (XEXP (XEXP (y, 0),1), 0) == XEXP (const_arg0, 0)) + return XEXP (XEXP (y, 0), 0); + } + + /* If second operand is a register equivalent to a negative + CONST_INT, see if we can find a register equivalent to the + positive constant. Make a MINUS if so. Don't do this for + a non-negative constant since we might then alternate between + chosing positive and negative constants. Having the positive + constant previously-used is the more common case. Be sure + the resulting constant is non-negative; if const_arg1 were + the smallest negative number this would overflow: depending + on the mode, this would either just be the same value (and + hence not save anything) or be incorrect. */ + if (const_arg1 != 0 && GET_CODE (const_arg1) == CONST_INT + && INTVAL (const_arg1) < 0 + && - INTVAL (const_arg1) >= 0 + && GET_CODE (folded_arg1) == REG) + { + rtx new_const = GEN_INT (- INTVAL (const_arg1)); + struct table_elt *p + = lookup (new_const, safe_hash (new_const, mode) % NBUCKETS, + mode); + + if (p) + for (p = p->first_same_value; p; p = p->next_same_value) + if (GET_CODE (p->exp) == REG) + return cse_gen_binary (MINUS, mode, folded_arg0, + canon_reg (p->exp, NULL_RTX)); + } + goto from_plus; + + case MINUS: + /* If we have (MINUS Y C), see if Y is known to be (PLUS Z C2). + If so, produce (PLUS Z C2-C). */ + if (const_arg1 != 0 && GET_CODE (const_arg1) == CONST_INT) + { + rtx y = lookup_as_function (XEXP (x, 0), PLUS); + if (y && GET_CODE (XEXP (y, 1)) == CONST_INT) + return fold_rtx (plus_constant (copy_rtx (y), + -INTVAL (const_arg1)), + NULL_RTX); + } + + /* ... fall through ... */ + + from_plus: + case SMIN: case SMAX: case UMIN: case UMAX: + case IOR: case AND: case XOR: + case MULT: case DIV: case UDIV: + case ASHIFT: case LSHIFTRT: case ASHIFTRT: + /* If we have ( ) for an associative OP and REG + is known to be of similar form, we may be able to replace the + operation with a combined operation. This may eliminate the + intermediate operation if every use is simplified in this way. + Note that the similar optimization done by combine.c only works + if the intermediate operation's result has only one reference. */ + + if (GET_CODE (folded_arg0) == REG + && const_arg1 && GET_CODE (const_arg1) == CONST_INT) + { + int is_shift + = (code == ASHIFT || code == ASHIFTRT || code == LSHIFTRT); + rtx y = lookup_as_function (folded_arg0, code); + rtx inner_const; + enum rtx_code associate_code; + rtx new_const; + + if (y == 0 + || 0 == (inner_const + = equiv_constant (fold_rtx (XEXP (y, 1), 0))) + || GET_CODE (inner_const) != CONST_INT + /* If we have compiled a statement like + "if (x == (x & mask1))", and now are looking at + "x & mask2", we will have a case where the first operand + of Y is the same as our first operand. Unless we detect + this case, an infinite loop will result. */ + || XEXP (y, 0) == folded_arg0) + break; + + /* Don't associate these operations if they are a PLUS with the + same constant and it is a power of two. These might be doable + with a pre- or post-increment. Similarly for two subtracts of + identical powers of two with post decrement. */ + + if (code == PLUS && INTVAL (const_arg1) == INTVAL (inner_const) + && ((HAVE_PRE_INCREMENT + && exact_log2 (INTVAL (const_arg1)) >= 0) + || (HAVE_POST_INCREMENT + && exact_log2 (INTVAL (const_arg1)) >= 0) + || (HAVE_PRE_DECREMENT + && exact_log2 (- INTVAL (const_arg1)) >= 0) + || (HAVE_POST_DECREMENT + && exact_log2 (- INTVAL (const_arg1)) >= 0))) + break; + + /* Compute the code used to compose the constants. For example, + A/C1/C2 is A/(C1 * C2), so if CODE == DIV, we want MULT. */ + + associate_code + = (code == MULT || code == DIV || code == UDIV ? MULT + : is_shift || code == PLUS || code == MINUS ? PLUS : code); + + new_const = simplify_binary_operation (associate_code, mode, + const_arg1, inner_const); + + if (new_const == 0) + break; + + /* If we are associating shift operations, don't let this + produce a shift of the size of the object or larger. + This could occur when we follow a sign-extend by a right + shift on a machine that does a sign-extend as a pair + of shifts. */ + + if (is_shift && GET_CODE (new_const) == CONST_INT + && INTVAL (new_const) >= GET_MODE_BITSIZE (mode)) + { + /* As an exception, we can turn an ASHIFTRT of this + form into a shift of the number of bits - 1. */ + if (code == ASHIFTRT) + new_const = GEN_INT (GET_MODE_BITSIZE (mode) - 1); + else + break; + } + + y = copy_rtx (XEXP (y, 0)); + + /* If Y contains our first operand (the most common way this + can happen is if Y is a MEM), we would do into an infinite + loop if we tried to fold it. So don't in that case. */ + + if (! reg_mentioned_p (folded_arg0, y)) + y = fold_rtx (y, insn); + + return cse_gen_binary (code, mode, y, new_const); + } + break; + + default: + break; + } + + new = simplify_binary_operation (code, mode, + const_arg0 ? const_arg0 : folded_arg0, + const_arg1 ? const_arg1 : folded_arg1); + break; + + case 'o': + /* (lo_sum (high X) X) is simply X. */ + if (code == LO_SUM && const_arg0 != 0 + && GET_CODE (const_arg0) == HIGH + && rtx_equal_p (XEXP (const_arg0, 0), const_arg1)) + return const_arg1; + break; + + case '3': + case 'b': + new = simplify_ternary_operation (code, mode, mode_arg0, + const_arg0 ? const_arg0 : folded_arg0, + const_arg1 ? const_arg1 : folded_arg1, + const_arg2 ? const_arg2 : XEXP (x, 2)); + break; + } + + return new ? new : x; +} + +/* Return a constant value currently equivalent to X. + Return 0 if we don't know one. */ + +static rtx +equiv_constant (x) + rtx x; +{ + if (GET_CODE (x) == REG + && REGNO_QTY_VALID_P (REGNO (x)) + && qty_const[reg_qty[REGNO (x)]]) + x = gen_lowpart_if_possible (GET_MODE (x), qty_const[reg_qty[REGNO (x)]]); + + if (x == 0 || CONSTANT_P (x)) + return x; + + /* If X is a MEM, try to fold it outside the context of any insn to see if + it might be equivalent to a constant. That handles the case where it + is a constant-pool reference. Then try to look it up in the hash table + in case it is something whose value we have seen before. */ + + if (GET_CODE (x) == MEM) + { + struct table_elt *elt; + + x = fold_rtx (x, NULL_RTX); + if (CONSTANT_P (x)) + return x; + + elt = lookup (x, safe_hash (x, GET_MODE (x)) % NBUCKETS, GET_MODE (x)); + if (elt == 0) + return 0; + + for (elt = elt->first_same_value; elt; elt = elt->next_same_value) + if (elt->is_const && CONSTANT_P (elt->exp)) + return elt->exp; + } + + return 0; +} + +/* Assuming that X is an rtx (e.g., MEM, REG or SUBREG) for a fixed-point + number, 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. + + If the requested operation cannot be done, 0 is returned. + + This is similar to gen_lowpart in emit-rtl.c. */ + +rtx +gen_lowpart_if_possible (mode, x) + enum machine_mode mode; + register rtx x; +{ + rtx result = gen_lowpart_common (mode, x); + + if (result) + return result; + else if (GET_CODE (x) == MEM) + { + /* This is the only other case we handle. */ + register int offset = 0; + rtx new; + + 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)))); + new = gen_rtx_MEM (mode, plus_constant (XEXP (x, 0), offset)); + if (! memory_address_p (mode, XEXP (new, 0))) + return 0; + RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (x); + MEM_COPY_ATTRIBUTES (new, x); + return new; + } + else + return 0; +} + +/* Given INSN, a jump insn, TAKEN indicates if we are following the "taken" + branch. It will be zero if not. + + In certain cases, this can cause us to add an equivalence. For example, + if we are following the taken case of + if (i == 2) + we can add the fact that `i' and '2' are now equivalent. + + In any case, we can record that this comparison was passed. If the same + comparison is seen later, we will know its value. */ + +static void +record_jump_equiv (insn, taken) + rtx insn; + int taken; +{ + int cond_known_true; + rtx op0, op1; + enum machine_mode mode, mode0, mode1; + int reversed_nonequality = 0; + enum rtx_code code; + + /* Ensure this is the right kind of insn. */ + if (! condjump_p (insn) || simplejump_p (insn)) + return; + + /* See if this jump condition is known true or false. */ + if (taken) + cond_known_true = (XEXP (SET_SRC (PATTERN (insn)), 2) == pc_rtx); + else + cond_known_true = (XEXP (SET_SRC (PATTERN (insn)), 1) == pc_rtx); + + /* Get the type of comparison being done and the operands being compared. + If we had to reverse a non-equality condition, record that fact so we + know that it isn't valid for floating-point. */ + code = GET_CODE (XEXP (SET_SRC (PATTERN (insn)), 0)); + op0 = fold_rtx (XEXP (XEXP (SET_SRC (PATTERN (insn)), 0), 0), insn); + op1 = fold_rtx (XEXP (XEXP (SET_SRC (PATTERN (insn)), 0), 1), insn); + + code = find_comparison_args (code, &op0, &op1, &mode0, &mode1); + if (! cond_known_true) + { + reversed_nonequality = (code != EQ && code != NE); + code = reverse_condition (code); + } + + /* The mode is the mode of the non-constant. */ + mode = mode0; + if (mode1 != VOIDmode) + mode = mode1; + + record_jump_cond (code, mode, op0, op1, reversed_nonequality); +} + +/* We know that comparison CODE applied to OP0 and OP1 in MODE is true. + REVERSED_NONEQUALITY is nonzero if CODE had to be swapped. + Make any useful entries we can with that information. Called from + above function and called recursively. */ + +static void +record_jump_cond (code, mode, op0, op1, reversed_nonequality) + enum rtx_code code; + enum machine_mode mode; + rtx op0, op1; + int reversed_nonequality; +{ + unsigned op0_hash, op1_hash; + int op0_in_memory, op0_in_struct, op1_in_memory, op1_in_struct; + struct table_elt *op0_elt, *op1_elt; + + /* If OP0 and OP1 are known equal, and either is a paradoxical SUBREG, + we know that they are also equal in the smaller mode (this is also + true for all smaller modes whether or not there is a SUBREG, but + is not worth testing for with no SUBREG. */ + + /* Note that GET_MODE (op0) may not equal MODE. */ + if (code == EQ && GET_CODE (op0) == SUBREG + && (GET_MODE_SIZE (GET_MODE (op0)) + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))))) + { + enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0)); + rtx tem = gen_lowpart_if_possible (inner_mode, op1); + + record_jump_cond (code, mode, SUBREG_REG (op0), + tem ? tem : gen_rtx_SUBREG (inner_mode, op1, 0), + reversed_nonequality); + } + + if (code == EQ && GET_CODE (op1) == SUBREG + && (GET_MODE_SIZE (GET_MODE (op1)) + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1))))) + { + enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1)); + rtx tem = gen_lowpart_if_possible (inner_mode, op0); + + record_jump_cond (code, mode, SUBREG_REG (op1), + tem ? tem : gen_rtx_SUBREG (inner_mode, op0, 0), + reversed_nonequality); + } + + /* Similarly, if this is an NE comparison, and either is a SUBREG + making a smaller mode, we know the whole thing is also NE. */ + + /* Note that GET_MODE (op0) may not equal MODE; + if we test MODE instead, we can get an infinite recursion + alternating between two modes each wider than MODE. */ + + if (code == NE && GET_CODE (op0) == SUBREG + && subreg_lowpart_p (op0) + && (GET_MODE_SIZE (GET_MODE (op0)) + < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))))) + { + enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0)); + rtx tem = gen_lowpart_if_possible (inner_mode, op1); + + record_jump_cond (code, mode, SUBREG_REG (op0), + tem ? tem : gen_rtx_SUBREG (inner_mode, op1, 0), + reversed_nonequality); + } + + if (code == NE && GET_CODE (op1) == SUBREG + && subreg_lowpart_p (op1) + && (GET_MODE_SIZE (GET_MODE (op1)) + < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1))))) + { + enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1)); + rtx tem = gen_lowpart_if_possible (inner_mode, op0); + + record_jump_cond (code, mode, SUBREG_REG (op1), + tem ? tem : gen_rtx_SUBREG (inner_mode, op0, 0), + reversed_nonequality); + } + + /* Hash both operands. */ + + do_not_record = 0; + hash_arg_in_memory = 0; + hash_arg_in_struct = 0; + op0_hash = HASH (op0, mode); + op0_in_memory = hash_arg_in_memory; + op0_in_struct = hash_arg_in_struct; + + if (do_not_record) + return; + + do_not_record = 0; + hash_arg_in_memory = 0; + hash_arg_in_struct = 0; + op1_hash = HASH (op1, mode); + op1_in_memory = hash_arg_in_memory; + op1_in_struct = hash_arg_in_struct; + + if (do_not_record) + return; + + /* Look up both operands. */ + op0_elt = lookup (op0, op0_hash, mode); + op1_elt = lookup (op1, op1_hash, mode); + + /* If both operands are already equivalent or if they are not in the + table but are identical, do nothing. */ + if ((op0_elt != 0 && op1_elt != 0 + && op0_elt->first_same_value == op1_elt->first_same_value) + || op0 == op1 || rtx_equal_p (op0, op1)) + return; + + /* If we aren't setting two things equal all we can do is save this + comparison. Similarly if this is floating-point. In the latter + case, OP1 might be zero and both -0.0 and 0.0 are equal to it. + If we record the equality, we might inadvertently delete code + whose intent was to change -0 to +0. */ + + if (code != EQ || FLOAT_MODE_P (GET_MODE (op0))) + { + /* If we reversed a floating-point comparison, if OP0 is not a + register, or if OP1 is neither a register or constant, we can't + do anything. */ + + if (GET_CODE (op1) != REG) + op1 = equiv_constant (op1); + + if ((reversed_nonequality && FLOAT_MODE_P (mode)) + || GET_CODE (op0) != REG || op1 == 0) + return; + + /* Put OP0 in the hash table if it isn't already. This gives it a + new quantity number. */ + if (op0_elt == 0) + { + if (insert_regs (op0, NULL_PTR, 0)) + { + rehash_using_reg (op0); + op0_hash = HASH (op0, mode); + + /* If OP0 is contained in OP1, this changes its hash code + as well. Faster to rehash than to check, except + for the simple case of a constant. */ + if (! CONSTANT_P (op1)) + op1_hash = HASH (op1,mode); + } + + op0_elt = insert (op0, NULL_PTR, op0_hash, mode); + op0_elt->in_memory = op0_in_memory; + op0_elt->in_struct = op0_in_struct; + } + + qty_comparison_code[reg_qty[REGNO (op0)]] = code; + if (GET_CODE (op1) == REG) + { + /* Look it up again--in case op0 and op1 are the same. */ + op1_elt = lookup (op1, op1_hash, mode); + + /* Put OP1 in the hash table so it gets a new quantity number. */ + if (op1_elt == 0) + { + if (insert_regs (op1, NULL_PTR, 0)) + { + rehash_using_reg (op1); + op1_hash = HASH (op1, mode); + } + + op1_elt = insert (op1, NULL_PTR, op1_hash, mode); + op1_elt->in_memory = op1_in_memory; + op1_elt->in_struct = op1_in_struct; + } + + qty_comparison_qty[reg_qty[REGNO (op0)]] = reg_qty[REGNO (op1)]; + qty_comparison_const[reg_qty[REGNO (op0)]] = 0; + } + else + { + qty_comparison_qty[reg_qty[REGNO (op0)]] = -1; + qty_comparison_const[reg_qty[REGNO (op0)]] = op1; + } + + return; + } + + /* If either side is still missing an equivalence, make it now, + then merge the equivalences. */ + + if (op0_elt == 0) + { + if (insert_regs (op0, NULL_PTR, 0)) + { + rehash_using_reg (op0); + op0_hash = HASH (op0, mode); + } + + op0_elt = insert (op0, NULL_PTR, op0_hash, mode); + op0_elt->in_memory = op0_in_memory; + op0_elt->in_struct = op0_in_struct; + } + + if (op1_elt == 0) + { + if (insert_regs (op1, NULL_PTR, 0)) + { + rehash_using_reg (op1); + op1_hash = HASH (op1, mode); + } + + op1_elt = insert (op1, NULL_PTR, op1_hash, mode); + op1_elt->in_memory = op1_in_memory; + op1_elt->in_struct = op1_in_struct; + } + + merge_equiv_classes (op0_elt, op1_elt); + last_jump_equiv_class = op0_elt; +} + +/* CSE processing for one instruction. + First simplify sources and addresses of all assignments + in the instruction, using previously-computed equivalents values. + Then install the new sources and destinations in the table + of available values. + + If LIBCALL_INSN is nonzero, don't record any equivalence made in + the insn. It means that INSN is inside libcall block. In this + case LIBCALL_INSN is the corresponding insn with REG_LIBCALL. */ + +/* Data on one SET contained in the instruction. */ + +struct set +{ + /* The SET rtx itself. */ + rtx rtl; + /* The SET_SRC of the rtx (the original value, if it is changing). */ + rtx src; + /* The hash-table element for the SET_SRC of the SET. */ + struct table_elt *src_elt; + /* Hash value for the SET_SRC. */ + unsigned src_hash; + /* Hash value for the SET_DEST. */ + unsigned dest_hash; + /* The SET_DEST, with SUBREG, etc., stripped. */ + rtx inner_dest; + /* Place where the pointer to the INNER_DEST was found. */ + rtx *inner_dest_loc; + /* Nonzero if the SET_SRC is in memory. */ + char src_in_memory; + /* Nonzero if the SET_SRC is in a structure. */ + char src_in_struct; + /* Nonzero if the SET_SRC contains something + whose value cannot be predicted and understood. */ + char src_volatile; + /* Original machine mode, in case it becomes a CONST_INT. */ + enum machine_mode mode; + /* A constant equivalent for SET_SRC, if any. */ + rtx src_const; + /* Hash value of constant equivalent for SET_SRC. */ + unsigned src_const_hash; + /* Table entry for constant equivalent for SET_SRC, if any. */ + struct table_elt *src_const_elt; +}; + +static void +cse_insn (insn, libcall_insn) + rtx insn; + rtx libcall_insn; +{ + register rtx x = PATTERN (insn); + register int i; + rtx tem; + register int n_sets = 0; + +#ifdef HAVE_cc0 + /* Records what this insn does to set CC0. */ + rtx this_insn_cc0 = 0; + enum machine_mode this_insn_cc0_mode = VOIDmode; +#endif + + rtx src_eqv = 0; + struct table_elt *src_eqv_elt = 0; + int src_eqv_volatile; + int src_eqv_in_memory; + int src_eqv_in_struct; + unsigned src_eqv_hash; + + struct set *sets; + + this_insn = insn; + + /* Find all the SETs and CLOBBERs in this instruction. + Record all the SETs in the array `set' and count them. + Also determine whether there is a CLOBBER that invalidates + all memory references, or all references at varying addresses. */ + + if (GET_CODE (insn) == CALL_INSN) + { + for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1)) + if (GET_CODE (XEXP (tem, 0)) == CLOBBER) + invalidate (SET_DEST (XEXP (tem, 0)), VOIDmode); + } + + if (GET_CODE (x) == SET) + { + sets = (struct set *) alloca (sizeof (struct set)); + sets[0].rtl = x; + + /* Ignore SETs that are unconditional jumps. + They never need cse processing, so this does not hurt. + The reason is not efficiency but rather + so that we can test at the end for instructions + that have been simplified to unconditional jumps + and not be misled by unchanged instructions + that were unconditional jumps to begin with. */ + if (SET_DEST (x) == pc_rtx + && GET_CODE (SET_SRC (x)) == LABEL_REF) + ; + + /* Don't count call-insns, (set (reg 0) (call ...)), as a set. + The hard function value register is used only once, to copy to + someplace else, so it isn't worth cse'ing (and on 80386 is unsafe)! + Ensure we invalidate the destination register. On the 80386 no + other code would invalidate it since it is a fixed_reg. + We need not check the return of apply_change_group; see canon_reg. */ + + else if (GET_CODE (SET_SRC (x)) == CALL) + { + canon_reg (SET_SRC (x), insn); + apply_change_group (); + fold_rtx (SET_SRC (x), insn); + invalidate (SET_DEST (x), VOIDmode); + } + else + n_sets = 1; + } + else if (GET_CODE (x) == PARALLEL) + { + register int lim = XVECLEN (x, 0); + + sets = (struct set *) alloca (lim * sizeof (struct set)); + + /* Find all regs explicitly clobbered in this insn, + and ensure they are not replaced with any other regs + elsewhere in this insn. + When a reg that is clobbered is also used for input, + we should presume that that is for a reason, + and we should not substitute some other register + which is not supposed to be clobbered. + Therefore, this loop cannot be merged into the one below + because a CALL may precede a CLOBBER and refer to the + value clobbered. We must not let a canonicalization do + anything in that case. */ + for (i = 0; i < lim; i++) + { + register rtx y = XVECEXP (x, 0, i); + if (GET_CODE (y) == CLOBBER) + { + rtx clobbered = XEXP (y, 0); + + if (GET_CODE (clobbered) == REG + || GET_CODE (clobbered) == SUBREG) + invalidate (clobbered, VOIDmode); + else if (GET_CODE (clobbered) == STRICT_LOW_PART + || GET_CODE (clobbered) == ZERO_EXTRACT) + invalidate (XEXP (clobbered, 0), GET_MODE (clobbered)); + } + } + + for (i = 0; i < lim; i++) + { + register rtx y = XVECEXP (x, 0, i); + if (GET_CODE (y) == SET) + { + /* As above, we ignore unconditional jumps and call-insns and + ignore the result of apply_change_group. */ + if (GET_CODE (SET_SRC (y)) == CALL) + { + canon_reg (SET_SRC (y), insn); + apply_change_group (); + fold_rtx (SET_SRC (y), insn); + invalidate (SET_DEST (y), VOIDmode); + } + else if (SET_DEST (y) == pc_rtx + && GET_CODE (SET_SRC (y)) == LABEL_REF) + ; + else + sets[n_sets++].rtl = y; + } + else if (GET_CODE (y) == CLOBBER) + { + /* If we clobber memory, canon the address. + This does nothing when a register is clobbered + because we have already invalidated the reg. */ + if (GET_CODE (XEXP (y, 0)) == MEM) + canon_reg (XEXP (y, 0), NULL_RTX); + } + else if (GET_CODE (y) == USE + && ! (GET_CODE (XEXP (y, 0)) == REG + && REGNO (XEXP (y, 0)) < FIRST_PSEUDO_REGISTER)) + canon_reg (y, NULL_RTX); + else if (GET_CODE (y) == CALL) + { + /* The result of apply_change_group can be ignored; see + canon_reg. */ + canon_reg (y, insn); + apply_change_group (); + fold_rtx (y, insn); + } + } + } + else if (GET_CODE (x) == CLOBBER) + { + if (GET_CODE (XEXP (x, 0)) == MEM) + canon_reg (XEXP (x, 0), NULL_RTX); + } + + /* Canonicalize a USE of a pseudo register or memory location. */ + else if (GET_CODE (x) == USE + && ! (GET_CODE (XEXP (x, 0)) == REG + && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER)) + canon_reg (XEXP (x, 0), NULL_RTX); + else if (GET_CODE (x) == CALL) + { + /* The result of apply_change_group can be ignored; see canon_reg. */ + canon_reg (x, insn); + apply_change_group (); + fold_rtx (x, insn); + } + + /* Store the equivalent value in SRC_EQV, if different, or if the DEST + is a STRICT_LOW_PART. The latter condition is necessary because SRC_EQV + is handled specially for this case, and if it isn't set, then there will + be no equivalence for the destination. */ + if (n_sets == 1 && REG_NOTES (insn) != 0 + && (tem = find_reg_note (insn, REG_EQUAL, NULL_RTX)) != 0 + && (! rtx_equal_p (XEXP (tem, 0), SET_SRC (sets[0].rtl)) + || GET_CODE (SET_DEST (sets[0].rtl)) == STRICT_LOW_PART)) + src_eqv = canon_reg (XEXP (tem, 0), NULL_RTX); + + /* Canonicalize sources and addresses of destinations. + We do this in a separate pass to avoid problems when a MATCH_DUP is + present in the insn pattern. In that case, we want to ensure that + we don't break the duplicate nature of the pattern. So we will replace + both operands at the same time. Otherwise, we would fail to find an + equivalent substitution in the loop calling validate_change below. + + We used to suppress canonicalization of DEST if it appears in SRC, + but we don't do this any more. */ + + for (i = 0; i < n_sets; i++) + { + rtx dest = SET_DEST (sets[i].rtl); + rtx src = SET_SRC (sets[i].rtl); + rtx new = canon_reg (src, insn); + int insn_code; + + if ((GET_CODE (new) == REG && GET_CODE (src) == REG + && ((REGNO (new) < FIRST_PSEUDO_REGISTER) + != (REGNO (src) < FIRST_PSEUDO_REGISTER))) + || (insn_code = recog_memoized (insn)) < 0 + || insn_n_dups[insn_code] > 0) + validate_change (insn, &SET_SRC (sets[i].rtl), new, 1); + else + SET_SRC (sets[i].rtl) = new; + + if (GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT) + { + validate_change (insn, &XEXP (dest, 1), + canon_reg (XEXP (dest, 1), insn), 1); + validate_change (insn, &XEXP (dest, 2), + canon_reg (XEXP (dest, 2), insn), 1); + } + + while (GET_CODE (dest) == SUBREG || GET_CODE (dest) == STRICT_LOW_PART + || GET_CODE (dest) == ZERO_EXTRACT + || GET_CODE (dest) == SIGN_EXTRACT) + dest = XEXP (dest, 0); + + if (GET_CODE (dest) == MEM) + canon_reg (dest, insn); + } + + /* Now that we have done all the replacements, we can apply the change + group and see if they all work. Note that this will cause some + canonicalizations that would have worked individually not to be applied + because some other canonicalization didn't work, but this should not + occur often. + + The result of apply_change_group can be ignored; see canon_reg. */ + + apply_change_group (); + + /* Set sets[i].src_elt to the class each source belongs to. + Detect assignments from or to volatile things + and set set[i] to zero so they will be ignored + in the rest of this function. + + Nothing in this loop changes the hash table or the register chains. */ + + for (i = 0; i < n_sets; i++) + { + register rtx src, dest; + register rtx src_folded; + register struct table_elt *elt = 0, *p; + enum machine_mode mode; + rtx src_eqv_here; + rtx src_const = 0; + rtx src_related = 0; + struct table_elt *src_const_elt = 0; + int src_cost = 10000, src_eqv_cost = 10000, src_folded_cost = 10000; + int src_related_cost = 10000, src_elt_cost = 10000; + /* Set non-zero if we need to call force_const_mem on with the + contents of src_folded before using it. */ + int src_folded_force_flag = 0; + + dest = SET_DEST (sets[i].rtl); + src = SET_SRC (sets[i].rtl); + + /* If SRC is a constant that has no machine mode, + hash it with the destination's machine mode. + This way we can keep different modes separate. */ + + mode = GET_MODE (src) == VOIDmode ? GET_MODE (dest) : GET_MODE (src); + sets[i].mode = mode; + + if (src_eqv) + { + enum machine_mode eqvmode = mode; + if (GET_CODE (dest) == STRICT_LOW_PART) + eqvmode = GET_MODE (SUBREG_REG (XEXP (dest, 0))); + do_not_record = 0; + hash_arg_in_memory = 0; + hash_arg_in_struct = 0; + src_eqv = fold_rtx (src_eqv, insn); + src_eqv_hash = HASH (src_eqv, eqvmode); + + /* Find the equivalence class for the equivalent expression. */ + + if (!do_not_record) + src_eqv_elt = lookup (src_eqv, src_eqv_hash, eqvmode); + + src_eqv_volatile = do_not_record; + src_eqv_in_memory = hash_arg_in_memory; + src_eqv_in_struct = hash_arg_in_struct; + } + + /* If this is a STRICT_LOW_PART assignment, src_eqv corresponds to the + value of the INNER register, not the destination. So it is not + a valid substitution for the source. But save it for later. */ + if (GET_CODE (dest) == STRICT_LOW_PART) + src_eqv_here = 0; + else + src_eqv_here = src_eqv; + + /* Simplify and foldable subexpressions in SRC. Then get the fully- + simplified result, which may not necessarily be valid. */ + src_folded = fold_rtx (src, insn); + +#if 0 + /* ??? This caused bad code to be generated for the m68k port with -O2. + Suppose src is (CONST_INT -1), and that after truncation src_folded + is (CONST_INT 3). Suppose src_folded is then used for src_const. + At the end we will add src and src_const to the same equivalence + class. We now have 3 and -1 on the same equivalence class. This + causes later instructions to be mis-optimized. */ + /* If storing a constant in a bitfield, pre-truncate the constant + so we will be able to record it later. */ + if (GET_CODE (SET_DEST (sets[i].rtl)) == ZERO_EXTRACT + || GET_CODE (SET_DEST (sets[i].rtl)) == SIGN_EXTRACT) + { + rtx width = XEXP (SET_DEST (sets[i].rtl), 1); + + if (GET_CODE (src) == CONST_INT + && GET_CODE (width) == CONST_INT + && INTVAL (width) < HOST_BITS_PER_WIDE_INT + && (INTVAL (src) & ((HOST_WIDE_INT) (-1) << INTVAL (width)))) + src_folded + = GEN_INT (INTVAL (src) & (((HOST_WIDE_INT) 1 + << INTVAL (width)) - 1)); + } +#endif + + /* Compute SRC's hash code, and also notice if it + should not be recorded at all. In that case, + prevent any further processing of this assignment. */ + do_not_record = 0; + hash_arg_in_memory = 0; + hash_arg_in_struct = 0; + + sets[i].src = src; + sets[i].src_hash = HASH (src, mode); + sets[i].src_volatile = do_not_record; + sets[i].src_in_memory = hash_arg_in_memory; + sets[i].src_in_struct = hash_arg_in_struct; + + /* If SRC is a MEM, there is a REG_EQUIV note for SRC, and DEST is + a pseudo that is set more than once, do not record SRC. Using + SRC as a replacement for anything else will be incorrect in that + situation. Note that this usually occurs only for stack slots, + in which case all the RTL would be referring to SRC, so we don't + lose any optimization opportunities by not having SRC in the + hash table. */ + + if (GET_CODE (src) == MEM + && find_reg_note (insn, REG_EQUIV, src) != 0 + && GET_CODE (dest) == REG + && REGNO (dest) >= FIRST_PSEUDO_REGISTER + && REG_N_SETS (REGNO (dest)) != 1) + sets[i].src_volatile = 1; + +#if 0 + /* It is no longer clear why we used to do this, but it doesn't + appear to still be needed. So let's try without it since this + code hurts cse'ing widened ops. */ + /* If source is a perverse subreg (such as QI treated as an SI), + treat it as volatile. It may do the work of an SI in one context + where the extra bits are not being used, but cannot replace an SI + in general. */ + if (GET_CODE (src) == SUBREG + && (GET_MODE_SIZE (GET_MODE (src)) + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))) + sets[i].src_volatile = 1; +#endif + + /* Locate all possible equivalent forms for SRC. Try to replace + SRC in the insn with each cheaper equivalent. + + We have the following types of equivalents: SRC itself, a folded + version, a value given in a REG_EQUAL note, or a value related + to a constant. + + Each of these equivalents may be part of an additional class + of equivalents (if more than one is in the table, they must be in + the same class; we check for this). + + If the source is volatile, we don't do any table lookups. + + We note any constant equivalent for possible later use in a + REG_NOTE. */ + + if (!sets[i].src_volatile) + elt = lookup (src, sets[i].src_hash, mode); + + sets[i].src_elt = elt; + + if (elt && src_eqv_here && src_eqv_elt) + { + if (elt->first_same_value != src_eqv_elt->first_same_value) + { + /* The REG_EQUAL is indicating that two formerly distinct + classes are now equivalent. So merge them. */ + merge_equiv_classes (elt, src_eqv_elt); + src_eqv_hash = HASH (src_eqv, elt->mode); + src_eqv_elt = lookup (src_eqv, src_eqv_hash, elt->mode); + } + + src_eqv_here = 0; + } + + else if (src_eqv_elt) + elt = src_eqv_elt; + + /* Try to find a constant somewhere and record it in `src_const'. + Record its table element, if any, in `src_const_elt'. Look in + any known equivalences first. (If the constant is not in the + table, also set `sets[i].src_const_hash'). */ + if (elt) + for (p = elt->first_same_value; p; p = p->next_same_value) + if (p->is_const) + { + src_const = p->exp; + src_const_elt = elt; + break; + } + + if (src_const == 0 + && (CONSTANT_P (src_folded) + /* Consider (minus (label_ref L1) (label_ref L2)) as + "constant" here so we will record it. This allows us + to fold switch statements when an ADDR_DIFF_VEC is used. */ + || (GET_CODE (src_folded) == MINUS + && GET_CODE (XEXP (src_folded, 0)) == LABEL_REF + && GET_CODE (XEXP (src_folded, 1)) == LABEL_REF))) + src_const = src_folded, src_const_elt = elt; + else if (src_const == 0 && src_eqv_here && CONSTANT_P (src_eqv_here)) + src_const = src_eqv_here, src_const_elt = src_eqv_elt; + + /* If we don't know if the constant is in the table, get its + hash code and look it up. */ + if (src_const && src_const_elt == 0) + { + sets[i].src_const_hash = HASH (src_const, mode); + src_const_elt = lookup (src_const, sets[i].src_const_hash, mode); + } + + sets[i].src_const = src_const; + sets[i].src_const_elt = src_const_elt; + + /* If the constant and our source are both in the table, mark them as + equivalent. Otherwise, if a constant is in the table but the source + isn't, set ELT to it. */ + if (src_const_elt && elt + && src_const_elt->first_same_value != elt->first_same_value) + merge_equiv_classes (elt, src_const_elt); + else if (src_const_elt && elt == 0) + elt = src_const_elt; + + /* See if there is a register linearly related to a constant + equivalent of SRC. */ + if (src_const + && (GET_CODE (src_const) == CONST + || (src_const_elt && src_const_elt->related_value != 0))) + { + src_related = use_related_value (src_const, src_const_elt); + if (src_related) + { + struct table_elt *src_related_elt + = lookup (src_related, HASH (src_related, mode), mode); + if (src_related_elt && elt) + { + if (elt->first_same_value + != src_related_elt->first_same_value) + /* This can occur when we previously saw a CONST + involving a SYMBOL_REF and then see the SYMBOL_REF + twice. Merge the involved classes. */ + merge_equiv_classes (elt, src_related_elt); + + src_related = 0; + src_related_elt = 0; + } + else if (src_related_elt && elt == 0) + elt = src_related_elt; + } + } + + /* See if we have a CONST_INT that is already in a register in a + wider mode. */ + + if (src_const && src_related == 0 && GET_CODE (src_const) == CONST_INT + && GET_MODE_CLASS (mode) == MODE_INT + && GET_MODE_BITSIZE (mode) < BITS_PER_WORD) + { + enum machine_mode wider_mode; + + for (wider_mode = GET_MODE_WIDER_MODE (mode); + GET_MODE_BITSIZE (wider_mode) <= BITS_PER_WORD + && src_related == 0; + wider_mode = GET_MODE_WIDER_MODE (wider_mode)) + { + struct table_elt *const_elt + = lookup (src_const, HASH (src_const, wider_mode), wider_mode); + + if (const_elt == 0) + continue; + + for (const_elt = const_elt->first_same_value; + const_elt; const_elt = const_elt->next_same_value) + if (GET_CODE (const_elt->exp) == REG) + { + src_related = gen_lowpart_if_possible (mode, + const_elt->exp); + break; + } + } + } + + /* Another possibility is that we have an AND with a constant in + a mode narrower than a word. If so, it might have been generated + as part of an "if" which would narrow the AND. If we already + have done the AND in a wider mode, we can use a SUBREG of that + value. */ + + if (flag_expensive_optimizations && ! src_related + && GET_CODE (src) == AND && GET_CODE (XEXP (src, 1)) == CONST_INT + && GET_MODE_SIZE (mode) < UNITS_PER_WORD) + { + enum machine_mode tmode; + rtx new_and = gen_rtx_AND (VOIDmode, NULL_RTX, XEXP (src, 1)); + + for (tmode = GET_MODE_WIDER_MODE (mode); + GET_MODE_SIZE (tmode) <= UNITS_PER_WORD; + tmode = GET_MODE_WIDER_MODE (tmode)) + { + rtx inner = gen_lowpart_if_possible (tmode, XEXP (src, 0)); + struct table_elt *larger_elt; + + if (inner) + { + PUT_MODE (new_and, tmode); + XEXP (new_and, 0) = inner; + larger_elt = lookup (new_and, HASH (new_and, tmode), tmode); + if (larger_elt == 0) + continue; + + for (larger_elt = larger_elt->first_same_value; + larger_elt; larger_elt = larger_elt->next_same_value) + if (GET_CODE (larger_elt->exp) == REG) + { + src_related + = gen_lowpart_if_possible (mode, larger_elt->exp); + break; + } + + if (src_related) + break; + } + } + } + +#ifdef LOAD_EXTEND_OP + /* See if a MEM has already been loaded with a widening operation; + if it has, we can use a subreg of that. Many CISC machines + also have such operations, but this is only likely to be + beneficial these machines. */ + + if (flag_expensive_optimizations && src_related == 0 + && (GET_MODE_SIZE (mode) < UNITS_PER_WORD) + && GET_MODE_CLASS (mode) == MODE_INT + && GET_CODE (src) == MEM && ! do_not_record + && LOAD_EXTEND_OP (mode) != NIL) + { + enum machine_mode tmode; + + /* Set what we are trying to extend and the operation it might + have been extended with. */ + PUT_CODE (memory_extend_rtx, LOAD_EXTEND_OP (mode)); + XEXP (memory_extend_rtx, 0) = src; + + for (tmode = GET_MODE_WIDER_MODE (mode); + GET_MODE_SIZE (tmode) <= UNITS_PER_WORD; + tmode = GET_MODE_WIDER_MODE (tmode)) + { + struct table_elt *larger_elt; + + PUT_MODE (memory_extend_rtx, tmode); + larger_elt = lookup (memory_extend_rtx, + HASH (memory_extend_rtx, tmode), tmode); + if (larger_elt == 0) + continue; + + for (larger_elt = larger_elt->first_same_value; + larger_elt; larger_elt = larger_elt->next_same_value) + if (GET_CODE (larger_elt->exp) == REG) + { + src_related = gen_lowpart_if_possible (mode, + larger_elt->exp); + break; + } + + if (src_related) + break; + } + } +#endif /* LOAD_EXTEND_OP */ + + if (src == src_folded) + src_folded = 0; + + /* At this point, ELT, if non-zero, points to a class of expressions + equivalent to the source of this SET and SRC, SRC_EQV, SRC_FOLDED, + and SRC_RELATED, if non-zero, each contain additional equivalent + expressions. Prune these latter expressions by deleting expressions + already in the equivalence class. + + Check for an equivalent identical to the destination. If found, + this is the preferred equivalent since it will likely lead to + elimination of the insn. Indicate this by placing it in + `src_related'. */ + + if (elt) elt = elt->first_same_value; + for (p = elt; p; p = p->next_same_value) + { + enum rtx_code code = GET_CODE (p->exp); + + /* If the expression is not valid, ignore it. Then we do not + have to check for validity below. In most cases, we can use + `rtx_equal_p', since canonicalization has already been done. */ + if (code != REG && ! exp_equiv_p (p->exp, p->exp, 1, 0)) + continue; + + /* Also skip paradoxical subregs, unless that's what we're + looking for. */ + if (code == SUBREG + && (GET_MODE_SIZE (GET_MODE (p->exp)) + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (p->exp)))) + && ! (src != 0 + && GET_CODE (src) == SUBREG + && GET_MODE (src) == GET_MODE (p->exp) + && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))) + < GET_MODE_SIZE (GET_MODE (SUBREG_REG (p->exp)))))) + continue; + + if (src && GET_CODE (src) == code && rtx_equal_p (src, p->exp)) + src = 0; + else if (src_folded && GET_CODE (src_folded) == code + && rtx_equal_p (src_folded, p->exp)) + src_folded = 0; + else if (src_eqv_here && GET_CODE (src_eqv_here) == code + && rtx_equal_p (src_eqv_here, p->exp)) + src_eqv_here = 0; + else if (src_related && GET_CODE (src_related) == code + && rtx_equal_p (src_related, p->exp)) + src_related = 0; + + /* This is the same as the destination of the insns, we want + to prefer it. Copy it to src_related. The code below will + then give it a negative cost. */ + if (GET_CODE (dest) == code && rtx_equal_p (p->exp, dest)) + src_related = dest; + + } + + /* Find the cheapest valid equivalent, trying all the available + possibilities. Prefer items not in the hash table to ones + that are when they are equal cost. Note that we can never + worsen an insn as the current contents will also succeed. + If we find an equivalent identical to the destination, use it as best, + since this insn will probably be eliminated in that case. */ + if (src) + { + if (rtx_equal_p (src, dest)) + src_cost = -1; + else + src_cost = COST (src); + } + + if (src_eqv_here) + { + if (rtx_equal_p (src_eqv_here, dest)) + src_eqv_cost = -1; + else + src_eqv_cost = COST (src_eqv_here); + } + + if (src_folded) + { + if (rtx_equal_p (src_folded, dest)) + src_folded_cost = -1; + else + src_folded_cost = COST (src_folded); + } + + if (src_related) + { + if (rtx_equal_p (src_related, dest)) + src_related_cost = -1; + else + src_related_cost = COST (src_related); + } + + /* If this was an indirect jump insn, a known label will really be + cheaper even though it looks more expensive. */ + if (dest == pc_rtx && src_const && GET_CODE (src_const) == LABEL_REF) + src_folded = src_const, src_folded_cost = -1; + + /* Terminate loop when replacement made. This must terminate since + the current contents will be tested and will always be valid. */ + while (1) + { + rtx trial, old_src; + + /* Skip invalid entries. */ + while (elt && GET_CODE (elt->exp) != REG + && ! exp_equiv_p (elt->exp, elt->exp, 1, 0)) + elt = elt->next_same_value; + + /* A paradoxical subreg would be bad here: it'll be the right + size, but later may be adjusted so that the upper bits aren't + what we want. So reject it. */ + if (elt != 0 + && GET_CODE (elt->exp) == SUBREG + && (GET_MODE_SIZE (GET_MODE (elt->exp)) + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (elt->exp)))) + /* It is okay, though, if the rtx we're trying to match + will ignore any of the bits we can't predict. */ + && ! (src != 0 + && GET_CODE (src) == SUBREG + && GET_MODE (src) == GET_MODE (elt->exp) + && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))) + < GET_MODE_SIZE (GET_MODE (SUBREG_REG (elt->exp)))))) + { + elt = elt->next_same_value; + continue; + } + + if (elt) src_elt_cost = elt->cost; + + /* Find cheapest and skip it for the next time. For items + of equal cost, use this order: + src_folded, src, src_eqv, src_related and hash table entry. */ + if (src_folded_cost <= src_cost + && src_folded_cost <= src_eqv_cost + && src_folded_cost <= src_related_cost + && src_folded_cost <= src_elt_cost) + { + trial = src_folded, src_folded_cost = 10000; + if (src_folded_force_flag) + trial = force_const_mem (mode, trial); + } + else if (src_cost <= src_eqv_cost + && src_cost <= src_related_cost + && src_cost <= src_elt_cost) + trial = src, src_cost = 10000; + else if (src_eqv_cost <= src_related_cost + && src_eqv_cost <= src_elt_cost) + trial = copy_rtx (src_eqv_here), src_eqv_cost = 10000; + else if (src_related_cost <= src_elt_cost) + trial = copy_rtx (src_related), src_related_cost = 10000; + else + { + trial = copy_rtx (elt->exp); + elt = elt->next_same_value; + src_elt_cost = 10000; + } + + /* We don't normally have an insn matching (set (pc) (pc)), so + check for this separately here. We will delete such an + insn below. + + Tablejump insns contain a USE of the table, so simply replacing + the operand with the constant won't match. This is simply an + unconditional branch, however, and is therefore valid. Just + insert the substitution here and we will delete and re-emit + the insn later. */ + + /* Keep track of the original SET_SRC so that we can fix notes + on libcall instructions. */ + old_src = SET_SRC (sets[i].rtl); + + if (n_sets == 1 && dest == pc_rtx + && (trial == pc_rtx + || (GET_CODE (trial) == LABEL_REF + && ! condjump_p (insn)))) + { + /* If TRIAL is a label in front of a jump table, we are + really falling through the switch (this is how casesi + insns work), so we must branch around the table. */ + if (GET_CODE (trial) == CODE_LABEL + && NEXT_INSN (trial) != 0 + && GET_CODE (NEXT_INSN (trial)) == JUMP_INSN + && (GET_CODE (PATTERN (NEXT_INSN (trial))) == ADDR_DIFF_VEC + || GET_CODE (PATTERN (NEXT_INSN (trial))) == ADDR_VEC)) + + trial = gen_rtx_LABEL_REF (Pmode, get_label_after (trial)); + + SET_SRC (sets[i].rtl) = trial; + cse_jumps_altered = 1; + break; + } + + /* A libcall return register would also be bad news if we're + in a libcall, and if a REG_EQUAL note on the RETVAL insn + mentions the value we want to replace. We would need to + update the note, but since the note comes after another + assignment to the same reg, it would still be wrong. + + So far, the only case where this has been a problem has + been libcall return registers immediately used as libcall + arguments, when the return register is also used as an + argument register. Normally, a hard reg would be more + expensive than an equivalent pseudo, but when SET_DEST + matches the hard reg, it gets a cost of -1. + + Rather than discarding the notes, and losing + opportunities for futures optimizations, let's try simply + not making the substitution at this time. */ + else if (libcall_insn + /* For now, we only concern ourselves with hard regs. */ + && GET_CODE (trial) == REG + && REGNO (trial) < FIRST_PSEUDO_REGISTER + /* No-op substitutions are harmless, and we have to + accept them anyways. */ + && old_src != trial + && ! rtx_equal_p (old_src, trial) + /* Skip this check if we can easily demonstrate that + we don't care if the value of TRIAL changes. */ + && ! (GET_CODE (old_src) == REG + && ! reg_mentioned_p (old_src, + REG_NOTES (libcall_insn))) + /* If none of the instructions change it, we're + okay. */ + && modified_between_p (trial, insn, libcall_insn)) + continue; + + /* Look for a substitution that makes a valid insn. */ + else if (validate_change (insn, &SET_SRC (sets[i].rtl), trial, 0)) + { + /* If we just made a substitution inside a libcall, then we + need to make the same substitution in any notes attached + to the RETVAL insn. */ + if (libcall_insn + && (GET_CODE (old_src) == REG + || GET_CODE (old_src) == SUBREG + || GET_CODE (old_src) == MEM)) + replace_rtx (REG_NOTES (libcall_insn), old_src, + canon_reg (SET_SRC (sets[i].rtl), insn)); + + /* The result of apply_change_group can be ignored; see + canon_reg. */ + + validate_change (insn, &SET_SRC (sets[i].rtl), + canon_reg (SET_SRC (sets[i].rtl), insn), + 1); + apply_change_group (); + break; + } + + /* If we previously found constant pool entries for + constants and this is a constant, try making a + pool entry. Put it in src_folded unless we already have done + this since that is where it likely came from. */ + + else if (constant_pool_entries_cost + && CONSTANT_P (trial) + && ! (GET_CODE (trial) == CONST + && GET_CODE (XEXP (trial, 0)) == TRUNCATE) + && (src_folded == 0 + || (GET_CODE (src_folded) != MEM + && ! src_folded_force_flag)) + && GET_MODE_CLASS (mode) != MODE_CC + && mode != VOIDmode) + { + src_folded_force_flag = 1; + src_folded = trial; + src_folded_cost = constant_pool_entries_cost; + } + } + + src = SET_SRC (sets[i].rtl); + + /* In general, it is good to have a SET with SET_SRC == SET_DEST. + However, there is an important exception: If both are registers + that are not the head of their equivalence class, replace SET_SRC + with the head of the class. If we do not do this, we will have + both registers live over a portion of the basic block. This way, + their lifetimes will likely abut instead of overlapping. */ + if (GET_CODE (dest) == REG + && REGNO_QTY_VALID_P (REGNO (dest)) + && qty_mode[reg_qty[REGNO (dest)]] == GET_MODE (dest) + && qty_first_reg[reg_qty[REGNO (dest)]] != REGNO (dest) + && GET_CODE (src) == REG && REGNO (src) == REGNO (dest) + /* Don't do this if the original insn had a hard reg as + SET_SRC. */ + && (GET_CODE (sets[i].src) != REG + || REGNO (sets[i].src) >= FIRST_PSEUDO_REGISTER)) + /* We can't call canon_reg here because it won't do anything if + SRC is a hard register. */ + { + int first = qty_first_reg[reg_qty[REGNO (src)]]; + rtx new_src + = (first >= FIRST_PSEUDO_REGISTER + ? regno_reg_rtx[first] : gen_rtx_REG (GET_MODE (src), first)); + + /* We must use validate-change even for this, because this + might be a special no-op instruction, suitable only to + tag notes onto. */ + if (validate_change (insn, &SET_SRC (sets[i].rtl), new_src, 0)) + { + src = new_src; + /* If we had a constant that is cheaper than what we are now + setting SRC to, use that constant. We ignored it when we + thought we could make this into a no-op. */ + if (src_const && COST (src_const) < COST (src) + && validate_change (insn, &SET_SRC (sets[i].rtl), src_const, + 0)) + src = src_const; + } + } + + /* If we made a change, recompute SRC values. */ + if (src != sets[i].src) + { + do_not_record = 0; + hash_arg_in_memory = 0; + hash_arg_in_struct = 0; + sets[i].src = src; + sets[i].src_hash = HASH (src, mode); + sets[i].src_volatile = do_not_record; + sets[i].src_in_memory = hash_arg_in_memory; + sets[i].src_in_struct = hash_arg_in_struct; + sets[i].src_elt = lookup (src, sets[i].src_hash, mode); + } + + /* If this is a single SET, we are setting a register, and we have an + equivalent constant, we want to add a REG_NOTE. We don't want + to write a REG_EQUAL note for a constant pseudo since verifying that + that pseudo hasn't been eliminated is a pain. Such a note also + won't help anything. */ + if (n_sets == 1 && src_const && GET_CODE (dest) == REG + && GET_CODE (src_const) != REG) + { + tem = find_reg_note (insn, REG_EQUAL, NULL_RTX); + + /* Record the actual constant value in a REG_EQUAL note, making + a new one if one does not already exist. */ + if (tem) + XEXP (tem, 0) = src_const; + else + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, + src_const, REG_NOTES (insn)); + + /* If storing a constant value in a register that + previously held the constant value 0, + record this fact with a REG_WAS_0 note on this insn. + + Note that the *register* is required to have previously held 0, + not just any register in the quantity and we must point to the + insn that set that register to zero. + + Rather than track each register individually, we just see if + the last set for this quantity was for this register. */ + + if (REGNO_QTY_VALID_P (REGNO (dest)) + && qty_const[reg_qty[REGNO (dest)]] == const0_rtx) + { + /* See if we previously had a REG_WAS_0 note. */ + rtx note = find_reg_note (insn, REG_WAS_0, NULL_RTX); + rtx const_insn = qty_const_insn[reg_qty[REGNO (dest)]]; + + if ((tem = single_set (const_insn)) != 0 + && rtx_equal_p (SET_DEST (tem), dest)) + { + if (note) + XEXP (note, 0) = const_insn; + else + REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_WAS_0, + const_insn, + REG_NOTES (insn)); + } + } + } + + /* Now deal with the destination. */ + do_not_record = 0; + sets[i].inner_dest_loc = &SET_DEST (sets[0].rtl); + + /* Look within any SIGN_EXTRACT or ZERO_EXTRACT + to the MEM or REG within it. */ + while (GET_CODE (dest) == SIGN_EXTRACT + || GET_CODE (dest) == ZERO_EXTRACT + || GET_CODE (dest) == SUBREG + || GET_CODE (dest) == STRICT_LOW_PART) + { + sets[i].inner_dest_loc = &XEXP (dest, 0); + dest = XEXP (dest, 0); + } + + sets[i].inner_dest = dest; + + if (GET_CODE (dest) == MEM) + { +#ifdef PUSH_ROUNDING + /* Stack pushes invalidate the stack pointer. */ + rtx addr = XEXP (dest, 0); + if ((GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == PRE_INC + || GET_CODE (addr) == POST_DEC || GET_CODE (addr) == POST_INC) + && XEXP (addr, 0) == stack_pointer_rtx) + invalidate (stack_pointer_rtx, Pmode); +#endif + dest = fold_rtx (dest, insn); + } + + /* Compute the hash code of the destination now, + before the effects of this instruction are recorded, + since the register values used in the address computation + are those before this instruction. */ + sets[i].dest_hash = HASH (dest, mode); + + /* Don't enter a bit-field in the hash table + because the value in it after the store + may not equal what was stored, due to truncation. */ + + if (GET_CODE (SET_DEST (sets[i].rtl)) == ZERO_EXTRACT + || GET_CODE (SET_DEST (sets[i].rtl)) == SIGN_EXTRACT) + { + rtx width = XEXP (SET_DEST (sets[i].rtl), 1); + + if (src_const != 0 && GET_CODE (src_const) == CONST_INT + && GET_CODE (width) == CONST_INT + && INTVAL (width) < HOST_BITS_PER_WIDE_INT + && ! (INTVAL (src_const) + & ((HOST_WIDE_INT) (-1) << INTVAL (width)))) + /* Exception: if the value is constant, + and it won't be truncated, record it. */ + ; + else + { + /* This is chosen so that the destination will be invalidated + but no new value will be recorded. + We must invalidate because sometimes constant + values can be recorded for bitfields. */ + sets[i].src_elt = 0; + sets[i].src_volatile = 1; + src_eqv = 0; + src_eqv_elt = 0; + } + } + + /* If only one set in a JUMP_INSN and it is now a no-op, we can delete + the insn. */ + else if (n_sets == 1 && dest == pc_rtx && src == pc_rtx) + { + PUT_CODE (insn, NOTE); + NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (insn) = 0; + cse_jumps_altered = 1; + /* One less use of the label this insn used to jump to. */ + if (JUMP_LABEL (insn) != 0) + --LABEL_NUSES (JUMP_LABEL (insn)); + /* No more processing for this set. */ + sets[i].rtl = 0; + } + + /* If this SET is now setting PC to a label, we know it used to + be a conditional or computed branch. So we see if we can follow + it. If it was a computed branch, delete it and re-emit. */ + else if (dest == pc_rtx && GET_CODE (src) == LABEL_REF) + { + rtx p; + + /* If this is not in the format for a simple branch and + we are the only SET in it, re-emit it. */ + if (! simplejump_p (insn) && n_sets == 1) + { + rtx new = emit_jump_insn_before (gen_jump (XEXP (src, 0)), insn); + JUMP_LABEL (new) = XEXP (src, 0); + LABEL_NUSES (XEXP (src, 0))++; + delete_insn (insn); + insn = new; + } + else + /* Otherwise, force rerecognition, since it probably had + a different pattern before. + This shouldn't really be necessary, since whatever + changed the source value above should have done this. + Until the right place is found, might as well do this here. */ + INSN_CODE (insn) = -1; + + /* Now that we've converted this jump to an unconditional jump, + there is dead code after it. Delete the dead code until we + reach a BARRIER, the end of the function, or a label. Do + not delete NOTEs except for NOTE_INSN_DELETED since later + phases assume these notes are retained. */ + + p = insn; + + while (NEXT_INSN (p) != 0 + && GET_CODE (NEXT_INSN (p)) != BARRIER + && GET_CODE (NEXT_INSN (p)) != CODE_LABEL) + { + if (GET_CODE (NEXT_INSN (p)) != NOTE + || NOTE_LINE_NUMBER (NEXT_INSN (p)) == NOTE_INSN_DELETED) + delete_insn (NEXT_INSN (p)); + else + p = NEXT_INSN (p); + } + + /* If we don't have a BARRIER immediately after INSN, put one there. + Much code assumes that there are no NOTEs between a JUMP_INSN and + BARRIER. */ + + if (NEXT_INSN (insn) == 0 + || GET_CODE (NEXT_INSN (insn)) != BARRIER) + emit_barrier_before (NEXT_INSN (insn)); + + /* We might have two BARRIERs separated by notes. Delete the second + one if so. */ + + if (p != insn && NEXT_INSN (p) != 0 + && GET_CODE (NEXT_INSN (p)) == BARRIER) + delete_insn (NEXT_INSN (p)); + + cse_jumps_altered = 1; + sets[i].rtl = 0; + } + + /* If destination is volatile, invalidate it and then do no further + processing for this assignment. */ + + else if (do_not_record) + { + if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG + || GET_CODE (dest) == MEM) + invalidate (dest, VOIDmode); + else if (GET_CODE (dest) == STRICT_LOW_PART + || GET_CODE (dest) == ZERO_EXTRACT) + invalidate (XEXP (dest, 0), GET_MODE (dest)); + sets[i].rtl = 0; + } + + if (sets[i].rtl != 0 && dest != SET_DEST (sets[i].rtl)) + sets[i].dest_hash = HASH (SET_DEST (sets[i].rtl), mode); + +#ifdef HAVE_cc0 + /* If setting CC0, record what it was set to, or a constant, if it + is equivalent to a constant. If it is being set to a floating-point + value, make a COMPARE with the appropriate constant of 0. If we + don't do this, later code can interpret this as a test against + const0_rtx, which can cause problems if we try to put it into an + insn as a floating-point operand. */ + if (dest == cc0_rtx) + { + this_insn_cc0 = src_const && mode != VOIDmode ? src_const : src; + this_insn_cc0_mode = mode; + if (FLOAT_MODE_P (mode)) + this_insn_cc0 = gen_rtx_COMPARE (VOIDmode, this_insn_cc0, + CONST0_RTX (mode)); + } +#endif + } + + /* Now enter all non-volatile source expressions in the hash table + if they are not already present. + Record their equivalence classes in src_elt. + This way we can insert the corresponding destinations into + the same classes even if the actual sources are no longer in them + (having been invalidated). */ + + if (src_eqv && src_eqv_elt == 0 && sets[0].rtl != 0 && ! src_eqv_volatile + && ! rtx_equal_p (src_eqv, SET_DEST (sets[0].rtl))) + { + register struct table_elt *elt; + register struct table_elt *classp = sets[0].src_elt; + rtx dest = SET_DEST (sets[0].rtl); + enum machine_mode eqvmode = GET_MODE (dest); + + if (GET_CODE (dest) == STRICT_LOW_PART) + { + eqvmode = GET_MODE (SUBREG_REG (XEXP (dest, 0))); + classp = 0; + } + if (insert_regs (src_eqv, classp, 0)) + { + rehash_using_reg (src_eqv); + src_eqv_hash = HASH (src_eqv, eqvmode); + } + elt = insert (src_eqv, classp, src_eqv_hash, eqvmode); + elt->in_memory = src_eqv_in_memory; + elt->in_struct = src_eqv_in_struct; + src_eqv_elt = elt; + + /* Check to see if src_eqv_elt is the same as a set source which + does not yet have an elt, and if so set the elt of the set source + to src_eqv_elt. */ + for (i = 0; i < n_sets; i++) + if (sets[i].rtl && sets[i].src_elt == 0 + && rtx_equal_p (SET_SRC (sets[i].rtl), src_eqv)) + sets[i].src_elt = src_eqv_elt; + } + + for (i = 0; i < n_sets; i++) + if (sets[i].rtl && ! sets[i].src_volatile + && ! rtx_equal_p (SET_SRC (sets[i].rtl), SET_DEST (sets[i].rtl))) + { + if (GET_CODE (SET_DEST (sets[i].rtl)) == STRICT_LOW_PART) + { + /* REG_EQUAL in setting a STRICT_LOW_PART + gives an equivalent for the entire destination register, + not just for the subreg being stored in now. + This is a more interesting equivalence, so we arrange later + to treat the entire reg as the destination. */ + sets[i].src_elt = src_eqv_elt; + sets[i].src_hash = src_eqv_hash; + } + else + { + /* Insert source and constant equivalent into hash table, if not + already present. */ + register struct table_elt *classp = src_eqv_elt; + register rtx src = sets[i].src; + register rtx dest = SET_DEST (sets[i].rtl); + enum machine_mode mode + = GET_MODE (src) == VOIDmode ? GET_MODE (dest) : GET_MODE (src); + + if (sets[i].src_elt == 0) + { + register struct table_elt *elt; + + /* Note that these insert_regs calls cannot remove + any of the src_elt's, because they would have failed to + match if not still valid. */ + if (insert_regs (src, classp, 0)) + { + rehash_using_reg (src); + sets[i].src_hash = HASH (src, mode); + } + elt = insert (src, classp, sets[i].src_hash, mode); + elt->in_memory = sets[i].src_in_memory; + elt->in_struct = sets[i].src_in_struct; + sets[i].src_elt = classp = elt; + } + + if (sets[i].src_const && sets[i].src_const_elt == 0 + && src != sets[i].src_const + && ! rtx_equal_p (sets[i].src_const, src)) + sets[i].src_elt = insert (sets[i].src_const, classp, + sets[i].src_const_hash, mode); + } + } + else if (sets[i].src_elt == 0) + /* If we did not insert the source into the hash table (e.g., it was + volatile), note the equivalence class for the REG_EQUAL value, if any, + so that the destination goes into that class. */ + sets[i].src_elt = src_eqv_elt; + + invalidate_from_clobbers (x); + + /* Some registers are invalidated by subroutine calls. Memory is + invalidated by non-constant calls. */ + + if (GET_CODE (insn) == CALL_INSN) + { + if (! CONST_CALL_P (insn)) + invalidate_memory (); + invalidate_for_call (); + } + + /* Now invalidate everything set by this instruction. + If a SUBREG or other funny destination is being set, + sets[i].rtl is still nonzero, so here we invalidate the reg + a part of which is being set. */ + + for (i = 0; i < n_sets; i++) + if (sets[i].rtl) + { + /* We can't use the inner dest, because the mode associated with + a ZERO_EXTRACT is significant. */ + register rtx dest = SET_DEST (sets[i].rtl); + + /* Needed for registers to remove the register from its + previous quantity's chain. + Needed for memory if this is a nonvarying address, unless + we have just done an invalidate_memory that covers even those. */ + if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG + || GET_CODE (dest) == MEM) + invalidate (dest, VOIDmode); + else if (GET_CODE (dest) == STRICT_LOW_PART + || GET_CODE (dest) == ZERO_EXTRACT) + invalidate (XEXP (dest, 0), GET_MODE (dest)); + } + + /* Make sure registers mentioned in destinations + are safe for use in an expression to be inserted. + This removes from the hash table + any invalid entry that refers to one of these registers. + + We don't care about the return value from mention_regs because + we are going to hash the SET_DEST values unconditionally. */ + + for (i = 0; i < n_sets; i++) + { + if (sets[i].rtl) + { + rtx x = SET_DEST (sets[i].rtl); + + if (GET_CODE (x) != REG) + mention_regs (x); + else + { + /* We used to rely on all references to a register becoming + inaccessible when a register changes to a new quantity, + since that changes the hash code. However, that is not + safe, since after NBUCKETS new quantities we get a + hash 'collision' of a register with its own invalid + entries. And since SUBREGs have been changed not to + change their hash code with the hash code of the register, + it wouldn't work any longer at all. So we have to check + for any invalid references lying around now. + This code is similar to the REG case in mention_regs, + but it knows that reg_tick has been incremented, and + it leaves reg_in_table as -1 . */ + register int regno = REGNO (x); + register int endregno + = regno + (regno >= FIRST_PSEUDO_REGISTER ? 1 + : HARD_REGNO_NREGS (regno, GET_MODE (x))); + int i; + + for (i = regno; i < endregno; i++) + { + if (reg_in_table[i] >= 0) + { + remove_invalid_refs (i); + reg_in_table[i] = -1; + } + } + } + } + } + + /* We may have just removed some of the src_elt's from the hash table. + So replace each one with the current head of the same class. */ + + for (i = 0; i < n_sets; i++) + if (sets[i].rtl) + { + if (sets[i].src_elt && sets[i].src_elt->first_same_value == 0) + /* If elt was removed, find current head of same class, + or 0 if nothing remains of that class. */ + { + register struct table_elt *elt = sets[i].src_elt; + + while (elt && elt->prev_same_value) + elt = elt->prev_same_value; + + while (elt && elt->first_same_value == 0) + elt = elt->next_same_value; + sets[i].src_elt = elt ? elt->first_same_value : 0; + } + } + + /* Now insert the destinations into their equivalence classes. */ + + for (i = 0; i < n_sets; i++) + if (sets[i].rtl) + { + register rtx dest = SET_DEST (sets[i].rtl); + rtx inner_dest = sets[i].inner_dest; + register struct table_elt *elt; + + /* Don't record value if we are not supposed to risk allocating + floating-point values in registers that might be wider than + memory. */ + if ((flag_float_store + && GET_CODE (dest) == MEM + && FLOAT_MODE_P (GET_MODE (dest))) + /* Don't record BLKmode values, because we don't know the + size of it, and can't be sure that other BLKmode values + have the same or smaller size. */ + || GET_MODE (dest) == BLKmode + /* Don't record values of destinations set inside a libcall block + since we might delete the libcall. Things should have been set + up so we won't want to reuse such a value, but we play it safe + here. */ + || libcall_insn + /* If we didn't put a REG_EQUAL value or a source into the hash + table, there is no point is recording DEST. */ + || sets[i].src_elt == 0 + /* If DEST is a paradoxical SUBREG and SRC is a ZERO_EXTEND + or SIGN_EXTEND, don't record DEST since it can cause + some tracking to be wrong. + + ??? Think about this more later. */ + || (GET_CODE (dest) == SUBREG + && (GET_MODE_SIZE (GET_MODE (dest)) + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))) + && (GET_CODE (sets[i].src) == SIGN_EXTEND + || GET_CODE (sets[i].src) == ZERO_EXTEND))) + continue; + + /* STRICT_LOW_PART isn't part of the value BEING set, + and neither is the SUBREG inside it. + Note that in this case SETS[I].SRC_ELT is really SRC_EQV_ELT. */ + if (GET_CODE (dest) == STRICT_LOW_PART) + dest = SUBREG_REG (XEXP (dest, 0)); + + if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG) + /* Registers must also be inserted into chains for quantities. */ + if (insert_regs (dest, sets[i].src_elt, 1)) + { + /* If `insert_regs' changes something, the hash code must be + recalculated. */ + rehash_using_reg (dest); + sets[i].dest_hash = HASH (dest, GET_MODE (dest)); + } + + if (GET_CODE (inner_dest) == MEM + && GET_CODE (XEXP (inner_dest, 0)) == ADDRESSOF) + /* Given (SET (MEM (ADDRESSOF (X))) Y) we don't want to say + that (MEM (ADDRESSOF (X))) is equivalent to Y. + Consider the case in which the address of the MEM is + passed to a function, which alters the MEM. Then, if we + later use Y instead of the MEM we'll miss the update. */ + elt = insert (dest, 0, sets[i].dest_hash, GET_MODE (dest)); + else + elt = insert (dest, sets[i].src_elt, + sets[i].dest_hash, GET_MODE (dest)); + + elt->in_memory = (GET_CODE (sets[i].inner_dest) == MEM + && (! RTX_UNCHANGING_P (sets[i].inner_dest) + || FIXED_BASE_PLUS_P (XEXP (sets[i].inner_dest, + 0)))); + + if (elt->in_memory) + { + /* This implicitly assumes a whole struct + need not have MEM_IN_STRUCT_P. + But a whole struct is *supposed* to have MEM_IN_STRUCT_P. */ + elt->in_struct = (MEM_IN_STRUCT_P (sets[i].inner_dest) + || sets[i].inner_dest != SET_DEST (sets[i].rtl)); + } + + /* If we have (set (subreg:m1 (reg:m2 foo) 0) (bar:m1)), M1 is no + narrower than M2, and both M1 and M2 are the same number of words, + we are also doing (set (reg:m2 foo) (subreg:m2 (bar:m1) 0)) so + make that equivalence as well. + + However, BAR may have equivalences for which gen_lowpart_if_possible + will produce a simpler value than gen_lowpart_if_possible applied to + BAR (e.g., if BAR was ZERO_EXTENDed from M2), so we will scan all + BAR's equivalences. If we don't get a simplified form, make + the SUBREG. It will not be used in an equivalence, but will + cause two similar assignments to be detected. + + Note the loop below will find SUBREG_REG (DEST) since we have + already entered SRC and DEST of the SET in the table. */ + + if (GET_CODE (dest) == SUBREG + && (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) - 1) + / UNITS_PER_WORD) + == (GET_MODE_SIZE (GET_MODE (dest)) - 1)/ UNITS_PER_WORD) + && (GET_MODE_SIZE (GET_MODE (dest)) + >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))) + && sets[i].src_elt != 0) + { + enum machine_mode new_mode = GET_MODE (SUBREG_REG (dest)); + struct table_elt *elt, *classp = 0; + + for (elt = sets[i].src_elt->first_same_value; elt; + elt = elt->next_same_value) + { + rtx new_src = 0; + unsigned src_hash; + struct table_elt *src_elt; + + /* Ignore invalid entries. */ + if (GET_CODE (elt->exp) != REG + && ! exp_equiv_p (elt->exp, elt->exp, 1, 0)) + continue; + + new_src = gen_lowpart_if_possible (new_mode, elt->exp); + if (new_src == 0) + new_src = gen_rtx_SUBREG (new_mode, elt->exp, 0); + + src_hash = HASH (new_src, new_mode); + src_elt = lookup (new_src, src_hash, new_mode); + + /* Put the new source in the hash table is if isn't + already. */ + if (src_elt == 0) + { + if (insert_regs (new_src, classp, 0)) + { + rehash_using_reg (new_src); + src_hash = HASH (new_src, new_mode); + } + src_elt = insert (new_src, classp, src_hash, new_mode); + src_elt->in_memory = elt->in_memory; + src_elt->in_struct = elt->in_struct; + } + else if (classp && classp != src_elt->first_same_value) + /* Show that two things that we've seen before are + actually the same. */ + merge_equiv_classes (src_elt, classp); + + classp = src_elt->first_same_value; + /* Ignore invalid entries. */ + while (classp + && GET_CODE (classp->exp) != REG + && ! exp_equiv_p (classp->exp, classp->exp, 1, 0)) + classp = classp->next_same_value; + } + } + } + + /* Special handling for (set REG0 REG1) + where REG0 is the "cheapest", cheaper than REG1. + After cse, REG1 will probably not be used in the sequel, + so (if easily done) change this insn to (set REG1 REG0) and + replace REG1 with REG0 in the previous insn that computed their value. + Then REG1 will become a dead store and won't cloud the situation + for later optimizations. + + Do not make this change if REG1 is a hard register, because it will + then be used in the sequel and we may be changing a two-operand insn + into a three-operand insn. + + Also do not do this if we are operating on a copy of INSN. */ + + if (n_sets == 1 && sets[0].rtl && GET_CODE (SET_DEST (sets[0].rtl)) == REG + && NEXT_INSN (PREV_INSN (insn)) == insn + && GET_CODE (SET_SRC (sets[0].rtl)) == REG + && REGNO (SET_SRC (sets[0].rtl)) >= FIRST_PSEUDO_REGISTER + && REGNO_QTY_VALID_P (REGNO (SET_SRC (sets[0].rtl))) + && (qty_first_reg[reg_qty[REGNO (SET_SRC (sets[0].rtl))]] + == REGNO (SET_DEST (sets[0].rtl)))) + { + rtx prev = PREV_INSN (insn); + while (prev && GET_CODE (prev) == NOTE) + prev = PREV_INSN (prev); + + if (prev && GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SET + && SET_DEST (PATTERN (prev)) == SET_SRC (sets[0].rtl)) + { + rtx dest = SET_DEST (sets[0].rtl); + rtx note = find_reg_note (prev, REG_EQUIV, NULL_RTX); + + validate_change (prev, & SET_DEST (PATTERN (prev)), dest, 1); + validate_change (insn, & SET_DEST (sets[0].rtl), + SET_SRC (sets[0].rtl), 1); + validate_change (insn, & SET_SRC (sets[0].rtl), dest, 1); + apply_change_group (); + + /* If REG1 was equivalent to a constant, REG0 is not. */ + if (note) + PUT_REG_NOTE_KIND (note, REG_EQUAL); + + /* If there was a REG_WAS_0 note on PREV, remove it. Move + any REG_WAS_0 note on INSN to PREV. */ + note = find_reg_note (prev, REG_WAS_0, NULL_RTX); + if (note) + remove_note (prev, note); + + note = find_reg_note (insn, REG_WAS_0, NULL_RTX); + if (note) + { + remove_note (insn, note); + XEXP (note, 1) = REG_NOTES (prev); + REG_NOTES (prev) = note; + } + + /* If INSN has a REG_EQUAL note, and this note mentions REG0, + then we must delete it, because the value in REG0 has changed. */ + note = find_reg_note (insn, REG_EQUAL, NULL_RTX); + if (note && reg_mentioned_p (dest, XEXP (note, 0))) + remove_note (insn, note); + } + } + + /* If this is a conditional jump insn, record any known equivalences due to + the condition being tested. */ + + last_jump_equiv_class = 0; + if (GET_CODE (insn) == JUMP_INSN + && n_sets == 1 && GET_CODE (x) == SET + && GET_CODE (SET_SRC (x)) == IF_THEN_ELSE) + record_jump_equiv (insn, 0); + +#ifdef HAVE_cc0 + /* If the previous insn set CC0 and this insn no longer references CC0, + delete the previous insn. Here we use the fact that nothing expects CC0 + to be valid over an insn, which is true until the final pass. */ + if (prev_insn && GET_CODE (prev_insn) == INSN + && (tem = single_set (prev_insn)) != 0 + && SET_DEST (tem) == cc0_rtx + && ! reg_mentioned_p (cc0_rtx, x)) + { + PUT_CODE (prev_insn, NOTE); + NOTE_LINE_NUMBER (prev_insn) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (prev_insn) = 0; + } + + prev_insn_cc0 = this_insn_cc0; + prev_insn_cc0_mode = this_insn_cc0_mode; +#endif + + prev_insn = insn; +} + +/* Remove from the ahsh table all expressions that reference memory. */ +static void +invalidate_memory () +{ + register int i; + register struct table_elt *p, *next; + + for (i = 0; i < NBUCKETS; i++) + for (p = table[i]; p; p = next) + { + next = p->next_same_hash; + if (p->in_memory) + remove_from_table (p, i); + } +} + +/* XXX ??? The name of this function bears little resemblance to + what this function actually does. FIXME. */ +static int +note_mem_written (addr) + register rtx addr; +{ + /* Pushing or popping the stack invalidates just the stack pointer. */ + if ((GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == PRE_INC + || GET_CODE (addr) == POST_DEC || GET_CODE (addr) == POST_INC) + && GET_CODE (XEXP (addr, 0)) == REG + && REGNO (XEXP (addr, 0)) == STACK_POINTER_REGNUM) + { + if (reg_tick[STACK_POINTER_REGNUM] >= 0) + reg_tick[STACK_POINTER_REGNUM]++; + + /* This should be *very* rare. */ + if (TEST_HARD_REG_BIT (hard_regs_in_table, STACK_POINTER_REGNUM)) + invalidate (stack_pointer_rtx, VOIDmode); + return 1; + } + return 0; +} + +/* Perform invalidation on the basis of everything about an insn + except for invalidating the actual places that are SET in it. + This includes the places CLOBBERed, and anything that might + alias with something that is SET or CLOBBERed. + + X is the pattern of the insn. */ + +static void +invalidate_from_clobbers (x) + rtx x; +{ + if (GET_CODE (x) == CLOBBER) + { + rtx ref = XEXP (x, 0); + if (ref) + { + if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG + || GET_CODE (ref) == MEM) + invalidate (ref, VOIDmode); + else if (GET_CODE (ref) == STRICT_LOW_PART + || GET_CODE (ref) == ZERO_EXTRACT) + invalidate (XEXP (ref, 0), GET_MODE (ref)); + } + } + else if (GET_CODE (x) == PARALLEL) + { + register int i; + for (i = XVECLEN (x, 0) - 1; i >= 0; i--) + { + register rtx y = XVECEXP (x, 0, i); + if (GET_CODE (y) == CLOBBER) + { + rtx ref = XEXP (y, 0); + if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG + || GET_CODE (ref) == MEM) + invalidate (ref, VOIDmode); + else if (GET_CODE (ref) == STRICT_LOW_PART + || GET_CODE (ref) == ZERO_EXTRACT) + invalidate (XEXP (ref, 0), GET_MODE (ref)); + } + } + } +} + +/* Process X, part of the REG_NOTES of an insn. Look at any REG_EQUAL notes + and replace any registers in them with either an equivalent constant + or the canonical form of the register. If we are inside an address, + only do this if the address remains valid. + + OBJECT is 0 except when within a MEM in which case it is the MEM. + + Return the replacement for X. */ + +static rtx +cse_process_notes (x, object) + rtx x; + rtx object; +{ + enum rtx_code code = GET_CODE (x); + char *fmt = GET_RTX_FORMAT (code); + int i; + + switch (code) + { + case CONST_INT: + case CONST: + case SYMBOL_REF: + case LABEL_REF: + case CONST_DOUBLE: + case PC: + case CC0: + case LO_SUM: + return x; + + case MEM: + XEXP (x, 0) = cse_process_notes (XEXP (x, 0), x); + return x; + + case EXPR_LIST: + case INSN_LIST: + if (REG_NOTE_KIND (x) == REG_EQUAL) + XEXP (x, 0) = cse_process_notes (XEXP (x, 0), NULL_RTX); + if (XEXP (x, 1)) + XEXP (x, 1) = cse_process_notes (XEXP (x, 1), NULL_RTX); + return x; + + case SIGN_EXTEND: + case ZERO_EXTEND: + case SUBREG: + { + rtx new = cse_process_notes (XEXP (x, 0), object); + /* We don't substitute VOIDmode constants into these rtx, + since they would impede folding. */ + if (GET_MODE (new) != VOIDmode) + validate_change (object, &XEXP (x, 0), new, 0); + return x; + } + + case REG: + i = reg_qty[REGNO (x)]; + + /* Return a constant or a constant register. */ + if (REGNO_QTY_VALID_P (REGNO (x)) + && qty_const[i] != 0 + && (CONSTANT_P (qty_const[i]) + || GET_CODE (qty_const[i]) == REG)) + { + rtx new = gen_lowpart_if_possible (GET_MODE (x), qty_const[i]); + if (new) + return new; + } + + /* Otherwise, canonicalize this register. */ + return canon_reg (x, NULL_RTX); + + default: + break; + } + + for (i = 0; i < GET_RTX_LENGTH (code); i++) + if (fmt[i] == 'e') + validate_change (object, &XEXP (x, i), + cse_process_notes (XEXP (x, i), object), 0); + + return x; +} + +/* Find common subexpressions between the end test of a loop and the beginning + of the loop. LOOP_START is the CODE_LABEL at the start of a loop. + + Often we have a loop where an expression in the exit test is used + in the body of the loop. For example "while (*p) *q++ = *p++;". + Because of the way we duplicate the loop exit test in front of the loop, + however, we don't detect that common subexpression. This will be caught + when global cse is implemented, but this is a quite common case. + + This function handles the most common cases of these common expressions. + It is called after we have processed the basic block ending with the + NOTE_INSN_LOOP_END note that ends a loop and the previous JUMP_INSN + jumps to a label used only once. */ + +static void +cse_around_loop (loop_start) + rtx loop_start; +{ + rtx insn; + int i; + struct table_elt *p; + + /* If the jump at the end of the loop doesn't go to the start, we don't + do anything. */ + for (insn = PREV_INSN (loop_start); + insn && (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) >= 0); + insn = PREV_INSN (insn)) + ; + + if (insn == 0 + || GET_CODE (insn) != NOTE + || NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_BEG) + return; + + /* If the last insn of the loop (the end test) was an NE comparison, + we will interpret it as an EQ comparison, since we fell through + the loop. Any equivalences resulting from that comparison are + therefore not valid and must be invalidated. */ + if (last_jump_equiv_class) + for (p = last_jump_equiv_class->first_same_value; p; + p = p->next_same_value) + { + if (GET_CODE (p->exp) == MEM || GET_CODE (p->exp) == REG + || (GET_CODE (p->exp) == SUBREG + && GET_CODE (SUBREG_REG (p->exp)) == REG)) + invalidate (p->exp, VOIDmode); + else if (GET_CODE (p->exp) == STRICT_LOW_PART + || GET_CODE (p->exp) == ZERO_EXTRACT) + invalidate (XEXP (p->exp, 0), GET_MODE (p->exp)); + } + + /* Process insns starting after LOOP_START until we hit a CALL_INSN or + a CODE_LABEL (we could handle a CALL_INSN, but it isn't worth it). + + The only thing we do with SET_DEST is invalidate entries, so we + can safely process each SET in order. It is slightly less efficient + to do so, but we only want to handle the most common cases. + + The gen_move_insn call in cse_set_around_loop may create new pseudos. + These pseudos won't have valid entries in any of the tables indexed + by register number, such as reg_qty. We avoid out-of-range array + accesses by not processing any instructions created after cse started. */ + + for (insn = NEXT_INSN (loop_start); + GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != CODE_LABEL + && INSN_UID (insn) < max_insn_uid + && ! (GET_CODE (insn) == NOTE + && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END); + insn = NEXT_INSN (insn)) + { + if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' + && (GET_CODE (PATTERN (insn)) == SET + || GET_CODE (PATTERN (insn)) == CLOBBER)) + cse_set_around_loop (PATTERN (insn), insn, loop_start); + else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' + && GET_CODE (PATTERN (insn)) == PARALLEL) + for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--) + if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET + || GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == CLOBBER) + cse_set_around_loop (XVECEXP (PATTERN (insn), 0, i), insn, + loop_start); + } +} + +/* Process one SET of an insn that was skipped. We ignore CLOBBERs + since they are done elsewhere. This function is called via note_stores. */ + +static void +invalidate_skipped_set (dest, set) + rtx set; + rtx dest; +{ + enum rtx_code code = GET_CODE (dest); + + if (code == MEM + && ! note_mem_written (dest) /* If this is not a stack push ... */ + /* There are times when an address can appear varying and be a PLUS + during this scan when it would be a fixed address were we to know + the proper equivalences. So invalidate all memory if there is + a BLKmode or nonscalar memory reference or a reference to a + variable address. */ + && (MEM_IN_STRUCT_P (dest) || GET_MODE (dest) == BLKmode + || cse_rtx_varies_p (XEXP (dest, 0)))) + { + invalidate_memory (); + return; + } + + if (GET_CODE (set) == CLOBBER +#ifdef HAVE_cc0 + || dest == cc0_rtx +#endif + || dest == pc_rtx) + return; + + if (code == STRICT_LOW_PART || code == ZERO_EXTRACT) + invalidate (XEXP (dest, 0), GET_MODE (dest)); + else if (code == REG || code == SUBREG || code == MEM) + invalidate (dest, VOIDmode); +} + +/* Invalidate all insns from START up to the end of the function or the + next label. This called when we wish to CSE around a block that is + conditionally executed. */ + +static void +invalidate_skipped_block (start) + rtx start; +{ + rtx insn; + + for (insn = start; insn && GET_CODE (insn) != CODE_LABEL; + insn = NEXT_INSN (insn)) + { + if (GET_RTX_CLASS (GET_CODE (insn)) != 'i') + continue; + + if (GET_CODE (insn) == CALL_INSN) + { + if (! CONST_CALL_P (insn)) + invalidate_memory (); + invalidate_for_call (); + } + + invalidate_from_clobbers (PATTERN (insn)); + note_stores (PATTERN (insn), invalidate_skipped_set); + } +} + +/* Used for communication between the following two routines; contains a + value to be checked for modification. */ + +static rtx cse_check_loop_start_value; + +/* If modifying X will modify the value in CSE_CHECK_LOOP_START_VALUE, + indicate that fact by setting CSE_CHECK_LOOP_START_VALUE to 0. */ + +static void +cse_check_loop_start (x, set) + rtx x; + rtx set ATTRIBUTE_UNUSED; +{ + if (cse_check_loop_start_value == 0 + || GET_CODE (x) == CC0 || GET_CODE (x) == PC) + return; + + if ((GET_CODE (x) == MEM && GET_CODE (cse_check_loop_start_value) == MEM) + || reg_overlap_mentioned_p (x, cse_check_loop_start_value)) + cse_check_loop_start_value = 0; +} + +/* X is a SET or CLOBBER contained in INSN that was found near the start of + a loop that starts with the label at LOOP_START. + + If X is a SET, we see if its SET_SRC is currently in our hash table. + If so, we see if it has a value equal to some register used only in the + loop exit code (as marked by jump.c). + + If those two conditions are true, we search backwards from the start of + the loop to see if that same value was loaded into a register that still + retains its value at the start of the loop. + + If so, we insert an insn after the load to copy the destination of that + load into the equivalent register and (try to) replace our SET_SRC with that + register. + + In any event, we invalidate whatever this SET or CLOBBER modifies. */ + +static void +cse_set_around_loop (x, insn, loop_start) + rtx x; + rtx insn; + rtx loop_start; +{ + struct table_elt *src_elt; + + /* If this is a SET, see if we can replace SET_SRC, but ignore SETs that + are setting PC or CC0 or whose SET_SRC is already a register. */ + if (GET_CODE (x) == SET + && GET_CODE (SET_DEST (x)) != PC && GET_CODE (SET_DEST (x)) != CC0 + && GET_CODE (SET_SRC (x)) != REG) + { + src_elt = lookup (SET_SRC (x), + HASH (SET_SRC (x), GET_MODE (SET_DEST (x))), + GET_MODE (SET_DEST (x))); + + if (src_elt) + for (src_elt = src_elt->first_same_value; src_elt; + src_elt = src_elt->next_same_value) + if (GET_CODE (src_elt->exp) == REG && REG_LOOP_TEST_P (src_elt->exp) + && COST (src_elt->exp) < COST (SET_SRC (x))) + { + rtx p, set; + + /* Look for an insn in front of LOOP_START that sets + something in the desired mode to SET_SRC (x) before we hit + a label or CALL_INSN. */ + + for (p = prev_nonnote_insn (loop_start); + p && GET_CODE (p) != CALL_INSN + && GET_CODE (p) != CODE_LABEL; + p = prev_nonnote_insn (p)) + if ((set = single_set (p)) != 0 + && GET_CODE (SET_DEST (set)) == REG + && GET_MODE (SET_DEST (set)) == src_elt->mode + && rtx_equal_p (SET_SRC (set), SET_SRC (x))) + { + /* We now have to ensure that nothing between P + and LOOP_START modified anything referenced in + SET_SRC (x). We know that nothing within the loop + can modify it, or we would have invalidated it in + the hash table. */ + rtx q; + + cse_check_loop_start_value = SET_SRC (x); + for (q = p; q != loop_start; q = NEXT_INSN (q)) + if (GET_RTX_CLASS (GET_CODE (q)) == 'i') + note_stores (PATTERN (q), cse_check_loop_start); + + /* If nothing was changed and we can replace our + SET_SRC, add an insn after P to copy its destination + to what we will be replacing SET_SRC with. */ + if (cse_check_loop_start_value + && validate_change (insn, &SET_SRC (x), + src_elt->exp, 0)) + { + /* If this creates new pseudos, this is unsafe, + because the regno of new pseudo is unsuitable + to index into reg_qty when cse_insn processes + the new insn. Therefore, if a new pseudo was + created, discard this optimization. */ + int nregs = max_reg_num (); + rtx move + = gen_move_insn (src_elt->exp, SET_DEST (set)); + if (nregs != max_reg_num ()) + { + if (! validate_change (insn, &SET_SRC (x), + SET_SRC (set), 0)) + abort (); + } + else + emit_insn_after (move, p); + } + break; + } + } + } + + /* Now invalidate anything modified by X. */ + note_mem_written (SET_DEST (x)); + + /* See comment on similar code in cse_insn for explanation of these tests. */ + if (GET_CODE (SET_DEST (x)) == REG || GET_CODE (SET_DEST (x)) == SUBREG + || GET_CODE (SET_DEST (x)) == MEM) + invalidate (SET_DEST (x), VOIDmode); + else if (GET_CODE (SET_DEST (x)) == STRICT_LOW_PART + || GET_CODE (SET_DEST (x)) == ZERO_EXTRACT) + invalidate (XEXP (SET_DEST (x), 0), GET_MODE (SET_DEST (x))); +} + +/* Find the end of INSN's basic block and return its range, + the total number of SETs in all the insns of the block, the last insn of the + block, and the branch path. + + The branch path indicates which branches should be followed. If a non-zero + path size is specified, the block should be rescanned and a different set + of branches will be taken. The branch path is only used if + FLAG_CSE_FOLLOW_JUMPS or FLAG_CSE_SKIP_BLOCKS is non-zero. + + DATA is a pointer to a struct cse_basic_block_data, defined below, that is + used to describe the block. It is filled in with the information about + the current block. The incoming structure's branch path, if any, is used + to construct the output branch path. */ + +void +cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks) + rtx insn; + struct cse_basic_block_data *data; + int follow_jumps; + int after_loop; + int skip_blocks; +{ + rtx p = insn, q; + int nsets = 0; + int low_cuid = INSN_CUID (insn), high_cuid = INSN_CUID (insn); + rtx next = GET_RTX_CLASS (GET_CODE (insn)) == 'i' ? insn : next_real_insn (insn); + int path_size = data->path_size; + int path_entry = 0; + int i; + + /* Update the previous branch path, if any. If the last branch was + previously TAKEN, mark it NOT_TAKEN. If it was previously NOT_TAKEN, + shorten the path by one and look at the previous branch. We know that + at least one branch must have been taken if PATH_SIZE is non-zero. */ + while (path_size > 0) + { + if (data->path[path_size - 1].status != NOT_TAKEN) + { + data->path[path_size - 1].status = NOT_TAKEN; + break; + } + else + path_size--; + } + + /* Scan to end of this basic block. */ + while (p && GET_CODE (p) != CODE_LABEL) + { + /* Don't cse out the end of a loop. This makes a difference + only for the unusual loops that always execute at least once; + all other loops have labels there so we will stop in any case. + Cse'ing out the end of the loop is dangerous because it + might cause an invariant expression inside the loop + to be reused after the end of the loop. This would make it + hard to move the expression out of the loop in loop.c, + especially if it is one of several equivalent expressions + and loop.c would like to eliminate it. + + If we are running after loop.c has finished, we can ignore + the NOTE_INSN_LOOP_END. */ + + if (! after_loop && GET_CODE (p) == NOTE + && NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_END) + break; + + /* Don't cse over a call to setjmp; on some machines (eg vax) + the regs restored by the longjmp come from + a later time than the setjmp. */ + if (GET_CODE (p) == NOTE + && NOTE_LINE_NUMBER (p) == NOTE_INSN_SETJMP) + break; + + /* A PARALLEL can have lots of SETs in it, + especially if it is really an ASM_OPERANDS. */ + if (GET_RTX_CLASS (GET_CODE (p)) == 'i' + && GET_CODE (PATTERN (p)) == PARALLEL) + nsets += XVECLEN (PATTERN (p), 0); + else if (GET_CODE (p) != NOTE) + nsets += 1; + + /* Ignore insns made by CSE; they cannot affect the boundaries of + the basic block. */ + + if (INSN_UID (p) <= max_uid && INSN_CUID (p) > high_cuid) + high_cuid = INSN_CUID (p); + if (INSN_UID (p) <= max_uid && INSN_CUID (p) < low_cuid) + low_cuid = INSN_CUID (p); + + /* See if this insn is in our branch path. If it is and we are to + take it, do so. */ + if (path_entry < path_size && data->path[path_entry].branch == p) + { + if (data->path[path_entry].status != NOT_TAKEN) + p = JUMP_LABEL (p); + + /* Point to next entry in path, if any. */ + path_entry++; + } + + /* If this is a conditional jump, we can follow it if -fcse-follow-jumps + was specified, we haven't reached our maximum path length, there are + insns following the target of the jump, this is the only use of the + jump label, and the target label is preceded by a BARRIER. + + Alternatively, we can follow the jump if it branches around a + block of code and there are no other branches into the block. + In this case invalidate_skipped_block will be called to invalidate any + registers set in the block when following the jump. */ + + else if ((follow_jumps || skip_blocks) && path_size < PATHLENGTH - 1 + && GET_CODE (p) == JUMP_INSN + && GET_CODE (PATTERN (p)) == SET + && GET_CODE (SET_SRC (PATTERN (p))) == IF_THEN_ELSE + && JUMP_LABEL (p) != 0 + && LABEL_NUSES (JUMP_LABEL (p)) == 1 + && NEXT_INSN (JUMP_LABEL (p)) != 0) + { + for (q = PREV_INSN (JUMP_LABEL (p)); q; q = PREV_INSN (q)) + if ((GET_CODE (q) != NOTE + || NOTE_LINE_NUMBER (q) == NOTE_INSN_LOOP_END + || NOTE_LINE_NUMBER (q) == NOTE_INSN_SETJMP) + && (GET_CODE (q) != CODE_LABEL || LABEL_NUSES (q) != 0)) + break; + + /* If we ran into a BARRIER, this code is an extension of the + basic block when the branch is taken. */ + if (follow_jumps && q != 0 && GET_CODE (q) == BARRIER) + { + /* Don't allow ourself to keep walking around an + always-executed loop. */ + if (next_real_insn (q) == next) + { + p = NEXT_INSN (p); + continue; + } + + /* Similarly, don't put a branch in our path more than once. */ + for (i = 0; i < path_entry; i++) + if (data->path[i].branch == p) + break; + + if (i != path_entry) + break; + + data->path[path_entry].branch = p; + data->path[path_entry++].status = TAKEN; + + /* This branch now ends our path. It was possible that we + didn't see this branch the last time around (when the + insn in front of the target was a JUMP_INSN that was + turned into a no-op). */ + path_size = path_entry; + + p = JUMP_LABEL (p); + /* Mark block so we won't scan it again later. */ + PUT_MODE (NEXT_INSN (p), QImode); + } + /* Detect a branch around a block of code. */ + else if (skip_blocks && q != 0 && GET_CODE (q) != CODE_LABEL) + { + register rtx tmp; + + if (next_real_insn (q) == next) + { + p = NEXT_INSN (p); + continue; + } + + for (i = 0; i < path_entry; i++) + if (data->path[i].branch == p) + break; + + if (i != path_entry) + break; + + /* This is no_labels_between_p (p, q) with an added check for + reaching the end of a function (in case Q precedes P). */ + for (tmp = NEXT_INSN (p); tmp && tmp != q; tmp = NEXT_INSN (tmp)) + if (GET_CODE (tmp) == CODE_LABEL) + break; + + if (tmp == q) + { + data->path[path_entry].branch = p; + data->path[path_entry++].status = AROUND; + + path_size = path_entry; + + p = JUMP_LABEL (p); + /* Mark block so we won't scan it again later. */ + PUT_MODE (NEXT_INSN (p), QImode); + } + } + } + p = NEXT_INSN (p); + } + + data->low_cuid = low_cuid; + data->high_cuid = high_cuid; + data->nsets = nsets; + data->last = p; + + /* If all jumps in the path are not taken, set our path length to zero + so a rescan won't be done. */ + for (i = path_size - 1; i >= 0; i--) + if (data->path[i].status != NOT_TAKEN) + break; + + if (i == -1) + data->path_size = 0; + else + data->path_size = path_size; + + /* End the current branch path. */ + data->path[path_size].branch = 0; +} + +/* Perform cse on the instructions of a function. + F is the first instruction. + NREGS is one plus the highest pseudo-reg number used in the instruction. + + AFTER_LOOP is 1 if this is the cse call done after loop optimization + (only if -frerun-cse-after-loop). + + Returns 1 if jump_optimize should be redone due to simplifications + in conditional jump instructions. */ + +int +cse_main (f, nregs, after_loop, file) + rtx f; + int nregs; + int after_loop; + FILE *file; +{ + struct cse_basic_block_data val; + register rtx insn = f; + register int i; + + cse_jumps_altered = 0; + recorded_label_ref = 0; + constant_pool_entries_cost = 0; + val.path_size = 0; + + init_recog (); + init_alias_analysis (); + + max_reg = nregs; + + max_insn_uid = get_max_uid (); + + all_minus_one = (int *) alloca (nregs * sizeof (int)); + consec_ints = (int *) alloca (nregs * sizeof (int)); + + for (i = 0; i < nregs; i++) + { + all_minus_one[i] = -1; + consec_ints[i] = i; + } + + reg_next_eqv = (int *) alloca (nregs * sizeof (int)); + reg_prev_eqv = (int *) alloca (nregs * sizeof (int)); + reg_qty = (int *) alloca (nregs * sizeof (int)); + reg_in_table = (int *) alloca (nregs * sizeof (int)); + reg_tick = (int *) alloca (nregs * sizeof (int)); + +#ifdef LOAD_EXTEND_OP + + /* Allocate scratch rtl here. cse_insn will fill in the memory reference + and change the code and mode as appropriate. */ + memory_extend_rtx = gen_rtx_ZERO_EXTEND (VOIDmode, NULL_RTX); +#endif + + /* Discard all the free elements of the previous function + since they are allocated in the temporarily obstack. */ + bzero ((char *) table, sizeof table); + free_element_chain = 0; + n_elements_made = 0; + + /* Find the largest uid. */ + + max_uid = get_max_uid (); + uid_cuid = (int *) alloca ((max_uid + 1) * sizeof (int)); + bzero ((char *) uid_cuid, (max_uid + 1) * sizeof (int)); + + /* Compute the mapping from uids to cuids. + CUIDs are numbers assigned to insns, like uids, + except that cuids increase monotonically through the code. + Don't assign cuids to line-number NOTEs, so that the distance in cuids + between two insns is not affected by -g. */ + + for (insn = f, i = 0; insn; insn = NEXT_INSN (insn)) + { + if (GET_CODE (insn) != NOTE + || NOTE_LINE_NUMBER (insn) < 0) + INSN_CUID (insn) = ++i; + else + /* Give a line number note the same cuid as preceding insn. */ + INSN_CUID (insn) = i; + } + + /* Initialize which registers are clobbered by calls. */ + + CLEAR_HARD_REG_SET (regs_invalidated_by_call); + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if ((call_used_regs[i] + /* Used to check !fixed_regs[i] here, but that isn't safe; + fixed regs are still call-clobbered, and sched can get + confused if they can "live across calls". + + The frame pointer is always preserved across calls. The arg + pointer is if it is fixed. The stack pointer usually is, unless + RETURN_POPS_ARGS, in which case an explicit CLOBBER + will be present. If we are generating PIC code, the PIC offset + table register is preserved across calls. */ + + && i != STACK_POINTER_REGNUM + && i != FRAME_POINTER_REGNUM +#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM + && i != HARD_FRAME_POINTER_REGNUM +#endif +#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM + && ! (i == ARG_POINTER_REGNUM && fixed_regs[i]) +#endif +#if defined (PIC_OFFSET_TABLE_REGNUM) && !defined (PIC_OFFSET_TABLE_REG_CALL_CLOBBERED) + && ! (i == PIC_OFFSET_TABLE_REGNUM && flag_pic) +#endif + ) + || global_regs[i]) + SET_HARD_REG_BIT (regs_invalidated_by_call, i); + + /* Loop over basic blocks. + Compute the maximum number of qty's needed for each basic block + (which is 2 for each SET). */ + insn = f; + while (insn) + { + cse_end_of_basic_block (insn, &val, flag_cse_follow_jumps, after_loop, + flag_cse_skip_blocks); + + /* If this basic block was already processed or has no sets, skip it. */ + if (val.nsets == 0 || GET_MODE (insn) == QImode) + { + PUT_MODE (insn, VOIDmode); + insn = (val.last ? NEXT_INSN (val.last) : 0); + val.path_size = 0; + continue; + } + + cse_basic_block_start = val.low_cuid; + cse_basic_block_end = val.high_cuid; + max_qty = val.nsets * 2; + + if (file) + fprintf (file, ";; Processing block from %d to %d, %d sets.\n", + INSN_UID (insn), val.last ? INSN_UID (val.last) : 0, + val.nsets); + + /* Make MAX_QTY bigger to give us room to optimize + past the end of this basic block, if that should prove useful. */ + if (max_qty < 500) + max_qty = 500; + + max_qty += max_reg; + + /* If this basic block is being extended by following certain jumps, + (see `cse_end_of_basic_block'), we reprocess the code from the start. + Otherwise, we start after this basic block. */ + if (val.path_size > 0) + cse_basic_block (insn, val.last, val.path, 0); + else + { + int old_cse_jumps_altered = cse_jumps_altered; + rtx temp; + + /* When cse changes a conditional jump to an unconditional + jump, we want to reprocess the block, since it will give + us a new branch path to investigate. */ + cse_jumps_altered = 0; + temp = cse_basic_block (insn, val.last, val.path, ! after_loop); + if (cse_jumps_altered == 0 + || (flag_cse_follow_jumps == 0 && flag_cse_skip_blocks == 0)) + insn = temp; + + cse_jumps_altered |= old_cse_jumps_altered; + } + +#ifdef USE_C_ALLOCA + alloca (0); +#endif + } + + /* Tell refers_to_mem_p that qty_const info is not available. */ + qty_const = 0; + + if (max_elements_made < n_elements_made) + max_elements_made = n_elements_made; + + return cse_jumps_altered || recorded_label_ref; +} + +/* Process a single basic block. FROM and TO and the limits of the basic + block. NEXT_BRANCH points to the branch path when following jumps or + a null path when not following jumps. + + AROUND_LOOP is non-zero if we are to try to cse around to the start of a + loop. This is true when we are being called for the last time on a + block and this CSE pass is before loop.c. */ + +static rtx +cse_basic_block (from, to, next_branch, around_loop) + register rtx from, to; + struct branch_path *next_branch; + int around_loop; +{ + register rtx insn; + int to_usage = 0; + rtx libcall_insn = NULL_RTX; + int num_insns = 0; + + /* Each of these arrays is undefined before max_reg, so only allocate + the space actually needed and adjust the start below. */ + + qty_first_reg = (int *) alloca ((max_qty - max_reg) * sizeof (int)); + qty_last_reg = (int *) alloca ((max_qty - max_reg) * sizeof (int)); + qty_mode= (enum machine_mode *) alloca ((max_qty - max_reg) * sizeof (enum machine_mode)); + qty_const = (rtx *) alloca ((max_qty - max_reg) * sizeof (rtx)); + qty_const_insn = (rtx *) alloca ((max_qty - max_reg) * sizeof (rtx)); + qty_comparison_code + = (enum rtx_code *) alloca ((max_qty - max_reg) * sizeof (enum rtx_code)); + qty_comparison_qty = (int *) alloca ((max_qty - max_reg) * sizeof (int)); + qty_comparison_const = (rtx *) alloca ((max_qty - max_reg) * sizeof (rtx)); + + qty_first_reg -= max_reg; + qty_last_reg -= max_reg; + qty_mode -= max_reg; + qty_const -= max_reg; + qty_const_insn -= max_reg; + qty_comparison_code -= max_reg; + qty_comparison_qty -= max_reg; + qty_comparison_const -= max_reg; + + new_basic_block (); + + /* TO might be a label. If so, protect it from being deleted. */ + if (to != 0 && GET_CODE (to) == CODE_LABEL) + ++LABEL_NUSES (to); + + for (insn = from; insn != to; insn = NEXT_INSN (insn)) + { + register enum rtx_code code = GET_CODE (insn); + int i; + struct table_elt *p; + + /* If we have processed 1,000 insns, flush the hash table to + avoid extreme quadratic behavior. We must not include NOTEs + in the count since there may be more or them when generating + debugging information. If we clear the table at different + times, code generated with -g -O might be different than code + generated with -O but not -g. + + ??? This is a real kludge and needs to be done some other way. + Perhaps for 2.9. */ + if (code != NOTE && num_insns++ > 1000) + { + for (i = 0; i < NBUCKETS; i++) + for (p = table[i]; p; p = table[i]) + { + /* Note that invalidate can remove elements + after P in the current hash chain. */ + if (GET_CODE (p->exp) == REG) + invalidate (p->exp, p->mode); + else + remove_from_table (p, i); + } + + num_insns = 0; + } + + /* See if this is a branch that is part of the path. If so, and it is + to be taken, do so. */ + if (next_branch->branch == insn) + { + enum taken status = next_branch++->status; + if (status != NOT_TAKEN) + { + if (status == TAKEN) + record_jump_equiv (insn, 1); + else + invalidate_skipped_block (NEXT_INSN (insn)); + + /* Set the last insn as the jump insn; it doesn't affect cc0. + Then follow this branch. */ +#ifdef HAVE_cc0 + prev_insn_cc0 = 0; +#endif + prev_insn = insn; + insn = JUMP_LABEL (insn); + continue; + } + } + + if (GET_MODE (insn) == QImode) + PUT_MODE (insn, VOIDmode); + + if (GET_RTX_CLASS (code) == 'i') + { + rtx p; + + /* Process notes first so we have all notes in canonical forms when + looking for duplicate operations. */ + + if (REG_NOTES (insn)) + REG_NOTES (insn) = cse_process_notes (REG_NOTES (insn), NULL_RTX); + + /* Track when we are inside in LIBCALL block. Inside such a block, + we do not want to record destinations. The last insn of a + LIBCALL block is not considered to be part of the block, since + its destination is the result of the block and hence should be + recorded. */ + + if ((p = find_reg_note (insn, REG_LIBCALL, NULL_RTX))) + libcall_insn = XEXP (p, 0); + else if (find_reg_note (insn, REG_RETVAL, NULL_RTX)) + libcall_insn = NULL_RTX; + + cse_insn (insn, libcall_insn); + } + + /* If INSN is now an unconditional jump, skip to the end of our + basic block by pretending that we just did the last insn in the + basic block. If we are jumping to the end of our block, show + that we can have one usage of TO. */ + + if (simplejump_p (insn)) + { + if (to == 0) + return 0; + + if (JUMP_LABEL (insn) == to) + to_usage = 1; + + /* Maybe TO was deleted because the jump is unconditional. + If so, there is nothing left in this basic block. */ + /* ??? Perhaps it would be smarter to set TO + to whatever follows this insn, + and pretend the basic block had always ended here. */ + if (INSN_DELETED_P (to)) + break; + + insn = PREV_INSN (to); + } + + /* See if it is ok to keep on going past the label + which used to end our basic block. Remember that we incremented + the count of that label, so we decrement it here. If we made + a jump unconditional, TO_USAGE will be one; in that case, we don't + want to count the use in that jump. */ + + if (to != 0 && NEXT_INSN (insn) == to + && GET_CODE (to) == CODE_LABEL && --LABEL_NUSES (to) == to_usage) + { + struct cse_basic_block_data val; + rtx prev; + + insn = NEXT_INSN (to); + + if (LABEL_NUSES (to) == 0) + insn = delete_insn (to); + + /* If TO was the last insn in the function, we are done. */ + if (insn == 0) + return 0; + + /* If TO was preceded by a BARRIER we are done with this block + because it has no continuation. */ + prev = prev_nonnote_insn (to); + if (prev && GET_CODE (prev) == BARRIER) + return insn; + + /* Find the end of the following block. Note that we won't be + following branches in this case. */ + to_usage = 0; + val.path_size = 0; + cse_end_of_basic_block (insn, &val, 0, 0, 0); + + /* If the tables we allocated have enough space left + to handle all the SETs in the next basic block, + continue through it. Otherwise, return, + and that block will be scanned individually. */ + if (val.nsets * 2 + next_qty > max_qty) + break; + + cse_basic_block_start = val.low_cuid; + cse_basic_block_end = val.high_cuid; + to = val.last; + + /* Prevent TO from being deleted if it is a label. */ + if (to != 0 && GET_CODE (to) == CODE_LABEL) + ++LABEL_NUSES (to); + + /* Back up so we process the first insn in the extension. */ + insn = PREV_INSN (insn); + } + } + + if (next_qty > max_qty) + abort (); + + /* If we are running before loop.c, we stopped on a NOTE_INSN_LOOP_END, and + the previous insn is the only insn that branches to the head of a loop, + we can cse into the loop. Don't do this if we changed the jump + structure of a loop unless we aren't going to be following jumps. */ + + if ((cse_jumps_altered == 0 + || (flag_cse_follow_jumps == 0 && flag_cse_skip_blocks == 0)) + && around_loop && to != 0 + && GET_CODE (to) == NOTE && NOTE_LINE_NUMBER (to) == NOTE_INSN_LOOP_END + && GET_CODE (PREV_INSN (to)) == JUMP_INSN + && JUMP_LABEL (PREV_INSN (to)) != 0 + && LABEL_NUSES (JUMP_LABEL (PREV_INSN (to))) == 1) + cse_around_loop (JUMP_LABEL (PREV_INSN (to))); + + return to ? NEXT_INSN (to) : 0; +} + +/* Count the number of times registers are used (not set) in X. + COUNTS is an array in which we accumulate the count, INCR is how much + we count each register usage. + + Don't count a usage of DEST, which is the SET_DEST of a SET which + contains X in its SET_SRC. This is because such a SET does not + modify the liveness of DEST. */ + +static void +count_reg_usage (x, counts, dest, incr) + rtx x; + int *counts; + rtx dest; + int incr; +{ + enum rtx_code code; + char *fmt; + int i, j; + + if (x == 0) + return; + + switch (code = GET_CODE (x)) + { + case REG: + if (x != dest) + counts[REGNO (x)] += incr; + return; + + case PC: + case CC0: + case CONST: + case CONST_INT: + case CONST_DOUBLE: + case SYMBOL_REF: + case LABEL_REF: + return; + + case CLOBBER: + /* If we are clobbering a MEM, mark any registers inside the address + as being used. */ + if (GET_CODE (XEXP (x, 0)) == MEM) + count_reg_usage (XEXP (XEXP (x, 0), 0), counts, NULL_RTX, incr); + return; + + case SET: + /* Unless we are setting a REG, count everything in SET_DEST. */ + if (GET_CODE (SET_DEST (x)) != REG) + count_reg_usage (SET_DEST (x), counts, NULL_RTX, incr); + + /* If SRC has side-effects, then we can't delete this insn, so the + usage of SET_DEST inside SRC counts. + + ??? Strictly-speaking, we might be preserving this insn + because some other SET has side-effects, but that's hard + to do and can't happen now. */ + count_reg_usage (SET_SRC (x), counts, + side_effects_p (SET_SRC (x)) ? NULL_RTX : SET_DEST (x), + incr); + return; + + case CALL_INSN: + count_reg_usage (CALL_INSN_FUNCTION_USAGE (x), counts, NULL_RTX, incr); + + /* ... falls through ... */ + case INSN: + case JUMP_INSN: + count_reg_usage (PATTERN (x), counts, NULL_RTX, incr); + + /* Things used in a REG_EQUAL note aren't dead since loop may try to + use them. */ + + count_reg_usage (REG_NOTES (x), counts, NULL_RTX, incr); + return; + + case EXPR_LIST: + case INSN_LIST: + if (REG_NOTE_KIND (x) == REG_EQUAL + || (REG_NOTE_KIND (x) != REG_NONNEG && GET_CODE (XEXP (x,0)) == USE)) + count_reg_usage (XEXP (x, 0), counts, NULL_RTX, incr); + count_reg_usage (XEXP (x, 1), counts, NULL_RTX, incr); + return; + + default: + break; + } + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + count_reg_usage (XEXP (x, i), counts, dest, incr); + else if (fmt[i] == 'E') + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + count_reg_usage (XVECEXP (x, i, j), counts, dest, incr); + } +} + +/* Scan all the insns and delete any that are dead; i.e., they store a register + that is never used or they copy a register to itself. + + This is used to remove insns made obviously dead by cse, loop or other + optimizations. It improves the heuristics in loop since it won't try to + move dead invariants out of loops or make givs for dead quantities. The + remaining passes of the compilation are also sped up. */ + +void +delete_trivially_dead_insns (insns, nreg) + rtx insns; + int nreg; +{ + int *counts = (int *) alloca (nreg * sizeof (int)); + rtx insn, prev; +#ifdef HAVE_cc0 + rtx tem; +#endif + int i; + int in_libcall = 0, dead_libcall = 0; + + /* First count the number of times each register is used. */ + bzero ((char *) counts, sizeof (int) * nreg); + for (insn = next_real_insn (insns); insn; insn = next_real_insn (insn)) + count_reg_usage (insn, counts, NULL_RTX, 1); + + /* Go from the last insn to the first and delete insns that only set unused + registers or copy a register to itself. As we delete an insn, remove + usage counts for registers it uses. */ + for (insn = prev_real_insn (get_last_insn ()); insn; insn = prev) + { + int live_insn = 0; + rtx note; + + prev = prev_real_insn (insn); + + /* Don't delete any insns that are part of a libcall block unless + we can delete the whole libcall block. + + Flow or loop might get confused if we did that. Remember + that we are scanning backwards. */ + if (find_reg_note (insn, REG_RETVAL, NULL_RTX)) + { + in_libcall = 1; + live_insn = 1; + dead_libcall = 0; + + /* See if there's a REG_EQUAL note on this insn and try to + replace the source with the REG_EQUAL expression. + + We assume that insns with REG_RETVALs can only be reg->reg + copies at this point. */ + note = find_reg_note (insn, REG_EQUAL, NULL_RTX); + if (note) + { + rtx set = single_set (insn); + if (set + && validate_change (insn, &SET_SRC (set), XEXP (note, 0), 0)) + { + remove_note (insn, + find_reg_note (insn, REG_RETVAL, NULL_RTX)); + dead_libcall = 1; + } + } + } + else if (in_libcall) + live_insn = ! dead_libcall; + else if (GET_CODE (PATTERN (insn)) == SET) + { + if (GET_CODE (SET_DEST (PATTERN (insn))) == REG + && SET_DEST (PATTERN (insn)) == SET_SRC (PATTERN (insn))) + ; + +#ifdef HAVE_cc0 + else if (GET_CODE (SET_DEST (PATTERN (insn))) == CC0 + && ! side_effects_p (SET_SRC (PATTERN (insn))) + && ((tem = next_nonnote_insn (insn)) == 0 + || GET_RTX_CLASS (GET_CODE (tem)) != 'i' + || ! reg_referenced_p (cc0_rtx, PATTERN (tem)))) + ; +#endif + else if (GET_CODE (SET_DEST (PATTERN (insn))) != REG + || REGNO (SET_DEST (PATTERN (insn))) < FIRST_PSEUDO_REGISTER + || counts[REGNO (SET_DEST (PATTERN (insn)))] != 0 + || side_effects_p (SET_SRC (PATTERN (insn)))) + live_insn = 1; + } + else if (GET_CODE (PATTERN (insn)) == PARALLEL) + for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--) + { + rtx elt = XVECEXP (PATTERN (insn), 0, i); + + if (GET_CODE (elt) == SET) + { + if (GET_CODE (SET_DEST (elt)) == REG + && SET_DEST (elt) == SET_SRC (elt)) + ; + +#ifdef HAVE_cc0 + else if (GET_CODE (SET_DEST (elt)) == CC0 + && ! side_effects_p (SET_SRC (elt)) + && ((tem = next_nonnote_insn (insn)) == 0 + || GET_RTX_CLASS (GET_CODE (tem)) != 'i' + || ! reg_referenced_p (cc0_rtx, PATTERN (tem)))) + ; +#endif + else if (GET_CODE (SET_DEST (elt)) != REG + || REGNO (SET_DEST (elt)) < FIRST_PSEUDO_REGISTER + || counts[REGNO (SET_DEST (elt))] != 0 + || side_effects_p (SET_SRC (elt))) + live_insn = 1; + } + else if (GET_CODE (elt) != CLOBBER && GET_CODE (elt) != USE) + live_insn = 1; + } + else + live_insn = 1; + + /* If this is a dead insn, delete it and show registers in it aren't + being used. */ + + if (! live_insn) + { + count_reg_usage (insn, counts, NULL_RTX, -1); + delete_insn (insn); + } + + if (find_reg_note (insn, REG_LIBCALL, NULL_RTX)) + { + in_libcall = 0; + dead_libcall = 0; + } + } +} diff --git a/gcc_arm/cstamp-h b/gcc_arm/cstamp-h new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/gcc_arm/cstamp-h @@ -0,0 +1 @@ + diff --git a/gcc_arm/cstamp-h.in b/gcc_arm/cstamp-h.in new file mode 100755 index 0000000..9788f70 --- /dev/null +++ b/gcc_arm/cstamp-h.in @@ -0,0 +1 @@ +timestamp diff --git a/gcc_arm/dbxout.c b/gcc_arm/dbxout.c new file mode 100755 index 0000000..ac55120 --- /dev/null +++ b/gcc_arm/dbxout.c @@ -0,0 +1,2927 @@ +/* Output dbx-format symbol table information from GNU compiler. + Copyright (C) 1987, 88, 92-97, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* Output dbx-format symbol table data. + This consists of many symbol table entries, each of them + a .stabs assembler pseudo-op with four operands: + a "name" which is really a description of one symbol and its type, + a "code", which is a symbol defined in stab.h whose name starts with N_, + an unused operand always 0, + and a "value" which is an address or an offset. + The name is enclosed in doublequote characters. + + Each function, variable, typedef, and structure tag + has a symbol table entry to define it. + The beginning and end of each level of name scoping within + a function are also marked by special symbol table entries. + + The "name" consists of the symbol name, a colon, a kind-of-symbol letter, + and a data type number. The data type number may be followed by + "=" and a type definition; normally this will happen the first time + the type number is mentioned. The type definition may refer to + other types by number, and those type numbers may be followed + by "=" and nested definitions. + + This can make the "name" quite long. + When a name is more than 80 characters, we split the .stabs pseudo-op + into two .stabs pseudo-ops, both sharing the same "code" and "value". + The first one is marked as continued with a double-backslash at the + end of its "name". + + The kind-of-symbol letter distinguished function names from global + variables from file-scope variables from parameters from auto + variables in memory from typedef names from register variables. + See `dbxout_symbol'. + + The "code" is mostly redundant with the kind-of-symbol letter + that goes in the "name", but not entirely: for symbols located + in static storage, the "code" says which segment the address is in, + which controls how it is relocated. + + The "value" for a symbol in static storage + is the core address of the symbol (actually, the assembler + label for the symbol). For a symbol located in a stack slot + it is the stack offset; for one in a register, the register number. + For a typedef symbol, it is zero. + + If DEBUG_SYMS_TEXT is defined, all debugging symbols must be + output while in the text section. + + For more on data type definitions, see `dbxout_type'. */ + +#include "config.h" +#include "system.h" + +#include "tree.h" +#include "rtl.h" +#include "flags.h" +#include "regs.h" +#include "insn-config.h" +#include "reload.h" +#include "defaults.h" +#include "output.h" /* ASM_OUTPUT_SOURCE_LINE may refer to sdb functions. */ +/* CYGNUS LOCAL LRS */ +#include "range.h" +/* END CYGNUS LOCAL */ +#include "dbxout.h" +#include "toplev.h" + +#ifdef XCOFF_DEBUGGING_INFO +#include "xcoffout.h" +#endif + +#ifndef ASM_STABS_OP +#define ASM_STABS_OP ".stabs" +#endif + +#ifndef ASM_STABN_OP +#define ASM_STABN_OP ".stabn" +#endif + +#ifndef DBX_TYPE_DECL_STABS_CODE +#define DBX_TYPE_DECL_STABS_CODE N_LSYM +#endif + +#ifndef DBX_STATIC_CONST_VAR_CODE +#define DBX_STATIC_CONST_VAR_CODE N_FUN +#endif + +#ifndef DBX_REGPARM_STABS_CODE +#define DBX_REGPARM_STABS_CODE N_RSYM +#endif + +#ifndef DBX_REGPARM_STABS_LETTER +#define DBX_REGPARM_STABS_LETTER 'P' +#endif + +/* 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 DBX_MEMPARM_STABS_LETTER +#define DBX_MEMPARM_STABS_LETTER 'p' +#endif + +#ifndef FILE_NAME_JOINER +#define FILE_NAME_JOINER "/" +#endif + +/* Nonzero means if the type has methods, only output debugging + information if methods are actually written to the asm file. This + optimization only works if the debugger can detect the special C++ + marker. */ + +#define MINIMAL_DEBUG 1 + +#ifdef NO_DOLLAR_IN_LABEL +#ifdef NO_DOT_IN_LABEL +#undef MINIMAL_DEBUG +#define MINIMAL_DEBUG 0 +#endif +#endif + +char *getpwd (); + +/* Typical USG systems don't have stab.h, and they also have + no use for DBX-format debugging info. */ + +#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) + +static int flag_minimal_debug = MINIMAL_DEBUG; + +/* 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 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. */ + +static int source_label_number = 1; + +#ifdef DEBUG_SYMS_TEXT +#define FORCE_TEXT text_section (); +#else +#define FORCE_TEXT +#endif + +/* If there is a system stab.h, use it. Otherwise, use our own. */ + +#if defined (USG) || !defined (HAVE_STAB_H) +#include "gstab.h" /* If doing DBX on sysV, use our own stab.h. */ +#else +#include + +/* This is a GNU extension we need to reference in this file. */ +#ifndef N_CATCH +#define N_CATCH 0x54 +#endif +#endif + +#ifdef __GNU_STAB__ +#define STAB_CODE_TYPE enum __stab_debug_code +#else +#define STAB_CODE_TYPE int +#endif + +/* 1 if PARM is passed to this function in memory. */ + +#define PARM_PASSED_IN_MEMORY(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). */ +#ifndef DEBUGGER_AUTO_OFFSET +#define DEBUGGER_AUTO_OFFSET(X) \ + (GET_CODE (X) == PLUS ? INTVAL (XEXP (X, 1)) : 0) +#endif + +/* A C expression for the integer offset value of an argument (N_PSYM) + having address X (an RTX). The nominal offset is OFFSET. */ +#ifndef DEBUGGER_ARG_OFFSET +#define DEBUGGER_ARG_OFFSET(OFFSET, X) (OFFSET) +#endif + +/* Stream for writing to assembler file. */ + +static FILE *asmfile; + +/* Last source file name mentioned in a NOTE insn. */ + +static char *lastfile; + +/* CYGNUS LOCAL LRS */ +/* Current label number for the live range labels. */ + +static int range_current; + +/* Maximum number used for range markers. */ +int range_max_number; +static int range_max_number_for_parms; +/* END CYGNUS LOCAL */ + +/* Current working directory. */ + +static char *cwd; + +enum typestatus {TYPE_UNSEEN, TYPE_XREF, TYPE_DEFINED}; + +/* Structure recording information about a C data type. + The status element says whether we have yet output + the definition of the type. TYPE_XREF says we have + output it as a cross-reference only. + The file_number and type_number elements are used if DBX_USE_BINCL + is defined. */ + +struct typeinfo +{ + enum typestatus status; +#ifdef DBX_USE_BINCL + int file_number; + int type_number; +#endif +}; + +/* Vector recording information about C data types. + When we first notice a data type (a tree node), + we assign it a number using next_type_number. + That is its index in this vector. */ + +struct typeinfo *typevec; + +/* Number of elements of space allocated in `typevec'. */ + +static int typevec_len; + +/* In dbx output, each type gets a unique number. + This is the number for the next type output. + The number, once assigned, is in the TYPE_SYMTAB_ADDRESS field. */ + +static int next_type_number; + +#ifdef DBX_USE_BINCL + +/* When using N_BINCL in dbx output, each type number is actually a + pair of the file number and the type number within the file. + This is a stack of input files. */ + +struct dbx_file +{ + struct dbx_file *next; + int file_number; + int next_type_number; +}; + +/* This is the top of the stack. */ + +static struct dbx_file *current_file; + +/* This is the next file number to use. */ + +static int next_file_number; + +#endif /* DBX_USE_BINCL */ + +/* In dbx output, we must assign symbol-blocks id numbers + in the order in which their beginnings are encountered. + We output debugging info that refers to the beginning and + end of the ranges of code in each block + with assembler labels LBBn and LBEn, where n is the block number. + The labels are generated in final, which assigns numbers to the + blocks in the same way. */ + +static int next_block_number; + +/* 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 +#endif + +void dbxout_types (); +void dbxout_args (); +void dbxout_symbol (); + +#if defined(ASM_OUTPUT_SECTION_NAME) +static void dbxout_function_end PROTO((void)); +#endif +static void dbxout_typedefs PROTO((tree)); +static void dbxout_type_index PROTO((tree)); +#if DBX_CONTIN_LENGTH > 0 +static void dbxout_continue PROTO((void)); +#endif +static void dbxout_type_fields PROTO((tree)); +static void dbxout_type_method_1 PROTO((tree, char *)); +static void dbxout_type_methods PROTO((tree)); +static void dbxout_range_type PROTO((tree)); +static void dbxout_type PROTO((tree, int, int)); +static void print_int_cst_octal PROTO((tree)); +static void print_octal PROTO((unsigned HOST_WIDE_INT, int)); +static void dbxout_type_name PROTO((tree)); +static void dbxout_symbol_location PROTO((tree, tree, char *, rtx)); +/* CYGNUS LOCAL LRS */ +static void dbxout_symbol_name PROTO((tree, char *, int, int)); +static void dbxout_live_range_alias PROTO((tree)); +static void dbxout_live_range_parms PROTO((tree, int)); +/* END CYGNUS LOCAL */ +static void dbxout_prepare_symbol PROTO((tree)); +static void dbxout_finish_symbol PROTO((tree)); +static void dbxout_block PROTO((tree, int, tree)); +static void dbxout_really_begin_function PROTO((tree)); + +#if defined(ASM_OUTPUT_SECTION_NAME) +static void +dbxout_function_end () +{ + static int scope_labelno = 0; + char lscope_label_name[100]; + /* 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); + ASM_OUTPUT_INTERNAL_LABEL (asmfile, "Lscope", scope_labelno); + scope_labelno++; + + /* By convention, GCC will mark the end of a function with an N_FUN + symbol and an empty string. */ + fprintf (asmfile, "%s \"\",%d,0,0,", ASM_STABS_OP, N_FUN); + assemble_name (asmfile, lscope_label_name); + fputc ('-', asmfile); + assemble_name (asmfile, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0)); + fprintf (asmfile, "\n"); +} +#endif /* ! NO_DBX_FUNCTION_END */ + +/* At the beginning of compilation, start writing the symbol table. + Initialize `typevec' and output the standard data types of C. */ + +void +dbxout_init (asm_file, input_file_name, syms) + FILE *asm_file; + char *input_file_name; + tree syms; +{ + char ltext_label_name[100]; + + asmfile = asm_file; + + typevec_len = 100; + typevec = (struct typeinfo *) xmalloc (typevec_len * sizeof typevec[0]); + bzero ((char *) typevec, typevec_len * sizeof typevec[0]); + + /* 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. */ +#ifndef DBX_WORKING_DIRECTORY /* Only some versions of DBX want this, + but GDB always does. */ + if (use_gnu_debug_info_extensions) +#endif + { + if (!cwd && (cwd = getpwd ()) && (!*cwd || cwd[strlen (cwd) - 1] != '/')) + { + char *wdslash = xmalloc (strlen (cwd) + sizeof (FILE_NAME_JOINER)); + sprintf (wdslash, "%s%s", cwd, FILE_NAME_JOINER); + cwd = wdslash; + } + if (cwd) + { +#ifdef DBX_OUTPUT_MAIN_SOURCE_DIRECTORY + DBX_OUTPUT_MAIN_SOURCE_DIRECTORY (asmfile, cwd); +#else /* no DBX_OUTPUT_MAIN_SOURCE_DIRECTORY */ + fprintf (asmfile, "%s ", ASM_STABS_OP); + output_quoted_string (asmfile, cwd); + fprintf (asmfile, ",%d,0,0,%s\n", N_SO, <ext_label_name[1]); +#endif /* no DBX_OUTPUT_MAIN_SOURCE_DIRECTORY */ + } + } + +#ifdef DBX_OUTPUT_MAIN_SOURCE_FILENAME + /* This should NOT be DBX_OUTPUT_SOURCE_FILENAME. That + would give us an N_SOL, and we want an N_SO. */ + 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,%s\n", + N_SO, <ext_label_name[1]); + text_section (); + ASM_OUTPUT_INTERNAL_LABEL (asmfile, "Ltext", 0); +#endif /* no DBX_OUTPUT_MAIN_SOURCE_FILENAME */ + + /* Possibly output something to inform GDB that this compilation was by + GCC. It's easier for GDB to parse it when after the N_SO's. This + is used in Solaris 2. */ +#ifdef ASM_IDENTIFY_GCC_AFTER_SOURCE + ASM_IDENTIFY_GCC_AFTER_SOURCE (asmfile); +#endif + + lastfile = input_file_name; + + next_type_number = 1; + next_block_number = 2; + +#ifdef DBX_USE_BINCL + current_file = (struct dbx_file *) xmalloc (sizeof *current_file); + current_file->next = NULL; + current_file->file_number = 0; + current_file->next_type_number = 1; + next_file_number = 1; +#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); +#else + dbxout_symbol (TYPE_NAME (integer_type_node), 0); + dbxout_symbol (TYPE_NAME (char_type_node), 0); +#endif + + /* Get all permanent types that have typedef names, + and output them all, except for those already output. */ + + dbxout_typedefs (syms); +} + +/* Output any typedef names for types described by TYPE_DECLs in SYMS, + in the reverse order from that which is found in SYMS. */ + +static void +dbxout_typedefs (syms) + tree syms; +{ + if (syms) + { + dbxout_typedefs (TREE_CHAIN (syms)); + if (TREE_CODE (syms) == TYPE_DECL) + { + tree type = TREE_TYPE (syms); + if (TYPE_NAME (type) + && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && TYPE_SIZE (type) != NULL_TREE + && ! TREE_ASM_WRITTEN (TYPE_NAME (type))) + dbxout_symbol (TYPE_NAME (type), 0); + } + } +} + +/* Change to reading from a new source file. Generate a N_BINCL stab. */ + +void +dbxout_start_new_source_file (filename) + char *filename; +{ +#ifdef DBX_USE_BINCL + struct dbx_file *n = (struct dbx_file *) xmalloc (sizeof *n); + + n->next = current_file; + n->file_number = next_file_number++; + n->next_type_number = 1; + current_file = n; + fprintf (asmfile, "%s ", ASM_STABS_OP); + output_quoted_string (asmfile, filename); + fprintf (asmfile, ",%d,0,0,0\n", N_BINCL); +#endif +} + +/* Revert to reading a previous source file. Generate a N_EINCL stab. */ + +void +dbxout_resume_previous_source_file () +{ +#ifdef DBX_USE_BINCL + struct dbx_file *next; + + fprintf (asmfile, "%s %d,0,0,0\n", ASM_STABN_OP, N_EINCL); + next = current_file->next; + free (current_file); + current_file = next; +#endif +} + +/* Output debugging info to FILE to switch to sourcefile FILENAME. */ + +void +dbxout_source_file (file, filename) + FILE *file; + char *filename; +{ + char ltext_label_name[100]; + + if (filename && (lastfile == 0 || strcmp (filename, lastfile))) + { +#ifdef DBX_OUTPUT_SOURCE_FILENAME + DBX_OUTPUT_SOURCE_FILENAME (file, filename); +#else + ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", + source_label_number); + fprintf (file, "%s ", ASM_STABS_OP); + output_quoted_string (file, filename); + fprintf (file, ",%d,0,0,%s\n", N_SOL, <ext_label_name[1]); + if (current_function_decl != NULL_TREE + && DECL_SECTION_NAME (current_function_decl) != NULL_TREE) + ; /* Don't change section amid function. */ + else + text_section (); + ASM_OUTPUT_INTERNAL_LABEL (file, "Ltext", source_label_number); + source_label_number++; +#endif + lastfile = filename; + } +} + +/* Output a line number symbol entry into output stream FILE, + for source file FILENAME and line number LINENO. */ + +void +dbxout_source_line (file, filename, lineno) + FILE *file; + char *filename; + int lineno; +{ + dbxout_source_file (file, filename); + +#ifdef ASM_OUTPUT_SOURCE_LINE + ASM_OUTPUT_SOURCE_LINE (file, lineno); +#else + fprintf (file, "\t%s %d,0,%d\n", ASM_STABD_OP, N_SLINE, lineno); +#endif +} + +/* At the end of compilation, finish writing the symbol table. + Unless you define DBX_OUTPUT_MAIN_SOURCE_FILE_END, the default is + to do nothing. */ + +void +dbxout_finish (file, filename) + FILE *file; + char *filename; +{ +#ifdef DBX_OUTPUT_MAIN_SOURCE_FILE_END + DBX_OUTPUT_MAIN_SOURCE_FILE_END (file, filename); +#endif /* DBX_OUTPUT_MAIN_SOURCE_FILE_END */ +} + +/* Output the index of a type. */ + +static void +dbxout_type_index (type) + tree type; +{ +#ifndef DBX_USE_BINCL + fprintf (asmfile, "%d", TYPE_SYMTAB_ADDRESS (type)); + CHARS (3); +#else + struct typeinfo *t = &typevec[TYPE_SYMTAB_ADDRESS (type)]; + fprintf (asmfile, "(%d,%d)", t->file_number, t->type_number); + CHARS (7); +#endif +} + +#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 () +{ +#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. */ + +static void +dbxout_type_fields (type) + tree type; +{ + tree tem; + /* Output the name, type, position (in bits), size (in bits) of each + field. */ + for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem)) + { + /* Omit here local type decls until we know how to support them. */ + if (TREE_CODE (tem) == TYPE_DECL) + continue; + /* Omit fields whose position or size are variable. */ + else if (TREE_CODE (tem) == FIELD_DECL + && (TREE_CODE (DECL_FIELD_BITPOS (tem)) != INTEGER_CST + || TREE_CODE (DECL_SIZE (tem)) != INTEGER_CST)) + continue; + /* Omit here the nameless fields that are used to skip bits. */ + else if (DECL_IGNORED_P (tem)) + continue; + else if (TREE_CODE (tem) != CONST_DECL) + { + /* Continue the line if necessary, + but not before the first field. */ + if (tem != TYPE_FIELDS (type)) + { + CONTIN; + } + + if (use_gnu_debug_info_extensions + && flag_minimal_debug + && TREE_CODE (tem) == FIELD_DECL + && DECL_VIRTUAL_P (tem) + && DECL_ASSEMBLER_NAME (tem)) + { + have_used_extensions = 1; + CHARS (3 + IDENTIFIER_LENGTH (DECL_ASSEMBLER_NAME (tem))); + fputs (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (tem)), asmfile); + dbxout_type (DECL_FCONTEXT (tem), 0, 0); + fprintf (asmfile, ":"); + dbxout_type (TREE_TYPE (tem), 0, 0); + fputc (',', asmfile); + fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, + TREE_INT_CST_LOW (DECL_FIELD_BITPOS (tem))); + fputc (';', asmfile); + continue; + } + + if (DECL_NAME (tem)) + { + fprintf (asmfile, "%s:", IDENTIFIER_POINTER (DECL_NAME (tem))); + CHARS (2 + IDENTIFIER_LENGTH (DECL_NAME (tem))); + } + else + { + fprintf (asmfile, ":"); + CHARS (2); + } + + if (use_gnu_debug_info_extensions + && (TREE_PRIVATE (tem) || TREE_PROTECTED (tem) + || TREE_CODE (tem) != FIELD_DECL)) + { + 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 + && DECL_BIT_FIELD_TYPE (tem)) + ? DECL_BIT_FIELD_TYPE (tem) + : TREE_TYPE (tem), 0, 0); + + if (TREE_CODE (tem) == VAR_DECL) + { + if (TREE_STATIC (tem) && use_gnu_debug_info_extensions) + { + char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (tem)); + have_used_extensions = 1; + fprintf (asmfile, ":%s;", name); + CHARS (strlen (name)); + } + else + { + /* If TEM is non-static, GDB won't understand it. */ + fprintf (asmfile, ",0,0;"); + } + } + else if (TREE_CODE (DECL_FIELD_BITPOS (tem)) == INTEGER_CST) + { + fputc (',', asmfile); + fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, + TREE_INT_CST_LOW (DECL_FIELD_BITPOS (tem))); + fputc (',', asmfile); + fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, + TREE_INT_CST_LOW (DECL_SIZE (tem))); + fputc (';', asmfile); + } + CHARS (23); + } + } +} + +/* Subroutine of `dbxout_type_methods'. Output debug info about the + 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 (decl, debug_name) + tree decl; + char *debug_name; +{ + char c1 = 'A', c2; + + if (TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE) + c2 = '?'; + else /* it's a METHOD_TYPE. */ + { + tree firstarg = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl))); + /* A for normal functions. + B for `const' member functions. + C for `volatile' member functions. + D for `const volatile' member functions. */ + if (TYPE_READONLY (TREE_TYPE (firstarg))) + c1 += 1; + if (TYPE_VOLATILE (TREE_TYPE (firstarg))) + c1 += 2; + + if (DECL_VINDEX (decl)) + c2 = '*'; + else + 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)) + { + fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, + TREE_INT_CST_LOW (DECL_VINDEX (decl))); + fputc (';', asmfile); + dbxout_type (DECL_CONTEXT (decl), 0, 0); + fprintf (asmfile, ";"); + CHARS (8); + } +} + +/* Subroutine of `dbxout_type'. Output debug info about the methods defined + in TYPE. */ + +static void +dbxout_type_methods (type) + register tree type; +{ + /* C++: put out the method names and their parameter lists */ + tree methods = TYPE_METHODS (type); + tree type_encoding; + register tree fndecl; + register tree last; + char formatted_type_identifier_length[16]; + register 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. */ + { + 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) + fndecl = TREE_VEC_ELT (methods, 0); + else + fndecl = TREE_VEC_ELT (methods, 1); + + while (fndecl) + { + tree name = DECL_NAME (fndecl); + int need_prefix = 1; + + /* Group together all the methods for the same operation. + These differ in the types of the arguments. */ + for (last = NULL_TREE; + fndecl && (last == NULL_TREE || DECL_NAME (fndecl) == DECL_NAME (last)); + fndecl = TREE_CHAIN (fndecl)) + /* Output the name of the field (after overloading), as + 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. */ + char *debug_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)); + int show_arg_types = 0; + + CONTIN; + + last = fndecl; + + if (DECL_IGNORED_P (fndecl)) + continue; + + if (flag_minimal_debug) + { + char marker; + + /* We can't optimize a method which uses an anonymous + class, because the debugger will not be able to + associate the arbitrary class name with the actual + class. */ +#ifndef NO_DOLLAR_IN_LABEL + marker = '$'; +#else + marker = '.'; +#endif + if (strchr (debug_name, marker)) + show_arg_types = 1; + /* Detect ordinary methods because their mangled names + start with the operation name. */ + else if (!strncmp (IDENTIFIER_POINTER (name), debug_name, + IDENTIFIER_LENGTH (name))) + { + debug_name += IDENTIFIER_LENGTH (name); + if (debug_name[0] == '_' && debug_name[1] == '_') + { + char *method_name = debug_name + 2; + char *length_ptr = formatted_type_identifier_length; + /* Get past const and volatile qualifiers. */ + while (*method_name == 'C' || *method_name == 'V') + method_name++; + /* Skip digits for length of type_encoding. */ + while (*method_name == *length_ptr && *length_ptr) + length_ptr++, method_name++; + if (! strncmp (method_name, + IDENTIFIER_POINTER (type_encoding), + type_identifier_length)) + method_name += type_identifier_length; + debug_name = method_name; + } + } + /* Detect constructors by their style of name mangling. */ + else if (debug_name[0] == '_' && debug_name[1] == '_') + { + char *ctor_name = debug_name + 2; + char *length_ptr = formatted_type_identifier_length; + while (*ctor_name == 'C' || *ctor_name == 'V') + ctor_name++; + /* Skip digits for length of type_encoding. */ + while (*ctor_name == *length_ptr && *length_ptr) + length_ptr++, ctor_name++; + if (!strncmp (IDENTIFIER_POINTER (type_encoding), ctor_name, + type_identifier_length)) + debug_name = ctor_name + type_identifier_length; + } + /* The other alternative is a destructor. */ + else + show_arg_types = 1; + + /* Output the operation name just once, for the first method + that we output. */ + if (need_prefix) + { + fprintf (asmfile, "%s::", IDENTIFIER_POINTER (name)); + CHARS (IDENTIFIER_LENGTH (name) + 2); + need_prefix = 0; + } + } + + dbxout_type (TREE_TYPE (fndecl), 0, show_arg_types); + + dbxout_type_method_1 (fndecl, debug_name); + } + if (!need_prefix) + { + putc (';', asmfile); + CHARS (1); + } + } +} + +/* Emit a "range" type specification, which has the form: + "r;;;". + TYPE is an INTEGER_TYPE. */ + +static void +dbxout_range_type (type) + tree type; +{ + fprintf (asmfile, "r"); + if (TREE_TYPE (type)) + dbxout_type (TREE_TYPE (type), 0, 0); + else if (TREE_CODE (type) != INTEGER_TYPE) + dbxout_type (type, 0, 0); /* E.g. Pascal's ARRAY [BOOLEAN] of INTEGER */ + else + { + /* Traditionally, we made sure 'int' was type 1, and builtin types + were defined to be sub-ranges of int. Unfortunately, this + does not allow us to distinguish true sub-ranges from integer + types. So, instead we define integer (non-sub-range) types as + sub-ranges of themselves. This matters for Chill. If this isn't + a subrange type, then we want to define it in terms of itself. + However, in C, this may be an anonymous integer type, and we don't + want to emit debug info referring to it. Just calling + dbxout_type_index won't work anyways, because the type hasn't been + defined yet. We make this work for both cases by checked to see + whether this is a defined type, referring to it if it is, and using + 'int' otherwise. */ + if (TYPE_SYMTAB_ADDRESS (type) != 0) + dbxout_type_index (type); + else + dbxout_type_index (integer_type_node); + } + if (TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST) + { + fputc (';', asmfile); + fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, + TREE_INT_CST_LOW (TYPE_MIN_VALUE (type))); + } + else + fprintf (asmfile, ";0"); + if (TYPE_MAX_VALUE (type) + && TREE_CODE (TYPE_MAX_VALUE (type)) == INTEGER_CST) + { + fputc (';', asmfile); + fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, + TREE_INT_CST_LOW (TYPE_MAX_VALUE (type))); + fputc (';', asmfile); + } + else + fprintf (asmfile, ";-1;"); +} + +/* Output a reference to a type. If the type has not yet been + described in the dbx output, output its definition now. + For a type already defined, just refer to its definition + using the type number. + + If FULL is nonzero, and the type has been described only with + a forward-reference, output the definition now. + If FULL is zero in this case, just refer to the forward-reference + using the number previously allocated. + + If SHOW_ARG_TYPES is nonzero, we output a description of the argument + types for a METHOD_TYPE. */ + +static void +dbxout_type (type, full, show_arg_types) + tree type; + int full; + int show_arg_types; +{ + register tree tem; + static int anonymous_type_number = 0; + + /* If there was an input error and we don't really have a type, + avoid crashing and write something that is at least valid + by assuming `int'. */ + if (type == error_mark_node) + type = integer_type_node; + else + { + /* Try to find the "main variant" with the same name but not const + or volatile. (Since stabs does not distinguish const and volatile, + there is no need to make them separate types. But types with + different names are usefully distinguished.) */ + + for (tem = TYPE_MAIN_VARIANT (type); tem; tem = TYPE_NEXT_VARIANT (tem)) + if (!TYPE_READONLY (tem) && !TYPE_VOLATILE (tem) + && TYPE_NAME (tem) == TYPE_NAME (type)) + { + type = tem; + break; + } + if (TYPE_NAME (type) + && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (type))) + full = 0; + } + + if (TYPE_SYMTAB_ADDRESS (type) == 0) + { + /* Type has no dbx number assigned. Assign next available number. */ + TYPE_SYMTAB_ADDRESS (type) = next_type_number++; + + /* Make sure type vector is long enough to record about this type. */ + + if (next_type_number == typevec_len) + { + typevec + = (struct typeinfo *) xrealloc (typevec, + typevec_len * 2 * sizeof typevec[0]); + bzero ((char *) (typevec + typevec_len), + typevec_len * sizeof typevec[0]); + typevec_len *= 2; + } + +#ifdef DBX_USE_BINCL + typevec[TYPE_SYMTAB_ADDRESS (type)].file_number + = current_file->file_number; + typevec[TYPE_SYMTAB_ADDRESS (type)].type_number + = current_file->next_type_number++; +#endif + } + + /* Output the number of this type, to refer to it. */ + dbxout_type_index (type); + +#ifdef DBX_TYPE_DEFINED + if (DBX_TYPE_DEFINED (type)) + return; +#endif + + /* If this type's definition has been output or is now being output, + that is all. */ + + switch (typevec[TYPE_SYMTAB_ADDRESS (type)].status) + { + case TYPE_UNSEEN: + break; + case TYPE_XREF: + /* If we have already had a cross reference, + and either that's all we want or that's the best we could do, + don't repeat the cross reference. + Sun dbx crashes if we do. */ + if (! full || TYPE_SIZE (type) == 0 + /* No way in DBX fmt to describe a variable size. */ + || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) + return; + break; + case TYPE_DEFINED: + return; + } + +#ifdef DBX_NO_XREFS + /* For systems where dbx output does not allow the `=xsNAME:' syntax, + leave the type-number completely undefined rather than output + a cross-reference. If we have already used GNU debug info extensions, + then it is OK to output a cross reference. This is necessary to get + proper C++ debug output. */ + if ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE + || TREE_CODE (type) == ENUMERAL_TYPE) + && ! use_gnu_debug_info_extensions) + /* We must use the same test here as we use twice below when deciding + whether to emit a cross-reference. */ + if ((TYPE_NAME (type) != 0 + && ! (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && DECL_IGNORED_P (TYPE_NAME (type))) + && !full) + || TYPE_SIZE (type) == 0 + /* No way in DBX fmt to describe a variable size. */ + || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) + { + typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_XREF; + return; + } +#endif + + /* Output a definition now. */ + + 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. */ + + typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_DEFINED; + + if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && DECL_ORIGINAL_TYPE (TYPE_NAME (type))) + { + dbxout_type (DECL_ORIGINAL_TYPE (TYPE_NAME (type)), 0, 0); + return; + } + + switch (TREE_CODE (type)) + { + case VOID_TYPE: + case LANG_TYPE: + /* 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 + ever override that default. */ + dbxout_type_index (type); + break; + + case INTEGER_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. */ + fprintf (asmfile, "r"); + dbxout_type_index (type); + fprintf (asmfile, ";0;127;"); + } + /* This used to check if the type's precision was more than + HOST_BITS_PER_WIDE_INT. That is wrong since gdb uses a + long (it has no concept of HOST_BITS_PER_WIDE_INT). */ + else if (use_gnu_debug_info_extensions + && (TYPE_PRECISION (type) > TYPE_PRECISION (integer_type_node) + || TYPE_PRECISION (type) >= HOST_BITS_PER_LONG)) + { + /* This used to say `r1' and we used to take care + to make sure that `int' was type number 1. */ + fprintf (asmfile, "r"); + dbxout_type_index (integer_type_node); + fprintf (asmfile, ";"); + print_int_cst_octal (TYPE_MIN_VALUE (type)); + fprintf (asmfile, ";"); + print_int_cst_octal (TYPE_MAX_VALUE (type)); + fprintf (asmfile, ";"); + } + else /* Output other integer types as subranges of `int'. */ + dbxout_range_type (type); + CHARS (22); + break; + + case REAL_TYPE: + /* This used to say `r1' and we used to take care + to make sure that `int' was type number 1. */ + fprintf (asmfile, "r"); + dbxout_type_index (integer_type_node); + fputc (';', asmfile); + fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, int_size_in_bytes (type)); + fputs (";0;", asmfile); + CHARS (13); + break; + + case CHAR_TYPE: + if (use_gnu_debug_info_extensions) + { + fputs ("@s", asmfile); + fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, + BITS_PER_UNIT * int_size_in_bytes (type)); + fputs (";-20;", asmfile); + } + else + { + /* Output the type `char' as a subrange of itself. + That is what pcc seems to do. */ + fprintf (asmfile, "r"); + dbxout_type_index (char_type_node); + fprintf (asmfile, ";0;%d;", TREE_UNSIGNED (type) ? 255 : 127); + } + CHARS (9); + break; + + case BOOLEAN_TYPE: + if (use_gnu_debug_info_extensions) + { + fputs ("@s", asmfile); + fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, + BITS_PER_UNIT * int_size_in_bytes (type)); + fputs (";-16;", asmfile); + } + else /* Define as enumeral type (False, True) */ + fprintf (asmfile, "eFalse:0,True:1,;"); + CHARS (17); + break; + + case FILE_TYPE: + putc ('d', asmfile); + CHARS (1); + dbxout_type (TREE_TYPE (type), 0, 0); + break; + + case COMPLEX_TYPE: + /* Differs from the REAL_TYPE by its new data type number */ + + if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE) + { + fprintf (asmfile, "r"); + dbxout_type_index (type); + fputc (';', asmfile); + fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, + int_size_in_bytes (TREE_TYPE (type))); + fputs (";0;", asmfile); + CHARS (12); /* The number is probably incorrect here. */ + } + else + { + /* Output a complex integer type as a structure, + pending some other way to do it. */ + fputc ('s', asmfile); + fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, int_size_in_bytes (type)); + + fprintf (asmfile, "real:"); + CHARS (10); + dbxout_type (TREE_TYPE (type), 0, 0); + fprintf (asmfile, ",%d,%d;", + 0, TYPE_PRECISION (TREE_TYPE (type))); + CHARS (8); + fprintf (asmfile, "imag:"); + CHARS (5); + dbxout_type (TREE_TYPE (type), 0, 0); + fprintf (asmfile, ",%d,%d;;", + TYPE_PRECISION (TREE_TYPE (type)), + TYPE_PRECISION (TREE_TYPE (type))); + CHARS (9); + } + break; + + case SET_TYPE: + if (use_gnu_debug_info_extensions) + { + have_used_extensions = 1; + fputs ("@s", asmfile); + fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, + BITS_PER_UNIT * int_size_in_bytes (type)); + fputc (';', asmfile); + /* Check if a bitstring type, which in Chill is + different from a [power]set. */ + if (TYPE_STRING_FLAG (type)) + fprintf (asmfile, "@S;"); + } + putc ('S', asmfile); + CHARS (1); + dbxout_type (TYPE_DOMAIN (type), 0, 0); + break; + + case ARRAY_TYPE: + /* Make arrays of packed bits look like bitstrings for chill. */ + if (TYPE_PACKED (type) && use_gnu_debug_info_extensions) + { + have_used_extensions = 1; + fputs ("@s", asmfile); + fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, + BITS_PER_UNIT * int_size_in_bytes (type)); + fputc (';', asmfile); + fprintf (asmfile, "@S;"); + putc ('S', asmfile); + CHARS (1); + dbxout_type (TYPE_DOMAIN (type), 0, 0); + break; + } + /* Output "a" followed by a range type definition + for the index type of the array + followed by a reference to the target-type. + ar1;0;N;M for a C array of type M and size N+1. */ + /* Check if a character string type, which in Chill is + different from an array of characters. */ + if (TYPE_STRING_FLAG (type) && use_gnu_debug_info_extensions) + { + have_used_extensions = 1; + fprintf (asmfile, "@S;"); + } + tem = TYPE_DOMAIN (type); + if (tem == NULL) + { + fprintf (asmfile, "ar"); + dbxout_type_index (integer_type_node); + fprintf (asmfile, ";0;-1;"); + } + else + { + fprintf (asmfile, "a"); + dbxout_range_type (tem); + } + CHARS (14); + dbxout_type (TREE_TYPE (type), 0, 0); + break; + + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_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. */ + if ((TYPE_NAME (type) != 0 + && ! (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && DECL_IGNORED_P (TYPE_NAME (type))) + && !full) + || TYPE_SIZE (type) == 0 + /* No way in DBX fmt to describe a variable size. */ + || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) + { + /* If the type is just a cross reference, output one + and mark the type as partially described. + If it later becomes defined, we will output + its real definition. + 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. */ + fprintf (asmfile, (TREE_CODE (type) == RECORD_TYPE) ? "xs" : "xu"); + CHARS (3); +#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 + fprintf (asmfile, "$$%d", anonymous_type_number++); + fprintf (asmfile, ":"); + typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_XREF; + break; + } + + /* Identify record or union, and print its size. */ + fputc (((TREE_CODE (type) == RECORD_TYPE) ? 's' : 'u'), asmfile); + fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, + int_size_in_bytes (type)); + + if (use_gnu_debug_info_extensions) + { + if (n_baseclasses) + { + have_used_extensions = 1; + fprintf (asmfile, "!%d,", n_baseclasses); + CHARS (8); + } + } + for (i = 0; i < n_baseclasses; i++) + { + tree child = TREE_VEC_ELT (BINFO_BASETYPES (TYPE_BINFO (type)), i); + if (use_gnu_debug_info_extensions) + { + have_used_extensions = 1; + putc (TREE_VIA_VIRTUAL (child) ? '1' + : '0', + asmfile); + putc (TREE_VIA_PUBLIC (child) ? '2' + : '0', + asmfile); + fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, + TREE_INT_CST_LOW (BINFO_OFFSET (child)) * BITS_PER_UNIT); + fputc (',', asmfile); + CHARS (15); + dbxout_type (BINFO_TYPE (child), 0, 0); + putc (';', asmfile); + } + 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); + dbxout_type (BINFO_TYPE (child), full, 0); + fputc (',', asmfile); + fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, + TREE_INT_CST_LOW (BINFO_OFFSET (child)) * BITS_PER_UNIT); + fputc (',', asmfile); + fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, + TREE_INT_CST_LOW (DECL_SIZE (TYPE_NAME (BINFO_TYPE (child)))) * BITS_PER_UNIT); + fputc (';', asmfile); + CHARS (20); + } + } + } + + CHARS (11); + + /* Write out the field declarations. */ + dbxout_type_fields (type); + if (use_gnu_debug_info_extensions && TYPE_METHODS (type) != NULL_TREE) + { + have_used_extensions = 1; + dbxout_type_methods (type); + } + putc (';', asmfile); + + 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); + + /* 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. */ + if (TYPE_VFIELD (type)) + { + putc ('%', asmfile); + dbxout_type (DECL_FCONTEXT (TYPE_VFIELD (type)), 0, 0); + } + putc (';', asmfile); + CHARS (3); + } + break; + + case ENUMERAL_TYPE: + /* We must use the same test here as we use in the DBX_NO_XREFS case + above. We simplify it a bit since an enum will never have a variable + size. */ + if ((TYPE_NAME (type) != 0 + && ! (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && DECL_IGNORED_P (TYPE_NAME (type))) + && !full) + || TYPE_SIZE (type) == 0) + { + fprintf (asmfile, "xe"); + CHARS (3); + dbxout_type_name (type); + typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_XREF; + fprintf (asmfile, ":"); + return; + } +#ifdef DBX_OUTPUT_ENUM + DBX_OUTPUT_ENUM (asmfile, type); +#else + if (use_gnu_debug_info_extensions + && TYPE_PRECISION (type) != TYPE_PRECISION (integer_type_node)) + fprintf (asmfile, "@s%d;", TYPE_PRECISION (type)); + putc ('e', asmfile); + CHARS (1); + for (tem = TYPE_VALUES (type); tem; tem = TREE_CHAIN (tem)) + { + fprintf (asmfile, "%s:", IDENTIFIER_POINTER (TREE_PURPOSE (tem))); + if (TREE_INT_CST_HIGH (TREE_VALUE (tem)) == 0) + fprintf (asmfile, HOST_WIDE_INT_PRINT_UNSIGNED, + TREE_INT_CST_LOW (TREE_VALUE (tem))); + else if (TREE_INT_CST_HIGH (TREE_VALUE (tem)) == -1 + && TREE_INT_CST_LOW (TREE_VALUE (tem)) < 0) + fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, + TREE_INT_CST_LOW (TREE_VALUE (tem))); + else + print_int_cst_octal (TREE_VALUE (tem)); + fprintf (asmfile, ","); + CHARS (20 + IDENTIFIER_LENGTH (TREE_PURPOSE (tem))); + if (TREE_CHAIN (tem) != 0) + { + CONTIN; + } + } + putc (';', asmfile); + CHARS (1); +#endif + break; + + case POINTER_TYPE: + putc ('*', asmfile); + CHARS (1); + dbxout_type (TREE_TYPE (type), 0, 0); + break; + + case METHOD_TYPE: + if (use_gnu_debug_info_extensions) + { + have_used_extensions = 1; + putc ('#', asmfile); + CHARS (1); + if (flag_minimal_debug && !show_arg_types) + { + /* Normally, just output the return type. + The argument types are encoded in the method name. */ + putc ('#', asmfile); + CHARS (1); + dbxout_type (TREE_TYPE (type), 0, 0); + putc (';', asmfile); + CHARS (1); + } + else + { + /* When outputting destructors, we need to write + the argument types out longhand. */ + dbxout_type (TYPE_METHOD_BASETYPE (type), 0, 0); + putc (',', asmfile); + CHARS (1); + dbxout_type (TREE_TYPE (type), 0, 0); + dbxout_args (TYPE_ARG_TYPES (type)); + putc (';', asmfile); + CHARS (1); + } + } + else + { + /* Treat it as a function type. */ + dbxout_type (TREE_TYPE (type), 0, 0); + } + break; + + case OFFSET_TYPE: + if (use_gnu_debug_info_extensions) + { + have_used_extensions = 1; + putc ('@', asmfile); + CHARS (1); + dbxout_type (TYPE_OFFSET_BASETYPE (type), 0, 0); + putc (',', asmfile); + CHARS (1); + dbxout_type (TREE_TYPE (type), 0, 0); + } + else + { + /* Should print as an int, because it is really + just an offset. */ + dbxout_type (integer_type_node, 0, 0); + } + break; + + case REFERENCE_TYPE: + if (use_gnu_debug_info_extensions) + have_used_extensions = 1; + putc (use_gnu_debug_info_extensions ? '&' : '*', asmfile); + CHARS (1); + dbxout_type (TREE_TYPE (type), 0, 0); + break; + + case FUNCTION_TYPE: + putc ('f', asmfile); + CHARS (1); + dbxout_type (TREE_TYPE (type), 0, 0); + break; + + default: + abort (); + } +} + +/* Print the value of integer constant C, in octal, + handling double precision. */ + +static void +print_int_cst_octal (c) + tree c; +{ + 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)); + int width = TYPE_PRECISION (TREE_TYPE (c)); + + /* 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); + + fprintf (asmfile, "0"); + + if (excess == 3) + { + 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); + print_octal (end, HOST_BITS_PER_WIDE_INT / 3); + } +} + +static void +print_octal (value, digits) + unsigned HOST_WIDE_INT value; + int digits; +{ + int i; + + for (i = digits - 1; i >= 0; i--) + fprintf (asmfile, "%01o", (int)((value >> (3 * i)) & 7)); +} + +/* 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 void +dbxout_type_name (type) + register tree type; +{ + tree t; + if (TYPE_NAME (type) == 0) + abort (); + if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) + { + t = TYPE_NAME (type); + } + else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL) + { + t = DECL_NAME (TYPE_NAME (type)); + } + else + abort (); + + fprintf (asmfile, "%s", IDENTIFIER_POINTER (t)); + CHARS (IDENTIFIER_LENGTH (t)); +} + +/* 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. + LOCAL is nonzero if the scope is less than the entire file. */ + +void +dbxout_symbol (decl, local) + tree decl; + int local; +{ + tree type = TREE_TYPE (decl); + tree context = NULL_TREE; + + /* Cast avoids warning in old compilers. */ + current_sym_code = (STAB_CODE_TYPE) 0; + current_sym_value = 0; + current_sym_addr = 0; + + /* Ignore nameless syms, but don't ignore type tags. */ + + if ((DECL_NAME (decl) == 0 && TREE_CODE (decl) != TYPE_DECL) + || DECL_IGNORED_P (decl)) + return; + + 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: + /* Enum values are defined by defining the enum type. */ + break; + + case FUNCTION_DECL: + if (DECL_RTL (decl) == 0) + return; + if (DECL_EXTERNAL (decl)) + break; + /* Don't mention a nested function under its parent. */ + context = decl_function_context (decl); + if (context == current_function_decl) + break; + if (GET_CODE (DECL_RTL (decl)) != MEM + || GET_CODE (XEXP (DECL_RTL (decl), 0)) != SYMBOL_REF) + break; + FORCE_TEXT; + + fprintf (asmfile, "%s \"%s:%c", ASM_STABS_OP, + IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), + TREE_PUBLIC (decl) ? 'F' : 'f'); + + current_sym_code = N_FUN; + current_sym_addr = XEXP (DECL_RTL (decl), 0); + + if (TREE_TYPE (type)) + dbxout_type (TREE_TYPE (type), 0, 0); + else + dbxout_type (void_type_node, 0, 0); + + /* For a nested function, when that function is compiled, + mention the containing function name + as well as (since dbx wants it) our own assembler-name. */ + if (context != 0) + fprintf (asmfile, ",%s,%s", + IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), + IDENTIFIER_POINTER (DECL_NAME (context))); + + dbxout_finish_symbol (decl); + break; + + case TYPE_DECL: +#if 0 + /* This seems all wrong. Outputting most kinds of types gives no name + at all. A true definition gives no name; a cross-ref for a + structure can give the tag name, but not a type name. + It seems that no typedef name is defined by outputting a type. */ + + /* If this typedef name was defined by outputting the type, + don't duplicate it. */ + if (typevec[TYPE_SYMTAB_ADDRESS (type)].status == TYPE_DEFINED + && TYPE_NAME (TREE_TYPE (decl)) == decl) + return; +#endif + /* Don't output the same typedef twice. + And don't output what language-specific stuff doesn't want output. */ + if (TREE_ASM_WRITTEN (decl) || TYPE_DECL_SUPPRESS_DEBUG (decl)) + return; + + FORCE_TEXT; + + { + int tag_needed = 1; + int did_output = 0; + + if (DECL_NAME (decl)) + { + /* Nonzero means we must output a tag as well as a typedef. */ + tag_needed = 0; + + /* Handle the case of a C++ structure or union + where the TYPE_NAME is a TYPE_DECL + which gives both a typedef name and a tag. */ + /* dbx requires the tag first and the typedef second. */ + if ((TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE) + && TYPE_NAME (type) == decl + && !(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. */ + && DECL_ARTIFICIAL (decl)) + { + tree name = TYPE_NAME (type); + if (TREE_CODE (name) == TYPE_DECL) + name = DECL_NAME (name); + + 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, 0); + dbxout_finish_symbol (NULL_TREE); + } + + /* Output typedef name. */ + fprintf (asmfile, "%s \"%s:", ASM_STABS_OP, + IDENTIFIER_POINTER (DECL_NAME (decl))); + + /* Short cut way to output a tag also. */ + if ((TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE) + && TYPE_NAME (type) == decl + /* Distinguish the implicit typedefs of C++ + from explicit ones that might be found in C. */ + && DECL_ARTIFICIAL (decl)) + { + if (use_gnu_debug_info_extensions && have_used_extensions) + { + 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 + } + + putc ('t', asmfile); + current_sym_code = DBX_TYPE_DECL_STABS_CODE; + + dbxout_type (type, 1, 0); + dbxout_finish_symbol (decl); + did_output = 1; + } + + /* Don't output a tag if this is an incomplete type (TYPE_SIZE is + zero). This prevents the sun4 Sun OS 4.x dbx from crashing. */ + + if (tag_needed && TYPE_NAME (type) != 0 + && (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE + || (DECL_NAME (TYPE_NAME (type)) != 0)) + && TYPE_SIZE (type) != 0 + && !TREE_ASM_WRITTEN (TYPE_NAME (type))) + { + /* For a TYPE_DECL with no name, but the type has a name, + output a tag. + This is what represents `struct foo' with no typedef. */ + /* In C++, the name of a type is the corresponding typedef. + In C, it is an IDENTIFIER_NODE. */ + tree name = TYPE_NAME (type); + if (TREE_CODE (name) == TYPE_DECL) + name = DECL_NAME (name); + + 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, 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, since the enumeration constants + can be referred to. */ + if (!did_output && TREE_CODE (type) == ENUMERAL_TYPE) + { + 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 ` '. */ + fprintf (asmfile, "%s \" :T", ASM_STABS_OP); + dbxout_type (type, 1, 0); + dbxout_finish_symbol (NULL_TREE); + } + + /* Prevent duplicate output of a typedef. */ + TREE_ASM_WRITTEN (decl) = 1; + break; + } + + case PARM_DECL: + /* Parm decls go in their own separate chains + and are output by dbxout_reg_parms and dbxout_parms. */ + abort (); + + case RESULT_DECL: + /* Named return value, treat like a VAR_DECL. */ + case VAR_DECL: + if (DECL_RTL (decl) == 0) + return; + /* 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. */ + if (TREE_STATIC (decl) && TREE_READONLY (decl) + && DECL_INITIAL (decl) != 0 + && ! TREE_ASM_WRITTEN (decl) + && (DECL_FIELD_CONTEXT (decl) == NULL_TREE + || TREE_CODE (DECL_FIELD_CONTEXT (decl)) == BLOCK)) + { + if (TREE_PUBLIC (decl) == 0) + { + /* The sun4 assembler does not grok this. */ + 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_INT_CST_LOW (DECL_INITIAL (decl)); +#ifdef DBX_OUTPUT_CONSTANT_SYMBOL + DBX_OUTPUT_CONSTANT_SYMBOL (asmfile, name, ival); +#else + fprintf (asmfile, "%s \"%s:c=i", ASM_STABS_OP, name); + + fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, ival); + fprintf (asmfile, "\",0x%x,0,0,0\n", N_LSYM); +#endif + return; + } + else if (TREE_CODE (TREE_TYPE (decl)) == REAL_TYPE) + { + /* don't know how to do this yet. */ + } + break; + } + /* else it is something we handle like a normal variable. */ + } + + DECL_RTL (decl) = eliminate_regs (DECL_RTL (decl), 0, NULL_RTX); +#ifdef LEAF_REG_REMAP + if (leaf_function) + leaf_renumber_regs_insn (DECL_RTL (decl)); +#endif + + dbxout_symbol_location (decl, type, 0, DECL_RTL (decl)); + break; + + default: + break; + } +} + +/* Output the stab for DECL, a VAR_DECL, RESULT_DECL or PARM_DECL. + Add SUFFIX to its name, if SUFFIX is not 0. + Describe the variable as residing in HOME + (usually HOME is DECL_RTL (DECL), but not always). */ + +static void +dbxout_symbol_location (decl, type, suffix, home) + tree decl, type; + char *suffix; + rtx home; +{ + int letter = 0; + int regno = -1; + + /* Don't mention a variable at all + if it was completely optimized into nothingness. + + If the decl was from an inline function, then its rtl + is not identically the rtl that was used in this + particular compilation. */ + if (GET_CODE (home) == REG) + { + regno = REGNO (home); + if (regno >= FIRST_PSEUDO_REGISTER) + return; + } + else if (GET_CODE (home) == SUBREG) + { + rtx value = home; + int offset = 0; + while (GET_CODE (value) == SUBREG) + { + offset += SUBREG_WORD (value); + value = SUBREG_REG (value); + } + if (GET_CODE (value) == REG) + { + regno = REGNO (value); + if (regno >= FIRST_PSEUDO_REGISTER) + return; + regno += offset; + } + alter_subreg (home); + } + + /* The kind-of-variable letter depends on where + the variable is and on the scope of its name: + G and N_GSYM for static storage and global scope, + S for static storage and file scope, + V for static storage and local scope, + for those two, use N_LCSYM if data is in bss segment, + N_STSYM if in data segment, N_FUN otherwise. + (We used N_FUN originally, then changed to N_STSYM + to please GDB. However, it seems that confused ld. + Now GDB has been fixed to like N_FUN, says Kingdon.) + no letter at all, and N_LSYM, for auto variable, + r and N_RSYM for register variable. */ + + if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == SYMBOL_REF) + { + if (TREE_PUBLIC (decl)) + { + letter = 'G'; + current_sym_code = N_GSYM; + } + else + { + current_sym_addr = XEXP (home, 0); + + letter = decl_function_context (decl) ? 'V' : 'S'; + + /* This should be the same condition as in assemble_variable, but + we don't have access to dont_output_data here. So, instead, + we rely on the fact that error_mark_node initializers always + end up in bss for C++ and never end up in bss for C. */ + if (DECL_INITIAL (decl) == 0 + || (!strcmp (lang_identify (), "cplusplus") + && DECL_INITIAL (decl) == error_mark_node)) + 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. */ + current_sym_code = DBX_STATIC_CONST_VAR_CODE; + else + { + /* Ultrix `as' seems to need this. */ +#ifdef DBX_STATIC_STAB_DATA_SECTION + data_section (); +#endif + current_sym_code = N_STSYM; + } + } + } + else if (regno >= 0) + { + letter = 'r'; + current_sym_code = N_RSYM; + current_sym_value = DBX_REGISTER_NUMBER (regno); + } + 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 + && REGNO (XEXP (home, 0)) != ARG_POINTER_REGNUM +#endif + ))) + /* If the value is indirect by memory or by a register + that isn't the frame pointer + 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. + (VAR_DECLs like this can be made by integrate.c.) */ + { + if (GET_CODE (XEXP (home, 0)) == REG) + { + letter = 'r'; + current_sym_code = N_RSYM; + current_sym_value = DBX_REGISTER_NUMBER (REGNO (XEXP (home, 0))); + } + else + { + current_sym_code = N_LSYM; + /* RTL looks like (MEM (MEM (PLUS (REG...) (CONST_INT...)))). + We want the value of that CONST_INT. */ + current_sym_value + = DEBUGGER_AUTO_OFFSET (XEXP (XEXP (home, 0), 0)); + } + + /* Effectively do build_pointer_type, but don't cache this type, + since it might be temporary whereas the type it points to + might have been saved for inlining. */ + /* Don't use REFERENCE_TYPE because dbx can't handle that. */ + type = make_node (POINTER_TYPE); + TREE_TYPE (type) = TREE_TYPE (decl); + } + else if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == REG) + { + current_sym_code = N_LSYM; + current_sym_value = DEBUGGER_AUTO_OFFSET (XEXP (home, 0)); + } + else if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == PLUS + && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT) + { + current_sym_code = N_LSYM; + /* RTL looks like (MEM (PLUS (REG...) (CONST_INT...))) + We want the value of that CONST_INT. */ + current_sym_value = DEBUGGER_AUTO_OFFSET (XEXP (home, 0)); + } + else if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == CONST) + { + /* Handle an obscure case which can arise when optimizing and + when there are few available registers. (This is *always* + the case for i386/i486 targets). The RTL looks like + (MEM (CONST ...)) even though this variable is a local `auto' + or a local `register' variable. In effect, what has happened + is that the reload pass has seen that all assignments and + references for one such a local variable can be replaced by + equivalent assignments and references to some static storage + 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'. */ + current_sym_code = N_LCSYM; + letter = 'V'; + current_sym_addr = XEXP (XEXP (home, 0), 0); + } + else if (GET_CODE (home) == CONCAT) + { + tree subtype = TREE_TYPE (type); + + /* If the variable's storage is in two parts, + output each as a separate stab with a modified name. */ + if (WORDS_BIG_ENDIAN) + dbxout_symbol_location (decl, subtype, "$imag", XEXP (home, 0)); + else + dbxout_symbol_location (decl, subtype, "$real", XEXP (home, 0)); + + /* Cast avoids warning in old compilers. */ + current_sym_code = (STAB_CODE_TYPE) 0; + current_sym_value = 0; + current_sym_addr = 0; + dbxout_prepare_symbol (decl); + + if (WORDS_BIG_ENDIAN) + dbxout_symbol_location (decl, subtype, "$real", XEXP (home, 1)); + else + dbxout_symbol_location (decl, subtype, "$imag", XEXP (home, 1)); + return; + } + else + /* Address might be a MEM, when DECL is a variable-sized object. + Or it might be const0_rtx, meaning previous passes + want us to ignore this variable. */ + return; + + /* Ok, start a symtab entry and output the variable name. */ + FORCE_TEXT; + +#ifdef DBX_STATIC_BLOCK_START + DBX_STATIC_BLOCK_START (asmfile, current_sym_code); +#endif + + /* CYGNUS LOCAL LRS */ + if (!DECL_LIVE_RANGE_RTL (decl) || !LIVE_RANGE_GDBSTAB_P ()) + dbxout_symbol_name (decl, suffix, letter, FALSE); + else + dbxout_symbol_name (decl, suffix, letter, 1); + /* END CYGNUS LOCAL */ + + dbxout_type (type, 0, 0); + dbxout_finish_symbol (decl); + + /* CYGNUS LOCAL LRS */ + dbxout_live_range_alias (decl); + /* END CYGNUS LOCAL */ + +#ifdef DBX_STATIC_BLOCK_END + DBX_STATIC_BLOCK_END (asmfile, current_sym_code); +#endif +} + +/* Output the symbol name of DECL for a stabs, with suffix SUFFIX. + Then output LETTER to indicate the kind of location the symbol has. */ + +/* CYGNUS LOCAL LRS */ +static void +dbxout_symbol_name (decl, suffix, letter, live_range_p) + tree decl; + char *suffix; + int letter; + int live_range_p; +{ + /* One slight hitch: if this is a VAR_DECL which is a static + class 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. */ + char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + char range_prefix[20]; + if (name == 0) + name = "(anon)"; + if (live_range_p == 1) + { + sprintf (range_prefix, "#%d=", ++range_max_number); + } + else if (live_range_p == 2) + { + sprintf (range_prefix, "#%d", range_max_number); + name = ""; + } + else + range_prefix[0] = '\0'; + fprintf (asmfile, "%s \"%s%s%s:", ASM_STABS_OP, range_prefix, name, + (suffix ? suffix : "")); + + if (letter) putc (letter, asmfile); +} +/* END CYGNUS LOCAL */ + +static void +dbxout_prepare_symbol (decl) + tree decl; +{ +#ifdef WINNING_GDB + char *filename = DECL_SOURCE_FILE (decl); + + dbxout_source_file (asmfile, filename); +#endif +} + +static void +dbxout_finish_symbol (sym) + 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. */ + +void +dbxout_syms (syms) + tree syms; +{ + while (syms) + { + dbxout_symbol (syms, 1); + syms = TREE_CHAIN (syms); + } +} + +/* The following two functions output definitions of function parameters. + Each parameter gets a definition locating it in the parameter list. + Each parameter that is a register variable gets a second definition + locating it in the register. + + Printing or argument lists in gdb uses the definitions that + locate in the parameter list. But reference to the variable in + expressions uses preferentially the definition as a register. */ + +/* Output definitions, referring to storage in the parmlist, + of all the parms in PARMS, which is a chain of PARM_DECL nodes. */ + +void +dbxout_parms (parms) + tree parms; +{ + for (; parms; parms = TREE_CHAIN (parms)) + if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node) + { + /* CYGNUS LOCAL LRS */ + char range_prefix[20]; + /* END CYGNUS LOCAL */ + + dbxout_prepare_symbol (parms); + + /* Perform any necessary register eliminations on the parameter's rtl, + so that the debugging output will be accurate. */ + DECL_INCOMING_RTL (parms) + = eliminate_regs (DECL_INCOMING_RTL (parms), 0, NULL_RTX); + DECL_RTL (parms) = eliminate_regs (DECL_RTL (parms), 0, NULL_RTX); +#ifdef LEAF_REG_REMAP + if (leaf_function) + { + leaf_renumber_regs_insn (DECL_INCOMING_RTL (parms)); + leaf_renumber_regs_insn (DECL_RTL (parms)); + } +#endif + + /* CYGNUS LOCAL LRS */ + /* Handle case where parameter was passed in a reg and had its + range split. + + In theory, we should only need to handle the REG case below. + Adding others is simple, but let's avoid unnecessary CYGNUS LOCAL + code. */ + if (GET_CODE (DECL_RTL (parms)) == REG + && DECL_LIVE_RANGE_RTL (parms) && LIVE_RANGE_GDBSTAB_P ()) + sprintf (range_prefix, "#%d=", ++range_max_number); + else + range_prefix[0] = '\0'; + /* END CYGNUS LOCAL */ + + if (PARM_PASSED_IN_MEMORY (parms)) + { + 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 (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 + { + 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, 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 erropneous value. */ + dbxout_type (DECL_ARG_TYPE (parms), 0, 0); + current_sym_value = DEBUGGER_ARG_OFFSET (current_sym_value, addr); + dbxout_finish_symbol (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. */ + + 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)) >= 0 + && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER) + { + 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); + parm_type = TREE_TYPE (parms); + } + current_sym_value = DBX_REGISTER_NUMBER (REGNO (best_rtl)); + + FORCE_TEXT; + /* CYGNUS LOCAL LRS */ + if (DECL_NAME (parms)) + { + current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (parms)); + fprintf (asmfile, "%s \"%s%s:%c", ASM_STABS_OP, + range_prefix, + IDENTIFIER_POINTER (DECL_NAME (parms)), + regparm_letter); + } + else + { + current_sym_nchars = 8; + fprintf (asmfile, "%s \"%s(anon):%c", ASM_STABS_OP, + range_prefix, regparm_letter); + } + /* END CYGNUS LOCAL */ + + dbxout_type (parm_type, 0, 0); + dbxout_finish_symbol (parms); + } + 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 + && REGNO (XEXP (DECL_RTL (parms), 0)) != ARG_POINTER_REGNUM +#endif + ) + { + /* Parm was passed via invisible reference. + That is, its address was passed in a register. + Output it as if it lived in that register. + The debugger will know from the type + that it was actually passed by invisible reference. */ + + 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. */ + if (REGNO (XEXP (DECL_RTL (parms), 0)) >= 0 + && REGNO (XEXP (DECL_RTL (parms), 0)) < FIRST_PSEUDO_REGISTER) + 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 + { + current_sym_nchars = 8; + fprintf (asmfile, "%s \"(anon):%c", ASM_STABS_OP, + regparm_letter); + } + + dbxout_type (TREE_TYPE (parms), 0, 0); + dbxout_finish_symbol (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. + Should make this not happen, after 2.4. */ + && ! CONSTANT_P (XEXP (DECL_RTL (parms), 0))) + { + /* Parm was passed in registers but lives on the stack. */ + + 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 ...)) or (MEM (MEM ...)), + in which case we use a value of zero. */ + if (GET_CODE (XEXP (DECL_RTL (parms), 0)) == REG + || GET_CODE (XEXP (DECL_RTL (parms), 0)) == MEM) + current_sym_value = 0; + else + 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) + { + current_sym_value += UNITS_PER_WORD - GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (parms))); + } + + 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, 0); + dbxout_finish_symbol (parms); + } + } +} + +/* Output definitions for the places where parms live during the function, + when different from where they were passed, when the parms were passed + in memory. + + It is not useful to do this for parms passed in registers + that live during the function in different registers, because it is + impossible to look in the passed register for the passed value, + so we use the within-the-function register to begin with. + + PARMS is a chain of PARM_DECL nodes. */ + +void +dbxout_reg_parms (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 (GET_CODE (DECL_RTL (parms)) == REG + && REGNO (DECL_RTL (parms)) >= 0 + && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER) + dbxout_symbol_location (parms, TREE_TYPE (parms), + 0, DECL_RTL (parms)); + else if (GET_CODE (DECL_RTL (parms)) == CONCAT) + 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 (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)); + } +} + +/* Given a chain of ..._TYPE nodes (as come in a parameter list), + output definitions of those names, in raw form */ + +void +dbxout_args (args) + tree args; +{ + while (args) + { + putc (',', asmfile); + dbxout_type (TREE_VALUE (args), 0, 0); + CHARS (1); + args = TREE_CHAIN (args); + } +} + +/* Given a chain of ..._TYPE nodes, + find those which have typedef names and output those names. + This is to ensure those types get output. */ + +void +dbxout_types (types) + register tree types; +{ + while (types) + { + if (TYPE_NAME (types) + && TREE_CODE (TYPE_NAME (types)) == TYPE_DECL + && ! TREE_ASM_WRITTEN (TYPE_NAME (types))) + dbxout_symbol (TYPE_NAME (types), 1); + types = TREE_CHAIN (types); + } +} + +/* Output everything about a symbol block (a BLOCK node + that represents a scope level), + including recursive output of contained blocks. + + BLOCK is the BLOCK node. + DEPTH is its depth within containing symbol blocks. + ARGS is usually zero; but for the outermost block of the + body of a function, it is a chain of PARM_DECLs for the function parameters. + We output definitions of all the register parms + as if they were local variables of that block. + + If -g1 was used, we count blocks just the same, but output nothing + except for the outermost block. + + Actually, BLOCK may be several blocks chained together. + We handle them all in sequence. */ + +static void +dbxout_block (block, depth, args) + register tree block; + int depth; + tree args; +{ + int blocknum; + + while (block) + { + /* Ignore blocks never expanded or otherwise marked as real. */ + if (TREE_USED (block)) + { +#ifndef DBX_LBRAC_FIRST + /* In dbx format, the syms of a block come before the N_LBRAC. */ + if (debug_info_level != DINFO_LEVEL_TERSE || depth == 0) + dbxout_syms (BLOCK_VARS (block)); + if (args) + dbxout_reg_parms (args); +#endif + + /* Now output an N_LBRAC symbol to represent the beginning of + the block. Use the block's tree-walk order to generate + the assembler symbols LBBn and LBEn + that final will define around the code in this block. */ + if (depth > 0 && debug_info_level != DINFO_LEVEL_TERSE) + { + char buf[20]; + blocknum = next_block_number++; + ASM_GENERATE_INTERNAL_LABEL (buf, "LBB", blocknum); + + if (BLOCK_HANDLER_BLOCK (block)) + { + /* A catch block. Must precede N_LBRAC. */ + tree decl = BLOCK_VARS (block); + while (decl) + { +#ifdef DBX_OUTPUT_CATCH + DBX_OUTPUT_CATCH (asmfile, decl, buf); +#else + fprintf (asmfile, "%s \"%s:C1\",%d,0,0,", ASM_STABS_OP, + IDENTIFIER_POINTER (DECL_NAME (decl)), N_CATCH); + assemble_name (asmfile, buf); + fprintf (asmfile, "\n"); +#endif + decl = TREE_CHAIN (decl); + } + } + +#ifdef DBX_OUTPUT_LBRAC + DBX_OUTPUT_LBRAC (asmfile, buf); +#else + fprintf (asmfile, "%s %d,0,0,", ASM_STABN_OP, N_LBRAC); + assemble_name (asmfile, buf); +#if DBX_BLOCKS_FUNCTION_RELATIVE + fputc ('-', asmfile); + assemble_name (asmfile, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0)); +#endif + fprintf (asmfile, "\n"); +#endif + } + else if (depth > 0) + /* Count blocks the same way regardless of debug_info_level. */ + next_block_number++; + +#ifdef DBX_LBRAC_FIRST + /* On some weird machines, the syms of a block + come after the N_LBRAC. */ + if (debug_info_level != DINFO_LEVEL_TERSE || depth == 0) + dbxout_syms (BLOCK_VARS (block)); + if (args) + dbxout_reg_parms (args); +#endif + + /* Output the subblocks. */ + dbxout_block (BLOCK_SUBBLOCKS (block), depth + 1, NULL_TREE); + + /* Refer to the marker for the end of the block. */ + if (depth > 0 && debug_info_level != DINFO_LEVEL_TERSE) + { + char buf[20]; + ASM_GENERATE_INTERNAL_LABEL (buf, "LBE", blocknum); +#ifdef DBX_OUTPUT_RBRAC + DBX_OUTPUT_RBRAC (asmfile, buf); +#else + fprintf (asmfile, "%s %d,0,0,", ASM_STABN_OP, N_RBRAC); + assemble_name (asmfile, buf); +#if DBX_BLOCKS_FUNCTION_RELATIVE + fputc ('-', asmfile); + assemble_name (asmfile, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0)); +#endif + fprintf (asmfile, "\n"); +#endif + } + } + block = BLOCK_CHAIN (block); + } +} + +/* Output the information about a function and its arguments and result. + Usually this follows the function's code, + but on some systems, it comes before. */ + +static void +dbxout_really_begin_function (decl) + tree decl; +{ + /* CYGNUS LOCAL LRS */ + range_max_number_for_parms = range_max_number; + /* END CYGNUS LOCAL */ + dbxout_symbol (decl, 0); + dbxout_parms (DECL_ARGUMENTS (decl)); + if (DECL_NAME (DECL_RESULT (decl)) != 0) + dbxout_symbol (DECL_RESULT (decl), 1); +} + +/* Called at beginning of output of function definition. */ + +void +dbxout_begin_function (decl) + tree decl; +{ +#ifdef DBX_FUNCTION_FIRST + dbxout_really_begin_function (decl); +#endif +} + +/* Output dbx data for a function definition. + This includes a definition of the function name itself (a symbol), + definitions of the parameters (locating them in the parameter list) + and then output the block that makes up the function's body + (including all the auto variables of the function). */ + +void +dbxout_function (decl) + tree decl; +{ +#ifndef DBX_FUNCTION_FIRST + dbxout_really_begin_function (decl); +#endif + dbxout_block (DECL_INITIAL (decl), 0, DECL_ARGUMENTS (decl)); + /* CYGNUS LOCAL LRS */ + dbxout_live_range_parms (DECL_ARGUMENTS (decl), range_max_number_for_parms); + /* END CYGNUS LOCAL */ +#ifdef DBX_OUTPUT_FUNCTION_END + DBX_OUTPUT_FUNCTION_END (asmfile, decl); +#endif +#if defined(ASM_OUTPUT_SECTION_NAME) + if (use_gnu_debug_info_extensions +#if defined(NO_DBX_FUNCTION_END) + && ! NO_DBX_FUNCTION_END +#endif + ) + dbxout_function_end (); +#endif +} + +/* CYGNUS LOCAL LRS */ +/* Output live ranges for parameter aliases. This must happen after + the body of the function has been output since the stabs may + reference things defined within the function itself. */ +static void +dbxout_live_range_parms (parms, range_max_number_for_parms) + tree parms; + int range_max_number_for_parms; +{ + int save_range_max_number = range_max_number; + + range_max_number = range_max_number_for_parms; + for (; parms; parms = TREE_CHAIN (parms)) + if (GET_CODE (DECL_RTL (parms)) == REG + && DECL_LIVE_RANGE_RTL (parms) && LIVE_RANGE_GDBSTAB_P ()) + { + range_max_number++; + dbxout_live_range_alias (parms); + } + + range_max_number = save_range_max_number; +} + +/* Output an "alias" symbol for DECL if DECL's live range was split. */ +static void +dbxout_live_range_alias (decl) + tree decl; +{ + /* Was the symbol broken into different distinct ranges? If so, + output LRS debugging information. */ + if (DECL_LIVE_RANGE_RTL (decl) && LIVE_RANGE_GDBSTAB_P ()) + { + rtx rv = DECL_LIVE_RANGE_RTL (decl); + rtx r; + + /* Go through each of the ranges now and emit the registers now + occupied. */ + for (r = RANGE_VAR_LIST (rv); r != NULL_RTX ; r = XEXP (r, 1)) + { + rtx rinfo = XEXP (r, 0); + int i, regno; + int letter; + tree type = TREE_TYPE (decl); + + /* Find the variable amongs the range registers. */ + for (i = RANGE_INFO_NUM_REGS (rinfo)-1; i >= 0; i--) + if (RANGE_REG_SYMBOL_NODE (rinfo, i) == decl) + break; + + /* If the variable did not get a register in this range, and + we reverted it back to the original variable, just skip it. */ + if (i < 0) + continue; + + regno = RANGE_REG_COPY (rinfo, i); + if (reg_renumber[regno] >= 0) /* found a register */ + { + letter = 'r'; + current_sym_code = N_RSYM; + current_sym_value = DBX_REGISTER_NUMBER (reg_renumber[regno]); + } + else /* must be on the stack */ + { + rtx stack = regno_reg_rtx[regno]; + + letter = '\0'; + if (GET_CODE (stack) == MEM + && GET_CODE (XEXP (stack, 0)) == REG) + { + current_sym_code = N_LSYM; + current_sym_value = DEBUGGER_AUTO_OFFSET (XEXP (stack, 0)); + } + else if (GET_CODE (stack) == MEM + && GET_CODE (XEXP (stack, 0)) == PLUS + && GET_CODE (XEXP (XEXP (stack, 0), 1)) == CONST_INT) + { + current_sym_code = N_LSYM; + /* RTL looks like (MEM (PLUS (REG...) (CONST_INT...))) + We want the value of that CONST_INT. */ + current_sym_value = DEBUGGER_AUTO_OFFSET (XEXP (stack, 0)); + } + else if (GET_CODE (stack) == MEM + && GET_CODE (XEXP (stack, 0)) == CONST) + { + /* Handle an obscure case which can arise when optimizing and + when there are few available registers. (This is *always* + the case for i386/i486 targets). The RTL looks like (MEM + (CONST ...)) even though this variable is a local `auto' + or a local `register' variable. In effect, what has + happened is that the reload pass has seen that all + assignments and references for one such a local variable + can be replaced by equivalent assignments and references + to some static storage 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'. */ + current_sym_code = N_LCSYM; + letter = 'V'; + current_sym_addr = XEXP (XEXP (stack, 0), 0); + } + else + continue; + } + + dbxout_symbol_name (decl, 0, letter, 2); + dbxout_type (type, 0, 0); + + fprintf (asmfile, ";l(#%d,#%d)", + RANGE_INFO_MARKER_START (rinfo), + RANGE_INFO_MARKER_END (rinfo)); + dbxout_finish_symbol (NULL_TREE); + } + } +} + +/* Output information to mark the beginning or end of a live range. */ +void +dbxout_live_range (number) + int number; +{ + char label[256]; + + ASM_OUTPUT_INTERNAL_LABEL (asmfile, "LR", range_current); + ASM_GENERATE_INTERNAL_LABEL (label, "LR", range_current); + fprintf (asmfile, "%s \"#%d=\",%d,0,0,", ASM_STABS_OP, number, N_SLINE); + assemble_name (asmfile, label); + +#if DBX_BLOCKS_FUNCTION_RELATIVE + putc ('-', asmfile); + assemble_name (asmfile, + XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0)); +#endif + + putc ('\n', asmfile); + range_current++; + + if (number > range_max_number) + range_max_number = number; +} +/* END CYGNUS LOCAL -- meissner/live range */ +#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */ diff --git a/gcc_arm/dbxout.h b/gcc_arm/dbxout.h new file mode 100755 index 0000000..1e45fa6 --- /dev/null +++ b/gcc_arm/dbxout.h @@ -0,0 +1,33 @@ +/* dbxout.h - Various declarations for functions found in dbxout.c + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +extern void dbxout_init PROTO ((FILE *, char *, tree)); +extern void dbxout_finish PROTO ((FILE *, char *)); + +extern void dbxout_start_new_source_file PROTO ((char *)); +extern void dbxout_resume_previous_source_file PROTO ((void)); + +extern void dbxout_symbol PROTO ((tree, int)); +extern void dbxout_parms PROTO ((tree)); +extern void dbxout_reg_parms PROTO ((tree)); +extern void dbxout_syms PROTO ((tree)); +extern void dbxout_function PROTO ((tree)); +extern void dbxout_source_line PROTO ((FILE *, char*, int)); +extern void dbxout_begin_function PROTO ((tree)); diff --git a/gcc_arm/dbxstclass.h b/gcc_arm/dbxstclass.h new file mode 100755 index 0000000..2d003fe --- /dev/null +++ b/gcc_arm/dbxstclass.h @@ -0,0 +1,17 @@ +/* Storage classes in XCOFF object file format designed for DBX's use. + This info is from the `Files Reference' manual for IBM's AIX version 3 + for the RS6000. */ + +#define C_GSYM 0x80 +#define C_LSYM 0x81 +#define C_PSYM 0x82 +#define C_RSYM 0x83 +#define C_RPSYM 0x84 +#define C_STSYM 0x85 + +#define C_BCOMM 0x87 +#define C_ECOML 0x88 +#define C_ECOMM 0x89 +#define C_DECL 0x8c +#define C_ENTRY 0x8d +#define C_FUN 0x8e diff --git a/gcc_arm/defaults.h b/gcc_arm/defaults.h new file mode 100755 index 0000000..0fbf2b9 --- /dev/null +++ b/gcc_arm/defaults.h @@ -0,0 +1,140 @@ +/* Definitions of various defaults for how to do assembler output + (most of which are designed to be appropriate for GAS or for + some BSD assembler). + Copyright (C) 1992, 1996, 1997, 1998 Free Software Foundation, Inc. + Contributed by Ron Guilmette (rfg@monkeys.com) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable or function named NAME. + LABELNO is an integer which is different for each call. */ + +#ifndef ASM_FORMAT_PRIVATE_NAME +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ + do { \ + int len = strlen (NAME); \ + char *temp = (char *) alloca (len + 3); \ + temp[0] = 'L'; \ + strcpy (&temp[1], (NAME)); \ + temp[len + 1] = '.'; \ + temp[len + 2] = 0; \ + (OUTPUT) = (char *) alloca (strlen (NAME) + 11); \ + ASM_GENERATE_INTERNAL_LABEL (OUTPUT, temp, LABELNO); \ + } while (0) +#endif + +#ifndef ASM_STABD_OP +#define ASM_STABD_OP ".stabd" +#endif + +/* This is how to output an element of a case-vector that is absolute. + Some targets don't use this, but we have to define it anyway. */ + +#ifndef ASM_OUTPUT_ADDR_VEC_ELT +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ +do { fprintf (FILE, "\t%s\t", ASM_LONG); \ + ASM_OUTPUT_INTERNAL_LABEL (FILE, "L", (VALUE)); \ + fputc ('\n', FILE); \ + } while (0) +#endif + +/* choose a reasonable default for ASM_OUTPUT_ASCII. */ + +#ifndef ASM_OUTPUT_ASCII +#define ASM_OUTPUT_ASCII(MYFILE, MYSTRING, MYLENGTH) \ + do { \ + FILE *_hide_asm_out_file = (MYFILE); \ + unsigned char *_hide_p = (unsigned char *) (MYSTRING); \ + int _hide_thissize = (MYLENGTH); \ + { \ + FILE *asm_out_file = _hide_asm_out_file; \ + unsigned char *p = _hide_p; \ + int thissize = _hide_thissize; \ + int i; \ + fprintf (asm_out_file, "\t.ascii \""); \ + \ + for (i = 0; i < thissize; i++) \ + { \ + register int c = p[i]; \ + if (c == '\"' || c == '\\') \ + putc ('\\', asm_out_file); \ + if (c >= ' ' && c < 0177) \ + putc (c, asm_out_file); \ + else \ + { \ + fprintf (asm_out_file, "\\%o", c); \ + /* After an octal-escape, if a digit follows, \ + terminate one string constant and start another. \ + The Vax assembler fails to stop reading the escape \ + after three digits, so this is the only way we \ + can get it to parse the data properly. */ \ + if (i < thissize - 1 \ + && p[i + 1] >= '0' && p[i + 1] <= '9') \ + fprintf (asm_out_file, "\"\n\t.ascii \""); \ + } \ + } \ + fprintf (asm_out_file, "\"\n"); \ + } \ + } \ + while (0) +#endif + +#ifndef ASM_IDENTIFY_GCC + /* Default the definition, only if ASM_IDENTIFY_GCC is not set, + because if it is set, we might not want ASM_IDENTIFY_LANGUAGE + outputting labels, if we do want it to, then it must be defined + in the tm.h file. */ +#ifndef ASM_IDENTIFY_LANGUAGE +#define ASM_IDENTIFY_LANGUAGE(FILE) output_lang_identify (FILE); +#endif +#endif + +/* This is how we tell the assembler to equate two values. */ +#ifdef SET_ASM_OP +#ifndef ASM_OUTPUT_DEF +#define ASM_OUTPUT_DEF(FILE,LABEL1,LABEL2) \ + do { fprintf ((FILE), "\t%s\t", SET_ASM_OP); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, ","); \ + assemble_name (FILE, LABEL2); \ + fprintf (FILE, "\n"); \ + } while (0) +#endif +#endif + +/* This is how to output a reference to a user-level label named NAME. */ + +#ifndef ASM_OUTPUT_LABELREF +#define ASM_OUTPUT_LABELREF(FILE,NAME) asm_fprintf ((FILE), "%U%s", (NAME)) +#endif + +/* This determines whether or not we support weak symbols. */ +#ifndef SUPPORTS_WEAK +#ifdef ASM_WEAKEN_LABEL +#define SUPPORTS_WEAK 1 +#else +#define SUPPORTS_WEAK 0 +#endif +#endif + +/* If we have a definition of INCOMING_RETURN_ADDR_RTX, assume that + the rest of the DWARF 2 frame unwind support is also provided. */ +#if !defined (DWARF2_UNWIND_INFO) && defined (INCOMING_RETURN_ADDR_RTX) +#define DWARF2_UNWIND_INFO 1 +#endif diff --git a/gcc_arm/doprint.c b/gcc_arm/doprint.c new file mode 100755 index 0000000..2dc4dde --- /dev/null +++ b/gcc_arm/doprint.c @@ -0,0 +1,295 @@ +/* Provide a version _doprnt in terms of fprintf. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Kaveh Ghazi (ghazi@caip.rutgers.edu) 3/29/98 + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + */ + +#include "config.h" +#include "system.h" +#undef _doprnt + +#ifdef TEST /* Make sure to use the internal one. */ +#define _doprnt my_doprnt +#endif + +#define COPY_VA_INT \ + do { \ + const int value = abs (va_arg (ap, int)); \ + char buf[32]; \ + ptr++; /* Go past the asterisk. */ \ + *sptr = '\0'; /* NULL terminate sptr. */ \ + sprintf(buf, "%d", value); \ + strcat(sptr, buf); \ + while (*sptr) sptr++; \ + } while (0) + +#define PRINT_CHAR(CHAR) \ + do { \ + putc(CHAR, stream); \ + ptr++; \ + total_printed++; \ + continue; \ + } while (0) + +#define PRINT_TYPE(TYPE) \ + do { \ + int result; \ + TYPE value = va_arg (ap, TYPE); \ + *sptr++ = *ptr++; /* Copy the type specifier. */ \ + *sptr = '\0'; /* NULL terminate sptr. */ \ + result = fprintf(stream, specifier, value); \ + if (result == -1) \ + return -1; \ + else \ + { \ + total_printed += result; \ + continue; \ + } \ + } while (0) + +int +_doprnt (format, ap, stream) + const char * format; + va_list ap; + FILE * stream; +{ + const char * ptr = format; + char specifier[128]; + int total_printed = 0; + + while (*ptr != '\0') + { + if (*ptr != '%') /* While we have regular characters, print them. */ + PRINT_CHAR(*ptr); + else /* We got a format specifier! */ + { + char * sptr = specifier; + int wide_width = 0, short_width = 0; + + *sptr++ = *ptr++; /* Copy the % and move forward. */ + + while (strchr ("-+ #0", *ptr)) /* Move past flags. */ + *sptr++ = *ptr++; + + if (*ptr == '*') + COPY_VA_INT; + else + while (isdigit(*ptr)) /* Handle explicit numeric value. */ + *sptr++ = *ptr++; + + if (*ptr == '.') + { + *sptr++ = *ptr++; /* Copy and go past the period. */ + if (*ptr == '*') + COPY_VA_INT; + else + while (isdigit(*ptr)) /* Handle explicit numeric value. */ + *sptr++ = *ptr++; + } + while (strchr ("hlL", *ptr)) + { + switch (*ptr) + { + case 'h': + short_width = 1; + break; + case 'l': + wide_width++; + break; + case 'L': + wide_width = 2; + break; + default: + abort(); + } + *sptr++ = *ptr++; + } + + switch (*ptr) + { + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + case 'c': + { + /* Short values are promoted to int, so just copy it + as an int and trust the C library printf to cast it + to the right width. */ + if (short_width) + PRINT_TYPE(int); + else + { + switch (wide_width) + { + case 0: + PRINT_TYPE(int); + break; + case 1: + PRINT_TYPE(long); + break; + case 2: + default: +#if defined(__GNUC__) || defined(HAVE_LONG_LONG) + PRINT_TYPE(long long); +#else + PRINT_TYPE(long); /* Fake it and hope for the best. */ +#endif + break; + } /* End of switch (wide_width) */ + } /* End of else statement */ + } /* End of integer case */ + break; + case 'f': + case 'e': + case 'E': + case 'g': + case 'G': + { + if (wide_width == 0) + PRINT_TYPE(double); + else + { +#if defined(__GNUC__) || defined(HAVE_LONG_DOUBLE) + PRINT_TYPE(long double); +#else + PRINT_TYPE(double); /* Fake it and hope for the best. */ +#endif + } + } + break; + case 's': + PRINT_TYPE(char *); + break; + case 'p': + PRINT_TYPE(void *); + break; + case '%': + PRINT_CHAR('%'); + break; + default: + abort(); + } /* End of switch (*ptr) */ + } /* End of else statement */ + } + + return total_printed; +} + +#ifdef TEST + +#include +#ifndef M_PI +#define M_PI (3.1415926535897932385) +#endif + +#define RESULT(x) do \ +{ \ + int i = (x); \ + printf ("printed %d characters\n", i); \ + fflush(stdin); \ +} while (0) + +static int checkit PVPROTO ((const char * format, ...)) ATTRIBUTE_PRINTF_1; + +static int +checkit VPROTO ((const char* format, ...)) +{ + va_list args; + int result; + +#ifndef ANSI_PROTOTYPES + char *format; +#endif + + VA_START (args, format); + +#ifndef ANSI_PROTOTYPES + format = va_arg (args, char *); +#endif + + result = _doprnt (format, args, stdout); + va_end(args); + + return result; +} + +int +main () +{ + RESULT(checkit ("<%d>\n", 0x12345678)); + RESULT(printf ("<%d>\n", 0x12345678)); + + RESULT(checkit ("<%200d>\n", 5)); + RESULT(printf ("<%200d>\n", 5)); + + RESULT(checkit ("<%.300d>\n", 6)); + RESULT(printf ("<%.300d>\n", 6)); + + RESULT(checkit ("<%100.150d>\n", 7)); + RESULT(printf ("<%100.150d>\n", 7)); + + RESULT(checkit ("<%s>\n", + "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ +777777777777777777333333333333366666666666622222222222777777777777733333")); + RESULT(printf ("<%s>\n", + "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ +777777777777777777333333333333366666666666622222222222777777777777733333")); + + RESULT(checkit ("<%f><%0+#f>%s%d%s>\n", + 1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx")); + RESULT(printf ("<%f><%0+#f>%s%d%s>\n", + 1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx")); + + RESULT(checkit ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI)); + RESULT(printf ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI)); + + RESULT(checkit ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI)); + RESULT(printf ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI)); + + RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n", + 75, 75, 75, 75, 75, 75, 75)); + RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n", + 75, 75, 75, 75, 75, 75, 75)); + + RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n", + 75, 75, 75, 75, 75, 75, 75)); + RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n", + 75, 75, 75, 75, 75, 75, 75)); + + RESULT(checkit ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456)); + RESULT(printf ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456)); + +#if defined(__GNUC__) || defined (HAVE_LONG_LONG) + RESULT(checkit ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345)); + RESULT(printf ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345)); + RESULT(checkit ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345)); + RESULT(printf ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345)); +#endif + +#if defined(__GNUC__) || defined (HAVE_LONG_DOUBLE) + RESULT(checkit ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n", + 1.23456, 1.234567890123456789L, 1.23456)); + RESULT(printf ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n", + 1.23456, 1.234567890123456789L, 1.23456)); +#endif + + return 0; +} +#endif /* TEST */ diff --git a/gcc_arm/doschk.c b/gcc_arm/doschk.c new file mode 100755 index 0000000..ad553df --- /dev/null +++ b/gcc_arm/doschk.c @@ -0,0 +1,360 @@ +/* +** DosFCheck - check file names for DOS consistency +** +** Distribute freely, it only encourages DOS compatibility! +** - DJ Delorie +*/ + +/* This file is not part of GCC. */ + +#include +#ifdef __MSDOS__ +#include +#else +#include +#endif +#include +#include + +typedef struct ENT +{ + struct ENT *next; + char *dos_name; + char *full_name; + char *path; + int tagged; +} ENT; + +ENT *eroot = 0; + +int first_inv = 1; +int first_msg = 1; + +/****************************************************************\ + * Utility routines * +\****************************************************************/ + +void +invalid_msg () +{ + if (first_inv) + { + if (first_msg) + first_msg = 0; + else + putchar ('\n'); + printf ("The following files are not valid DOS file names:\n"); + first_inv = 0; + } +} + +ENT * +alloc_ent () +{ + ENT *rv = (ENT *)malloc (sizeof (ENT)); + if (rv == 0) + { + fprintf (stderr, "Unable to allocate memory for an ENT\n"); + exit (1); + } + memset (rv, 0, sizeof (ENT)); + return rv; +} + +void +fill_ent (ent, path) +ENT *ent; +char *path; +{ + char *first = path; + char *null = path+strlen (path); + char *last_slash = strrchr (path, '/'); + char *cp, *dp; + int dots_seen, chars_seen; + + if (last_slash+1 == null) + { + * --null = '\0'; + last_slash = strrchr (path, '/'); + } + + if (!last_slash) + { + last_slash = first-1; + } + + if (null-last_slash < 13) + ent->dos_name = (char *)malloc (null-last_slash); + else + ent->dos_name = (char *)malloc (13); + ent->full_name = (char *)malloc (null-last_slash); + ent->path = (char *)malloc (last_slash-first+1); + + strcpy (ent->full_name, last_slash+1); + if (last_slash > first) + { + strncpy (ent->path, first, last_slash-first); + ent->path[last_slash-first] = '\0'; + } + else + *ent->path = '\0'; + + cp = last_slash+1; + dp = ent->dos_name; + dots_seen = 0; + chars_seen = 0; + while (1) + { + if (! *cp) + break; + switch (*cp) + { + case '.': + if (cp == last_slash+1 && strcmp (last_slash+1, ".")) + { + invalid_msg (); + printf ("%s - file name cannot start with dot\n", path); + *dp = 0; + break; + } + if (dots_seen == 1) + { + invalid_msg (); + printf ("%s - too many dots\n", path); + *dp = '\0'; + break; + } + *dp++ = '.'; + chars_seen = 0; + dots_seen++; + break; + case '"': + case '*': + case '+': + case ',': + case ';': + case '<': + case '=': + case '>': + case '?': + case '[': + case '\\': + case ']': + case '|': + invalid_msg (); + printf ("%s - invalid character `%c'\n", path, *cp); + *dp++ = '?'; + chars_seen++; + break; + default: + if (dots_seen) + { + if (chars_seen >= 3) + break; + } + else + if (chars_seen >= 8) + break; + if ((*cp <= ' ') || (*cp >= 0x7f)) + { + invalid_msg (); + printf ("%s - invalid character `%c'\n", path, *cp); + *dp++ = '?'; + chars_seen++; + break; + } + if (islower (*cp)) + *dp++ = toupper (*cp); + else + *dp++ = *cp; + chars_seen++; + break; + } + cp++; + } + *dp++ = '\0'; +} + +int +compare_ent_dosname (e1, e2) +ENT **e1; +ENT **e2; +{ + int r = strcmp ((*e1)->dos_name, (*e2)->dos_name); + if (r == 0) + r = strcmp ((*e1)->path, (*e2)->path); + if (r == 0) + r = strcmp ((*e1)->full_name, (*e2)->full_name); + return r; +} + +int +compare_ent_fullname (e1, e2) +ENT **e1; +ENT **e2; +{ + int r = strncmp ((*e1)->full_name, (*e2)->full_name, 14); + if (r == 0) + r = strcmp ((*e1)->path, (*e2)->path); + if (r == 0) + r = strcmp ((*e1)->full_name, (*e2)->full_name); + return r; +} + +char * +mpath (ent) +ENT *ent; +{ + static char buf[500]; + if (ent->path && ent->path[0]) + sprintf (buf, "%s/%s", ent->path, ent->full_name); + else + return ent->full_name; + return buf; +} + +/****************************************************************\ + * List handling routines * +\****************************************************************/ + +void +add_ent (ent) +ENT *ent; +{ + ent->next = eroot; + eroot = ent; +} + +void +handle_input (line) +char *line; +{ + ENT *ent = alloc_ent (); + fill_ent (ent, line); + add_ent (ent); +} + +void +display_problems () +{ + ENT **elist, *ent; + int ecount, i, first, first_err; + + for (ecount=0, ent=eroot; ent; ent=ent->next, ecount++); + elist = (ENT **)malloc (sizeof (ENT *) * ecount); + for (ecount=0, ent=eroot; ent; ent=ent->next, ecount++) + elist[ecount] = ent; + + qsort (elist, ecount, sizeof (ENT *), compare_ent_dosname); + + first = 1; + first_err = 1; + for (i=0; idos_name, elist[i+1]->dos_name) == 0) + && (strcmp (elist[i]->path, elist[i+1]->path) == 0)) + { + if (first_err) + { + if (first_msg) + first_msg = 0; + else + putchar ('\n'); + printf ("The following resolve to the same DOS file names:\n"); + first_err = 0; + } + if (first) + { + printf ("%14s : %s\n", elist[i]->dos_name, mpath (elist[i])); + first = 0; + } + printf ("\t\t %s\n", mpath (elist[i+1])); + } + else + first = 1; + } + + qsort (elist, ecount, sizeof (ENT *), compare_ent_fullname); + + first = 1; + first_err = 1; + for (i=0; ifull_name, elist[i+1]->full_name, 14) == 0) + && (strcmp (elist[i]->path, elist[i+1]->path) == 0)) + { + if (first_err) + { + if (first_msg) + first_msg = 0; + else + putchar ('\n'); + printf ("The following resolve to the same SysV file names:\n"); + first_err = 0; + } + if (first) + { + printf ("%.14s : %s\n", elist[i]->full_name, mpath (elist[i])); + first = 0; + elist[i]->tagged = 1; + } + printf ("\t\t %s\n", mpath (elist[i+1])); + elist[i+1]->tagged = 1; + } + else + first = 1; + } + + first_err = 1; + for (i=0; ifull_name) > 14) && !elist[i]->tagged) + { + if (first_err) + { + if (first_msg) + first_msg = 0; + else + putchar ('\n'); + printf ("The following file names are too long for SysV:\n"); + first_err = 0; + } + printf ("%.14s : %s\n", elist[i]->full_name, mpath (elist[i])); + } + } +} + +/****************************************************************\ + * Main entry point * +\****************************************************************/ + +main (argc, argv) +int argc; +char **argv; +{ + FILE *input = stdin; + if (argc > 1) + { + input = fopen (argv[1], "r"); + if (!input) + { + perror (argv[1]); + exit (1); + } + } + while (1) + { + char line[500]; + char *lp; + fgets (line, 500, input); + if (feof (input)) + break; + lp = line+strlen (line); + while ((lp != line) && (*lp <= ' ')) + lp--; + lp[1] = 0; + handle_input (line); + } + display_problems (); +} + diff --git a/gcc_arm/dostage2 b/gcc_arm/dostage2 new file mode 100755 index 0000000..bb33f7d --- /dev/null +++ b/gcc_arm/dostage2 @@ -0,0 +1,2 @@ +#!/bin/sh +make -k LANGUAGES=c $1 CC=stage1/xgcc XCFLAGS=-Bstage1/ CFLAGS="-g $2" >log2 2>&1 diff --git a/gcc_arm/dostage3 b/gcc_arm/dostage3 new file mode 100755 index 0000000..21f17fc --- /dev/null +++ b/gcc_arm/dostage3 @@ -0,0 +1,3 @@ +#!/bin/sh +make -k LANGUAGES=c $1 CC=stage2/xgcc XCFLAGS=-Bstage2/ CFLAGS="-g $2" >log3 2>&1 + diff --git a/gcc_arm/dwarf.h b/gcc_arm/dwarf.h new file mode 100755 index 0000000..6aca017 --- /dev/null +++ b/gcc_arm/dwarf.h @@ -0,0 +1,315 @@ +/* Declarations and definitions of codes relating to the DWARF symbolic + debugging information format. + + Written by Ron Guilmette (rfg@netcom.com) + +Copyright (C) 1992 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* This file is derived from the DWARF specification (a public document) + Revision 1.0.1 (April 8, 1992) developed by the UNIX International + Programming Languages Special Interest Group (UI/PLSIG) and distributed + by UNIX International. Copies of this specification are available from + UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054. +*/ + +/* Tag names and codes. */ + +enum dwarf_tag { + TAG_padding = 0x0000, + TAG_array_type = 0x0001, + TAG_class_type = 0x0002, + TAG_entry_point = 0x0003, + TAG_enumeration_type = 0x0004, + TAG_formal_parameter = 0x0005, + TAG_global_subroutine = 0x0006, + TAG_global_variable = 0x0007, + /* 0x0008 -- reserved */ + /* 0x0009 -- reserved */ + TAG_label = 0x000a, + TAG_lexical_block = 0x000b, + TAG_local_variable = 0x000c, + TAG_member = 0x000d, + /* 0x000e -- reserved */ + TAG_pointer_type = 0x000f, + TAG_reference_type = 0x0010, + TAG_compile_unit = 0x0011, + TAG_string_type = 0x0012, + TAG_structure_type = 0x0013, + TAG_subroutine = 0x0014, + TAG_subroutine_type = 0x0015, + TAG_typedef = 0x0016, + TAG_union_type = 0x0017, + TAG_unspecified_parameters = 0x0018, + TAG_variant = 0x0019, + TAG_common_block = 0x001a, + TAG_common_inclusion = 0x001b, + TAG_inheritance = 0x001c, + TAG_inlined_subroutine = 0x001d, + TAG_module = 0x001e, + TAG_ptr_to_member_type = 0x001f, + TAG_set_type = 0x0020, + TAG_subrange_type = 0x0021, + TAG_with_stmt = 0x0022, + + /* GNU extensions */ + + TAG_format_label = 0x8000, /* for FORTRAN 77 and Fortran 90 */ + TAG_namelist = 0x8001, /* For Fortran 90 */ + TAG_function_template = 0x8002, /* for C++ */ + TAG_class_template = 0x8003 /* for C++ */ +}; + +#define TAG_lo_user 0x8000 /* implementation-defined range start */ +#define TAG_hi_user 0xffff /* implementation-defined range end */ +#define TAG_source_file TAG_compile_unit /* for backward compatibility */ + +/* Form names and codes. */ + +enum dwarf_form { + FORM_ADDR = 0x1, + FORM_REF = 0x2, + FORM_BLOCK2 = 0x3, + FORM_BLOCK4 = 0x4, + FORM_DATA2 = 0x5, + FORM_DATA4 = 0x6, + FORM_DATA8 = 0x7, + FORM_STRING = 0x8 +}; + +/* Attribute names and codes. */ + +enum dwarf_attribute { + AT_sibling = (0x0010|FORM_REF), + AT_location = (0x0020|FORM_BLOCK2), + AT_name = (0x0030|FORM_STRING), + AT_fund_type = (0x0050|FORM_DATA2), + AT_mod_fund_type = (0x0060|FORM_BLOCK2), + AT_user_def_type = (0x0070|FORM_REF), + AT_mod_u_d_type = (0x0080|FORM_BLOCK2), + AT_ordering = (0x0090|FORM_DATA2), + AT_subscr_data = (0x00a0|FORM_BLOCK2), + AT_byte_size = (0x00b0|FORM_DATA4), + AT_bit_offset = (0x00c0|FORM_DATA2), + AT_bit_size = (0x00d0|FORM_DATA4), + /* (0x00e0|FORM_xxxx) -- reserved */ + AT_element_list = (0x00f0|FORM_BLOCK4), + AT_stmt_list = (0x0100|FORM_DATA4), + AT_low_pc = (0x0110|FORM_ADDR), + AT_high_pc = (0x0120|FORM_ADDR), + AT_language = (0x0130|FORM_DATA4), + AT_member = (0x0140|FORM_REF), + AT_discr = (0x0150|FORM_REF), + AT_discr_value = (0x0160|FORM_BLOCK2), + /* (0x0170|FORM_xxxx) -- reserved */ + /* (0x0180|FORM_xxxx) -- reserved */ + AT_string_length = (0x0190|FORM_BLOCK2), + AT_common_reference = (0x01a0|FORM_REF), + AT_comp_dir = (0x01b0|FORM_STRING), + AT_const_value_string = (0x01c0|FORM_STRING), + AT_const_value_data2 = (0x01c0|FORM_DATA2), + AT_const_value_data4 = (0x01c0|FORM_DATA4), + AT_const_value_data8 = (0x01c0|FORM_DATA8), + AT_const_value_block2 = (0x01c0|FORM_BLOCK2), + AT_const_value_block4 = (0x01c0|FORM_BLOCK4), + AT_containing_type = (0x01d0|FORM_REF), + AT_default_value_addr = (0x01e0|FORM_ADDR), + AT_default_value_data2 = (0x01e0|FORM_DATA2), + AT_default_value_data4 = (0x01e0|FORM_DATA4), + AT_default_value_data8 = (0x01e0|FORM_DATA8), + AT_default_value_string = (0x01e0|FORM_STRING), + AT_friends = (0x01f0|FORM_BLOCK2), + AT_inline = (0x0200|FORM_STRING), + AT_is_optional = (0x0210|FORM_STRING), + AT_lower_bound_ref = (0x0220|FORM_REF), + AT_lower_bound_data2 = (0x0220|FORM_DATA2), + AT_lower_bound_data4 = (0x0220|FORM_DATA4), + AT_lower_bound_data8 = (0x0220|FORM_DATA8), + AT_private = (0x0240|FORM_STRING), + AT_producer = (0x0250|FORM_STRING), + AT_program = (0x0230|FORM_STRING), + AT_protected = (0x0260|FORM_STRING), + AT_prototyped = (0x0270|FORM_STRING), + AT_public = (0x0280|FORM_STRING), + AT_pure_virtual = (0x0290|FORM_STRING), + AT_return_addr = (0x02a0|FORM_BLOCK2), + AT_abstract_origin = (0x02b0|FORM_REF), + AT_start_scope = (0x02c0|FORM_DATA4), + AT_stride_size = (0x02e0|FORM_DATA4), + AT_upper_bound_ref = (0x02f0|FORM_REF), + AT_upper_bound_data2 = (0x02f0|FORM_DATA2), + AT_upper_bound_data4 = (0x02f0|FORM_DATA4), + AT_upper_bound_data8 = (0x02f0|FORM_DATA8), + AT_virtual = (0x0300|FORM_STRING), + + /* GNU extensions. */ + + AT_sf_names = (0x8000|FORM_DATA4), + AT_src_info = (0x8010|FORM_DATA4), + AT_mac_info = (0x8020|FORM_DATA4), + AT_src_coords = (0x8030|FORM_DATA4), + AT_body_begin = (0x8040|FORM_ADDR), + AT_body_end = (0x8050|FORM_ADDR) +}; + +#define AT_lo_user 0x2000 /* implementation-defined range start */ +#define AT_hi_user 0x3ff0 /* implementation-defined range end */ + +/* Location atom names and codes. */ + +enum dwarf_location_atom { + OP_REG = 0x01, + OP_BASEREG = 0x02, + OP_ADDR = 0x03, + OP_CONST = 0x04, + OP_DEREF2 = 0x05, + OP_DEREF4 = 0x06, + OP_ADD = 0x07, + + /* GNU extensions. */ + + OP_MULT = 0x80 +}; + +#define OP_LO_USER 0x80 /* implementation-defined range start */ +#define OP_HI_USER 0xff /* implementation-defined range end */ + +/* Fundamental type names and codes. */ + +enum dwarf_fundamental_type { + FT_char = 0x0001, + FT_signed_char = 0x0002, + FT_unsigned_char = 0x0003, + FT_short = 0x0004, + FT_signed_short = 0x0005, + FT_unsigned_short = 0x0006, + FT_integer = 0x0007, + FT_signed_integer = 0x0008, + FT_unsigned_integer = 0x0009, + FT_long = 0x000a, + FT_signed_long = 0x000b, + FT_unsigned_long = 0x000c, + FT_pointer = 0x000d, /* an alias for (void *) */ + FT_float = 0x000e, + FT_dbl_prec_float = 0x000f, + FT_ext_prec_float = 0x0010, /* breaks "classic" svr4 SDB */ + FT_complex = 0x0011, /* breaks "classic" svr4 SDB */ + FT_dbl_prec_complex = 0x0012, /* breaks "classic" svr4 SDB */ + /* 0x0013 -- reserved */ + FT_void = 0x0014, + FT_boolean = 0x0015, /* breaks "classic" svr4 SDB */ + FT_ext_prec_complex = 0x0016, /* breaks "classic" svr4 SDB */ + FT_label = 0x0017, + + /* GNU extensions + The low order byte must indicate the size (in bytes) for the type. + All of these types will probably break "classic" svr4 SDB */ + + FT_long_long = 0x8008, + FT_signed_long_long = 0x8108, + FT_unsigned_long_long = 0x8208, + + FT_int8 = 0x9001, + FT_signed_int8 = 0x9101, + FT_unsigned_int8 = 0x9201, + FT_int16 = 0x9302, + FT_signed_int16 = 0x9402, + FT_unsigned_int16 = 0x9502, + FT_int32 = 0x9604, + FT_signed_int32 = 0x9704, + FT_unsigned_int32 = 0x9804, + FT_int64 = 0x9908, + FT_signed_int64 = 0x9a08, + FT_unsigned_int64 = 0x9b08, + + FT_real32 = 0xa004, + FT_real64 = 0xa108, + FT_real96 = 0xa20c, + FT_real128 = 0xa310 +}; + +#define FT_lo_user 0x8000 /* implementation-defined range start */ +#define FT_hi_user 0xffff /* implementation defined range end */ + +/* Type modifier names and codes. */ + +enum dwarf_type_modifier { + MOD_pointer_to = 0x01, + MOD_reference_to = 0x02, + MOD_const = 0x03, + MOD_volatile = 0x04 +}; + +#define MOD_lo_user 0x80 /* implementation-defined range start */ +#define MOD_hi_user 0xff /* implementation-defined range end */ + +/* Array ordering names and codes. */ + +enum dwarf_array_dim_ordering { + ORD_row_major = 0, + ORD_col_major = 1 +}; + +/* Array subscript format names and codes. */ + +enum dwarf_subscr_data_formats { + FMT_FT_C_C = 0x0, + FMT_FT_C_X = 0x1, + FMT_FT_X_C = 0x2, + FMT_FT_X_X = 0x3, + FMT_UT_C_C = 0x4, + FMT_UT_C_X = 0x5, + FMT_UT_X_C = 0x6, + FMT_UT_X_X = 0x7, + FMT_ET = 0x8 +}; + +/* Derived from above for ease of use. */ + +#define FMT_CODE(_FUNDAMENTAL_TYPE_P, _UB_CONST_P, _LB_CONST_P) \ + (((_FUNDAMENTAL_TYPE_P) ? 0 : 4) \ + | ((_UB_CONST_P) ? 0 : 2) \ + | ((_LB_CONST_P) ? 0 : 1)) + +/* Source language names and codes. */ + +enum dwarf_source_language { + LANG_C89 = 0x00000001, + LANG_C = 0x00000002, + LANG_ADA83 = 0x00000003, + LANG_C_PLUS_PLUS = 0x00000004, + LANG_COBOL74 = 0x00000005, + LANG_COBOL85 = 0x00000006, + LANG_FORTRAN77 = 0x00000007, + LANG_FORTRAN90 = 0x00000008, + LANG_PASCAL83 = 0x00000009, + LANG_MODULA2 = 0x0000000a +}; + +#define LANG_lo_user 0x00008000 /* implementation-defined range start */ +#define LANG_hi_user 0x0000ffff /* implementation-defined range end */ + +/* Names and codes for GNU "macinfo" extension. */ + +enum dwarf_macinfo_record_type { + MACINFO_start = 's', + MACINFO_resume = 'r', + MACINFO_define = 'd', + MACINFO_undef = 'u' +}; diff --git a/gcc_arm/dwarf2.h b/gcc_arm/dwarf2.h new file mode 100755 index 0000000..ddbe1b8 --- /dev/null +++ b/gcc_arm/dwarf2.h @@ -0,0 +1,549 @@ +/* Declarations and definitions of codes relating to the DWARF2 symbolic + debugging information format. + Copyright (C) 1992, 1993, 1995, 1996, 1997 Free Software Foundation, Inc. + Contributed by Gary Funck (gary@intrepid.com). Derived from the + DWARF 1 implementation written by Ron Guilmette (rfg@monkeys.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* This file is derived from the DWARF specification (a public document) + Revision 2.0.0 (July 27, 1993) developed by the UNIX International + Programming Languages Special Interest Group (UI/PLSIG) and distributed + by UNIX International. Copies of this specification are available from + UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054. */ + +/* This file is shared between GCC and GDB, and should not contain + prototypes. */ + +/* Tag names and codes. */ + +enum dwarf_tag + { + DW_TAG_padding = 0x00, + DW_TAG_array_type = 0x01, + DW_TAG_class_type = 0x02, + DW_TAG_entry_point = 0x03, + DW_TAG_enumeration_type = 0x04, + DW_TAG_formal_parameter = 0x05, + DW_TAG_imported_declaration = 0x08, + DW_TAG_label = 0x0a, + DW_TAG_lexical_block = 0x0b, + DW_TAG_member = 0x0d, + DW_TAG_pointer_type = 0x0f, + DW_TAG_reference_type = 0x10, + DW_TAG_compile_unit = 0x11, + DW_TAG_string_type = 0x12, + DW_TAG_structure_type = 0x13, + DW_TAG_subroutine_type = 0x15, + DW_TAG_typedef = 0x16, + DW_TAG_union_type = 0x17, + DW_TAG_unspecified_parameters = 0x18, + DW_TAG_variant = 0x19, + DW_TAG_common_block = 0x1a, + DW_TAG_common_inclusion = 0x1b, + DW_TAG_inheritance = 0x1c, + DW_TAG_inlined_subroutine = 0x1d, + DW_TAG_module = 0x1e, + DW_TAG_ptr_to_member_type = 0x1f, + DW_TAG_set_type = 0x20, + DW_TAG_subrange_type = 0x21, + DW_TAG_with_stmt = 0x22, + DW_TAG_access_declaration = 0x23, + DW_TAG_base_type = 0x24, + DW_TAG_catch_block = 0x25, + DW_TAG_const_type = 0x26, + DW_TAG_constant = 0x27, + DW_TAG_enumerator = 0x28, + DW_TAG_file_type = 0x29, + DW_TAG_friend = 0x2a, + DW_TAG_namelist = 0x2b, + DW_TAG_namelist_item = 0x2c, + DW_TAG_packed_type = 0x2d, + DW_TAG_subprogram = 0x2e, + DW_TAG_template_type_param = 0x2f, + DW_TAG_template_value_param = 0x30, + DW_TAG_thrown_type = 0x31, + DW_TAG_try_block = 0x32, + DW_TAG_variant_part = 0x33, + DW_TAG_variable = 0x34, + DW_TAG_volatile_type = 0x35, + /* SGI/MIPS Extensions */ + DW_TAG_MIPS_loop = 0x4081, + /* GNU extensions */ + DW_TAG_format_label = 0x4101, /* for FORTRAN 77 and Fortran 90 */ + DW_TAG_function_template = 0x4102, /* for C++ */ + DW_TAG_class_template = 0x4103 /* for C++ */ + }; + +#define DW_TAG_lo_user 0x4080 +#define DW_TAG_hi_user 0xffff + +/* flag that tells whether entry has a child or not */ +#define DW_children_no 0 +#define DW_children_yes 1 + +/* Form names and codes. */ +enum dwarf_form + { + DW_FORM_addr = 0x01, + DW_FORM_block2 = 0x03, + DW_FORM_block4 = 0x04, + DW_FORM_data2 = 0x05, + DW_FORM_data4 = 0x06, + DW_FORM_data8 = 0x07, + DW_FORM_string = 0x08, + DW_FORM_block = 0x09, + DW_FORM_block1 = 0x0a, + DW_FORM_data1 = 0x0b, + DW_FORM_flag = 0x0c, + DW_FORM_sdata = 0x0d, + DW_FORM_strp = 0x0e, + DW_FORM_udata = 0x0f, + DW_FORM_ref_addr = 0x10, + DW_FORM_ref1 = 0x11, + DW_FORM_ref2 = 0x12, + DW_FORM_ref4 = 0x13, + DW_FORM_ref8 = 0x14, + DW_FORM_ref_udata = 0x15, + DW_FORM_indirect = 0x16 + }; + +/* Attribute names and codes. */ + +enum dwarf_attribute + { + DW_AT_sibling = 0x01, + DW_AT_location = 0x02, + DW_AT_name = 0x03, + DW_AT_ordering = 0x09, + DW_AT_subscr_data = 0x0a, + DW_AT_byte_size = 0x0b, + DW_AT_bit_offset = 0x0c, + DW_AT_bit_size = 0x0d, + DW_AT_element_list = 0x0f, + DW_AT_stmt_list = 0x10, + DW_AT_low_pc = 0x11, + DW_AT_high_pc = 0x12, + DW_AT_language = 0x13, + DW_AT_member = 0x14, + DW_AT_discr = 0x15, + DW_AT_discr_value = 0x16, + DW_AT_visibility = 0x17, + DW_AT_import = 0x18, + DW_AT_string_length = 0x19, + DW_AT_common_reference = 0x1a, + DW_AT_comp_dir = 0x1b, + DW_AT_const_value = 0x1c, + DW_AT_containing_type = 0x1d, + DW_AT_default_value = 0x1e, + DW_AT_inline = 0x20, + DW_AT_is_optional = 0x21, + DW_AT_lower_bound = 0x22, + DW_AT_producer = 0x25, + DW_AT_prototyped = 0x27, + DW_AT_return_addr = 0x2a, + DW_AT_start_scope = 0x2c, + DW_AT_stride_size = 0x2e, + DW_AT_upper_bound = 0x2f, + DW_AT_abstract_origin = 0x31, + DW_AT_accessibility = 0x32, + DW_AT_address_class = 0x33, + DW_AT_artificial = 0x34, + DW_AT_base_types = 0x35, + DW_AT_calling_convention = 0x36, + DW_AT_count = 0x37, + DW_AT_data_member_location = 0x38, + DW_AT_decl_column = 0x39, + DW_AT_decl_file = 0x3a, + DW_AT_decl_line = 0x3b, + DW_AT_declaration = 0x3c, + DW_AT_discr_list = 0x3d, + DW_AT_encoding = 0x3e, + DW_AT_external = 0x3f, + DW_AT_frame_base = 0x40, + DW_AT_friend = 0x41, + DW_AT_identifier_case = 0x42, + DW_AT_macro_info = 0x43, + DW_AT_namelist_items = 0x44, + DW_AT_priority = 0x45, + DW_AT_segment = 0x46, + DW_AT_specification = 0x47, + DW_AT_static_link = 0x48, + DW_AT_type = 0x49, + DW_AT_use_location = 0x4a, + DW_AT_variable_parameter = 0x4b, + DW_AT_virtuality = 0x4c, + DW_AT_vtable_elem_location = 0x4d, + /* SGI/MIPS Extensions */ + DW_AT_MIPS_fde = 0x2001, + DW_AT_MIPS_loop_begin = 0x2002, + DW_AT_MIPS_tail_loop_begin = 0x2003, + DW_AT_MIPS_epilog_begin = 0x2004, + DW_AT_MIPS_loop_unroll_factor = 0x2005, + DW_AT_MIPS_software_pipeline_depth = 0x2006, + DW_AT_MIPS_linkage_name = 0x2007, + DW_AT_MIPS_stride = 0x2008, + DW_AT_MIPS_abstract_name = 0x2009, + DW_AT_MIPS_clone_origin = 0x200a, + DW_AT_MIPS_has_inlines = 0x200b, + /* GNU extensions. */ + DW_AT_sf_names = 0x2101, + DW_AT_src_info = 0x2102, + DW_AT_mac_info = 0x2103, + DW_AT_src_coords = 0x2104, + DW_AT_body_begin = 0x2105, + DW_AT_body_end = 0x2106 + }; + +#define DW_AT_lo_user 0x2000 /* implementation-defined range start */ +#define DW_AT_hi_user 0x3ff0 /* implementation-defined range end */ + +/* Location atom names and codes. */ + +enum dwarf_location_atom + { + DW_OP_addr = 0x03, + DW_OP_deref = 0x06, + DW_OP_const1u = 0x08, + DW_OP_const1s = 0x09, + DW_OP_const2u = 0x0a, + DW_OP_const2s = 0x0b, + DW_OP_const4u = 0x0c, + DW_OP_const4s = 0x0d, + DW_OP_const8u = 0x0e, + DW_OP_const8s = 0x0f, + DW_OP_constu = 0x10, + DW_OP_consts = 0x11, + DW_OP_dup = 0x12, + DW_OP_drop = 0x13, + DW_OP_over = 0x14, + DW_OP_pick = 0x15, + DW_OP_swap = 0x16, + DW_OP_rot = 0x17, + DW_OP_xderef = 0x18, + DW_OP_abs = 0x19, + DW_OP_and = 0x1a, + DW_OP_div = 0x1b, + DW_OP_minus = 0x1c, + DW_OP_mod = 0x1d, + DW_OP_mul = 0x1e, + DW_OP_neg = 0x1f, + DW_OP_not = 0x20, + DW_OP_or = 0x21, + DW_OP_plus = 0x22, + DW_OP_plus_uconst = 0x23, + DW_OP_shl = 0x24, + DW_OP_shr = 0x25, + DW_OP_shra = 0x26, + DW_OP_xor = 0x27, + DW_OP_bra = 0x28, + DW_OP_eq = 0x29, + DW_OP_ge = 0x2a, + DW_OP_gt = 0x2b, + DW_OP_le = 0x2c, + DW_OP_lt = 0x2d, + DW_OP_ne = 0x2e, + DW_OP_skip = 0x2f, + DW_OP_lit0 = 0x30, + DW_OP_lit1 = 0x31, + DW_OP_lit2 = 0x32, + DW_OP_lit3 = 0x33, + DW_OP_lit4 = 0x34, + DW_OP_lit5 = 0x35, + DW_OP_lit6 = 0x36, + DW_OP_lit7 = 0x37, + DW_OP_lit8 = 0x38, + DW_OP_lit9 = 0x39, + DW_OP_lit10 = 0x3a, + DW_OP_lit11 = 0x3b, + DW_OP_lit12 = 0x3c, + DW_OP_lit13 = 0x3d, + DW_OP_lit14 = 0x3e, + DW_OP_lit15 = 0x3f, + DW_OP_lit16 = 0x40, + DW_OP_lit17 = 0x41, + DW_OP_lit18 = 0x42, + DW_OP_lit19 = 0x43, + DW_OP_lit20 = 0x44, + DW_OP_lit21 = 0x45, + DW_OP_lit22 = 0x46, + DW_OP_lit23 = 0x47, + DW_OP_lit24 = 0x48, + DW_OP_lit25 = 0x49, + DW_OP_lit26 = 0x4a, + DW_OP_lit27 = 0x4b, + DW_OP_lit28 = 0x4c, + DW_OP_lit29 = 0x4d, + DW_OP_lit30 = 0x4e, + DW_OP_lit31 = 0x4f, + DW_OP_reg0 = 0x50, + DW_OP_reg1 = 0x51, + DW_OP_reg2 = 0x52, + DW_OP_reg3 = 0x53, + DW_OP_reg4 = 0x54, + DW_OP_reg5 = 0x55, + DW_OP_reg6 = 0x56, + DW_OP_reg7 = 0x57, + DW_OP_reg8 = 0x58, + DW_OP_reg9 = 0x59, + DW_OP_reg10 = 0x5a, + DW_OP_reg11 = 0x5b, + DW_OP_reg12 = 0x5c, + DW_OP_reg13 = 0x5d, + DW_OP_reg14 = 0x5e, + DW_OP_reg15 = 0x5f, + DW_OP_reg16 = 0x60, + DW_OP_reg17 = 0x61, + DW_OP_reg18 = 0x62, + DW_OP_reg19 = 0x63, + DW_OP_reg20 = 0x64, + DW_OP_reg21 = 0x65, + DW_OP_reg22 = 0x66, + DW_OP_reg23 = 0x67, + DW_OP_reg24 = 0x68, + DW_OP_reg25 = 0x69, + DW_OP_reg26 = 0x6a, + DW_OP_reg27 = 0x6b, + DW_OP_reg28 = 0x6c, + DW_OP_reg29 = 0x6d, + DW_OP_reg30 = 0x6e, + DW_OP_reg31 = 0x6f, + DW_OP_breg0 = 0x70, + DW_OP_breg1 = 0x71, + DW_OP_breg2 = 0x72, + DW_OP_breg3 = 0x73, + DW_OP_breg4 = 0x74, + DW_OP_breg5 = 0x75, + DW_OP_breg6 = 0x76, + DW_OP_breg7 = 0x77, + DW_OP_breg8 = 0x78, + DW_OP_breg9 = 0x79, + DW_OP_breg10 = 0x7a, + DW_OP_breg11 = 0x7b, + DW_OP_breg12 = 0x7c, + DW_OP_breg13 = 0x7d, + DW_OP_breg14 = 0x7e, + DW_OP_breg15 = 0x7f, + DW_OP_breg16 = 0x80, + DW_OP_breg17 = 0x81, + DW_OP_breg18 = 0x82, + DW_OP_breg19 = 0x83, + DW_OP_breg20 = 0x84, + DW_OP_breg21 = 0x85, + DW_OP_breg22 = 0x86, + DW_OP_breg23 = 0x87, + DW_OP_breg24 = 0x88, + DW_OP_breg25 = 0x89, + DW_OP_breg26 = 0x8a, + DW_OP_breg27 = 0x8b, + DW_OP_breg28 = 0x8c, + DW_OP_breg29 = 0x8d, + DW_OP_breg30 = 0x8e, + DW_OP_breg31 = 0x8f, + DW_OP_regx = 0x90, + DW_OP_fbreg = 0x91, + DW_OP_bregx = 0x92, + DW_OP_piece = 0x93, + DW_OP_deref_size = 0x94, + DW_OP_xderef_size = 0x95, + DW_OP_nop = 0x96 + }; + +#define DW_OP_lo_user 0x80 /* implementation-defined range start */ +#define DW_OP_hi_user 0xff /* implementation-defined range end */ + +/* Type encodings. */ + +enum dwarf_type + { + DW_ATE_void = 0x0, + DW_ATE_address = 0x1, + DW_ATE_boolean = 0x2, + DW_ATE_complex_float = 0x3, + DW_ATE_float = 0x4, + DW_ATE_signed = 0x5, + DW_ATE_signed_char = 0x6, + DW_ATE_unsigned = 0x7, + DW_ATE_unsigned_char = 0x8 + }; + +#define DW_ATE_lo_user 0x80 +#define DW_ATE_hi_user 0xff + +/* Array ordering names and codes. */ +enum dwarf_array_dim_ordering + { + DW_ORD_row_major = 0, + DW_ORD_col_major = 1 + }; + +/* access attribute */ +enum dwarf_access_attribute + { + DW_ACCESS_public = 1, + DW_ACCESS_protected = 2, + DW_ACCESS_private = 3 + }; + +/* visibility */ +enum dwarf_visibility_attribute + { + DW_VIS_local = 1, + DW_VIS_exported = 2, + DW_VIS_qualified = 3 + }; + +/* virtuality */ +enum dwarf_virtuality_attribute + { + DW_VIRTUALITY_none = 0, + DW_VIRTUALITY_virtual = 1, + DW_VIRTUALITY_pure_virtual = 2 + }; + +/* case sensitivity */ +enum dwarf_id_case + { + DW_ID_case_sensitive = 0, + DW_ID_up_case = 1, + DW_ID_down_case = 2, + DW_ID_case_insensitive = 3 + }; + +/* calling convention */ +enum dwarf_calling_convention + { + DW_CC_normal = 0x1, + DW_CC_program = 0x2, + DW_CC_nocall = 0x3 + }; + +#define DW_CC_lo_user 0x40 +#define DW_CC_hi_user 0xff + +/* inline attribute */ +enum dwarf_inline_attribute + { + DW_INL_not_inlined = 0, + DW_INL_inlined = 1, + DW_INL_declared_not_inlined = 2, + DW_INL_declared_inlined = 3 + }; + +/* discriminant lists */ +enum dwarf_discrim_list + { + DW_DSC_label = 0, + DW_DSC_range = 1 + }; + +/* line number opcodes */ +enum dwarf_line_number_ops + { + DW_LNS_extended_op = 0, + DW_LNS_copy = 1, + DW_LNS_advance_pc = 2, + DW_LNS_advance_line = 3, + DW_LNS_set_file = 4, + DW_LNS_set_column = 5, + DW_LNS_negate_stmt = 6, + DW_LNS_set_basic_block = 7, + DW_LNS_const_add_pc = 8, + DW_LNS_fixed_advance_pc = 9 + }; + +/* line number extended opcodes */ +enum dwarf_line_number_x_ops + { + DW_LNE_end_sequence = 1, + DW_LNE_set_address = 2, + DW_LNE_define_file = 3 + }; + +/* call frame information */ +enum dwarf_call_frame_info + { + DW_CFA_advance_loc = 0x40, + DW_CFA_offset = 0x80, + DW_CFA_restore = 0xc0, + DW_CFA_nop = 0x00, + DW_CFA_set_loc = 0x01, + DW_CFA_advance_loc1 = 0x02, + DW_CFA_advance_loc2 = 0x03, + DW_CFA_advance_loc4 = 0x04, + DW_CFA_offset_extended = 0x05, + DW_CFA_restore_extended = 0x06, + DW_CFA_undefined = 0x07, + DW_CFA_same_value = 0x08, + DW_CFA_register = 0x09, + DW_CFA_remember_state = 0x0a, + DW_CFA_restore_state = 0x0b, + DW_CFA_def_cfa = 0x0c, + DW_CFA_def_cfa_register = 0x0d, + DW_CFA_def_cfa_offset = 0x0e, + /* SGI/MIPS specific */ + DW_CFA_MIPS_advance_loc8 = 0x1d, + + /* GNU extensions */ + DW_CFA_GNU_window_save = 0x2d, + DW_CFA_GNU_args_size = 0x2e + }; + +#define DW_CIE_ID 0xffffffff +#define DW_CIE_VERSION 1 + +#define DW_CFA_extended 0 +#define DW_CFA_low_user 0x1c +#define DW_CFA_high_user 0x3f + +#define DW_CHILDREN_no 0x00 +#define DW_CHILDREN_yes 0x01 + +#define DW_ADDR_none 0 + +/* Source language names and codes. */ + +enum dwarf_source_language + { + DW_LANG_C89 = 0x0001, + DW_LANG_C = 0x0002, + DW_LANG_Ada83 = 0x0003, + DW_LANG_C_plus_plus = 0x0004, + DW_LANG_Cobol74 = 0x0005, + DW_LANG_Cobol85 = 0x0006, + DW_LANG_Fortran77 = 0x0007, + DW_LANG_Fortran90 = 0x0008, + DW_LANG_Pascal83 = 0x0009, + DW_LANG_Modula2 = 0x000a, + DW_LANG_Mips_Assembler = 0x8001 + }; + + +#define DW_LANG_lo_user 0x8000 /* implementation-defined range start */ +#define DW_LANG_hi_user 0xffff /* implementation-defined range start */ + +/* Names and codes for macro information. */ + +enum dwarf_macinfo_record_type + { + DW_MACINFO_define = 1, + DW_MACINFO_undef = 2, + DW_MACINFO_start_file = 3, + DW_MACINFO_end_file = 4, + DW_MACINFO_vendor_ext = 255 + }; diff --git a/gcc_arm/dwarf2out.c b/gcc_arm/dwarf2out.c new file mode 100755 index 0000000..9329c71 --- /dev/null +++ b/gcc_arm/dwarf2out.c @@ -0,0 +1,9934 @@ +/* Output Dwarf2 format symbol table information from the GNU C compiler. + Copyright (C) 1992, 93, 95, 96, 97, 1998 Free Software Foundation, Inc. + Contributed by Gary Funck (gary@intrepid.com). + Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com). + Extensively modified by Jason Merrill (jason@cygnus.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* The first part of this file deals with the DWARF 2 frame unwind + information, which is also used by the GCC efficient exception handling + mechanism. The second part, controlled only by an #ifdef + DWARF2_DEBUGGING_INFO, deals with the other DWARF 2 debugging + information. */ + +#include "config.h" +#include "system.h" +#include "defaults.h" +#include "tree.h" +#include "flags.h" +#include "rtl.h" +#include "hard-reg-set.h" +#include "regs.h" +#include "insn-config.h" +#include "reload.h" +#include "output.h" +#include "expr.h" +#include "except.h" +#include "dwarf2.h" +#include "dwarf2out.h" +#include "toplev.h" +#include "dyn-string.h" + +/* We cannot use in GCC source, since that would include + GCC's assert.h, which may not be compatible with the host compiler. */ +#undef assert +#ifdef NDEBUG +# define assert(e) +#else +# define assert(e) do { if (! (e)) abort (); } while (0) +#endif + +/* Decide whether we want to emit frame unwind information for the current + translation unit. */ + +int +dwarf2out_do_frame () +{ + return (write_symbols == DWARF2_DEBUG +#ifdef DWARF2_FRAME_INFO + || DWARF2_FRAME_INFO +#endif +#ifdef DWARF2_UNWIND_INFO + || (flag_exceptions && ! exceptions_via_longjmp) +#endif + ); +} + +#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO) + +#ifndef __GNUC__ +#define inline +#endif + +/* How to start an assembler comment. */ +#ifndef ASM_COMMENT_START +#define ASM_COMMENT_START ";#" +#endif + +typedef struct dw_cfi_struct *dw_cfi_ref; +typedef struct dw_fde_struct *dw_fde_ref; +typedef union dw_cfi_oprnd_struct *dw_cfi_oprnd_ref; + +/* Call frames are described using a sequence of Call Frame + Information instructions. The register number, offset + and address fields are provided as possible operands; + their use is selected by the opcode field. */ + +typedef union dw_cfi_oprnd_struct +{ + unsigned long dw_cfi_reg_num; + long int dw_cfi_offset; + char *dw_cfi_addr; +} +dw_cfi_oprnd; + +typedef struct dw_cfi_struct +{ + dw_cfi_ref dw_cfi_next; + enum dwarf_call_frame_info dw_cfi_opc; + dw_cfi_oprnd dw_cfi_oprnd1; + dw_cfi_oprnd dw_cfi_oprnd2; +} +dw_cfi_node; + +/* All call frame descriptions (FDE's) in the GCC generated DWARF + refer to a single Common Information Entry (CIE), defined at + the beginning of the .debug_frame section. This used of a single + CIE obviates the need to keep track of multiple CIE's + in the DWARF generation routines below. */ + +typedef struct dw_fde_struct +{ + char *dw_fde_begin; + char *dw_fde_current_label; + char *dw_fde_end; + dw_cfi_ref dw_fde_cfi; +} +dw_fde_node; + +/* Maximum size (in bytes) of an artificially generated label. */ +#define MAX_ARTIFICIAL_LABEL_BYTES 30 + +/* Make sure we know the sizes of the various types dwarf can describe. These + are only defaults. If the sizes are different for your target, you should + override these values by defining the appropriate symbols in your tm.h + file. */ + +#ifndef CHAR_TYPE_SIZE +#define CHAR_TYPE_SIZE BITS_PER_UNIT +#endif +#ifndef PTR_SIZE +#define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT) +#endif + +/* The size in bytes of a DWARF field indicating an offset or length + relative to a debug info section, specified to be 4 bytes in the DWARF-2 + specification. The SGI/MIPS ABI defines it to be the same as PTR_SIZE. */ + +#ifndef DWARF_OFFSET_SIZE +#define DWARF_OFFSET_SIZE 4 +#endif + +#define DWARF_VERSION 2 + +/* Round SIZE up to the nearest BOUNDARY. */ +#define DWARF_ROUND(SIZE,BOUNDARY) \ + (((SIZE) + (BOUNDARY) - 1) & ~((BOUNDARY) - 1)) + +/* Offsets recorded in opcodes are a multiple of this alignment factor. */ +#ifdef STACK_GROWS_DOWNWARD +#define DWARF_CIE_DATA_ALIGNMENT (-UNITS_PER_WORD) +#else +#define DWARF_CIE_DATA_ALIGNMENT UNITS_PER_WORD +#endif + +/* A pointer to the base of a table that contains frame description + information for each routine. */ +static dw_fde_ref fde_table; + +/* Number of elements currently allocated for fde_table. */ +static unsigned fde_table_allocated; + +/* Number of elements in fde_table currently in use. */ +static unsigned fde_table_in_use; + +/* Size (in elements) of increments by which we may expand the + fde_table. */ +#define FDE_TABLE_INCREMENT 256 + +/* A list of call frame insns for the CIE. */ +static dw_cfi_ref cie_cfi_head; + +/* The number of the current function definition for which debugging + information is being generated. These numbers range from 1 up to the + maximum number of function definitions contained within the current + compilation unit. These numbers are used to create unique label id's + unique to each function definition. */ +static unsigned current_funcdef_number = 0; + +/* Some DWARF extensions (e.g., MIPS/SGI) implement a subprogram + attribute that accelerates the lookup of the FDE associated + with the subprogram. This variable holds the table index of the FDE + associated with the current function (body) definition. */ +static unsigned current_funcdef_fde; + +/* Forward declarations for functions defined in this file. */ + +static char *stripattributes PROTO((char *)); +static char *dwarf_cfi_name PROTO((unsigned)); +static dw_cfi_ref new_cfi PROTO((void)); +static void add_cfi PROTO((dw_cfi_ref *, dw_cfi_ref)); +static unsigned long size_of_uleb128 PROTO((unsigned long)); +static unsigned long size_of_sleb128 PROTO((long)); +static void output_uleb128 PROTO((unsigned long)); +static void output_sleb128 PROTO((long)); +static void add_fde_cfi PROTO((char *, dw_cfi_ref)); +static void lookup_cfa_1 PROTO((dw_cfi_ref, unsigned long *, + long *)); +static void lookup_cfa PROTO((unsigned long *, long *)); +static void reg_save PROTO((char *, unsigned, unsigned, + long)); +static void initial_return_save PROTO((rtx)); +static void output_cfi PROTO((dw_cfi_ref, dw_fde_ref)); +static void output_call_frame_info PROTO((int)); +static unsigned reg_number PROTO((rtx)); +static void dwarf2out_stack_adjust PROTO((rtx)); + +/* Definitions of defaults for assembler-dependent names of various + pseudo-ops and section names. + Theses may be overridden in the tm.h file (if necessary) for a particular + assembler. */ + +#ifdef OBJECT_FORMAT_ELF +#ifndef UNALIGNED_SHORT_ASM_OP +#define UNALIGNED_SHORT_ASM_OP ".2byte" +#endif +#ifndef UNALIGNED_INT_ASM_OP +#define UNALIGNED_INT_ASM_OP ".4byte" +#endif +#ifndef UNALIGNED_DOUBLE_INT_ASM_OP +#define UNALIGNED_DOUBLE_INT_ASM_OP ".8byte" +#endif +#endif /* OBJECT_FORMAT_ELF */ + +#ifndef ASM_BYTE_OP +#define ASM_BYTE_OP ".byte" +#endif + +/* Data and reference forms for relocatable data. */ +#define DW_FORM_data (DWARF_OFFSET_SIZE == 8 ? DW_FORM_data8 : DW_FORM_data4) +#define DW_FORM_ref (DWARF_OFFSET_SIZE == 8 ? DW_FORM_ref8 : DW_FORM_ref4) + +/* Pseudo-op for defining a new section. */ +#ifndef SECTION_ASM_OP +#define SECTION_ASM_OP ".section" +#endif + +/* The default format used by the ASM_OUTPUT_SECTION macro (see below) to + print the SECTION_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 SECTION_FORMAT +#ifdef PUSHSECTION_FORMAT +#define SECTION_FORMAT PUSHSECTION_FORMAT +#else +#define SECTION_FORMAT "\t%s\t%s\n" +#endif +#endif + +#ifndef FRAME_SECTION +#define FRAME_SECTION ".debug_frame" +#endif + +#ifndef FUNC_BEGIN_LABEL +#define FUNC_BEGIN_LABEL "LFB" +#endif +#ifndef FUNC_END_LABEL +#define FUNC_END_LABEL "LFE" +#endif +#define CIE_AFTER_SIZE_LABEL "LSCIE" +#define CIE_END_LABEL "LECIE" +#define CIE_LENGTH_LABEL "LLCIE" +#define FDE_AFTER_SIZE_LABEL "LSFDE" +#define FDE_END_LABEL "LEFDE" +#define FDE_LENGTH_LABEL "LLFDE" + +/* Definitions of defaults for various types of primitive assembly language + output operations. These may be overridden from within the tm.h file, + but typically, that is unnecessary. */ + +#ifndef ASM_OUTPUT_SECTION +#define ASM_OUTPUT_SECTION(FILE, SECTION) \ + fprintf ((FILE), SECTION_FORMAT, SECTION_ASM_OP, SECTION) +#endif + +#ifndef ASM_OUTPUT_DWARF_DATA1 +#define ASM_OUTPUT_DWARF_DATA1(FILE,VALUE) \ + fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) (VALUE)) +#endif + +#ifndef ASM_OUTPUT_DWARF_DELTA1 +#define ASM_OUTPUT_DWARF_DELTA1(FILE,LABEL1,LABEL2) \ + do { fprintf ((FILE), "\t%s\t", ASM_BYTE_OP); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, "-"); \ + assemble_name (FILE, LABEL2); \ + } while (0) +#endif + +#ifdef UNALIGNED_INT_ASM_OP + +#ifndef UNALIGNED_OFFSET_ASM_OP +#define UNALIGNED_OFFSET_ASM_OP \ + (DWARF_OFFSET_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP) +#endif + +#ifndef UNALIGNED_WORD_ASM_OP +#define UNALIGNED_WORD_ASM_OP \ + (PTR_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP) +#endif + +#ifndef ASM_OUTPUT_DWARF_DELTA2 +#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2) \ + do { fprintf ((FILE), "\t%s\t", UNALIGNED_SHORT_ASM_OP); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, "-"); \ + assemble_name (FILE, LABEL2); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_DELTA4 +#define ASM_OUTPUT_DWARF_DELTA4(FILE,LABEL1,LABEL2) \ + do { fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, "-"); \ + assemble_name (FILE, LABEL2); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_DELTA +#define ASM_OUTPUT_DWARF_DELTA(FILE,LABEL1,LABEL2) \ + do { fprintf ((FILE), "\t%s\t", UNALIGNED_OFFSET_ASM_OP); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, "-"); \ + assemble_name (FILE, LABEL2); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_ADDR_DELTA +#define ASM_OUTPUT_DWARF_ADDR_DELTA(FILE,LABEL1,LABEL2) \ + do { fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, "-"); \ + assemble_name (FILE, LABEL2); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_ADDR +#define ASM_OUTPUT_DWARF_ADDR(FILE,LABEL) \ + do { fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \ + assemble_name (FILE, LABEL); \ + } while (0) +#endif + +/* ??? This macro takes an RTX in dwarfout.c and a string in dwarf2out.c. + We resolve the conflict by creating a new macro ASM_OUTPUT_DWARF2_ADDR_CONST + for ports that want to support both DWARF1 and DWARF2. This needs a better + solution. See also the comments in sparc/sp64-elf.h. */ +#ifdef ASM_OUTPUT_DWARF2_ADDR_CONST +#undef ASM_OUTPUT_DWARF_ADDR_CONST +#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,ADDR) \ + ASM_OUTPUT_DWARF2_ADDR_CONST (FILE, ADDR) +#endif + +#ifndef ASM_OUTPUT_DWARF_ADDR_CONST +#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,ADDR) \ + fprintf ((FILE), "\t%s\t%s", UNALIGNED_WORD_ASM_OP, (ADDR)) +#endif + +#ifndef ASM_OUTPUT_DWARF_OFFSET4 +#define ASM_OUTPUT_DWARF_OFFSET4(FILE,LABEL) \ + do { fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP); \ + assemble_name (FILE, LABEL); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_OFFSET +#define ASM_OUTPUT_DWARF_OFFSET(FILE,LABEL) \ + do { fprintf ((FILE), "\t%s\t", UNALIGNED_OFFSET_ASM_OP); \ + assemble_name (FILE, LABEL); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_DATA2 +#define ASM_OUTPUT_DWARF_DATA2(FILE,VALUE) \ + fprintf ((FILE), "\t%s\t0x%x", UNALIGNED_SHORT_ASM_OP, (unsigned) (VALUE)) +#endif + +#ifndef ASM_OUTPUT_DWARF_DATA4 +#define ASM_OUTPUT_DWARF_DATA4(FILE,VALUE) \ + fprintf ((FILE), "\t%s\t0x%x", UNALIGNED_INT_ASM_OP, (unsigned) (VALUE)) +#endif + +#ifndef ASM_OUTPUT_DWARF_DATA +#define ASM_OUTPUT_DWARF_DATA(FILE,VALUE) \ + fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_OFFSET_ASM_OP, \ + (unsigned long) (VALUE)) +#endif + +#ifndef ASM_OUTPUT_DWARF_ADDR_DATA +#define ASM_OUTPUT_DWARF_ADDR_DATA(FILE,VALUE) \ + fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_WORD_ASM_OP, \ + (unsigned long) (VALUE)) +#endif + +#ifndef ASM_OUTPUT_DWARF_DATA8 +#define ASM_OUTPUT_DWARF_DATA8(FILE,HIGH_VALUE,LOW_VALUE) \ + do { \ + if (WORDS_BIG_ENDIAN) \ + { \ + fprintf ((FILE), "\t%s\t0x%lx\n", UNALIGNED_INT_ASM_OP, (HIGH_VALUE));\ + fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_INT_ASM_OP, (LOW_VALUE));\ + } \ + else \ + { \ + fprintf ((FILE), "\t%s\t0x%lx\n", UNALIGNED_INT_ASM_OP, (LOW_VALUE)); \ + fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_INT_ASM_OP, (HIGH_VALUE)); \ + } \ + } while (0) +#endif + +#else /* UNALIGNED_INT_ASM_OP */ + +/* We don't have unaligned support, let's hope the normal output works for + .debug_frame. */ + +#define ASM_OUTPUT_DWARF_ADDR(FILE,LABEL) \ + assemble_integer (gen_rtx_SYMBOL_REF (Pmode, LABEL), PTR_SIZE, 1) + +#define ASM_OUTPUT_DWARF_OFFSET4(FILE,LABEL) \ + assemble_integer (gen_rtx_SYMBOL_REF (SImode, LABEL), 4, 1) + +#define ASM_OUTPUT_DWARF_OFFSET(FILE,LABEL) \ + assemble_integer (gen_rtx_SYMBOL_REF (SImode, LABEL), 4, 1) + +#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2) \ + assemble_integer (gen_rtx_MINUS (HImode, \ + gen_rtx_SYMBOL_REF (Pmode, LABEL1), \ + gen_rtx_SYMBOL_REF (Pmode, LABEL2)), \ + 2, 1) + +#define ASM_OUTPUT_DWARF_DELTA4(FILE,LABEL1,LABEL2) \ + assemble_integer (gen_rtx_MINUS (SImode, \ + gen_rtx_SYMBOL_REF (Pmode, LABEL1), \ + gen_rtx_SYMBOL_REF (Pmode, LABEL2)), \ + 4, 1) + +#define ASM_OUTPUT_DWARF_ADDR_DELTA(FILE,LABEL1,LABEL2) \ + assemble_integer (gen_rtx_MINUS (Pmode, \ + gen_rtx_SYMBOL_REF (Pmode, LABEL1), \ + gen_rtx_SYMBOL_REF (Pmode, LABEL2)), \ + PTR_SIZE, 1) + +#define ASM_OUTPUT_DWARF_DELTA(FILE,LABEL1,LABEL2) \ + ASM_OUTPUT_DWARF_DELTA4 (FILE,LABEL1,LABEL2) + +#define ASM_OUTPUT_DWARF_DATA4(FILE,VALUE) \ + assemble_integer (GEN_INT (VALUE), 4, 1) + +#endif /* UNALIGNED_INT_ASM_OP */ + +#ifdef SET_ASM_OP +#ifndef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL +#define ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL(FILE, SY, HI, LO) \ + do { \ + fprintf (FILE, "\t%s\t", SET_ASM_OP); \ + assemble_name (FILE, SY); \ + fputc (',', FILE); \ + assemble_name (FILE, HI); \ + fputc ('-', FILE); \ + assemble_name (FILE, LO); \ + } while (0) +#endif +#endif /* SET_ASM_OP */ + +/* This is similar to the default ASM_OUTPUT_ASCII, except that no trailing + newline is produced. When flag_debug_asm is asserted, we add commentary + at the end of the line, so we must avoid output of a newline here. */ +#ifndef ASM_OUTPUT_DWARF_STRING +#define ASM_OUTPUT_DWARF_STRING(FILE,P) \ + do { \ + register int slen = strlen(P); \ + register char *p = (P); \ + register int i; \ + fprintf (FILE, "\t.ascii \""); \ + for (i = 0; i < slen; i++) \ + { \ + register int c = p[i]; \ + if (c == '\"' || c == '\\') \ + putc ('\\', FILE); \ + if (c >= ' ' && c < 0177) \ + putc (c, FILE); \ + else \ + { \ + fprintf (FILE, "\\%o", c); \ + } \ + } \ + fprintf (FILE, "\\0\""); \ + } \ + while (0) +#endif + +/* The DWARF 2 CFA column which tracks the return address. Normally this + is the column for PC, or the first column after all of the hard + registers. */ +#ifndef DWARF_FRAME_RETURN_COLUMN +#ifdef PC_REGNUM +#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (PC_REGNUM) +#else +#define DWARF_FRAME_RETURN_COLUMN FIRST_PSEUDO_REGISTER +#endif +#endif + +/* The mapping from gcc register number to DWARF 2 CFA column number. By + default, we just provide columns for all registers. */ +#ifndef DWARF_FRAME_REGNUM +#define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG) +#endif + +/* Hook used by __throw. */ + +rtx +expand_builtin_dwarf_fp_regnum () +{ + return GEN_INT (DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM)); +} + +/* The offset from the incoming value of %sp to the top of the stack frame + for the current function. */ +#ifndef INCOMING_FRAME_SP_OFFSET +#define INCOMING_FRAME_SP_OFFSET 0 +#endif + +/* Return a pointer to a copy of the section string name S with all + attributes stripped off, and an asterisk prepended (for assemble_name). */ + +static inline char * +stripattributes (s) + char *s; +{ + char *stripped = xmalloc (strlen (s) + 2); + char *p = stripped; + + *p++ = '*'; + + while (*s && *s != ',') + *p++ = *s++; + + *p = '\0'; + return stripped; +} + +/* Return the register number described by a given RTL node. */ + +static unsigned +reg_number (rtl) + register rtx rtl; +{ + register unsigned regno = REGNO (rtl); + + if (regno >= FIRST_PSEUDO_REGISTER) + { + warning ("internal regno botch: regno = %d\n", regno); + regno = 0; + } + + regno = DBX_REGISTER_NUMBER (regno); + return regno; +} + +struct reg_size_range +{ + int beg; + int end; + int size; +}; + +/* Given a register number in REG_TREE, return an rtx for its size in bytes. + We do this in kind of a roundabout way, by building up a list of + register size ranges and seeing where our register falls in one of those + ranges. We need to do it this way because REG_TREE is not a constant, + and the target macros were not designed to make this task easy. */ + +rtx +expand_builtin_dwarf_reg_size (reg_tree, target) + tree reg_tree; + rtx target; +{ + enum machine_mode mode; + int size; + struct reg_size_range ranges[5]; + tree t, t2; + + int i = 0; + int n_ranges = 0; + int last_size = -1; + + for (; i < FIRST_PSEUDO_REGISTER; ++i) + { + /* The return address is out of order on the MIPS, and we don't use + copy_reg for it anyway, so we don't care here how large it is. */ + if (DWARF_FRAME_REGNUM (i) == DWARF_FRAME_RETURN_COLUMN) + continue; + + mode = reg_raw_mode[i]; + + /* CCmode is arbitrarily given a size of 4 bytes. It is more useful + to use the same size as word_mode, since that reduces the number + of ranges we need. It should not matter, since the result should + never be used for a condition code register anyways. */ + if (GET_MODE_CLASS (mode) == MODE_CC) + mode = word_mode; + + size = GET_MODE_SIZE (mode); + + /* If this register is not valid in the specified mode and + we have a previous size, use that for the size of this + register to avoid making junk tiny ranges. */ + if (! HARD_REGNO_MODE_OK (i, mode) && last_size != -1) + size = last_size; + + if (size != last_size) + { + ranges[n_ranges].beg = i; + ranges[n_ranges].size = last_size = size; + ++n_ranges; + if (n_ranges >= 5) + abort (); + } + ranges[n_ranges-1].end = i; + } + + /* The usual case: fp regs surrounded by general regs. */ + if (n_ranges == 3 && ranges[0].size == ranges[2].size) + { + if ((DWARF_FRAME_REGNUM (ranges[1].end) + - DWARF_FRAME_REGNUM (ranges[1].beg)) + != ranges[1].end - ranges[1].beg) + abort (); + t = fold (build (GE_EXPR, integer_type_node, reg_tree, + build_int_2 (DWARF_FRAME_REGNUM (ranges[1].beg), 0))); + t2 = fold (build (LE_EXPR, integer_type_node, reg_tree, + build_int_2 (DWARF_FRAME_REGNUM (ranges[1].end), 0))); + t = fold (build (TRUTH_ANDIF_EXPR, integer_type_node, t, t2)); + t = fold (build (COND_EXPR, integer_type_node, t, + build_int_2 (ranges[1].size, 0), + build_int_2 (ranges[0].size, 0))); + } + else + { + /* Initialize last_end to be larger than any possible + DWARF_FRAME_REGNUM. */ + int last_end = 0x7fffffff; + --n_ranges; + t = build_int_2 (ranges[n_ranges].size, 0); + do + { + int beg = DWARF_FRAME_REGNUM (ranges[n_ranges].beg); + int end = DWARF_FRAME_REGNUM (ranges[n_ranges].end); + if (beg < 0) + continue; + if (end >= last_end) + abort (); + last_end = end; + if (end - beg != ranges[n_ranges].end - ranges[n_ranges].beg) + abort (); + t2 = fold (build (LE_EXPR, integer_type_node, reg_tree, + build_int_2 (end, 0))); + t = fold (build (COND_EXPR, integer_type_node, t2, + build_int_2 (ranges[n_ranges].size, 0), t)); + } + while (--n_ranges >= 0); + } + return expand_expr (t, target, Pmode, 0); +} + +/* Convert a DWARF call frame info. operation to its string name */ + +static char * +dwarf_cfi_name (cfi_opc) + register unsigned cfi_opc; +{ + switch (cfi_opc) + { + case DW_CFA_advance_loc: + return "DW_CFA_advance_loc"; + case DW_CFA_offset: + return "DW_CFA_offset"; + case DW_CFA_restore: + return "DW_CFA_restore"; + case DW_CFA_nop: + return "DW_CFA_nop"; + case DW_CFA_set_loc: + return "DW_CFA_set_loc"; + case DW_CFA_advance_loc1: + return "DW_CFA_advance_loc1"; + case DW_CFA_advance_loc2: + return "DW_CFA_advance_loc2"; + case DW_CFA_advance_loc4: + return "DW_CFA_advance_loc4"; + case DW_CFA_offset_extended: + return "DW_CFA_offset_extended"; + case DW_CFA_restore_extended: + return "DW_CFA_restore_extended"; + case DW_CFA_undefined: + return "DW_CFA_undefined"; + case DW_CFA_same_value: + return "DW_CFA_same_value"; + case DW_CFA_register: + return "DW_CFA_register"; + case DW_CFA_remember_state: + return "DW_CFA_remember_state"; + case DW_CFA_restore_state: + return "DW_CFA_restore_state"; + case DW_CFA_def_cfa: + return "DW_CFA_def_cfa"; + case DW_CFA_def_cfa_register: + return "DW_CFA_def_cfa_register"; + case DW_CFA_def_cfa_offset: + return "DW_CFA_def_cfa_offset"; + + /* SGI/MIPS specific */ + case DW_CFA_MIPS_advance_loc8: + return "DW_CFA_MIPS_advance_loc8"; + + /* GNU extensions */ + case DW_CFA_GNU_window_save: + return "DW_CFA_GNU_window_save"; + case DW_CFA_GNU_args_size: + return "DW_CFA_GNU_args_size"; + + default: + return "DW_CFA_"; + } +} + +/* Return a pointer to a newly allocated Call Frame Instruction. */ + +static inline dw_cfi_ref +new_cfi () +{ + register dw_cfi_ref cfi = (dw_cfi_ref) xmalloc (sizeof (dw_cfi_node)); + + cfi->dw_cfi_next = NULL; + cfi->dw_cfi_oprnd1.dw_cfi_reg_num = 0; + cfi->dw_cfi_oprnd2.dw_cfi_reg_num = 0; + + return cfi; +} + +/* Add a Call Frame Instruction to list of instructions. */ + +static inline void +add_cfi (list_head, cfi) + register dw_cfi_ref *list_head; + register dw_cfi_ref cfi; +{ + register dw_cfi_ref *p; + + /* Find the end of the chain. */ + for (p = list_head; (*p) != NULL; p = &(*p)->dw_cfi_next) + ; + + *p = cfi; +} + +/* Generate a new label for the CFI info to refer to. */ + +char * +dwarf2out_cfi_label () +{ + static char label[20]; + static unsigned long label_num = 0; + + ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", label_num++); + ASM_OUTPUT_LABEL (asm_out_file, label); + + return label; +} + +/* Add CFI to the current fde at the PC value indicated by LABEL if specified, + or to the CIE if LABEL is NULL. */ + +static void +add_fde_cfi (label, cfi) + register char *label; + register dw_cfi_ref cfi; +{ + if (label) + { + register dw_fde_ref fde = &fde_table[fde_table_in_use - 1]; + + if (*label == 0) + label = dwarf2out_cfi_label (); + + if (fde->dw_fde_current_label == NULL + || strcmp (label, fde->dw_fde_current_label) != 0) + { + register dw_cfi_ref xcfi; + + fde->dw_fde_current_label = label = xstrdup (label); + + /* Set the location counter to the new label. */ + xcfi = new_cfi (); + xcfi->dw_cfi_opc = DW_CFA_advance_loc4; + xcfi->dw_cfi_oprnd1.dw_cfi_addr = label; + add_cfi (&fde->dw_fde_cfi, xcfi); + } + + add_cfi (&fde->dw_fde_cfi, cfi); + } + + else + add_cfi (&cie_cfi_head, cfi); +} + +/* Subroutine of lookup_cfa. */ + +static inline void +lookup_cfa_1 (cfi, regp, offsetp) + register dw_cfi_ref cfi; + register unsigned long *regp; + register long *offsetp; +{ + switch (cfi->dw_cfi_opc) + { + case DW_CFA_def_cfa_offset: + *offsetp = cfi->dw_cfi_oprnd1.dw_cfi_offset; + break; + case DW_CFA_def_cfa_register: + *regp = cfi->dw_cfi_oprnd1.dw_cfi_reg_num; + break; + case DW_CFA_def_cfa: + *regp = cfi->dw_cfi_oprnd1.dw_cfi_reg_num; + *offsetp = cfi->dw_cfi_oprnd2.dw_cfi_offset; + break; + default: + break; + } +} + +/* Find the previous value for the CFA. */ + +static void +lookup_cfa (regp, offsetp) + register unsigned long *regp; + register long *offsetp; +{ + register dw_cfi_ref cfi; + + *regp = (unsigned long) -1; + *offsetp = 0; + + for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next) + lookup_cfa_1 (cfi, regp, offsetp); + + if (fde_table_in_use) + { + register dw_fde_ref fde = &fde_table[fde_table_in_use - 1]; + for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next) + lookup_cfa_1 (cfi, regp, offsetp); + } +} + +/* The current rule for calculating the DWARF2 canonical frame address. */ +static unsigned long cfa_reg; +static long cfa_offset; + +/* The register used for saving registers to the stack, and its offset + from the CFA. */ +static unsigned cfa_store_reg; +static long cfa_store_offset; + +/* The running total of the size of arguments pushed onto the stack. */ +static long args_size; + +/* The last args_size we actually output. */ +static long old_args_size; + +/* Entry point to update the canonical frame address (CFA). + LABEL is passed to add_fde_cfi. The value of CFA is now to be + calculated from REG+OFFSET. */ + +void +dwarf2out_def_cfa (label, reg, offset) + register char *label; + register unsigned reg; + register long offset; +{ + register dw_cfi_ref cfi; + unsigned long old_reg; + long old_offset; + + cfa_reg = reg; + cfa_offset = offset; + if (cfa_store_reg == reg) + cfa_store_offset = offset; + + reg = DWARF_FRAME_REGNUM (reg); + lookup_cfa (&old_reg, &old_offset); + + if (reg == old_reg && offset == old_offset) + return; + + cfi = new_cfi (); + + if (reg == old_reg) + { + cfi->dw_cfi_opc = DW_CFA_def_cfa_offset; + cfi->dw_cfi_oprnd1.dw_cfi_offset = offset; + } + +#ifndef MIPS_DEBUGGING_INFO /* SGI dbx thinks this means no offset. */ + else if (offset == old_offset && old_reg != (unsigned long) -1) + { + cfi->dw_cfi_opc = DW_CFA_def_cfa_register; + cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg; + } +#endif + + else + { + cfi->dw_cfi_opc = DW_CFA_def_cfa; + cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg; + cfi->dw_cfi_oprnd2.dw_cfi_offset = offset; + } + + add_fde_cfi (label, cfi); +} + +/* Add the CFI for saving a register. REG is the CFA column number. + LABEL is passed to add_fde_cfi. + If SREG is -1, the register is saved at OFFSET from the CFA; + otherwise it is saved in SREG. */ + +static void +reg_save (label, reg, sreg, offset) + register char * label; + register unsigned reg; + register unsigned sreg; + register long offset; +{ + register dw_cfi_ref cfi = new_cfi (); + + cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg; + + /* The following comparison is correct. -1 is used to indicate that + the value isn't a register number. */ + if (sreg == (unsigned int) -1) + { + if (reg & ~0x3f) + /* The register number won't fit in 6 bits, so we have to use + the long form. */ + cfi->dw_cfi_opc = DW_CFA_offset_extended; + else + cfi->dw_cfi_opc = DW_CFA_offset; + + offset /= DWARF_CIE_DATA_ALIGNMENT; + if (offset < 0) + abort (); + cfi->dw_cfi_oprnd2.dw_cfi_offset = offset; + } + else + { + cfi->dw_cfi_opc = DW_CFA_register; + cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg; + } + + add_fde_cfi (label, cfi); +} + +/* Add the CFI for saving a register window. LABEL is passed to reg_save. + This CFI tells the unwinder that it needs to restore the window registers + from the previous frame's window save area. + + ??? Perhaps we should note in the CIE where windows are saved (instead of + assuming 0(cfa)) and what registers are in the window. */ + +void +dwarf2out_window_save (label) + register char * label; +{ + register dw_cfi_ref cfi = new_cfi (); + cfi->dw_cfi_opc = DW_CFA_GNU_window_save; + add_fde_cfi (label, cfi); +} + +/* Add a CFI to update the running total of the size of arguments + pushed onto the stack. */ + +void +dwarf2out_args_size (label, size) + char *label; + long size; +{ + register dw_cfi_ref cfi; + + if (size == old_args_size) + return; + old_args_size = size; + + cfi = new_cfi (); + cfi->dw_cfi_opc = DW_CFA_GNU_args_size; + cfi->dw_cfi_oprnd1.dw_cfi_offset = size; + add_fde_cfi (label, cfi); +} + +/* Entry point for saving a register to the stack. REG is the GCC register + number. LABEL and OFFSET are passed to reg_save. */ + +void +dwarf2out_reg_save (label, reg, offset) + register char * label; + register unsigned reg; + register long offset; +{ + reg_save (label, DWARF_FRAME_REGNUM (reg), -1, offset); +} + +/* Entry point for saving the return address in the stack. + LABEL and OFFSET are passed to reg_save. */ + +void +dwarf2out_return_save (label, offset) + register char * label; + register long offset; +{ + reg_save (label, DWARF_FRAME_RETURN_COLUMN, -1, offset); +} + +/* Entry point for saving the return address in a register. + LABEL and SREG are passed to reg_save. */ + +void +dwarf2out_return_reg (label, sreg) + register char * label; + register unsigned sreg; +{ + reg_save (label, DWARF_FRAME_RETURN_COLUMN, sreg, 0); +} + +/* Record the initial position of the return address. RTL is + INCOMING_RETURN_ADDR_RTX. */ + +static void +initial_return_save (rtl) + register rtx rtl; +{ + unsigned int reg = (unsigned int) -1; + long offset = 0; + + switch (GET_CODE (rtl)) + { + case REG: + /* RA is in a register. */ + reg = reg_number (rtl); + break; + case MEM: + /* RA is on the stack. */ + rtl = XEXP (rtl, 0); + switch (GET_CODE (rtl)) + { + case REG: + if (REGNO (rtl) != STACK_POINTER_REGNUM) + abort (); + offset = 0; + break; + case PLUS: + if (REGNO (XEXP (rtl, 0)) != STACK_POINTER_REGNUM) + abort (); + offset = INTVAL (XEXP (rtl, 1)); + break; + case MINUS: + if (REGNO (XEXP (rtl, 0)) != STACK_POINTER_REGNUM) + abort (); + offset = -INTVAL (XEXP (rtl, 1)); + break; + default: + abort (); + } + break; + case PLUS: + /* The return address is at some offset from any value we can + actually load. For instance, on the SPARC it is in %i7+8. Just + ignore the offset for now; it doesn't matter for unwinding frames. */ + if (GET_CODE (XEXP (rtl, 1)) != CONST_INT) + abort (); + initial_return_save (XEXP (rtl, 0)); + return; + default: + abort (); + } + + reg_save (NULL, DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa_offset); +} + +/* Check INSN to see if it looks like a push or a stack adjustment, and + make a note of it if it does. EH uses this information to find out how + much extra space it needs to pop off the stack. */ + +static void +dwarf2out_stack_adjust (insn) + rtx insn; +{ + long offset; + char *label; + + if (! asynchronous_exceptions && GET_CODE (insn) == CALL_INSN) + { + /* Extract the size of the args from the CALL rtx itself. */ + + insn = PATTERN (insn); + if (GET_CODE (insn) == PARALLEL) + insn = XVECEXP (insn, 0, 0); + if (GET_CODE (insn) == SET) + insn = SET_SRC (insn); + assert (GET_CODE (insn) == CALL); + dwarf2out_args_size ("", INTVAL (XEXP (insn, 1))); + return; + } + + /* If only calls can throw, and we have a frame pointer, + save up adjustments until we see the CALL_INSN. */ + else if (! asynchronous_exceptions + && cfa_reg != STACK_POINTER_REGNUM) + return; + + if (GET_CODE (insn) == BARRIER) + { + /* When we see a BARRIER, we know to reset args_size to 0. Usually + the compiler will have already emitted a stack adjustment, but + doesn't bother for calls to noreturn functions. */ +#ifdef STACK_GROWS_DOWNWARD + offset = -args_size; +#else + offset = args_size; +#endif + } + else if (GET_CODE (PATTERN (insn)) == SET) + { + rtx src, dest; + enum rtx_code code; + + insn = PATTERN (insn); + src = SET_SRC (insn); + dest = SET_DEST (insn); + + if (dest == stack_pointer_rtx) + { + /* (set (reg sp) (plus (reg sp) (const_int))) */ + code = GET_CODE (src); + if (! (code == PLUS || code == MINUS) + || XEXP (src, 0) != stack_pointer_rtx + || GET_CODE (XEXP (src, 1)) != CONST_INT) + return; + + offset = INTVAL (XEXP (src, 1)); + } + else if (GET_CODE (dest) == MEM) + { + /* (set (mem (pre_dec (reg sp))) (foo)) */ + src = XEXP (dest, 0); + code = GET_CODE (src); + + if (! (code == PRE_DEC || code == PRE_INC) + || XEXP (src, 0) != stack_pointer_rtx) + return; + + offset = GET_MODE_SIZE (GET_MODE (dest)); + } + else + return; + + if (code == PLUS || code == PRE_INC) + offset = -offset; + } + else + return; + + if (offset == 0) + return; + + if (cfa_reg == STACK_POINTER_REGNUM) + cfa_offset += offset; + +#ifndef STACK_GROWS_DOWNWARD + offset = -offset; +#endif + args_size += offset; + if (args_size < 0) + args_size = 0; + + label = dwarf2out_cfi_label (); + dwarf2out_def_cfa (label, cfa_reg, cfa_offset); + dwarf2out_args_size (label, args_size); +} + +/* Record call frame debugging information for INSN, which either + sets SP or FP (adjusting how we calculate the frame address) or saves a + register to the stack. If INSN is NULL_RTX, initialize our state. */ + +void +dwarf2out_frame_debug (insn) + rtx insn; +{ + char *label; + rtx src, dest; + long offset; + + /* A temporary register used in adjusting SP or setting up the store_reg. */ + static unsigned cfa_temp_reg; + static long cfa_temp_value; + + if (insn == NULL_RTX) + { + /* Set up state for generating call frame debug info. */ + lookup_cfa (&cfa_reg, &cfa_offset); + if (cfa_reg != DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM)) + abort (); + cfa_reg = STACK_POINTER_REGNUM; + cfa_store_reg = cfa_reg; + cfa_store_offset = cfa_offset; + cfa_temp_reg = -1; + cfa_temp_value = 0; + return; + } + + if (! RTX_FRAME_RELATED_P (insn)) + { + dwarf2out_stack_adjust (insn); + return; + } + + label = dwarf2out_cfi_label (); + + src = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX); + if (src) + insn = XEXP (src, 0); + else + insn = PATTERN (insn); + + /* Assume that in a PARALLEL prologue insn, only the first elt is + significant. Currently this is true. */ + if (GET_CODE (insn) == PARALLEL) + insn = XVECEXP (insn, 0, 0); + if (GET_CODE (insn) != SET) + abort (); + + src = SET_SRC (insn); + dest = SET_DEST (insn); + + switch (GET_CODE (dest)) + { + case REG: + /* Update the CFA rule wrt SP or FP. Make sure src is + relative to the current CFA register. */ + switch (GET_CODE (src)) + { + /* Setting FP from SP. */ + case REG: + if (cfa_reg != (unsigned) REGNO (src)) + abort (); + if (REGNO (dest) != STACK_POINTER_REGNUM + && !(frame_pointer_needed + && REGNO (dest) == HARD_FRAME_POINTER_REGNUM)) + abort (); + cfa_reg = REGNO (dest); + break; + + case PLUS: + case MINUS: + if (dest == stack_pointer_rtx) + { + /* Adjusting SP. */ + switch (GET_CODE (XEXP (src, 1))) + { + case CONST_INT: + offset = INTVAL (XEXP (src, 1)); + break; + case REG: + if ((unsigned) REGNO (XEXP (src, 1)) != cfa_temp_reg) + abort (); + offset = cfa_temp_value; + break; + default: + abort (); + } + + if (XEXP (src, 0) == hard_frame_pointer_rtx) + { + /* Restoring SP from FP in the epilogue. */ + if (cfa_reg != (unsigned) HARD_FRAME_POINTER_REGNUM) + abort (); + cfa_reg = STACK_POINTER_REGNUM; + } + else if (XEXP (src, 0) != stack_pointer_rtx) + abort (); + + if (GET_CODE (src) == PLUS) + offset = -offset; + if (cfa_reg == STACK_POINTER_REGNUM) + cfa_offset += offset; + if (cfa_store_reg == STACK_POINTER_REGNUM) + cfa_store_offset += offset; + } + else if (dest == hard_frame_pointer_rtx) + { + /* Either setting the FP from an offset of the SP, + or adjusting the FP */ + if (! frame_pointer_needed + || REGNO (dest) != HARD_FRAME_POINTER_REGNUM) + abort (); + + if (XEXP (src, 0) == stack_pointer_rtx + && GET_CODE (XEXP (src, 1)) == CONST_INT) + { + if (cfa_reg != STACK_POINTER_REGNUM) + abort (); + offset = INTVAL (XEXP (src, 1)); + if (GET_CODE (src) == PLUS) + offset = -offset; + cfa_offset += offset; + cfa_reg = HARD_FRAME_POINTER_REGNUM; + } + else if (XEXP (src, 0) == hard_frame_pointer_rtx + && GET_CODE (XEXP (src, 1)) == CONST_INT) + { + if (cfa_reg != (unsigned) HARD_FRAME_POINTER_REGNUM) + abort (); + offset = INTVAL (XEXP (src, 1)); + if (GET_CODE (src) == PLUS) + offset = -offset; + cfa_offset += offset; + } + + else + abort(); + } + else + { + if (GET_CODE (src) != PLUS + || XEXP (src, 1) != stack_pointer_rtx) + abort (); + if (GET_CODE (XEXP (src, 0)) != REG + || (unsigned) REGNO (XEXP (src, 0)) != cfa_temp_reg) + abort (); + if (cfa_reg != STACK_POINTER_REGNUM) + abort (); + cfa_store_reg = REGNO (dest); + cfa_store_offset = cfa_offset - cfa_temp_value; + } + break; + + case CONST_INT: + cfa_temp_reg = REGNO (dest); + cfa_temp_value = INTVAL (src); + break; + + case IOR: + if (GET_CODE (XEXP (src, 0)) != REG + || (unsigned) REGNO (XEXP (src, 0)) != cfa_temp_reg + || (unsigned) REGNO (dest) != cfa_temp_reg + || GET_CODE (XEXP (src, 1)) != CONST_INT) + abort (); + cfa_temp_value |= INTVAL (XEXP (src, 1)); + break; + + default: + abort (); + } + dwarf2out_def_cfa (label, cfa_reg, cfa_offset); + break; + + case MEM: + /* Saving a register to the stack. Make sure dest is relative to the + CFA register. */ + if (GET_CODE (src) != REG) + abort (); + switch (GET_CODE (XEXP (dest, 0))) + { + /* With a push. */ + case PRE_INC: + case PRE_DEC: + offset = GET_MODE_SIZE (GET_MODE (dest)); + if (GET_CODE (XEXP (dest, 0)) == PRE_INC) + offset = -offset; + + if (REGNO (XEXP (XEXP (dest, 0), 0)) != STACK_POINTER_REGNUM + || cfa_store_reg != STACK_POINTER_REGNUM) + abort (); + cfa_store_offset += offset; + if (cfa_reg == STACK_POINTER_REGNUM) + cfa_offset = cfa_store_offset; + + offset = -cfa_store_offset; + break; + + /* With an offset. */ + case PLUS: + case MINUS: + offset = INTVAL (XEXP (XEXP (dest, 0), 1)); + if (GET_CODE (src) == MINUS) + offset = -offset; + + if (cfa_store_reg != (unsigned) REGNO (XEXP (XEXP (dest, 0), 0))) + abort (); + offset -= cfa_store_offset; + break; + + /* Without an offset. */ + case REG: + if (cfa_store_reg != (unsigned) REGNO (XEXP (dest, 0))) + abort(); + offset = -cfa_store_offset; + break; + + default: + abort (); + } + dwarf2out_def_cfa (label, cfa_reg, cfa_offset); + dwarf2out_reg_save (label, REGNO (src), offset); + break; + + default: + abort (); + } +} + +/* Return the size of an unsigned LEB128 quantity. */ + +static inline unsigned long +size_of_uleb128 (value) + register unsigned long value; +{ + register unsigned long size = 0; + register unsigned byte; + + do + { + byte = (value & 0x7f); + value >>= 7; + size += 1; + } + while (value != 0); + + return size; +} + +/* Return the size of a signed LEB128 quantity. */ + +static inline unsigned long +size_of_sleb128 (value) + register long value; +{ + register unsigned long size = 0; + register unsigned byte; + + do + { + byte = (value & 0x7f); + value >>= 7; + size += 1; + } + while (!(((value == 0) && ((byte & 0x40) == 0)) + || ((value == -1) && ((byte & 0x40) != 0)))); + + return size; +} + +/* Output an unsigned LEB128 quantity. */ + +static void +output_uleb128 (value) + register unsigned long value; +{ + unsigned long save_value = value; + + fprintf (asm_out_file, "\t%s\t", ASM_BYTE_OP); + do + { + register unsigned byte = (value & 0x7f); + value >>= 7; + if (value != 0) + /* More bytes to follow. */ + byte |= 0x80; + + fprintf (asm_out_file, "0x%x", byte); + if (value != 0) + fprintf (asm_out_file, ","); + } + while (value != 0); + + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s ULEB128 0x%lx", ASM_COMMENT_START, save_value); +} + +/* Output an signed LEB128 quantity. */ + +static void +output_sleb128 (value) + register long value; +{ + register int more; + register unsigned byte; + long save_value = value; + + fprintf (asm_out_file, "\t%s\t", ASM_BYTE_OP); + do + { + byte = (value & 0x7f); + /* arithmetic shift */ + value >>= 7; + more = !((((value == 0) && ((byte & 0x40) == 0)) + || ((value == -1) && ((byte & 0x40) != 0)))); + if (more) + byte |= 0x80; + + fprintf (asm_out_file, "0x%x", byte); + if (more) + fprintf (asm_out_file, ","); + } + + while (more); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s SLEB128 %ld", ASM_COMMENT_START, save_value); +} + +/* Output a Call Frame Information opcode and its operand(s). */ + +static void +output_cfi (cfi, fde) + register dw_cfi_ref cfi; + register dw_fde_ref fde; +{ + if (cfi->dw_cfi_opc == DW_CFA_advance_loc) + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, + cfi->dw_cfi_opc + | (cfi->dw_cfi_oprnd1.dw_cfi_offset & 0x3f)); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_CFA_advance_loc 0x%lx", + ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_offset); + fputc ('\n', asm_out_file); + } + + else if (cfi->dw_cfi_opc == DW_CFA_offset) + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, + cfi->dw_cfi_opc + | (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f)); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_CFA_offset, column 0x%lx", + ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_reg_num); + + fputc ('\n', asm_out_file); + output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset); + fputc ('\n', asm_out_file); + } + else if (cfi->dw_cfi_opc == DW_CFA_restore) + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, + cfi->dw_cfi_opc + | (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f)); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_CFA_restore, column 0x%lx", + ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_reg_num); + + fputc ('\n', asm_out_file); + } + else + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, cfi->dw_cfi_opc); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START, + dwarf_cfi_name (cfi->dw_cfi_opc)); + + fputc ('\n', asm_out_file); + switch (cfi->dw_cfi_opc) + { + case DW_CFA_set_loc: + ASM_OUTPUT_DWARF_ADDR (asm_out_file, cfi->dw_cfi_oprnd1.dw_cfi_addr); + fputc ('\n', asm_out_file); + break; + case DW_CFA_advance_loc1: + ASM_OUTPUT_DWARF_DELTA1 (asm_out_file, + cfi->dw_cfi_oprnd1.dw_cfi_addr, + fde->dw_fde_current_label); + fputc ('\n', asm_out_file); + fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr; + break; + case DW_CFA_advance_loc2: + ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, + cfi->dw_cfi_oprnd1.dw_cfi_addr, + fde->dw_fde_current_label); + fputc ('\n', asm_out_file); + fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr; + break; + case DW_CFA_advance_loc4: + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, + cfi->dw_cfi_oprnd1.dw_cfi_addr, + fde->dw_fde_current_label); + fputc ('\n', asm_out_file); + fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr; + break; +#ifdef MIPS_DEBUGGING_INFO + case DW_CFA_MIPS_advance_loc8: + /* TODO: not currently implemented. */ + abort (); + break; +#endif + case DW_CFA_offset_extended: + case DW_CFA_def_cfa: + output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num); + fputc ('\n', asm_out_file); + output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset); + fputc ('\n', asm_out_file); + break; + case DW_CFA_restore_extended: + case DW_CFA_undefined: + output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num); + fputc ('\n', asm_out_file); + break; + case DW_CFA_same_value: + case DW_CFA_def_cfa_register: + output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num); + fputc ('\n', asm_out_file); + break; + case DW_CFA_register: + output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num); + fputc ('\n', asm_out_file); + output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_reg_num); + fputc ('\n', asm_out_file); + break; + case DW_CFA_def_cfa_offset: + output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset); + fputc ('\n', asm_out_file); + break; + case DW_CFA_GNU_window_save: + break; + case DW_CFA_GNU_args_size: + output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset); + fputc ('\n', asm_out_file); + break; + default: + break; + } + } +} + +#if !defined (EH_FRAME_SECTION) +#if defined (EH_FRAME_SECTION_ASM_OP) +#define EH_FRAME_SECTION() eh_frame_section(); +#else +#if defined (ASM_OUTPUT_SECTION_NAME) +#define EH_FRAME_SECTION() \ + do { \ + named_section (NULL_TREE, ".eh_frame", 0); \ + } while (0) +#endif +#endif +#endif + +/* If we aren't using crtstuff to run ctors, don't use it for EH. */ +#if !defined (HAS_INIT_SECTION) && !defined (INIT_SECTION_ASM_OP) +#undef EH_FRAME_SECTION +#endif + +/* Output the call frame information used to used to record information + that relates to calculating the frame pointer, and records the + location of saved registers. */ + +static void +output_call_frame_info (for_eh) + int for_eh; +{ + register unsigned long i; + register dw_fde_ref fde; + register dw_cfi_ref cfi; + char l1[20], l2[20]; +#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL + char ld[20]; +#endif + + /* Do we want to include a pointer to the exception table? */ + int eh_ptr = for_eh && exception_table_p (); + + fputc ('\n', asm_out_file); + + /* We're going to be generating comments, so turn on app. */ + if (flag_debug_asm) + app_enable (); + + if (for_eh) + { +#ifdef EH_FRAME_SECTION + EH_FRAME_SECTION (); +#else + tree label = get_file_function_name ('F'); + + force_data_section (); + ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE)); + ASM_GLOBALIZE_LABEL (asm_out_file, IDENTIFIER_POINTER (label)); + ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label)); +#endif + assemble_label ("__FRAME_BEGIN__"); + } + else + ASM_OUTPUT_SECTION (asm_out_file, FRAME_SECTION); + + /* Output the CIE. */ + ASM_GENERATE_INTERNAL_LABEL (l1, CIE_AFTER_SIZE_LABEL, for_eh); + ASM_GENERATE_INTERNAL_LABEL (l2, CIE_END_LABEL, for_eh); +#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL + ASM_GENERATE_INTERNAL_LABEL (ld, CIE_LENGTH_LABEL, for_eh); + if (for_eh) + ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld); + else + ASM_OUTPUT_DWARF_OFFSET (asm_out_file, ld); +#else + if (for_eh) + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l2, l1); + else + ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1); +#endif + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Length of Common Information Entry", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_LABEL (asm_out_file, l1); + + if (for_eh) + /* Now that the CIE pointer is PC-relative for EH, + use 0 to identify the CIE. */ + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0); + else + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID); + + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s CIE Identifier Tag", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + if (! for_eh && DWARF_OFFSET_SIZE == 8) + { + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID); + fputc ('\n', asm_out_file); + } + + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_CIE_VERSION); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s CIE Version", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + if (eh_ptr) + { + /* The CIE contains a pointer to the exception region info for the + frame. Make the augmentation string three bytes (including the + trailing null) so the pointer is 4-byte aligned. The Solaris ld + can't handle unaligned relocs. */ + if (flag_debug_asm) + { + ASM_OUTPUT_DWARF_STRING (asm_out_file, "eh"); + fprintf (asm_out_file, "\t%s CIE Augmentation", ASM_COMMENT_START); + } + else + { + ASM_OUTPUT_ASCII (asm_out_file, "eh", 3); + } + fputc ('\n', asm_out_file); + + ASM_OUTPUT_DWARF_ADDR (asm_out_file, "__EXCEPTION_TABLE__"); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s pointer to exception region info", + ASM_COMMENT_START); + } + else + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s CIE Augmentation (none)", + ASM_COMMENT_START); + } + + fputc ('\n', asm_out_file); + output_uleb128 (1); + if (flag_debug_asm) + fprintf (asm_out_file, " (CIE Code Alignment Factor)"); + + fputc ('\n', asm_out_file); + output_sleb128 (DWARF_CIE_DATA_ALIGNMENT); + if (flag_debug_asm) + fprintf (asm_out_file, " (CIE Data Alignment Factor)"); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_FRAME_RETURN_COLUMN); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s CIE RA Column", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + + for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next) + output_cfi (cfi, NULL); + + /* Pad the CIE out to an address sized boundary. */ + ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE)); + ASM_OUTPUT_LABEL (asm_out_file, l2); +#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL + ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s CIE Length Symbol", ASM_COMMENT_START); + fputc ('\n', asm_out_file); +#endif + + /* Loop through all of the FDE's. */ + for (i = 0; i < fde_table_in_use; ++i) + { + fde = &fde_table[i]; + + ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + i*2); + ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + i*2); +#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL + ASM_GENERATE_INTERNAL_LABEL (ld, FDE_LENGTH_LABEL, for_eh + i*2); + if (for_eh) + ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld); + else + ASM_OUTPUT_DWARF_OFFSET (asm_out_file, ld); +#else + if (for_eh) + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l2, l1); + else + ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1); +#endif + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s FDE Length", ASM_COMMENT_START); + fputc ('\n', asm_out_file); + ASM_OUTPUT_LABEL (asm_out_file, l1); + + /* ??? This always emits a 4 byte offset when for_eh is true, but it + emits a target dependent sized offset when for_eh is not true. + This inconsistency may confuse gdb. The only case where we need a + non-4 byte offset is for the Irix6 N64 ABI, so we may lose SGI + compatibility if we emit a 4 byte offset. We need a 4 byte offset + though in order to be compatible with the dwarf_fde struct in frame.c. + If the for_eh case is changed, then the struct in frame.c has + to be adjusted appropriately. */ + if (for_eh) + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l1, "__FRAME_BEGIN__"); + else + ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (FRAME_SECTION)); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s FDE CIE offset", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, fde->dw_fde_begin); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s FDE initial location", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, + fde->dw_fde_end, fde->dw_fde_begin); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s FDE address range", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + + /* Loop through the Call Frame Instructions associated with + this FDE. */ + fde->dw_fde_current_label = fde->dw_fde_begin; + for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next) + output_cfi (cfi, fde); + + /* Pad the FDE out to an address sized boundary. */ + ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE)); + ASM_OUTPUT_LABEL (asm_out_file, l2); +#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL + ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s FDE Length Symbol", ASM_COMMENT_START); + fputc ('\n', asm_out_file); +#endif + } +#ifndef EH_FRAME_SECTION + if (for_eh) + { + /* Emit terminating zero for table. */ + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0); + fputc ('\n', asm_out_file); + } +#endif +#ifdef MIPS_DEBUGGING_INFO + /* Work around Irix 6 assembler bug whereby labels at the end of a section + get a value of 0. Putting .align 0 after the label fixes it. */ + ASM_OUTPUT_ALIGN (asm_out_file, 0); +#endif + + /* Turn off app to make assembly quicker. */ + if (flag_debug_asm) + app_disable (); +} + +/* Output a marker (i.e. a label) for the beginning of a function, before + the prologue. */ + +void +dwarf2out_begin_prologue () +{ + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + register dw_fde_ref fde; + + ++current_funcdef_number; + + function_section (current_function_decl); + ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL, + current_funcdef_number); + ASM_OUTPUT_LABEL (asm_out_file, label); + + /* Expand the fde table if necessary. */ + if (fde_table_in_use == fde_table_allocated) + { + fde_table_allocated += FDE_TABLE_INCREMENT; + fde_table + = (dw_fde_ref) xrealloc (fde_table, + fde_table_allocated * sizeof (dw_fde_node)); + } + + /* Record the FDE associated with this function. */ + current_funcdef_fde = fde_table_in_use; + + /* Add the new FDE at the end of the fde_table. */ + fde = &fde_table[fde_table_in_use++]; + fde->dw_fde_begin = xstrdup (label); + fde->dw_fde_current_label = NULL; + fde->dw_fde_end = NULL; + fde->dw_fde_cfi = NULL; + + args_size = old_args_size = 0; +} + +/* 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. */ + +void +dwarf2out_end_epilogue () +{ + dw_fde_ref fde; + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + /* Output a label to mark the endpoint of the code generated for this + function. */ + ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL, current_funcdef_number); + ASM_OUTPUT_LABEL (asm_out_file, label); + fde = &fde_table[fde_table_in_use - 1]; + fde->dw_fde_end = xstrdup (label); +} + +void +dwarf2out_frame_init () +{ + /* Allocate the initial hunk of the fde_table. */ + fde_table + = (dw_fde_ref) xmalloc (FDE_TABLE_INCREMENT * sizeof (dw_fde_node)); + bzero ((char *) fde_table, FDE_TABLE_INCREMENT * sizeof (dw_fde_node)); + fde_table_allocated = FDE_TABLE_INCREMENT; + fde_table_in_use = 0; + + /* Generate the CFA instructions common to all FDE's. Do it now for the + sake of lookup_cfa. */ + +#ifdef DWARF2_UNWIND_INFO + /* On entry, the Canonical Frame Address is at SP. */ + dwarf2out_def_cfa (NULL, STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET); + initial_return_save (INCOMING_RETURN_ADDR_RTX); +#endif +} + +void +dwarf2out_frame_finish () +{ + /* Output call frame information. */ +#ifdef MIPS_DEBUGGING_INFO + if (write_symbols == DWARF2_DEBUG) + output_call_frame_info (0); + if (flag_exceptions && ! exceptions_via_longjmp) + output_call_frame_info (1); +#else + if (write_symbols == DWARF2_DEBUG + || (flag_exceptions && ! exceptions_via_longjmp)) + output_call_frame_info (1); +#endif +} + +#endif /* .debug_frame support */ + +/* And now, the support for symbolic debugging information. */ +#ifdef DWARF2_DEBUGGING_INFO + +extern char *getpwd PROTO((void)); + +/* NOTE: In the comments in this file, many references are made to + "Debugging Information Entries". This term is abbreviated as `DIE' + throughout the remainder of this file. */ + +/* An internal representation of the DWARF output is built, and then + walked to generate the DWARF debugging info. The walk of the internal + representation is done after the entire program has been compiled. + The types below are used to describe the internal representation. */ + +/* Each DIE may have a series of attribute/value pairs. Values + can take on several forms. The forms that are used in this + implementation are listed below. */ + +typedef enum +{ + dw_val_class_addr, + dw_val_class_loc, + dw_val_class_const, + dw_val_class_unsigned_const, + dw_val_class_long_long, + dw_val_class_float, + dw_val_class_flag, + dw_val_class_die_ref, + dw_val_class_fde_ref, + dw_val_class_lbl_id, + dw_val_class_section_offset, + dw_val_class_str +} +dw_val_class; + +/* Various DIE's use offsets relative to the beginning of the + .debug_info section to refer to each other. */ + +typedef long int dw_offset; + +/* Define typedefs here to avoid circular dependencies. */ + +typedef struct die_struct *dw_die_ref; +typedef struct dw_attr_struct *dw_attr_ref; +typedef struct dw_val_struct *dw_val_ref; +typedef struct dw_line_info_struct *dw_line_info_ref; +typedef struct dw_separate_line_info_struct *dw_separate_line_info_ref; +typedef struct dw_loc_descr_struct *dw_loc_descr_ref; +typedef struct pubname_struct *pubname_ref; +typedef dw_die_ref *arange_ref; + +/* Describe a double word constant value. */ + +typedef struct dw_long_long_struct +{ + unsigned long hi; + unsigned long low; +} +dw_long_long_const; + +/* Describe a floating point constant value. */ + +typedef struct dw_fp_struct +{ + long *array; + unsigned length; +} +dw_float_const; + +/* Each entry in the line_info_table maintains the file and + line number associated with the label generated for that + entry. The label gives the PC value associated with + the line number entry. */ + +typedef struct dw_line_info_struct +{ + unsigned long dw_file_num; + unsigned long dw_line_num; +} +dw_line_info_entry; + +/* Line information for functions in separate sections; each one gets its + own sequence. */ +typedef struct dw_separate_line_info_struct +{ + unsigned long dw_file_num; + unsigned long dw_line_num; + unsigned long function; +} +dw_separate_line_info_entry; + +/* The dw_val_node describes an attribute's value, as it is + represented internally. */ + +typedef struct dw_val_struct +{ + dw_val_class val_class; + union + { + char *val_addr; + dw_loc_descr_ref val_loc; + long int val_int; + long unsigned val_unsigned; + dw_long_long_const val_long_long; + dw_float_const val_float; + dw_die_ref val_die_ref; + unsigned val_fde_index; + char *val_str; + char *val_lbl_id; + char *val_section; + unsigned char val_flag; + } + v; +} +dw_val_node; + +/* Locations in memory are described using a sequence of stack machine + operations. */ + +typedef struct dw_loc_descr_struct +{ + dw_loc_descr_ref dw_loc_next; + enum dwarf_location_atom dw_loc_opc; + dw_val_node dw_loc_oprnd1; + dw_val_node dw_loc_oprnd2; +} +dw_loc_descr_node; + +/* Each DIE attribute has a field specifying the attribute kind, + a link to the next attribute in the chain, and an attribute value. + Attributes are typically linked below the DIE they modify. */ + +typedef struct dw_attr_struct +{ + enum dwarf_attribute dw_attr; + dw_attr_ref dw_attr_next; + dw_val_node dw_attr_val; +} +dw_attr_node; + +/* The Debugging Information Entry (DIE) structure */ + +typedef struct die_struct +{ + enum dwarf_tag die_tag; + dw_attr_ref die_attr; + dw_attr_ref die_attr_last; + dw_die_ref die_parent; + dw_die_ref die_child; + dw_die_ref die_child_last; + dw_die_ref die_sib; + dw_offset die_offset; + unsigned long die_abbrev; +} +die_node; + +/* The pubname structure */ + +typedef struct pubname_struct +{ + dw_die_ref die; + char * name; +} +pubname_entry; + +/* The limbo die list structure. */ +typedef struct limbo_die_struct +{ + dw_die_ref die; + struct limbo_die_struct *next; +} +limbo_die_node; + +/* How to start an assembler comment. */ +#ifndef ASM_COMMENT_START +#define ASM_COMMENT_START ";#" +#endif + +/* Define a macro which returns non-zero 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_TREE \ + || (DECL_ARTIFICIAL (decl) \ + && is_tagged_type (TREE_TYPE (decl)) \ + && ((decl == TYPE_STUB_DECL (TREE_TYPE (decl))) \ + /* This is necessary for stub decls that \ + appear in nested inline functions. */ \ + || (DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE \ + && (decl_ultimate_origin (decl) \ + == TYPE_STUB_DECL (TREE_TYPE (decl))))))) + +/* Information concerning the compilation unit's programming + language, and compiler version. */ + +extern int flag_traditional; +extern char *version_string; +extern char *language_string; + +/* Fixed size portion of the DWARF compilation unit header. */ +#define DWARF_COMPILE_UNIT_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 3) + +/* Fixed size portion of debugging line information prolog. */ +#define DWARF_LINE_PROLOG_HEADER_SIZE 5 + +/* Fixed size portion of public names info. */ +#define DWARF_PUBNAMES_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 2) + +/* Fixed size portion of the address range info. */ +#define DWARF_ARANGES_HEADER_SIZE \ + (DWARF_ROUND (2 * DWARF_OFFSET_SIZE + 4, PTR_SIZE * 2) - DWARF_OFFSET_SIZE) + +/* Define the architecture-dependent minimum instruction length (in bytes). + In this implementation of DWARF, this field is used for information + purposes only. Since GCC generates assembly language, we have + no a priori knowledge of how many instruction bytes are generated + for each source line, and therefore can use only the DW_LNE_set_address + and DW_LNS_fixed_advance_pc line information commands. */ + +#ifndef DWARF_LINE_MIN_INSTR_LENGTH +#define DWARF_LINE_MIN_INSTR_LENGTH 4 +#endif + +/* Minimum line offset in a special line info. opcode. + This value was chosen to give a reasonable range of values. */ +#define DWARF_LINE_BASE -10 + +/* First special line opcde - leave room for the standard opcodes. */ +#define DWARF_LINE_OPCODE_BASE 10 + +/* Range of line offsets in a special line info. opcode. */ +#define DWARF_LINE_RANGE (254-DWARF_LINE_OPCODE_BASE+1) + +/* Flag that indicates the initial value of the is_stmt_start flag. + In the present implementation, we do not mark any lines as + the beginning of a source statement, because that information + is not made available by the GCC front-end. */ +#define DWARF_LINE_DEFAULT_IS_STMT_START 1 + +/* This location is used by calc_die_sizes() to keep track + the offset of each DIE within the .debug_info section. */ +static unsigned long next_die_offset; + +/* Record the root of the DIE's built for the current compilation unit. */ +static dw_die_ref comp_unit_die; + +/* A list of DIEs with a NULL parent waiting to be relocated. */ +static limbo_die_node *limbo_die_list = 0; + +/* Pointer to an array of filenames referenced by this compilation unit. */ +static char **file_table; + +/* Total number of entries in the table (i.e. array) pointed to by + `file_table'. This is the *total* and includes both used and unused + slots. */ +static unsigned file_table_allocated; + +/* Number of entries in the file_table which are actually in use. */ +static unsigned file_table_in_use; + +/* Size (in elements) of increments by which we may expand the filename + table. */ +#define FILE_TABLE_INCREMENT 64 + +/* Local pointer to the name of the main input file. Initialized in + dwarf2out_init. */ +static char *primary_filename; + +/* For Dwarf output, we must assign lexical-blocks id numbers in the order in + which their beginnings are encountered. We output Dwarf debugging info + that refers to the beginnings and ends of the ranges of code for each + lexical block. The labels themselves are generated in final.c, which + assigns numbers to the blocks in the same way. */ +static unsigned next_block_number = 2; + +/* A pointer to the base of a table of references to DIE's that describe + declarations. The table is indexed by DECL_UID() which is a unique + number identifying each decl. */ +static dw_die_ref *decl_die_table; + +/* Number of elements currently allocated for the decl_die_table. */ +static unsigned decl_die_table_allocated; + +/* Number of elements in decl_die_table currently in use. */ +static unsigned decl_die_table_in_use; + +/* Size (in elements) of increments by which we may expand the + decl_die_table. */ +#define DECL_DIE_TABLE_INCREMENT 256 + +/* Structure used for the decl_scope table. scope is the current declaration + scope, and previous is the entry that is the parent of this scope. This + is usually but not always the immediately preceeding entry. */ + +typedef struct decl_scope_struct +{ + tree scope; + int previous; +} +decl_scope_node; + +/* A pointer to the base of a table of references to declaration + scopes. This table is a display which tracks the nesting + of declaration scopes at the current scope and containing + scopes. This table is used to find the proper place to + define type declaration DIE's. */ +static decl_scope_node *decl_scope_table; + +/* Number of elements currently allocated for the decl_scope_table. */ +static int decl_scope_table_allocated; + +/* Current level of nesting of declaration scopes. */ +static int decl_scope_depth; + +/* Size (in elements) of increments by which we may expand the + decl_scope_table. */ +#define DECL_SCOPE_TABLE_INCREMENT 64 + +/* A pointer to the base of a list of references to DIE's that + are uniquely identified by their tag, presence/absence of + children DIE's, and list of attribute/value pairs. */ +static dw_die_ref *abbrev_die_table; + +/* Number of elements currently allocated for abbrev_die_table. */ +static unsigned abbrev_die_table_allocated; + +/* Number of elements in type_die_table currently in use. */ +static unsigned abbrev_die_table_in_use; + +/* Size (in elements) of increments by which we may expand the + abbrev_die_table. */ +#define ABBREV_DIE_TABLE_INCREMENT 256 + +/* A pointer to the base of a table that contains line information + for each source code line in .text in the compilation unit. */ +static dw_line_info_ref line_info_table; + +/* Number of elements currently allocated for line_info_table. */ +static unsigned line_info_table_allocated; + +/* Number of elements in separate_line_info_table currently in use. */ +static unsigned separate_line_info_table_in_use; + +/* A pointer to the base of a table that contains line information + for each source code line outside of .text in the compilation unit. */ +static dw_separate_line_info_ref separate_line_info_table; + +/* Number of elements currently allocated for separate_line_info_table. */ +static unsigned separate_line_info_table_allocated; + +/* Number of elements in line_info_table currently in use. */ +static unsigned line_info_table_in_use; + +/* Size (in elements) of increments by which we may expand the + line_info_table. */ +#define LINE_INFO_TABLE_INCREMENT 1024 + +/* A pointer to the base of a table that contains a list of publicly + accessible names. */ +static pubname_ref pubname_table; + +/* Number of elements currently allocated for pubname_table. */ +static unsigned pubname_table_allocated; + +/* Number of elements in pubname_table currently in use. */ +static unsigned pubname_table_in_use; + +/* Size (in elements) of increments by which we may expand the + pubname_table. */ +#define PUBNAME_TABLE_INCREMENT 64 + +/* A pointer to the base of a table that contains a list of publicly + accessible names. */ +static arange_ref arange_table; + +/* Number of elements currently allocated for arange_table. */ +static unsigned arange_table_allocated; + +/* Number of elements in arange_table currently in use. */ +static unsigned arange_table_in_use; + +/* Size (in elements) of increments by which we may expand the + arange_table. */ +#define ARANGE_TABLE_INCREMENT 64 + +/* 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 + +/* Record whether the function being analyzed contains inlined functions. */ +static int current_function_has_inlines; +#if 0 && defined (MIPS_DEBUGGING_INFO) +static int comp_unit_has_inlines; +#endif + +/* 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; + +/* Forward declarations for functions defined in this file. */ + +static void addr_const_to_string PROTO((dyn_string_t, rtx)); +static char *addr_to_string PROTO((rtx)); +static int is_pseudo_reg PROTO((rtx)); +static tree type_main_variant PROTO((tree)); +static int is_tagged_type PROTO((tree)); +static char *dwarf_tag_name PROTO((unsigned)); +static char *dwarf_attr_name PROTO((unsigned)); +static char *dwarf_form_name PROTO((unsigned)); +static char *dwarf_stack_op_name PROTO((unsigned)); +#if 0 +static char *dwarf_type_encoding_name PROTO((unsigned)); +#endif +static tree decl_ultimate_origin PROTO((tree)); +static tree block_ultimate_origin PROTO((tree)); +static tree decl_class_context PROTO((tree)); +static void add_dwarf_attr PROTO((dw_die_ref, dw_attr_ref)); +static void add_AT_flag PROTO((dw_die_ref, + enum dwarf_attribute, + unsigned)); +static void add_AT_int PROTO((dw_die_ref, + enum dwarf_attribute, long)); +static void add_AT_unsigned PROTO((dw_die_ref, + enum dwarf_attribute, + unsigned long)); +static void add_AT_long_long PROTO((dw_die_ref, + enum dwarf_attribute, + unsigned long, unsigned long)); +static void add_AT_float PROTO((dw_die_ref, + enum dwarf_attribute, + unsigned, long *)); +static void add_AT_string PROTO((dw_die_ref, + enum dwarf_attribute, char *)); +static void add_AT_die_ref PROTO((dw_die_ref, + enum dwarf_attribute, + dw_die_ref)); +static void add_AT_fde_ref PROTO((dw_die_ref, + enum dwarf_attribute, + unsigned)); +static void add_AT_loc PROTO((dw_die_ref, + enum dwarf_attribute, + dw_loc_descr_ref)); +static void add_AT_addr PROTO((dw_die_ref, + enum dwarf_attribute, char *)); +static void add_AT_lbl_id PROTO((dw_die_ref, + enum dwarf_attribute, char *)); +static void add_AT_section_offset PROTO((dw_die_ref, + enum dwarf_attribute, char *)); +static int is_extern_subr_die PROTO((dw_die_ref)); +static dw_attr_ref get_AT PROTO((dw_die_ref, + enum dwarf_attribute)); +static char *get_AT_low_pc PROTO((dw_die_ref)); +static char *get_AT_hi_pc PROTO((dw_die_ref)); +static char *get_AT_string PROTO((dw_die_ref, + enum dwarf_attribute)); +static int get_AT_flag PROTO((dw_die_ref, + enum dwarf_attribute)); +static unsigned get_AT_unsigned PROTO((dw_die_ref, + enum dwarf_attribute)); +static int is_c_family PROTO((void)); +static int is_fortran PROTO((void)); +static void remove_AT PROTO((dw_die_ref, + enum dwarf_attribute)); +static void remove_children PROTO((dw_die_ref)); +static void add_child_die PROTO((dw_die_ref, dw_die_ref)); +static dw_die_ref new_die PROTO((enum dwarf_tag, dw_die_ref)); +static dw_die_ref lookup_type_die PROTO((tree)); +static void equate_type_number_to_die PROTO((tree, dw_die_ref)); +static dw_die_ref lookup_decl_die PROTO((tree)); +static void equate_decl_number_to_die PROTO((tree, dw_die_ref)); +static dw_loc_descr_ref new_loc_descr PROTO((enum dwarf_location_atom, + unsigned long, unsigned long)); +static void add_loc_descr PROTO((dw_loc_descr_ref *, + dw_loc_descr_ref)); +static void print_spaces PROTO((FILE *)); +static void print_die PROTO((dw_die_ref, FILE *)); +static void print_dwarf_line_table PROTO((FILE *)); +static void add_sibling_attributes PROTO((dw_die_ref)); +static void build_abbrev_table PROTO((dw_die_ref)); +static unsigned long size_of_string PROTO((char *)); +static unsigned long size_of_loc_descr PROTO((dw_loc_descr_ref)); +static unsigned long size_of_locs PROTO((dw_loc_descr_ref)); +static int constant_size PROTO((long unsigned)); +static unsigned long size_of_die PROTO((dw_die_ref)); +static void calc_die_sizes PROTO((dw_die_ref)); +static unsigned long size_of_line_prolog PROTO((void)); +static unsigned long size_of_line_info PROTO((void)); +static unsigned long size_of_pubnames PROTO((void)); +static unsigned long size_of_aranges PROTO((void)); +static enum dwarf_form value_format PROTO((dw_val_ref)); +static void output_value_format PROTO((dw_val_ref)); +static void output_abbrev_section PROTO((void)); +static void output_loc_operands PROTO((dw_loc_descr_ref)); +static unsigned long sibling_offset PROTO((dw_die_ref)); +static void output_die PROTO((dw_die_ref)); +static void output_compilation_unit_header PROTO((void)); +static char *dwarf2_name PROTO((tree, int)); +static void add_pubname PROTO((tree, dw_die_ref)); +static void output_pubnames PROTO((void)); +static void add_arange PROTO((tree, dw_die_ref)); +static void output_aranges PROTO((void)); +static void output_line_info PROTO((void)); +static int is_body_block PROTO((tree)); +static dw_die_ref base_type_die PROTO((tree)); +static tree root_type PROTO((tree)); +static int is_base_type PROTO((tree)); +static dw_die_ref modified_type_die PROTO((tree, int, int, dw_die_ref)); +static int type_is_enum PROTO((tree)); +static dw_loc_descr_ref reg_loc_descriptor PROTO((rtx)); +static dw_loc_descr_ref based_loc_descr PROTO((unsigned, long)); +static int is_based_loc PROTO((rtx)); +static dw_loc_descr_ref mem_loc_descriptor PROTO((rtx)); +static dw_loc_descr_ref concat_loc_descriptor PROTO((rtx, rtx)); +static dw_loc_descr_ref loc_descriptor PROTO((rtx)); +static unsigned ceiling PROTO((unsigned, unsigned)); +static tree field_type PROTO((tree)); +static unsigned simple_type_align_in_bits PROTO((tree)); +static unsigned simple_type_size_in_bits PROTO((tree)); +static unsigned field_byte_offset PROTO((tree)); +static void add_AT_location_description PROTO((dw_die_ref, + enum dwarf_attribute, rtx)); +static void add_data_member_location_attribute PROTO((dw_die_ref, tree)); +static void add_const_value_attribute PROTO((dw_die_ref, rtx)); +static void add_location_or_const_value_attribute PROTO((dw_die_ref, tree)); +static void add_name_attribute PROTO((dw_die_ref, char *)); +static void add_bound_info PROTO((dw_die_ref, + enum dwarf_attribute, tree)); +static void add_subscript_info PROTO((dw_die_ref, tree)); +static void add_byte_size_attribute PROTO((dw_die_ref, tree)); +static void add_bit_offset_attribute PROTO((dw_die_ref, tree)); +static void add_bit_size_attribute PROTO((dw_die_ref, tree)); +static void add_prototyped_attribute PROTO((dw_die_ref, tree)); +static void add_abstract_origin_attribute PROTO((dw_die_ref, tree)); +static void add_pure_or_virtual_attribute PROTO((dw_die_ref, tree)); +static void add_src_coords_attributes PROTO((dw_die_ref, tree)); +static void add_name_and_src_coords_attributes PROTO((dw_die_ref, tree)); +static void push_decl_scope PROTO((tree)); +static dw_die_ref scope_die_for PROTO((tree, dw_die_ref)); +static void pop_decl_scope PROTO((void)); +static void add_type_attribute PROTO((dw_die_ref, tree, int, int, + dw_die_ref)); +static char *type_tag PROTO((tree)); +static tree member_declared_type PROTO((tree)); +#if 0 +static char *decl_start_label PROTO((tree)); +#endif +static void gen_array_type_die PROTO((tree, dw_die_ref)); +static void gen_set_type_die PROTO((tree, dw_die_ref)); +#if 0 +static void gen_entry_point_die PROTO((tree, dw_die_ref)); +#endif +static void pend_type PROTO((tree)); +static void output_pending_types_for_scope PROTO((dw_die_ref)); +static void gen_inlined_enumeration_type_die PROTO((tree, dw_die_ref)); +static void gen_inlined_structure_type_die PROTO((tree, dw_die_ref)); +static void gen_inlined_union_type_die PROTO((tree, dw_die_ref)); +static void gen_enumeration_type_die PROTO((tree, dw_die_ref)); +static dw_die_ref gen_formal_parameter_die PROTO((tree, dw_die_ref)); +static void gen_unspecified_parameters_die PROTO((tree, dw_die_ref)); +static void gen_formal_types_die PROTO((tree, dw_die_ref)); +static void gen_subprogram_die PROTO((tree, dw_die_ref)); +static void gen_variable_die PROTO((tree, dw_die_ref)); +static void gen_label_die PROTO((tree, dw_die_ref)); +static void gen_lexical_block_die PROTO((tree, dw_die_ref, int)); +static void gen_inlined_subroutine_die PROTO((tree, dw_die_ref, int)); +static void gen_field_die PROTO((tree, dw_die_ref)); +static void gen_ptr_to_mbr_type_die PROTO((tree, dw_die_ref)); +static void gen_compile_unit_die PROTO((char *)); +static void gen_string_type_die PROTO((tree, dw_die_ref)); +static void gen_inheritance_die PROTO((tree, dw_die_ref)); +static void gen_member_die PROTO((tree, dw_die_ref)); +static void gen_struct_or_union_type_die PROTO((tree, dw_die_ref)); +static void gen_subroutine_type_die PROTO((tree, dw_die_ref)); +static void gen_typedef_die PROTO((tree, dw_die_ref)); +static void gen_type_die PROTO((tree, dw_die_ref)); +static void gen_tagged_type_instantiation_die PROTO((tree, dw_die_ref)); +static void gen_block_die PROTO((tree, dw_die_ref, int)); +static void decls_for_scope PROTO((tree, dw_die_ref, int)); +static int is_redundant_typedef PROTO((tree)); +static void gen_decl_die PROTO((tree, dw_die_ref)); +static unsigned lookup_filename PROTO((char *)); + +/* Section names used to hold DWARF debugging information. */ +#ifndef DEBUG_INFO_SECTION +#define DEBUG_INFO_SECTION ".debug_info" +#endif +#ifndef ABBREV_SECTION +#define ABBREV_SECTION ".debug_abbrev" +#endif +#ifndef ARANGES_SECTION +#define ARANGES_SECTION ".debug_aranges" +#endif +#ifndef DW_MACINFO_SECTION +#define DW_MACINFO_SECTION ".debug_macinfo" +#endif +#ifndef DEBUG_LINE_SECTION +#define DEBUG_LINE_SECTION ".debug_line" +#endif +#ifndef LOC_SECTION +#define LOC_SECTION ".debug_loc" +#endif +#ifndef PUBNAMES_SECTION +#define PUBNAMES_SECTION ".debug_pubnames" +#endif +#ifndef STR_SECTION +#define STR_SECTION ".debug_str" +#endif + +/* Standard ELF section names for compiled code and data. */ +#ifndef TEXT_SECTION +#define TEXT_SECTION ".text" +#endif +#ifndef DATA_SECTION +#define DATA_SECTION ".data" +#endif +#ifndef BSS_SECTION +#define BSS_SECTION ".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 the tm.h file, but + typically, overriding these defaults is unnecessary. */ + +static char text_end_label[MAX_ARTIFICIAL_LABEL_BYTES]; + +#ifndef TEXT_END_LABEL +#define TEXT_END_LABEL "Letext" +#endif +#ifndef DATA_END_LABEL +#define DATA_END_LABEL "Ledata" +#endif +#ifndef BSS_END_LABEL +#define BSS_END_LABEL "Lebss" +#endif +#ifndef INSN_LABEL_FMT +#define INSN_LABEL_FMT "LI%u_" +#endif +#ifndef BLOCK_BEGIN_LABEL +#define BLOCK_BEGIN_LABEL "LBB" +#endif +#ifndef BLOCK_END_LABEL +#define BLOCK_END_LABEL "LBE" +#endif +#ifndef BODY_BEGIN_LABEL +#define BODY_BEGIN_LABEL "Lbb" +#endif +#ifndef BODY_END_LABEL +#define BODY_END_LABEL "Lbe" +#endif +#ifndef LINE_CODE_LABEL +#define LINE_CODE_LABEL "LM" +#endif +#ifndef SEPARATE_LINE_CODE_LABEL +#define SEPARATE_LINE_CODE_LABEL "LSM" +#endif + +/* Convert a reference to the assembler name of a C-level name. This + macro has the same effect as ASM_OUTPUT_LABELREF, but copies to + a string rather than writing to a file. */ +#ifndef ASM_NAME_TO_STRING +#define ASM_NAME_TO_STRING(STR, NAME) \ + do { \ + if ((NAME)[0] == '*') \ + dyn_string_append (STR, NAME + 1); \ + else \ + { \ + dyn_string_append (STR, user_label_prefix); \ + dyn_string_append (STR, NAME); \ + } \ + } \ + while (0) +#endif + +/* Convert an integer constant expression into assembler syntax. Addition + and subtraction are the only arithmetic that may appear in these + expressions. This is an adaptation of output_addr_const in final.c. + Here, the target of the conversion is a string buffer. We can't use + output_addr_const directly, because it writes to a file. */ + +static void +addr_const_to_string (str, x) + dyn_string_t str; + rtx x; +{ + char buf1[256]; + +restart: + switch (GET_CODE (x)) + { + case PC: + if (flag_pic) + dyn_string_append (str, ","); + else + abort (); + break; + + case SYMBOL_REF: + ASM_NAME_TO_STRING (str, XSTR (x, 0)); + break; + + case LABEL_REF: + ASM_GENERATE_INTERNAL_LABEL (buf1, "L", CODE_LABEL_NUMBER (XEXP (x, 0))); + ASM_NAME_TO_STRING (str, buf1); + break; + + case CODE_LABEL: + ASM_GENERATE_INTERNAL_LABEL (buf1, "L", CODE_LABEL_NUMBER (x)); + ASM_NAME_TO_STRING (str, buf1); + break; + + case CONST_INT: + sprintf (buf1, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); + dyn_string_append (str, buf1); + break; + + case CONST: + /* This used to output parentheses around the expression, but that does + not work on the 386 (either ATT or BSD assembler). */ + addr_const_to_string (str, XEXP (x, 0)); + break; + + case CONST_DOUBLE: + if (GET_MODE (x) == VOIDmode) + { + /* We can use %d if the number is one word and positive. */ + if (CONST_DOUBLE_HIGH (x)) + sprintf (buf1, HOST_WIDE_INT_PRINT_DOUBLE_HEX, + CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x)); + else if (CONST_DOUBLE_LOW (x) < 0) + sprintf (buf1, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x)); + else + sprintf (buf1, HOST_WIDE_INT_PRINT_DEC, + CONST_DOUBLE_LOW (x)); + dyn_string_append (str, buf1); + } + else + /* We can't handle floating point constants; PRINT_OPERAND must + handle them. */ + output_operand_lossage ("floating constant misused"); + break; + + case PLUS: + /* Some assemblers need integer constants to appear last (eg masm). */ + if (GET_CODE (XEXP (x, 0)) == CONST_INT) + { + addr_const_to_string (str, XEXP (x, 1)); + if (INTVAL (XEXP (x, 0)) >= 0) + dyn_string_append (str, "+"); + + addr_const_to_string (str, XEXP (x, 0)); + } + else + { + addr_const_to_string (str, XEXP (x, 0)); + if (INTVAL (XEXP (x, 1)) >= 0) + dyn_string_append (str, "+"); + + addr_const_to_string (str, XEXP (x, 1)); + } + break; + + case MINUS: + /* Avoid outputting things like x-x or x+5-x, since some assemblers + can't handle that. */ + x = simplify_subtraction (x); + if (GET_CODE (x) != MINUS) + goto restart; + + addr_const_to_string (str, XEXP (x, 0)); + dyn_string_append (str, "-"); + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) < 0) + { + dyn_string_append (str, ASM_OPEN_PAREN); + addr_const_to_string (str, XEXP (x, 1)); + dyn_string_append (str, ASM_CLOSE_PAREN); + } + else + addr_const_to_string (str, XEXP (x, 1)); + break; + + case ZERO_EXTEND: + case SIGN_EXTEND: + addr_const_to_string (str, XEXP (x, 0)); + break; + + default: + output_operand_lossage ("invalid expression as operand"); + } +} + +/* Convert an address constant to a string, and return a pointer to + a copy of the result, located on the heap. */ + +static char * +addr_to_string (x) + rtx x; +{ + dyn_string_t ds = dyn_string_new (256); + char *s; + + addr_const_to_string (ds, x); + + /* Return the dynamically allocated string, but free the + dyn_string_t itself. */ + s = ds->s; + free (ds); + return s; +} + +/* Test if rtl node points to a pseudo register. */ + +static inline int +is_pseudo_reg (rtl) + register rtx rtl; +{ + return (((GET_CODE (rtl) == REG) && (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)) + || ((GET_CODE (rtl) == SUBREG) + && (REGNO (XEXP (rtl, 0)) >= FIRST_PSEUDO_REGISTER))); +} + +/* Return a reference to a type, with its const and volatile qualifiers + removed. */ + +static inline tree +type_main_variant (type) + register 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 non-zero if the given type node represents a tagged type. */ + +static inline int +is_tagged_type (type) + register tree type; +{ + register enum tree_code code = TREE_CODE (type); + + return (code == RECORD_TYPE || code == UNION_TYPE + || code == QUAL_UNION_TYPE || code == ENUMERAL_TYPE); +} + +/* Convert a DIE tag into its string name. */ + +static char * +dwarf_tag_name (tag) + register unsigned tag; +{ + switch (tag) + { + case DW_TAG_padding: + return "DW_TAG_padding"; + case DW_TAG_array_type: + return "DW_TAG_array_type"; + case DW_TAG_class_type: + return "DW_TAG_class_type"; + case DW_TAG_entry_point: + return "DW_TAG_entry_point"; + case DW_TAG_enumeration_type: + return "DW_TAG_enumeration_type"; + case DW_TAG_formal_parameter: + return "DW_TAG_formal_parameter"; + case DW_TAG_imported_declaration: + return "DW_TAG_imported_declaration"; + case DW_TAG_label: + return "DW_TAG_label"; + case DW_TAG_lexical_block: + return "DW_TAG_lexical_block"; + case DW_TAG_member: + return "DW_TAG_member"; + case DW_TAG_pointer_type: + return "DW_TAG_pointer_type"; + case DW_TAG_reference_type: + return "DW_TAG_reference_type"; + case DW_TAG_compile_unit: + return "DW_TAG_compile_unit"; + case DW_TAG_string_type: + return "DW_TAG_string_type"; + case DW_TAG_structure_type: + return "DW_TAG_structure_type"; + case DW_TAG_subroutine_type: + return "DW_TAG_subroutine_type"; + case DW_TAG_typedef: + return "DW_TAG_typedef"; + case DW_TAG_union_type: + return "DW_TAG_union_type"; + case DW_TAG_unspecified_parameters: + return "DW_TAG_unspecified_parameters"; + case DW_TAG_variant: + return "DW_TAG_variant"; + case DW_TAG_common_block: + return "DW_TAG_common_block"; + case DW_TAG_common_inclusion: + return "DW_TAG_common_inclusion"; + case DW_TAG_inheritance: + return "DW_TAG_inheritance"; + case DW_TAG_inlined_subroutine: + return "DW_TAG_inlined_subroutine"; + case DW_TAG_module: + return "DW_TAG_module"; + case DW_TAG_ptr_to_member_type: + return "DW_TAG_ptr_to_member_type"; + case DW_TAG_set_type: + return "DW_TAG_set_type"; + case DW_TAG_subrange_type: + return "DW_TAG_subrange_type"; + case DW_TAG_with_stmt: + return "DW_TAG_with_stmt"; + case DW_TAG_access_declaration: + return "DW_TAG_access_declaration"; + case DW_TAG_base_type: + return "DW_TAG_base_type"; + case DW_TAG_catch_block: + return "DW_TAG_catch_block"; + case DW_TAG_const_type: + return "DW_TAG_const_type"; + case DW_TAG_constant: + return "DW_TAG_constant"; + case DW_TAG_enumerator: + return "DW_TAG_enumerator"; + case DW_TAG_file_type: + return "DW_TAG_file_type"; + case DW_TAG_friend: + return "DW_TAG_friend"; + case DW_TAG_namelist: + return "DW_TAG_namelist"; + case DW_TAG_namelist_item: + return "DW_TAG_namelist_item"; + case DW_TAG_packed_type: + return "DW_TAG_packed_type"; + case DW_TAG_subprogram: + return "DW_TAG_subprogram"; + case DW_TAG_template_type_param: + return "DW_TAG_template_type_param"; + case DW_TAG_template_value_param: + return "DW_TAG_template_value_param"; + case DW_TAG_thrown_type: + return "DW_TAG_thrown_type"; + case DW_TAG_try_block: + return "DW_TAG_try_block"; + case DW_TAG_variant_part: + return "DW_TAG_variant_part"; + case DW_TAG_variable: + return "DW_TAG_variable"; + case DW_TAG_volatile_type: + return "DW_TAG_volatile_type"; + case DW_TAG_MIPS_loop: + return "DW_TAG_MIPS_loop"; + case DW_TAG_format_label: + return "DW_TAG_format_label"; + case DW_TAG_function_template: + return "DW_TAG_function_template"; + case DW_TAG_class_template: + return "DW_TAG_class_template"; + default: + return "DW_TAG_"; + } +} + +/* Convert a DWARF attribute code into its string name. */ + +static char * +dwarf_attr_name (attr) + register unsigned attr; +{ + switch (attr) + { + case DW_AT_sibling: + return "DW_AT_sibling"; + case DW_AT_location: + return "DW_AT_location"; + case DW_AT_name: + return "DW_AT_name"; + case DW_AT_ordering: + return "DW_AT_ordering"; + case DW_AT_subscr_data: + return "DW_AT_subscr_data"; + case DW_AT_byte_size: + return "DW_AT_byte_size"; + case DW_AT_bit_offset: + return "DW_AT_bit_offset"; + case DW_AT_bit_size: + return "DW_AT_bit_size"; + case DW_AT_element_list: + return "DW_AT_element_list"; + case DW_AT_stmt_list: + return "DW_AT_stmt_list"; + case DW_AT_low_pc: + return "DW_AT_low_pc"; + case DW_AT_high_pc: + return "DW_AT_high_pc"; + case DW_AT_language: + return "DW_AT_language"; + case DW_AT_member: + return "DW_AT_member"; + case DW_AT_discr: + return "DW_AT_discr"; + case DW_AT_discr_value: + return "DW_AT_discr_value"; + case DW_AT_visibility: + return "DW_AT_visibility"; + case DW_AT_import: + return "DW_AT_import"; + case DW_AT_string_length: + return "DW_AT_string_length"; + case DW_AT_common_reference: + return "DW_AT_common_reference"; + case DW_AT_comp_dir: + return "DW_AT_comp_dir"; + case DW_AT_const_value: + return "DW_AT_const_value"; + case DW_AT_containing_type: + return "DW_AT_containing_type"; + case DW_AT_default_value: + return "DW_AT_default_value"; + case DW_AT_inline: + return "DW_AT_inline"; + case DW_AT_is_optional: + return "DW_AT_is_optional"; + case DW_AT_lower_bound: + return "DW_AT_lower_bound"; + case DW_AT_producer: + return "DW_AT_producer"; + case DW_AT_prototyped: + return "DW_AT_prototyped"; + case DW_AT_return_addr: + return "DW_AT_return_addr"; + case DW_AT_start_scope: + return "DW_AT_start_scope"; + case DW_AT_stride_size: + return "DW_AT_stride_size"; + case DW_AT_upper_bound: + return "DW_AT_upper_bound"; + case DW_AT_abstract_origin: + return "DW_AT_abstract_origin"; + case DW_AT_accessibility: + return "DW_AT_accessibility"; + case DW_AT_address_class: + return "DW_AT_address_class"; + case DW_AT_artificial: + return "DW_AT_artificial"; + case DW_AT_base_types: + return "DW_AT_base_types"; + case DW_AT_calling_convention: + return "DW_AT_calling_convention"; + case DW_AT_count: + return "DW_AT_count"; + case DW_AT_data_member_location: + return "DW_AT_data_member_location"; + case DW_AT_decl_column: + return "DW_AT_decl_column"; + case DW_AT_decl_file: + return "DW_AT_decl_file"; + case DW_AT_decl_line: + return "DW_AT_decl_line"; + case DW_AT_declaration: + return "DW_AT_declaration"; + case DW_AT_discr_list: + return "DW_AT_discr_list"; + case DW_AT_encoding: + return "DW_AT_encoding"; + case DW_AT_external: + return "DW_AT_external"; + case DW_AT_frame_base: + return "DW_AT_frame_base"; + case DW_AT_friend: + return "DW_AT_friend"; + case DW_AT_identifier_case: + return "DW_AT_identifier_case"; + case DW_AT_macro_info: + return "DW_AT_macro_info"; + case DW_AT_namelist_items: + return "DW_AT_namelist_items"; + case DW_AT_priority: + return "DW_AT_priority"; + case DW_AT_segment: + return "DW_AT_segment"; + case DW_AT_specification: + return "DW_AT_specification"; + case DW_AT_static_link: + return "DW_AT_static_link"; + case DW_AT_type: + return "DW_AT_type"; + case DW_AT_use_location: + return "DW_AT_use_location"; + case DW_AT_variable_parameter: + return "DW_AT_variable_parameter"; + case DW_AT_virtuality: + return "DW_AT_virtuality"; + case DW_AT_vtable_elem_location: + return "DW_AT_vtable_elem_location"; + + case DW_AT_MIPS_fde: + return "DW_AT_MIPS_fde"; + case DW_AT_MIPS_loop_begin: + return "DW_AT_MIPS_loop_begin"; + case DW_AT_MIPS_tail_loop_begin: + return "DW_AT_MIPS_tail_loop_begin"; + case DW_AT_MIPS_epilog_begin: + return "DW_AT_MIPS_epilog_begin"; + case DW_AT_MIPS_loop_unroll_factor: + return "DW_AT_MIPS_loop_unroll_factor"; + case DW_AT_MIPS_software_pipeline_depth: + return "DW_AT_MIPS_software_pipeline_depth"; + case DW_AT_MIPS_linkage_name: + return "DW_AT_MIPS_linkage_name"; + case DW_AT_MIPS_stride: + return "DW_AT_MIPS_stride"; + case DW_AT_MIPS_abstract_name: + return "DW_AT_MIPS_abstract_name"; + case DW_AT_MIPS_clone_origin: + return "DW_AT_MIPS_clone_origin"; + case DW_AT_MIPS_has_inlines: + return "DW_AT_MIPS_has_inlines"; + + case DW_AT_sf_names: + return "DW_AT_sf_names"; + case DW_AT_src_info: + return "DW_AT_src_info"; + case DW_AT_mac_info: + return "DW_AT_mac_info"; + case DW_AT_src_coords: + return "DW_AT_src_coords"; + case DW_AT_body_begin: + return "DW_AT_body_begin"; + case DW_AT_body_end: + return "DW_AT_body_end"; + default: + return "DW_AT_"; + } +} + +/* Convert a DWARF value form code into its string name. */ + +static char * +dwarf_form_name (form) + register unsigned form; +{ + switch (form) + { + case DW_FORM_addr: + return "DW_FORM_addr"; + case DW_FORM_block2: + return "DW_FORM_block2"; + case DW_FORM_block4: + return "DW_FORM_block4"; + case DW_FORM_data2: + return "DW_FORM_data2"; + case DW_FORM_data4: + return "DW_FORM_data4"; + case DW_FORM_data8: + return "DW_FORM_data8"; + case DW_FORM_string: + return "DW_FORM_string"; + case DW_FORM_block: + return "DW_FORM_block"; + case DW_FORM_block1: + return "DW_FORM_block1"; + case DW_FORM_data1: + return "DW_FORM_data1"; + case DW_FORM_flag: + return "DW_FORM_flag"; + case DW_FORM_sdata: + return "DW_FORM_sdata"; + case DW_FORM_strp: + return "DW_FORM_strp"; + case DW_FORM_udata: + return "DW_FORM_udata"; + case DW_FORM_ref_addr: + return "DW_FORM_ref_addr"; + case DW_FORM_ref1: + return "DW_FORM_ref1"; + case DW_FORM_ref2: + return "DW_FORM_ref2"; + case DW_FORM_ref4: + return "DW_FORM_ref4"; + case DW_FORM_ref8: + return "DW_FORM_ref8"; + case DW_FORM_ref_udata: + return "DW_FORM_ref_udata"; + case DW_FORM_indirect: + return "DW_FORM_indirect"; + default: + return "DW_FORM_"; + } +} + +/* Convert a DWARF stack opcode into its string name. */ + +static char * +dwarf_stack_op_name (op) + register unsigned op; +{ + switch (op) + { + case DW_OP_addr: + return "DW_OP_addr"; + case DW_OP_deref: + return "DW_OP_deref"; + case DW_OP_const1u: + return "DW_OP_const1u"; + case DW_OP_const1s: + return "DW_OP_const1s"; + case DW_OP_const2u: + return "DW_OP_const2u"; + case DW_OP_const2s: + return "DW_OP_const2s"; + case DW_OP_const4u: + return "DW_OP_const4u"; + case DW_OP_const4s: + return "DW_OP_const4s"; + case DW_OP_const8u: + return "DW_OP_const8u"; + case DW_OP_const8s: + return "DW_OP_const8s"; + case DW_OP_constu: + return "DW_OP_constu"; + case DW_OP_consts: + return "DW_OP_consts"; + case DW_OP_dup: + return "DW_OP_dup"; + case DW_OP_drop: + return "DW_OP_drop"; + case DW_OP_over: + return "DW_OP_over"; + case DW_OP_pick: + return "DW_OP_pick"; + case DW_OP_swap: + return "DW_OP_swap"; + case DW_OP_rot: + return "DW_OP_rot"; + case DW_OP_xderef: + return "DW_OP_xderef"; + case DW_OP_abs: + return "DW_OP_abs"; + case DW_OP_and: + return "DW_OP_and"; + case DW_OP_div: + return "DW_OP_div"; + case DW_OP_minus: + return "DW_OP_minus"; + case DW_OP_mod: + return "DW_OP_mod"; + case DW_OP_mul: + return "DW_OP_mul"; + case DW_OP_neg: + return "DW_OP_neg"; + case DW_OP_not: + return "DW_OP_not"; + case DW_OP_or: + return "DW_OP_or"; + case DW_OP_plus: + return "DW_OP_plus"; + case DW_OP_plus_uconst: + return "DW_OP_plus_uconst"; + case DW_OP_shl: + return "DW_OP_shl"; + case DW_OP_shr: + return "DW_OP_shr"; + case DW_OP_shra: + return "DW_OP_shra"; + case DW_OP_xor: + return "DW_OP_xor"; + case DW_OP_bra: + return "DW_OP_bra"; + case DW_OP_eq: + return "DW_OP_eq"; + case DW_OP_ge: + return "DW_OP_ge"; + case DW_OP_gt: + return "DW_OP_gt"; + case DW_OP_le: + return "DW_OP_le"; + case DW_OP_lt: + return "DW_OP_lt"; + case DW_OP_ne: + return "DW_OP_ne"; + case DW_OP_skip: + return "DW_OP_skip"; + case DW_OP_lit0: + return "DW_OP_lit0"; + case DW_OP_lit1: + return "DW_OP_lit1"; + case DW_OP_lit2: + return "DW_OP_lit2"; + case DW_OP_lit3: + return "DW_OP_lit3"; + case DW_OP_lit4: + return "DW_OP_lit4"; + case DW_OP_lit5: + return "DW_OP_lit5"; + case DW_OP_lit6: + return "DW_OP_lit6"; + case DW_OP_lit7: + return "DW_OP_lit7"; + case DW_OP_lit8: + return "DW_OP_lit8"; + case DW_OP_lit9: + return "DW_OP_lit9"; + case DW_OP_lit10: + return "DW_OP_lit10"; + case DW_OP_lit11: + return "DW_OP_lit11"; + case DW_OP_lit12: + return "DW_OP_lit12"; + case DW_OP_lit13: + return "DW_OP_lit13"; + case DW_OP_lit14: + return "DW_OP_lit14"; + case DW_OP_lit15: + return "DW_OP_lit15"; + case DW_OP_lit16: + return "DW_OP_lit16"; + case DW_OP_lit17: + return "DW_OP_lit17"; + case DW_OP_lit18: + return "DW_OP_lit18"; + case DW_OP_lit19: + return "DW_OP_lit19"; + case DW_OP_lit20: + return "DW_OP_lit20"; + case DW_OP_lit21: + return "DW_OP_lit21"; + case DW_OP_lit22: + return "DW_OP_lit22"; + case DW_OP_lit23: + return "DW_OP_lit23"; + case DW_OP_lit24: + return "DW_OP_lit24"; + case DW_OP_lit25: + return "DW_OP_lit25"; + case DW_OP_lit26: + return "DW_OP_lit26"; + case DW_OP_lit27: + return "DW_OP_lit27"; + case DW_OP_lit28: + return "DW_OP_lit28"; + case DW_OP_lit29: + return "DW_OP_lit29"; + case DW_OP_lit30: + return "DW_OP_lit30"; + case DW_OP_lit31: + return "DW_OP_lit31"; + case DW_OP_reg0: + return "DW_OP_reg0"; + case DW_OP_reg1: + return "DW_OP_reg1"; + case DW_OP_reg2: + return "DW_OP_reg2"; + case DW_OP_reg3: + return "DW_OP_reg3"; + case DW_OP_reg4: + return "DW_OP_reg4"; + case DW_OP_reg5: + return "DW_OP_reg5"; + case DW_OP_reg6: + return "DW_OP_reg6"; + case DW_OP_reg7: + return "DW_OP_reg7"; + case DW_OP_reg8: + return "DW_OP_reg8"; + case DW_OP_reg9: + return "DW_OP_reg9"; + case DW_OP_reg10: + return "DW_OP_reg10"; + case DW_OP_reg11: + return "DW_OP_reg11"; + case DW_OP_reg12: + return "DW_OP_reg12"; + case DW_OP_reg13: + return "DW_OP_reg13"; + case DW_OP_reg14: + return "DW_OP_reg14"; + case DW_OP_reg15: + return "DW_OP_reg15"; + case DW_OP_reg16: + return "DW_OP_reg16"; + case DW_OP_reg17: + return "DW_OP_reg17"; + case DW_OP_reg18: + return "DW_OP_reg18"; + case DW_OP_reg19: + return "DW_OP_reg19"; + case DW_OP_reg20: + return "DW_OP_reg20"; + case DW_OP_reg21: + return "DW_OP_reg21"; + case DW_OP_reg22: + return "DW_OP_reg22"; + case DW_OP_reg23: + return "DW_OP_reg23"; + case DW_OP_reg24: + return "DW_OP_reg24"; + case DW_OP_reg25: + return "DW_OP_reg25"; + case DW_OP_reg26: + return "DW_OP_reg26"; + case DW_OP_reg27: + return "DW_OP_reg27"; + case DW_OP_reg28: + return "DW_OP_reg28"; + case DW_OP_reg29: + return "DW_OP_reg29"; + case DW_OP_reg30: + return "DW_OP_reg30"; + case DW_OP_reg31: + return "DW_OP_reg31"; + case DW_OP_breg0: + return "DW_OP_breg0"; + case DW_OP_breg1: + return "DW_OP_breg1"; + case DW_OP_breg2: + return "DW_OP_breg2"; + case DW_OP_breg3: + return "DW_OP_breg3"; + case DW_OP_breg4: + return "DW_OP_breg4"; + case DW_OP_breg5: + return "DW_OP_breg5"; + case DW_OP_breg6: + return "DW_OP_breg6"; + case DW_OP_breg7: + return "DW_OP_breg7"; + case DW_OP_breg8: + return "DW_OP_breg8"; + case DW_OP_breg9: + return "DW_OP_breg9"; + case DW_OP_breg10: + return "DW_OP_breg10"; + case DW_OP_breg11: + return "DW_OP_breg11"; + case DW_OP_breg12: + return "DW_OP_breg12"; + case DW_OP_breg13: + return "DW_OP_breg13"; + case DW_OP_breg14: + return "DW_OP_breg14"; + case DW_OP_breg15: + return "DW_OP_breg15"; + case DW_OP_breg16: + return "DW_OP_breg16"; + case DW_OP_breg17: + return "DW_OP_breg17"; + case DW_OP_breg18: + return "DW_OP_breg18"; + case DW_OP_breg19: + return "DW_OP_breg19"; + case DW_OP_breg20: + return "DW_OP_breg20"; + case DW_OP_breg21: + return "DW_OP_breg21"; + case DW_OP_breg22: + return "DW_OP_breg22"; + case DW_OP_breg23: + return "DW_OP_breg23"; + case DW_OP_breg24: + return "DW_OP_breg24"; + case DW_OP_breg25: + return "DW_OP_breg25"; + case DW_OP_breg26: + return "DW_OP_breg26"; + case DW_OP_breg27: + return "DW_OP_breg27"; + case DW_OP_breg28: + return "DW_OP_breg28"; + case DW_OP_breg29: + return "DW_OP_breg29"; + case DW_OP_breg30: + return "DW_OP_breg30"; + case DW_OP_breg31: + return "DW_OP_breg31"; + case DW_OP_regx: + return "DW_OP_regx"; + case DW_OP_fbreg: + return "DW_OP_fbreg"; + case DW_OP_bregx: + return "DW_OP_bregx"; + case DW_OP_piece: + return "DW_OP_piece"; + case DW_OP_deref_size: + return "DW_OP_deref_size"; + case DW_OP_xderef_size: + return "DW_OP_xderef_size"; + case DW_OP_nop: + return "DW_OP_nop"; + default: + return "OP_"; + } +} + +/* Convert a DWARF type code into its string name. */ + +#if 0 +static char * +dwarf_type_encoding_name (enc) + register unsigned enc; +{ + switch (enc) + { + case DW_ATE_address: + return "DW_ATE_address"; + case DW_ATE_boolean: + return "DW_ATE_boolean"; + case DW_ATE_complex_float: + return "DW_ATE_complex_float"; + case DW_ATE_float: + return "DW_ATE_float"; + case DW_ATE_signed: + return "DW_ATE_signed"; + case DW_ATE_signed_char: + return "DW_ATE_signed_char"; + case DW_ATE_unsigned: + return "DW_ATE_unsigned"; + case DW_ATE_unsigned_char: + return "DW_ATE_unsigned_char"; + default: + return "DW_ATE_"; + } +} +#endif + +/* 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) + register 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) + register tree block; +{ + register tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block); + + if (immediate_origin == NULL_TREE) + return NULL_TREE; + else + { + register tree ret_val; + register 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 && TREE_CODE_CLASS (TREE_CODE (context)) != 't') + context = NULL_TREE; + + return context; +} + +/* Add an attribute/value pair to a DIE */ + +static inline void +add_dwarf_attr (die, attr) + register dw_die_ref die; + register dw_attr_ref attr; +{ + if (die != NULL && attr != NULL) + { + if (die->die_attr == NULL) + { + die->die_attr = attr; + die->die_attr_last = attr; + } + else + { + die->die_attr_last->dw_attr_next = attr; + die->die_attr_last = attr; + } + } +} + +/* Add a flag value attribute to a DIE. */ + +static inline void +add_AT_flag (die, attr_kind, flag) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register unsigned flag; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_flag; + attr->dw_attr_val.v.val_flag = flag; + add_dwarf_attr (die, attr); +} + +/* Add a signed integer attribute value to a DIE. */ + +static inline void +add_AT_int (die, attr_kind, int_val) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register long int int_val; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_const; + attr->dw_attr_val.v.val_int = int_val; + add_dwarf_attr (die, attr); +} + +/* Add an unsigned integer attribute value to a DIE. */ + +static inline void +add_AT_unsigned (die, attr_kind, unsigned_val) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register unsigned long unsigned_val; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_unsigned_const; + attr->dw_attr_val.v.val_unsigned = unsigned_val; + add_dwarf_attr (die, attr); +} + +/* Add an unsigned double integer attribute value to a DIE. */ + +static inline void +add_AT_long_long (die, attr_kind, val_hi, val_low) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register unsigned long val_hi; + register unsigned long val_low; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_long_long; + attr->dw_attr_val.v.val_long_long.hi = val_hi; + attr->dw_attr_val.v.val_long_long.low = val_low; + add_dwarf_attr (die, attr); +} + +/* Add a floating point attribute value to a DIE and return it. */ + +static inline void +add_AT_float (die, attr_kind, length, array) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register unsigned length; + register long *array; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_float; + attr->dw_attr_val.v.val_float.length = length; + attr->dw_attr_val.v.val_float.array = array; + add_dwarf_attr (die, attr); +} + +/* Add a string attribute value to a DIE. */ + +static inline void +add_AT_string (die, attr_kind, str) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register char *str; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_str; + attr->dw_attr_val.v.val_str = xstrdup (str); + add_dwarf_attr (die, attr); +} + +/* Add a DIE reference attribute value to a DIE. */ + +static inline void +add_AT_die_ref (die, attr_kind, targ_die) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register dw_die_ref targ_die; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_die_ref; + attr->dw_attr_val.v.val_die_ref = targ_die; + add_dwarf_attr (die, attr); +} + +/* Add an FDE reference attribute value to a DIE. */ + +static inline void +add_AT_fde_ref (die, attr_kind, targ_fde) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register unsigned targ_fde; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_fde_ref; + attr->dw_attr_val.v.val_fde_index = targ_fde; + add_dwarf_attr (die, attr); +} + +/* Add a location description attribute value to a DIE. */ + +static inline void +add_AT_loc (die, attr_kind, loc) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register dw_loc_descr_ref loc; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_loc; + attr->dw_attr_val.v.val_loc = loc; + add_dwarf_attr (die, attr); +} + +/* Add an address constant attribute value to a DIE. */ + +static inline void +add_AT_addr (die, attr_kind, addr) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + char *addr; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_addr; + attr->dw_attr_val.v.val_addr = addr; + add_dwarf_attr (die, attr); +} + +/* Add a label identifier attribute value to a DIE. */ + +static inline void +add_AT_lbl_id (die, attr_kind, lbl_id) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register char *lbl_id; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_lbl_id; + attr->dw_attr_val.v.val_lbl_id = xstrdup (lbl_id); + add_dwarf_attr (die, attr); +} + +/* Add a section offset attribute value to a DIE. */ + +static inline void +add_AT_section_offset (die, attr_kind, section) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register char *section; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_section_offset; + attr->dw_attr_val.v.val_section = section; + add_dwarf_attr (die, attr); + +} + +/* Test if die refers to an external subroutine. */ + +static inline int +is_extern_subr_die (die) + register dw_die_ref die; +{ + register dw_attr_ref a; + register int is_subr = FALSE; + register int is_extern = FALSE; + + if (die != NULL && die->die_tag == DW_TAG_subprogram) + { + is_subr = TRUE; + for (a = die->die_attr; a != NULL; a = a->dw_attr_next) + { + if (a->dw_attr == DW_AT_external + && a->dw_attr_val.val_class == dw_val_class_flag + && a->dw_attr_val.v.val_flag != 0) + { + is_extern = TRUE; + break; + } + } + } + + return is_subr && is_extern; +} + +/* Get the attribute of type attr_kind. */ + +static inline dw_attr_ref +get_AT (die, attr_kind) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; +{ + register dw_attr_ref a; + register dw_die_ref spec = NULL; + + if (die != NULL) + { + for (a = die->die_attr; a != NULL; a = a->dw_attr_next) + { + if (a->dw_attr == attr_kind) + return a; + + if (a->dw_attr == DW_AT_specification + || a->dw_attr == DW_AT_abstract_origin) + spec = a->dw_attr_val.v.val_die_ref; + } + + if (spec) + return get_AT (spec, attr_kind); + } + + return NULL; +} + +/* Return the "low pc" attribute value, typically associated with + a subprogram DIE. Return null if the "low pc" attribute is + either not prsent, or if it cannot be represented as an + assembler label identifier. */ + +static inline char * +get_AT_low_pc (die) + register dw_die_ref die; +{ + register dw_attr_ref a = get_AT (die, DW_AT_low_pc); + + if (a && a->dw_attr_val.val_class == dw_val_class_lbl_id) + return a->dw_attr_val.v.val_lbl_id; + + return NULL; +} + +/* Return the "high pc" attribute value, typically associated with + a subprogram DIE. Return null if the "high pc" attribute is + either not prsent, or if it cannot be represented as an + assembler label identifier. */ + +static inline char * +get_AT_hi_pc (die) + register dw_die_ref die; +{ + register dw_attr_ref a = get_AT (die, DW_AT_high_pc); + + if (a && a->dw_attr_val.val_class == dw_val_class_lbl_id) + return a->dw_attr_val.v.val_lbl_id; + + return NULL; +} + +/* Return the value of the string attribute designated by ATTR_KIND, or + NULL if it is not present. */ + +static inline char * +get_AT_string (die, attr_kind) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; +{ + register dw_attr_ref a = get_AT (die, attr_kind); + + if (a && a->dw_attr_val.val_class == dw_val_class_str) + return a->dw_attr_val.v.val_str; + + return NULL; +} + +/* Return the value of the flag attribute designated by ATTR_KIND, or -1 + if it is not present. */ + +static inline int +get_AT_flag (die, attr_kind) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; +{ + register dw_attr_ref a = get_AT (die, attr_kind); + + if (a && a->dw_attr_val.val_class == dw_val_class_flag) + return a->dw_attr_val.v.val_flag; + + return -1; +} + +/* Return the value of the unsigned attribute designated by ATTR_KIND, or 0 + if it is not present. */ + +static inline unsigned +get_AT_unsigned (die, attr_kind) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; +{ + register dw_attr_ref a = get_AT (die, attr_kind); + + if (a && a->dw_attr_val.val_class == dw_val_class_unsigned_const) + return a->dw_attr_val.v.val_unsigned; + + return 0; +} + +static inline int +is_c_family () +{ + register unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language); + + return (lang == DW_LANG_C || lang == DW_LANG_C89 + || lang == DW_LANG_C_plus_plus); +} + +static inline int +is_fortran () +{ + register unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language); + + return (lang == DW_LANG_Fortran77 || lang == DW_LANG_Fortran90); +} + +/* Remove the specified attribute if present. */ + +static inline void +remove_AT (die, attr_kind) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; +{ + register dw_attr_ref a; + register dw_attr_ref removed = NULL;; + + if (die != NULL) + { + if (die->die_attr->dw_attr == attr_kind) + { + removed = die->die_attr; + if (die->die_attr_last == die->die_attr) + die->die_attr_last = NULL; + + die->die_attr = die->die_attr->dw_attr_next; + } + + else + for (a = die->die_attr; a->dw_attr_next != NULL; + a = a->dw_attr_next) + if (a->dw_attr_next->dw_attr == attr_kind) + { + removed = a->dw_attr_next; + if (die->die_attr_last == a->dw_attr_next) + die->die_attr_last = a; + + a->dw_attr_next = a->dw_attr_next->dw_attr_next; + break; + } + + if (removed != 0) + free (removed); + } +} + +/* Discard the children of this DIE. */ + +static inline void +remove_children (die) + register dw_die_ref die; +{ + register dw_die_ref child_die = die->die_child; + + die->die_child = NULL; + die->die_child_last = NULL; + + while (child_die != NULL) + { + register dw_die_ref tmp_die = child_die; + register dw_attr_ref a; + + child_die = child_die->die_sib; + + for (a = tmp_die->die_attr; a != NULL; ) + { + register dw_attr_ref tmp_a = a; + + a = a->dw_attr_next; + free (tmp_a); + } + + free (tmp_die); + } +} + +/* Add a child DIE below its parent. */ + +static inline void +add_child_die (die, child_die) + register dw_die_ref die; + register dw_die_ref child_die; +{ + if (die != NULL && child_die != NULL) + { + if (die == child_die) + abort (); + child_die->die_parent = die; + child_die->die_sib = NULL; + + if (die->die_child == NULL) + { + die->die_child = child_die; + die->die_child_last = child_die; + } + else + { + die->die_child_last->die_sib = child_die; + die->die_child_last = child_die; + } + } +} + +/* Return a pointer to a newly created DIE node. */ + +static inline dw_die_ref +new_die (tag_value, parent_die) + register enum dwarf_tag tag_value; + register dw_die_ref parent_die; +{ + register dw_die_ref die = (dw_die_ref) xmalloc (sizeof (die_node)); + + die->die_tag = tag_value; + die->die_abbrev = 0; + die->die_offset = 0; + die->die_child = NULL; + die->die_parent = NULL; + die->die_sib = NULL; + die->die_child_last = NULL; + die->die_attr = NULL; + die->die_attr_last = NULL; + + if (parent_die != NULL) + add_child_die (parent_die, die); + else + { + limbo_die_node *limbo_node; + + limbo_node = (limbo_die_node *) xmalloc (sizeof (limbo_die_node)); + limbo_node->die = die; + limbo_node->next = limbo_die_list; + limbo_die_list = limbo_node; + } + + return die; +} + +/* Return the DIE associated with the given type specifier. */ + +static inline dw_die_ref +lookup_type_die (type) + register tree type; +{ + return (dw_die_ref) TYPE_SYMTAB_POINTER (type); +} + +/* Equate a DIE to a given type specifier. */ + +static void +equate_type_number_to_die (type, type_die) + register tree type; + register dw_die_ref type_die; +{ + TYPE_SYMTAB_POINTER (type) = (char *) type_die; +} + +/* Return the DIE associated with a given declaration. */ + +static inline dw_die_ref +lookup_decl_die (decl) + register tree decl; +{ + register unsigned decl_id = DECL_UID (decl); + + return (decl_id < decl_die_table_in_use + ? decl_die_table[decl_id] : NULL); +} + +/* Equate a DIE to a particular declaration. */ + +static void +equate_decl_number_to_die (decl, decl_die) + register tree decl; + register dw_die_ref decl_die; +{ + register unsigned decl_id = DECL_UID (decl); + register unsigned num_allocated; + + if (decl_id >= decl_die_table_allocated) + { + num_allocated + = ((decl_id + 1 + DECL_DIE_TABLE_INCREMENT - 1) + / DECL_DIE_TABLE_INCREMENT) + * DECL_DIE_TABLE_INCREMENT; + + decl_die_table + = (dw_die_ref *) xrealloc (decl_die_table, + sizeof (dw_die_ref) * num_allocated); + + bzero ((char *) &decl_die_table[decl_die_table_allocated], + (num_allocated - decl_die_table_allocated) * sizeof (dw_die_ref)); + decl_die_table_allocated = num_allocated; + } + + if (decl_id >= decl_die_table_in_use) + decl_die_table_in_use = (decl_id + 1); + + decl_die_table[decl_id] = decl_die; +} + +/* Return a pointer to a newly allocated location description. Location + descriptions are simple expression terms that can be strung + together to form more complicated location (address) descriptions. */ + +static inline dw_loc_descr_ref +new_loc_descr (op, oprnd1, oprnd2) + register enum dwarf_location_atom op; + register unsigned long oprnd1; + register unsigned long oprnd2; +{ + register dw_loc_descr_ref descr + = (dw_loc_descr_ref) xmalloc (sizeof (dw_loc_descr_node)); + + descr->dw_loc_next = NULL; + descr->dw_loc_opc = op; + descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const; + descr->dw_loc_oprnd1.v.val_unsigned = oprnd1; + descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const; + descr->dw_loc_oprnd2.v.val_unsigned = oprnd2; + + return descr; +} + +/* Add a location description term to a location description expression. */ + +static inline void +add_loc_descr (list_head, descr) + register dw_loc_descr_ref *list_head; + register dw_loc_descr_ref descr; +{ + register dw_loc_descr_ref *d; + + /* Find the end of the chain. */ + for (d = list_head; (*d) != NULL; d = &(*d)->dw_loc_next) + ; + + *d = descr; +} + +/* Keep track of the number of spaces used to indent the + output of the debugging routines that print the structure of + the DIE internal representation. */ +static int print_indent; + +/* Indent the line the number of spaces given by print_indent. */ + +static inline void +print_spaces (outfile) + FILE *outfile; +{ + fprintf (outfile, "%*s", print_indent, ""); +} + +/* Print the information associated with a given DIE, and its children. + This routine is a debugging aid only. */ + +static void +print_die (die, outfile) + dw_die_ref die; + FILE *outfile; +{ + register dw_attr_ref a; + register dw_die_ref c; + + print_spaces (outfile); + fprintf (outfile, "DIE %4lu: %s\n", + die->die_offset, dwarf_tag_name (die->die_tag)); + print_spaces (outfile); + fprintf (outfile, " abbrev id: %lu", die->die_abbrev); + fprintf (outfile, " offset: %lu\n", die->die_offset); + + for (a = die->die_attr; a != NULL; a = a->dw_attr_next) + { + print_spaces (outfile); + fprintf (outfile, " %s: ", dwarf_attr_name (a->dw_attr)); + + switch (a->dw_attr_val.val_class) + { + case dw_val_class_addr: + fprintf (outfile, "address"); + break; + case dw_val_class_loc: + fprintf (outfile, "location descriptor"); + break; + case dw_val_class_const: + fprintf (outfile, "%ld", a->dw_attr_val.v.val_int); + break; + case dw_val_class_unsigned_const: + fprintf (outfile, "%lu", a->dw_attr_val.v.val_unsigned); + break; + case dw_val_class_long_long: + fprintf (outfile, "constant (%lu,%lu)", + a->dw_attr_val.v.val_long_long.hi, + a->dw_attr_val.v.val_long_long.low); + break; + case dw_val_class_float: + fprintf (outfile, "floating-point constant"); + break; + case dw_val_class_flag: + fprintf (outfile, "%u", a->dw_attr_val.v.val_flag); + break; + case dw_val_class_die_ref: + if (a->dw_attr_val.v.val_die_ref != NULL) + fprintf (outfile, "die -> %lu", + a->dw_attr_val.v.val_die_ref->die_offset); + else + fprintf (outfile, "die -> "); + break; + case dw_val_class_lbl_id: + fprintf (outfile, "label: %s", a->dw_attr_val.v.val_lbl_id); + break; + case dw_val_class_section_offset: + fprintf (outfile, "section: %s", a->dw_attr_val.v.val_section); + break; + case dw_val_class_str: + if (a->dw_attr_val.v.val_str != NULL) + fprintf (outfile, "\"%s\"", a->dw_attr_val.v.val_str); + else + fprintf (outfile, ""); + break; + default: + break; + } + + fprintf (outfile, "\n"); + } + + if (die->die_child != NULL) + { + print_indent += 4; + for (c = die->die_child; c != NULL; c = c->die_sib) + print_die (c, outfile); + + print_indent -= 4; + } +} + +/* Print the contents of the source code line number correspondence table. + This routine is a debugging aid only. */ + +static void +print_dwarf_line_table (outfile) + FILE *outfile; +{ + register unsigned i; + register dw_line_info_ref line_info; + + fprintf (outfile, "\n\nDWARF source line information\n"); + for (i = 1; i < line_info_table_in_use; ++i) + { + line_info = &line_info_table[i]; + fprintf (outfile, "%5d: ", i); + fprintf (outfile, "%-20s", file_table[line_info->dw_file_num]); + fprintf (outfile, "%6ld", line_info->dw_line_num); + fprintf (outfile, "\n"); + } + + fprintf (outfile, "\n\n"); +} + +/* Print the information collected for a given DIE. */ + +void +debug_dwarf_die (die) + dw_die_ref die; +{ + print_die (die, stderr); +} + +/* Print all DWARF information collected for the compilation unit. + This routine is a debugging aid only. */ + +void +debug_dwarf () +{ + print_indent = 0; + print_die (comp_unit_die, stderr); + print_dwarf_line_table (stderr); +} + +/* Traverse the DIE, and add a sibling attribute if it may have the + effect of speeding up access to siblings. To save some space, + avoid generating sibling attributes for DIE's without children. */ + +static void +add_sibling_attributes(die) + register dw_die_ref die; +{ + register dw_die_ref c; + register dw_attr_ref attr; + if (die != comp_unit_die && die->die_child != NULL) + { + attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + attr->dw_attr_next = NULL; + attr->dw_attr = DW_AT_sibling; + attr->dw_attr_val.val_class = dw_val_class_die_ref; + attr->dw_attr_val.v.val_die_ref = die->die_sib; + + /* Add the sibling link to the front of the attribute list. */ + attr->dw_attr_next = die->die_attr; + if (die->die_attr == NULL) + die->die_attr_last = attr; + + die->die_attr = attr; + } + + for (c = die->die_child; c != NULL; c = c->die_sib) + add_sibling_attributes (c); +} + +/* The format of each DIE (and its attribute value pairs) + is encoded in an abbreviation table. This routine builds the + abbreviation table and assigns a unique abbreviation id for + each abbreviation entry. The children of each die are visited + recursively. */ + +static void +build_abbrev_table (die) + register dw_die_ref die; +{ + register unsigned long abbrev_id; + register unsigned long n_alloc; + register dw_die_ref c; + register dw_attr_ref d_attr, a_attr; + for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id) + { + register dw_die_ref abbrev = abbrev_die_table[abbrev_id]; + + if (abbrev->die_tag == die->die_tag) + { + if ((abbrev->die_child != NULL) == (die->die_child != NULL)) + { + a_attr = abbrev->die_attr; + d_attr = die->die_attr; + + while (a_attr != NULL && d_attr != NULL) + { + if ((a_attr->dw_attr != d_attr->dw_attr) + || (value_format (&a_attr->dw_attr_val) + != value_format (&d_attr->dw_attr_val))) + break; + + a_attr = a_attr->dw_attr_next; + d_attr = d_attr->dw_attr_next; + } + + if (a_attr == NULL && d_attr == NULL) + break; + } + } + } + + if (abbrev_id >= abbrev_die_table_in_use) + { + if (abbrev_die_table_in_use >= abbrev_die_table_allocated) + { + n_alloc = abbrev_die_table_allocated + ABBREV_DIE_TABLE_INCREMENT; + abbrev_die_table + = (dw_die_ref *) xrealloc (abbrev_die_table, + sizeof (dw_die_ref) * n_alloc); + + bzero ((char *) &abbrev_die_table[abbrev_die_table_allocated], + (n_alloc - abbrev_die_table_allocated) * sizeof (dw_die_ref)); + abbrev_die_table_allocated = n_alloc; + } + + ++abbrev_die_table_in_use; + abbrev_die_table[abbrev_id] = die; + } + + die->die_abbrev = abbrev_id; + for (c = die->die_child; c != NULL; c = c->die_sib) + build_abbrev_table (c); +} + +/* Return the size of a string, including the null byte. + + This used to treat backslashes as escapes, and hence they were not included + in the count. However, that conflicts with what ASM_OUTPUT_ASCII does, + which treats a backslash as a backslash, escaping it if necessary, and hence + we must include them in the count. */ + +static unsigned long +size_of_string (str) + register char *str; +{ + return strlen (str) + 1; +} + +/* Return the size of a location descriptor. */ + +static unsigned long +size_of_loc_descr (loc) + register dw_loc_descr_ref loc; +{ + register unsigned long size = 1; + + switch (loc->dw_loc_opc) + { + case DW_OP_addr: + size += PTR_SIZE; + break; + case DW_OP_const1u: + case DW_OP_const1s: + size += 1; + break; + case DW_OP_const2u: + case DW_OP_const2s: + size += 2; + break; + case DW_OP_const4u: + case DW_OP_const4s: + size += 4; + break; + case DW_OP_const8u: + case DW_OP_const8s: + size += 8; + break; + case DW_OP_constu: + size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); + break; + case DW_OP_consts: + size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int); + break; + case DW_OP_pick: + size += 1; + break; + case DW_OP_plus_uconst: + size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); + break; + case DW_OP_skip: + case DW_OP_bra: + size += 2; + break; + case DW_OP_breg0: + case DW_OP_breg1: + case DW_OP_breg2: + case DW_OP_breg3: + case DW_OP_breg4: + case DW_OP_breg5: + case DW_OP_breg6: + case DW_OP_breg7: + case DW_OP_breg8: + case DW_OP_breg9: + case DW_OP_breg10: + case DW_OP_breg11: + case DW_OP_breg12: + case DW_OP_breg13: + case DW_OP_breg14: + case DW_OP_breg15: + case DW_OP_breg16: + case DW_OP_breg17: + case DW_OP_breg18: + case DW_OP_breg19: + case DW_OP_breg20: + case DW_OP_breg21: + case DW_OP_breg22: + case DW_OP_breg23: + case DW_OP_breg24: + case DW_OP_breg25: + case DW_OP_breg26: + case DW_OP_breg27: + case DW_OP_breg28: + case DW_OP_breg29: + case DW_OP_breg30: + case DW_OP_breg31: + size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int); + break; + case DW_OP_regx: + size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); + break; + case DW_OP_fbreg: + size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int); + break; + case DW_OP_bregx: + size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); + size += size_of_sleb128 (loc->dw_loc_oprnd2.v.val_int); + break; + case DW_OP_piece: + size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); + break; + case DW_OP_deref_size: + case DW_OP_xderef_size: + size += 1; + break; + default: + break; + } + + return size; +} + +/* Return the size of a series of location descriptors. */ + +static unsigned long +size_of_locs (loc) + register dw_loc_descr_ref loc; +{ + register unsigned long size = 0; + + for (; loc != NULL; loc = loc->dw_loc_next) + size += size_of_loc_descr (loc); + + return size; +} + +/* Return the power-of-two number of bytes necessary to represent VALUE. */ + +static int +constant_size (value) + long unsigned value; +{ + int log; + + if (value == 0) + log = 0; + else + log = floor_log2 (value); + + log = log / 8; + log = 1 << (floor_log2 (log) + 1); + + return log; +} + +/* Return the size of a DIE, as it is represented in the + .debug_info section. */ + +static unsigned long +size_of_die (die) + register dw_die_ref die; +{ + register unsigned long size = 0; + register dw_attr_ref a; + + size += size_of_uleb128 (die->die_abbrev); + for (a = die->die_attr; a != NULL; a = a->dw_attr_next) + { + switch (a->dw_attr_val.val_class) + { + case dw_val_class_addr: + size += PTR_SIZE; + break; + case dw_val_class_loc: + { + register unsigned long lsize + = size_of_locs (a->dw_attr_val.v.val_loc); + + /* Block length. */ + size += constant_size (lsize); + size += lsize; + } + break; + case dw_val_class_const: + size += 4; + break; + case dw_val_class_unsigned_const: + size += constant_size (a->dw_attr_val.v.val_unsigned); + break; + case dw_val_class_long_long: + size += 1 + 8; /* block */ + break; + case dw_val_class_float: + size += 1 + a->dw_attr_val.v.val_float.length * 4; /* block */ + break; + case dw_val_class_flag: + size += 1; + break; + case dw_val_class_die_ref: + size += DWARF_OFFSET_SIZE; + break; + case dw_val_class_fde_ref: + size += DWARF_OFFSET_SIZE; + break; + case dw_val_class_lbl_id: + size += PTR_SIZE; + break; + case dw_val_class_section_offset: + size += DWARF_OFFSET_SIZE; + break; + case dw_val_class_str: + size += size_of_string (a->dw_attr_val.v.val_str); + break; + default: + abort (); + } + } + + return size; +} + +/* Size the debugging information associated with a given DIE. + Visits the DIE's children recursively. Updates the global + variable next_die_offset, on each time through. Uses the + current value of next_die_offset to update the die_offset + field in each DIE. */ + +static void +calc_die_sizes (die) + dw_die_ref die; +{ + register dw_die_ref c; + die->die_offset = next_die_offset; + next_die_offset += size_of_die (die); + + for (c = die->die_child; c != NULL; c = c->die_sib) + calc_die_sizes (c); + + if (die->die_child != NULL) + /* Count the null byte used to terminate sibling lists. */ + next_die_offset += 1; +} + +/* Return the size of the line information prolog generated for the + compilation unit. */ + +static unsigned long +size_of_line_prolog () +{ + register unsigned long size; + register unsigned long ft_index; + + size = DWARF_LINE_PROLOG_HEADER_SIZE; + + /* Count the size of the table giving number of args for each + standard opcode. */ + size += DWARF_LINE_OPCODE_BASE - 1; + + /* Include directory table is empty (at present). Count only the + null byte used to terminate the table. */ + size += 1; + + for (ft_index = 1; ft_index < file_table_in_use; ++ft_index) + { + /* File name entry. */ + size += size_of_string (file_table[ft_index]); + + /* Include directory index. */ + size += size_of_uleb128 (0); + + /* Modification time. */ + size += size_of_uleb128 (0); + + /* File length in bytes. */ + size += size_of_uleb128 (0); + } + + /* Count the file table terminator. */ + size += 1; + return size; +} + +/* Return the size of the line information generated for this + compilation unit. */ + +static unsigned long +size_of_line_info () +{ + register unsigned long size; + register unsigned long lt_index; + register unsigned long current_line; + register long line_offset; + register long line_delta; + register unsigned long current_file; + register unsigned long function; + unsigned long size_of_set_address; + + /* Size of a DW_LNE_set_address instruction. */ + size_of_set_address = 1 + size_of_uleb128 (1 + PTR_SIZE) + 1 + PTR_SIZE; + + /* Version number. */ + size = 2; + + /* Prolog length specifier. */ + size += DWARF_OFFSET_SIZE; + + /* Prolog. */ + size += size_of_line_prolog (); + + /* Set address register instruction. */ + size += size_of_set_address; + + current_file = 1; + current_line = 1; + for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index) + { + register dw_line_info_ref line_info; + + /* Advance pc instruction. */ + /* ??? See the DW_LNS_advance_pc comment in output_line_info. */ + if (0) + size += 1 + 2; + else + size += size_of_set_address; + + line_info = &line_info_table[lt_index]; + if (line_info->dw_file_num != current_file) + { + /* Set file number instruction. */ + size += 1; + current_file = line_info->dw_file_num; + size += size_of_uleb128 (current_file); + } + + if (line_info->dw_line_num != current_line) + { + line_offset = line_info->dw_line_num - current_line; + line_delta = line_offset - DWARF_LINE_BASE; + current_line = line_info->dw_line_num; + if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1)) + /* 1-byte special line number instruction. */ + size += 1; + else + { + /* Advance line instruction. */ + size += 1; + size += size_of_sleb128 (line_offset); + /* Generate line entry instruction. */ + size += 1; + } + } + } + + /* Advance pc instruction. */ + if (0) + size += 1 + 2; + else + size += size_of_set_address; + + /* End of line number info. marker. */ + size += 1 + size_of_uleb128 (1) + 1; + + function = 0; + current_file = 1; + current_line = 1; + for (lt_index = 0; lt_index < separate_line_info_table_in_use; ) + { + register dw_separate_line_info_ref line_info + = &separate_line_info_table[lt_index]; + if (function != line_info->function) + { + function = line_info->function; + /* Set address register instruction. */ + size += size_of_set_address; + } + else + { + /* Advance pc instruction. */ + if (0) + size += 1 + 2; + else + size += size_of_set_address; + } + + if (line_info->dw_file_num != current_file) + { + /* Set file number instruction. */ + size += 1; + current_file = line_info->dw_file_num; + size += size_of_uleb128 (current_file); + } + + if (line_info->dw_line_num != current_line) + { + line_offset = line_info->dw_line_num - current_line; + line_delta = line_offset - DWARF_LINE_BASE; + current_line = line_info->dw_line_num; + if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1)) + /* 1-byte special line number instruction. */ + size += 1; + else + { + /* Advance line instruction. */ + size += 1; + size += size_of_sleb128 (line_offset); + + /* Generate line entry instruction. */ + size += 1; + } + } + + ++lt_index; + + /* If we're done with a function, end its sequence. */ + if (lt_index == separate_line_info_table_in_use + || separate_line_info_table[lt_index].function != function) + { + current_file = 1; + current_line = 1; + + /* Advance pc instruction. */ + if (0) + size += 1 + 2; + else + size += size_of_set_address; + + /* End of line number info. marker. */ + size += 1 + size_of_uleb128 (1) + 1; + } + } + + return size; +} + +/* Return the size of the .debug_pubnames table generated for the + compilation unit. */ + +static unsigned long +size_of_pubnames () +{ + register unsigned long size; + register unsigned i; + + size = DWARF_PUBNAMES_HEADER_SIZE; + for (i = 0; i < pubname_table_in_use; ++i) + { + register pubname_ref p = &pubname_table[i]; + size += DWARF_OFFSET_SIZE + size_of_string (p->name); + } + + size += DWARF_OFFSET_SIZE; + return size; +} + +/* Return the size of the information in the .debug_aranges section. */ + +static unsigned long +size_of_aranges () +{ + register unsigned long size; + + size = DWARF_ARANGES_HEADER_SIZE; + + /* Count the address/length pair for this compilation unit. */ + size += 2 * PTR_SIZE; + size += 2 * PTR_SIZE * arange_table_in_use; + + /* Count the two zero words used to terminated the address range table. */ + size += 2 * PTR_SIZE; + return size; +} + +/* Select the encoding of an attribute value. */ + +static enum dwarf_form +value_format (v) + dw_val_ref v; +{ + switch (v->val_class) + { + case dw_val_class_addr: + return DW_FORM_addr; + case dw_val_class_loc: + switch (constant_size (size_of_locs (v->v.val_loc))) + { + case 1: + return DW_FORM_block1; + case 2: + return DW_FORM_block2; + default: + abort (); + } + case dw_val_class_const: + return DW_FORM_data4; + case dw_val_class_unsigned_const: + switch (constant_size (v->v.val_unsigned)) + { + case 1: + return DW_FORM_data1; + case 2: + return DW_FORM_data2; + case 4: + return DW_FORM_data4; + case 8: + return DW_FORM_data8; + default: + abort (); + } + case dw_val_class_long_long: + return DW_FORM_block1; + case dw_val_class_float: + return DW_FORM_block1; + case dw_val_class_flag: + return DW_FORM_flag; + case dw_val_class_die_ref: + return DW_FORM_ref; + case dw_val_class_fde_ref: + return DW_FORM_data; + case dw_val_class_lbl_id: + return DW_FORM_addr; + case dw_val_class_section_offset: + return DW_FORM_data; + case dw_val_class_str: + return DW_FORM_string; + default: + abort (); + } +} + +/* Output the encoding of an attribute value. */ + +static void +output_value_format (v) + dw_val_ref v; +{ + enum dwarf_form form = value_format (v); + + output_uleb128 (form); + if (flag_debug_asm) + fprintf (asm_out_file, " (%s)", dwarf_form_name (form)); + + fputc ('\n', asm_out_file); +} + +/* Output the .debug_abbrev section which defines the DIE abbreviation + table. */ + +static void +output_abbrev_section () +{ + unsigned long abbrev_id; + + dw_attr_ref a_attr; + for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id) + { + register dw_die_ref abbrev = abbrev_die_table[abbrev_id]; + + output_uleb128 (abbrev_id); + if (flag_debug_asm) + fprintf (asm_out_file, " (abbrev code)"); + + fputc ('\n', asm_out_file); + output_uleb128 (abbrev->die_tag); + if (flag_debug_asm) + fprintf (asm_out_file, " (TAG: %s)", + dwarf_tag_name (abbrev->die_tag)); + + fputc ('\n', asm_out_file); + fprintf (asm_out_file, "\t%s\t0x%x", ASM_BYTE_OP, + abbrev->die_child != NULL ? DW_children_yes : DW_children_no); + + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s %s", + ASM_COMMENT_START, + (abbrev->die_child != NULL + ? "DW_children_yes" : "DW_children_no")); + + fputc ('\n', asm_out_file); + + for (a_attr = abbrev->die_attr; a_attr != NULL; + a_attr = a_attr->dw_attr_next) + { + output_uleb128 (a_attr->dw_attr); + if (flag_debug_asm) + fprintf (asm_out_file, " (%s)", + dwarf_attr_name (a_attr->dw_attr)); + + fputc ('\n', asm_out_file); + output_value_format (&a_attr->dw_attr_val); + } + + fprintf (asm_out_file, "\t%s\t0,0\n", ASM_BYTE_OP); + } +} + +/* Output location description stack opcode's operands (if any). */ + +static void +output_loc_operands (loc) + register dw_loc_descr_ref loc; +{ + register dw_val_ref val1 = &loc->dw_loc_oprnd1; + register dw_val_ref val2 = &loc->dw_loc_oprnd2; + + switch (loc->dw_loc_opc) + { + case DW_OP_addr: + ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file, val1->v.val_addr); + fputc ('\n', asm_out_file); + break; + case DW_OP_const1u: + case DW_OP_const1s: + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_flag); + fputc ('\n', asm_out_file); + break; + case DW_OP_const2u: + case DW_OP_const2s: + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, val1->v.val_int); + fputc ('\n', asm_out_file); + break; + case DW_OP_const4u: + case DW_OP_const4s: + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, val1->v.val_int); + fputc ('\n', asm_out_file); + break; + case DW_OP_const8u: + case DW_OP_const8s: + abort (); + fputc ('\n', asm_out_file); + break; + case DW_OP_constu: + output_uleb128 (val1->v.val_unsigned); + fputc ('\n', asm_out_file); + break; + case DW_OP_consts: + output_sleb128 (val1->v.val_int); + fputc ('\n', asm_out_file); + break; + case DW_OP_pick: + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_int); + fputc ('\n', asm_out_file); + break; + case DW_OP_plus_uconst: + output_uleb128 (val1->v.val_unsigned); + fputc ('\n', asm_out_file); + break; + case DW_OP_skip: + case DW_OP_bra: + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, val1->v.val_int); + fputc ('\n', asm_out_file); + break; + case DW_OP_breg0: + case DW_OP_breg1: + case DW_OP_breg2: + case DW_OP_breg3: + case DW_OP_breg4: + case DW_OP_breg5: + case DW_OP_breg6: + case DW_OP_breg7: + case DW_OP_breg8: + case DW_OP_breg9: + case DW_OP_breg10: + case DW_OP_breg11: + case DW_OP_breg12: + case DW_OP_breg13: + case DW_OP_breg14: + case DW_OP_breg15: + case DW_OP_breg16: + case DW_OP_breg17: + case DW_OP_breg18: + case DW_OP_breg19: + case DW_OP_breg20: + case DW_OP_breg21: + case DW_OP_breg22: + case DW_OP_breg23: + case DW_OP_breg24: + case DW_OP_breg25: + case DW_OP_breg26: + case DW_OP_breg27: + case DW_OP_breg28: + case DW_OP_breg29: + case DW_OP_breg30: + case DW_OP_breg31: + output_sleb128 (val1->v.val_int); + fputc ('\n', asm_out_file); + break; + case DW_OP_regx: + output_uleb128 (val1->v.val_unsigned); + fputc ('\n', asm_out_file); + break; + case DW_OP_fbreg: + output_sleb128 (val1->v.val_int); + fputc ('\n', asm_out_file); + break; + case DW_OP_bregx: + output_uleb128 (val1->v.val_unsigned); + fputc ('\n', asm_out_file); + output_sleb128 (val2->v.val_int); + fputc ('\n', asm_out_file); + break; + case DW_OP_piece: + output_uleb128 (val1->v.val_unsigned); + fputc ('\n', asm_out_file); + break; + case DW_OP_deref_size: + case DW_OP_xderef_size: + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_flag); + fputc ('\n', asm_out_file); + break; + default: + break; + } +} + +/* Compute the offset of a sibling. */ + +static unsigned long +sibling_offset (die) + dw_die_ref die; +{ + unsigned long offset; + + if (die->die_child_last == NULL) + offset = die->die_offset + size_of_die (die); + else + offset = sibling_offset (die->die_child_last) + 1; + + return offset; +} + +/* Output the DIE and its attributes. Called recursively to generate + the definitions of each child DIE. */ + +static void +output_die (die) + register dw_die_ref die; +{ + register dw_attr_ref a; + register dw_die_ref c; + register unsigned long ref_offset; + register unsigned long size; + register dw_loc_descr_ref loc; + + output_uleb128 (die->die_abbrev); + if (flag_debug_asm) + fprintf (asm_out_file, " (DIE (0x%lx) %s)", + die->die_offset, dwarf_tag_name (die->die_tag)); + + fputc ('\n', asm_out_file); + + for (a = die->die_attr; a != NULL; a = a->dw_attr_next) + { + switch (a->dw_attr_val.val_class) + { + case dw_val_class_addr: + ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file, + a->dw_attr_val.v.val_addr); + break; + + case dw_val_class_loc: + size = size_of_locs (a->dw_attr_val.v.val_loc); + + /* Output the block length for this list of location operations. */ + switch (constant_size (size)) + { + case 1: + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, size); + break; + case 2: + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, size); + break; + default: + abort (); + } + + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s %s", + ASM_COMMENT_START, dwarf_attr_name (a->dw_attr)); + + fputc ('\n', asm_out_file); + for (loc = a->dw_attr_val.v.val_loc; loc != NULL; + loc = loc->dw_loc_next) + { + /* Output the opcode. */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, loc->dw_loc_opc); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START, + dwarf_stack_op_name (loc->dw_loc_opc)); + + fputc ('\n', asm_out_file); + + /* Output the operand(s) (if any). */ + output_loc_operands (loc); + } + break; + + case dw_val_class_const: + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, a->dw_attr_val.v.val_int); + break; + + case dw_val_class_unsigned_const: + switch (constant_size (a->dw_attr_val.v.val_unsigned)) + { + case 1: + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, + a->dw_attr_val.v.val_unsigned); + break; + case 2: + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, + a->dw_attr_val.v.val_unsigned); + break; + case 4: + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, + a->dw_attr_val.v.val_unsigned); + break; + case 8: + ASM_OUTPUT_DWARF_DATA8 (asm_out_file, + a->dw_attr_val.v.val_long_long.hi, + a->dw_attr_val.v.val_long_long.low); + break; + default: + abort (); + } + break; + + case dw_val_class_long_long: + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 8); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s %s", + ASM_COMMENT_START, dwarf_attr_name (a->dw_attr)); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA8 (asm_out_file, + a->dw_attr_val.v.val_long_long.hi, + a->dw_attr_val.v.val_long_long.low); + + if (flag_debug_asm) + fprintf (asm_out_file, + "\t%s long long constant", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + break; + + case dw_val_class_float: + { + register unsigned int i; + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, + a->dw_attr_val.v.val_float.length * 4); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s %s", + ASM_COMMENT_START, dwarf_attr_name (a->dw_attr)); + + fputc ('\n', asm_out_file); + for (i = 0; i < a->dw_attr_val.v.val_float.length; ++i) + { + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, + a->dw_attr_val.v.val_float.array[i]); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s fp constant word %u", + ASM_COMMENT_START, i); + + fputc ('\n', asm_out_file); + } + break; + } + + case dw_val_class_flag: + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, a->dw_attr_val.v.val_flag); + break; + + case dw_val_class_die_ref: + if (a->dw_attr_val.v.val_die_ref != NULL) + ref_offset = a->dw_attr_val.v.val_die_ref->die_offset; + else if (a->dw_attr == DW_AT_sibling) + ref_offset = sibling_offset(die); + else + abort (); + + ASM_OUTPUT_DWARF_DATA (asm_out_file, ref_offset); + break; + + case dw_val_class_fde_ref: + { + char l1[20]; + ASM_GENERATE_INTERNAL_LABEL + (l1, FDE_AFTER_SIZE_LABEL, a->dw_attr_val.v.val_fde_index * 2); + ASM_OUTPUT_DWARF_OFFSET (asm_out_file, l1); + fprintf (asm_out_file, " - %d", DWARF_OFFSET_SIZE); + } + break; + + case dw_val_class_lbl_id: + ASM_OUTPUT_DWARF_ADDR (asm_out_file, a->dw_attr_val.v.val_lbl_id); + break; + + case dw_val_class_section_offset: + ASM_OUTPUT_DWARF_OFFSET (asm_out_file, + stripattributes + (a->dw_attr_val.v.val_section)); + break; + + case dw_val_class_str: + if (flag_debug_asm) + ASM_OUTPUT_DWARF_STRING (asm_out_file, a->dw_attr_val.v.val_str); + else + ASM_OUTPUT_ASCII (asm_out_file, + a->dw_attr_val.v.val_str, + (int) strlen (a->dw_attr_val.v.val_str) + 1); + break; + + default: + abort (); + } + + if (a->dw_attr_val.val_class != dw_val_class_loc + && a->dw_attr_val.val_class != dw_val_class_long_long + && a->dw_attr_val.val_class != dw_val_class_float) + { + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s %s", + ASM_COMMENT_START, dwarf_attr_name (a->dw_attr)); + + fputc ('\n', asm_out_file); + } + } + + for (c = die->die_child; c != NULL; c = c->die_sib) + output_die (c); + + if (die->die_child != NULL) + { + /* Add null byte to terminate sibling list. */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s end of children of DIE 0x%lx", + ASM_COMMENT_START, die->die_offset); + + fputc ('\n', asm_out_file); + } +} + +/* Output the compilation unit that appears at the beginning of the + .debug_info section, and precedes the DIE descriptions. */ + +static void +output_compilation_unit_header () +{ + ASM_OUTPUT_DWARF_DATA (asm_out_file, next_die_offset - DWARF_OFFSET_SIZE); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Length of Compilation Unit Info.", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DWARF version number", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (ABBREV_SECTION)); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Offset Into Abbrev. Section", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, PTR_SIZE); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Pointer Size (in bytes)", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); +} + +/* The DWARF2 pubname for a nested thingy looks like "A::f". The output + of decl_printable_name for C++ looks like "A::f(int)". Let's drop the + argument list, and maybe the scope. */ + +static char * +dwarf2_name (decl, scope) + tree decl; + int scope; +{ + return (*decl_printable_name) (decl, scope ? 1 : 0); +} + +/* Add a new entry to .debug_pubnames if appropriate. */ + +static void +add_pubname (decl, die) + tree decl; + dw_die_ref die; +{ + pubname_ref p; + + if (! TREE_PUBLIC (decl)) + return; + + if (pubname_table_in_use == pubname_table_allocated) + { + pubname_table_allocated += PUBNAME_TABLE_INCREMENT; + pubname_table = (pubname_ref) xrealloc + (pubname_table, pubname_table_allocated * sizeof (pubname_entry)); + } + + p = &pubname_table[pubname_table_in_use++]; + p->die = die; + + p->name = xstrdup (dwarf2_name (decl, 1)); +} + +/* Output the public names table used to speed up access to externally + visible names. For now, only generate entries for externally + visible procedures. */ + +static void +output_pubnames () +{ + register unsigned i; + register unsigned long pubnames_length = size_of_pubnames (); + + ASM_OUTPUT_DWARF_DATA (asm_out_file, pubnames_length); + + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Length of Public Names Info.", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION); + + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (DEBUG_INFO_SECTION)); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Offset of Compilation Unit Info.", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA (asm_out_file, next_die_offset); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Compilation Unit Length", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + for (i = 0; i < pubname_table_in_use; ++i) + { + register pubname_ref pub = &pubname_table[i]; + + ASM_OUTPUT_DWARF_DATA (asm_out_file, pub->die->die_offset); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DIE offset", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + + if (flag_debug_asm) + { + ASM_OUTPUT_DWARF_STRING (asm_out_file, pub->name); + fprintf (asm_out_file, "%s external name", ASM_COMMENT_START); + } + else + { + ASM_OUTPUT_ASCII (asm_out_file, pub->name, + (int) strlen (pub->name) + 1); + } + + fputc ('\n', asm_out_file); + } + + ASM_OUTPUT_DWARF_DATA (asm_out_file, 0); + fputc ('\n', asm_out_file); +} + +/* Add a new entry to .debug_aranges if appropriate. */ + +static void +add_arange (decl, die) + tree decl; + dw_die_ref die; +{ + if (! DECL_SECTION_NAME (decl)) + return; + + if (arange_table_in_use == arange_table_allocated) + { + arange_table_allocated += ARANGE_TABLE_INCREMENT; + arange_table + = (arange_ref) xrealloc (arange_table, + arange_table_allocated * sizeof (dw_die_ref)); + } + + arange_table[arange_table_in_use++] = die; +} + +/* Output the information that goes into the .debug_aranges table. + Namely, define the beginning and ending address range of the + text section generated for this compilation unit. */ + +static void +output_aranges () +{ + register unsigned i; + register unsigned long aranges_length = size_of_aranges (); + + ASM_OUTPUT_DWARF_DATA (asm_out_file, aranges_length); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Length of Address Ranges Info.", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (DEBUG_INFO_SECTION)); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Offset of Compilation Unit Info.", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, PTR_SIZE); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Size of Address", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Size of Segment Descriptor", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 4); + if (PTR_SIZE == 8) + fprintf (asm_out_file, ",0,0"); + + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Pad to %d byte boundary", + ASM_COMMENT_START, 2 * PTR_SIZE); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, stripattributes (TEXT_SECTION)); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Address", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, text_end_label, + stripattributes (TEXT_SECTION)); + if (flag_debug_asm) + fprintf (asm_out_file, "%s Length", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + for (i = 0; i < arange_table_in_use; ++i) + { + dw_die_ref a = arange_table[i]; + + if (a->die_tag == DW_TAG_subprogram) + ASM_OUTPUT_DWARF_ADDR (asm_out_file, get_AT_low_pc (a)); + else + { + char *name = get_AT_string (a, DW_AT_MIPS_linkage_name); + if (! name) + name = get_AT_string (a, DW_AT_name); + + ASM_OUTPUT_DWARF_ADDR (asm_out_file, name); + } + + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Address", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + if (a->die_tag == DW_TAG_subprogram) + ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, get_AT_hi_pc (a), + get_AT_low_pc (a)); + else + ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, + get_AT_unsigned (a, DW_AT_byte_size)); + + if (flag_debug_asm) + fprintf (asm_out_file, "%s Length", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + } + + /* Output the terminator words. */ + ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, 0); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, 0); + fputc ('\n', asm_out_file); +} + +/* Output the source line number correspondence information. This + information goes into the .debug_line section. + + If the format of this data changes, then the function size_of_line_info + must also be adjusted the same way. */ + +static void +output_line_info () +{ + char line_label[MAX_ARTIFICIAL_LABEL_BYTES]; + char prev_line_label[MAX_ARTIFICIAL_LABEL_BYTES]; + register unsigned opc; + register unsigned n_op_args; + register unsigned long ft_index; + register unsigned long lt_index; + register unsigned long current_line; + register long line_offset; + register long line_delta; + register unsigned long current_file; + register unsigned long function; + + ASM_OUTPUT_DWARF_DATA (asm_out_file, size_of_line_info ()); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Length of Source Line Info.", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA (asm_out_file, size_of_line_prolog ()); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Prolog Length", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_LINE_MIN_INSTR_LENGTH); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Minimum Instruction Length", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_LINE_DEFAULT_IS_STMT_START); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Default is_stmt_start flag", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + fprintf (asm_out_file, "\t%s\t%d", ASM_BYTE_OP, DWARF_LINE_BASE); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Line Base Value (Special Opcodes)", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + fprintf (asm_out_file, "\t%s\t%u", ASM_BYTE_OP, DWARF_LINE_RANGE); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Line Range Value (Special Opcodes)", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + fprintf (asm_out_file, "\t%s\t%u", ASM_BYTE_OP, DWARF_LINE_OPCODE_BASE); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Special Opcode Base", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + for (opc = 1; opc < DWARF_LINE_OPCODE_BASE; ++opc) + { + switch (opc) + { + case DW_LNS_advance_pc: + case DW_LNS_advance_line: + case DW_LNS_set_file: + case DW_LNS_set_column: + case DW_LNS_fixed_advance_pc: + n_op_args = 1; + break; + default: + n_op_args = 0; + break; + } + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, n_op_args); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s opcode: 0x%x has %d args", + ASM_COMMENT_START, opc, n_op_args); + fputc ('\n', asm_out_file); + } + + if (flag_debug_asm) + fprintf (asm_out_file, "%s Include Directory Table\n", ASM_COMMENT_START); + + /* Include directory table is empty, at present */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + fputc ('\n', asm_out_file); + if (flag_debug_asm) + fprintf (asm_out_file, "%s File Name Table\n", ASM_COMMENT_START); + + for (ft_index = 1; ft_index < file_table_in_use; ++ft_index) + { + if (flag_debug_asm) + { + ASM_OUTPUT_DWARF_STRING (asm_out_file, file_table[ft_index]); + fprintf (asm_out_file, "%s File Entry: 0x%lx", + ASM_COMMENT_START, ft_index); + } + else + { + ASM_OUTPUT_ASCII (asm_out_file, + file_table[ft_index], + (int) strlen (file_table[ft_index]) + 1); + } + + fputc ('\n', asm_out_file); + + /* Include directory index */ + output_uleb128 (0); + fputc ('\n', asm_out_file); + + /* Modification time */ + output_uleb128 (0); + fputc ('\n', asm_out_file); + + /* File length in bytes */ + output_uleb128 (0); + fputc ('\n', asm_out_file); + } + + /* Terminate the file name table */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + fputc ('\n', asm_out_file); + + /* Set the address register to the first location in the text section */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNE_set_address", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + output_uleb128 (1 + PTR_SIZE); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, stripattributes (TEXT_SECTION)); + fputc ('\n', asm_out_file); + + /* Generate the line number to PC correspondence table, encoded as + a series of state machine operations. */ + current_file = 1; + current_line = 1; + strcpy (prev_line_label, stripattributes (TEXT_SECTION)); + for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index) + { + register dw_line_info_ref line_info; + + /* Emit debug info for the address of the current line, choosing + the encoding that uses the least amount of space. */ + /* ??? Unfortunately, we have little choice here currently, and must + always use the most general form. Gcc does not know the address + delta itself, so we can't use DW_LNS_advance_pc. There are no known + dwarf2 aware assemblers at this time, so we can't use any special + pseudo ops that would allow the assembler to optimally encode this for + us. Many ports do have length attributes which will give an upper + bound on the address range. We could perhaps use length attributes + to determine when it is safe to use DW_LNS_fixed_advance_pc. */ + ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, lt_index); + if (0) + { + /* This can handle deltas up to 0xffff. This takes 3 bytes. */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label, prev_line_label); + fputc ('\n', asm_out_file); + } + else + { + /* This can handle any delta. This takes 4+PTR_SIZE bytes. */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNE_set_address", + ASM_COMMENT_START); + fputc ('\n', asm_out_file); + output_uleb128 (1 + PTR_SIZE); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label); + fputc ('\n', asm_out_file); + } + strcpy (prev_line_label, line_label); + + /* Emit debug info for the source file of the current line, if + different from the previous line. */ + line_info = &line_info_table[lt_index]; + if (line_info->dw_file_num != current_file) + { + current_file = line_info->dw_file_num; + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_set_file); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNS_set_file", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + output_uleb128 (current_file); + if (flag_debug_asm) + fprintf (asm_out_file, " (\"%s\")", file_table[current_file]); + + fputc ('\n', asm_out_file); + } + + /* Emit debug info for the current line number, choosing the encoding + that uses the least amount of space. */ + line_offset = line_info->dw_line_num - current_line; + line_delta = line_offset - DWARF_LINE_BASE; + current_line = line_info->dw_line_num; + if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1)) + { + /* This can handle deltas from -10 to 234, using the current + definitions of DWARF_LINE_BASE and DWARF_LINE_RANGE. This + takes 1 byte. */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, + DWARF_LINE_OPCODE_BASE + line_delta); + if (flag_debug_asm) + fprintf (asm_out_file, + "\t%s line %ld", ASM_COMMENT_START, current_line); + + fputc ('\n', asm_out_file); + } + else + { + /* This can handle any delta. This takes at least 4 bytes, depending + on the value being encoded. */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_advance_line); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s advance to line %ld", + ASM_COMMENT_START, current_line); + + fputc ('\n', asm_out_file); + output_sleb128 (line_offset); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy); + fputc ('\n', asm_out_file); + } + } + + /* Emit debug info for the address of the end of the function. */ + if (0) + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, text_end_label, prev_line_label); + fputc ('\n', asm_out_file); + } + else + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNE_set_address", ASM_COMMENT_START); + fputc ('\n', asm_out_file); + output_uleb128 (1 + PTR_SIZE); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, text_end_label); + fputc ('\n', asm_out_file); + } + + /* Output the marker for the end of the line number info. */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNE_end_sequence", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + output_uleb128 (1); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_end_sequence); + fputc ('\n', asm_out_file); + + function = 0; + current_file = 1; + current_line = 1; + for (lt_index = 0; lt_index < separate_line_info_table_in_use; ) + { + register dw_separate_line_info_ref line_info + = &separate_line_info_table[lt_index]; + + /* Emit debug info for the address of the current line. If this is + a new function, or the first line of a function, then we need + to handle it differently. */ + ASM_GENERATE_INTERNAL_LABEL (line_label, SEPARATE_LINE_CODE_LABEL, + lt_index); + if (function != line_info->function) + { + function = line_info->function; + + /* Set the address register to the first line in the function */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNE_set_address", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + output_uleb128 (1 + PTR_SIZE); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label); + fputc ('\n', asm_out_file); + } + else + { + /* ??? See the DW_LNS_advance_pc comment above. */ + if (0) + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label, + prev_line_label); + fputc ('\n', asm_out_file); + } + else + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNE_set_address", + ASM_COMMENT_START); + fputc ('\n', asm_out_file); + output_uleb128 (1 + PTR_SIZE); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label); + fputc ('\n', asm_out_file); + } + } + strcpy (prev_line_label, line_label); + + /* Emit debug info for the source file of the current line, if + different from the previous line. */ + if (line_info->dw_file_num != current_file) + { + current_file = line_info->dw_file_num; + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_set_file); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNS_set_file", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + output_uleb128 (current_file); + if (flag_debug_asm) + fprintf (asm_out_file, " (\"%s\")", file_table[current_file]); + + fputc ('\n', asm_out_file); + } + + /* Emit debug info for the current line number, choosing the encoding + that uses the least amount of space. */ + if (line_info->dw_line_num != current_line) + { + line_offset = line_info->dw_line_num - current_line; + line_delta = line_offset - DWARF_LINE_BASE; + current_line = line_info->dw_line_num; + if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1)) + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, + DWARF_LINE_OPCODE_BASE + line_delta); + if (flag_debug_asm) + fprintf (asm_out_file, + "\t%s line %ld", ASM_COMMENT_START, current_line); + + fputc ('\n', asm_out_file); + } + else + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_advance_line); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s advance to line %ld", + ASM_COMMENT_START, current_line); + + fputc ('\n', asm_out_file); + output_sleb128 (line_offset); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy); + fputc ('\n', asm_out_file); + } + } + + ++lt_index; + + /* If we're done with a function, end its sequence. */ + if (lt_index == separate_line_info_table_in_use + || separate_line_info_table[lt_index].function != function) + { + current_file = 1; + current_line = 1; + + /* Emit debug info for the address of the end of the function. */ + ASM_GENERATE_INTERNAL_LABEL (line_label, FUNC_END_LABEL, function); + if (0) + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label, + prev_line_label); + fputc ('\n', asm_out_file); + } + else + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNE_set_address", + ASM_COMMENT_START); + fputc ('\n', asm_out_file); + output_uleb128 (1 + PTR_SIZE); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label); + fputc ('\n', asm_out_file); + } + + /* Output the marker for the end of this sequence. */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNE_end_sequence", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + output_uleb128 (1); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_end_sequence); + fputc ('\n', asm_out_file); + } + } +} + +/* Given a pointer to a BLOCK node return non-zero if (and only if) the node + in question represents the outermost pair of curly braces (i.e. the "body + block") of a function or method. + + For any BLOCK node representing a "body block" of a function or method, the + BLOCK_SUPERCONTEXT of the node will point to another BLOCK node which + represents the outermost (function) scope for the function or method (i.e. + the one which includes the formal parameters). The BLOCK_SUPERCONTEXT of + *that* node in turn will point to the relevant FUNCTION_DECL node. */ + +static inline int +is_body_block (stmt) + register tree stmt; +{ + if (TREE_CODE (stmt) == BLOCK) + { + register tree parent = BLOCK_SUPERCONTEXT (stmt); + + if (TREE_CODE (parent) == BLOCK) + { + register tree grandparent = BLOCK_SUPERCONTEXT (parent); + + if (TREE_CODE (grandparent) == FUNCTION_DECL) + return 1; + } + } + + return 0; +} + +/* Given a pointer to a tree node for some base type, return a pointer to + a DIE that describes the given type. + + This routine must only be called for GCC type nodes that correspond to + Dwarf base (fundamental) types. */ + +static dw_die_ref +base_type_die (type) + register tree type; +{ + register dw_die_ref base_type_result; + register char *type_name; + register enum dwarf_type encoding; + register tree name = TYPE_NAME (type); + + if (TREE_CODE (type) == ERROR_MARK + || TREE_CODE (type) == VOID_TYPE) + return 0; + + if (TREE_CODE (name) == TYPE_DECL) + name = DECL_NAME (name); + type_name = IDENTIFIER_POINTER (name); + + switch (TREE_CODE (type)) + { + case INTEGER_TYPE: + /* Carefully distinguish the C character types, 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_PRECISION (type) == CHAR_TYPE_SIZE + && (type == char_type_node + || ! strcmp (type_name, "signed char") + || ! strcmp (type_name, "unsigned char")))) + { + if (TREE_UNSIGNED (type)) + encoding = DW_ATE_unsigned; + else + encoding = DW_ATE_signed; + break; + } + /* else fall through */ + + case CHAR_TYPE: + /* GNU Pascal/Ada CHAR type. Not used in C. */ + if (TREE_UNSIGNED (type)) + encoding = DW_ATE_unsigned_char; + else + encoding = DW_ATE_signed_char; + break; + + case REAL_TYPE: + encoding = DW_ATE_float; + break; + + case COMPLEX_TYPE: + encoding = DW_ATE_complex_float; + break; + + case BOOLEAN_TYPE: + /* GNU FORTRAN/Ada/C++ BOOLEAN type. */ + encoding = DW_ATE_boolean; + break; + + default: + abort (); /* No other TREE_CODEs are Dwarf fundamental types. */ + } + + base_type_result = new_die (DW_TAG_base_type, comp_unit_die); + add_AT_string (base_type_result, DW_AT_name, type_name); + add_AT_unsigned (base_type_result, DW_AT_byte_size, + int_size_in_bytes (type)); + add_AT_unsigned (base_type_result, DW_AT_encoding, encoding); + + return base_type_result; +} + +/* 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 (type) + register tree type; +{ + if (TREE_CODE (type) == ERROR_MARK) + return error_mark_node; + + switch (TREE_CODE (type)) + { + case ERROR_MARK: + return error_mark_node; + + case POINTER_TYPE: + case REFERENCE_TYPE: + return type_main_variant (root_type (TREE_TYPE (type))); + + default: + return type_main_variant (type); + } +} + +/* Given a pointer to an arbitrary ..._TYPE tree node, return non-zero if the + given input type is a Dwarf "fundamental" type. Otherwise return null. */ + +static inline int +is_base_type (type) + register 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: + return 0; + + default: + abort (); + } + + return 0; +} + +/* Given a pointer to an arbitrary ..._TYPE tree node, return a debugging + entry that chains various modifiers in front of the given type. */ + +static dw_die_ref +modified_type_die (type, is_const_type, is_volatile_type, context_die) + register tree type; + register int is_const_type; + register int is_volatile_type; + register dw_die_ref context_die; +{ + register enum tree_code code = TREE_CODE (type); + register dw_die_ref mod_type_die = NULL; + register dw_die_ref sub_die = NULL; + register tree item_type = NULL; + + if (code != ERROR_MARK) + { + type = build_type_variant (type, is_const_type, is_volatile_type); + + mod_type_die = lookup_type_die (type); + if (mod_type_die) + return mod_type_die; + + /* Handle C typedef types. */ + if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && DECL_ORIGINAL_TYPE (TYPE_NAME (type))) + { + tree dtype = TREE_TYPE (TYPE_NAME (type)); + if (type == dtype) + { + /* For a named type, use the typedef. */ + gen_type_die (type, context_die); + mod_type_die = lookup_type_die (type); + } + + else if (is_const_type < TYPE_READONLY (dtype) + || is_volatile_type < TYPE_VOLATILE (dtype)) + /* cv-unqualified version of named type. Just use the unnamed + type to which it refers. */ + mod_type_die + = modified_type_die (DECL_ORIGINAL_TYPE (TYPE_NAME (type)), + is_const_type, is_volatile_type, + context_die); + /* Else cv-qualified version of named type; fall through. */ + } + + if (mod_type_die) + /* OK */; + else if (is_const_type) + { + mod_type_die = new_die (DW_TAG_const_type, comp_unit_die); + sub_die = modified_type_die (type, 0, is_volatile_type, context_die); + } + else if (is_volatile_type) + { + mod_type_die = new_die (DW_TAG_volatile_type, comp_unit_die); + sub_die = modified_type_die (type, 0, 0, context_die); + } + else if (code == POINTER_TYPE) + { + mod_type_die = new_die (DW_TAG_pointer_type, comp_unit_die); + add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE); +#if 0 + add_AT_unsigned (mod_type_die, DW_AT_address_class, 0); +#endif + item_type = TREE_TYPE (type); + } + else if (code == REFERENCE_TYPE) + { + mod_type_die = new_die (DW_TAG_reference_type, comp_unit_die); + add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE); +#if 0 + add_AT_unsigned (mod_type_die, DW_AT_address_class, 0); +#endif + item_type = TREE_TYPE (type); + } + else if (is_base_type (type)) + mod_type_die = base_type_die (type); + else + { + gen_type_die (type, context_die); + + /* We have to get the type_main_variant here (and pass that to the + `lookup_type_die' 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. */ + mod_type_die = lookup_type_die (type_main_variant (type)); + if (mod_type_die == NULL) + abort (); + } + } + + equate_type_number_to_die (type, mod_type_die); + if (item_type) + /* We must do this after the equate_type_number_to_die call, in case + this is a recursive type. This ensures that the modified_type_die + recursion will terminate even if the type is recursive. Recursive + types are possible in Ada. */ + sub_die = modified_type_die (item_type, + TYPE_READONLY (item_type), + TYPE_VOLATILE (item_type), + context_die); + + if (sub_die != NULL) + add_AT_die_ref (mod_type_die, DW_AT_type, sub_die); + + return mod_type_die; +} + +/* Given a pointer to an arbitrary ..._TYPE tree node, return true if it is + an enumerated type. */ + +static inline int +type_is_enum (type) + register tree type; +{ + return TREE_CODE (type) == ENUMERAL_TYPE; +} + +/* Return a location descriptor that designates a machine register. */ + +static dw_loc_descr_ref +reg_loc_descriptor (rtl) + register rtx rtl; +{ + register dw_loc_descr_ref loc_result = NULL; + register unsigned reg = reg_number (rtl); + + if (reg <= 31) + loc_result = new_loc_descr (DW_OP_reg0 + reg, 0, 0); + else + loc_result = new_loc_descr (DW_OP_regx, reg, 0); + + return loc_result; +} + +/* Return a location descriptor that designates a base+offset location. */ + +static dw_loc_descr_ref +based_loc_descr (reg, offset) + unsigned reg; + long int offset; +{ + register dw_loc_descr_ref loc_result; + /* For the "frame base", we use the frame pointer or stack pointer + registers, since the RTL for local variables is relative to one of + them. */ + register unsigned fp_reg = DBX_REGISTER_NUMBER (frame_pointer_needed + ? HARD_FRAME_POINTER_REGNUM + : STACK_POINTER_REGNUM); + + if (reg == fp_reg) + loc_result = new_loc_descr (DW_OP_fbreg, offset, 0); + else if (reg <= 31) + loc_result = new_loc_descr (DW_OP_breg0 + reg, offset, 0); + else + loc_result = new_loc_descr (DW_OP_bregx, reg, offset); + + return loc_result; +} + +/* Return true if this RTL expression describes a base+offset calculation. */ + +static inline int +is_based_loc (rtl) + register rtx rtl; +{ + return (GET_CODE (rtl) == PLUS + && ((GET_CODE (XEXP (rtl, 0)) == REG + && GET_CODE (XEXP (rtl, 1)) == CONST_INT))); +} + +/* The following routine 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 transforming + the RTL for a memory-resident object into its Dwarf postfix expression + equivalent. This routine recursively descends an RTL tree, turning + it into Dwarf postfix code as it goes. */ + +static dw_loc_descr_ref +mem_loc_descriptor (rtl) + register rtx rtl; +{ + dw_loc_descr_ref mem_loc_result = NULL; + /* 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. */ + + 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 = XEXP (rtl, 0); + + /* ... fall through ... */ + + 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 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. */ + mem_loc_result = based_loc_descr (reg_number (rtl), 0); + break; + + case MEM: + mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0)); + add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0)); + break; + + case CONST: + case LABEL_REF: + case SYMBOL_REF: + mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0); + mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr; + mem_loc_result->dw_loc_oprnd1.v.val_addr = addr_to_string (rtl); + break; + + case PLUS: + if (is_based_loc (rtl)) + mem_loc_result = based_loc_descr (reg_number (XEXP (rtl, 0)), + INTVAL (XEXP (rtl, 1))); + else + { + add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 0))); + add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 1))); + add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_plus, 0, 0)); + } + break; + + case MULT: + /* If a pseudo-reg is optimized away, it is possible for it to + be replaced with a MEM containing a multiply. */ + add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 0))); + add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 1))); + add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0)); + break; + + case CONST_INT: + mem_loc_result = new_loc_descr (DW_OP_constu, INTVAL (rtl), 0); + break; + + default: + abort (); + } + + return mem_loc_result; +} + +/* Return a descriptor that describes the concatenation of two locations. + This is typically a complex variable. */ + +static dw_loc_descr_ref +concat_loc_descriptor (x0, x1) + register rtx x0, x1; +{ + dw_loc_descr_ref cc_loc_result = NULL; + + if (!is_pseudo_reg (x0) + && (GET_CODE (x0) != MEM || !is_pseudo_reg (XEXP (x0, 0)))) + add_loc_descr (&cc_loc_result, loc_descriptor (x0)); + add_loc_descr (&cc_loc_result, + new_loc_descr (DW_OP_piece, GET_MODE_SIZE (GET_MODE (x0)), 0)); + + if (!is_pseudo_reg (x1) + && (GET_CODE (x1) != MEM || !is_pseudo_reg (XEXP (x1, 0)))) + add_loc_descr (&cc_loc_result, loc_descriptor (x1)); + add_loc_descr (&cc_loc_result, + new_loc_descr (DW_OP_piece, GET_MODE_SIZE (GET_MODE (x1)), 0)); + + return cc_loc_result; +} + +/* 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 dw_loc_descr_ref +loc_descriptor (rtl) + register rtx rtl; +{ + dw_loc_descr_ref loc_result = NULL; + 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 = XEXP (rtl, 0); + + /* ... fall through ... */ + + case REG: + loc_result = reg_loc_descriptor (rtl); + break; + + case MEM: + loc_result = mem_loc_descriptor (XEXP (rtl, 0)); + break; + + case CONCAT: + loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1)); + break; + + default: + abort (); + } + + return loc_result; +} + +/* Given an unsigned value, round it up to the lowest multiple of `boundary' + which is not less than the value itself. */ + +static inline unsigned +ceiling (value, boundary) + register unsigned value; + register unsigned 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) + register tree decl; +{ + register tree type; + + if (TREE_CODE (decl) == ERROR_MARK) + return integer_type_node; + + type = DECL_BIT_FIELD_TYPE (decl); + if (type == NULL_TREE) + 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 +simple_type_align_in_bits (type) + register 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 +simple_type_size_in_bits (type) + register tree type; +{ + if (TREE_CODE (type) == ERROR_MARK) + return BITS_PER_WORD; + else + { + register tree type_size_tree = TYPE_SIZE (type); + + if (TREE_CODE (type_size_tree) != INTEGER_CST) + return TYPE_ALIGN (type); + + return (unsigned) TREE_INT_CST_LOW (type_size_tree); + } +} + +/* 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 + determine 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 unsigned +field_byte_offset (decl) + register tree decl; +{ + register unsigned type_align_in_bytes; + register unsigned type_align_in_bits; + register unsigned type_size_in_bits; + register unsigned object_offset_in_align_units; + register unsigned object_offset_in_bits; + register unsigned object_offset_in_bytes; + register tree type; + register tree bitpos_tree; + register tree field_size_tree; + register unsigned bitpos_int; + register unsigned deepest_bitpos; + register unsigned field_size_in_bits; + + if (TREE_CODE (decl) == ERROR_MARK) + return 0; + + if (TREE_CODE (decl) != FIELD_DECL) + abort (); + + type = field_type (decl); + + bitpos_tree = DECL_FIELD_BITPOS (decl); + field_size_tree = DECL_SIZE (decl); + + /* 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 (TREE_CODE (bitpos_tree) != INTEGER_CST) + return 0; + bitpos_int = (unsigned) TREE_INT_CST_LOW (bitpos_tree); + + if (TREE_CODE (field_size_tree) != INTEGER_CST) + return 0; + + field_size_in_bits = (unsigned) TREE_INT_CST_LOW (field_size_tree); + 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 information 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 "containing 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 DW_AT_location and DW_AT_bit_offset attributes + for fields (both bit-fields and, in the case of DW_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; + + return object_offset_in_bytes; +} + +/* The following routines define various Dwarf attributes and any data + associated with them. */ + +/* Add a location description attribute value to a DIE. + + This emits 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 +add_AT_location_description (die, attr_kind, rtl) + dw_die_ref die; + enum dwarf_attribute attr_kind; + register rtx rtl; +{ + /* 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. 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. */ + + if (is_pseudo_reg (rtl) + || (GET_CODE (rtl) == MEM + && is_pseudo_reg (XEXP (rtl, 0))) + || (GET_CODE (rtl) == CONCAT + && is_pseudo_reg (XEXP (rtl, 0)) + && is_pseudo_reg (XEXP (rtl, 1)))) + return; + + add_AT_loc (die, attr_kind, loc_descriptor (rtl)); +} + +/* Attach 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 DW_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 DW_AT_bit_offset attribute. + (See the `bit_offset_attribute' function below). */ + +static void +add_data_member_location_attribute (die, decl) + register dw_die_ref die; + register tree decl; +{ + register unsigned long offset; + register dw_loc_descr_ref loc_descr; + register enum dwarf_location_atom op; + + if (TREE_CODE (decl) == TREE_VEC) + offset = TREE_INT_CST_LOW (BINFO_OFFSET (decl)); + else + offset = field_byte_offset (decl); + + /* The DWARF2 standard says that we should assume that the structure address + is already on the stack, so we can specify a structure field address + by using DW_OP_plus_uconst. */ + +#ifdef MIPS_DEBUGGING_INFO + /* ??? The SGI dwarf reader does not handle the DW_OP_plus_uconst operator + correctly. It works only if we leave the offset on the stack. */ + op = DW_OP_constu; +#else + op = DW_OP_plus_uconst; +#endif + + loc_descr = new_loc_descr (op, offset, 0); + add_AT_loc (die, DW_AT_data_member_location, loc_descr); +} + +/* Attach an DW_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 +add_const_value_attribute (die, rtl) + register dw_die_ref die; + register rtx rtl; +{ + 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. */ + add_AT_unsigned (die, DW_AT_const_value, (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. We output CONST_DOUBLEs as blocks. */ + { + register enum machine_mode mode = GET_MODE (rtl); + + if (GET_MODE_CLASS (mode) == MODE_FLOAT) + { + register unsigned length = GET_MODE_SIZE (mode) / sizeof (long); + long array[4]; + REAL_VALUE_TYPE rv; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, rtl); + switch (mode) + { + case SFmode: + REAL_VALUE_TO_TARGET_SINGLE (rv, array[0]); + break; + + case DFmode: + REAL_VALUE_TO_TARGET_DOUBLE (rv, array); + break; + + case XFmode: + case TFmode: + REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, array); + break; + + default: + abort (); + } + + add_AT_float (die, DW_AT_const_value, length, array); + } + else + add_AT_long_long (die, DW_AT_const_value, + CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl)); + } + break; + + case CONST_STRING: + add_AT_string (die, DW_AT_const_value, XSTR (rtl, 0)); + break; + + case SYMBOL_REF: + case LABEL_REF: + case CONST: + add_AT_addr (die, DW_AT_const_value, addr_to_string (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 nothing. */ + break; + + default: + /* No other kinds of rtx should be possible here. */ + abort (); + } + +} + +/* Generate *either* an DW_AT_location attribute or else an DW_AT_const_value + data attribute for a variable or a parameter. We generate the + DW_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 +add_location_or_const_value_attribute (die, decl) + register dw_die_ref die; + register tree decl; +{ + register rtx rtl; + register tree declared_type; + register tree passed_type; + + if (TREE_CODE (decl) == ERROR_MARK) + return; + + if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != PARM_DECL) + abort (); + + /* 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 + activation 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, + we cannot (in general) use DECL_INCOMING_RTL as a 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. + + 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 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 that 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 dwarf2out.c may generate two additional + attributes for any given DW_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)) + { + declared_type = type_main_variant (TREE_TYPE (decl)); + passed_type = type_main_variant (DECL_ARG_TYPE (decl)); + + /* This decl represents a formal parameter which was optimized out. + 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 + && TREE_CODE (declared_type) == INTEGER_TYPE + && 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 (leaf_function) + 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 ...)) */ + add_const_value_attribute (die, rtl); + break; + + case MEM: + case REG: + case SUBREG: + case CONCAT: + add_AT_location_description (die, DW_AT_location, rtl); + break; + + default: + abort (); + } +} + +/* Generate an DW_AT_name attribute given some string value to be included as + the value of the attribute. */ + +static inline void +add_name_attribute (die, name_string) + register dw_die_ref die; + register char *name_string; +{ + if (name_string != NULL && *name_string != 0) + add_AT_string (die, DW_AT_name, name_string); +} + +/* Given a tree node describing an array bound (either lower or upper) output + a representation for that bound. */ + +static void +add_bound_info (subrange_die, bound_attr, bound) + register dw_die_ref subrange_die; + register enum dwarf_attribute bound_attr; + register tree bound; +{ + register unsigned bound_value = 0; + + /* If this is an Ada unconstrained array type, then don't emit any debug + info because the array bounds are unknown. They are parameterized when + the type is instantiated. */ + if (contains_placeholder_p (bound)) + return; + + switch (TREE_CODE (bound)) + { + case ERROR_MARK: + return; + + /* All fixed-bounds are represented by INTEGER_CST nodes. */ + case INTEGER_CST: + bound_value = TREE_INT_CST_LOW (bound); + if (bound_attr == DW_AT_lower_bound + && ((is_c_family () && bound_value == 0) + || (is_fortran () && bound_value == 1))) + /* use the default */; + else + add_AT_unsigned (subrange_die, bound_attr, bound_value); + break; + + case CONVERT_EXPR: + case NOP_EXPR: + case NON_LVALUE_EXPR: + add_bound_info (subrange_die, bound_attr, TREE_OPERAND (bound, 0)); + break; + + case SAVE_EXPR: + /* If optimization is turned on, the SAVE_EXPRs that describe how to + access the upper bound values may be bogus. If they refer to a + register, they may only describe 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 (though the + number of elements will), 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 don't add an attribute + 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. + + We assume that a MEM rtx is safe because gcc wouldn't put the + value there unless it was going to be used repeatedly in the + function, i.e. for cleanups. */ + if (! optimize || GET_CODE (SAVE_EXPR_RTL (bound)) == MEM) + { + register dw_die_ref ctx = lookup_decl_die (current_function_decl); + register dw_die_ref decl_die = new_die (DW_TAG_variable, ctx); + register rtx loc = SAVE_EXPR_RTL (bound); + + /* If the RTL for the SAVE_EXPR is memory, handle the case where + it references an outer function's frame. */ + + if (GET_CODE (loc) == MEM) + { + rtx new_addr = fix_lexical_addr (XEXP (loc, 0), bound); + + if (XEXP (loc, 0) != new_addr) + loc = gen_rtx (MEM, GET_MODE (loc), new_addr); + } + + add_AT_flag (decl_die, DW_AT_artificial, 1); + add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx); + add_AT_location_description (decl_die, DW_AT_location, loc); + add_AT_die_ref (subrange_die, bound_attr, decl_die); + } + + /* Else leave out the attribute. */ + break; + + case MAX_EXPR: + case VAR_DECL: + case COMPONENT_REF: + /* ??? These types of bounds can be created by the Ada front end, + and it isn't clear how to emit debug info for them. */ + break; + + default: + abort (); + } +} + +/* 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 +add_subscript_info (type_die, type) + register dw_die_ref type_die; + register tree type; +{ +#ifndef MIPS_DEBUGGING_INFO + register unsigned dimension_number; +#endif + register tree lower, upper; + register dw_die_ref subrange_die; + + /* 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. */ + + /* ??? The SGI dwarf reader fails for multidimensional arrays with a + const enum type. E.g. const enum machine_mode insn_operand_mode[2][10]. + We work around this by disabling this feature. See also + gen_array_type_die. */ +#ifndef MIPS_DEBUGGING_INFO + for (dimension_number = 0; + TREE_CODE (type) == ARRAY_TYPE; + type = TREE_TYPE (type), dimension_number++) + { +#endif + register 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. */ + subrange_die = new_die (DW_TAG_subrange_type, type_die); + if (domain) + { + /* We have an array type with specified bounds. */ + lower = TYPE_MIN_VALUE (domain); + upper = TYPE_MAX_VALUE (domain); + + /* define the index type. */ + if (TREE_TYPE (domain)) + { + /* ??? This is probably an Ada unnamed subrange type. Ignore the + TREE_TYPE field. We can't emit debug info for this + because it is an unnamed integral type. */ + if (TREE_CODE (domain) == INTEGER_TYPE + && TYPE_NAME (domain) == NULL_TREE + && TREE_CODE (TREE_TYPE (domain)) == INTEGER_TYPE + && TYPE_NAME (TREE_TYPE (domain)) == NULL_TREE) + ; + else + add_type_attribute (subrange_die, TREE_TYPE (domain), 0, 0, + type_die); + } + + /* ??? If upper is NULL, the array has unspecified length, + but it does have a lower bound. This happens with Fortran + dimension arr(N:*) + Since the debugger is definitely going to need to know N + to produce useful results, go ahead and output the lower + bound solo, and hope the debugger can cope. */ + + add_bound_info (subrange_die, DW_AT_lower_bound, lower); + if (upper) + add_bound_info (subrange_die, DW_AT_upper_bound, upper); + } + else + /* We have an array type with an unspecified length. The DWARF-2 + spec does not say how to handle this; let's just leave out the + bounds. */ + {;} + + +#ifndef MIPS_DEBUGGING_INFO + } +#endif +} + +static void +add_byte_size_attribute (die, tree_node) + dw_die_ref die; + register tree tree_node; +{ + register unsigned 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: + size = int_size_in_bytes (tree_node); + break; + case FIELD_DECL: + /* For a data member of a struct or union, the DW_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. */ + + add_AT_unsigned (die, DW_AT_byte_size, 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 DW_AT_byte_size attribute for this bit-field. + (See `byte_size_attribute' above). */ + +static inline void +add_bit_offset_attribute (die, decl) + register dw_die_ref die; + register tree decl; +{ + register unsigned object_offset_in_bytes = field_byte_offset (decl); + register tree type = DECL_BIT_FIELD_TYPE (decl); + register tree bitpos_tree = DECL_FIELD_BITPOS (decl); + register unsigned bitpos_int; + register unsigned highest_order_object_bit_offset; + register unsigned highest_order_field_bit_offset; + register unsigned bit_offset; + + /* Must be a field and a bit field. */ + if (!type + || TREE_CODE (decl) != FIELD_DECL) + abort (); + + /* We can't yet handle bit-fields whose offsets are variable, so if we + encounter such things, just return without generating any attribute + whatsoever. */ + if (TREE_CODE (bitpos_tree) != INTEGER_CST) + return; + + bitpos_int = (unsigned) TREE_INT_CST_LOW (bitpos_tree); + + /* 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 + += (unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl)); + + 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); + + add_AT_unsigned (die, DW_AT_bit_offset, 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 +add_bit_size_attribute (die, decl) + register dw_die_ref die; + register tree decl; +{ + /* Must be a field and a bit field. */ + if (TREE_CODE (decl) != FIELD_DECL + || ! DECL_BIT_FIELD_TYPE (decl)) + abort (); + add_AT_unsigned (die, DW_AT_bit_size, + (unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl))); +} + +/* If the compiled language is ANSI C, then add a 'prototyped' + attribute, if arg types are given for the parameters of a function. */ + +static inline void +add_prototyped_attribute (die, func_type) + register dw_die_ref die; + register tree func_type; +{ + if (get_AT_unsigned (comp_unit_die, DW_AT_language) == DW_LANG_C89 + && TYPE_ARG_TYPES (func_type) != NULL) + add_AT_flag (die, DW_AT_prototyped, 1); +} + + +/* Add an 'abstract_origin' attribute below a given DIE. The DIE is found + by looking in either the type declaration or object declaration + equate table. */ + +static inline void +add_abstract_origin_attribute (die, origin) + register dw_die_ref die; + register tree origin; +{ + dw_die_ref origin_die = NULL; + if (TREE_CODE_CLASS (TREE_CODE (origin)) == 'd') + origin_die = lookup_decl_die (origin); + else if (TREE_CODE_CLASS (TREE_CODE (origin)) == 't') + origin_die = lookup_type_die (origin); + + add_AT_die_ref (die, DW_AT_abstract_origin, origin_die); +} + +/* We do not currently support the pure_virtual attribute. */ + +static inline void +add_pure_or_virtual_attribute (die, func_decl) + register dw_die_ref die; + register tree func_decl; +{ + if (DECL_VINDEX (func_decl)) + { + add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual); + add_AT_loc (die, DW_AT_vtable_elem_location, + new_loc_descr (DW_OP_constu, + TREE_INT_CST_LOW (DECL_VINDEX (func_decl)), + 0)); + + /* GNU extension: Record what type this method came from originally. */ + if (debug_info_level > DINFO_LEVEL_TERSE) + add_AT_die_ref (die, DW_AT_containing_type, + lookup_type_die (DECL_CONTEXT (func_decl))); + } +} + +/* Add source coordinate attributes for the given decl. */ + +static void +add_src_coords_attributes (die, decl) + register dw_die_ref die; + register tree decl; +{ + register unsigned file_index = lookup_filename (DECL_SOURCE_FILE (decl)); + + add_AT_unsigned (die, DW_AT_decl_file, file_index); + add_AT_unsigned (die, DW_AT_decl_line, DECL_SOURCE_LINE (decl)); +} + +/* Add an DW_AT_name attribute and source coordinate attribute for the + given decl, but only if it actually has a name. */ + +static void +add_name_and_src_coords_attributes (die, decl) + register dw_die_ref die; + register tree decl; +{ + register tree decl_name; + + decl_name = DECL_NAME (decl); + if (decl_name != NULL && IDENTIFIER_POINTER (decl_name) != NULL) + { + add_name_attribute (die, dwarf2_name (decl, 0)); + add_src_coords_attributes (die, decl); + if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL) + && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)) + add_AT_string (die, DW_AT_MIPS_linkage_name, + IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))); + } +} + +/* Push a new declaration scope. */ + +static void +push_decl_scope (scope) + tree scope; +{ + tree containing_scope; + int i; + + /* Make room in the decl_scope_table, if necessary. */ + if (decl_scope_table_allocated == decl_scope_depth) + { + decl_scope_table_allocated += DECL_SCOPE_TABLE_INCREMENT; + decl_scope_table + = (decl_scope_node *) xrealloc (decl_scope_table, + (decl_scope_table_allocated + * sizeof (decl_scope_node))); + } + + decl_scope_table[decl_scope_depth].scope = scope; + + /* Sometimes, while recursively emitting subtypes within a class type, + we end up recuring on a subtype at a higher level then the current + subtype. In such a case, we need to search the decl_scope_table to + find the parent of this subtype. */ + + if (AGGREGATE_TYPE_P (scope)) + containing_scope = TYPE_CONTEXT (scope); + else + containing_scope = NULL_TREE; + + /* The normal case. */ + if (decl_scope_depth == 0 + || containing_scope == NULL_TREE + /* Ignore namespaces for the moment. */ + || TREE_CODE (containing_scope) == NAMESPACE_DECL + || containing_scope == decl_scope_table[decl_scope_depth - 1].scope) + decl_scope_table[decl_scope_depth].previous = decl_scope_depth - 1; + else + { + /* We need to search for the containing_scope. */ + for (i = 0; i < decl_scope_depth; i++) + if (decl_scope_table[i].scope == containing_scope) + break; + + if (i == decl_scope_depth) + abort (); + else + decl_scope_table[decl_scope_depth].previous = i; + } + + decl_scope_depth++; +} + +/* Return the DIE for the scope that immediately contains this declaration. */ + +static dw_die_ref +scope_die_for (t, context_die) + register tree t; + register dw_die_ref context_die; +{ + register dw_die_ref scope_die = NULL; + register tree containing_scope; + register int i; + + /* Walk back up the declaration tree looking for a place to define + this type. */ + if (TREE_CODE_CLASS (TREE_CODE (t)) == 't') + containing_scope = TYPE_CONTEXT (t); + else if (TREE_CODE (t) == FUNCTION_DECL && DECL_VINDEX (t)) + containing_scope = decl_class_context (t); + else + containing_scope = DECL_CONTEXT (t); + + /* Ignore namespaces for the moment. */ + if (containing_scope && TREE_CODE (containing_scope) == NAMESPACE_DECL) + containing_scope = NULL_TREE; + + /* Ignore function type "scopes" from the C frontend. They mean that + a tagged type is local to a parmlist of a function declarator, but + that isn't useful to DWARF. */ + if (containing_scope && TREE_CODE (containing_scope) == FUNCTION_TYPE) + containing_scope = NULL_TREE; + + /* Function-local tags and functions get stuck in limbo until they are + fixed up by decls_for_scope. */ + if (context_die == NULL && containing_scope != NULL_TREE + && (TREE_CODE (t) == FUNCTION_DECL || is_tagged_type (t))) + return NULL; + + if (containing_scope == NULL_TREE) + scope_die = comp_unit_die; + else + { + for (i = decl_scope_depth - 1, scope_die = context_die; + i >= 0 && decl_scope_table[i].scope != containing_scope; + (scope_die = scope_die->die_parent, + i = decl_scope_table[i].previous)) + ; + + /* ??? Integrate_decl_tree does not handle BLOCK_TYPE_TAGS, nor + does it try to handle types defined by TYPE_DECLs. Such types + thus have an incorrect TYPE_CONTEXT, which points to the block + they were originally defined in, instead of the current block + created by function inlining. We try to detect that here and + work around it. */ + + if (i < 0 && scope_die == comp_unit_die + && TREE_CODE (containing_scope) == BLOCK + && is_tagged_type (t) + && (block_ultimate_origin (decl_scope_table[decl_scope_depth - 1].scope) + == containing_scope)) + { + scope_die = context_die; + /* Since the checks below are no longer applicable. */ + i = 0; + } + + if (i < 0) + { + if (scope_die != comp_unit_die + || TREE_CODE_CLASS (TREE_CODE (containing_scope)) != 't') + abort (); + if (debug_info_level > DINFO_LEVEL_TERSE + && !TREE_ASM_WRITTEN (containing_scope)) + abort (); + } + } + + return scope_die; +} + +/* Pop a declaration scope. */ +static inline void +pop_decl_scope () +{ + if (decl_scope_depth <= 0) + abort (); + --decl_scope_depth; +} + +/* Many forms of DIEs require a "type description" attribute. This + routine locates the proper "type descriptor" die for the type given + by 'type', and adds an DW_AT_type attribute below the given die. */ + +static void +add_type_attribute (object_die, type, decl_const, decl_volatile, context_die) + register dw_die_ref object_die; + register tree type; + register int decl_const; + register int decl_volatile; + register dw_die_ref context_die; +{ + register enum tree_code code = TREE_CODE (type); + register dw_die_ref type_die = NULL; + + /* ??? If this type is an unnamed subrange type of an integral or + floating-point type, use the inner type. This is because we have no + support for unnamed types in base_type_die. This can happen if this is + an Ada subrange type. Correct solution is emit a subrange type die. */ + if ((code == INTEGER_TYPE || code == REAL_TYPE) + && TREE_TYPE (type) != 0 && TYPE_NAME (type) == 0) + type = TREE_TYPE (type), code = TREE_CODE (type); + + 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; + + type_die = modified_type_die (type, + decl_const || TYPE_READONLY (type), + decl_volatile || TYPE_VOLATILE (type), + context_die); + if (type_die != NULL) + add_AT_die_ref (object_die, DW_AT_type, type_die); +} + +/* 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 char * +type_tag (type) + register tree type; +{ + register char *name = 0; + + if (TYPE_NAME (type) != 0) + { + register 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; +} + +/* Return the type associated with a data member, make a special check + for bit field types. */ + +static inline tree +member_declared_type (member) + register tree member; +{ + return (DECL_BIT_FIELD_TYPE (member) + ? DECL_BIT_FIELD_TYPE (member) + : TREE_TYPE (member)); +} + +/* Get the decl's label, as described by its RTL. This may be different + from the DECL_NAME name used in the source file. */ + +#if 0 +static char * +decl_start_label (decl) + register tree decl; +{ + rtx x; + 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; +} +#endif + +/* These routines generate the internal representation of the DIE's for + the compilation unit. Debugging information is collected by walking + the declaration trees passed in from dwarf2out_decl(). */ + +static void +gen_array_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref scope_die = scope_die_for (type, context_die); + register dw_die_ref array_die; + register tree element_type; + + /* ??? The SGI dwarf reader fails for array of array of enum types unless + the inner array type comes before the outer array type. Thus we must + call gen_type_die before we call new_die. See below also. */ +#ifdef MIPS_DEBUGGING_INFO + gen_type_die (TREE_TYPE (type), context_die); +#endif + + array_die = new_die (DW_TAG_array_type, scope_die); + +#if 0 + /* We default the array ordering. SDB will probably do + the right things even if DW_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 DW_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. */ + add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_row_major); +#endif + +#ifdef MIPS_DEBUGGING_INFO + /* The SGI compilers handle arrays of unknown bound by setting + AT_declaration and not emitting any subrange DIEs. */ + if (! TYPE_DOMAIN (type)) + add_AT_unsigned (array_die, DW_AT_declaration, 1); + else +#endif + add_subscript_info (array_die, type); + + equate_type_number_to_die (type, array_die); + + /* Add representation of the type of the elements of this array type. */ + element_type = TREE_TYPE (type); + + /* ??? The SGI dwarf reader fails for multidimensional arrays with a + const enum type. E.g. const enum machine_mode insn_operand_mode[2][10]. + We work around this by disabling this feature. See also + add_subscript_info. */ +#ifndef MIPS_DEBUGGING_INFO + while (TREE_CODE (element_type) == ARRAY_TYPE) + element_type = TREE_TYPE (element_type); + + gen_type_die (element_type, context_die); +#endif + + add_type_attribute (array_die, element_type, 0, 0, context_die); +} + +static void +gen_set_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref type_die + = new_die (DW_TAG_set_type, scope_die_for (type, context_die)); + + equate_type_number_to_die (type, type_die); + add_type_attribute (type_die, TREE_TYPE (type), 0, 0, context_die); +} + +#if 0 +static void +gen_entry_point_die (decl, context_die) + register tree decl; + register dw_die_ref context_die; +{ + register tree origin = decl_ultimate_origin (decl); + register dw_die_ref decl_die = new_die (DW_TAG_entry_point, context_die); + if (origin != NULL) + add_abstract_origin_attribute (decl_die, origin); + else + { + add_name_and_src_coords_attributes (decl_die, decl); + add_type_attribute (decl_die, TREE_TYPE (TREE_TYPE (decl)), + 0, 0, context_die); + } + + if (DECL_ABSTRACT (decl)) + equate_decl_number_to_die (decl, decl_die); + else + add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl)); +} +#endif + +/* Remember a type in the pending_types_list. */ + +static void +pend_type (type) + register 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; +} + +/* 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. */ + +static void +output_pending_types_for_scope (context_die) + register dw_die_ref context_die; +{ + register tree type; + + while (pending_types) + { + --pending_types; + type = pending_types_list[pending_types]; + gen_type_die (type, context_die); + if (!TREE_ASM_WRITTEN (type)) + abort (); + } +} + +/* Generate a DIE to represent an inlined instance of an enumeration type. */ + +static void +gen_inlined_enumeration_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref type_die = new_die (DW_TAG_enumeration_type, + scope_die_for (type, context_die)); + + if (!TREE_ASM_WRITTEN (type)) + abort (); + add_abstract_origin_attribute (type_die, type); +} + +/* Generate a DIE to represent an inlined instance of a structure type. */ + +static void +gen_inlined_structure_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref type_die = new_die (DW_TAG_structure_type, + scope_die_for (type, context_die)); + + if (!TREE_ASM_WRITTEN (type)) + abort (); + add_abstract_origin_attribute (type_die, type); +} + +/* Generate a DIE to represent an inlined instance of a union type. */ + +static void +gen_inlined_union_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref type_die = new_die (DW_TAG_union_type, + scope_die_for (type, context_die)); + + if (!TREE_ASM_WRITTEN (type)) + abort (); + add_abstract_origin_attribute (type_die, type); +} + +/* Generate a DIE to represent an enumeration type. Note that these DIEs + include all of the information about the enumeration values also. Each + enumerated type name/value is listed as a child of the enumerated type + DIE. */ + +static void +gen_enumeration_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref type_die = lookup_type_die (type); + + if (type_die == NULL) + { + type_die = new_die (DW_TAG_enumeration_type, + scope_die_for (type, context_die)); + equate_type_number_to_die (type, type_die); + add_name_attribute (type_die, type_tag (type)); + } + else if (! TYPE_SIZE (type)) + return; + else + remove_AT (type_die, DW_AT_declaration); + + /* Handle a GNU C/C++ extension, i.e. incomplete enum types. If the + given enum type is incomplete, do not generate the DW_AT_byte_size + attribute or the DW_AT_element_list attribute. */ + if (TYPE_SIZE (type)) + { + register tree link; + + TREE_ASM_WRITTEN (type) = 1; + add_byte_size_attribute (type_die, type); + if (TYPE_STUB_DECL (type) != NULL_TREE) + add_src_coords_attributes (type_die, TYPE_STUB_DECL (type)); + + /* If the first reference to this type was as the return type of an + inline function, then it may not have a parent. Fix this now. */ + if (type_die->die_parent == NULL) + add_child_die (scope_die_for (type, context_die), type_die); + + for (link = TYPE_FIELDS (type); + link != NULL; link = TREE_CHAIN (link)) + { + register dw_die_ref enum_die = new_die (DW_TAG_enumerator, type_die); + + add_name_attribute (enum_die, + IDENTIFIER_POINTER (TREE_PURPOSE (link))); + add_AT_unsigned (enum_die, DW_AT_const_value, + (unsigned) TREE_INT_CST_LOW (TREE_VALUE (link))); + } + } + else + add_AT_flag (type_die, DW_AT_declaration, 1); +} + + +/* Generate 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 + DW_TAG_formal_parameter DIE to stand as a placeholder for some formal + argument type of some subprogram type. */ + +static dw_die_ref +gen_formal_parameter_die (node, context_die) + register tree node; + register dw_die_ref context_die; +{ + register dw_die_ref parm_die + = new_die (DW_TAG_formal_parameter, context_die); + register tree origin; + + switch (TREE_CODE_CLASS (TREE_CODE (node))) + { + case 'd': + origin = decl_ultimate_origin (node); + if (origin != NULL) + add_abstract_origin_attribute (parm_die, origin); + else + { + add_name_and_src_coords_attributes (parm_die, node); + add_type_attribute (parm_die, TREE_TYPE (node), + TREE_READONLY (node), + TREE_THIS_VOLATILE (node), + context_die); + if (DECL_ARTIFICIAL (node)) + add_AT_flag (parm_die, DW_AT_artificial, 1); + } + + equate_decl_number_to_die (node, parm_die); + if (! DECL_ABSTRACT (node)) + add_location_or_const_value_attribute (parm_die, node); + + break; + + case 't': + /* We were called with some kind of a ..._TYPE node. */ + add_type_attribute (parm_die, node, 0, 0, context_die); + break; + + default: + abort (); + } + + return parm_die; +} + +/* 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 +gen_unspecified_parameters_die (decl_or_type, context_die) + register tree decl_or_type; + register dw_die_ref context_die; +{ + new_die (DW_TAG_unspecified_parameters, context_die); +} + +/* Generate a list of nameless DW_TAG_formal_parameter DIEs (and perhaps a + DW_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 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 +gen_formal_types_die (function_or_method_type, context_die) + register tree function_or_method_type; + register dw_die_ref context_die; +{ + register tree link; + register tree formal_type = NULL; + register tree first_parm_type = TYPE_ARG_TYPES (function_or_method_type); + +#if 0 + /* 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 DW_AT_member attribute of the parent + DW_TAG_subroutine_type DIE. */ + if (TREE_CODE (function_or_method_type) == METHOD_TYPE) + first_parm_type = TREE_CHAIN (first_parm_type); +#endif + + /* Make our first pass over the list of formal parameter types and output a + DW_TAG_formal_parameter DIE for each one. */ + for (link = first_parm_type; link; link = TREE_CHAIN (link)) + { + register dw_die_ref parm_die; + + formal_type = TREE_VALUE (link); + if (formal_type == void_type_node) + break; + + /* Output a (nameless) DIE to represent the formal parameter itself. */ + parm_die = gen_formal_parameter_die (formal_type, context_die); + if (TREE_CODE (function_or_method_type) == METHOD_TYPE + && link == first_parm_type) + add_AT_flag (parm_die, DW_AT_artificial, 1); + } + + /* If this function type has an ellipsis, add a + DW_TAG_unspecified_parameters DIE to the end of the parameter list. */ + if (formal_type != void_type_node) + gen_unspecified_parameters_die (function_or_method_type, context_die); + + /* 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; + + gen_type_die (formal_type, context_die); + } +} + +/* Generate a DIE to represent a declared function (either file-scope or + block-local). */ + +static void +gen_subprogram_die (decl, context_die) + register tree decl; + register dw_die_ref context_die; +{ + char label_id[MAX_ARTIFICIAL_LABEL_BYTES]; + register tree origin = decl_ultimate_origin (decl); + register dw_die_ref subr_die; + register rtx fp_reg; + register tree fn_arg_types; + register tree outer_scope; + register dw_die_ref old_die = lookup_decl_die (decl); + register int declaration + = (current_function_decl != decl + || (context_die + && (context_die->die_tag == DW_TAG_structure_type + || context_die->die_tag == DW_TAG_union_type))); + + if (origin != NULL) + { + subr_die = new_die (DW_TAG_subprogram, context_die); + add_abstract_origin_attribute (subr_die, origin); + } + else if (old_die && DECL_ABSTRACT (decl) + && get_AT_unsigned (old_die, DW_AT_inline)) + { + /* This must be a redefinition of an extern inline function. + We can just reuse the old die here. */ + subr_die = old_die; + + /* Clear out the inlined attribute and parm types. */ + remove_AT (subr_die, DW_AT_inline); + remove_children (subr_die); + } + else if (old_die) + { + register unsigned file_index + = lookup_filename (DECL_SOURCE_FILE (decl)); + + if (get_AT_flag (old_die, DW_AT_declaration) != 1) + { + /* ??? This can happen if there is a bug in the program, for + instance, if it has duplicate function definitions. Ideally, + we should detect this case and ignore it. For now, if we have + already reported an error, any error at all, then assume that + we got here because of a input error, not a dwarf2 bug. */ + extern int errorcount; + if (errorcount) + return; + abort (); + } + + /* If the definition comes from the same place as the declaration, + maybe use the old DIE. We always want the DIE for this function + that has the *_pc attributes to be under comp_unit_die so the + debugger can find it. For inlines, that is the concrete instance, + so we can use the old DIE here. For non-inline methods, we want a + specification DIE at toplevel, so we need a new DIE. For local + class methods, this does not apply. */ + if ((DECL_ABSTRACT (decl) || old_die->die_parent == comp_unit_die + || context_die == NULL) + && get_AT_unsigned (old_die, DW_AT_decl_file) == file_index + && (get_AT_unsigned (old_die, DW_AT_decl_line) + == DECL_SOURCE_LINE (decl))) + { + subr_die = old_die; + + /* Clear out the declaration attribute and the parm types. */ + remove_AT (subr_die, DW_AT_declaration); + remove_children (subr_die); + } + else + { + subr_die = new_die (DW_TAG_subprogram, context_die); + add_AT_die_ref (subr_die, DW_AT_specification, old_die); + if (get_AT_unsigned (old_die, DW_AT_decl_file) != file_index) + add_AT_unsigned (subr_die, DW_AT_decl_file, file_index); + if (get_AT_unsigned (old_die, DW_AT_decl_line) + != DECL_SOURCE_LINE (decl)) + add_AT_unsigned + (subr_die, DW_AT_decl_line, DECL_SOURCE_LINE (decl)); + } + } + else + { + register dw_die_ref scope_die; + + if (DECL_CONTEXT (decl)) + scope_die = scope_die_for (decl, context_die); + else + /* Don't put block extern declarations under comp_unit_die. */ + scope_die = context_die; + + subr_die = new_die (DW_TAG_subprogram, scope_die); + + if (TREE_PUBLIC (decl)) + add_AT_flag (subr_die, DW_AT_external, 1); + + add_name_and_src_coords_attributes (subr_die, decl); + if (debug_info_level > DINFO_LEVEL_TERSE) + { + register tree type = TREE_TYPE (decl); + + add_prototyped_attribute (subr_die, type); + add_type_attribute (subr_die, TREE_TYPE (type), 0, 0, context_die); + } + + add_pure_or_virtual_attribute (subr_die, decl); + if (DECL_ARTIFICIAL (decl)) + add_AT_flag (subr_die, DW_AT_artificial, 1); + if (TREE_PROTECTED (decl)) + add_AT_unsigned (subr_die, DW_AT_accessibility, DW_ACCESS_protected); + else if (TREE_PRIVATE (decl)) + add_AT_unsigned (subr_die, DW_AT_accessibility, DW_ACCESS_private); + } + + if (declaration) + { + add_AT_flag (subr_die, DW_AT_declaration, 1); + + /* The first time we see a member function, it is in the context of + the class to which it belongs. We make sure of this by emitting + the class first. The next time is the definition, which is + handled above. The two may come from the same source text. */ + if (DECL_CONTEXT (decl)) + equate_decl_number_to_die (decl, subr_die); + } + else if (DECL_ABSTRACT (decl)) + { + /* ??? Checking DECL_DEFER_OUTPUT is correct for static inline functions, + but not for extern inline functions. We can't get this completely + correct because information about whether the function was declared + inline is not saved anywhere. */ + if (DECL_DEFER_OUTPUT (decl)) + { + if (DECL_INLINE (decl)) + add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_inlined); + else + add_AT_unsigned (subr_die, DW_AT_inline, + DW_INL_declared_not_inlined); + } + else if (DECL_INLINE (decl)) + add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined); + else + abort (); + + equate_decl_number_to_die (decl, subr_die); + } + else if (!DECL_EXTERNAL (decl)) + { + if (origin == NULL_TREE) + equate_decl_number_to_die (decl, subr_die); + + ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL, + current_funcdef_number); + add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id); + ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL, + current_funcdef_number); + add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id); + + add_pubname (decl, subr_die); + add_arange (decl, subr_die); + +#ifdef MIPS_DEBUGGING_INFO + /* Add a reference to the FDE for this routine. */ + add_AT_fde_ref (subr_die, DW_AT_MIPS_fde, current_funcdef_fde); +#endif + + /* Define the "frame base" location for this routine. We use the + frame pointer or stack pointer registers, since the RTL for local + variables is relative to one of them. */ + fp_reg + = frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx; + add_AT_loc (subr_die, DW_AT_frame_base, reg_loc_descriptor (fp_reg)); + +#if 0 + /* ??? This fails for nested inline functions, because context_display + is not part of the state saved/restored for inline functions. */ + if (current_function_needs_context) + add_AT_location_description (subr_die, DW_AT_static_link, + lookup_static_chain (decl)); +#endif + } + + /* 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. */ + push_decl_scope (decl); + + /* 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 (debug_info_level <= DINFO_LEVEL_TERSE) + ; + else if (declaration) + gen_formal_types_die (TREE_TYPE (decl), subr_die); + else + { + /* Generate DIEs to represent all known formal parameters */ + register tree arg_decls = DECL_ARGUMENTS (decl); + register tree parm; + + /* 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")) + gen_unspecified_parameters_die (parm, subr_die); + else + gen_decl_die (parm, subr_die); + } + + /* Decide whether we need a 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. */ + fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl)); + if (fn_arg_types != NULL) + { + /* this is the prototyped case, check for ... */ + if (TREE_VALUE (tree_last (fn_arg_types)) != void_type_node) + gen_unspecified_parameters_die (decl, subr_die); + } + else if (DECL_INITIAL (decl) == NULL_TREE) + gen_unspecified_parameters_die (decl, subr_die); + } + + /* Output Dwarf info for all of the stuff within the body of the function + (if it has one - it may be just a declaration). */ + outer_scope = DECL_INITIAL (decl); + + /* 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 in + decls_for_scope. 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. */ + if (! declaration && TREE_CODE (outer_scope) != ERROR_MARK) + { + current_function_has_inlines = 0; + decls_for_scope (outer_scope, subr_die, 0); + +#if 0 && defined (MIPS_DEBUGGING_INFO) + if (current_function_has_inlines) + { + add_AT_flag (subr_die, DW_AT_MIPS_has_inlines, 1); + if (! comp_unit_has_inlines) + { + add_AT_flag (comp_unit_die, DW_AT_MIPS_has_inlines, 1); + comp_unit_has_inlines = 1; + } + } +#endif + } + + pop_decl_scope (); +} + +/* Generate a DIE to represent a declared data object. */ + +static void +gen_variable_die (decl, context_die) + register tree decl; + register dw_die_ref context_die; +{ + register tree origin = decl_ultimate_origin (decl); + register dw_die_ref var_die = new_die (DW_TAG_variable, context_die); + + dw_die_ref old_die = lookup_decl_die (decl); + int declaration + = (DECL_EXTERNAL (decl) + || current_function_decl != decl_function_context (decl) + || context_die->die_tag == DW_TAG_structure_type + || context_die->die_tag == DW_TAG_union_type); + + if (origin != NULL) + add_abstract_origin_attribute (var_die, origin); + /* Loop unrolling can create multiple blocks that refer to the same + static variable, so we must test for the DW_AT_declaration flag. */ + /* ??? Loop unrolling/reorder_blocks should perhaps be rewritten to + copy decls and set the DECL_ABSTRACT flag on them instead of + sharing them. */ + else if (old_die && TREE_STATIC (decl) + && get_AT_flag (old_die, DW_AT_declaration) == 1) + { + /* ??? This is an instantiation of a C++ class level static. */ + add_AT_die_ref (var_die, DW_AT_specification, old_die); + if (DECL_NAME (decl)) + { + register unsigned file_index + = lookup_filename (DECL_SOURCE_FILE (decl)); + + if (get_AT_unsigned (old_die, DW_AT_decl_file) != file_index) + add_AT_unsigned (var_die, DW_AT_decl_file, file_index); + + if (get_AT_unsigned (old_die, DW_AT_decl_line) + != DECL_SOURCE_LINE (decl)) + + add_AT_unsigned (var_die, DW_AT_decl_line, + DECL_SOURCE_LINE (decl)); + } + } + else + { + add_name_and_src_coords_attributes (var_die, decl); + add_type_attribute (var_die, TREE_TYPE (decl), + TREE_READONLY (decl), + TREE_THIS_VOLATILE (decl), context_die); + + if (TREE_PUBLIC (decl)) + add_AT_flag (var_die, DW_AT_external, 1); + + if (DECL_ARTIFICIAL (decl)) + add_AT_flag (var_die, DW_AT_artificial, 1); + + if (TREE_PROTECTED (decl)) + add_AT_unsigned (var_die, DW_AT_accessibility, DW_ACCESS_protected); + + else if (TREE_PRIVATE (decl)) + add_AT_unsigned (var_die, DW_AT_accessibility, DW_ACCESS_private); + } + + if (declaration) + add_AT_flag (var_die, DW_AT_declaration, 1); + + if ((declaration && decl_class_context (decl)) || DECL_ABSTRACT (decl)) + equate_decl_number_to_die (decl, var_die); + + if (! declaration && ! DECL_ABSTRACT (decl)) + { + equate_decl_number_to_die (decl, var_die); + add_location_or_const_value_attribute (var_die, decl); + add_pubname (decl, var_die); + } +} + +/* Generate a DIE to represent a label identifier. */ + +static void +gen_label_die (decl, context_die) + register tree decl; + register dw_die_ref context_die; +{ + register tree origin = decl_ultimate_origin (decl); + register dw_die_ref lbl_die = new_die (DW_TAG_label, context_die); + register rtx insn; + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + char label2[MAX_ARTIFICIAL_LABEL_BYTES]; + + if (origin != NULL) + add_abstract_origin_attribute (lbl_die, origin); + else + add_name_and_src_coords_attributes (lbl_die, decl); + + if (DECL_ABSTRACT (decl)) + equate_decl_number_to_die (decl, lbl_die); + else + { + insn = DECL_RTL (decl); + if (GET_CODE (insn) == CODE_LABEL) + { + /* 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 (); + + sprintf (label2, INSN_LABEL_FMT, current_funcdef_number); + ASM_GENERATE_INTERNAL_LABEL (label, label2, + (unsigned) INSN_UID (insn)); + add_AT_lbl_id (lbl_die, DW_AT_low_pc, label); + } + } +} + +/* Generate a DIE for a lexical block. */ + +static void +gen_lexical_block_die (stmt, context_die, depth) + register tree stmt; + register dw_die_ref context_die; + int depth; +{ + register dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die); + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + if (! BLOCK_ABSTRACT (stmt)) + { + ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL, + next_block_number); + add_AT_lbl_id (stmt_die, DW_AT_low_pc, label); + ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL, next_block_number); + add_AT_lbl_id (stmt_die, DW_AT_high_pc, label); + } + + push_decl_scope (stmt); + decls_for_scope (stmt, stmt_die, depth); + pop_decl_scope (); +} + +/* Generate a DIE for an inlined subprogram. */ + +static void +gen_inlined_subroutine_die (stmt, context_die, depth) + register tree stmt; + register dw_die_ref context_die; + int depth; +{ + if (! BLOCK_ABSTRACT (stmt)) + { + register dw_die_ref subr_die + = new_die (DW_TAG_inlined_subroutine, context_die); + register tree decl = block_ultimate_origin (stmt); + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + add_abstract_origin_attribute (subr_die, decl); + ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL, + next_block_number); + add_AT_lbl_id (subr_die, DW_AT_low_pc, label); + ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL, next_block_number); + add_AT_lbl_id (subr_die, DW_AT_high_pc, label); + push_decl_scope (decl); + decls_for_scope (stmt, subr_die, depth); + pop_decl_scope (); + current_function_has_inlines = 1; + } +} + +/* Generate a DIE for a field in a record, or structure. */ + +static void +gen_field_die (decl, context_die) + register tree decl; + register dw_die_ref context_die; +{ + register dw_die_ref decl_die = new_die (DW_TAG_member, context_die); + + add_name_and_src_coords_attributes (decl_die, decl); + add_type_attribute (decl_die, member_declared_type (decl), + TREE_READONLY (decl), TREE_THIS_VOLATILE (decl), + context_die); + + /* If this is a bit field... */ + if (DECL_BIT_FIELD_TYPE (decl)) + { + add_byte_size_attribute (decl_die, decl); + add_bit_size_attribute (decl_die, decl); + add_bit_offset_attribute (decl_die, decl); + } + + if (TREE_CODE (DECL_FIELD_CONTEXT (decl)) != UNION_TYPE) + add_data_member_location_attribute (decl_die, decl); + + if (DECL_ARTIFICIAL (decl)) + add_AT_flag (decl_die, DW_AT_artificial, 1); + + if (TREE_PROTECTED (decl)) + add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_protected); + + else if (TREE_PRIVATE (decl)) + add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_private); +} + +#if 0 +/* Don't generate either pointer_type DIEs or reference_type DIEs here. + Use modified_type_die 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 +gen_pointer_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref ptr_die + = new_die (DW_TAG_pointer_type, scope_die_for (type, context_die)); + + equate_type_number_to_die (type, ptr_die); + add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die); + add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE); +} + +/* Don't generate either pointer_type DIEs or reference_type DIEs here. + Use modified_type_die 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 +gen_reference_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref ref_die + = new_die (DW_TAG_reference_type, scope_die_for (type, context_die)); + + equate_type_number_to_die (type, ref_die); + add_type_attribute (ref_die, TREE_TYPE (type), 0, 0, context_die); + add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE); +} +#endif + +/* Generate a DIE for a pointer to a member type. */ +static void +gen_ptr_to_mbr_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref ptr_die + = new_die (DW_TAG_ptr_to_member_type, scope_die_for (type, context_die)); + + equate_type_number_to_die (type, ptr_die); + add_AT_die_ref (ptr_die, DW_AT_containing_type, + lookup_type_die (TYPE_OFFSET_BASETYPE (type))); + add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die); +} + +/* Generate the DIE for the compilation unit. */ + +static void +gen_compile_unit_die (main_input_filename) + register char *main_input_filename; +{ + char producer[250]; + char *wd = getpwd (); + + comp_unit_die = new_die (DW_TAG_compile_unit, NULL); + add_name_attribute (comp_unit_die, main_input_filename); + + if (wd != NULL) + add_AT_string (comp_unit_die, DW_AT_comp_dir, wd); + + sprintf (producer, "%s %s", language_string, version_string); + +#ifdef MIPS_DEBUGGING_INFO + /* The MIPS/SGI compilers place the 'cc' command line options in the producer + string. The SGI debugger looks for -g, -g1, -g2, or -g3; if they do + not appear in the producer string, the debugger reaches the conclusion + that the object file is stripped and has no debugging information. + To get the MIPS/SGI debugger to believe that there is debugging + information in the object file, we add a -g to the producer string. */ + if (debug_info_level > DINFO_LEVEL_TERSE) + strcat (producer, " -g"); +#endif + + add_AT_string (comp_unit_die, DW_AT_producer, producer); + + if (strcmp (language_string, "GNU C++") == 0) + add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C_plus_plus); + + else if (strcmp (language_string, "GNU Ada") == 0) + add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Ada83); + + else if (strcmp (language_string, "GNU F77") == 0) + add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Fortran77); + + else if (strcmp (language_string, "GNU Pascal") == 0) + add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Pascal83); + + else if (flag_traditional) + add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C); + + else + add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C89); + +#if 0 /* unimplemented */ + if (debug_info_level >= DINFO_LEVEL_VERBOSE) + add_AT_unsigned (comp_unit_die, DW_AT_macro_info, 0); +#endif +} + +/* Generate a DIE for a string type. */ + +static void +gen_string_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref type_die + = new_die (DW_TAG_string_type, scope_die_for (type, context_die)); + + equate_type_number_to_die (type, type_die); + + /* Fudge the string length attribute for now. */ + + /* TODO: add string length info. + string_length_attribute (TYPE_MAX_VALUE (TYPE_DOMAIN (type))); + bound_representation (upper_bound, 0, 'u'); */ +} + +/* Generate the DIE for a base class. */ + +static void +gen_inheritance_die (binfo, context_die) + register tree binfo; + register dw_die_ref context_die; +{ + dw_die_ref die = new_die (DW_TAG_inheritance, context_die); + + add_type_attribute (die, BINFO_TYPE (binfo), 0, 0, context_die); + add_data_member_location_attribute (die, binfo); + + if (TREE_VIA_VIRTUAL (binfo)) + add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual); + if (TREE_VIA_PUBLIC (binfo)) + add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_public); + else if (TREE_VIA_PROTECTED (binfo)) + add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_protected); +} + +/* Generate a DIE for a class member. */ + +static void +gen_member_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register tree member; + + /* 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 `type' + function (above) will specifically avoid generating type DIEs for member + types *within* the list of member DIEs for this (containing) type execpt + 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. */ + + /* 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++) + gen_inheritance_die (TREE_VEC_ELT (bases, i), context_die); + } + + /* Now output info about the data members and type members. */ + for (member = TYPE_FIELDS (type); member; member = TREE_CHAIN (member)) + gen_decl_die (member, context_die); + + /* Now output info about the function members (if any). */ + for (member = TYPE_METHODS (type); member; member = TREE_CHAIN (member)) + gen_decl_die (member, context_die); +} + +/* Generate a DIE for a structure or union type. */ + +static void +gen_struct_or_union_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref type_die = lookup_type_die (type); + register dw_die_ref scope_die = 0; + register int nested = 0; + + if (type_die && ! TYPE_SIZE (type)) + return; + + if (TYPE_CONTEXT (type) != NULL_TREE + && AGGREGATE_TYPE_P (TYPE_CONTEXT (type))) + nested = 1; + + scope_die = scope_die_for (type, context_die); + + if (! type_die || (nested && scope_die == comp_unit_die)) + /* First occurrence of type or toplevel definition of nested class. */ + { + register dw_die_ref old_die = type_die; + + type_die = new_die (TREE_CODE (type) == RECORD_TYPE + ? DW_TAG_structure_type : DW_TAG_union_type, + scope_die); + equate_type_number_to_die (type, type_die); + add_name_attribute (type_die, type_tag (type)); + if (old_die) + add_AT_die_ref (type_die, DW_AT_specification, old_die); + } + else + remove_AT (type_die, DW_AT_declaration); + + /* If we're not in the right context to be defining this type, defer to + avoid tricky recursion. */ + if (TYPE_SIZE (type) && decl_scope_depth > 0 && scope_die == comp_unit_die) + { + add_AT_flag (type_die, DW_AT_declaration, 1); + pend_type (type); + } + /* If this type has been completed, then give it a byte_size attribute and + then give a list of members. */ + else if (TYPE_SIZE (type)) + { + /* 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; + add_byte_size_attribute (type_die, type); + if (TYPE_STUB_DECL (type) != NULL_TREE) + add_src_coords_attributes (type_die, TYPE_STUB_DECL (type)); + + /* If the first reference to this type was as the return type of an + inline function, then it may not have a parent. Fix this now. */ + if (type_die->die_parent == NULL) + add_child_die (scope_die, type_die); + + push_decl_scope (type); + gen_member_die (type, type_die); + pop_decl_scope (); + + /* GNU extension: Record what type our vtable lives in. */ + if (TYPE_VFIELD (type)) + { + tree vtype = DECL_FCONTEXT (TYPE_VFIELD (type)); + + gen_type_die (vtype, context_die); + add_AT_die_ref (type_die, DW_AT_containing_type, + lookup_type_die (vtype)); + } + } + else + add_AT_flag (type_die, DW_AT_declaration, 1); +} + +/* Generate a DIE for a subroutine _type_. */ + +static void +gen_subroutine_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register tree return_type = TREE_TYPE (type); + register dw_die_ref subr_die + = new_die (DW_TAG_subroutine_type, scope_die_for (type, context_die)); + + equate_type_number_to_die (type, subr_die); + add_prototyped_attribute (subr_die, type); + add_type_attribute (subr_die, return_type, 0, 0, context_die); + gen_formal_types_die (type, subr_die); +} + +/* Generate a DIE for a type definition */ + +static void +gen_typedef_die (decl, context_die) + register tree decl; + register dw_die_ref context_die; +{ + register dw_die_ref type_die; + register tree origin; + + if (TREE_ASM_WRITTEN (decl)) + return; + TREE_ASM_WRITTEN (decl) = 1; + + type_die = new_die (DW_TAG_typedef, scope_die_for (decl, context_die)); + origin = decl_ultimate_origin (decl); + if (origin != NULL) + add_abstract_origin_attribute (type_die, origin); + else + { + register tree type; + add_name_and_src_coords_attributes (type_die, decl); + if (DECL_ORIGINAL_TYPE (decl)) + { + type = DECL_ORIGINAL_TYPE (decl); + equate_type_number_to_die (TREE_TYPE (decl), type_die); + } + else + type = TREE_TYPE (decl); + add_type_attribute (type_die, type, TREE_READONLY (decl), + TREE_THIS_VOLATILE (decl), context_die); + } + + if (DECL_ABSTRACT (decl)) + equate_decl_number_to_die (decl, type_die); +} + +/* Generate a type description DIE. */ + +static void +gen_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + if (type == NULL_TREE || 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)) + return; + + if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && DECL_ORIGINAL_TYPE (TYPE_NAME (type))) + { + TREE_ASM_WRITTEN (type) = 1; + gen_decl_die (TYPE_NAME (type), context_die); + return; + } + + switch (TREE_CODE (type)) + { + case ERROR_MARK: + break; + + case POINTER_TYPE: + case REFERENCE_TYPE: + /* We must set TREE_ASM_WRITTEN in case this is a recursive type. This + ensures that the gen_type_die recursion will terminate even if the + type is recursive. Recursive types are possible in Ada. */ + /* ??? We could perhaps do this for all types before the switch + statement. */ + 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. */ + gen_type_die (TREE_TYPE (type), context_die); + break; + + case OFFSET_TYPE: + /* This code is used for C++ pointer-to-data-member types. + Output a description of the relevant class type. */ + gen_type_die (TYPE_OFFSET_BASETYPE (type), context_die); + + /* Output a description of the type of the object pointed to. */ + gen_type_die (TREE_TYPE (type), context_die); + + /* Now output a DIE to represent this pointer-to-data-member type + itself. */ + gen_ptr_to_mbr_type_die (type, context_die); + break; + + case SET_TYPE: + gen_type_die (TYPE_DOMAIN (type), context_die); + gen_set_type_die (type, context_die); + break; + + case FILE_TYPE: + gen_type_die (TREE_TYPE (type), context_die); + 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). */ + gen_type_die (TREE_TYPE (type), context_die); + gen_subroutine_type_die (type, context_die); + break; + + case METHOD_TYPE: + /* Force out return type (in case it wasn't forced out already). */ + gen_type_die (TREE_TYPE (type), context_die); + gen_subroutine_type_die (type, context_die); + break; + + case ARRAY_TYPE: + if (TYPE_STRING_FLAG (type) && TREE_CODE (TREE_TYPE (type)) == CHAR_TYPE) + { + gen_type_die (TREE_TYPE (type), context_die); + gen_string_type_die (type, context_die); + } + else + gen_array_type_die (type, context_die); + break; + + case ENUMERAL_TYPE: + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + /* 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) + && AGGREGATE_TYPE_P (TYPE_CONTEXT (type)) + && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type))) + { + gen_type_die (TYPE_CONTEXT (type), context_die); + + if (TREE_ASM_WRITTEN (TYPE_CONTEXT (type))) + return; + + /* If that failed, attach ourselves to the stub. */ + push_decl_scope (TYPE_CONTEXT (type)); + context_die = lookup_type_die (TYPE_CONTEXT (type)); + } + + if (TREE_CODE (type) == ENUMERAL_TYPE) + gen_enumeration_type_die (type, context_die); + else + gen_struct_or_union_type_die (type, context_die); + + if (TYPE_CONTEXT (type) + && AGGREGATE_TYPE_P (TYPE_CONTEXT (type)) + && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type))) + pop_decl_scope (); + + /* Don't set TREE_ASM_WRITTEN on an incomplete struct; we want to fix + it up if it is ever completed. gen_*_type_die will set it for us + when appropriate. */ + return; + + case VOID_TYPE: + case INTEGER_TYPE: + case REAL_TYPE: + case COMPLEX_TYPE: + case BOOLEAN_TYPE: + case CHAR_TYPE: + /* No DIEs needed for fundamental types. */ + break; + + case LANG_TYPE: + /* No Dwarf representation currently defined. */ + break; + + default: + abort (); + } + + TREE_ASM_WRITTEN (type) = 1; +} + +/* Generate a DIE for a tagged type instantiation. */ + +static void +gen_tagged_type_instantiation_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + if (type == NULL_TREE || 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) + || !TREE_ASM_WRITTEN (type)) + abort (); + + switch (TREE_CODE (type)) + { + case ERROR_MARK: + break; + + case ENUMERAL_TYPE: + gen_inlined_enumeration_type_die (type, context_die); + break; + + case RECORD_TYPE: + gen_inlined_structure_type_die (type, context_die); + break; + + case UNION_TYPE: + case QUAL_UNION_TYPE: + gen_inlined_union_type_die (type, context_die); + break; + + default: + abort (); + } +} + +/* Generate a DW_TAG_lexical_block DIE followed by DIEs to represent all of the + things which are local to the given block. */ + +static void +gen_block_die (stmt, context_die, depth) + register tree stmt; + register dw_die_ref context_die; + int depth; +{ + register int must_output_die = 0; + register tree origin; + register tree decl; + register enum tree_code origin_code; + + /* Ignore blocks never really used to make RTL. */ + + if (stmt == NULL_TREE || !TREE_USED (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 DW_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 + /* We are in terse mode, so only local (nested) function + definitions count as "significant" local declarations. */ + for (decl = BLOCK_VARS (stmt); + decl != NULL; 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 DW_TAG_lexical_block + DIE for any block which contains no significant local declarations at + all. Rather, in such cases we just call `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 (must_output_die) + { + if (origin_code == FUNCTION_DECL) + gen_inlined_subroutine_die (stmt, context_die, depth); + else + gen_lexical_block_die (stmt, context_die, depth); + } + else + decls_for_scope (stmt, context_die, depth); +} + +/* Generate all of the decls declared within a given scope and (recursively) + all of its sub-blocks. */ + +static void +decls_for_scope (stmt, context_die, depth) + register tree stmt; + register dw_die_ref context_die; + int depth; +{ + register tree decl; + register tree subblocks; + + /* Ignore blocks never really used to make RTL. */ + if (stmt == NULL_TREE || ! TREE_USED (stmt)) + return; + + if (!BLOCK_ABSTRACT (stmt) && depth > 0) + next_block_number++; + + /* Output the DIEs to represent all of the data objects and typedefs + declared directly within this block but not within any nested + sub-blocks. Also, nested function and tag DIEs have been + generated with a parent of NULL; fix that up now. */ + for (decl = BLOCK_VARS (stmt); + decl != NULL; decl = TREE_CHAIN (decl)) + { + register dw_die_ref die; + + if (TREE_CODE (decl) == FUNCTION_DECL) + die = lookup_decl_die (decl); + else if (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl)) + die = lookup_type_die (TREE_TYPE (decl)); + else + die = NULL; + + if (die != NULL && die->die_parent == NULL) + add_child_die (context_die, die); + else + gen_decl_die (decl, context_die); + } + + /* Output the DIEs to represent all sub-blocks (and the items declared + therein) of this block. */ + for (subblocks = BLOCK_SUBBLOCKS (stmt); + subblocks != NULL; + subblocks = BLOCK_CHAIN (subblocks)) + gen_block_die (subblocks, context_die, depth + 1); +} + +/* Is this a typedef we can avoid emitting? */ + +static inline int +is_redundant_typedef (decl) + register 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; +} + +/* Generate Dwarf debug information for a decl described by DECL. */ + +static void +gen_decl_die (decl, context_die) + register tree decl; + register dw_die_ref context_die; +{ + register tree origin; + + /* 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 this ..._DECL node is marked to be ignored, then ignore it. But don't + ignore a function definition, since that would screw up our count of + blocks, and that in turn will completely screw up the labels we will + reference in subsequent DW_AT_low_pc and DW_AT_high_pc attributes (for + subsequent blocks). */ + if (DECL_IGNORED_P (decl) && TREE_CODE (decl) != FUNCTION_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: + /* Don't output any DIEs to represent mere function declarations, + unless they are class members or explicit block externs. */ + if (DECL_INITIAL (decl) == NULL_TREE && DECL_CONTEXT (decl) == NULL_TREE + && (current_function_decl == NULL_TREE || ! DECL_ARTIFICIAL (decl))) + break; + + if (debug_info_level > DINFO_LEVEL_TERSE) + { + /* Before we describe the FUNCTION_DECL itself, make sure that we + have described its return type. */ + gen_type_die (TREE_TYPE (TREE_TYPE (decl)), context_die); + + /* And its containing type. */ + origin = decl_class_context (decl); + if (origin != NULL_TREE) + gen_type_die (origin, context_die); + + /* And its virtual context. */ + if (DECL_VINDEX (decl) != NULL_TREE) + gen_type_die (DECL_CONTEXT (decl), context_die); + } + + /* Now output a DIE to represent the function itself. */ + gen_subprogram_die (decl, context_die); + break; + + case TYPE_DECL: + /* If we are in terse mode, don't generate any DIEs to represent any + actual typedefs. */ + if (debug_info_level <= DINFO_LEVEL_TERSE) + break; + + /* 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) + DW_TAG_structure_type, DW_TAG_union_type, or DW_TAG_enumeration_type + DIE here. */ + if (TYPE_DECL_IS_STUB (decl) && DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE) + { + gen_tagged_type_instantiation_die (TREE_TYPE (decl), context_die); + break; + } + + if (is_redundant_typedef (decl)) + gen_type_die (TREE_TYPE (decl), context_die); + else + /* Output a DIE to represent the typedef itself. */ + gen_typedef_die (decl, context_die); + break; + + case LABEL_DECL: + if (debug_info_level >= DINFO_LEVEL_NORMAL) + gen_label_die (decl, context_die); + break; + + case VAR_DECL: + /* 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. */ + gen_type_die (TREE_TYPE (decl), context_die); + + /* And its containing type. */ + origin = decl_class_context (decl); + if (origin != NULL_TREE) + gen_type_die (origin, context_die); + + /* 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. */ + origin = decl_ultimate_origin (decl); + if (origin != NULL_TREE && TREE_CODE (origin) == PARM_DECL) + gen_formal_parameter_die (decl, context_die); + else + gen_variable_die (decl, context_die); + break; + + case FIELD_DECL: + /* Ignore the nameless fields that are used to skip bits, but + handle C++ anonymous unions. */ + if (DECL_NAME (decl) != NULL_TREE + || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE) + { + gen_type_die (member_declared_type (decl), context_die); + gen_field_die (decl, context_die); + } + break; + + case PARM_DECL: + gen_type_die (TREE_TYPE (decl), context_die); + gen_formal_parameter_die (decl, context_die); + break; + + default: + abort (); + } +} + +/* Write the debugging output for DECL. */ + +void +dwarf2out_decl (decl) + register tree decl; +{ + register dw_die_ref context_die = comp_unit_die; + + if (TREE_CODE (decl) == ERROR_MARK) + return; + + /* If this ..._DECL node is marked to be ignored, then ignore it. We gotta + hope that the node in question doesn't represent a function definition. + If it does, then totally ignoring it is bound to screw up our count of + blocks, and that in turn will completely screw up the labels we will + reference in subsequent DW_AT_low_pc and DW_AT_high_pc attributes (for + subsequent blocks). (It's too bad that BLOCK nodes don't carry their + own sequence numbers with them!) */ + if (DECL_IGNORED_P (decl)) + { + if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_INITIAL (decl) != NULL) + abort (); + + 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 wil 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 we're a nested function, initially use a parent of NULL; if we're + a plain function, this will be fixed up in decls_for_scope. If + we're a method, it will be ignored, since we already have a DIE. */ + if (decl_function_context (decl)) + context_die = NULL; + + 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 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. */ + if (DECL_SOURCE_LINE (decl) == 0) + { + /* OK, we need to generate one for `bool' so GDB knows what type + comparisons have. */ + if ((get_AT_unsigned (comp_unit_die, DW_AT_language) + == DW_LANG_C_plus_plus) + && TREE_CODE (TREE_TYPE (decl)) == BOOLEAN_TYPE) + modified_type_die (TREE_TYPE (decl), 0, 0, NULL); + + return; + } + + /* If we are in terse mode, don't generate any DIEs for types. */ + if (debug_info_level <= DINFO_LEVEL_TERSE) + return; + + /* If we're a function-scope tag, initially use a parent of NULL; + this will be fixed up in decls_for_scope. */ + if (decl_function_context (decl)) + context_die = NULL; + + break; + + default: + return; + } + + gen_decl_die (decl, context_die); + output_pending_types_for_scope (comp_unit_die); +} + +/* Output a marker (i.e. a label) for the beginning of the generated code for + a lexical block. */ + +void +dwarf2out_begin_block (blocknum) + register unsigned blocknum; +{ + function_section (current_function_decl); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum); +} + +/* Output a marker (i.e. a label) for the end of the generated code for a + lexical block. */ + +void +dwarf2out_end_block (blocknum) + register unsigned blocknum; +{ + function_section (current_function_decl); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum); +} + +/* Output a marker (i.e. a label) at a point in the assembly code which + corresponds to a given source level label. */ + +void +dwarf2out_label (insn) + register rtx insn; +{ + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + if (debug_info_level >= DINFO_LEVEL_NORMAL) + { + function_section (current_function_decl); + sprintf (label, INSN_LABEL_FMT, current_funcdef_number); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, label, + (unsigned) INSN_UID (insn)); + } +} + +/* Lookup a filename (in the list of filenames that we know about here in + dwarf2out.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 + files numbers (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. + In order to speed up searches, we remember the index of the filename + was looked up last. This handles the majority of all searches. */ + +static unsigned +lookup_filename (file_name) + char *file_name; +{ + static unsigned last_file_lookup_index = 0; + register unsigned i; + + /* Check to see if the file name that was searched on the previous call + matches this file name. If so, return the index. */ + if (last_file_lookup_index != 0) + if (strcmp (file_name, file_table[last_file_lookup_index]) == 0) + return last_file_lookup_index; + + /* Didn't match the previous lookup, search the table */ + for (i = 1; i < file_table_in_use; ++i) + if (strcmp (file_name, file_table[i]) == 0) + { + last_file_lookup_index = i; + return i; + } + + /* 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 (file_table_in_use == file_table_allocated) + { + file_table_allocated += FILE_TABLE_INCREMENT; + file_table + = (char **) xrealloc (file_table, + file_table_allocated * sizeof (char *)); + } + + /* Add the new entry to the end of the filename table. */ + file_table[file_table_in_use] = xstrdup (file_name); + last_file_lookup_index = file_table_in_use++; + + return last_file_lookup_index; +} + +/* Output a label to mark the beginning of a source code line entry + and record information relating to this source line, in + 'line_info_table' for later output of the .debug_line section. */ + +void +dwarf2out_line (filename, line) + register char *filename; + register unsigned line; +{ + if (debug_info_level >= DINFO_LEVEL_NORMAL) + { + function_section (current_function_decl); + + if (DECL_SECTION_NAME (current_function_decl)) + { + register dw_separate_line_info_ref line_info; + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, SEPARATE_LINE_CODE_LABEL, + separate_line_info_table_in_use); + fputc ('\n', asm_out_file); + + /* expand the line info table if necessary */ + if (separate_line_info_table_in_use + == separate_line_info_table_allocated) + { + separate_line_info_table_allocated += LINE_INFO_TABLE_INCREMENT; + separate_line_info_table + = (dw_separate_line_info_ref) + xrealloc (separate_line_info_table, + separate_line_info_table_allocated + * sizeof (dw_separate_line_info_entry)); + } + + /* Add the new entry at the end of the line_info_table. */ + line_info + = &separate_line_info_table[separate_line_info_table_in_use++]; + line_info->dw_file_num = lookup_filename (filename); + line_info->dw_line_num = line; + line_info->function = current_funcdef_number; + } + else + { + register dw_line_info_ref line_info; + + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, LINE_CODE_LABEL, + line_info_table_in_use); + fputc ('\n', asm_out_file); + + /* Expand the line info table if necessary. */ + if (line_info_table_in_use == line_info_table_allocated) + { + line_info_table_allocated += LINE_INFO_TABLE_INCREMENT; + line_info_table + = (dw_line_info_ref) + xrealloc (line_info_table, + (line_info_table_allocated + * sizeof (dw_line_info_entry))); + } + + /* Add the new entry at the end of the line_info_table. */ + line_info = &line_info_table[line_info_table_in_use++]; + line_info->dw_file_num = lookup_filename (filename); + line_info->dw_line_num = line; + } + } +} + +/* Record the beginning of a new source file, for later output + of the .debug_macinfo section. At present, unimplemented. */ + +void +dwarf2out_start_source_file (filename) + register char *filename ATTRIBUTE_UNUSED; +{ +} + +/* Record the end of a source file, for later output + of the .debug_macinfo section. At present, unimplemented. */ + +void +dwarf2out_end_source_file () +{ +} + +/* 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. */ + +void +dwarf2out_define (lineno, buffer) + register unsigned lineno; + register char *buffer; +{ + static int initialized = 0; + if (!initialized) + { + dwarf2out_start_source_file (primary_filename); + initialized = 1; + } +} + +/* 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. */ + +void +dwarf2out_undef (lineno, buffer) + register unsigned lineno ATTRIBUTE_UNUSED; + register char *buffer ATTRIBUTE_UNUSED; +{ +} + +/* Set up for Dwarf output at the start of compilation. */ + +void +dwarf2out_init (asm_out_file, main_input_filename) + register FILE *asm_out_file; + register char *main_input_filename; +{ + /* Remember the name of the primary input file. */ + primary_filename = main_input_filename; + + /* Allocate the initial hunk of the file_table. */ + file_table = (char **) xmalloc (FILE_TABLE_INCREMENT * sizeof (char *)); + bzero ((char *) file_table, FILE_TABLE_INCREMENT * sizeof (char *)); + file_table_allocated = FILE_TABLE_INCREMENT; + + /* Skip the first entry - file numbers begin at 1. */ + file_table_in_use = 1; + + /* Allocate the initial hunk of the decl_die_table. */ + decl_die_table + = (dw_die_ref *) xmalloc (DECL_DIE_TABLE_INCREMENT * sizeof (dw_die_ref)); + bzero ((char *) decl_die_table, + DECL_DIE_TABLE_INCREMENT * sizeof (dw_die_ref)); + decl_die_table_allocated = DECL_DIE_TABLE_INCREMENT; + decl_die_table_in_use = 0; + + /* Allocate the initial hunk of the decl_scope_table. */ + decl_scope_table + = (decl_scope_node *) xmalloc (DECL_SCOPE_TABLE_INCREMENT + * sizeof (decl_scope_node)); + bzero ((char *) decl_scope_table, + DECL_SCOPE_TABLE_INCREMENT * sizeof (decl_scope_node)); + decl_scope_table_allocated = DECL_SCOPE_TABLE_INCREMENT; + decl_scope_depth = 0; + + /* Allocate the initial hunk of the abbrev_die_table. */ + abbrev_die_table + = (dw_die_ref *) xmalloc (ABBREV_DIE_TABLE_INCREMENT + * sizeof (dw_die_ref)); + bzero ((char *) abbrev_die_table, + ABBREV_DIE_TABLE_INCREMENT * sizeof (dw_die_ref)); + abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT; + /* Zero-th entry is allocated, but unused */ + abbrev_die_table_in_use = 1; + + /* Allocate the initial hunk of the line_info_table. */ + line_info_table + = (dw_line_info_ref) xmalloc (LINE_INFO_TABLE_INCREMENT + * sizeof (dw_line_info_entry)); + bzero ((char *) line_info_table, + LINE_INFO_TABLE_INCREMENT * sizeof (dw_line_info_entry)); + line_info_table_allocated = LINE_INFO_TABLE_INCREMENT; + /* Zero-th entry is allocated, but unused */ + line_info_table_in_use = 1; + + /* Generate the initial DIE for the .debug section. Note that the (string) + value given in the DW_AT_name attribute of the DW_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. */ + gen_compile_unit_die (main_input_filename); + + ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0); +} + +/* Output stuff that dwarf requires at the end of every file, + and generate the DWARF-2 debugging info. */ + +void +dwarf2out_finish () +{ + limbo_die_node *node, *next_node; + dw_die_ref die; + dw_attr_ref a; + + /* Traverse the limbo die list, and add parent/child links. The only + dies without parents that should be here are concrete instances of + inline functions, and the comp_unit_die. We can ignore the comp_unit_die. + For concrete instances, we can get the parent die from the abstract + instance. */ + for (node = limbo_die_list; node; node = next_node) + { + next_node = node->next; + die = node->die; + + if (die->die_parent == NULL) + { + a = get_AT (die, DW_AT_abstract_origin); + if (a) + add_child_die (a->dw_attr_val.v.val_die_ref->die_parent, die); + else if (die == comp_unit_die) + ; + else + abort (); + } + free (node); + } + + /* Traverse the DIE tree and add sibling attributes to those DIE's + that have children. */ + add_sibling_attributes (comp_unit_die); + + /* Output a terminator label for the .text section. */ + fputc ('\n', asm_out_file); + ASM_OUTPUT_SECTION (asm_out_file, TEXT_SECTION); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, TEXT_END_LABEL, 0); + +#if 0 + /* Output a terminator label for the .data section. */ + fputc ('\n', asm_out_file); + ASM_OUTPUT_SECTION (asm_out_file, DATA_SECTION); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, DATA_END_LABEL, 0); + + /* Output a terminator label for the .bss section. */ + fputc ('\n', asm_out_file); + ASM_OUTPUT_SECTION (asm_out_file, BSS_SECTION); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BSS_END_LABEL, 0); +#endif + + /* Output the source line correspondence table. */ + if (line_info_table_in_use > 1 || separate_line_info_table_in_use) + { + fputc ('\n', asm_out_file); + ASM_OUTPUT_SECTION (asm_out_file, DEBUG_LINE_SECTION); + output_line_info (); + + /* We can only use the low/high_pc attributes if all of the code + was in .text. */ + if (separate_line_info_table_in_use == 0) + { + add_AT_lbl_id (comp_unit_die, DW_AT_low_pc, + stripattributes (TEXT_SECTION)); + add_AT_lbl_id (comp_unit_die, DW_AT_high_pc, text_end_label); + } + + add_AT_section_offset (comp_unit_die, DW_AT_stmt_list, DEBUG_LINE_SECTION); + } + + /* Output the abbreviation table. */ + fputc ('\n', asm_out_file); + ASM_OUTPUT_SECTION (asm_out_file, ABBREV_SECTION); + build_abbrev_table (comp_unit_die); + output_abbrev_section (); + + /* Initialize the beginning DIE offset - and calculate sizes/offsets. */ + next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE; + calc_die_sizes (comp_unit_die); + + /* Output debugging information. */ + fputc ('\n', asm_out_file); + ASM_OUTPUT_SECTION (asm_out_file, DEBUG_INFO_SECTION); + output_compilation_unit_header (); + output_die (comp_unit_die); + + if (pubname_table_in_use) + { + /* Output public names table. */ + fputc ('\n', asm_out_file); + ASM_OUTPUT_SECTION (asm_out_file, PUBNAMES_SECTION); + output_pubnames (); + } + + if (fde_table_in_use) + { + /* Output the address range information. */ + fputc ('\n', asm_out_file); + ASM_OUTPUT_SECTION (asm_out_file, ARANGES_SECTION); + output_aranges (); + } +} +#endif /* DWARF2_DEBUGGING_INFO */ diff --git a/gcc_arm/dwarf2out.h b/gcc_arm/dwarf2out.h new file mode 100755 index 0000000..ad6232e --- /dev/null +++ b/gcc_arm/dwarf2out.h @@ -0,0 +1,41 @@ +/* dwarf2out.h - Various declarations for functions found in dwarf2out.c + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +extern void dwarf2out_init PROTO ((FILE *asm_out_file, + char *main_input_filename)); +extern void dwarf2out_finish PROTO ((void)); + +extern void dwarf2out_define PROTO ((unsigned, char *)); +extern void dwarf2out_undef PROTO ((unsigned, char *)); +extern void dwarf2out_start_source_file PROTO ((char *)); +extern void dwarf2out_end_source_file PROTO ((void)); + +extern void dwarf2out_begin_block PROTO ((unsigned)); +extern void dwarf2out_end_block PROTO ((unsigned)); +extern void dwarf2out_label PROTO ((rtx)); +extern void dwarf2out_decl PROTO ((tree)); +extern void dwarf2out_line PROTO ((char *, unsigned)); +extern void dwarf2out_frame_init PROTO ((void)); +extern void dwarf2out_frame_debug PROTO ((rtx)); +extern void dwarf2out_frame_finish PROTO ((void)); + +extern void debug_dwarf PROTO ((void)); +struct die_struct; +extern void debug_dwarf_die PROTO ((struct die_struct *)); diff --git a/gcc_arm/dwarf2out_020422.c b/gcc_arm/dwarf2out_020422.c new file mode 100755 index 0000000..d5d85e9 --- /dev/null +++ b/gcc_arm/dwarf2out_020422.c @@ -0,0 +1,9925 @@ +/* Output Dwarf2 format symbol table information from the GNU C compiler. + Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 2001, 2002 + Free Software Foundation, Inc. + Contributed by Gary Funck (gary@intrepid.com). + Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com). + Extensively modified by Jason Merrill (jason@cygnus.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* The first part of this file deals with the DWARF 2 frame unwind + information, which is also used by the GCC efficient exception handling + mechanism. The second part, controlled only by an #ifdef + DWARF2_DEBUGGING_INFO, deals with the other DWARF 2 debugging + information. */ + +#include "config.h" +#include "system.h" +#include "defaults.h" +#include "tree.h" +#include "flags.h" +#include "rtl.h" +#include "hard-reg-set.h" +#include "regs.h" +#include "insn-config.h" +#include "reload.h" +#include "output.h" +#include "expr.h" +#include "except.h" +#include "dwarf2.h" +#include "dwarf2out.h" +#include "toplev.h" +#include "dyn-string.h" + +/* We cannot use in GCC source, since that would include + GCC's assert.h, which may not be compatible with the host compiler. */ +#undef assert +#ifdef NDEBUG +# define assert(e) +#else +# define assert(e) do { if (! (e)) abort (); } while (0) +#endif + +/* Decide whether we want to emit frame unwind information for the current + translation unit. */ + +int +dwarf2out_do_frame () +{ + return (write_symbols == DWARF2_DEBUG +#ifdef DWARF2_FRAME_INFO + || DWARF2_FRAME_INFO +#endif +#ifdef DWARF2_UNWIND_INFO + || (flag_exceptions && ! exceptions_via_longjmp) +#endif + ); +} + +#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO) + +#ifndef __GNUC__ +#define inline +#endif + +/* How to start an assembler comment. */ +#ifndef ASM_COMMENT_START +#define ASM_COMMENT_START ";#" +#endif + +typedef struct dw_cfi_struct *dw_cfi_ref; +typedef struct dw_fde_struct *dw_fde_ref; +typedef union dw_cfi_oprnd_struct *dw_cfi_oprnd_ref; + +/* Call frames are described using a sequence of Call Frame + Information instructions. The register number, offset + and address fields are provided as possible operands; + their use is selected by the opcode field. */ + +typedef union dw_cfi_oprnd_struct +{ + unsigned long dw_cfi_reg_num; + long int dw_cfi_offset; + char *dw_cfi_addr; +} +dw_cfi_oprnd; + +typedef struct dw_cfi_struct +{ + dw_cfi_ref dw_cfi_next; + enum dwarf_call_frame_info dw_cfi_opc; + dw_cfi_oprnd dw_cfi_oprnd1; + dw_cfi_oprnd dw_cfi_oprnd2; +} +dw_cfi_node; + +/* All call frame descriptions (FDE's) in the GCC generated DWARF + refer to a single Common Information Entry (CIE), defined at + the beginning of the .debug_frame section. This used of a single + CIE obviates the need to keep track of multiple CIE's + in the DWARF generation routines below. */ + +typedef struct dw_fde_struct +{ + char *dw_fde_begin; + char *dw_fde_current_label; + char *dw_fde_end; + dw_cfi_ref dw_fde_cfi; +} +dw_fde_node; + +/* Maximum size (in bytes) of an artificially generated label. */ +#define MAX_ARTIFICIAL_LABEL_BYTES 30 + +/* Make sure we know the sizes of the various types dwarf can describe. These + are only defaults. If the sizes are different for your target, you should + override these values by defining the appropriate symbols in your tm.h + file. */ + +#ifndef CHAR_TYPE_SIZE +#define CHAR_TYPE_SIZE BITS_PER_UNIT +#endif +#ifndef PTR_SIZE +#define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT) +#endif + +/* The size in bytes of a DWARF field indicating an offset or length + relative to a debug info section, specified to be 4 bytes in the DWARF-2 + specification. The SGI/MIPS ABI defines it to be the same as PTR_SIZE. */ + +#ifndef DWARF_OFFSET_SIZE +#define DWARF_OFFSET_SIZE 4 +#endif + +#define DWARF_VERSION 2 + +/* Round SIZE up to the nearest BOUNDARY. */ +#define DWARF_ROUND(SIZE,BOUNDARY) \ + (((SIZE) + (BOUNDARY) - 1) & ~((BOUNDARY) - 1)) + +/* Offsets recorded in opcodes are a multiple of this alignment factor. */ +#ifdef STACK_GROWS_DOWNWARD +#define DWARF_CIE_DATA_ALIGNMENT (-UNITS_PER_WORD) +#else +#define DWARF_CIE_DATA_ALIGNMENT UNITS_PER_WORD +#endif + +/* A pointer to the base of a table that contains frame description + information for each routine. */ +static dw_fde_ref fde_table; + +/* Number of elements currently allocated for fde_table. */ +static unsigned fde_table_allocated; + +/* Number of elements in fde_table currently in use. */ +static unsigned fde_table_in_use; + +/* Size (in elements) of increments by which we may expand the + fde_table. */ +#define FDE_TABLE_INCREMENT 256 + +/* A list of call frame insns for the CIE. */ +static dw_cfi_ref cie_cfi_head; + +/* The number of the current function definition for which debugging + information is being generated. These numbers range from 1 up to the + maximum number of function definitions contained within the current + compilation unit. These numbers are used to create unique label id's + unique to each function definition. */ +static unsigned current_funcdef_number = 0; + +/* Some DWARF extensions (e.g., MIPS/SGI) implement a subprogram + attribute that accelerates the lookup of the FDE associated + with the subprogram. This variable holds the table index of the FDE + associated with the current function (body) definition. */ +static unsigned current_funcdef_fde; + +/* Forward declarations for functions defined in this file. */ + +static char *stripattributes PROTO((char *)); +static char *dwarf_cfi_name PROTO((unsigned)); +static dw_cfi_ref new_cfi PROTO((void)); +static void add_cfi PROTO((dw_cfi_ref *, dw_cfi_ref)); +static unsigned long size_of_uleb128 PROTO((unsigned long)); +static unsigned long size_of_sleb128 PROTO((long)); +static void output_uleb128 PROTO((unsigned long)); +static void output_sleb128 PROTO((long)); +static void add_fde_cfi PROTO((char *, dw_cfi_ref)); +static void lookup_cfa_1 PROTO((dw_cfi_ref, unsigned long *, + long *)); +static void lookup_cfa PROTO((unsigned long *, long *)); +static void reg_save PROTO((char *, unsigned, unsigned, + long)); +static void initial_return_save PROTO((rtx)); +static void output_cfi PROTO((dw_cfi_ref, dw_fde_ref)); +static void output_call_frame_info PROTO((int)); +static unsigned reg_number PROTO((rtx)); +static void dwarf2out_stack_adjust PROTO((rtx)); + +/* Definitions of defaults for assembler-dependent names of various + pseudo-ops and section names. + Theses may be overridden in the tm.h file (if necessary) for a particular + assembler. */ + +#ifdef OBJECT_FORMAT_ELF +#ifndef UNALIGNED_SHORT_ASM_OP +#define UNALIGNED_SHORT_ASM_OP ".2byte" +#endif +#ifndef UNALIGNED_INT_ASM_OP +#define UNALIGNED_INT_ASM_OP ".4byte" +#endif +#ifndef UNALIGNED_DOUBLE_INT_ASM_OP +#define UNALIGNED_DOUBLE_INT_ASM_OP ".8byte" +#endif +#endif /* OBJECT_FORMAT_ELF */ + +#ifndef ASM_BYTE_OP +#define ASM_BYTE_OP ".byte" +#endif + +/* Data and reference forms for relocatable data. */ +#define DW_FORM_data (DWARF_OFFSET_SIZE == 8 ? DW_FORM_data8 : DW_FORM_data4) +#define DW_FORM_ref (DWARF_OFFSET_SIZE == 8 ? DW_FORM_ref8 : DW_FORM_ref4) + +/* Pseudo-op for defining a new section. */ +#ifndef SECTION_ASM_OP +#define SECTION_ASM_OP ".section" +#endif + +/* The default format used by the ASM_OUTPUT_SECTION macro (see below) to + print the SECTION_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 SECTION_FORMAT +#ifdef PUSHSECTION_FORMAT +#define SECTION_FORMAT PUSHSECTION_FORMAT +#else +#define SECTION_FORMAT "\t%s\t%s\n" +#endif +#endif + +#ifndef FRAME_SECTION +#define FRAME_SECTION ".debug_frame" +#endif + +#ifndef FUNC_BEGIN_LABEL +#define FUNC_BEGIN_LABEL "LFB" +#endif +#ifndef FUNC_END_LABEL +#define FUNC_END_LABEL "LFE" +#endif +#define CIE_AFTER_SIZE_LABEL "LSCIE" +#define CIE_END_LABEL "LECIE" +#define CIE_LENGTH_LABEL "LLCIE" +#define FDE_AFTER_SIZE_LABEL "LSFDE" +#define FDE_END_LABEL "LEFDE" +#define FDE_LENGTH_LABEL "LLFDE" + +/* Definitions of defaults for various types of primitive assembly language + output operations. These may be overridden from within the tm.h file, + but typically, that is unnecessary. */ + +#ifndef ASM_OUTPUT_SECTION +#define ASM_OUTPUT_SECTION(FILE, SECTION) \ + fprintf ((FILE), SECTION_FORMAT, SECTION_ASM_OP, SECTION) +#endif + +#ifndef ASM_OUTPUT_DWARF_DATA1 +#define ASM_OUTPUT_DWARF_DATA1(FILE,VALUE) \ + fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) (VALUE)) +#endif + +#ifndef ASM_OUTPUT_DWARF_DELTA1 +#define ASM_OUTPUT_DWARF_DELTA1(FILE,LABEL1,LABEL2) \ + do { fprintf ((FILE), "\t%s\t", ASM_BYTE_OP); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, "-"); \ + assemble_name (FILE, LABEL2); \ + } while (0) +#endif + +#ifdef UNALIGNED_INT_ASM_OP + +#ifndef UNALIGNED_OFFSET_ASM_OP +#define UNALIGNED_OFFSET_ASM_OP \ + (DWARF_OFFSET_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP) +#endif + +#ifndef UNALIGNED_WORD_ASM_OP +#define UNALIGNED_WORD_ASM_OP \ + (PTR_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP) +#endif + +#ifndef ASM_OUTPUT_DWARF_DELTA2 +#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2) \ + do { fprintf ((FILE), "\t%s\t", UNALIGNED_SHORT_ASM_OP); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, "-"); \ + assemble_name (FILE, LABEL2); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_DELTA4 +#define ASM_OUTPUT_DWARF_DELTA4(FILE,LABEL1,LABEL2) \ + do { fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, "-"); \ + assemble_name (FILE, LABEL2); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_DELTA +#define ASM_OUTPUT_DWARF_DELTA(FILE,LABEL1,LABEL2) \ + do { fprintf ((FILE), "\t%s\t", UNALIGNED_OFFSET_ASM_OP); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, "-"); \ + assemble_name (FILE, LABEL2); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_ADDR_DELTA +#define ASM_OUTPUT_DWARF_ADDR_DELTA(FILE,LABEL1,LABEL2) \ + do { fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, "-"); \ + assemble_name (FILE, LABEL2); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_ADDR +#define ASM_OUTPUT_DWARF_ADDR(FILE,LABEL) \ + do { fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \ + assemble_name (FILE, LABEL); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_ADDR_CONST +#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,RTX) \ + do { \ + fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP); \ + output_addr_const ((FILE), (RTX)); \ + fputc ('\n', (FILE)); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_OFFSET4 +#define ASM_OUTPUT_DWARF_OFFSET4(FILE,LABEL) \ + do { fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP); \ + assemble_name (FILE, LABEL); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_OFFSET +#define ASM_OUTPUT_DWARF_OFFSET(FILE,LABEL) \ + do { fprintf ((FILE), "\t%s\t", UNALIGNED_OFFSET_ASM_OP); \ + assemble_name (FILE, LABEL); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_DATA2 +#define ASM_OUTPUT_DWARF_DATA2(FILE,VALUE) \ + fprintf ((FILE), "\t%s\t0x%x", UNALIGNED_SHORT_ASM_OP, (unsigned) (VALUE)) +#endif + +#ifndef ASM_OUTPUT_DWARF_DATA4 +#define ASM_OUTPUT_DWARF_DATA4(FILE,VALUE) \ + fprintf ((FILE), "\t%s\t0x%x", UNALIGNED_INT_ASM_OP, (unsigned) (VALUE)) +#endif + +#ifndef ASM_OUTPUT_DWARF_DATA +#define ASM_OUTPUT_DWARF_DATA(FILE,VALUE) \ + fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_OFFSET_ASM_OP, \ + (unsigned long) (VALUE)) +#endif + +#ifndef ASM_OUTPUT_DWARF_ADDR_DATA +#define ASM_OUTPUT_DWARF_ADDR_DATA(FILE,VALUE) \ + fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_WORD_ASM_OP, \ + (unsigned long) (VALUE)) +#endif + +#ifndef ASM_OUTPUT_DWARF_DATA8 +#define ASM_OUTPUT_DWARF_DATA8(FILE,HIGH_VALUE,LOW_VALUE) \ + do { \ + if (WORDS_BIG_ENDIAN) \ + { \ + fprintf ((FILE), "\t%s\t0x%lx\n", UNALIGNED_INT_ASM_OP, (HIGH_VALUE));\ + fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_INT_ASM_OP, (LOW_VALUE));\ + } \ + else \ + { \ + fprintf ((FILE), "\t%s\t0x%lx\n", UNALIGNED_INT_ASM_OP, (LOW_VALUE)); \ + fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_INT_ASM_OP, (HIGH_VALUE)); \ + } \ + } while (0) +#endif + +#else /* UNALIGNED_INT_ASM_OP */ + +/* We don't have unaligned support, let's hope the normal output works for + .debug_frame. */ + +#define ASM_OUTPUT_DWARF_ADDR(FILE,LABEL) \ + assemble_integer (gen_rtx_SYMBOL_REF (Pmode, LABEL), PTR_SIZE, 1) + +#define ASM_OUTPUT_DWARF_OFFSET4(FILE,LABEL) \ + assemble_integer (gen_rtx_SYMBOL_REF (SImode, LABEL), 4, 1) + +#define ASM_OUTPUT_DWARF_OFFSET(FILE,LABEL) \ + assemble_integer (gen_rtx_SYMBOL_REF (SImode, LABEL), 4, 1) + +#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2) \ + assemble_integer (gen_rtx_MINUS (HImode, \ + gen_rtx_SYMBOL_REF (Pmode, LABEL1), \ + gen_rtx_SYMBOL_REF (Pmode, LABEL2)), \ + 2, 1) + +#define ASM_OUTPUT_DWARF_DELTA4(FILE,LABEL1,LABEL2) \ + assemble_integer (gen_rtx_MINUS (SImode, \ + gen_rtx_SYMBOL_REF (Pmode, LABEL1), \ + gen_rtx_SYMBOL_REF (Pmode, LABEL2)), \ + 4, 1) + +#define ASM_OUTPUT_DWARF_ADDR_DELTA(FILE,LABEL1,LABEL2) \ + assemble_integer (gen_rtx_MINUS (Pmode, \ + gen_rtx_SYMBOL_REF (Pmode, LABEL1), \ + gen_rtx_SYMBOL_REF (Pmode, LABEL2)), \ + PTR_SIZE, 1) + +#define ASM_OUTPUT_DWARF_DELTA(FILE,LABEL1,LABEL2) \ + ASM_OUTPUT_DWARF_DELTA4 (FILE,LABEL1,LABEL2) + +#define ASM_OUTPUT_DWARF_DATA4(FILE,VALUE) \ + assemble_integer (GEN_INT (VALUE), 4, 1) + +#endif /* UNALIGNED_INT_ASM_OP */ + +#ifdef SET_ASM_OP +#ifndef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL +#define ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL(FILE, SY, HI, LO) \ + do { \ + fprintf (FILE, "\t%s\t", SET_ASM_OP); \ + assemble_name (FILE, SY); \ + fputc (',', FILE); \ + assemble_name (FILE, HI); \ + fputc ('-', FILE); \ + assemble_name (FILE, LO); \ + } while (0) +#endif +#endif /* SET_ASM_OP */ + +/* This is similar to the default ASM_OUTPUT_ASCII, except that no trailing + newline is produced. When flag_debug_asm is asserted, we add commentary + at the end of the line, so we must avoid output of a newline here. */ +#ifndef ASM_OUTPUT_DWARF_STRING +#define ASM_OUTPUT_DWARF_STRING(FILE,P) \ + do { \ + register int slen = strlen(P); \ + register char *p = (P); \ + register int i; \ + fprintf (FILE, "\t.ascii \""); \ + for (i = 0; i < slen; i++) \ + { \ + register int c = p[i]; \ + if (c == '\"' || c == '\\') \ + putc ('\\', FILE); \ + if (c >= ' ' && c < 0177) \ + putc (c, FILE); \ + else \ + { \ + fprintf (FILE, "\\%o", c); \ + } \ + } \ + fprintf (FILE, "\\0\""); \ + } \ + while (0) +#endif + +/* The DWARF 2 CFA column which tracks the return address. Normally this + is the column for PC, or the first column after all of the hard + registers. */ +#ifndef DWARF_FRAME_RETURN_COLUMN +#ifdef PC_REGNUM +#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (PC_REGNUM) +#else +#define DWARF_FRAME_RETURN_COLUMN FIRST_PSEUDO_REGISTER +#endif +#endif + +/* The mapping from gcc register number to DWARF 2 CFA column number. By + default, we just provide columns for all registers. */ +#ifndef DWARF_FRAME_REGNUM +#define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG) +#endif + +/* Hook used by __throw. */ + +rtx +expand_builtin_dwarf_fp_regnum () +{ + return GEN_INT (DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM)); +} + +/* The offset from the incoming value of %sp to the top of the stack frame + for the current function. */ +#ifndef INCOMING_FRAME_SP_OFFSET +#define INCOMING_FRAME_SP_OFFSET 0 +#endif + +/* Return a pointer to a copy of the section string name S with all + attributes stripped off, and an asterisk prepended (for assemble_name). */ + +static inline char * +stripattributes (s) + char *s; +{ + char *stripped = xmalloc (strlen (s) + 2); + char *p = stripped; + + *p++ = '*'; + + while (*s && *s != ',') + *p++ = *s++; + + *p = '\0'; + return stripped; +} + +/* Return the register number described by a given RTL node. */ + +static unsigned +reg_number (rtl) + register rtx rtl; +{ + register unsigned regno = REGNO (rtl); + + if (regno >= FIRST_PSEUDO_REGISTER) + { + warning ("internal regno botch: regno = %d\n", regno); + regno = 0; + } + + regno = DBX_REGISTER_NUMBER (regno); + return regno; +} + +struct reg_size_range +{ + int beg; + int end; + int size; +}; + +/* Given a register number in REG_TREE, return an rtx for its size in bytes. + We do this in kind of a roundabout way, by building up a list of + register size ranges and seeing where our register falls in one of those + ranges. We need to do it this way because REG_TREE is not a constant, + and the target macros were not designed to make this task easy. */ + +rtx +expand_builtin_dwarf_reg_size (reg_tree, target) + tree reg_tree; + rtx target; +{ + enum machine_mode mode; + int size; + struct reg_size_range ranges[5]; + tree t, t2; + + int i = 0; + int n_ranges = 0; + int last_size = -1; + + for (; i < FIRST_PSEUDO_REGISTER; ++i) + { + /* The return address is out of order on the MIPS, and we don't use + copy_reg for it anyway, so we don't care here how large it is. */ + if (DWARF_FRAME_REGNUM (i) == DWARF_FRAME_RETURN_COLUMN) + continue; + + mode = reg_raw_mode[i]; + + /* CCmode is arbitrarily given a size of 4 bytes. It is more useful + to use the same size as word_mode, since that reduces the number + of ranges we need. It should not matter, since the result should + never be used for a condition code register anyways. */ + if (GET_MODE_CLASS (mode) == MODE_CC) + mode = word_mode; + + size = GET_MODE_SIZE (mode); + + /* If this register is not valid in the specified mode and + we have a previous size, use that for the size of this + register to avoid making junk tiny ranges. */ + if (! HARD_REGNO_MODE_OK (i, mode) && last_size != -1) + size = last_size; + + if (size != last_size) + { + ranges[n_ranges].beg = i; + ranges[n_ranges].size = last_size = size; + ++n_ranges; + if (n_ranges >= 5) + abort (); + } + ranges[n_ranges-1].end = i; + } + + /* The usual case: fp regs surrounded by general regs. */ + if (n_ranges == 3 && ranges[0].size == ranges[2].size) + { + if ((DWARF_FRAME_REGNUM (ranges[1].end) + - DWARF_FRAME_REGNUM (ranges[1].beg)) + != ranges[1].end - ranges[1].beg) + abort (); + t = fold (build (GE_EXPR, integer_type_node, reg_tree, + build_int_2 (DWARF_FRAME_REGNUM (ranges[1].beg), 0))); + t2 = fold (build (LE_EXPR, integer_type_node, reg_tree, + build_int_2 (DWARF_FRAME_REGNUM (ranges[1].end), 0))); + t = fold (build (TRUTH_ANDIF_EXPR, integer_type_node, t, t2)); + t = fold (build (COND_EXPR, integer_type_node, t, + build_int_2 (ranges[1].size, 0), + build_int_2 (ranges[0].size, 0))); + } + else + { + /* Initialize last_end to be larger than any possible + DWARF_FRAME_REGNUM. */ + int last_end = 0x7fffffff; + --n_ranges; + t = build_int_2 (ranges[n_ranges].size, 0); + do + { + int beg = DWARF_FRAME_REGNUM (ranges[n_ranges].beg); + int end = DWARF_FRAME_REGNUM (ranges[n_ranges].end); + if (beg < 0) + continue; + if (end >= last_end) + abort (); + last_end = end; + if (end - beg != ranges[n_ranges].end - ranges[n_ranges].beg) + abort (); + t2 = fold (build (LE_EXPR, integer_type_node, reg_tree, + build_int_2 (end, 0))); + t = fold (build (COND_EXPR, integer_type_node, t2, + build_int_2 (ranges[n_ranges].size, 0), t)); + } + while (--n_ranges >= 0); + } + return expand_expr (t, target, Pmode, 0); +} + +/* Convert a DWARF call frame info. operation to its string name */ + +static char * +dwarf_cfi_name (cfi_opc) + register unsigned cfi_opc; +{ + switch (cfi_opc) + { + case DW_CFA_advance_loc: + return "DW_CFA_advance_loc"; + case DW_CFA_offset: + return "DW_CFA_offset"; + case DW_CFA_restore: + return "DW_CFA_restore"; + case DW_CFA_nop: + return "DW_CFA_nop"; + case DW_CFA_set_loc: + return "DW_CFA_set_loc"; + case DW_CFA_advance_loc1: + return "DW_CFA_advance_loc1"; + case DW_CFA_advance_loc2: + return "DW_CFA_advance_loc2"; + case DW_CFA_advance_loc4: + return "DW_CFA_advance_loc4"; + case DW_CFA_offset_extended: + return "DW_CFA_offset_extended"; + case DW_CFA_restore_extended: + return "DW_CFA_restore_extended"; + case DW_CFA_undefined: + return "DW_CFA_undefined"; + case DW_CFA_same_value: + return "DW_CFA_same_value"; + case DW_CFA_register: + return "DW_CFA_register"; + case DW_CFA_remember_state: + return "DW_CFA_remember_state"; + case DW_CFA_restore_state: + return "DW_CFA_restore_state"; + case DW_CFA_def_cfa: + return "DW_CFA_def_cfa"; + case DW_CFA_def_cfa_register: + return "DW_CFA_def_cfa_register"; + case DW_CFA_def_cfa_offset: + return "DW_CFA_def_cfa_offset"; + + /* SGI/MIPS specific */ + case DW_CFA_MIPS_advance_loc8: + return "DW_CFA_MIPS_advance_loc8"; + + /* GNU extensions */ + case DW_CFA_GNU_window_save: + return "DW_CFA_GNU_window_save"; + case DW_CFA_GNU_args_size: + return "DW_CFA_GNU_args_size"; + + default: + return "DW_CFA_"; + } +} + +/* Return a pointer to a newly allocated Call Frame Instruction. */ + +static inline dw_cfi_ref +new_cfi () +{ + register dw_cfi_ref cfi = (dw_cfi_ref) xmalloc (sizeof (dw_cfi_node)); + + cfi->dw_cfi_next = NULL; + cfi->dw_cfi_oprnd1.dw_cfi_reg_num = 0; + cfi->dw_cfi_oprnd2.dw_cfi_reg_num = 0; + + return cfi; +} + +/* Add a Call Frame Instruction to list of instructions. */ + +static inline void +add_cfi (list_head, cfi) + register dw_cfi_ref *list_head; + register dw_cfi_ref cfi; +{ + register dw_cfi_ref *p; + + /* Find the end of the chain. */ + for (p = list_head; (*p) != NULL; p = &(*p)->dw_cfi_next) + ; + + *p = cfi; +} + +/* Generate a new label for the CFI info to refer to. */ + +char * +dwarf2out_cfi_label () +{ + static char label[20]; + static unsigned long label_num = 0; + + ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", label_num++); + ASM_OUTPUT_LABEL (asm_out_file, label); + + return label; +} + +/* Add CFI to the current fde at the PC value indicated by LABEL if specified, + or to the CIE if LABEL is NULL. */ + +static void +add_fde_cfi (label, cfi) + register char *label; + register dw_cfi_ref cfi; +{ + if (label) + { + register dw_fde_ref fde = &fde_table[fde_table_in_use - 1]; + + if (*label == 0) + label = dwarf2out_cfi_label (); + + if (fde->dw_fde_current_label == NULL + || strcmp (label, fde->dw_fde_current_label) != 0) + { + register dw_cfi_ref xcfi; + + fde->dw_fde_current_label = label = xstrdup (label); + + /* Set the location counter to the new label. */ + xcfi = new_cfi (); + xcfi->dw_cfi_opc = DW_CFA_advance_loc4; + xcfi->dw_cfi_oprnd1.dw_cfi_addr = label; + add_cfi (&fde->dw_fde_cfi, xcfi); + } + + add_cfi (&fde->dw_fde_cfi, cfi); + } + + else + add_cfi (&cie_cfi_head, cfi); +} + +/* Subroutine of lookup_cfa. */ + +static inline void +lookup_cfa_1 (cfi, regp, offsetp) + register dw_cfi_ref cfi; + register unsigned long *regp; + register long *offsetp; +{ + switch (cfi->dw_cfi_opc) + { + case DW_CFA_def_cfa_offset: + *offsetp = cfi->dw_cfi_oprnd1.dw_cfi_offset; + break; + case DW_CFA_def_cfa_register: + *regp = cfi->dw_cfi_oprnd1.dw_cfi_reg_num; + break; + case DW_CFA_def_cfa: + *regp = cfi->dw_cfi_oprnd1.dw_cfi_reg_num; + *offsetp = cfi->dw_cfi_oprnd2.dw_cfi_offset; + break; + default: + break; + } +} + +/* Find the previous value for the CFA. */ + +static void +lookup_cfa (regp, offsetp) + register unsigned long *regp; + register long *offsetp; +{ + register dw_cfi_ref cfi; + + *regp = (unsigned long) -1; + *offsetp = 0; + + for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next) + lookup_cfa_1 (cfi, regp, offsetp); + + if (fde_table_in_use) + { + register dw_fde_ref fde = &fde_table[fde_table_in_use - 1]; + for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next) + lookup_cfa_1 (cfi, regp, offsetp); + } +} + +/* The current rule for calculating the DWARF2 canonical frame address. */ +static unsigned long cfa_reg; +static long cfa_offset; + +/* The register used for saving registers to the stack, and its offset + from the CFA. */ +static unsigned cfa_store_reg; +static long cfa_store_offset; + +/* The running total of the size of arguments pushed onto the stack. */ +static long args_size; + +/* The last args_size we actually output. */ +static long old_args_size; + +/* Entry point to update the canonical frame address (CFA). + LABEL is passed to add_fde_cfi. The value of CFA is now to be + calculated from REG+OFFSET. */ + +void +dwarf2out_def_cfa (label, reg, offset) + register char *label; + register unsigned reg; + register long offset; +{ + register dw_cfi_ref cfi; + unsigned long old_reg; + long old_offset; + + cfa_reg = reg; + cfa_offset = offset; + if (cfa_store_reg == reg) + cfa_store_offset = offset; + + reg = DWARF_FRAME_REGNUM (reg); + lookup_cfa (&old_reg, &old_offset); + + if (reg == old_reg && offset == old_offset) + return; + + cfi = new_cfi (); + + if (reg == old_reg) + { + cfi->dw_cfi_opc = DW_CFA_def_cfa_offset; + cfi->dw_cfi_oprnd1.dw_cfi_offset = offset; + } + +#ifndef MIPS_DEBUGGING_INFO /* SGI dbx thinks this means no offset. */ + else if (offset == old_offset && old_reg != (unsigned long) -1) + { + cfi->dw_cfi_opc = DW_CFA_def_cfa_register; + cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg; + } +#endif + + else + { + cfi->dw_cfi_opc = DW_CFA_def_cfa; + cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg; + cfi->dw_cfi_oprnd2.dw_cfi_offset = offset; + } + + add_fde_cfi (label, cfi); +} + +/* Add the CFI for saving a register. REG is the CFA column number. + LABEL is passed to add_fde_cfi. + If SREG is -1, the register is saved at OFFSET from the CFA; + otherwise it is saved in SREG. */ + +static void +reg_save (label, reg, sreg, offset) + register char * label; + register unsigned reg; + register unsigned sreg; + register long offset; +{ + register dw_cfi_ref cfi = new_cfi (); + + cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg; + + /* The following comparison is correct. -1 is used to indicate that + the value isn't a register number. */ + if (sreg == (unsigned int) -1) + { + if (reg & ~0x3f) + /* The register number won't fit in 6 bits, so we have to use + the long form. */ + cfi->dw_cfi_opc = DW_CFA_offset_extended; + else + cfi->dw_cfi_opc = DW_CFA_offset; + + offset /= DWARF_CIE_DATA_ALIGNMENT; + if (offset < 0) + abort (); + cfi->dw_cfi_oprnd2.dw_cfi_offset = offset; + } + else + { + cfi->dw_cfi_opc = DW_CFA_register; + cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg; + } + + add_fde_cfi (label, cfi); +} + +/* Add the CFI for saving a register window. LABEL is passed to reg_save. + This CFI tells the unwinder that it needs to restore the window registers + from the previous frame's window save area. + + ??? Perhaps we should note in the CIE where windows are saved (instead of + assuming 0(cfa)) and what registers are in the window. */ + +void +dwarf2out_window_save (label) + register char * label; +{ + register dw_cfi_ref cfi = new_cfi (); + cfi->dw_cfi_opc = DW_CFA_GNU_window_save; + add_fde_cfi (label, cfi); +} + +/* Add a CFI to update the running total of the size of arguments + pushed onto the stack. */ + +void +dwarf2out_args_size (label, size) + char *label; + long size; +{ + register dw_cfi_ref cfi; + + if (size == old_args_size) + return; + old_args_size = size; + + cfi = new_cfi (); + cfi->dw_cfi_opc = DW_CFA_GNU_args_size; + cfi->dw_cfi_oprnd1.dw_cfi_offset = size; + add_fde_cfi (label, cfi); +} + +/* Entry point for saving a register to the stack. REG is the GCC register + number. LABEL and OFFSET are passed to reg_save. */ + +void +dwarf2out_reg_save (label, reg, offset) + register char * label; + register unsigned reg; + register long offset; +{ + reg_save (label, DWARF_FRAME_REGNUM (reg), -1, offset); +} + +/* Entry point for saving the return address in the stack. + LABEL and OFFSET are passed to reg_save. */ + +void +dwarf2out_return_save (label, offset) + register char * label; + register long offset; +{ + reg_save (label, DWARF_FRAME_RETURN_COLUMN, -1, offset); +} + +/* Entry point for saving the return address in a register. + LABEL and SREG are passed to reg_save. */ + +void +dwarf2out_return_reg (label, sreg) + register char * label; + register unsigned sreg; +{ + reg_save (label, DWARF_FRAME_RETURN_COLUMN, sreg, 0); +} + +/* Record the initial position of the return address. RTL is + INCOMING_RETURN_ADDR_RTX. */ + +static void +initial_return_save (rtl) + register rtx rtl; +{ + unsigned int reg = (unsigned int) -1; + long offset = 0; + + switch (GET_CODE (rtl)) + { + case REG: + /* RA is in a register. */ + reg = reg_number (rtl); + break; + case MEM: + /* RA is on the stack. */ + rtl = XEXP (rtl, 0); + switch (GET_CODE (rtl)) + { + case REG: + if (REGNO (rtl) != STACK_POINTER_REGNUM) + abort (); + offset = 0; + break; + case PLUS: + if (REGNO (XEXP (rtl, 0)) != STACK_POINTER_REGNUM) + abort (); + offset = INTVAL (XEXP (rtl, 1)); + break; + case MINUS: + if (REGNO (XEXP (rtl, 0)) != STACK_POINTER_REGNUM) + abort (); + offset = -INTVAL (XEXP (rtl, 1)); + break; + default: + abort (); + } + break; + case PLUS: + /* The return address is at some offset from any value we can + actually load. For instance, on the SPARC it is in %i7+8. Just + ignore the offset for now; it doesn't matter for unwinding frames. */ + if (GET_CODE (XEXP (rtl, 1)) != CONST_INT) + abort (); + initial_return_save (XEXP (rtl, 0)); + return; + default: + abort (); + } + + reg_save (NULL, DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa_offset); +} + +/* Check INSN to see if it looks like a push or a stack adjustment, and + make a note of it if it does. EH uses this information to find out how + much extra space it needs to pop off the stack. */ + +static void +dwarf2out_stack_adjust (insn) + rtx insn; +{ + long offset; + char *label; + + if (! asynchronous_exceptions && GET_CODE (insn) == CALL_INSN) + { + /* Extract the size of the args from the CALL rtx itself. */ + + insn = PATTERN (insn); + if (GET_CODE (insn) == PARALLEL) + insn = XVECEXP (insn, 0, 0); + if (GET_CODE (insn) == SET) + insn = SET_SRC (insn); + assert (GET_CODE (insn) == CALL); + dwarf2out_args_size ("", INTVAL (XEXP (insn, 1))); + return; + } + + /* If only calls can throw, and we have a frame pointer, + save up adjustments until we see the CALL_INSN. */ + else if (! asynchronous_exceptions + && cfa_reg != STACK_POINTER_REGNUM) + return; + + if (GET_CODE (insn) == BARRIER) + { + /* When we see a BARRIER, we know to reset args_size to 0. Usually + the compiler will have already emitted a stack adjustment, but + doesn't bother for calls to noreturn functions. */ +#ifdef STACK_GROWS_DOWNWARD + offset = -args_size; +#else + offset = args_size; +#endif + } + else if (GET_CODE (PATTERN (insn)) == SET) + { + rtx src, dest; + enum rtx_code code; + + insn = PATTERN (insn); + src = SET_SRC (insn); + dest = SET_DEST (insn); + + if (dest == stack_pointer_rtx) + { + /* (set (reg sp) (plus (reg sp) (const_int))) */ + code = GET_CODE (src); + if (! (code == PLUS || code == MINUS) + || XEXP (src, 0) != stack_pointer_rtx + || GET_CODE (XEXP (src, 1)) != CONST_INT) + return; + + offset = INTVAL (XEXP (src, 1)); + } + else if (GET_CODE (dest) == MEM) + { + /* (set (mem (pre_dec (reg sp))) (foo)) */ + src = XEXP (dest, 0); + code = GET_CODE (src); + + if (! (code == PRE_DEC || code == PRE_INC) + || XEXP (src, 0) != stack_pointer_rtx) + return; + + offset = GET_MODE_SIZE (GET_MODE (dest)); + } + else + return; + + if (code == PLUS || code == PRE_INC) + offset = -offset; + } + else + return; + + if (offset == 0) + return; + + if (cfa_reg == STACK_POINTER_REGNUM) + cfa_offset += offset; + +#ifndef STACK_GROWS_DOWNWARD + offset = -offset; +#endif + args_size += offset; + if (args_size < 0) + args_size = 0; + + label = dwarf2out_cfi_label (); + dwarf2out_def_cfa (label, cfa_reg, cfa_offset); + dwarf2out_args_size (label, args_size); +} + +/* Record call frame debugging information for INSN, which either + sets SP or FP (adjusting how we calculate the frame address) or saves a + register to the stack. If INSN is NULL_RTX, initialize our state. */ + +void +dwarf2out_frame_debug (insn) + rtx insn; +{ + char *label; + rtx src, dest; + long offset; + + /* A temporary register used in adjusting SP or setting up the store_reg. */ + static unsigned cfa_temp_reg; + static long cfa_temp_value; + + if (insn == NULL_RTX) + { + /* Set up state for generating call frame debug info. */ + lookup_cfa (&cfa_reg, &cfa_offset); + if (cfa_reg != DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM)) + abort (); + cfa_reg = STACK_POINTER_REGNUM; + cfa_store_reg = cfa_reg; + cfa_store_offset = cfa_offset; + cfa_temp_reg = -1; + cfa_temp_value = 0; + return; + } + + if (! RTX_FRAME_RELATED_P (insn)) + { + dwarf2out_stack_adjust (insn); + return; + } + + label = dwarf2out_cfi_label (); + + src = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX); + if (src) + insn = XEXP (src, 0); + else + insn = PATTERN (insn); + + /* Assume that in a PARALLEL prologue insn, only the first elt is + significant. Currently this is true. */ + if (GET_CODE (insn) == PARALLEL) + insn = XVECEXP (insn, 0, 0); + if (GET_CODE (insn) != SET) + abort (); + + src = SET_SRC (insn); + dest = SET_DEST (insn); + + switch (GET_CODE (dest)) + { + case REG: + /* Update the CFA rule wrt SP or FP. Make sure src is + relative to the current CFA register. */ + switch (GET_CODE (src)) + { + /* Setting FP from SP. */ + case REG: + if (cfa_reg != (unsigned) REGNO (src)) + abort (); + if (REGNO (dest) != STACK_POINTER_REGNUM + && !(frame_pointer_needed + && REGNO (dest) == HARD_FRAME_POINTER_REGNUM)) + abort (); + cfa_reg = REGNO (dest); + break; + + case PLUS: + case MINUS: + if (dest == stack_pointer_rtx) + { + /* Adjusting SP. */ + switch (GET_CODE (XEXP (src, 1))) + { + case CONST_INT: + offset = INTVAL (XEXP (src, 1)); + break; + case REG: + if ((unsigned) REGNO (XEXP (src, 1)) != cfa_temp_reg) + abort (); + offset = cfa_temp_value; + break; + default: + abort (); + } + + if (XEXP (src, 0) == hard_frame_pointer_rtx) + { + /* Restoring SP from FP in the epilogue. */ + if (cfa_reg != (unsigned) HARD_FRAME_POINTER_REGNUM) + abort (); + cfa_reg = STACK_POINTER_REGNUM; + } + else if (XEXP (src, 0) != stack_pointer_rtx) + abort (); + + if (GET_CODE (src) == PLUS) + offset = -offset; + if (cfa_reg == STACK_POINTER_REGNUM) + cfa_offset += offset; + if (cfa_store_reg == STACK_POINTER_REGNUM) + cfa_store_offset += offset; + } + else if (dest == hard_frame_pointer_rtx) + { + /* Either setting the FP from an offset of the SP, + or adjusting the FP */ + if (! frame_pointer_needed + || REGNO (dest) != HARD_FRAME_POINTER_REGNUM) + abort (); + + if (XEXP (src, 0) == stack_pointer_rtx + && GET_CODE (XEXP (src, 1)) == CONST_INT) + { + if (cfa_reg != STACK_POINTER_REGNUM) + abort (); + offset = INTVAL (XEXP (src, 1)); + if (GET_CODE (src) == PLUS) + offset = -offset; + cfa_offset += offset; + cfa_reg = HARD_FRAME_POINTER_REGNUM; + } + else if (XEXP (src, 0) == hard_frame_pointer_rtx + && GET_CODE (XEXP (src, 1)) == CONST_INT) + { + if (cfa_reg != (unsigned) HARD_FRAME_POINTER_REGNUM) + abort (); + offset = INTVAL (XEXP (src, 1)); + if (GET_CODE (src) == PLUS) + offset = -offset; + cfa_offset += offset; + } + + else + abort(); + } + else + { + if (GET_CODE (src) != PLUS + || XEXP (src, 1) != stack_pointer_rtx) + abort (); + if (GET_CODE (XEXP (src, 0)) != REG + || (unsigned) REGNO (XEXP (src, 0)) != cfa_temp_reg) + abort (); + if (cfa_reg != STACK_POINTER_REGNUM) + abort (); + cfa_store_reg = REGNO (dest); + cfa_store_offset = cfa_offset - cfa_temp_value; + } + break; + + case CONST_INT: + cfa_temp_reg = REGNO (dest); + cfa_temp_value = INTVAL (src); + break; + + case IOR: + if (GET_CODE (XEXP (src, 0)) != REG + || (unsigned) REGNO (XEXP (src, 0)) != cfa_temp_reg + || (unsigned) REGNO (dest) != cfa_temp_reg + || GET_CODE (XEXP (src, 1)) != CONST_INT) + abort (); + cfa_temp_value |= INTVAL (XEXP (src, 1)); + break; + + default: + abort (); + } + dwarf2out_def_cfa (label, cfa_reg, cfa_offset); + break; + + case MEM: + /* Saving a register to the stack. Make sure dest is relative to the + CFA register. */ + if (GET_CODE (src) != REG) + abort (); + switch (GET_CODE (XEXP (dest, 0))) + { + /* With a push. */ + case PRE_INC: + case PRE_DEC: + offset = GET_MODE_SIZE (GET_MODE (dest)); + if (GET_CODE (XEXP (dest, 0)) == PRE_INC) + offset = -offset; + + if (REGNO (XEXP (XEXP (dest, 0), 0)) != STACK_POINTER_REGNUM + || cfa_store_reg != STACK_POINTER_REGNUM) + abort (); + cfa_store_offset += offset; + if (cfa_reg == STACK_POINTER_REGNUM) + cfa_offset = cfa_store_offset; + + offset = -cfa_store_offset; + break; + + /* With an offset. */ + case PLUS: + case MINUS: + offset = INTVAL (XEXP (XEXP (dest, 0), 1)); + if (GET_CODE (src) == MINUS) + offset = -offset; + + if (cfa_store_reg != (unsigned) REGNO (XEXP (XEXP (dest, 0), 0))) + abort (); + offset -= cfa_store_offset; + break; + + /* Without an offset. */ + case REG: + if (cfa_store_reg != (unsigned) REGNO (XEXP (dest, 0))) + abort(); + offset = -cfa_store_offset; + break; + + default: + abort (); + } + dwarf2out_def_cfa (label, cfa_reg, cfa_offset); + dwarf2out_reg_save (label, REGNO (src), offset); + break; + + default: + abort (); + } +} + +/* Return the size of an unsigned LEB128 quantity. */ + +static inline unsigned long +size_of_uleb128 (value) + register unsigned long value; +{ + register unsigned long size = 0; + register unsigned byte; + + do + { + byte = (value & 0x7f); + value >>= 7; + size += 1; + } + while (value != 0); + + return size; +} + +/* Return the size of a signed LEB128 quantity. */ + +static inline unsigned long +size_of_sleb128 (value) + register long value; +{ + register unsigned long size = 0; + register unsigned byte; + + do + { + byte = (value & 0x7f); + value >>= 7; + size += 1; + } + while (!(((value == 0) && ((byte & 0x40) == 0)) + || ((value == -1) && ((byte & 0x40) != 0)))); + + return size; +} + +/* Output an unsigned LEB128 quantity. */ + +static void +output_uleb128 (value) + register unsigned long value; +{ + unsigned long save_value = value; + + fprintf (asm_out_file, "\t%s\t", ASM_BYTE_OP); + do + { + register unsigned byte = (value & 0x7f); + value >>= 7; + if (value != 0) + /* More bytes to follow. */ + byte |= 0x80; + + fprintf (asm_out_file, "0x%x", byte); + if (value != 0) + fprintf (asm_out_file, ","); + } + while (value != 0); + + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s ULEB128 0x%lx", ASM_COMMENT_START, save_value); +} + +/* Output an signed LEB128 quantity. */ + +static void +output_sleb128 (value) + register long value; +{ + register int more; + register unsigned byte; + long save_value = value; + + fprintf (asm_out_file, "\t%s\t", ASM_BYTE_OP); + do + { + byte = (value & 0x7f); + /* arithmetic shift */ + value >>= 7; + more = !((((value == 0) && ((byte & 0x40) == 0)) + || ((value == -1) && ((byte & 0x40) != 0)))); + if (more) + byte |= 0x80; + + fprintf (asm_out_file, "0x%x", byte); + if (more) + fprintf (asm_out_file, ","); + } + + while (more); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s SLEB128 %ld", ASM_COMMENT_START, save_value); +} + +/* Output a Call Frame Information opcode and its operand(s). */ + +static void +output_cfi (cfi, fde) + register dw_cfi_ref cfi; + register dw_fde_ref fde; +{ + if (cfi->dw_cfi_opc == DW_CFA_advance_loc) + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, + cfi->dw_cfi_opc + | (cfi->dw_cfi_oprnd1.dw_cfi_offset & 0x3f)); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_CFA_advance_loc 0x%lx", + ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_offset); + fputc ('\n', asm_out_file); + } + + else if (cfi->dw_cfi_opc == DW_CFA_offset) + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, + cfi->dw_cfi_opc + | (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f)); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_CFA_offset, column 0x%lx", + ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_reg_num); + + fputc ('\n', asm_out_file); + output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset); + fputc ('\n', asm_out_file); + } + else if (cfi->dw_cfi_opc == DW_CFA_restore) + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, + cfi->dw_cfi_opc + | (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f)); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_CFA_restore, column 0x%lx", + ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_reg_num); + + fputc ('\n', asm_out_file); + } + else + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, cfi->dw_cfi_opc); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START, + dwarf_cfi_name (cfi->dw_cfi_opc)); + + fputc ('\n', asm_out_file); + switch (cfi->dw_cfi_opc) + { + case DW_CFA_set_loc: + ASM_OUTPUT_DWARF_ADDR (asm_out_file, cfi->dw_cfi_oprnd1.dw_cfi_addr); + fputc ('\n', asm_out_file); + break; + case DW_CFA_advance_loc1: + ASM_OUTPUT_DWARF_DELTA1 (asm_out_file, + cfi->dw_cfi_oprnd1.dw_cfi_addr, + fde->dw_fde_current_label); + fputc ('\n', asm_out_file); + fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr; + break; + case DW_CFA_advance_loc2: + ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, + cfi->dw_cfi_oprnd1.dw_cfi_addr, + fde->dw_fde_current_label); + fputc ('\n', asm_out_file); + fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr; + break; + case DW_CFA_advance_loc4: + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, + cfi->dw_cfi_oprnd1.dw_cfi_addr, + fde->dw_fde_current_label); + fputc ('\n', asm_out_file); + fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr; + break; +#ifdef MIPS_DEBUGGING_INFO + case DW_CFA_MIPS_advance_loc8: + /* TODO: not currently implemented. */ + abort (); + break; +#endif + case DW_CFA_offset_extended: + case DW_CFA_def_cfa: + output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num); + fputc ('\n', asm_out_file); + output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset); + fputc ('\n', asm_out_file); + break; + case DW_CFA_restore_extended: + case DW_CFA_undefined: + output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num); + fputc ('\n', asm_out_file); + break; + case DW_CFA_same_value: + case DW_CFA_def_cfa_register: + output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num); + fputc ('\n', asm_out_file); + break; + case DW_CFA_register: + output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num); + fputc ('\n', asm_out_file); + output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_reg_num); + fputc ('\n', asm_out_file); + break; + case DW_CFA_def_cfa_offset: + output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset); + fputc ('\n', asm_out_file); + break; + case DW_CFA_GNU_window_save: + break; + case DW_CFA_GNU_args_size: + output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset); + fputc ('\n', asm_out_file); + break; + default: + break; + } + } +} + +#if !defined (EH_FRAME_SECTION) +#if defined (EH_FRAME_SECTION_ASM_OP) +#define EH_FRAME_SECTION() eh_frame_section(); +#else +#if defined (ASM_OUTPUT_SECTION_NAME) +#define EH_FRAME_SECTION() \ + do { \ + named_section (NULL_TREE, ".eh_frame", 0); \ + } while (0) +#endif +#endif +#endif + +/* If we aren't using crtstuff to run ctors, don't use it for EH. */ +#if !defined (HAS_INIT_SECTION) && !defined (INIT_SECTION_ASM_OP) +#undef EH_FRAME_SECTION +#endif + +/* Output the call frame information used to used to record information + that relates to calculating the frame pointer, and records the + location of saved registers. */ + +static void +output_call_frame_info (for_eh) + int for_eh; +{ + register unsigned long i; + register dw_fde_ref fde; + register dw_cfi_ref cfi; + char l1[20], l2[20]; +#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL + char ld[20]; +#endif + + /* Do we want to include a pointer to the exception table? */ + int eh_ptr = for_eh && exception_table_p (); + + fputc ('\n', asm_out_file); + + /* We're going to be generating comments, so turn on app. */ + if (flag_debug_asm) + app_enable (); + + if (for_eh) + { +#ifdef EH_FRAME_SECTION + EH_FRAME_SECTION (); +#else + tree label = get_file_function_name ('F'); + + force_data_section (); + ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE)); + ASM_GLOBALIZE_LABEL (asm_out_file, IDENTIFIER_POINTER (label)); + ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label)); +#endif + assemble_label ("__FRAME_BEGIN__"); + } + else + ASM_OUTPUT_SECTION (asm_out_file, FRAME_SECTION); + + /* Output the CIE. */ + ASM_GENERATE_INTERNAL_LABEL (l1, CIE_AFTER_SIZE_LABEL, for_eh); + ASM_GENERATE_INTERNAL_LABEL (l2, CIE_END_LABEL, for_eh); +#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL + ASM_GENERATE_INTERNAL_LABEL (ld, CIE_LENGTH_LABEL, for_eh); + if (for_eh) + ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld); + else + ASM_OUTPUT_DWARF_OFFSET (asm_out_file, ld); +#else + if (for_eh) + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l2, l1); + else + ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1); +#endif + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Length of Common Information Entry", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_LABEL (asm_out_file, l1); + + if (for_eh) + /* Now that the CIE pointer is PC-relative for EH, + use 0 to identify the CIE. */ + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0); + else + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID); + + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s CIE Identifier Tag", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + if (! for_eh && DWARF_OFFSET_SIZE == 8) + { + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID); + fputc ('\n', asm_out_file); + } + + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_CIE_VERSION); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s CIE Version", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + if (eh_ptr) + { + /* The CIE contains a pointer to the exception region info for the + frame. Make the augmentation string three bytes (including the + trailing null) so the pointer is 4-byte aligned. The Solaris ld + can't handle unaligned relocs. */ + if (flag_debug_asm) + { + ASM_OUTPUT_DWARF_STRING (asm_out_file, "eh"); + fprintf (asm_out_file, "\t%s CIE Augmentation", ASM_COMMENT_START); + } + else + { + ASM_OUTPUT_ASCII (asm_out_file, "eh", 3); + } + fputc ('\n', asm_out_file); + + ASM_OUTPUT_DWARF_ADDR (asm_out_file, "__EXCEPTION_TABLE__"); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s pointer to exception region info", + ASM_COMMENT_START); + } + else + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s CIE Augmentation (none)", + ASM_COMMENT_START); + } + + fputc ('\n', asm_out_file); + output_uleb128 (1); + if (flag_debug_asm) + fprintf (asm_out_file, " (CIE Code Alignment Factor)"); + + fputc ('\n', asm_out_file); + output_sleb128 (DWARF_CIE_DATA_ALIGNMENT); + if (flag_debug_asm) + fprintf (asm_out_file, " (CIE Data Alignment Factor)"); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_FRAME_RETURN_COLUMN); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s CIE RA Column", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + + for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next) + output_cfi (cfi, NULL); + + /* Pad the CIE out to an address sized boundary. */ + ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE)); + ASM_OUTPUT_LABEL (asm_out_file, l2); +#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL + ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s CIE Length Symbol", ASM_COMMENT_START); + fputc ('\n', asm_out_file); +#endif + + /* Loop through all of the FDE's. */ + for (i = 0; i < fde_table_in_use; ++i) + { + fde = &fde_table[i]; + + ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + i*2); + ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + i*2); +#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL + ASM_GENERATE_INTERNAL_LABEL (ld, FDE_LENGTH_LABEL, for_eh + i*2); + if (for_eh) + ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld); + else + ASM_OUTPUT_DWARF_OFFSET (asm_out_file, ld); +#else + if (for_eh) + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l2, l1); + else + ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1); +#endif + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s FDE Length", ASM_COMMENT_START); + fputc ('\n', asm_out_file); + ASM_OUTPUT_LABEL (asm_out_file, l1); + + /* ??? This always emits a 4 byte offset when for_eh is true, but it + emits a target dependent sized offset when for_eh is not true. + This inconsistency may confuse gdb. The only case where we need a + non-4 byte offset is for the Irix6 N64 ABI, so we may lose SGI + compatibility if we emit a 4 byte offset. We need a 4 byte offset + though in order to be compatible with the dwarf_fde struct in frame.c. + If the for_eh case is changed, then the struct in frame.c has + to be adjusted appropriately. */ + if (for_eh) + ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l1, "__FRAME_BEGIN__"); + else + ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (FRAME_SECTION)); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s FDE CIE offset", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, fde->dw_fde_begin); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s FDE initial location", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, + fde->dw_fde_end, fde->dw_fde_begin); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s FDE address range", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + + /* Loop through the Call Frame Instructions associated with + this FDE. */ + fde->dw_fde_current_label = fde->dw_fde_begin; + for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next) + output_cfi (cfi, fde); + + /* Pad the FDE out to an address sized boundary. */ + ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE)); + ASM_OUTPUT_LABEL (asm_out_file, l2); +#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL + ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s FDE Length Symbol", ASM_COMMENT_START); + fputc ('\n', asm_out_file); +#endif + } +#ifndef EH_FRAME_SECTION + if (for_eh) + { + /* Emit terminating zero for table. */ + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0); + fputc ('\n', asm_out_file); + } +#endif +#ifdef MIPS_DEBUGGING_INFO + /* Work around Irix 6 assembler bug whereby labels at the end of a section + get a value of 0. Putting .align 0 after the label fixes it. */ + ASM_OUTPUT_ALIGN (asm_out_file, 0); +#endif + + /* Turn off app to make assembly quicker. */ + if (flag_debug_asm) + app_disable (); +} + +/* Output a marker (i.e. a label) for the beginning of a function, before + the prologue. */ + +void +dwarf2out_begin_prologue () +{ + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + register dw_fde_ref fde; + + ++current_funcdef_number; + + function_section (current_function_decl); + ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL, + current_funcdef_number); + ASM_OUTPUT_LABEL (asm_out_file, label); + + /* Expand the fde table if necessary. */ + if (fde_table_in_use == fde_table_allocated) + { + fde_table_allocated += FDE_TABLE_INCREMENT; + fde_table + = (dw_fde_ref) xrealloc (fde_table, + fde_table_allocated * sizeof (dw_fde_node)); + } + + /* Record the FDE associated with this function. */ + current_funcdef_fde = fde_table_in_use; + + /* Add the new FDE at the end of the fde_table. */ + fde = &fde_table[fde_table_in_use++]; + fde->dw_fde_begin = xstrdup (label); + fde->dw_fde_current_label = NULL; + fde->dw_fde_end = NULL; + fde->dw_fde_cfi = NULL; + + args_size = old_args_size = 0; +} + +/* 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. */ + +void +dwarf2out_end_epilogue () +{ + dw_fde_ref fde; + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + /* Output a label to mark the endpoint of the code generated for this + function. */ + ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL, current_funcdef_number); + ASM_OUTPUT_LABEL (asm_out_file, label); + fde = &fde_table[fde_table_in_use - 1]; + fde->dw_fde_end = xstrdup (label); +} + +void +dwarf2out_frame_init () +{ + /* Allocate the initial hunk of the fde_table. */ + fde_table + = (dw_fde_ref) xmalloc (FDE_TABLE_INCREMENT * sizeof (dw_fde_node)); + bzero ((char *) fde_table, FDE_TABLE_INCREMENT * sizeof (dw_fde_node)); + fde_table_allocated = FDE_TABLE_INCREMENT; + fde_table_in_use = 0; + + /* Generate the CFA instructions common to all FDE's. Do it now for the + sake of lookup_cfa. */ + +#ifdef DWARF2_UNWIND_INFO + /* On entry, the Canonical Frame Address is at SP. */ + dwarf2out_def_cfa (NULL, STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET); + initial_return_save (INCOMING_RETURN_ADDR_RTX); +#endif +} + +void +dwarf2out_frame_finish () +{ + /* Output call frame information. */ +#ifdef MIPS_DEBUGGING_INFO + if (write_symbols == DWARF2_DEBUG) + output_call_frame_info (0); + if (flag_exceptions && ! exceptions_via_longjmp) + output_call_frame_info (1); +#else + if (write_symbols == DWARF2_DEBUG + || (flag_exceptions && ! exceptions_via_longjmp)) + output_call_frame_info (1); +#endif +} + +#endif /* .debug_frame support */ + +/* And now, the support for symbolic debugging information. */ +#ifdef DWARF2_DEBUGGING_INFO + +extern char *getpwd PROTO((void)); + +/* NOTE: In the comments in this file, many references are made to + "Debugging Information Entries". This term is abbreviated as `DIE' + throughout the remainder of this file. */ + +/* An internal representation of the DWARF output is built, and then + walked to generate the DWARF debugging info. The walk of the internal + representation is done after the entire program has been compiled. + The types below are used to describe the internal representation. */ + +/* Each DIE may have a series of attribute/value pairs. Values + can take on several forms. The forms that are used in this + implementation are listed below. */ + +typedef enum +{ + dw_val_class_addr, + dw_val_class_loc, + dw_val_class_const, + dw_val_class_unsigned_const, + dw_val_class_long_long, + dw_val_class_float, + dw_val_class_flag, + dw_val_class_die_ref, + dw_val_class_fde_ref, + dw_val_class_lbl_id, + dw_val_class_section_offset, + dw_val_class_str +} +dw_val_class; + +/* Various DIE's use offsets relative to the beginning of the + .debug_info section to refer to each other. */ + +typedef long int dw_offset; + +/* Define typedefs here to avoid circular dependencies. */ + +typedef struct die_struct *dw_die_ref; +typedef struct dw_attr_struct *dw_attr_ref; +typedef struct dw_val_struct *dw_val_ref; +typedef struct dw_line_info_struct *dw_line_info_ref; +typedef struct dw_separate_line_info_struct *dw_separate_line_info_ref; +typedef struct dw_loc_descr_struct *dw_loc_descr_ref; +typedef struct pubname_struct *pubname_ref; +typedef dw_die_ref *arange_ref; + +/* Describe a double word constant value. */ + +typedef struct dw_long_long_struct +{ + unsigned long hi; + unsigned long low; +} +dw_long_long_const; + +/* Describe a floating point constant value. */ + +typedef struct dw_fp_struct +{ + long *array; + unsigned length; +} +dw_float_const; + +/* Each entry in the line_info_table maintains the file and + line number associated with the label generated for that + entry. The label gives the PC value associated with + the line number entry. */ + +typedef struct dw_line_info_struct +{ + unsigned long dw_file_num; + unsigned long dw_line_num; +} +dw_line_info_entry; + +/* Line information for functions in separate sections; each one gets its + own sequence. */ +typedef struct dw_separate_line_info_struct +{ + unsigned long dw_file_num; + unsigned long dw_line_num; + unsigned long function; +} +dw_separate_line_info_entry; + +/* The dw_val_node describes an attribute's value, as it is + represented internally. */ + +typedef struct dw_val_struct +{ + dw_val_class val_class; + union + { + rtx val_addr; + dw_loc_descr_ref val_loc; + long int val_int; + long unsigned val_unsigned; + dw_long_long_const val_long_long; + dw_float_const val_float; + dw_die_ref val_die_ref; + unsigned val_fde_index; + char *val_str; + char *val_lbl_id; + char *val_section; + unsigned char val_flag; + } + v; +} +dw_val_node; + +/* Locations in memory are described using a sequence of stack machine + operations. */ + +typedef struct dw_loc_descr_struct +{ + dw_loc_descr_ref dw_loc_next; + enum dwarf_location_atom dw_loc_opc; + dw_val_node dw_loc_oprnd1; + dw_val_node dw_loc_oprnd2; +} +dw_loc_descr_node; + +/* Each DIE attribute has a field specifying the attribute kind, + a link to the next attribute in the chain, and an attribute value. + Attributes are typically linked below the DIE they modify. */ + +typedef struct dw_attr_struct +{ + enum dwarf_attribute dw_attr; + dw_attr_ref dw_attr_next; + dw_val_node dw_attr_val; +} +dw_attr_node; + +/* The Debugging Information Entry (DIE) structure */ + +typedef struct die_struct +{ + enum dwarf_tag die_tag; + dw_attr_ref die_attr; + dw_attr_ref die_attr_last; + dw_die_ref die_parent; + dw_die_ref die_child; + dw_die_ref die_child_last; + dw_die_ref die_sib; + dw_offset die_offset; + unsigned long die_abbrev; +} +die_node; + +/* The pubname structure */ + +typedef struct pubname_struct +{ + dw_die_ref die; + char * name; +} +pubname_entry; + +/* The limbo die list structure. */ +typedef struct limbo_die_struct +{ + dw_die_ref die; + struct limbo_die_struct *next; +} +limbo_die_node; + +/* How to start an assembler comment. */ +#ifndef ASM_COMMENT_START +#define ASM_COMMENT_START ";#" +#endif + +/* Define a macro which returns non-zero 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_TREE \ + || (DECL_ARTIFICIAL (decl) \ + && is_tagged_type (TREE_TYPE (decl)) \ + && ((decl == TYPE_STUB_DECL (TREE_TYPE (decl))) \ + /* This is necessary for stub decls that \ + appear in nested inline functions. */ \ + || (DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE \ + && (decl_ultimate_origin (decl) \ + == TYPE_STUB_DECL (TREE_TYPE (decl))))))) + +/* Information concerning the compilation unit's programming + language, and compiler version. */ + +extern int flag_traditional; +extern char *version_string; +extern char *language_string; + +/* Fixed size portion of the DWARF compilation unit header. */ +#define DWARF_COMPILE_UNIT_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 3) + +/* Fixed size portion of debugging line information prolog. */ +#define DWARF_LINE_PROLOG_HEADER_SIZE 5 + +/* Fixed size portion of public names info. */ +#define DWARF_PUBNAMES_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 2) + +/* Fixed size portion of the address range info. */ +#define DWARF_ARANGES_HEADER_SIZE \ + (DWARF_ROUND (2 * DWARF_OFFSET_SIZE + 4, PTR_SIZE * 2) - DWARF_OFFSET_SIZE) + +/* Define the architecture-dependent minimum instruction length (in bytes). + In this implementation of DWARF, this field is used for information + purposes only. Since GCC generates assembly language, we have + no a priori knowledge of how many instruction bytes are generated + for each source line, and therefore can use only the DW_LNE_set_address + and DW_LNS_fixed_advance_pc line information commands. */ + +#ifndef DWARF_LINE_MIN_INSTR_LENGTH +#define DWARF_LINE_MIN_INSTR_LENGTH 4 +#endif + +/* Minimum line offset in a special line info. opcode. + This value was chosen to give a reasonable range of values. */ +#define DWARF_LINE_BASE -10 + +/* First special line opcde - leave room for the standard opcodes. */ +#define DWARF_LINE_OPCODE_BASE 10 + +/* Range of line offsets in a special line info. opcode. */ +#define DWARF_LINE_RANGE (254-DWARF_LINE_OPCODE_BASE+1) + +/* Flag that indicates the initial value of the is_stmt_start flag. + In the present implementation, we do not mark any lines as + the beginning of a source statement, because that information + is not made available by the GCC front-end. */ +#define DWARF_LINE_DEFAULT_IS_STMT_START 1 + +/* This location is used by calc_die_sizes() to keep track + the offset of each DIE within the .debug_info section. */ +static unsigned long next_die_offset; + +/* Record the root of the DIE's built for the current compilation unit. */ +static dw_die_ref comp_unit_die; + +/* A list of DIEs with a NULL parent waiting to be relocated. */ +static limbo_die_node *limbo_die_list = 0; + +/* Pointer to an array of filenames referenced by this compilation unit. */ +static char **file_table; + +/* Total number of entries in the table (i.e. array) pointed to by + `file_table'. This is the *total* and includes both used and unused + slots. */ +static unsigned file_table_allocated; + +/* Number of entries in the file_table which are actually in use. */ +static unsigned file_table_in_use; + +/* Size (in elements) of increments by which we may expand the filename + table. */ +#define FILE_TABLE_INCREMENT 64 + +/* Local pointer to the name of the main input file. Initialized in + dwarf2out_init. */ +static char *primary_filename; + +/* For Dwarf output, we must assign lexical-blocks id numbers in the order in + which their beginnings are encountered. We output Dwarf debugging info + that refers to the beginnings and ends of the ranges of code for each + lexical block. The labels themselves are generated in final.c, which + assigns numbers to the blocks in the same way. */ +static unsigned next_block_number = 2; + +/* A pointer to the base of a table of references to DIE's that describe + declarations. The table is indexed by DECL_UID() which is a unique + number identifying each decl. */ +static dw_die_ref *decl_die_table; + +/* Number of elements currently allocated for the decl_die_table. */ +static unsigned decl_die_table_allocated; + +/* Number of elements in decl_die_table currently in use. */ +static unsigned decl_die_table_in_use; + +/* Size (in elements) of increments by which we may expand the + decl_die_table. */ +#define DECL_DIE_TABLE_INCREMENT 256 + +/* Structure used for the decl_scope table. scope is the current declaration + scope, and previous is the entry that is the parent of this scope. This + is usually but not always the immediately preceeding entry. */ + +typedef struct decl_scope_struct +{ + tree scope; + int previous; +} +decl_scope_node; + +/* A pointer to the base of a table of references to declaration + scopes. This table is a display which tracks the nesting + of declaration scopes at the current scope and containing + scopes. This table is used to find the proper place to + define type declaration DIE's. */ +static decl_scope_node *decl_scope_table; + +/* Number of elements currently allocated for the decl_scope_table. */ +static int decl_scope_table_allocated; + +/* Current level of nesting of declaration scopes. */ +static int decl_scope_depth; + +/* Size (in elements) of increments by which we may expand the + decl_scope_table. */ +#define DECL_SCOPE_TABLE_INCREMENT 64 + +/* A pointer to the base of a list of references to DIE's that + are uniquely identified by their tag, presence/absence of + children DIE's, and list of attribute/value pairs. */ +static dw_die_ref *abbrev_die_table; + +/* Number of elements currently allocated for abbrev_die_table. */ +static unsigned abbrev_die_table_allocated; + +/* Number of elements in type_die_table currently in use. */ +static unsigned abbrev_die_table_in_use; + +/* Size (in elements) of increments by which we may expand the + abbrev_die_table. */ +#define ABBREV_DIE_TABLE_INCREMENT 256 + +/* A pointer to the base of a table that contains line information + for each source code line in .text in the compilation unit. */ +static dw_line_info_ref line_info_table; + +/* Number of elements currently allocated for line_info_table. */ +static unsigned line_info_table_allocated; + +/* Number of elements in separate_line_info_table currently in use. */ +static unsigned separate_line_info_table_in_use; + +/* A pointer to the base of a table that contains line information + for each source code line outside of .text in the compilation unit. */ +static dw_separate_line_info_ref separate_line_info_table; + +/* Number of elements currently allocated for separate_line_info_table. */ +static unsigned separate_line_info_table_allocated; + +/* Number of elements in line_info_table currently in use. */ +static unsigned line_info_table_in_use; + +/* Size (in elements) of increments by which we may expand the + line_info_table. */ +#define LINE_INFO_TABLE_INCREMENT 1024 + +/* A pointer to the base of a table that contains a list of publicly + accessible names. */ +static pubname_ref pubname_table; + +/* Number of elements currently allocated for pubname_table. */ +static unsigned pubname_table_allocated; + +/* Number of elements in pubname_table currently in use. */ +static unsigned pubname_table_in_use; + +/* Size (in elements) of increments by which we may expand the + pubname_table. */ +#define PUBNAME_TABLE_INCREMENT 64 + +/* A pointer to the base of a table that contains a list of publicly + accessible names. */ +static arange_ref arange_table; + +/* Number of elements currently allocated for arange_table. */ +static unsigned arange_table_allocated; + +/* Number of elements in arange_table currently in use. */ +static unsigned arange_table_in_use; + +/* Size (in elements) of increments by which we may expand the + arange_table. */ +#define ARANGE_TABLE_INCREMENT 64 + +/* 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 + +/* Record whether the function being analyzed contains inlined functions. */ +static int current_function_has_inlines; +#if 0 && defined (MIPS_DEBUGGING_INFO) +static int comp_unit_has_inlines; +#endif + +/* 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; + +/* Forward declarations for functions defined in this file. */ + +static void addr_const_to_string PROTO((dyn_string_t, rtx)); +static int is_pseudo_reg PROTO((rtx)); +static tree type_main_variant PROTO((tree)); +static int is_tagged_type PROTO((tree)); +static char *dwarf_tag_name PROTO((unsigned)); +static char *dwarf_attr_name PROTO((unsigned)); +static char *dwarf_form_name PROTO((unsigned)); +static char *dwarf_stack_op_name PROTO((unsigned)); +#if 0 +static char *dwarf_type_encoding_name PROTO((unsigned)); +#endif +static tree decl_ultimate_origin PROTO((tree)); +static tree block_ultimate_origin PROTO((tree)); +static tree decl_class_context PROTO((tree)); +static void add_dwarf_attr PROTO((dw_die_ref, dw_attr_ref)); +static void add_AT_flag PROTO((dw_die_ref, + enum dwarf_attribute, + unsigned)); +static void add_AT_int PROTO((dw_die_ref, + enum dwarf_attribute, long)); +static void add_AT_unsigned PROTO((dw_die_ref, + enum dwarf_attribute, + unsigned long)); +static void add_AT_long_long PROTO((dw_die_ref, + enum dwarf_attribute, + unsigned long, unsigned long)); +static void add_AT_float PROTO((dw_die_ref, + enum dwarf_attribute, + unsigned, long *)); +static void add_AT_string PROTO((dw_die_ref, + enum dwarf_attribute, char *)); +static void add_AT_die_ref PROTO((dw_die_ref, + enum dwarf_attribute, + dw_die_ref)); +static void add_AT_fde_ref PROTO((dw_die_ref, + enum dwarf_attribute, + unsigned)); +static void add_AT_loc PROTO((dw_die_ref, + enum dwarf_attribute, + dw_loc_descr_ref)); +static void add_AT_addr PROTO((dw_die_ref, + enum dwarf_attribute, rtx)); +static void add_AT_lbl_id PROTO((dw_die_ref, + enum dwarf_attribute, char *)); +static void add_AT_section_offset PROTO((dw_die_ref, + enum dwarf_attribute, char *)); +static int is_extern_subr_die PROTO((dw_die_ref)); +static dw_attr_ref get_AT PROTO((dw_die_ref, + enum dwarf_attribute)); +static char *get_AT_low_pc PROTO((dw_die_ref)); +static char *get_AT_hi_pc PROTO((dw_die_ref)); +static char *get_AT_string PROTO((dw_die_ref, + enum dwarf_attribute)); +static int get_AT_flag PROTO((dw_die_ref, + enum dwarf_attribute)); +static unsigned get_AT_unsigned PROTO((dw_die_ref, + enum dwarf_attribute)); +static int is_c_family PROTO((void)); +static int is_fortran PROTO((void)); +static void remove_AT PROTO((dw_die_ref, + enum dwarf_attribute)); +static void remove_children PROTO((dw_die_ref)); +static void add_child_die PROTO((dw_die_ref, dw_die_ref)); +static dw_die_ref new_die PROTO((enum dwarf_tag, dw_die_ref)); +static dw_die_ref lookup_type_die PROTO((tree)); +static void equate_type_number_to_die PROTO((tree, dw_die_ref)); +static dw_die_ref lookup_decl_die PROTO((tree)); +static void equate_decl_number_to_die PROTO((tree, dw_die_ref)); +static dw_loc_descr_ref new_loc_descr PROTO((enum dwarf_location_atom, + unsigned long, unsigned long)); +static void add_loc_descr PROTO((dw_loc_descr_ref *, + dw_loc_descr_ref)); +static void print_spaces PROTO((FILE *)); +static void print_die PROTO((dw_die_ref, FILE *)); +static void print_dwarf_line_table PROTO((FILE *)); +static void add_sibling_attributes PROTO((dw_die_ref)); +static void build_abbrev_table PROTO((dw_die_ref)); +static unsigned long size_of_string PROTO((char *)); +static unsigned long size_of_loc_descr PROTO((dw_loc_descr_ref)); +static unsigned long size_of_locs PROTO((dw_loc_descr_ref)); +static int constant_size PROTO((long unsigned)); +static unsigned long size_of_die PROTO((dw_die_ref)); +static void calc_die_sizes PROTO((dw_die_ref)); +static unsigned long size_of_line_prolog PROTO((void)); +static unsigned long size_of_line_info PROTO((void)); +static unsigned long size_of_pubnames PROTO((void)); +static unsigned long size_of_aranges PROTO((void)); +static enum dwarf_form value_format PROTO((dw_val_ref)); +static void output_value_format PROTO((dw_val_ref)); +static void output_abbrev_section PROTO((void)); +static void output_loc_operands PROTO((dw_loc_descr_ref)); +static unsigned long sibling_offset PROTO((dw_die_ref)); +static void output_die PROTO((dw_die_ref)); +static void output_compilation_unit_header PROTO((void)); +static char *dwarf2_name PROTO((tree, int)); +static void add_pubname PROTO((tree, dw_die_ref)); +static void output_pubnames PROTO((void)); +static void add_arange PROTO((tree, dw_die_ref)); +static void output_aranges PROTO((void)); +static void output_line_info PROTO((void)); +static int is_body_block PROTO((tree)); +static dw_die_ref base_type_die PROTO((tree)); +static tree root_type PROTO((tree)); +static int is_base_type PROTO((tree)); +static dw_die_ref modified_type_die PROTO((tree, int, int, dw_die_ref)); +static int type_is_enum PROTO((tree)); +static dw_loc_descr_ref reg_loc_descriptor PROTO((rtx)); +static dw_loc_descr_ref based_loc_descr PROTO((unsigned, long)); +static int is_based_loc PROTO((rtx)); +static dw_loc_descr_ref mem_loc_descriptor PROTO((rtx)); +static dw_loc_descr_ref concat_loc_descriptor PROTO((rtx, rtx)); +static dw_loc_descr_ref loc_descriptor PROTO((rtx)); +static unsigned ceiling PROTO((unsigned, unsigned)); +static tree field_type PROTO((tree)); +static unsigned simple_type_align_in_bits PROTO((tree)); +static unsigned simple_type_size_in_bits PROTO((tree)); +static unsigned field_byte_offset PROTO((tree)); +static void add_AT_location_description PROTO((dw_die_ref, + enum dwarf_attribute, rtx)); +static void add_data_member_location_attribute PROTO((dw_die_ref, tree)); +static void add_const_value_attribute PROTO((dw_die_ref, rtx)); +static void add_location_or_const_value_attribute PROTO((dw_die_ref, tree)); +static void add_name_attribute PROTO((dw_die_ref, char *)); +static void add_bound_info PROTO((dw_die_ref, + enum dwarf_attribute, tree)); +static void add_subscript_info PROTO((dw_die_ref, tree)); +static void add_byte_size_attribute PROTO((dw_die_ref, tree)); +static void add_bit_offset_attribute PROTO((dw_die_ref, tree)); +static void add_bit_size_attribute PROTO((dw_die_ref, tree)); +static void add_prototyped_attribute PROTO((dw_die_ref, tree)); +static void add_abstract_origin_attribute PROTO((dw_die_ref, tree)); +static void add_pure_or_virtual_attribute PROTO((dw_die_ref, tree)); +static void add_src_coords_attributes PROTO((dw_die_ref, tree)); +static void add_name_and_src_coords_attributes PROTO((dw_die_ref, tree)); +static void push_decl_scope PROTO((tree)); +static dw_die_ref scope_die_for PROTO((tree, dw_die_ref)); +static void pop_decl_scope PROTO((void)); +static void add_type_attribute PROTO((dw_die_ref, tree, int, int, + dw_die_ref)); +static char *type_tag PROTO((tree)); +static tree member_declared_type PROTO((tree)); +#if 0 +static char *decl_start_label PROTO((tree)); +#endif +static void gen_array_type_die PROTO((tree, dw_die_ref)); +static void gen_set_type_die PROTO((tree, dw_die_ref)); +#if 0 +static void gen_entry_point_die PROTO((tree, dw_die_ref)); +#endif +static void pend_type PROTO((tree)); +static void output_pending_types_for_scope PROTO((dw_die_ref)); +static void gen_inlined_enumeration_type_die PROTO((tree, dw_die_ref)); +static void gen_inlined_structure_type_die PROTO((tree, dw_die_ref)); +static void gen_inlined_union_type_die PROTO((tree, dw_die_ref)); +static void gen_enumeration_type_die PROTO((tree, dw_die_ref)); +static dw_die_ref gen_formal_parameter_die PROTO((tree, dw_die_ref)); +static void gen_unspecified_parameters_die PROTO((tree, dw_die_ref)); +static void gen_formal_types_die PROTO((tree, dw_die_ref)); +static void gen_subprogram_die PROTO((tree, dw_die_ref)); +static void gen_variable_die PROTO((tree, dw_die_ref)); +static void gen_label_die PROTO((tree, dw_die_ref)); +static void gen_lexical_block_die PROTO((tree, dw_die_ref, int)); +static void gen_inlined_subroutine_die PROTO((tree, dw_die_ref, int)); +static void gen_field_die PROTO((tree, dw_die_ref)); +static void gen_ptr_to_mbr_type_die PROTO((tree, dw_die_ref)); +static void gen_compile_unit_die PROTO((char *)); +static void gen_string_type_die PROTO((tree, dw_die_ref)); +static void gen_inheritance_die PROTO((tree, dw_die_ref)); +static void gen_member_die PROTO((tree, dw_die_ref)); +static void gen_struct_or_union_type_die PROTO((tree, dw_die_ref)); +static void gen_subroutine_type_die PROTO((tree, dw_die_ref)); +static void gen_typedef_die PROTO((tree, dw_die_ref)); +static void gen_type_die PROTO((tree, dw_die_ref)); +static void gen_tagged_type_instantiation_die PROTO((tree, dw_die_ref)); +static void gen_block_die PROTO((tree, dw_die_ref, int)); +static void decls_for_scope PROTO((tree, dw_die_ref, int)); +static int is_redundant_typedef PROTO((tree)); +static void gen_decl_die PROTO((tree, dw_die_ref)); +static unsigned lookup_filename PROTO((char *)); +static rtx save_rtx PROTO((rtx)); + +/* Section names used to hold DWARF debugging information. */ +#ifndef DEBUG_INFO_SECTION +#define DEBUG_INFO_SECTION ".debug_info" +#endif +#ifndef ABBREV_SECTION +#define ABBREV_SECTION ".debug_abbrev" +#endif +#ifndef ARANGES_SECTION +#define ARANGES_SECTION ".debug_aranges" +#endif +#ifndef DW_MACINFO_SECTION +#define DW_MACINFO_SECTION ".debug_macinfo" +#endif +#ifndef DEBUG_LINE_SECTION +#define DEBUG_LINE_SECTION ".debug_line" +#endif +#ifndef LOC_SECTION +#define LOC_SECTION ".debug_loc" +#endif +#ifndef PUBNAMES_SECTION +#define PUBNAMES_SECTION ".debug_pubnames" +#endif +#ifndef STR_SECTION +#define STR_SECTION ".debug_str" +#endif + +/* Standard ELF section names for compiled code and data. */ +#ifndef TEXT_SECTION +#define TEXT_SECTION ".text" +#endif +#ifndef DATA_SECTION +#define DATA_SECTION ".data" +#endif +#ifndef BSS_SECTION +#define BSS_SECTION ".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 the tm.h file, but + typically, overriding these defaults is unnecessary. */ + +static char text_end_label[MAX_ARTIFICIAL_LABEL_BYTES]; + +#ifndef TEXT_END_LABEL +#define TEXT_END_LABEL "Letext" +#endif +#ifndef DATA_END_LABEL +#define DATA_END_LABEL "Ledata" +#endif +#ifndef BSS_END_LABEL +#define BSS_END_LABEL "Lebss" +#endif +#ifndef INSN_LABEL_FMT +#define INSN_LABEL_FMT "LI%u_" +#endif +#ifndef BLOCK_BEGIN_LABEL +#define BLOCK_BEGIN_LABEL "LBB" +#endif +#ifndef BLOCK_END_LABEL +#define BLOCK_END_LABEL "LBE" +#endif +#ifndef BODY_BEGIN_LABEL +#define BODY_BEGIN_LABEL "Lbb" +#endif +#ifndef BODY_END_LABEL +#define BODY_END_LABEL "Lbe" +#endif +#ifndef LINE_CODE_LABEL +#define LINE_CODE_LABEL "LM" +#endif +#ifndef SEPARATE_LINE_CODE_LABEL +#define SEPARATE_LINE_CODE_LABEL "LSM" +#endif + +/* Convert a reference to the assembler name of a C-level name. This + macro has the same effect as ASM_OUTPUT_LABELREF, but copies to + a string rather than writing to a file. */ +#ifndef ASM_NAME_TO_STRING +#define ASM_NAME_TO_STRING(STR, NAME) \ + do { \ + if ((NAME)[0] == '*') \ + dyn_string_append (STR, NAME + 1); \ + else \ + { \ + dyn_string_append (STR, user_label_prefix); \ + dyn_string_append (STR, NAME); \ + } \ + } \ + while (0) +#endif + +/* Convert an integer constant expression into assembler syntax. Addition + and subtraction are the only arithmetic that may appear in these + expressions. This is an adaptation of output_addr_const in final.c. + Here, the target of the conversion is a string buffer. We can't use + output_addr_const directly, because it writes to a file. */ + +static void +addr_const_to_string (str, x) + dyn_string_t str; + rtx x; +{ + char buf1[256]; + +restart: + switch (GET_CODE (x)) + { + case PC: + if (flag_pic) + dyn_string_append (str, ","); + else + abort (); + break; + + case SYMBOL_REF: + ASM_NAME_TO_STRING (str, XSTR (x, 0)); + break; + + case LABEL_REF: + ASM_GENERATE_INTERNAL_LABEL (buf1, "L", CODE_LABEL_NUMBER (XEXP (x, 0))); + ASM_NAME_TO_STRING (str, buf1); + break; + + case CODE_LABEL: + ASM_GENERATE_INTERNAL_LABEL (buf1, "L", CODE_LABEL_NUMBER (x)); + ASM_NAME_TO_STRING (str, buf1); + break; + + case CONST_INT: + sprintf (buf1, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); + dyn_string_append (str, buf1); + break; + + case CONST: + /* This used to output parentheses around the expression, but that does + not work on the 386 (either ATT or BSD assembler). */ + addr_const_to_string (str, XEXP (x, 0)); + break; + + case CONST_DOUBLE: + if (GET_MODE (x) == VOIDmode) + { + /* We can use %d if the number is one word and positive. */ + if (CONST_DOUBLE_HIGH (x)) + sprintf (buf1, HOST_WIDE_INT_PRINT_DOUBLE_HEX, + CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x)); + else if (CONST_DOUBLE_LOW (x) < 0) + sprintf (buf1, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x)); + else + sprintf (buf1, HOST_WIDE_INT_PRINT_DEC, + CONST_DOUBLE_LOW (x)); + dyn_string_append (str, buf1); + } + else + /* We can't handle floating point constants; PRINT_OPERAND must + handle them. */ + output_operand_lossage ("floating constant misused"); + break; + + case PLUS: + /* Some assemblers need integer constants to appear last (eg masm). */ + if (GET_CODE (XEXP (x, 0)) == CONST_INT) + { + addr_const_to_string (str, XEXP (x, 1)); + if (INTVAL (XEXP (x, 0)) >= 0) + dyn_string_append (str, "+"); + + addr_const_to_string (str, XEXP (x, 0)); + } + else + { + addr_const_to_string (str, XEXP (x, 0)); + if (INTVAL (XEXP (x, 1)) >= 0) + dyn_string_append (str, "+"); + + addr_const_to_string (str, XEXP (x, 1)); + } + break; + + case MINUS: + /* Avoid outputting things like x-x or x+5-x, since some assemblers + can't handle that. */ + x = simplify_subtraction (x); + if (GET_CODE (x) != MINUS) + goto restart; + + addr_const_to_string (str, XEXP (x, 0)); + dyn_string_append (str, "-"); + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) < 0) + { + dyn_string_append (str, ASM_OPEN_PAREN); + addr_const_to_string (str, XEXP (x, 1)); + dyn_string_append (str, ASM_CLOSE_PAREN); + } + else + addr_const_to_string (str, XEXP (x, 1)); + break; + + case ZERO_EXTEND: + case SIGN_EXTEND: + addr_const_to_string (str, XEXP (x, 0)); + break; + + default: + output_operand_lossage ("invalid expression as operand"); + } +} + +/* Return an rtx like ORIG which lives forever. That means making a + copy on the permanent_obstack. */ + +static rtx +save_rtx (orig) + register rtx orig; +{ + push_obstacks_nochange (); + end_temporary_allocation (); + orig = really_copy_rtx (orig); + pop_obstacks (); + + return orig; +} + +/* Test if rtl node points to a pseudo register. */ + +static inline int +is_pseudo_reg (rtl) + register rtx rtl; +{ + return (((GET_CODE (rtl) == REG) && (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)) + || ((GET_CODE (rtl) == SUBREG) + && (REGNO (XEXP (rtl, 0)) >= FIRST_PSEUDO_REGISTER))); +} + +/* Return a reference to a type, with its const and volatile qualifiers + removed. */ + +static inline tree +type_main_variant (type) + register 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 non-zero if the given type node represents a tagged type. */ + +static inline int +is_tagged_type (type) + register tree type; +{ + register enum tree_code code = TREE_CODE (type); + + return (code == RECORD_TYPE || code == UNION_TYPE + || code == QUAL_UNION_TYPE || code == ENUMERAL_TYPE); +} + +/* Convert a DIE tag into its string name. */ + +static char * +dwarf_tag_name (tag) + register unsigned tag; +{ + switch (tag) + { + case DW_TAG_padding: + return "DW_TAG_padding"; + case DW_TAG_array_type: + return "DW_TAG_array_type"; + case DW_TAG_class_type: + return "DW_TAG_class_type"; + case DW_TAG_entry_point: + return "DW_TAG_entry_point"; + case DW_TAG_enumeration_type: + return "DW_TAG_enumeration_type"; + case DW_TAG_formal_parameter: + return "DW_TAG_formal_parameter"; + case DW_TAG_imported_declaration: + return "DW_TAG_imported_declaration"; + case DW_TAG_label: + return "DW_TAG_label"; + case DW_TAG_lexical_block: + return "DW_TAG_lexical_block"; + case DW_TAG_member: + return "DW_TAG_member"; + case DW_TAG_pointer_type: + return "DW_TAG_pointer_type"; + case DW_TAG_reference_type: + return "DW_TAG_reference_type"; + case DW_TAG_compile_unit: + return "DW_TAG_compile_unit"; + case DW_TAG_string_type: + return "DW_TAG_string_type"; + case DW_TAG_structure_type: + return "DW_TAG_structure_type"; + case DW_TAG_subroutine_type: + return "DW_TAG_subroutine_type"; + case DW_TAG_typedef: + return "DW_TAG_typedef"; + case DW_TAG_union_type: + return "DW_TAG_union_type"; + case DW_TAG_unspecified_parameters: + return "DW_TAG_unspecified_parameters"; + case DW_TAG_variant: + return "DW_TAG_variant"; + case DW_TAG_common_block: + return "DW_TAG_common_block"; + case DW_TAG_common_inclusion: + return "DW_TAG_common_inclusion"; + case DW_TAG_inheritance: + return "DW_TAG_inheritance"; + case DW_TAG_inlined_subroutine: + return "DW_TAG_inlined_subroutine"; + case DW_TAG_module: + return "DW_TAG_module"; + case DW_TAG_ptr_to_member_type: + return "DW_TAG_ptr_to_member_type"; + case DW_TAG_set_type: + return "DW_TAG_set_type"; + case DW_TAG_subrange_type: + return "DW_TAG_subrange_type"; + case DW_TAG_with_stmt: + return "DW_TAG_with_stmt"; + case DW_TAG_access_declaration: + return "DW_TAG_access_declaration"; + case DW_TAG_base_type: + return "DW_TAG_base_type"; + case DW_TAG_catch_block: + return "DW_TAG_catch_block"; + case DW_TAG_const_type: + return "DW_TAG_const_type"; + case DW_TAG_constant: + return "DW_TAG_constant"; + case DW_TAG_enumerator: + return "DW_TAG_enumerator"; + case DW_TAG_file_type: + return "DW_TAG_file_type"; + case DW_TAG_friend: + return "DW_TAG_friend"; + case DW_TAG_namelist: + return "DW_TAG_namelist"; + case DW_TAG_namelist_item: + return "DW_TAG_namelist_item"; + case DW_TAG_packed_type: + return "DW_TAG_packed_type"; + case DW_TAG_subprogram: + return "DW_TAG_subprogram"; + case DW_TAG_template_type_param: + return "DW_TAG_template_type_param"; + case DW_TAG_template_value_param: + return "DW_TAG_template_value_param"; + case DW_TAG_thrown_type: + return "DW_TAG_thrown_type"; + case DW_TAG_try_block: + return "DW_TAG_try_block"; + case DW_TAG_variant_part: + return "DW_TAG_variant_part"; + case DW_TAG_variable: + return "DW_TAG_variable"; + case DW_TAG_volatile_type: + return "DW_TAG_volatile_type"; + case DW_TAG_MIPS_loop: + return "DW_TAG_MIPS_loop"; + case DW_TAG_format_label: + return "DW_TAG_format_label"; + case DW_TAG_function_template: + return "DW_TAG_function_template"; + case DW_TAG_class_template: + return "DW_TAG_class_template"; + default: + return "DW_TAG_"; + } +} + +/* Convert a DWARF attribute code into its string name. */ + +static char * +dwarf_attr_name (attr) + register unsigned attr; +{ + switch (attr) + { + case DW_AT_sibling: + return "DW_AT_sibling"; + case DW_AT_location: + return "DW_AT_location"; + case DW_AT_name: + return "DW_AT_name"; + case DW_AT_ordering: + return "DW_AT_ordering"; + case DW_AT_subscr_data: + return "DW_AT_subscr_data"; + case DW_AT_byte_size: + return "DW_AT_byte_size"; + case DW_AT_bit_offset: + return "DW_AT_bit_offset"; + case DW_AT_bit_size: + return "DW_AT_bit_size"; + case DW_AT_element_list: + return "DW_AT_element_list"; + case DW_AT_stmt_list: + return "DW_AT_stmt_list"; + case DW_AT_low_pc: + return "DW_AT_low_pc"; + case DW_AT_high_pc: + return "DW_AT_high_pc"; + case DW_AT_language: + return "DW_AT_language"; + case DW_AT_member: + return "DW_AT_member"; + case DW_AT_discr: + return "DW_AT_discr"; + case DW_AT_discr_value: + return "DW_AT_discr_value"; + case DW_AT_visibility: + return "DW_AT_visibility"; + case DW_AT_import: + return "DW_AT_import"; + case DW_AT_string_length: + return "DW_AT_string_length"; + case DW_AT_common_reference: + return "DW_AT_common_reference"; + case DW_AT_comp_dir: + return "DW_AT_comp_dir"; + case DW_AT_const_value: + return "DW_AT_const_value"; + case DW_AT_containing_type: + return "DW_AT_containing_type"; + case DW_AT_default_value: + return "DW_AT_default_value"; + case DW_AT_inline: + return "DW_AT_inline"; + case DW_AT_is_optional: + return "DW_AT_is_optional"; + case DW_AT_lower_bound: + return "DW_AT_lower_bound"; + case DW_AT_producer: + return "DW_AT_producer"; + case DW_AT_prototyped: + return "DW_AT_prototyped"; + case DW_AT_return_addr: + return "DW_AT_return_addr"; + case DW_AT_start_scope: + return "DW_AT_start_scope"; + case DW_AT_stride_size: + return "DW_AT_stride_size"; + case DW_AT_upper_bound: + return "DW_AT_upper_bound"; + case DW_AT_abstract_origin: + return "DW_AT_abstract_origin"; + case DW_AT_accessibility: + return "DW_AT_accessibility"; + case DW_AT_address_class: + return "DW_AT_address_class"; + case DW_AT_artificial: + return "DW_AT_artificial"; + case DW_AT_base_types: + return "DW_AT_base_types"; + case DW_AT_calling_convention: + return "DW_AT_calling_convention"; + case DW_AT_count: + return "DW_AT_count"; + case DW_AT_data_member_location: + return "DW_AT_data_member_location"; + case DW_AT_decl_column: + return "DW_AT_decl_column"; + case DW_AT_decl_file: + return "DW_AT_decl_file"; + case DW_AT_decl_line: + return "DW_AT_decl_line"; + case DW_AT_declaration: + return "DW_AT_declaration"; + case DW_AT_discr_list: + return "DW_AT_discr_list"; + case DW_AT_encoding: + return "DW_AT_encoding"; + case DW_AT_external: + return "DW_AT_external"; + case DW_AT_frame_base: + return "DW_AT_frame_base"; + case DW_AT_friend: + return "DW_AT_friend"; + case DW_AT_identifier_case: + return "DW_AT_identifier_case"; + case DW_AT_macro_info: + return "DW_AT_macro_info"; + case DW_AT_namelist_items: + return "DW_AT_namelist_items"; + case DW_AT_priority: + return "DW_AT_priority"; + case DW_AT_segment: + return "DW_AT_segment"; + case DW_AT_specification: + return "DW_AT_specification"; + case DW_AT_static_link: + return "DW_AT_static_link"; + case DW_AT_type: + return "DW_AT_type"; + case DW_AT_use_location: + return "DW_AT_use_location"; + case DW_AT_variable_parameter: + return "DW_AT_variable_parameter"; + case DW_AT_virtuality: + return "DW_AT_virtuality"; + case DW_AT_vtable_elem_location: + return "DW_AT_vtable_elem_location"; + + case DW_AT_MIPS_fde: + return "DW_AT_MIPS_fde"; + case DW_AT_MIPS_loop_begin: + return "DW_AT_MIPS_loop_begin"; + case DW_AT_MIPS_tail_loop_begin: + return "DW_AT_MIPS_tail_loop_begin"; + case DW_AT_MIPS_epilog_begin: + return "DW_AT_MIPS_epilog_begin"; + case DW_AT_MIPS_loop_unroll_factor: + return "DW_AT_MIPS_loop_unroll_factor"; + case DW_AT_MIPS_software_pipeline_depth: + return "DW_AT_MIPS_software_pipeline_depth"; + case DW_AT_MIPS_linkage_name: + return "DW_AT_MIPS_linkage_name"; + case DW_AT_MIPS_stride: + return "DW_AT_MIPS_stride"; + case DW_AT_MIPS_abstract_name: + return "DW_AT_MIPS_abstract_name"; + case DW_AT_MIPS_clone_origin: + return "DW_AT_MIPS_clone_origin"; + case DW_AT_MIPS_has_inlines: + return "DW_AT_MIPS_has_inlines"; + + case DW_AT_sf_names: + return "DW_AT_sf_names"; + case DW_AT_src_info: + return "DW_AT_src_info"; + case DW_AT_mac_info: + return "DW_AT_mac_info"; + case DW_AT_src_coords: + return "DW_AT_src_coords"; + case DW_AT_body_begin: + return "DW_AT_body_begin"; + case DW_AT_body_end: + return "DW_AT_body_end"; + default: + return "DW_AT_"; + } +} + +/* Convert a DWARF value form code into its string name. */ + +static char * +dwarf_form_name (form) + register unsigned form; +{ + switch (form) + { + case DW_FORM_addr: + return "DW_FORM_addr"; + case DW_FORM_block2: + return "DW_FORM_block2"; + case DW_FORM_block4: + return "DW_FORM_block4"; + case DW_FORM_data2: + return "DW_FORM_data2"; + case DW_FORM_data4: + return "DW_FORM_data4"; + case DW_FORM_data8: + return "DW_FORM_data8"; + case DW_FORM_string: + return "DW_FORM_string"; + case DW_FORM_block: + return "DW_FORM_block"; + case DW_FORM_block1: + return "DW_FORM_block1"; + case DW_FORM_data1: + return "DW_FORM_data1"; + case DW_FORM_flag: + return "DW_FORM_flag"; + case DW_FORM_sdata: + return "DW_FORM_sdata"; + case DW_FORM_strp: + return "DW_FORM_strp"; + case DW_FORM_udata: + return "DW_FORM_udata"; + case DW_FORM_ref_addr: + return "DW_FORM_ref_addr"; + case DW_FORM_ref1: + return "DW_FORM_ref1"; + case DW_FORM_ref2: + return "DW_FORM_ref2"; + case DW_FORM_ref4: + return "DW_FORM_ref4"; + case DW_FORM_ref8: + return "DW_FORM_ref8"; + case DW_FORM_ref_udata: + return "DW_FORM_ref_udata"; + case DW_FORM_indirect: + return "DW_FORM_indirect"; + default: + return "DW_FORM_"; + } +} + +/* Convert a DWARF stack opcode into its string name. */ + +static char * +dwarf_stack_op_name (op) + register unsigned op; +{ + switch (op) + { + case DW_OP_addr: + return "DW_OP_addr"; + case DW_OP_deref: + return "DW_OP_deref"; + case DW_OP_const1u: + return "DW_OP_const1u"; + case DW_OP_const1s: + return "DW_OP_const1s"; + case DW_OP_const2u: + return "DW_OP_const2u"; + case DW_OP_const2s: + return "DW_OP_const2s"; + case DW_OP_const4u: + return "DW_OP_const4u"; + case DW_OP_const4s: + return "DW_OP_const4s"; + case DW_OP_const8u: + return "DW_OP_const8u"; + case DW_OP_const8s: + return "DW_OP_const8s"; + case DW_OP_constu: + return "DW_OP_constu"; + case DW_OP_consts: + return "DW_OP_consts"; + case DW_OP_dup: + return "DW_OP_dup"; + case DW_OP_drop: + return "DW_OP_drop"; + case DW_OP_over: + return "DW_OP_over"; + case DW_OP_pick: + return "DW_OP_pick"; + case DW_OP_swap: + return "DW_OP_swap"; + case DW_OP_rot: + return "DW_OP_rot"; + case DW_OP_xderef: + return "DW_OP_xderef"; + case DW_OP_abs: + return "DW_OP_abs"; + case DW_OP_and: + return "DW_OP_and"; + case DW_OP_div: + return "DW_OP_div"; + case DW_OP_minus: + return "DW_OP_minus"; + case DW_OP_mod: + return "DW_OP_mod"; + case DW_OP_mul: + return "DW_OP_mul"; + case DW_OP_neg: + return "DW_OP_neg"; + case DW_OP_not: + return "DW_OP_not"; + case DW_OP_or: + return "DW_OP_or"; + case DW_OP_plus: + return "DW_OP_plus"; + case DW_OP_plus_uconst: + return "DW_OP_plus_uconst"; + case DW_OP_shl: + return "DW_OP_shl"; + case DW_OP_shr: + return "DW_OP_shr"; + case DW_OP_shra: + return "DW_OP_shra"; + case DW_OP_xor: + return "DW_OP_xor"; + case DW_OP_bra: + return "DW_OP_bra"; + case DW_OP_eq: + return "DW_OP_eq"; + case DW_OP_ge: + return "DW_OP_ge"; + case DW_OP_gt: + return "DW_OP_gt"; + case DW_OP_le: + return "DW_OP_le"; + case DW_OP_lt: + return "DW_OP_lt"; + case DW_OP_ne: + return "DW_OP_ne"; + case DW_OP_skip: + return "DW_OP_skip"; + case DW_OP_lit0: + return "DW_OP_lit0"; + case DW_OP_lit1: + return "DW_OP_lit1"; + case DW_OP_lit2: + return "DW_OP_lit2"; + case DW_OP_lit3: + return "DW_OP_lit3"; + case DW_OP_lit4: + return "DW_OP_lit4"; + case DW_OP_lit5: + return "DW_OP_lit5"; + case DW_OP_lit6: + return "DW_OP_lit6"; + case DW_OP_lit7: + return "DW_OP_lit7"; + case DW_OP_lit8: + return "DW_OP_lit8"; + case DW_OP_lit9: + return "DW_OP_lit9"; + case DW_OP_lit10: + return "DW_OP_lit10"; + case DW_OP_lit11: + return "DW_OP_lit11"; + case DW_OP_lit12: + return "DW_OP_lit12"; + case DW_OP_lit13: + return "DW_OP_lit13"; + case DW_OP_lit14: + return "DW_OP_lit14"; + case DW_OP_lit15: + return "DW_OP_lit15"; + case DW_OP_lit16: + return "DW_OP_lit16"; + case DW_OP_lit17: + return "DW_OP_lit17"; + case DW_OP_lit18: + return "DW_OP_lit18"; + case DW_OP_lit19: + return "DW_OP_lit19"; + case DW_OP_lit20: + return "DW_OP_lit20"; + case DW_OP_lit21: + return "DW_OP_lit21"; + case DW_OP_lit22: + return "DW_OP_lit22"; + case DW_OP_lit23: + return "DW_OP_lit23"; + case DW_OP_lit24: + return "DW_OP_lit24"; + case DW_OP_lit25: + return "DW_OP_lit25"; + case DW_OP_lit26: + return "DW_OP_lit26"; + case DW_OP_lit27: + return "DW_OP_lit27"; + case DW_OP_lit28: + return "DW_OP_lit28"; + case DW_OP_lit29: + return "DW_OP_lit29"; + case DW_OP_lit30: + return "DW_OP_lit30"; + case DW_OP_lit31: + return "DW_OP_lit31"; + case DW_OP_reg0: + return "DW_OP_reg0"; + case DW_OP_reg1: + return "DW_OP_reg1"; + case DW_OP_reg2: + return "DW_OP_reg2"; + case DW_OP_reg3: + return "DW_OP_reg3"; + case DW_OP_reg4: + return "DW_OP_reg4"; + case DW_OP_reg5: + return "DW_OP_reg5"; + case DW_OP_reg6: + return "DW_OP_reg6"; + case DW_OP_reg7: + return "DW_OP_reg7"; + case DW_OP_reg8: + return "DW_OP_reg8"; + case DW_OP_reg9: + return "DW_OP_reg9"; + case DW_OP_reg10: + return "DW_OP_reg10"; + case DW_OP_reg11: + return "DW_OP_reg11"; + case DW_OP_reg12: + return "DW_OP_reg12"; + case DW_OP_reg13: + return "DW_OP_reg13"; + case DW_OP_reg14: + return "DW_OP_reg14"; + case DW_OP_reg15: + return "DW_OP_reg15"; + case DW_OP_reg16: + return "DW_OP_reg16"; + case DW_OP_reg17: + return "DW_OP_reg17"; + case DW_OP_reg18: + return "DW_OP_reg18"; + case DW_OP_reg19: + return "DW_OP_reg19"; + case DW_OP_reg20: + return "DW_OP_reg20"; + case DW_OP_reg21: + return "DW_OP_reg21"; + case DW_OP_reg22: + return "DW_OP_reg22"; + case DW_OP_reg23: + return "DW_OP_reg23"; + case DW_OP_reg24: + return "DW_OP_reg24"; + case DW_OP_reg25: + return "DW_OP_reg25"; + case DW_OP_reg26: + return "DW_OP_reg26"; + case DW_OP_reg27: + return "DW_OP_reg27"; + case DW_OP_reg28: + return "DW_OP_reg28"; + case DW_OP_reg29: + return "DW_OP_reg29"; + case DW_OP_reg30: + return "DW_OP_reg30"; + case DW_OP_reg31: + return "DW_OP_reg31"; + case DW_OP_breg0: + return "DW_OP_breg0"; + case DW_OP_breg1: + return "DW_OP_breg1"; + case DW_OP_breg2: + return "DW_OP_breg2"; + case DW_OP_breg3: + return "DW_OP_breg3"; + case DW_OP_breg4: + return "DW_OP_breg4"; + case DW_OP_breg5: + return "DW_OP_breg5"; + case DW_OP_breg6: + return "DW_OP_breg6"; + case DW_OP_breg7: + return "DW_OP_breg7"; + case DW_OP_breg8: + return "DW_OP_breg8"; + case DW_OP_breg9: + return "DW_OP_breg9"; + case DW_OP_breg10: + return "DW_OP_breg10"; + case DW_OP_breg11: + return "DW_OP_breg11"; + case DW_OP_breg12: + return "DW_OP_breg12"; + case DW_OP_breg13: + return "DW_OP_breg13"; + case DW_OP_breg14: + return "DW_OP_breg14"; + case DW_OP_breg15: + return "DW_OP_breg15"; + case DW_OP_breg16: + return "DW_OP_breg16"; + case DW_OP_breg17: + return "DW_OP_breg17"; + case DW_OP_breg18: + return "DW_OP_breg18"; + case DW_OP_breg19: + return "DW_OP_breg19"; + case DW_OP_breg20: + return "DW_OP_breg20"; + case DW_OP_breg21: + return "DW_OP_breg21"; + case DW_OP_breg22: + return "DW_OP_breg22"; + case DW_OP_breg23: + return "DW_OP_breg23"; + case DW_OP_breg24: + return "DW_OP_breg24"; + case DW_OP_breg25: + return "DW_OP_breg25"; + case DW_OP_breg26: + return "DW_OP_breg26"; + case DW_OP_breg27: + return "DW_OP_breg27"; + case DW_OP_breg28: + return "DW_OP_breg28"; + case DW_OP_breg29: + return "DW_OP_breg29"; + case DW_OP_breg30: + return "DW_OP_breg30"; + case DW_OP_breg31: + return "DW_OP_breg31"; + case DW_OP_regx: + return "DW_OP_regx"; + case DW_OP_fbreg: + return "DW_OP_fbreg"; + case DW_OP_bregx: + return "DW_OP_bregx"; + case DW_OP_piece: + return "DW_OP_piece"; + case DW_OP_deref_size: + return "DW_OP_deref_size"; + case DW_OP_xderef_size: + return "DW_OP_xderef_size"; + case DW_OP_nop: + return "DW_OP_nop"; + default: + return "OP_"; + } +} + +/* Convert a DWARF type code into its string name. */ + +#if 0 +static char * +dwarf_type_encoding_name (enc) + register unsigned enc; +{ + switch (enc) + { + case DW_ATE_address: + return "DW_ATE_address"; + case DW_ATE_boolean: + return "DW_ATE_boolean"; + case DW_ATE_complex_float: + return "DW_ATE_complex_float"; + case DW_ATE_float: + return "DW_ATE_float"; + case DW_ATE_signed: + return "DW_ATE_signed"; + case DW_ATE_signed_char: + return "DW_ATE_signed_char"; + case DW_ATE_unsigned: + return "DW_ATE_unsigned"; + case DW_ATE_unsigned_char: + return "DW_ATE_unsigned_char"; + default: + return "DW_ATE_"; + } +} +#endif + +/* 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) + register 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) + register tree block; +{ + register tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block); + + if (immediate_origin == NULL_TREE) + return NULL_TREE; + else + { + register tree ret_val; + register 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 && TREE_CODE_CLASS (TREE_CODE (context)) != 't') + context = NULL_TREE; + + return context; +} + +/* Add an attribute/value pair to a DIE */ + +static inline void +add_dwarf_attr (die, attr) + register dw_die_ref die; + register dw_attr_ref attr; +{ + if (die != NULL && attr != NULL) + { + if (die->die_attr == NULL) + { + die->die_attr = attr; + die->die_attr_last = attr; + } + else + { + die->die_attr_last->dw_attr_next = attr; + die->die_attr_last = attr; + } + } +} + +/* Add a flag value attribute to a DIE. */ + +static inline void +add_AT_flag (die, attr_kind, flag) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register unsigned flag; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_flag; + attr->dw_attr_val.v.val_flag = flag; + add_dwarf_attr (die, attr); +} + +/* Add a signed integer attribute value to a DIE. */ + +static inline void +add_AT_int (die, attr_kind, int_val) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register long int int_val; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_const; + attr->dw_attr_val.v.val_int = int_val; + add_dwarf_attr (die, attr); +} + +/* Add an unsigned integer attribute value to a DIE. */ + +static inline void +add_AT_unsigned (die, attr_kind, unsigned_val) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register unsigned long unsigned_val; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_unsigned_const; + attr->dw_attr_val.v.val_unsigned = unsigned_val; + add_dwarf_attr (die, attr); +} + +/* Add an unsigned double integer attribute value to a DIE. */ + +static inline void +add_AT_long_long (die, attr_kind, val_hi, val_low) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register unsigned long val_hi; + register unsigned long val_low; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_long_long; + attr->dw_attr_val.v.val_long_long.hi = val_hi; + attr->dw_attr_val.v.val_long_long.low = val_low; + add_dwarf_attr (die, attr); +} + +/* Add a floating point attribute value to a DIE and return it. */ + +static inline void +add_AT_float (die, attr_kind, length, array) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register unsigned length; + register long *array; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_float; + attr->dw_attr_val.v.val_float.length = length; + attr->dw_attr_val.v.val_float.array = array; + add_dwarf_attr (die, attr); +} + +/* Add a string attribute value to a DIE. */ + +static inline void +add_AT_string (die, attr_kind, str) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register char *str; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_str; + attr->dw_attr_val.v.val_str = xstrdup (str); + add_dwarf_attr (die, attr); +} + +/* Add a DIE reference attribute value to a DIE. */ + +static inline void +add_AT_die_ref (die, attr_kind, targ_die) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register dw_die_ref targ_die; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_die_ref; + attr->dw_attr_val.v.val_die_ref = targ_die; + add_dwarf_attr (die, attr); +} + +/* Add an FDE reference attribute value to a DIE. */ + +static inline void +add_AT_fde_ref (die, attr_kind, targ_fde) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register unsigned targ_fde; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_fde_ref; + attr->dw_attr_val.v.val_fde_index = targ_fde; + add_dwarf_attr (die, attr); +} + +/* Add a location description attribute value to a DIE. */ + +static inline void +add_AT_loc (die, attr_kind, loc) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register dw_loc_descr_ref loc; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_loc; + attr->dw_attr_val.v.val_loc = loc; + add_dwarf_attr (die, attr); +} + +/* Add an address constant attribute value to a DIE. */ + +static inline void +add_AT_addr (die, attr_kind, addr) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + rtx addr; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_addr; + attr->dw_attr_val.v.val_addr = addr; + add_dwarf_attr (die, attr); +} + +/* Add a label identifier attribute value to a DIE. */ + +static inline void +add_AT_lbl_id (die, attr_kind, lbl_id) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register char *lbl_id; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_lbl_id; + attr->dw_attr_val.v.val_lbl_id = xstrdup (lbl_id); + add_dwarf_attr (die, attr); +} + +/* Add a section offset attribute value to a DIE. */ + +static inline void +add_AT_section_offset (die, attr_kind, section) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; + register char *section; +{ + register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + + attr->dw_attr_next = NULL; + attr->dw_attr = attr_kind; + attr->dw_attr_val.val_class = dw_val_class_section_offset; + attr->dw_attr_val.v.val_section = section; + add_dwarf_attr (die, attr); + +} + +/* Test if die refers to an external subroutine. */ + +static inline int +is_extern_subr_die (die) + register dw_die_ref die; +{ + register dw_attr_ref a; + register int is_subr = FALSE; + register int is_extern = FALSE; + + if (die != NULL && die->die_tag == DW_TAG_subprogram) + { + is_subr = TRUE; + for (a = die->die_attr; a != NULL; a = a->dw_attr_next) + { + if (a->dw_attr == DW_AT_external + && a->dw_attr_val.val_class == dw_val_class_flag + && a->dw_attr_val.v.val_flag != 0) + { + is_extern = TRUE; + break; + } + } + } + + return is_subr && is_extern; +} + +/* Get the attribute of type attr_kind. */ + +static inline dw_attr_ref +get_AT (die, attr_kind) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; +{ + register dw_attr_ref a; + register dw_die_ref spec = NULL; + + if (die != NULL) + { + for (a = die->die_attr; a != NULL; a = a->dw_attr_next) + { + if (a->dw_attr == attr_kind) + return a; + + if (a->dw_attr == DW_AT_specification + || a->dw_attr == DW_AT_abstract_origin) + spec = a->dw_attr_val.v.val_die_ref; + } + + if (spec) + return get_AT (spec, attr_kind); + } + + return NULL; +} + +/* Return the "low pc" attribute value, typically associated with + a subprogram DIE. Return null if the "low pc" attribute is + either not prsent, or if it cannot be represented as an + assembler label identifier. */ + +static inline char * +get_AT_low_pc (die) + register dw_die_ref die; +{ + register dw_attr_ref a = get_AT (die, DW_AT_low_pc); + + if (a && a->dw_attr_val.val_class == dw_val_class_lbl_id) + return a->dw_attr_val.v.val_lbl_id; + + return NULL; +} + +/* Return the "high pc" attribute value, typically associated with + a subprogram DIE. Return null if the "high pc" attribute is + either not prsent, or if it cannot be represented as an + assembler label identifier. */ + +static inline char * +get_AT_hi_pc (die) + register dw_die_ref die; +{ + register dw_attr_ref a = get_AT (die, DW_AT_high_pc); + + if (a && a->dw_attr_val.val_class == dw_val_class_lbl_id) + return a->dw_attr_val.v.val_lbl_id; + + return NULL; +} + +/* Return the value of the string attribute designated by ATTR_KIND, or + NULL if it is not present. */ + +static inline char * +get_AT_string (die, attr_kind) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; +{ + register dw_attr_ref a = get_AT (die, attr_kind); + + if (a && a->dw_attr_val.val_class == dw_val_class_str) + return a->dw_attr_val.v.val_str; + + return NULL; +} + +/* Return the value of the flag attribute designated by ATTR_KIND, or -1 + if it is not present. */ + +static inline int +get_AT_flag (die, attr_kind) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; +{ + register dw_attr_ref a = get_AT (die, attr_kind); + + if (a && a->dw_attr_val.val_class == dw_val_class_flag) + return a->dw_attr_val.v.val_flag; + + return -1; +} + +/* Return the value of the unsigned attribute designated by ATTR_KIND, or 0 + if it is not present. */ + +static inline unsigned +get_AT_unsigned (die, attr_kind) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; +{ + register dw_attr_ref a = get_AT (die, attr_kind); + + if (a && a->dw_attr_val.val_class == dw_val_class_unsigned_const) + return a->dw_attr_val.v.val_unsigned; + + return 0; +} + +static inline int +is_c_family () +{ + register unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language); + + return (lang == DW_LANG_C || lang == DW_LANG_C89 + || lang == DW_LANG_C_plus_plus); +} + +static inline int +is_fortran () +{ + register unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language); + + return (lang == DW_LANG_Fortran77 || lang == DW_LANG_Fortran90); +} + +/* Remove the specified attribute if present. */ + +static inline void +remove_AT (die, attr_kind) + register dw_die_ref die; + register enum dwarf_attribute attr_kind; +{ + register dw_attr_ref a; + register dw_attr_ref removed = NULL;; + + if (die != NULL) + { + if (die->die_attr->dw_attr == attr_kind) + { + removed = die->die_attr; + if (die->die_attr_last == die->die_attr) + die->die_attr_last = NULL; + + die->die_attr = die->die_attr->dw_attr_next; + } + + else + for (a = die->die_attr; a->dw_attr_next != NULL; + a = a->dw_attr_next) + if (a->dw_attr_next->dw_attr == attr_kind) + { + removed = a->dw_attr_next; + if (die->die_attr_last == a->dw_attr_next) + die->die_attr_last = a; + + a->dw_attr_next = a->dw_attr_next->dw_attr_next; + break; + } + + if (removed != 0) + free (removed); + } +} + +/* Discard the children of this DIE. */ + +static inline void +remove_children (die) + register dw_die_ref die; +{ + register dw_die_ref child_die = die->die_child; + + die->die_child = NULL; + die->die_child_last = NULL; + + while (child_die != NULL) + { + register dw_die_ref tmp_die = child_die; + register dw_attr_ref a; + + child_die = child_die->die_sib; + + for (a = tmp_die->die_attr; a != NULL; ) + { + register dw_attr_ref tmp_a = a; + + a = a->dw_attr_next; + free (tmp_a); + } + + free (tmp_die); + } +} + +/* Add a child DIE below its parent. */ + +static inline void +add_child_die (die, child_die) + register dw_die_ref die; + register dw_die_ref child_die; +{ + if (die != NULL && child_die != NULL) + { + if (die == child_die) + abort (); + child_die->die_parent = die; + child_die->die_sib = NULL; + + if (die->die_child == NULL) + { + die->die_child = child_die; + die->die_child_last = child_die; + } + else + { + die->die_child_last->die_sib = child_die; + die->die_child_last = child_die; + } + } +} + +/* Return a pointer to a newly created DIE node. */ + +static inline dw_die_ref +new_die (tag_value, parent_die) + register enum dwarf_tag tag_value; + register dw_die_ref parent_die; +{ + register dw_die_ref die = (dw_die_ref) xmalloc (sizeof (die_node)); + + die->die_tag = tag_value; + die->die_abbrev = 0; + die->die_offset = 0; + die->die_child = NULL; + die->die_parent = NULL; + die->die_sib = NULL; + die->die_child_last = NULL; + die->die_attr = NULL; + die->die_attr_last = NULL; + + if (parent_die != NULL) + add_child_die (parent_die, die); + else + { + limbo_die_node *limbo_node; + + limbo_node = (limbo_die_node *) xmalloc (sizeof (limbo_die_node)); + limbo_node->die = die; + limbo_node->next = limbo_die_list; + limbo_die_list = limbo_node; + } + + return die; +} + +/* Return the DIE associated with the given type specifier. */ + +static inline dw_die_ref +lookup_type_die (type) + register tree type; +{ + return (dw_die_ref) TYPE_SYMTAB_POINTER (type); +} + +/* Equate a DIE to a given type specifier. */ + +static void +equate_type_number_to_die (type, type_die) + register tree type; + register dw_die_ref type_die; +{ + TYPE_SYMTAB_POINTER (type) = (char *) type_die; +} + +/* Return the DIE associated with a given declaration. */ + +static inline dw_die_ref +lookup_decl_die (decl) + register tree decl; +{ + register unsigned decl_id = DECL_UID (decl); + + return (decl_id < decl_die_table_in_use + ? decl_die_table[decl_id] : NULL); +} + +/* Equate a DIE to a particular declaration. */ + +static void +equate_decl_number_to_die (decl, decl_die) + register tree decl; + register dw_die_ref decl_die; +{ + register unsigned decl_id = DECL_UID (decl); + register unsigned num_allocated; + + if (decl_id >= decl_die_table_allocated) + { + num_allocated + = ((decl_id + 1 + DECL_DIE_TABLE_INCREMENT - 1) + / DECL_DIE_TABLE_INCREMENT) + * DECL_DIE_TABLE_INCREMENT; + + decl_die_table + = (dw_die_ref *) xrealloc (decl_die_table, + sizeof (dw_die_ref) * num_allocated); + + bzero ((char *) &decl_die_table[decl_die_table_allocated], + (num_allocated - decl_die_table_allocated) * sizeof (dw_die_ref)); + decl_die_table_allocated = num_allocated; + } + + if (decl_id >= decl_die_table_in_use) + decl_die_table_in_use = (decl_id + 1); + + decl_die_table[decl_id] = decl_die; +} + +/* Return a pointer to a newly allocated location description. Location + descriptions are simple expression terms that can be strung + together to form more complicated location (address) descriptions. */ + +static inline dw_loc_descr_ref +new_loc_descr (op, oprnd1, oprnd2) + register enum dwarf_location_atom op; + register unsigned long oprnd1; + register unsigned long oprnd2; +{ + register dw_loc_descr_ref descr + = (dw_loc_descr_ref) xmalloc (sizeof (dw_loc_descr_node)); + + descr->dw_loc_next = NULL; + descr->dw_loc_opc = op; + descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const; + descr->dw_loc_oprnd1.v.val_unsigned = oprnd1; + descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const; + descr->dw_loc_oprnd2.v.val_unsigned = oprnd2; + + return descr; +} + +/* Add a location description term to a location description expression. */ + +static inline void +add_loc_descr (list_head, descr) + register dw_loc_descr_ref *list_head; + register dw_loc_descr_ref descr; +{ + register dw_loc_descr_ref *d; + + /* Find the end of the chain. */ + for (d = list_head; (*d) != NULL; d = &(*d)->dw_loc_next) + ; + + *d = descr; +} + +/* Keep track of the number of spaces used to indent the + output of the debugging routines that print the structure of + the DIE internal representation. */ +static int print_indent; + +/* Indent the line the number of spaces given by print_indent. */ + +static inline void +print_spaces (outfile) + FILE *outfile; +{ + fprintf (outfile, "%*s", print_indent, ""); +} + +/* Print the information associated with a given DIE, and its children. + This routine is a debugging aid only. */ + +static void +print_die (die, outfile) + dw_die_ref die; + FILE *outfile; +{ + register dw_attr_ref a; + register dw_die_ref c; + + print_spaces (outfile); + fprintf (outfile, "DIE %4lu: %s\n", + die->die_offset, dwarf_tag_name (die->die_tag)); + print_spaces (outfile); + fprintf (outfile, " abbrev id: %lu", die->die_abbrev); + fprintf (outfile, " offset: %lu\n", die->die_offset); + + for (a = die->die_attr; a != NULL; a = a->dw_attr_next) + { + print_spaces (outfile); + fprintf (outfile, " %s: ", dwarf_attr_name (a->dw_attr)); + + switch (a->dw_attr_val.val_class) + { + case dw_val_class_addr: + fprintf (outfile, "address"); + break; + case dw_val_class_loc: + fprintf (outfile, "location descriptor"); + break; + case dw_val_class_const: + fprintf (outfile, "%ld", a->dw_attr_val.v.val_int); + break; + case dw_val_class_unsigned_const: + fprintf (outfile, "%lu", a->dw_attr_val.v.val_unsigned); + break; + case dw_val_class_long_long: + fprintf (outfile, "constant (%lu,%lu)", + a->dw_attr_val.v.val_long_long.hi, + a->dw_attr_val.v.val_long_long.low); + break; + case dw_val_class_float: + fprintf (outfile, "floating-point constant"); + break; + case dw_val_class_flag: + fprintf (outfile, "%u", a->dw_attr_val.v.val_flag); + break; + case dw_val_class_die_ref: + if (a->dw_attr_val.v.val_die_ref != NULL) + fprintf (outfile, "die -> %lu", + a->dw_attr_val.v.val_die_ref->die_offset); + else + fprintf (outfile, "die -> "); + break; + case dw_val_class_lbl_id: + fprintf (outfile, "label: %s", a->dw_attr_val.v.val_lbl_id); + break; + case dw_val_class_section_offset: + fprintf (outfile, "section: %s", a->dw_attr_val.v.val_section); + break; + case dw_val_class_str: + if (a->dw_attr_val.v.val_str != NULL) + fprintf (outfile, "\"%s\"", a->dw_attr_val.v.val_str); + else + fprintf (outfile, ""); + break; + default: + break; + } + + fprintf (outfile, "\n"); + } + + if (die->die_child != NULL) + { + print_indent += 4; + for (c = die->die_child; c != NULL; c = c->die_sib) + print_die (c, outfile); + + print_indent -= 4; + } +} + +/* Print the contents of the source code line number correspondence table. + This routine is a debugging aid only. */ + +static void +print_dwarf_line_table (outfile) + FILE *outfile; +{ + register unsigned i; + register dw_line_info_ref line_info; + + fprintf (outfile, "\n\nDWARF source line information\n"); + for (i = 1; i < line_info_table_in_use; ++i) + { + line_info = &line_info_table[i]; + fprintf (outfile, "%5d: ", i); + fprintf (outfile, "%-20s", file_table[line_info->dw_file_num]); + fprintf (outfile, "%6ld", line_info->dw_line_num); + fprintf (outfile, "\n"); + } + + fprintf (outfile, "\n\n"); +} + +/* Print the information collected for a given DIE. */ + +void +debug_dwarf_die (die) + dw_die_ref die; +{ + print_die (die, stderr); +} + +/* Print all DWARF information collected for the compilation unit. + This routine is a debugging aid only. */ + +void +debug_dwarf () +{ + print_indent = 0; + print_die (comp_unit_die, stderr); + print_dwarf_line_table (stderr); +} + +/* Traverse the DIE, and add a sibling attribute if it may have the + effect of speeding up access to siblings. To save some space, + avoid generating sibling attributes for DIE's without children. */ + +static void +add_sibling_attributes(die) + register dw_die_ref die; +{ + register dw_die_ref c; + register dw_attr_ref attr; + if (die != comp_unit_die && die->die_child != NULL) + { + attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); + attr->dw_attr_next = NULL; + attr->dw_attr = DW_AT_sibling; + attr->dw_attr_val.val_class = dw_val_class_die_ref; + attr->dw_attr_val.v.val_die_ref = die->die_sib; + + /* Add the sibling link to the front of the attribute list. */ + attr->dw_attr_next = die->die_attr; + if (die->die_attr == NULL) + die->die_attr_last = attr; + + die->die_attr = attr; + } + + for (c = die->die_child; c != NULL; c = c->die_sib) + add_sibling_attributes (c); +} + +/* The format of each DIE (and its attribute value pairs) + is encoded in an abbreviation table. This routine builds the + abbreviation table and assigns a unique abbreviation id for + each abbreviation entry. The children of each die are visited + recursively. */ + +static void +build_abbrev_table (die) + register dw_die_ref die; +{ + register unsigned long abbrev_id; + register unsigned long n_alloc; + register dw_die_ref c; + register dw_attr_ref d_attr, a_attr; + for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id) + { + register dw_die_ref abbrev = abbrev_die_table[abbrev_id]; + + if (abbrev->die_tag == die->die_tag) + { + if ((abbrev->die_child != NULL) == (die->die_child != NULL)) + { + a_attr = abbrev->die_attr; + d_attr = die->die_attr; + + while (a_attr != NULL && d_attr != NULL) + { + if ((a_attr->dw_attr != d_attr->dw_attr) + || (value_format (&a_attr->dw_attr_val) + != value_format (&d_attr->dw_attr_val))) + break; + + a_attr = a_attr->dw_attr_next; + d_attr = d_attr->dw_attr_next; + } + + if (a_attr == NULL && d_attr == NULL) + break; + } + } + } + + if (abbrev_id >= abbrev_die_table_in_use) + { + if (abbrev_die_table_in_use >= abbrev_die_table_allocated) + { + n_alloc = abbrev_die_table_allocated + ABBREV_DIE_TABLE_INCREMENT; + abbrev_die_table + = (dw_die_ref *) xrealloc (abbrev_die_table, + sizeof (dw_die_ref) * n_alloc); + + bzero ((char *) &abbrev_die_table[abbrev_die_table_allocated], + (n_alloc - abbrev_die_table_allocated) * sizeof (dw_die_ref)); + abbrev_die_table_allocated = n_alloc; + } + + ++abbrev_die_table_in_use; + abbrev_die_table[abbrev_id] = die; + } + + die->die_abbrev = abbrev_id; + for (c = die->die_child; c != NULL; c = c->die_sib) + build_abbrev_table (c); +} + +/* Return the size of a string, including the null byte. + + This used to treat backslashes as escapes, and hence they were not included + in the count. However, that conflicts with what ASM_OUTPUT_ASCII does, + which treats a backslash as a backslash, escaping it if necessary, and hence + we must include them in the count. */ + +static unsigned long +size_of_string (str) + register char *str; +{ + return strlen (str) + 1; +} + +/* Return the size of a location descriptor. */ + +static unsigned long +size_of_loc_descr (loc) + register dw_loc_descr_ref loc; +{ + register unsigned long size = 1; + + switch (loc->dw_loc_opc) + { + case DW_OP_addr: + size += PTR_SIZE; + break; + case DW_OP_const1u: + case DW_OP_const1s: + size += 1; + break; + case DW_OP_const2u: + case DW_OP_const2s: + size += 2; + break; + case DW_OP_const4u: + case DW_OP_const4s: + size += 4; + break; + case DW_OP_const8u: + case DW_OP_const8s: + size += 8; + break; + case DW_OP_constu: + size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); + break; + case DW_OP_consts: + size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int); + break; + case DW_OP_pick: + size += 1; + break; + case DW_OP_plus_uconst: + size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); + break; + case DW_OP_skip: + case DW_OP_bra: + size += 2; + break; + case DW_OP_breg0: + case DW_OP_breg1: + case DW_OP_breg2: + case DW_OP_breg3: + case DW_OP_breg4: + case DW_OP_breg5: + case DW_OP_breg6: + case DW_OP_breg7: + case DW_OP_breg8: + case DW_OP_breg9: + case DW_OP_breg10: + case DW_OP_breg11: + case DW_OP_breg12: + case DW_OP_breg13: + case DW_OP_breg14: + case DW_OP_breg15: + case DW_OP_breg16: + case DW_OP_breg17: + case DW_OP_breg18: + case DW_OP_breg19: + case DW_OP_breg20: + case DW_OP_breg21: + case DW_OP_breg22: + case DW_OP_breg23: + case DW_OP_breg24: + case DW_OP_breg25: + case DW_OP_breg26: + case DW_OP_breg27: + case DW_OP_breg28: + case DW_OP_breg29: + case DW_OP_breg30: + case DW_OP_breg31: + size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int); + break; + case DW_OP_regx: + size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); + break; + case DW_OP_fbreg: + size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int); + break; + case DW_OP_bregx: + size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); + size += size_of_sleb128 (loc->dw_loc_oprnd2.v.val_int); + break; + case DW_OP_piece: + size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); + break; + case DW_OP_deref_size: + case DW_OP_xderef_size: + size += 1; + break; + default: + break; + } + + return size; +} + +/* Return the size of a series of location descriptors. */ + +static unsigned long +size_of_locs (loc) + register dw_loc_descr_ref loc; +{ + register unsigned long size = 0; + + for (; loc != NULL; loc = loc->dw_loc_next) + size += size_of_loc_descr (loc); + + return size; +} + +/* Return the power-of-two number of bytes necessary to represent VALUE. */ + +static int +constant_size (value) + long unsigned value; +{ + int log; + + if (value == 0) + log = 0; + else + log = floor_log2 (value); + + log = log / 8; + log = 1 << (floor_log2 (log) + 1); + + return log; +} + +/* Return the size of a DIE, as it is represented in the + .debug_info section. */ + +static unsigned long +size_of_die (die) + register dw_die_ref die; +{ + register unsigned long size = 0; + register dw_attr_ref a; + + size += size_of_uleb128 (die->die_abbrev); + for (a = die->die_attr; a != NULL; a = a->dw_attr_next) + { + switch (a->dw_attr_val.val_class) + { + case dw_val_class_addr: + size += PTR_SIZE; + break; + case dw_val_class_loc: + { + register unsigned long lsize + = size_of_locs (a->dw_attr_val.v.val_loc); + + /* Block length. */ + size += constant_size (lsize); + size += lsize; + } + break; + case dw_val_class_const: + size += 4; + break; + case dw_val_class_unsigned_const: + size += constant_size (a->dw_attr_val.v.val_unsigned); + break; + case dw_val_class_long_long: + size += 1 + 8; /* block */ + break; + case dw_val_class_float: + size += 1 + a->dw_attr_val.v.val_float.length * 4; /* block */ + break; + case dw_val_class_flag: + size += 1; + break; + case dw_val_class_die_ref: + size += DWARF_OFFSET_SIZE; + break; + case dw_val_class_fde_ref: + size += DWARF_OFFSET_SIZE; + break; + case dw_val_class_lbl_id: + size += PTR_SIZE; + break; + case dw_val_class_section_offset: + size += DWARF_OFFSET_SIZE; + break; + case dw_val_class_str: + size += size_of_string (a->dw_attr_val.v.val_str); + break; + default: + abort (); + } + } + + return size; +} + +/* Size the debugging information associated with a given DIE. + Visits the DIE's children recursively. Updates the global + variable next_die_offset, on each time through. Uses the + current value of next_die_offset to update the die_offset + field in each DIE. */ + +static void +calc_die_sizes (die) + dw_die_ref die; +{ + register dw_die_ref c; + die->die_offset = next_die_offset; + next_die_offset += size_of_die (die); + + for (c = die->die_child; c != NULL; c = c->die_sib) + calc_die_sizes (c); + + if (die->die_child != NULL) + /* Count the null byte used to terminate sibling lists. */ + next_die_offset += 1; +} + +/* Return the size of the line information prolog generated for the + compilation unit. */ + +static unsigned long +size_of_line_prolog () +{ + register unsigned long size; + register unsigned long ft_index; + + size = DWARF_LINE_PROLOG_HEADER_SIZE; + + /* Count the size of the table giving number of args for each + standard opcode. */ + size += DWARF_LINE_OPCODE_BASE - 1; + + /* Include directory table is empty (at present). Count only the + null byte used to terminate the table. */ + size += 1; + + for (ft_index = 1; ft_index < file_table_in_use; ++ft_index) + { + /* File name entry. */ + size += size_of_string (file_table[ft_index]); + + /* Include directory index. */ + size += size_of_uleb128 (0); + + /* Modification time. */ + size += size_of_uleb128 (0); + + /* File length in bytes. */ + size += size_of_uleb128 (0); + } + + /* Count the file table terminator. */ + size += 1; + return size; +} + +/* Return the size of the line information generated for this + compilation unit. */ + +static unsigned long +size_of_line_info () +{ + register unsigned long size; + register unsigned long lt_index; + register unsigned long current_line; + register long line_offset; + register long line_delta; + register unsigned long current_file; + register unsigned long function; + unsigned long size_of_set_address; + + /* Size of a DW_LNE_set_address instruction. */ + size_of_set_address = 1 + size_of_uleb128 (1 + PTR_SIZE) + 1 + PTR_SIZE; + + /* Version number. */ + size = 2; + + /* Prolog length specifier. */ + size += DWARF_OFFSET_SIZE; + + /* Prolog. */ + size += size_of_line_prolog (); + + /* Set address register instruction. */ + size += size_of_set_address; + + current_file = 1; + current_line = 1; + for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index) + { + register dw_line_info_ref line_info; + + /* Advance pc instruction. */ + /* ??? See the DW_LNS_advance_pc comment in output_line_info. */ + if (0) + size += 1 + 2; + else + size += size_of_set_address; + + line_info = &line_info_table[lt_index]; + if (line_info->dw_file_num != current_file) + { + /* Set file number instruction. */ + size += 1; + current_file = line_info->dw_file_num; + size += size_of_uleb128 (current_file); + } + + if (line_info->dw_line_num != current_line) + { + line_offset = line_info->dw_line_num - current_line; + line_delta = line_offset - DWARF_LINE_BASE; + current_line = line_info->dw_line_num; + if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1)) + /* 1-byte special line number instruction. */ + size += 1; + else + { + /* Advance line instruction. */ + size += 1; + size += size_of_sleb128 (line_offset); + /* Generate line entry instruction. */ + size += 1; + } + } + } + + /* Advance pc instruction. */ + if (0) + size += 1 + 2; + else + size += size_of_set_address; + + /* End of line number info. marker. */ + size += 1 + size_of_uleb128 (1) + 1; + + function = 0; + current_file = 1; + current_line = 1; + for (lt_index = 0; lt_index < separate_line_info_table_in_use; ) + { + register dw_separate_line_info_ref line_info + = &separate_line_info_table[lt_index]; + if (function != line_info->function) + { + function = line_info->function; + /* Set address register instruction. */ + size += size_of_set_address; + } + else + { + /* Advance pc instruction. */ + if (0) + size += 1 + 2; + else + size += size_of_set_address; + } + + if (line_info->dw_file_num != current_file) + { + /* Set file number instruction. */ + size += 1; + current_file = line_info->dw_file_num; + size += size_of_uleb128 (current_file); + } + + if (line_info->dw_line_num != current_line) + { + line_offset = line_info->dw_line_num - current_line; + line_delta = line_offset - DWARF_LINE_BASE; + current_line = line_info->dw_line_num; + if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1)) + /* 1-byte special line number instruction. */ + size += 1; + else + { + /* Advance line instruction. */ + size += 1; + size += size_of_sleb128 (line_offset); + + /* Generate line entry instruction. */ + size += 1; + } + } + + ++lt_index; + + /* If we're done with a function, end its sequence. */ + if (lt_index == separate_line_info_table_in_use + || separate_line_info_table[lt_index].function != function) + { + current_file = 1; + current_line = 1; + + /* Advance pc instruction. */ + if (0) + size += 1 + 2; + else + size += size_of_set_address; + + /* End of line number info. marker. */ + size += 1 + size_of_uleb128 (1) + 1; + } + } + + return size; +} + +/* Return the size of the .debug_pubnames table generated for the + compilation unit. */ + +static unsigned long +size_of_pubnames () +{ + register unsigned long size; + register unsigned i; + + size = DWARF_PUBNAMES_HEADER_SIZE; + for (i = 0; i < pubname_table_in_use; ++i) + { + register pubname_ref p = &pubname_table[i]; + size += DWARF_OFFSET_SIZE + size_of_string (p->name); + } + + size += DWARF_OFFSET_SIZE; + return size; +} + +/* Return the size of the information in the .debug_aranges section. */ + +static unsigned long +size_of_aranges () +{ + register unsigned long size; + + size = DWARF_ARANGES_HEADER_SIZE; + + /* Count the address/length pair for this compilation unit. */ + size += 2 * PTR_SIZE; + size += 2 * PTR_SIZE * arange_table_in_use; + + /* Count the two zero words used to terminated the address range table. */ + size += 2 * PTR_SIZE; + return size; +} + +/* Select the encoding of an attribute value. */ + +static enum dwarf_form +value_format (v) + dw_val_ref v; +{ + switch (v->val_class) + { + case dw_val_class_addr: + return DW_FORM_addr; + case dw_val_class_loc: + switch (constant_size (size_of_locs (v->v.val_loc))) + { + case 1: + return DW_FORM_block1; + case 2: + return DW_FORM_block2; + default: + abort (); + } + case dw_val_class_const: + return DW_FORM_data4; + case dw_val_class_unsigned_const: + switch (constant_size (v->v.val_unsigned)) + { + case 1: + return DW_FORM_data1; + case 2: + return DW_FORM_data2; + case 4: + return DW_FORM_data4; + case 8: + return DW_FORM_data8; + default: + abort (); + } + case dw_val_class_long_long: + return DW_FORM_block1; + case dw_val_class_float: + return DW_FORM_block1; + case dw_val_class_flag: + return DW_FORM_flag; + case dw_val_class_die_ref: + return DW_FORM_ref; + case dw_val_class_fde_ref: + return DW_FORM_data; + case dw_val_class_lbl_id: + return DW_FORM_addr; + case dw_val_class_section_offset: + return DW_FORM_data; + case dw_val_class_str: + return DW_FORM_string; + default: + abort (); + } +} + +/* Output the encoding of an attribute value. */ + +static void +output_value_format (v) + dw_val_ref v; +{ + enum dwarf_form form = value_format (v); + + output_uleb128 (form); + if (flag_debug_asm) + fprintf (asm_out_file, " (%s)", dwarf_form_name (form)); + + fputc ('\n', asm_out_file); +} + +/* Output the .debug_abbrev section which defines the DIE abbreviation + table. */ + +static void +output_abbrev_section () +{ + unsigned long abbrev_id; + + dw_attr_ref a_attr; + for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id) + { + register dw_die_ref abbrev = abbrev_die_table[abbrev_id]; + + output_uleb128 (abbrev_id); + if (flag_debug_asm) + fprintf (asm_out_file, " (abbrev code)"); + + fputc ('\n', asm_out_file); + output_uleb128 (abbrev->die_tag); + if (flag_debug_asm) + fprintf (asm_out_file, " (TAG: %s)", + dwarf_tag_name (abbrev->die_tag)); + + fputc ('\n', asm_out_file); + fprintf (asm_out_file, "\t%s\t0x%x", ASM_BYTE_OP, + abbrev->die_child != NULL ? DW_children_yes : DW_children_no); + + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s %s", + ASM_COMMENT_START, + (abbrev->die_child != NULL + ? "DW_children_yes" : "DW_children_no")); + + fputc ('\n', asm_out_file); + + for (a_attr = abbrev->die_attr; a_attr != NULL; + a_attr = a_attr->dw_attr_next) + { + output_uleb128 (a_attr->dw_attr); + if (flag_debug_asm) + fprintf (asm_out_file, " (%s)", + dwarf_attr_name (a_attr->dw_attr)); + + fputc ('\n', asm_out_file); + output_value_format (&a_attr->dw_attr_val); + } + + fprintf (asm_out_file, "\t%s\t0,0\n", ASM_BYTE_OP); + } +} + +/* Output location description stack opcode's operands (if any). */ + +static void +output_loc_operands (loc) + register dw_loc_descr_ref loc; +{ + register dw_val_ref val1 = &loc->dw_loc_oprnd1; + register dw_val_ref val2 = &loc->dw_loc_oprnd2; + + switch (loc->dw_loc_opc) + { + case DW_OP_addr: + ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file, val1->v.val_addr); + fputc ('\n', asm_out_file); + break; + case DW_OP_const1u: + case DW_OP_const1s: + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_flag); + fputc ('\n', asm_out_file); + break; + case DW_OP_const2u: + case DW_OP_const2s: + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, val1->v.val_int); + fputc ('\n', asm_out_file); + break; + case DW_OP_const4u: + case DW_OP_const4s: + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, val1->v.val_int); + fputc ('\n', asm_out_file); + break; + case DW_OP_const8u: + case DW_OP_const8s: + abort (); + fputc ('\n', asm_out_file); + break; + case DW_OP_constu: + output_uleb128 (val1->v.val_unsigned); + fputc ('\n', asm_out_file); + break; + case DW_OP_consts: + output_sleb128 (val1->v.val_int); + fputc ('\n', asm_out_file); + break; + case DW_OP_pick: + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_int); + fputc ('\n', asm_out_file); + break; + case DW_OP_plus_uconst: + output_uleb128 (val1->v.val_unsigned); + fputc ('\n', asm_out_file); + break; + case DW_OP_skip: + case DW_OP_bra: + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, val1->v.val_int); + fputc ('\n', asm_out_file); + break; + case DW_OP_breg0: + case DW_OP_breg1: + case DW_OP_breg2: + case DW_OP_breg3: + case DW_OP_breg4: + case DW_OP_breg5: + case DW_OP_breg6: + case DW_OP_breg7: + case DW_OP_breg8: + case DW_OP_breg9: + case DW_OP_breg10: + case DW_OP_breg11: + case DW_OP_breg12: + case DW_OP_breg13: + case DW_OP_breg14: + case DW_OP_breg15: + case DW_OP_breg16: + case DW_OP_breg17: + case DW_OP_breg18: + case DW_OP_breg19: + case DW_OP_breg20: + case DW_OP_breg21: + case DW_OP_breg22: + case DW_OP_breg23: + case DW_OP_breg24: + case DW_OP_breg25: + case DW_OP_breg26: + case DW_OP_breg27: + case DW_OP_breg28: + case DW_OP_breg29: + case DW_OP_breg30: + case DW_OP_breg31: + output_sleb128 (val1->v.val_int); + fputc ('\n', asm_out_file); + break; + case DW_OP_regx: + output_uleb128 (val1->v.val_unsigned); + fputc ('\n', asm_out_file); + break; + case DW_OP_fbreg: + output_sleb128 (val1->v.val_int); + fputc ('\n', asm_out_file); + break; + case DW_OP_bregx: + output_uleb128 (val1->v.val_unsigned); + fputc ('\n', asm_out_file); + output_sleb128 (val2->v.val_int); + fputc ('\n', asm_out_file); + break; + case DW_OP_piece: + output_uleb128 (val1->v.val_unsigned); + fputc ('\n', asm_out_file); + break; + case DW_OP_deref_size: + case DW_OP_xderef_size: + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_flag); + fputc ('\n', asm_out_file); + break; + default: + break; + } +} + +/* Compute the offset of a sibling. */ + +static unsigned long +sibling_offset (die) + dw_die_ref die; +{ + unsigned long offset; + + if (die->die_child_last == NULL) + offset = die->die_offset + size_of_die (die); + else + offset = sibling_offset (die->die_child_last) + 1; + + return offset; +} + +/* Output the DIE and its attributes. Called recursively to generate + the definitions of each child DIE. */ + +static void +output_die (die) + register dw_die_ref die; +{ + register dw_attr_ref a; + register dw_die_ref c; + register unsigned long ref_offset; + register unsigned long size; + register dw_loc_descr_ref loc; + + output_uleb128 (die->die_abbrev); + if (flag_debug_asm) + fprintf (asm_out_file, " (DIE (0x%lx) %s)", + die->die_offset, dwarf_tag_name (die->die_tag)); + + fputc ('\n', asm_out_file); + + for (a = die->die_attr; a != NULL; a = a->dw_attr_next) + { + switch (a->dw_attr_val.val_class) + { + case dw_val_class_addr: + ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file, + a->dw_attr_val.v.val_addr); + break; + + case dw_val_class_loc: + size = size_of_locs (a->dw_attr_val.v.val_loc); + + /* Output the block length for this list of location operations. */ + switch (constant_size (size)) + { + case 1: + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, size); + break; + case 2: + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, size); + break; + default: + abort (); + } + + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s %s", + ASM_COMMENT_START, dwarf_attr_name (a->dw_attr)); + + fputc ('\n', asm_out_file); + for (loc = a->dw_attr_val.v.val_loc; loc != NULL; + loc = loc->dw_loc_next) + { + /* Output the opcode. */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, loc->dw_loc_opc); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START, + dwarf_stack_op_name (loc->dw_loc_opc)); + + fputc ('\n', asm_out_file); + + /* Output the operand(s) (if any). */ + output_loc_operands (loc); + } + break; + + case dw_val_class_const: + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, a->dw_attr_val.v.val_int); + break; + + case dw_val_class_unsigned_const: + switch (constant_size (a->dw_attr_val.v.val_unsigned)) + { + case 1: + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, + a->dw_attr_val.v.val_unsigned); + break; + case 2: + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, + a->dw_attr_val.v.val_unsigned); + break; + case 4: + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, + a->dw_attr_val.v.val_unsigned); + break; + case 8: + ASM_OUTPUT_DWARF_DATA8 (asm_out_file, + a->dw_attr_val.v.val_long_long.hi, + a->dw_attr_val.v.val_long_long.low); + break; + default: + abort (); + } + break; + + case dw_val_class_long_long: + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 8); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s %s", + ASM_COMMENT_START, dwarf_attr_name (a->dw_attr)); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA8 (asm_out_file, + a->dw_attr_val.v.val_long_long.hi, + a->dw_attr_val.v.val_long_long.low); + + if (flag_debug_asm) + fprintf (asm_out_file, + "\t%s long long constant", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + break; + + case dw_val_class_float: + { + register unsigned int i; + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, + a->dw_attr_val.v.val_float.length * 4); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s %s", + ASM_COMMENT_START, dwarf_attr_name (a->dw_attr)); + + fputc ('\n', asm_out_file); + for (i = 0; i < a->dw_attr_val.v.val_float.length; ++i) + { + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, + a->dw_attr_val.v.val_float.array[i]); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s fp constant word %u", + ASM_COMMENT_START, i); + + fputc ('\n', asm_out_file); + } + break; + } + + case dw_val_class_flag: + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, a->dw_attr_val.v.val_flag); + break; + + case dw_val_class_die_ref: + if (a->dw_attr_val.v.val_die_ref != NULL) + ref_offset = a->dw_attr_val.v.val_die_ref->die_offset; + else if (a->dw_attr == DW_AT_sibling) + ref_offset = sibling_offset(die); + else + abort (); + + ASM_OUTPUT_DWARF_DATA (asm_out_file, ref_offset); + break; + + case dw_val_class_fde_ref: + { + char l1[20]; + ASM_GENERATE_INTERNAL_LABEL + (l1, FDE_AFTER_SIZE_LABEL, a->dw_attr_val.v.val_fde_index * 2); + ASM_OUTPUT_DWARF_OFFSET (asm_out_file, l1); + fprintf (asm_out_file, " - %d", DWARF_OFFSET_SIZE); + } + break; + + case dw_val_class_lbl_id: + ASM_OUTPUT_DWARF_ADDR (asm_out_file, a->dw_attr_val.v.val_lbl_id); + break; + + case dw_val_class_section_offset: + ASM_OUTPUT_DWARF_OFFSET (asm_out_file, + stripattributes + (a->dw_attr_val.v.val_section)); + break; + + case dw_val_class_str: + if (flag_debug_asm) + ASM_OUTPUT_DWARF_STRING (asm_out_file, a->dw_attr_val.v.val_str); + else + ASM_OUTPUT_ASCII (asm_out_file, + a->dw_attr_val.v.val_str, + (int) strlen (a->dw_attr_val.v.val_str) + 1); + break; + + default: + abort (); + } + + if (a->dw_attr_val.val_class != dw_val_class_loc + && a->dw_attr_val.val_class != dw_val_class_long_long + && a->dw_attr_val.val_class != dw_val_class_float) + { + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s %s", + ASM_COMMENT_START, dwarf_attr_name (a->dw_attr)); + + fputc ('\n', asm_out_file); + } + } + + for (c = die->die_child; c != NULL; c = c->die_sib) + output_die (c); + + if (die->die_child != NULL) + { + /* Add null byte to terminate sibling list. */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s end of children of DIE 0x%lx", + ASM_COMMENT_START, die->die_offset); + + fputc ('\n', asm_out_file); + } +} + +/* Output the compilation unit that appears at the beginning of the + .debug_info section, and precedes the DIE descriptions. */ + +static void +output_compilation_unit_header () +{ + ASM_OUTPUT_DWARF_DATA (asm_out_file, next_die_offset - DWARF_OFFSET_SIZE); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Length of Compilation Unit Info.", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DWARF version number", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (ABBREV_SECTION)); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Offset Into Abbrev. Section", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, PTR_SIZE); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Pointer Size (in bytes)", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); +} + +/* The DWARF2 pubname for a nested thingy looks like "A::f". The output + of decl_printable_name for C++ looks like "A::f(int)". Let's drop the + argument list, and maybe the scope. */ + +static char * +dwarf2_name (decl, scope) + tree decl; + int scope; +{ + return (*decl_printable_name) (decl, scope ? 1 : 0); +} + +/* Add a new entry to .debug_pubnames if appropriate. */ + +static void +add_pubname (decl, die) + tree decl; + dw_die_ref die; +{ + pubname_ref p; + + if (! TREE_PUBLIC (decl)) + return; + + if (pubname_table_in_use == pubname_table_allocated) + { + pubname_table_allocated += PUBNAME_TABLE_INCREMENT; + pubname_table = (pubname_ref) xrealloc + (pubname_table, pubname_table_allocated * sizeof (pubname_entry)); + } + + p = &pubname_table[pubname_table_in_use++]; + p->die = die; + + p->name = xstrdup (dwarf2_name (decl, 1)); +} + +/* Output the public names table used to speed up access to externally + visible names. For now, only generate entries for externally + visible procedures. */ + +static void +output_pubnames () +{ + register unsigned i; + register unsigned long pubnames_length = size_of_pubnames (); + + ASM_OUTPUT_DWARF_DATA (asm_out_file, pubnames_length); + + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Length of Public Names Info.", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION); + + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (DEBUG_INFO_SECTION)); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Offset of Compilation Unit Info.", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA (asm_out_file, next_die_offset); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Compilation Unit Length", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + for (i = 0; i < pubname_table_in_use; ++i) + { + register pubname_ref pub = &pubname_table[i]; + + ASM_OUTPUT_DWARF_DATA (asm_out_file, pub->die->die_offset); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DIE offset", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + + if (flag_debug_asm) + { + ASM_OUTPUT_DWARF_STRING (asm_out_file, pub->name); + fprintf (asm_out_file, "%s external name", ASM_COMMENT_START); + } + else + { + ASM_OUTPUT_ASCII (asm_out_file, pub->name, + (int) strlen (pub->name) + 1); + } + + fputc ('\n', asm_out_file); + } + + ASM_OUTPUT_DWARF_DATA (asm_out_file, 0); + fputc ('\n', asm_out_file); +} + +/* Add a new entry to .debug_aranges if appropriate. */ + +static void +add_arange (decl, die) + tree decl; + dw_die_ref die; +{ + if (! DECL_SECTION_NAME (decl)) + return; + + if (arange_table_in_use == arange_table_allocated) + { + arange_table_allocated += ARANGE_TABLE_INCREMENT; + arange_table + = (arange_ref) xrealloc (arange_table, + arange_table_allocated * sizeof (dw_die_ref)); + } + + arange_table[arange_table_in_use++] = die; +} + +/* Output the information that goes into the .debug_aranges table. + Namely, define the beginning and ending address range of the + text section generated for this compilation unit. */ + +static void +output_aranges () +{ + register unsigned i; + register unsigned long aranges_length = size_of_aranges (); + + ASM_OUTPUT_DWARF_DATA (asm_out_file, aranges_length); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Length of Address Ranges Info.", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (DEBUG_INFO_SECTION)); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Offset of Compilation Unit Info.", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, PTR_SIZE); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Size of Address", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Size of Segment Descriptor", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 4); + if (PTR_SIZE == 8) + fprintf (asm_out_file, ",0,0"); + + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Pad to %d byte boundary", + ASM_COMMENT_START, 2 * PTR_SIZE); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, stripattributes (TEXT_SECTION)); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Address", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, text_end_label, + stripattributes (TEXT_SECTION)); + if (flag_debug_asm) + fprintf (asm_out_file, "%s Length", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + for (i = 0; i < arange_table_in_use; ++i) + { + dw_die_ref a = arange_table[i]; + + if (a->die_tag == DW_TAG_subprogram) + ASM_OUTPUT_DWARF_ADDR (asm_out_file, get_AT_low_pc (a)); + else + { + char *name = get_AT_string (a, DW_AT_MIPS_linkage_name); + if (! name) + name = get_AT_string (a, DW_AT_name); + + ASM_OUTPUT_DWARF_ADDR (asm_out_file, name); + } + + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Address", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + if (a->die_tag == DW_TAG_subprogram) + ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, get_AT_hi_pc (a), + get_AT_low_pc (a)); + else + ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, + get_AT_unsigned (a, DW_AT_byte_size)); + + if (flag_debug_asm) + fprintf (asm_out_file, "%s Length", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + } + + /* Output the terminator words. */ + ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, 0); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, 0); + fputc ('\n', asm_out_file); +} + +/* Output the source line number correspondence information. This + information goes into the .debug_line section. + + If the format of this data changes, then the function size_of_line_info + must also be adjusted the same way. */ + +static void +output_line_info () +{ + char line_label[MAX_ARTIFICIAL_LABEL_BYTES]; + char prev_line_label[MAX_ARTIFICIAL_LABEL_BYTES]; + register unsigned opc; + register unsigned n_op_args; + register unsigned long ft_index; + register unsigned long lt_index; + register unsigned long current_line; + register long line_offset; + register long line_delta; + register unsigned long current_file; + register unsigned long function; + + ASM_OUTPUT_DWARF_DATA (asm_out_file, size_of_line_info ()); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Length of Source Line Info.", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA (asm_out_file, size_of_line_prolog ()); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Prolog Length", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_LINE_MIN_INSTR_LENGTH); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Minimum Instruction Length", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_LINE_DEFAULT_IS_STMT_START); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Default is_stmt_start flag", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + fprintf (asm_out_file, "\t%s\t%d", ASM_BYTE_OP, DWARF_LINE_BASE); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Line Base Value (Special Opcodes)", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + fprintf (asm_out_file, "\t%s\t%u", ASM_BYTE_OP, DWARF_LINE_RANGE); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Line Range Value (Special Opcodes)", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + fprintf (asm_out_file, "\t%s\t%u", ASM_BYTE_OP, DWARF_LINE_OPCODE_BASE); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s Special Opcode Base", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + for (opc = 1; opc < DWARF_LINE_OPCODE_BASE; ++opc) + { + switch (opc) + { + case DW_LNS_advance_pc: + case DW_LNS_advance_line: + case DW_LNS_set_file: + case DW_LNS_set_column: + case DW_LNS_fixed_advance_pc: + n_op_args = 1; + break; + default: + n_op_args = 0; + break; + } + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, n_op_args); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s opcode: 0x%x has %d args", + ASM_COMMENT_START, opc, n_op_args); + fputc ('\n', asm_out_file); + } + + if (flag_debug_asm) + fprintf (asm_out_file, "%s Include Directory Table\n", ASM_COMMENT_START); + + /* Include directory table is empty, at present */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + fputc ('\n', asm_out_file); + if (flag_debug_asm) + fprintf (asm_out_file, "%s File Name Table\n", ASM_COMMENT_START); + + for (ft_index = 1; ft_index < file_table_in_use; ++ft_index) + { + if (flag_debug_asm) + { + ASM_OUTPUT_DWARF_STRING (asm_out_file, file_table[ft_index]); + fprintf (asm_out_file, "%s File Entry: 0x%lx", + ASM_COMMENT_START, ft_index); + } + else + { + ASM_OUTPUT_ASCII (asm_out_file, + file_table[ft_index], + (int) strlen (file_table[ft_index]) + 1); + } + + fputc ('\n', asm_out_file); + + /* Include directory index */ + output_uleb128 (0); + fputc ('\n', asm_out_file); + + /* Modification time */ + output_uleb128 (0); + fputc ('\n', asm_out_file); + + /* File length in bytes */ + output_uleb128 (0); + fputc ('\n', asm_out_file); + } + + /* Terminate the file name table */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + fputc ('\n', asm_out_file); + + /* Set the address register to the first location in the text section */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNE_set_address", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + output_uleb128 (1 + PTR_SIZE); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, stripattributes (TEXT_SECTION)); + fputc ('\n', asm_out_file); + + /* Generate the line number to PC correspondence table, encoded as + a series of state machine operations. */ + current_file = 1; + current_line = 1; + strcpy (prev_line_label, stripattributes (TEXT_SECTION)); + for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index) + { + register dw_line_info_ref line_info; + + /* Emit debug info for the address of the current line, choosing + the encoding that uses the least amount of space. */ + /* ??? Unfortunately, we have little choice here currently, and must + always use the most general form. Gcc does not know the address + delta itself, so we can't use DW_LNS_advance_pc. There are no known + dwarf2 aware assemblers at this time, so we can't use any special + pseudo ops that would allow the assembler to optimally encode this for + us. Many ports do have length attributes which will give an upper + bound on the address range. We could perhaps use length attributes + to determine when it is safe to use DW_LNS_fixed_advance_pc. */ + ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, lt_index); + if (0) + { + /* This can handle deltas up to 0xffff. This takes 3 bytes. */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label, prev_line_label); + fputc ('\n', asm_out_file); + } + else + { + /* This can handle any delta. This takes 4+PTR_SIZE bytes. */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNE_set_address", + ASM_COMMENT_START); + fputc ('\n', asm_out_file); + output_uleb128 (1 + PTR_SIZE); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label); + fputc ('\n', asm_out_file); + } + strcpy (prev_line_label, line_label); + + /* Emit debug info for the source file of the current line, if + different from the previous line. */ + line_info = &line_info_table[lt_index]; + if (line_info->dw_file_num != current_file) + { + current_file = line_info->dw_file_num; + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_set_file); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNS_set_file", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + output_uleb128 (current_file); + if (flag_debug_asm) + fprintf (asm_out_file, " (\"%s\")", file_table[current_file]); + + fputc ('\n', asm_out_file); + } + + /* Emit debug info for the current line number, choosing the encoding + that uses the least amount of space. */ + line_offset = line_info->dw_line_num - current_line; + line_delta = line_offset - DWARF_LINE_BASE; + current_line = line_info->dw_line_num; + if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1)) + { + /* This can handle deltas from -10 to 234, using the current + definitions of DWARF_LINE_BASE and DWARF_LINE_RANGE. This + takes 1 byte. */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, + DWARF_LINE_OPCODE_BASE + line_delta); + if (flag_debug_asm) + fprintf (asm_out_file, + "\t%s line %ld", ASM_COMMENT_START, current_line); + + fputc ('\n', asm_out_file); + } + else + { + /* This can handle any delta. This takes at least 4 bytes, depending + on the value being encoded. */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_advance_line); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s advance to line %ld", + ASM_COMMENT_START, current_line); + + fputc ('\n', asm_out_file); + output_sleb128 (line_offset); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy); + fputc ('\n', asm_out_file); + } + } + + /* Emit debug info for the address of the end of the function. */ + if (0) + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, text_end_label, prev_line_label); + fputc ('\n', asm_out_file); + } + else + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNE_set_address", ASM_COMMENT_START); + fputc ('\n', asm_out_file); + output_uleb128 (1 + PTR_SIZE); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, text_end_label); + fputc ('\n', asm_out_file); + } + + /* Output the marker for the end of the line number info. */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNE_end_sequence", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + output_uleb128 (1); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_end_sequence); + fputc ('\n', asm_out_file); + + function = 0; + current_file = 1; + current_line = 1; + for (lt_index = 0; lt_index < separate_line_info_table_in_use; ) + { + register dw_separate_line_info_ref line_info + = &separate_line_info_table[lt_index]; + + /* Emit debug info for the address of the current line. If this is + a new function, or the first line of a function, then we need + to handle it differently. */ + ASM_GENERATE_INTERNAL_LABEL (line_label, SEPARATE_LINE_CODE_LABEL, + lt_index); + if (function != line_info->function) + { + function = line_info->function; + + /* Set the address register to the first line in the function */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNE_set_address", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + output_uleb128 (1 + PTR_SIZE); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label); + fputc ('\n', asm_out_file); + } + else + { + /* ??? See the DW_LNS_advance_pc comment above. */ + if (0) + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label, + prev_line_label); + fputc ('\n', asm_out_file); + } + else + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNE_set_address", + ASM_COMMENT_START); + fputc ('\n', asm_out_file); + output_uleb128 (1 + PTR_SIZE); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label); + fputc ('\n', asm_out_file); + } + } + strcpy (prev_line_label, line_label); + + /* Emit debug info for the source file of the current line, if + different from the previous line. */ + if (line_info->dw_file_num != current_file) + { + current_file = line_info->dw_file_num; + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_set_file); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNS_set_file", ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + output_uleb128 (current_file); + if (flag_debug_asm) + fprintf (asm_out_file, " (\"%s\")", file_table[current_file]); + + fputc ('\n', asm_out_file); + } + + /* Emit debug info for the current line number, choosing the encoding + that uses the least amount of space. */ + if (line_info->dw_line_num != current_line) + { + line_offset = line_info->dw_line_num - current_line; + line_delta = line_offset - DWARF_LINE_BASE; + current_line = line_info->dw_line_num; + if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1)) + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, + DWARF_LINE_OPCODE_BASE + line_delta); + if (flag_debug_asm) + fprintf (asm_out_file, + "\t%s line %ld", ASM_COMMENT_START, current_line); + + fputc ('\n', asm_out_file); + } + else + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_advance_line); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s advance to line %ld", + ASM_COMMENT_START, current_line); + + fputc ('\n', asm_out_file); + output_sleb128 (line_offset); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy); + fputc ('\n', asm_out_file); + } + } + + ++lt_index; + + /* If we're done with a function, end its sequence. */ + if (lt_index == separate_line_info_table_in_use + || separate_line_info_table[lt_index].function != function) + { + current_file = 1; + current_line = 1; + + /* Emit debug info for the address of the end of the function. */ + ASM_GENERATE_INTERNAL_LABEL (line_label, FUNC_END_LABEL, function); + if (0) + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label, + prev_line_label); + fputc ('\n', asm_out_file); + } + else + { + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNE_set_address", + ASM_COMMENT_START); + fputc ('\n', asm_out_file); + output_uleb128 (1 + PTR_SIZE); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label); + fputc ('\n', asm_out_file); + } + + /* Output the marker for the end of this sequence. */ + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s DW_LNE_end_sequence", + ASM_COMMENT_START); + + fputc ('\n', asm_out_file); + output_uleb128 (1); + fputc ('\n', asm_out_file); + ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_end_sequence); + fputc ('\n', asm_out_file); + } + } +} + +/* Given a pointer to a BLOCK node return non-zero if (and only if) the node + in question represents the outermost pair of curly braces (i.e. the "body + block") of a function or method. + + For any BLOCK node representing a "body block" of a function or method, the + BLOCK_SUPERCONTEXT of the node will point to another BLOCK node which + represents the outermost (function) scope for the function or method (i.e. + the one which includes the formal parameters). The BLOCK_SUPERCONTEXT of + *that* node in turn will point to the relevant FUNCTION_DECL node. */ + +static inline int +is_body_block (stmt) + register tree stmt; +{ + if (TREE_CODE (stmt) == BLOCK) + { + register tree parent = BLOCK_SUPERCONTEXT (stmt); + + if (TREE_CODE (parent) == BLOCK) + { + register tree grandparent = BLOCK_SUPERCONTEXT (parent); + + if (TREE_CODE (grandparent) == FUNCTION_DECL) + return 1; + } + } + + return 0; +} + +/* Given a pointer to a tree node for some base type, return a pointer to + a DIE that describes the given type. + + This routine must only be called for GCC type nodes that correspond to + Dwarf base (fundamental) types. */ + +static dw_die_ref +base_type_die (type) + register tree type; +{ + register dw_die_ref base_type_result; + register char *type_name; + register enum dwarf_type encoding; + register tree name = TYPE_NAME (type); + + if (TREE_CODE (type) == ERROR_MARK + || TREE_CODE (type) == VOID_TYPE) + return 0; + + if (TREE_CODE (name) == TYPE_DECL) + name = DECL_NAME (name); + type_name = IDENTIFIER_POINTER (name); + + switch (TREE_CODE (type)) + { + case INTEGER_TYPE: + /* Carefully distinguish the C character types, 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_PRECISION (type) == CHAR_TYPE_SIZE + && (type == char_type_node + || ! strcmp (type_name, "signed char") + || ! strcmp (type_name, "unsigned char")))) + { + if (TREE_UNSIGNED (type)) + encoding = DW_ATE_unsigned; + else + encoding = DW_ATE_signed; + break; + } + /* else fall through */ + + case CHAR_TYPE: + /* GNU Pascal/Ada CHAR type. Not used in C. */ + if (TREE_UNSIGNED (type)) + encoding = DW_ATE_unsigned_char; + else + encoding = DW_ATE_signed_char; + break; + + case REAL_TYPE: + encoding = DW_ATE_float; + break; + + case COMPLEX_TYPE: + encoding = DW_ATE_complex_float; + break; + + case BOOLEAN_TYPE: + /* GNU FORTRAN/Ada/C++ BOOLEAN type. */ + encoding = DW_ATE_boolean; + break; + + default: + abort (); /* No other TREE_CODEs are Dwarf fundamental types. */ + } + + base_type_result = new_die (DW_TAG_base_type, comp_unit_die); + add_AT_string (base_type_result, DW_AT_name, type_name); + add_AT_unsigned (base_type_result, DW_AT_byte_size, + int_size_in_bytes (type)); + add_AT_unsigned (base_type_result, DW_AT_encoding, encoding); + + return base_type_result; +} + +/* 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 (type) + register tree type; +{ + if (TREE_CODE (type) == ERROR_MARK) + return error_mark_node; + + switch (TREE_CODE (type)) + { + case ERROR_MARK: + return error_mark_node; + + case POINTER_TYPE: + case REFERENCE_TYPE: + return type_main_variant (root_type (TREE_TYPE (type))); + + default: + return type_main_variant (type); + } +} + +/* Given a pointer to an arbitrary ..._TYPE tree node, return non-zero if the + given input type is a Dwarf "fundamental" type. Otherwise return null. */ + +static inline int +is_base_type (type) + register 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: + return 0; + + default: + abort (); + } + + return 0; +} + +/* Given a pointer to an arbitrary ..._TYPE tree node, return a debugging + entry that chains various modifiers in front of the given type. */ + +static dw_die_ref +modified_type_die (type, is_const_type, is_volatile_type, context_die) + register tree type; + register int is_const_type; + register int is_volatile_type; + register dw_die_ref context_die; +{ + register enum tree_code code = TREE_CODE (type); + register dw_die_ref mod_type_die = NULL; + register dw_die_ref sub_die = NULL; + register tree item_type = NULL; + + if (code != ERROR_MARK) + { + type = build_type_variant (type, is_const_type, is_volatile_type); + + mod_type_die = lookup_type_die (type); + if (mod_type_die) + return mod_type_die; + + /* Handle C typedef types. */ + if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && DECL_ORIGINAL_TYPE (TYPE_NAME (type))) + { + tree dtype = TREE_TYPE (TYPE_NAME (type)); + if (type == dtype) + { + /* For a named type, use the typedef. */ + gen_type_die (type, context_die); + mod_type_die = lookup_type_die (type); + } + + else if (is_const_type < TYPE_READONLY (dtype) + || is_volatile_type < TYPE_VOLATILE (dtype)) + /* cv-unqualified version of named type. Just use the unnamed + type to which it refers. */ + mod_type_die + = modified_type_die (DECL_ORIGINAL_TYPE (TYPE_NAME (type)), + is_const_type, is_volatile_type, + context_die); + /* Else cv-qualified version of named type; fall through. */ + } + + if (mod_type_die) + /* OK */; + else if (is_const_type) + { + mod_type_die = new_die (DW_TAG_const_type, comp_unit_die); + sub_die = modified_type_die (type, 0, is_volatile_type, context_die); + } + else if (is_volatile_type) + { + mod_type_die = new_die (DW_TAG_volatile_type, comp_unit_die); + sub_die = modified_type_die (type, 0, 0, context_die); + } + else if (code == POINTER_TYPE) + { + mod_type_die = new_die (DW_TAG_pointer_type, comp_unit_die); + add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE); +#if 0 + add_AT_unsigned (mod_type_die, DW_AT_address_class, 0); +#endif + item_type = TREE_TYPE (type); + } + else if (code == REFERENCE_TYPE) + { + mod_type_die = new_die (DW_TAG_reference_type, comp_unit_die); + add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE); +#if 0 + add_AT_unsigned (mod_type_die, DW_AT_address_class, 0); +#endif + item_type = TREE_TYPE (type); + } + else if (is_base_type (type)) + mod_type_die = base_type_die (type); + else + { + gen_type_die (type, context_die); + + /* We have to get the type_main_variant here (and pass that to the + `lookup_type_die' 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. */ + mod_type_die = lookup_type_die (type_main_variant (type)); + if (mod_type_die == NULL) + abort (); + } + } + + equate_type_number_to_die (type, mod_type_die); + if (item_type) + /* We must do this after the equate_type_number_to_die call, in case + this is a recursive type. This ensures that the modified_type_die + recursion will terminate even if the type is recursive. Recursive + types are possible in Ada. */ + sub_die = modified_type_die (item_type, + TYPE_READONLY (item_type), + TYPE_VOLATILE (item_type), + context_die); + + if (sub_die != NULL) + add_AT_die_ref (mod_type_die, DW_AT_type, sub_die); + + return mod_type_die; +} + +/* Given a pointer to an arbitrary ..._TYPE tree node, return true if it is + an enumerated type. */ + +static inline int +type_is_enum (type) + register tree type; +{ + return TREE_CODE (type) == ENUMERAL_TYPE; +} + +/* Return a location descriptor that designates a machine register. */ + +static dw_loc_descr_ref +reg_loc_descriptor (rtl) + register rtx rtl; +{ + register dw_loc_descr_ref loc_result = NULL; + register unsigned reg = reg_number (rtl); + + if (reg <= 31) + loc_result = new_loc_descr (DW_OP_reg0 + reg, 0, 0); + else + loc_result = new_loc_descr (DW_OP_regx, reg, 0); + + return loc_result; +} + +/* Return a location descriptor that designates a base+offset location. */ + +static dw_loc_descr_ref +based_loc_descr (reg, offset) + unsigned reg; + long int offset; +{ + register dw_loc_descr_ref loc_result; + /* For the "frame base", we use the frame pointer or stack pointer + registers, since the RTL for local variables is relative to one of + them. */ + register unsigned fp_reg = DBX_REGISTER_NUMBER (frame_pointer_needed + ? HARD_FRAME_POINTER_REGNUM + : STACK_POINTER_REGNUM); + + if (reg == fp_reg) + loc_result = new_loc_descr (DW_OP_fbreg, offset, 0); + else if (reg <= 31) + loc_result = new_loc_descr (DW_OP_breg0 + reg, offset, 0); + else + loc_result = new_loc_descr (DW_OP_bregx, reg, offset); + + return loc_result; +} + +/* Return true if this RTL expression describes a base+offset calculation. */ + +static inline int +is_based_loc (rtl) + register rtx rtl; +{ + return (GET_CODE (rtl) == PLUS + && ((GET_CODE (XEXP (rtl, 0)) == REG + && GET_CODE (XEXP (rtl, 1)) == CONST_INT))); +} + +/* The following routine 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 transforming + the RTL for a memory-resident object into its Dwarf postfix expression + equivalent. This routine recursively descends an RTL tree, turning + it into Dwarf postfix code as it goes. */ + +static dw_loc_descr_ref +mem_loc_descriptor (rtl) + register rtx rtl; +{ + dw_loc_descr_ref mem_loc_result = NULL; + /* 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. */ + + 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 = XEXP (rtl, 0); + + /* ... fall through ... */ + + 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 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. */ + mem_loc_result = based_loc_descr (reg_number (rtl), 0); + break; + + case MEM: + mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0)); + add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0)); + break; + + case CONST: + case LABEL_REF: + case SYMBOL_REF: + mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0); + mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr; + mem_loc_result->dw_loc_oprnd1.v.val_addr = save_rtx (rtl); + break; + + case PLUS: + if (is_based_loc (rtl)) + mem_loc_result = based_loc_descr (reg_number (XEXP (rtl, 0)), + INTVAL (XEXP (rtl, 1))); + else + { + add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 0))); + add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 1))); + add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_plus, 0, 0)); + } + break; + + case MULT: + /* If a pseudo-reg is optimized away, it is possible for it to + be replaced with a MEM containing a multiply. */ + add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 0))); + add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 1))); + add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0)); + break; + + case CONST_INT: + mem_loc_result = new_loc_descr (DW_OP_constu, INTVAL (rtl), 0); + break; + + default: + abort (); + } + + return mem_loc_result; +} + +/* Return a descriptor that describes the concatenation of two locations. + This is typically a complex variable. */ + +static dw_loc_descr_ref +concat_loc_descriptor (x0, x1) + register rtx x0, x1; +{ + dw_loc_descr_ref cc_loc_result = NULL; + + if (!is_pseudo_reg (x0) + && (GET_CODE (x0) != MEM || !is_pseudo_reg (XEXP (x0, 0)))) + add_loc_descr (&cc_loc_result, loc_descriptor (x0)); + add_loc_descr (&cc_loc_result, + new_loc_descr (DW_OP_piece, GET_MODE_SIZE (GET_MODE (x0)), 0)); + + if (!is_pseudo_reg (x1) + && (GET_CODE (x1) != MEM || !is_pseudo_reg (XEXP (x1, 0)))) + add_loc_descr (&cc_loc_result, loc_descriptor (x1)); + add_loc_descr (&cc_loc_result, + new_loc_descr (DW_OP_piece, GET_MODE_SIZE (GET_MODE (x1)), 0)); + + return cc_loc_result; +} + +/* 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 dw_loc_descr_ref +loc_descriptor (rtl) + register rtx rtl; +{ + dw_loc_descr_ref loc_result = NULL; + 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 = XEXP (rtl, 0); + + /* ... fall through ... */ + + case REG: + loc_result = reg_loc_descriptor (rtl); + break; + + case MEM: + loc_result = mem_loc_descriptor (XEXP (rtl, 0)); + break; + + case CONCAT: + loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1)); + break; + + default: + abort (); + } + + return loc_result; +} + +/* Given an unsigned value, round it up to the lowest multiple of `boundary' + which is not less than the value itself. */ + +static inline unsigned +ceiling (value, boundary) + register unsigned value; + register unsigned 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) + register tree decl; +{ + register tree type; + + if (TREE_CODE (decl) == ERROR_MARK) + return integer_type_node; + + type = DECL_BIT_FIELD_TYPE (decl); + if (type == NULL_TREE) + 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 +simple_type_align_in_bits (type) + register 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 +simple_type_size_in_bits (type) + register tree type; +{ + if (TREE_CODE (type) == ERROR_MARK) + return BITS_PER_WORD; + else + { + register tree type_size_tree = TYPE_SIZE (type); + + if (TREE_CODE (type_size_tree) != INTEGER_CST) + return TYPE_ALIGN (type); + + return (unsigned) TREE_INT_CST_LOW (type_size_tree); + } +} + +/* 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 + determine 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 unsigned +field_byte_offset (decl) + register tree decl; +{ + register unsigned type_align_in_bytes; + register unsigned type_align_in_bits; + register unsigned type_size_in_bits; + register unsigned object_offset_in_align_units; + register unsigned object_offset_in_bits; + register unsigned object_offset_in_bytes; + register tree type; + register tree bitpos_tree; + register tree field_size_tree; + register unsigned bitpos_int; + register unsigned deepest_bitpos; + register unsigned field_size_in_bits; + + if (TREE_CODE (decl) == ERROR_MARK) + return 0; + + if (TREE_CODE (decl) != FIELD_DECL) + abort (); + + type = field_type (decl); + + bitpos_tree = DECL_FIELD_BITPOS (decl); + field_size_tree = DECL_SIZE (decl); + + /* 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 (TREE_CODE (bitpos_tree) != INTEGER_CST) + return 0; + bitpos_int = (unsigned) TREE_INT_CST_LOW (bitpos_tree); + + if (TREE_CODE (field_size_tree) != INTEGER_CST) + return 0; + + field_size_in_bits = (unsigned) TREE_INT_CST_LOW (field_size_tree); + 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 information 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 "containing 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 DW_AT_location and DW_AT_bit_offset attributes + for fields (both bit-fields and, in the case of DW_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; + + return object_offset_in_bytes; +} + +/* The following routines define various Dwarf attributes and any data + associated with them. */ + +/* Add a location description attribute value to a DIE. + + This emits 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 +add_AT_location_description (die, attr_kind, rtl) + dw_die_ref die; + enum dwarf_attribute attr_kind; + register rtx rtl; +{ + /* 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. 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. */ + + if (is_pseudo_reg (rtl) + || (GET_CODE (rtl) == MEM + && is_pseudo_reg (XEXP (rtl, 0))) + || (GET_CODE (rtl) == CONCAT + && is_pseudo_reg (XEXP (rtl, 0)) + && is_pseudo_reg (XEXP (rtl, 1)))) + return; + + add_AT_loc (die, attr_kind, loc_descriptor (rtl)); +} + +/* Attach 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 DW_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 DW_AT_bit_offset attribute. + (See the `bit_offset_attribute' function below). */ + +static void +add_data_member_location_attribute (die, decl) + register dw_die_ref die; + register tree decl; +{ + register unsigned long offset; + register dw_loc_descr_ref loc_descr; + register enum dwarf_location_atom op; + + if (TREE_CODE (decl) == TREE_VEC) + offset = TREE_INT_CST_LOW (BINFO_OFFSET (decl)); + else + offset = field_byte_offset (decl); + + /* The DWARF2 standard says that we should assume that the structure address + is already on the stack, so we can specify a structure field address + by using DW_OP_plus_uconst. */ + +#ifdef MIPS_DEBUGGING_INFO + /* ??? The SGI dwarf reader does not handle the DW_OP_plus_uconst operator + correctly. It works only if we leave the offset on the stack. */ + op = DW_OP_constu; +#else + op = DW_OP_plus_uconst; +#endif + + loc_descr = new_loc_descr (op, offset, 0); + add_AT_loc (die, DW_AT_data_member_location, loc_descr); +} + +/* Attach an DW_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 +add_const_value_attribute (die, rtl) + register dw_die_ref die; + register rtx rtl; +{ + 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. */ + add_AT_unsigned (die, DW_AT_const_value, (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. We output CONST_DOUBLEs as blocks. */ + { + register enum machine_mode mode = GET_MODE (rtl); + + if (GET_MODE_CLASS (mode) == MODE_FLOAT) + { + register unsigned length = GET_MODE_SIZE (mode) / sizeof (long); + long array[4]; + REAL_VALUE_TYPE rv; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, rtl); + switch (mode) + { + case SFmode: + REAL_VALUE_TO_TARGET_SINGLE (rv, array[0]); + break; + + case DFmode: + REAL_VALUE_TO_TARGET_DOUBLE (rv, array); + break; + + case XFmode: + case TFmode: + REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, array); + break; + + default: + abort (); + } + + add_AT_float (die, DW_AT_const_value, length, array); + } + else + add_AT_long_long (die, DW_AT_const_value, + CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl)); + } + break; + + case CONST_STRING: + add_AT_string (die, DW_AT_const_value, XSTR (rtl, 0)); + break; + + case SYMBOL_REF: + case LABEL_REF: + case CONST: + add_AT_addr (die, DW_AT_const_value, save_rtx (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 nothing. */ + break; + + default: + /* No other kinds of rtx should be possible here. */ + abort (); + } + +} + +/* Generate *either* an DW_AT_location attribute or else an DW_AT_const_value + data attribute for a variable or a parameter. We generate the + DW_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 +add_location_or_const_value_attribute (die, decl) + register dw_die_ref die; + register tree decl; +{ + register rtx rtl; + register tree declared_type; + register tree passed_type; + + if (TREE_CODE (decl) == ERROR_MARK) + return; + + if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != PARM_DECL) + abort (); + + /* 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 + activation 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, + we cannot (in general) use DECL_INCOMING_RTL as a 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. + + 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 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 that 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 dwarf2out.c may generate two additional + attributes for any given DW_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)) + { + declared_type = type_main_variant (TREE_TYPE (decl)); + passed_type = type_main_variant (DECL_ARG_TYPE (decl)); + + /* This decl represents a formal parameter which was optimized out. + 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 + && TREE_CODE (declared_type) == INTEGER_TYPE + && 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 (leaf_function) + 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 ...)) */ + add_const_value_attribute (die, rtl); + break; + + case MEM: + case REG: + case SUBREG: + case CONCAT: + add_AT_location_description (die, DW_AT_location, rtl); + break; + + default: + abort (); + } +} + +/* Generate an DW_AT_name attribute given some string value to be included as + the value of the attribute. */ + +static inline void +add_name_attribute (die, name_string) + register dw_die_ref die; + register char *name_string; +{ + if (name_string != NULL && *name_string != 0) + add_AT_string (die, DW_AT_name, name_string); +} + +/* Given a tree node describing an array bound (either lower or upper) output + a representation for that bound. */ + +static void +add_bound_info (subrange_die, bound_attr, bound) + register dw_die_ref subrange_die; + register enum dwarf_attribute bound_attr; + register tree bound; +{ + register unsigned bound_value = 0; + + /* If this is an Ada unconstrained array type, then don't emit any debug + info because the array bounds are unknown. They are parameterized when + the type is instantiated. */ + if (contains_placeholder_p (bound)) + return; + + switch (TREE_CODE (bound)) + { + case ERROR_MARK: + return; + + /* All fixed-bounds are represented by INTEGER_CST nodes. */ + case INTEGER_CST: + bound_value = TREE_INT_CST_LOW (bound); + if (bound_attr == DW_AT_lower_bound + && ((is_c_family () && bound_value == 0) + || (is_fortran () && bound_value == 1))) + /* use the default */; + else + add_AT_unsigned (subrange_die, bound_attr, bound_value); + break; + + case CONVERT_EXPR: + case NOP_EXPR: + case NON_LVALUE_EXPR: + add_bound_info (subrange_die, bound_attr, TREE_OPERAND (bound, 0)); + break; + + case SAVE_EXPR: + /* If optimization is turned on, the SAVE_EXPRs that describe how to + access the upper bound values may be bogus. If they refer to a + register, they may only describe 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 (though the + number of elements will), 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 don't add an attribute + 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. + + We assume that a MEM rtx is safe because gcc wouldn't put the + value there unless it was going to be used repeatedly in the + function, i.e. for cleanups. */ + if (! optimize || GET_CODE (SAVE_EXPR_RTL (bound)) == MEM) + { + register dw_die_ref ctx = lookup_decl_die (current_function_decl); + register dw_die_ref decl_die = new_die (DW_TAG_variable, ctx); + register rtx loc = SAVE_EXPR_RTL (bound); + + /* If the RTL for the SAVE_EXPR is memory, handle the case where + it references an outer function's frame. */ + + if (GET_CODE (loc) == MEM) + { + rtx new_addr = fix_lexical_addr (XEXP (loc, 0), bound); + + if (XEXP (loc, 0) != new_addr) + loc = gen_rtx (MEM, GET_MODE (loc), new_addr); + } + + add_AT_flag (decl_die, DW_AT_artificial, 1); + add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx); + add_AT_location_description (decl_die, DW_AT_location, loc); + add_AT_die_ref (subrange_die, bound_attr, decl_die); + } + + /* Else leave out the attribute. */ + break; + + case MAX_EXPR: + case VAR_DECL: + case COMPONENT_REF: + /* ??? These types of bounds can be created by the Ada front end, + and it isn't clear how to emit debug info for them. */ + break; + + default: + abort (); + } +} + +/* 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 +add_subscript_info (type_die, type) + register dw_die_ref type_die; + register tree type; +{ +#ifndef MIPS_DEBUGGING_INFO + register unsigned dimension_number; +#endif + register tree lower, upper; + register dw_die_ref subrange_die; + + /* 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. */ + + /* ??? The SGI dwarf reader fails for multidimensional arrays with a + const enum type. E.g. const enum machine_mode insn_operand_mode[2][10]. + We work around this by disabling this feature. See also + gen_array_type_die. */ +#ifndef MIPS_DEBUGGING_INFO + for (dimension_number = 0; + TREE_CODE (type) == ARRAY_TYPE; + type = TREE_TYPE (type), dimension_number++) + { +#endif + register 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. */ + subrange_die = new_die (DW_TAG_subrange_type, type_die); + if (domain) + { + /* We have an array type with specified bounds. */ + lower = TYPE_MIN_VALUE (domain); + upper = TYPE_MAX_VALUE (domain); + + /* define the index type. */ + if (TREE_TYPE (domain)) + { + /* ??? This is probably an Ada unnamed subrange type. Ignore the + TREE_TYPE field. We can't emit debug info for this + because it is an unnamed integral type. */ + if (TREE_CODE (domain) == INTEGER_TYPE + && TYPE_NAME (domain) == NULL_TREE + && TREE_CODE (TREE_TYPE (domain)) == INTEGER_TYPE + && TYPE_NAME (TREE_TYPE (domain)) == NULL_TREE) + ; + else + add_type_attribute (subrange_die, TREE_TYPE (domain), 0, 0, + type_die); + } + + /* ??? If upper is NULL, the array has unspecified length, + but it does have a lower bound. This happens with Fortran + dimension arr(N:*) + Since the debugger is definitely going to need to know N + to produce useful results, go ahead and output the lower + bound solo, and hope the debugger can cope. */ + + add_bound_info (subrange_die, DW_AT_lower_bound, lower); + if (upper) + add_bound_info (subrange_die, DW_AT_upper_bound, upper); + } + else + /* We have an array type with an unspecified length. The DWARF-2 + spec does not say how to handle this; let's just leave out the + bounds. */ + {;} + + +#ifndef MIPS_DEBUGGING_INFO + } +#endif +} + +static void +add_byte_size_attribute (die, tree_node) + dw_die_ref die; + register tree tree_node; +{ + register unsigned 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: + size = int_size_in_bytes (tree_node); + break; + case FIELD_DECL: + /* For a data member of a struct or union, the DW_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. */ + + add_AT_unsigned (die, DW_AT_byte_size, 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 DW_AT_byte_size attribute for this bit-field. + (See `byte_size_attribute' above). */ + +static inline void +add_bit_offset_attribute (die, decl) + register dw_die_ref die; + register tree decl; +{ + register unsigned object_offset_in_bytes = field_byte_offset (decl); + register tree type = DECL_BIT_FIELD_TYPE (decl); + register tree bitpos_tree = DECL_FIELD_BITPOS (decl); + register unsigned bitpos_int; + register unsigned highest_order_object_bit_offset; + register unsigned highest_order_field_bit_offset; + register unsigned bit_offset; + + /* Must be a field and a bit field. */ + if (!type + || TREE_CODE (decl) != FIELD_DECL) + abort (); + + /* We can't yet handle bit-fields whose offsets are variable, so if we + encounter such things, just return without generating any attribute + whatsoever. */ + if (TREE_CODE (bitpos_tree) != INTEGER_CST) + return; + + bitpos_int = (unsigned) TREE_INT_CST_LOW (bitpos_tree); + + /* 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 + += (unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl)); + + 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); + + add_AT_unsigned (die, DW_AT_bit_offset, 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 +add_bit_size_attribute (die, decl) + register dw_die_ref die; + register tree decl; +{ + /* Must be a field and a bit field. */ + if (TREE_CODE (decl) != FIELD_DECL + || ! DECL_BIT_FIELD_TYPE (decl)) + abort (); + add_AT_unsigned (die, DW_AT_bit_size, + (unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl))); +} + +/* If the compiled language is ANSI C, then add a 'prototyped' + attribute, if arg types are given for the parameters of a function. */ + +static inline void +add_prototyped_attribute (die, func_type) + register dw_die_ref die; + register tree func_type; +{ + if (get_AT_unsigned (comp_unit_die, DW_AT_language) == DW_LANG_C89 + && TYPE_ARG_TYPES (func_type) != NULL) + add_AT_flag (die, DW_AT_prototyped, 1); +} + + +/* Add an 'abstract_origin' attribute below a given DIE. The DIE is found + by looking in either the type declaration or object declaration + equate table. */ + +static inline void +add_abstract_origin_attribute (die, origin) + register dw_die_ref die; + register tree origin; +{ + dw_die_ref origin_die = NULL; + if (TREE_CODE_CLASS (TREE_CODE (origin)) == 'd') + origin_die = lookup_decl_die (origin); + else if (TREE_CODE_CLASS (TREE_CODE (origin)) == 't') + origin_die = lookup_type_die (origin); + + add_AT_die_ref (die, DW_AT_abstract_origin, origin_die); +} + +/* We do not currently support the pure_virtual attribute. */ + +static inline void +add_pure_or_virtual_attribute (die, func_decl) + register dw_die_ref die; + register tree func_decl; +{ + if (DECL_VINDEX (func_decl)) + { + add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual); + add_AT_loc (die, DW_AT_vtable_elem_location, + new_loc_descr (DW_OP_constu, + TREE_INT_CST_LOW (DECL_VINDEX (func_decl)), + 0)); + + /* GNU extension: Record what type this method came from originally. */ + if (debug_info_level > DINFO_LEVEL_TERSE) + add_AT_die_ref (die, DW_AT_containing_type, + lookup_type_die (DECL_CONTEXT (func_decl))); + } +} + +/* Add source coordinate attributes for the given decl. */ + +static void +add_src_coords_attributes (die, decl) + register dw_die_ref die; + register tree decl; +{ + register unsigned file_index = lookup_filename (DECL_SOURCE_FILE (decl)); + + add_AT_unsigned (die, DW_AT_decl_file, file_index); + add_AT_unsigned (die, DW_AT_decl_line, DECL_SOURCE_LINE (decl)); +} + +/* Add an DW_AT_name attribute and source coordinate attribute for the + given decl, but only if it actually has a name. */ + +static void +add_name_and_src_coords_attributes (die, decl) + register dw_die_ref die; + register tree decl; +{ + register tree decl_name; + + decl_name = DECL_NAME (decl); + if (decl_name != NULL && IDENTIFIER_POINTER (decl_name) != NULL) + { + add_name_attribute (die, dwarf2_name (decl, 0)); + add_src_coords_attributes (die, decl); + if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL) + && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)) + add_AT_string (die, DW_AT_MIPS_linkage_name, + IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))); + } +} + +/* Push a new declaration scope. */ + +static void +push_decl_scope (scope) + tree scope; +{ + tree containing_scope; + int i; + + /* Make room in the decl_scope_table, if necessary. */ + if (decl_scope_table_allocated == decl_scope_depth) + { + decl_scope_table_allocated += DECL_SCOPE_TABLE_INCREMENT; + decl_scope_table + = (decl_scope_node *) xrealloc (decl_scope_table, + (decl_scope_table_allocated + * sizeof (decl_scope_node))); + } + + decl_scope_table[decl_scope_depth].scope = scope; + + /* Sometimes, while recursively emitting subtypes within a class type, + we end up recuring on a subtype at a higher level then the current + subtype. In such a case, we need to search the decl_scope_table to + find the parent of this subtype. */ + + if (AGGREGATE_TYPE_P (scope)) + containing_scope = TYPE_CONTEXT (scope); + else + containing_scope = NULL_TREE; + + /* The normal case. */ + if (decl_scope_depth == 0 + || containing_scope == NULL_TREE + /* Ignore namespaces for the moment. */ + || TREE_CODE (containing_scope) == NAMESPACE_DECL + || containing_scope == decl_scope_table[decl_scope_depth - 1].scope) + decl_scope_table[decl_scope_depth].previous = decl_scope_depth - 1; + else + { + /* We need to search for the containing_scope. */ + for (i = 0; i < decl_scope_depth; i++) + if (decl_scope_table[i].scope == containing_scope) + break; + + if (i == decl_scope_depth) + abort (); + else + decl_scope_table[decl_scope_depth].previous = i; + } + + decl_scope_depth++; +} + +/* Return the DIE for the scope that immediately contains this declaration. */ + +static dw_die_ref +scope_die_for (t, context_die) + register tree t; + register dw_die_ref context_die; +{ + register dw_die_ref scope_die = NULL; + register tree containing_scope; + register int i; + + /* Walk back up the declaration tree looking for a place to define + this type. */ + if (TREE_CODE_CLASS (TREE_CODE (t)) == 't') + containing_scope = TYPE_CONTEXT (t); + else if (TREE_CODE (t) == FUNCTION_DECL && DECL_VINDEX (t)) + containing_scope = decl_class_context (t); + else + containing_scope = DECL_CONTEXT (t); + + /* Ignore namespaces for the moment. */ + if (containing_scope && TREE_CODE (containing_scope) == NAMESPACE_DECL) + containing_scope = NULL_TREE; + + /* Ignore function type "scopes" from the C frontend. They mean that + a tagged type is local to a parmlist of a function declarator, but + that isn't useful to DWARF. */ + if (containing_scope && TREE_CODE (containing_scope) == FUNCTION_TYPE) + containing_scope = NULL_TREE; + + /* Function-local tags and functions get stuck in limbo until they are + fixed up by decls_for_scope. */ + if (context_die == NULL && containing_scope != NULL_TREE + && (TREE_CODE (t) == FUNCTION_DECL || is_tagged_type (t))) + return NULL; + + if (containing_scope == NULL_TREE) + scope_die = comp_unit_die; + else + { + for (i = decl_scope_depth - 1, scope_die = context_die; + i >= 0 && decl_scope_table[i].scope != containing_scope; + (scope_die = scope_die->die_parent, + i = decl_scope_table[i].previous)) + ; + + /* ??? Integrate_decl_tree does not handle BLOCK_TYPE_TAGS, nor + does it try to handle types defined by TYPE_DECLs. Such types + thus have an incorrect TYPE_CONTEXT, which points to the block + they were originally defined in, instead of the current block + created by function inlining. We try to detect that here and + work around it. */ + + if (i < 0 && scope_die == comp_unit_die + && TREE_CODE (containing_scope) == BLOCK + && is_tagged_type (t) + && (block_ultimate_origin (decl_scope_table[decl_scope_depth - 1].scope) + == containing_scope)) + { + scope_die = context_die; + /* Since the checks below are no longer applicable. */ + i = 0; + } + + if (i < 0) + { + if (scope_die != comp_unit_die + || TREE_CODE_CLASS (TREE_CODE (containing_scope)) != 't') + abort (); + if (debug_info_level > DINFO_LEVEL_TERSE + && !TREE_ASM_WRITTEN (containing_scope)) + abort (); + } + } + + return scope_die; +} + +/* Pop a declaration scope. */ +static inline void +pop_decl_scope () +{ + if (decl_scope_depth <= 0) + abort (); + --decl_scope_depth; +} + +/* Many forms of DIEs require a "type description" attribute. This + routine locates the proper "type descriptor" die for the type given + by 'type', and adds an DW_AT_type attribute below the given die. */ + +static void +add_type_attribute (object_die, type, decl_const, decl_volatile, context_die) + register dw_die_ref object_die; + register tree type; + register int decl_const; + register int decl_volatile; + register dw_die_ref context_die; +{ + register enum tree_code code = TREE_CODE (type); + register dw_die_ref type_die = NULL; + + /* ??? If this type is an unnamed subrange type of an integral or + floating-point type, use the inner type. This is because we have no + support for unnamed types in base_type_die. This can happen if this is + an Ada subrange type. Correct solution is emit a subrange type die. */ + if ((code == INTEGER_TYPE || code == REAL_TYPE) + && TREE_TYPE (type) != 0 && TYPE_NAME (type) == 0) + type = TREE_TYPE (type), code = TREE_CODE (type); + + 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; + + type_die = modified_type_die (type, + decl_const || TYPE_READONLY (type), + decl_volatile || TYPE_VOLATILE (type), + context_die); + if (type_die != NULL) + add_AT_die_ref (object_die, DW_AT_type, type_die); +} + +/* 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 char * +type_tag (type) + register tree type; +{ + register char *name = 0; + + if (TYPE_NAME (type) != 0) + { + register 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; +} + +/* Return the type associated with a data member, make a special check + for bit field types. */ + +static inline tree +member_declared_type (member) + register tree member; +{ + return (DECL_BIT_FIELD_TYPE (member) + ? DECL_BIT_FIELD_TYPE (member) + : TREE_TYPE (member)); +} + +/* Get the decl's label, as described by its RTL. This may be different + from the DECL_NAME name used in the source file. */ + +#if 0 +static char * +decl_start_label (decl) + register tree decl; +{ + rtx x; + 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; +} +#endif + +/* These routines generate the internal representation of the DIE's for + the compilation unit. Debugging information is collected by walking + the declaration trees passed in from dwarf2out_decl(). */ + +static void +gen_array_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref scope_die = scope_die_for (type, context_die); + register dw_die_ref array_die; + register tree element_type; + + /* ??? The SGI dwarf reader fails for array of array of enum types unless + the inner array type comes before the outer array type. Thus we must + call gen_type_die before we call new_die. See below also. */ +#ifdef MIPS_DEBUGGING_INFO + gen_type_die (TREE_TYPE (type), context_die); +#endif + + array_die = new_die (DW_TAG_array_type, scope_die); + +#if 0 + /* We default the array ordering. SDB will probably do + the right things even if DW_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 DW_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. */ + add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_row_major); +#endif + +#ifdef MIPS_DEBUGGING_INFO + /* The SGI compilers handle arrays of unknown bound by setting + AT_declaration and not emitting any subrange DIEs. */ + if (! TYPE_DOMAIN (type)) + add_AT_unsigned (array_die, DW_AT_declaration, 1); + else +#endif + add_subscript_info (array_die, type); + + equate_type_number_to_die (type, array_die); + + /* Add representation of the type of the elements of this array type. */ + element_type = TREE_TYPE (type); + + /* ??? The SGI dwarf reader fails for multidimensional arrays with a + const enum type. E.g. const enum machine_mode insn_operand_mode[2][10]. + We work around this by disabling this feature. See also + add_subscript_info. */ +#ifndef MIPS_DEBUGGING_INFO + while (TREE_CODE (element_type) == ARRAY_TYPE) + element_type = TREE_TYPE (element_type); + + gen_type_die (element_type, context_die); +#endif + + add_type_attribute (array_die, element_type, 0, 0, context_die); +} + +static void +gen_set_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref type_die + = new_die (DW_TAG_set_type, scope_die_for (type, context_die)); + + equate_type_number_to_die (type, type_die); + add_type_attribute (type_die, TREE_TYPE (type), 0, 0, context_die); +} + +#if 0 +static void +gen_entry_point_die (decl, context_die) + register tree decl; + register dw_die_ref context_die; +{ + register tree origin = decl_ultimate_origin (decl); + register dw_die_ref decl_die = new_die (DW_TAG_entry_point, context_die); + if (origin != NULL) + add_abstract_origin_attribute (decl_die, origin); + else + { + add_name_and_src_coords_attributes (decl_die, decl); + add_type_attribute (decl_die, TREE_TYPE (TREE_TYPE (decl)), + 0, 0, context_die); + } + + if (DECL_ABSTRACT (decl)) + equate_decl_number_to_die (decl, decl_die); + else + add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl)); +} +#endif + +/* Remember a type in the pending_types_list. */ + +static void +pend_type (type) + register 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; +} + +/* 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. */ + +static void +output_pending_types_for_scope (context_die) + register dw_die_ref context_die; +{ + register tree type; + + while (pending_types) + { + --pending_types; + type = pending_types_list[pending_types]; + gen_type_die (type, context_die); + if (!TREE_ASM_WRITTEN (type)) + abort (); + } +} + +/* Generate a DIE to represent an inlined instance of an enumeration type. */ + +static void +gen_inlined_enumeration_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref type_die = new_die (DW_TAG_enumeration_type, + scope_die_for (type, context_die)); + + if (!TREE_ASM_WRITTEN (type)) + abort (); + add_abstract_origin_attribute (type_die, type); +} + +/* Generate a DIE to represent an inlined instance of a structure type. */ + +static void +gen_inlined_structure_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref type_die = new_die (DW_TAG_structure_type, + scope_die_for (type, context_die)); + + if (!TREE_ASM_WRITTEN (type)) + abort (); + add_abstract_origin_attribute (type_die, type); +} + +/* Generate a DIE to represent an inlined instance of a union type. */ + +static void +gen_inlined_union_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref type_die = new_die (DW_TAG_union_type, + scope_die_for (type, context_die)); + + if (!TREE_ASM_WRITTEN (type)) + abort (); + add_abstract_origin_attribute (type_die, type); +} + +/* Generate a DIE to represent an enumeration type. Note that these DIEs + include all of the information about the enumeration values also. Each + enumerated type name/value is listed as a child of the enumerated type + DIE. */ + +static void +gen_enumeration_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref type_die = lookup_type_die (type); + + if (type_die == NULL) + { + type_die = new_die (DW_TAG_enumeration_type, + scope_die_for (type, context_die)); + equate_type_number_to_die (type, type_die); + add_name_attribute (type_die, type_tag (type)); + } + else if (! TYPE_SIZE (type)) + return; + else + remove_AT (type_die, DW_AT_declaration); + + /* Handle a GNU C/C++ extension, i.e. incomplete enum types. If the + given enum type is incomplete, do not generate the DW_AT_byte_size + attribute or the DW_AT_element_list attribute. */ + if (TYPE_SIZE (type)) + { + register tree link; + + TREE_ASM_WRITTEN (type) = 1; + add_byte_size_attribute (type_die, type); + if (TYPE_STUB_DECL (type) != NULL_TREE) + add_src_coords_attributes (type_die, TYPE_STUB_DECL (type)); + + /* If the first reference to this type was as the return type of an + inline function, then it may not have a parent. Fix this now. */ + if (type_die->die_parent == NULL) + add_child_die (scope_die_for (type, context_die), type_die); + + for (link = TYPE_FIELDS (type); + link != NULL; link = TREE_CHAIN (link)) + { + register dw_die_ref enum_die = new_die (DW_TAG_enumerator, type_die); + + add_name_attribute (enum_die, + IDENTIFIER_POINTER (TREE_PURPOSE (link))); + add_AT_unsigned (enum_die, DW_AT_const_value, + (unsigned) TREE_INT_CST_LOW (TREE_VALUE (link))); + } + } + else + add_AT_flag (type_die, DW_AT_declaration, 1); +} + + +/* Generate 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 + DW_TAG_formal_parameter DIE to stand as a placeholder for some formal + argument type of some subprogram type. */ + +static dw_die_ref +gen_formal_parameter_die (node, context_die) + register tree node; + register dw_die_ref context_die; +{ + register dw_die_ref parm_die + = new_die (DW_TAG_formal_parameter, context_die); + register tree origin; + + switch (TREE_CODE_CLASS (TREE_CODE (node))) + { + case 'd': + origin = decl_ultimate_origin (node); + if (origin != NULL) + add_abstract_origin_attribute (parm_die, origin); + else + { + add_name_and_src_coords_attributes (parm_die, node); + add_type_attribute (parm_die, TREE_TYPE (node), + TREE_READONLY (node), + TREE_THIS_VOLATILE (node), + context_die); + if (DECL_ARTIFICIAL (node)) + add_AT_flag (parm_die, DW_AT_artificial, 1); + } + + equate_decl_number_to_die (node, parm_die); + if (! DECL_ABSTRACT (node)) + add_location_or_const_value_attribute (parm_die, node); + + break; + + case 't': + /* We were called with some kind of a ..._TYPE node. */ + add_type_attribute (parm_die, node, 0, 0, context_die); + break; + + default: + abort (); + } + + return parm_die; +} + +/* 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 +gen_unspecified_parameters_die (decl_or_type, context_die) + register tree decl_or_type; + register dw_die_ref context_die; +{ + new_die (DW_TAG_unspecified_parameters, context_die); +} + +/* Generate a list of nameless DW_TAG_formal_parameter DIEs (and perhaps a + DW_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 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 +gen_formal_types_die (function_or_method_type, context_die) + register tree function_or_method_type; + register dw_die_ref context_die; +{ + register tree link; + register tree formal_type = NULL; + register tree first_parm_type = TYPE_ARG_TYPES (function_or_method_type); + +#if 0 + /* 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 DW_AT_member attribute of the parent + DW_TAG_subroutine_type DIE. */ + if (TREE_CODE (function_or_method_type) == METHOD_TYPE) + first_parm_type = TREE_CHAIN (first_parm_type); +#endif + + /* Make our first pass over the list of formal parameter types and output a + DW_TAG_formal_parameter DIE for each one. */ + for (link = first_parm_type; link; link = TREE_CHAIN (link)) + { + register dw_die_ref parm_die; + + formal_type = TREE_VALUE (link); + if (formal_type == void_type_node) + break; + + /* Output a (nameless) DIE to represent the formal parameter itself. */ + parm_die = gen_formal_parameter_die (formal_type, context_die); + if (TREE_CODE (function_or_method_type) == METHOD_TYPE + && link == first_parm_type) + add_AT_flag (parm_die, DW_AT_artificial, 1); + } + + /* If this function type has an ellipsis, add a + DW_TAG_unspecified_parameters DIE to the end of the parameter list. */ + if (formal_type != void_type_node) + gen_unspecified_parameters_die (function_or_method_type, context_die); + + /* 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; + + gen_type_die (formal_type, context_die); + } +} + +/* Generate a DIE to represent a declared function (either file-scope or + block-local). */ + +static void +gen_subprogram_die (decl, context_die) + register tree decl; + register dw_die_ref context_die; +{ + char label_id[MAX_ARTIFICIAL_LABEL_BYTES]; + register tree origin = decl_ultimate_origin (decl); + register dw_die_ref subr_die; + register rtx fp_reg; + register tree fn_arg_types; + register tree outer_scope; + register dw_die_ref old_die = lookup_decl_die (decl); + register int declaration + = (current_function_decl != decl + || (context_die + && (context_die->die_tag == DW_TAG_structure_type + || context_die->die_tag == DW_TAG_union_type))); + + if (origin != NULL) + { + subr_die = new_die (DW_TAG_subprogram, context_die); + add_abstract_origin_attribute (subr_die, origin); + } + else if (old_die && DECL_ABSTRACT (decl) + && get_AT_unsigned (old_die, DW_AT_inline)) + { + /* This must be a redefinition of an extern inline function. + We can just reuse the old die here. */ + subr_die = old_die; + + /* Clear out the inlined attribute and parm types. */ + remove_AT (subr_die, DW_AT_inline); + remove_children (subr_die); + } + else if (old_die) + { + register unsigned file_index + = lookup_filename (DECL_SOURCE_FILE (decl)); + + if (get_AT_flag (old_die, DW_AT_declaration) != 1) + { + /* ??? This can happen if there is a bug in the program, for + instance, if it has duplicate function definitions. Ideally, + we should detect this case and ignore it. For now, if we have + already reported an error, any error at all, then assume that + we got here because of a input error, not a dwarf2 bug. */ + extern int errorcount; + if (errorcount) + return; + abort (); + } + + /* If the definition comes from the same place as the declaration, + maybe use the old DIE. We always want the DIE for this function + that has the *_pc attributes to be under comp_unit_die so the + debugger can find it. For inlines, that is the concrete instance, + so we can use the old DIE here. For non-inline methods, we want a + specification DIE at toplevel, so we need a new DIE. For local + class methods, this does not apply. */ + if ((DECL_ABSTRACT (decl) || old_die->die_parent == comp_unit_die + || context_die == NULL) + && get_AT_unsigned (old_die, DW_AT_decl_file) == file_index + && (get_AT_unsigned (old_die, DW_AT_decl_line) + == DECL_SOURCE_LINE (decl))) + { + subr_die = old_die; + + /* Clear out the declaration attribute and the parm types. */ + remove_AT (subr_die, DW_AT_declaration); + remove_children (subr_die); + } + else + { + subr_die = new_die (DW_TAG_subprogram, context_die); + add_AT_die_ref (subr_die, DW_AT_specification, old_die); + if (get_AT_unsigned (old_die, DW_AT_decl_file) != file_index) + add_AT_unsigned (subr_die, DW_AT_decl_file, file_index); + if (get_AT_unsigned (old_die, DW_AT_decl_line) + != DECL_SOURCE_LINE (decl)) + add_AT_unsigned + (subr_die, DW_AT_decl_line, DECL_SOURCE_LINE (decl)); + } + } + else + { + register dw_die_ref scope_die; + + if (DECL_CONTEXT (decl)) + scope_die = scope_die_for (decl, context_die); + else + /* Don't put block extern declarations under comp_unit_die. */ + scope_die = context_die; + + subr_die = new_die (DW_TAG_subprogram, scope_die); + + if (TREE_PUBLIC (decl)) + add_AT_flag (subr_die, DW_AT_external, 1); + + add_name_and_src_coords_attributes (subr_die, decl); + if (debug_info_level > DINFO_LEVEL_TERSE) + { + register tree type = TREE_TYPE (decl); + + add_prototyped_attribute (subr_die, type); + add_type_attribute (subr_die, TREE_TYPE (type), 0, 0, context_die); + } + + add_pure_or_virtual_attribute (subr_die, decl); + if (DECL_ARTIFICIAL (decl)) + add_AT_flag (subr_die, DW_AT_artificial, 1); + if (TREE_PROTECTED (decl)) + add_AT_unsigned (subr_die, DW_AT_accessibility, DW_ACCESS_protected); + else if (TREE_PRIVATE (decl)) + add_AT_unsigned (subr_die, DW_AT_accessibility, DW_ACCESS_private); + } + + if (declaration) + { + add_AT_flag (subr_die, DW_AT_declaration, 1); + + /* The first time we see a member function, it is in the context of + the class to which it belongs. We make sure of this by emitting + the class first. The next time is the definition, which is + handled above. The two may come from the same source text. */ + if (DECL_CONTEXT (decl)) + equate_decl_number_to_die (decl, subr_die); + } + else if (DECL_ABSTRACT (decl)) + { + /* ??? Checking DECL_DEFER_OUTPUT is correct for static inline functions, + but not for extern inline functions. We can't get this completely + correct because information about whether the function was declared + inline is not saved anywhere. */ + if (DECL_DEFER_OUTPUT (decl)) + { + if (DECL_INLINE (decl)) + add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_inlined); + else + add_AT_unsigned (subr_die, DW_AT_inline, + DW_INL_declared_not_inlined); + } + else if (DECL_INLINE (decl)) + add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined); + else + abort (); + + equate_decl_number_to_die (decl, subr_die); + } + else if (!DECL_EXTERNAL (decl)) + { + if (origin == NULL_TREE) + equate_decl_number_to_die (decl, subr_die); + + ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL, + current_funcdef_number); + add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id); + ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL, + current_funcdef_number); + add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id); + + add_pubname (decl, subr_die); + add_arange (decl, subr_die); + +#ifdef MIPS_DEBUGGING_INFO + /* Add a reference to the FDE for this routine. */ + add_AT_fde_ref (subr_die, DW_AT_MIPS_fde, current_funcdef_fde); +#endif + + /* Define the "frame base" location for this routine. We use the + frame pointer or stack pointer registers, since the RTL for local + variables is relative to one of them. */ + fp_reg + = frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx; + add_AT_loc (subr_die, DW_AT_frame_base, reg_loc_descriptor (fp_reg)); + +#if 0 + /* ??? This fails for nested inline functions, because context_display + is not part of the state saved/restored for inline functions. */ + if (current_function_needs_context) + add_AT_location_description (subr_die, DW_AT_static_link, + lookup_static_chain (decl)); +#endif + } + + /* 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. */ + push_decl_scope (decl); + + /* 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 (debug_info_level <= DINFO_LEVEL_TERSE) + ; + else if (declaration) + gen_formal_types_die (TREE_TYPE (decl), subr_die); + else + { + /* Generate DIEs to represent all known formal parameters */ + register tree arg_decls = DECL_ARGUMENTS (decl); + register tree parm; + + /* 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")) + gen_unspecified_parameters_die (parm, subr_die); + else + gen_decl_die (parm, subr_die); + } + + /* Decide whether we need a 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. */ + fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl)); + if (fn_arg_types != NULL) + { + /* this is the prototyped case, check for ... */ + if (TREE_VALUE (tree_last (fn_arg_types)) != void_type_node) + gen_unspecified_parameters_die (decl, subr_die); + } + else if (DECL_INITIAL (decl) == NULL_TREE) + gen_unspecified_parameters_die (decl, subr_die); + } + + /* Output Dwarf info for all of the stuff within the body of the function + (if it has one - it may be just a declaration). */ + outer_scope = DECL_INITIAL (decl); + + /* 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 in + decls_for_scope. 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. */ + if (! declaration && TREE_CODE (outer_scope) != ERROR_MARK) + { + current_function_has_inlines = 0; + decls_for_scope (outer_scope, subr_die, 0); + +#if 0 && defined (MIPS_DEBUGGING_INFO) + if (current_function_has_inlines) + { + add_AT_flag (subr_die, DW_AT_MIPS_has_inlines, 1); + if (! comp_unit_has_inlines) + { + add_AT_flag (comp_unit_die, DW_AT_MIPS_has_inlines, 1); + comp_unit_has_inlines = 1; + } + } +#endif + } + + pop_decl_scope (); +} + +/* Generate a DIE to represent a declared data object. */ + +static void +gen_variable_die (decl, context_die) + register tree decl; + register dw_die_ref context_die; +{ + register tree origin = decl_ultimate_origin (decl); + register dw_die_ref var_die = new_die (DW_TAG_variable, context_die); + + dw_die_ref old_die = lookup_decl_die (decl); + int declaration + = (DECL_EXTERNAL (decl) + || current_function_decl != decl_function_context (decl) + || context_die->die_tag == DW_TAG_structure_type + || context_die->die_tag == DW_TAG_union_type); + + if (origin != NULL) + add_abstract_origin_attribute (var_die, origin); + /* Loop unrolling can create multiple blocks that refer to the same + static variable, so we must test for the DW_AT_declaration flag. */ + /* ??? Loop unrolling/reorder_blocks should perhaps be rewritten to + copy decls and set the DECL_ABSTRACT flag on them instead of + sharing them. */ + else if (old_die && TREE_STATIC (decl) + && get_AT_flag (old_die, DW_AT_declaration) == 1) + { + /* ??? This is an instantiation of a C++ class level static. */ + add_AT_die_ref (var_die, DW_AT_specification, old_die); + if (DECL_NAME (decl)) + { + register unsigned file_index + = lookup_filename (DECL_SOURCE_FILE (decl)); + + if (get_AT_unsigned (old_die, DW_AT_decl_file) != file_index) + add_AT_unsigned (var_die, DW_AT_decl_file, file_index); + + if (get_AT_unsigned (old_die, DW_AT_decl_line) + != DECL_SOURCE_LINE (decl)) + + add_AT_unsigned (var_die, DW_AT_decl_line, + DECL_SOURCE_LINE (decl)); + } + } + else + { + add_name_and_src_coords_attributes (var_die, decl); + add_type_attribute (var_die, TREE_TYPE (decl), + TREE_READONLY (decl), + TREE_THIS_VOLATILE (decl), context_die); + + if (TREE_PUBLIC (decl)) + add_AT_flag (var_die, DW_AT_external, 1); + + if (DECL_ARTIFICIAL (decl)) + add_AT_flag (var_die, DW_AT_artificial, 1); + + if (TREE_PROTECTED (decl)) + add_AT_unsigned (var_die, DW_AT_accessibility, DW_ACCESS_protected); + + else if (TREE_PRIVATE (decl)) + add_AT_unsigned (var_die, DW_AT_accessibility, DW_ACCESS_private); + } + + if (declaration) + add_AT_flag (var_die, DW_AT_declaration, 1); + + if ((declaration && decl_class_context (decl)) || DECL_ABSTRACT (decl)) + equate_decl_number_to_die (decl, var_die); + + if (! declaration && ! DECL_ABSTRACT (decl)) + { + equate_decl_number_to_die (decl, var_die); + add_location_or_const_value_attribute (var_die, decl); + add_pubname (decl, var_die); + } +} + +/* Generate a DIE to represent a label identifier. */ + +static void +gen_label_die (decl, context_die) + register tree decl; + register dw_die_ref context_die; +{ + register tree origin = decl_ultimate_origin (decl); + register dw_die_ref lbl_die = new_die (DW_TAG_label, context_die); + register rtx insn; + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + char label2[MAX_ARTIFICIAL_LABEL_BYTES]; + + if (origin != NULL) + add_abstract_origin_attribute (lbl_die, origin); + else + add_name_and_src_coords_attributes (lbl_die, decl); + + if (DECL_ABSTRACT (decl)) + equate_decl_number_to_die (decl, lbl_die); + else + { + insn = DECL_RTL (decl); + if (GET_CODE (insn) == CODE_LABEL) + { + /* 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 (); + + sprintf (label2, INSN_LABEL_FMT, current_funcdef_number); + ASM_GENERATE_INTERNAL_LABEL (label, label2, + (unsigned) INSN_UID (insn)); + add_AT_lbl_id (lbl_die, DW_AT_low_pc, label); + } + } +} + +/* Generate a DIE for a lexical block. */ + +static void +gen_lexical_block_die (stmt, context_die, depth) + register tree stmt; + register dw_die_ref context_die; + int depth; +{ + register dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die); + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + if (! BLOCK_ABSTRACT (stmt)) + { + ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL, + next_block_number); + add_AT_lbl_id (stmt_die, DW_AT_low_pc, label); + ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL, next_block_number); + add_AT_lbl_id (stmt_die, DW_AT_high_pc, label); + } + + push_decl_scope (stmt); + decls_for_scope (stmt, stmt_die, depth); + pop_decl_scope (); +} + +/* Generate a DIE for an inlined subprogram. */ + +static void +gen_inlined_subroutine_die (stmt, context_die, depth) + register tree stmt; + register dw_die_ref context_die; + int depth; +{ + if (! BLOCK_ABSTRACT (stmt)) + { + register dw_die_ref subr_die + = new_die (DW_TAG_inlined_subroutine, context_die); + register tree decl = block_ultimate_origin (stmt); + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + add_abstract_origin_attribute (subr_die, decl); + ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL, + next_block_number); + add_AT_lbl_id (subr_die, DW_AT_low_pc, label); + ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL, next_block_number); + add_AT_lbl_id (subr_die, DW_AT_high_pc, label); + push_decl_scope (decl); + decls_for_scope (stmt, subr_die, depth); + pop_decl_scope (); + current_function_has_inlines = 1; + } +} + +/* Generate a DIE for a field in a record, or structure. */ + +static void +gen_field_die (decl, context_die) + register tree decl; + register dw_die_ref context_die; +{ + register dw_die_ref decl_die = new_die (DW_TAG_member, context_die); + + add_name_and_src_coords_attributes (decl_die, decl); + add_type_attribute (decl_die, member_declared_type (decl), + TREE_READONLY (decl), TREE_THIS_VOLATILE (decl), + context_die); + + /* If this is a bit field... */ + if (DECL_BIT_FIELD_TYPE (decl)) + { + add_byte_size_attribute (decl_die, decl); + add_bit_size_attribute (decl_die, decl); + add_bit_offset_attribute (decl_die, decl); + } + + if (TREE_CODE (DECL_FIELD_CONTEXT (decl)) != UNION_TYPE) + add_data_member_location_attribute (decl_die, decl); + + if (DECL_ARTIFICIAL (decl)) + add_AT_flag (decl_die, DW_AT_artificial, 1); + + if (TREE_PROTECTED (decl)) + add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_protected); + + else if (TREE_PRIVATE (decl)) + add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_private); +} + +#if 0 +/* Don't generate either pointer_type DIEs or reference_type DIEs here. + Use modified_type_die 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 +gen_pointer_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref ptr_die + = new_die (DW_TAG_pointer_type, scope_die_for (type, context_die)); + + equate_type_number_to_die (type, ptr_die); + add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die); + add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE); +} + +/* Don't generate either pointer_type DIEs or reference_type DIEs here. + Use modified_type_die 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 +gen_reference_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref ref_die + = new_die (DW_TAG_reference_type, scope_die_for (type, context_die)); + + equate_type_number_to_die (type, ref_die); + add_type_attribute (ref_die, TREE_TYPE (type), 0, 0, context_die); + add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE); +} +#endif + +/* Generate a DIE for a pointer to a member type. */ +static void +gen_ptr_to_mbr_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref ptr_die + = new_die (DW_TAG_ptr_to_member_type, scope_die_for (type, context_die)); + + equate_type_number_to_die (type, ptr_die); + add_AT_die_ref (ptr_die, DW_AT_containing_type, + lookup_type_die (TYPE_OFFSET_BASETYPE (type))); + add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die); +} + +/* Generate the DIE for the compilation unit. */ + +static void +gen_compile_unit_die (main_input_filename) + register char *main_input_filename; +{ + char producer[250]; + char *wd = getpwd (); + + comp_unit_die = new_die (DW_TAG_compile_unit, NULL); + add_name_attribute (comp_unit_die, main_input_filename); + + if (wd != NULL) + add_AT_string (comp_unit_die, DW_AT_comp_dir, wd); + + sprintf (producer, "%s %s", language_string, version_string); + +#ifdef MIPS_DEBUGGING_INFO + /* The MIPS/SGI compilers place the 'cc' command line options in the producer + string. The SGI debugger looks for -g, -g1, -g2, or -g3; if they do + not appear in the producer string, the debugger reaches the conclusion + that the object file is stripped and has no debugging information. + To get the MIPS/SGI debugger to believe that there is debugging + information in the object file, we add a -g to the producer string. */ + if (debug_info_level > DINFO_LEVEL_TERSE) + strcat (producer, " -g"); +#endif + + add_AT_string (comp_unit_die, DW_AT_producer, producer); + + if (strcmp (language_string, "GNU C++") == 0) + add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C_plus_plus); + + else if (strcmp (language_string, "GNU Ada") == 0) + add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Ada83); + + else if (strcmp (language_string, "GNU F77") == 0) + add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Fortran77); + + else if (strcmp (language_string, "GNU Pascal") == 0) + add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Pascal83); + + else if (flag_traditional) + add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C); + + else + add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C89); + +#if 0 /* unimplemented */ + if (debug_info_level >= DINFO_LEVEL_VERBOSE) + add_AT_unsigned (comp_unit_die, DW_AT_macro_info, 0); +#endif +} + +/* Generate a DIE for a string type. */ + +static void +gen_string_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref type_die + = new_die (DW_TAG_string_type, scope_die_for (type, context_die)); + + equate_type_number_to_die (type, type_die); + + /* Fudge the string length attribute for now. */ + + /* TODO: add string length info. + string_length_attribute (TYPE_MAX_VALUE (TYPE_DOMAIN (type))); + bound_representation (upper_bound, 0, 'u'); */ +} + +/* Generate the DIE for a base class. */ + +static void +gen_inheritance_die (binfo, context_die) + register tree binfo; + register dw_die_ref context_die; +{ + dw_die_ref die = new_die (DW_TAG_inheritance, context_die); + + add_type_attribute (die, BINFO_TYPE (binfo), 0, 0, context_die); + add_data_member_location_attribute (die, binfo); + + if (TREE_VIA_VIRTUAL (binfo)) + add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual); + if (TREE_VIA_PUBLIC (binfo)) + add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_public); + else if (TREE_VIA_PROTECTED (binfo)) + add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_protected); +} + +/* Generate a DIE for a class member. */ + +static void +gen_member_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register tree member; + + /* 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 `type' + function (above) will specifically avoid generating type DIEs for member + types *within* the list of member DIEs for this (containing) type execpt + 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. */ + + /* 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++) + gen_inheritance_die (TREE_VEC_ELT (bases, i), context_die); + } + + /* Now output info about the data members and type members. */ + for (member = TYPE_FIELDS (type); member; member = TREE_CHAIN (member)) + gen_decl_die (member, context_die); + + /* Now output info about the function members (if any). */ + for (member = TYPE_METHODS (type); member; member = TREE_CHAIN (member)) + gen_decl_die (member, context_die); +} + +/* Generate a DIE for a structure or union type. */ + +static void +gen_struct_or_union_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register dw_die_ref type_die = lookup_type_die (type); + register dw_die_ref scope_die = 0; + register int nested = 0; + + if (type_die && ! TYPE_SIZE (type)) + return; + + if (TYPE_CONTEXT (type) != NULL_TREE + && AGGREGATE_TYPE_P (TYPE_CONTEXT (type))) + nested = 1; + + scope_die = scope_die_for (type, context_die); + + if (! type_die || (nested && scope_die == comp_unit_die)) + /* First occurrence of type or toplevel definition of nested class. */ + { + register dw_die_ref old_die = type_die; + + type_die = new_die (TREE_CODE (type) == RECORD_TYPE + ? DW_TAG_structure_type : DW_TAG_union_type, + scope_die); + equate_type_number_to_die (type, type_die); + add_name_attribute (type_die, type_tag (type)); + if (old_die) + add_AT_die_ref (type_die, DW_AT_specification, old_die); + } + else + remove_AT (type_die, DW_AT_declaration); + + /* If we're not in the right context to be defining this type, defer to + avoid tricky recursion. */ + if (TYPE_SIZE (type) && decl_scope_depth > 0 && scope_die == comp_unit_die) + { + add_AT_flag (type_die, DW_AT_declaration, 1); + pend_type (type); + } + /* If this type has been completed, then give it a byte_size attribute and + then give a list of members. */ + else if (TYPE_SIZE (type)) + { + /* 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; + add_byte_size_attribute (type_die, type); + if (TYPE_STUB_DECL (type) != NULL_TREE) + add_src_coords_attributes (type_die, TYPE_STUB_DECL (type)); + + /* If the first reference to this type was as the return type of an + inline function, then it may not have a parent. Fix this now. */ + if (type_die->die_parent == NULL) + add_child_die (scope_die, type_die); + + push_decl_scope (type); + gen_member_die (type, type_die); + pop_decl_scope (); + + /* GNU extension: Record what type our vtable lives in. */ + if (TYPE_VFIELD (type)) + { + tree vtype = DECL_FCONTEXT (TYPE_VFIELD (type)); + + gen_type_die (vtype, context_die); + add_AT_die_ref (type_die, DW_AT_containing_type, + lookup_type_die (vtype)); + } + } + else + add_AT_flag (type_die, DW_AT_declaration, 1); +} + +/* Generate a DIE for a subroutine _type_. */ + +static void +gen_subroutine_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + register tree return_type = TREE_TYPE (type); + register dw_die_ref subr_die + = new_die (DW_TAG_subroutine_type, scope_die_for (type, context_die)); + + equate_type_number_to_die (type, subr_die); + add_prototyped_attribute (subr_die, type); + add_type_attribute (subr_die, return_type, 0, 0, context_die); + gen_formal_types_die (type, subr_die); +} + +/* Generate a DIE for a type definition */ + +static void +gen_typedef_die (decl, context_die) + register tree decl; + register dw_die_ref context_die; +{ + register dw_die_ref type_die; + register tree origin; + + if (TREE_ASM_WRITTEN (decl)) + return; + TREE_ASM_WRITTEN (decl) = 1; + + type_die = new_die (DW_TAG_typedef, scope_die_for (decl, context_die)); + origin = decl_ultimate_origin (decl); + if (origin != NULL) + add_abstract_origin_attribute (type_die, origin); + else + { + register tree type; + add_name_and_src_coords_attributes (type_die, decl); + if (DECL_ORIGINAL_TYPE (decl)) + { + type = DECL_ORIGINAL_TYPE (decl); + equate_type_number_to_die (TREE_TYPE (decl), type_die); + } + else + type = TREE_TYPE (decl); + add_type_attribute (type_die, type, TREE_READONLY (decl), + TREE_THIS_VOLATILE (decl), context_die); + } + + if (DECL_ABSTRACT (decl)) + equate_decl_number_to_die (decl, type_die); +} + +/* Generate a type description DIE. */ + +static void +gen_type_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + if (type == NULL_TREE || 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)) + return; + + if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && DECL_ORIGINAL_TYPE (TYPE_NAME (type))) + { + TREE_ASM_WRITTEN (type) = 1; + gen_decl_die (TYPE_NAME (type), context_die); + return; + } + + switch (TREE_CODE (type)) + { + case ERROR_MARK: + break; + + case POINTER_TYPE: + case REFERENCE_TYPE: + /* We must set TREE_ASM_WRITTEN in case this is a recursive type. This + ensures that the gen_type_die recursion will terminate even if the + type is recursive. Recursive types are possible in Ada. */ + /* ??? We could perhaps do this for all types before the switch + statement. */ + 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. */ + gen_type_die (TREE_TYPE (type), context_die); + break; + + case OFFSET_TYPE: + /* This code is used for C++ pointer-to-data-member types. + Output a description of the relevant class type. */ + gen_type_die (TYPE_OFFSET_BASETYPE (type), context_die); + + /* Output a description of the type of the object pointed to. */ + gen_type_die (TREE_TYPE (type), context_die); + + /* Now output a DIE to represent this pointer-to-data-member type + itself. */ + gen_ptr_to_mbr_type_die (type, context_die); + break; + + case SET_TYPE: + gen_type_die (TYPE_DOMAIN (type), context_die); + gen_set_type_die (type, context_die); + break; + + case FILE_TYPE: + gen_type_die (TREE_TYPE (type), context_die); + 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). */ + gen_type_die (TREE_TYPE (type), context_die); + gen_subroutine_type_die (type, context_die); + break; + + case METHOD_TYPE: + /* Force out return type (in case it wasn't forced out already). */ + gen_type_die (TREE_TYPE (type), context_die); + gen_subroutine_type_die (type, context_die); + break; + + case ARRAY_TYPE: + if (TYPE_STRING_FLAG (type) && TREE_CODE (TREE_TYPE (type)) == CHAR_TYPE) + { + gen_type_die (TREE_TYPE (type), context_die); + gen_string_type_die (type, context_die); + } + else + gen_array_type_die (type, context_die); + break; + + case ENUMERAL_TYPE: + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + /* 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) + && AGGREGATE_TYPE_P (TYPE_CONTEXT (type)) + && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type))) + { + gen_type_die (TYPE_CONTEXT (type), context_die); + + if (TREE_ASM_WRITTEN (TYPE_CONTEXT (type))) + return; + + /* If that failed, attach ourselves to the stub. */ + push_decl_scope (TYPE_CONTEXT (type)); + context_die = lookup_type_die (TYPE_CONTEXT (type)); + } + + if (TREE_CODE (type) == ENUMERAL_TYPE) + gen_enumeration_type_die (type, context_die); + else + gen_struct_or_union_type_die (type, context_die); + + if (TYPE_CONTEXT (type) + && AGGREGATE_TYPE_P (TYPE_CONTEXT (type)) + && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type))) + pop_decl_scope (); + + /* Don't set TREE_ASM_WRITTEN on an incomplete struct; we want to fix + it up if it is ever completed. gen_*_type_die will set it for us + when appropriate. */ + return; + + case VOID_TYPE: + case INTEGER_TYPE: + case REAL_TYPE: + case COMPLEX_TYPE: + case BOOLEAN_TYPE: + case CHAR_TYPE: + /* No DIEs needed for fundamental types. */ + break; + + case LANG_TYPE: + /* No Dwarf representation currently defined. */ + break; + + default: + abort (); + } + + TREE_ASM_WRITTEN (type) = 1; +} + +/* Generate a DIE for a tagged type instantiation. */ + +static void +gen_tagged_type_instantiation_die (type, context_die) + register tree type; + register dw_die_ref context_die; +{ + if (type == NULL_TREE || 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) + || !TREE_ASM_WRITTEN (type)) + abort (); + + switch (TREE_CODE (type)) + { + case ERROR_MARK: + break; + + case ENUMERAL_TYPE: + gen_inlined_enumeration_type_die (type, context_die); + break; + + case RECORD_TYPE: + gen_inlined_structure_type_die (type, context_die); + break; + + case UNION_TYPE: + case QUAL_UNION_TYPE: + gen_inlined_union_type_die (type, context_die); + break; + + default: + abort (); + } +} + +/* Generate a DW_TAG_lexical_block DIE followed by DIEs to represent all of the + things which are local to the given block. */ + +static void +gen_block_die (stmt, context_die, depth) + register tree stmt; + register dw_die_ref context_die; + int depth; +{ + register int must_output_die = 0; + register tree origin; + register tree decl; + register enum tree_code origin_code; + + /* Ignore blocks never really used to make RTL. */ + + if (stmt == NULL_TREE || !TREE_USED (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 DW_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 + /* We are in terse mode, so only local (nested) function + definitions count as "significant" local declarations. */ + for (decl = BLOCK_VARS (stmt); + decl != NULL; 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 DW_TAG_lexical_block + DIE for any block which contains no significant local declarations at + all. Rather, in such cases we just call `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 (must_output_die) + { + if (origin_code == FUNCTION_DECL) + gen_inlined_subroutine_die (stmt, context_die, depth); + else + gen_lexical_block_die (stmt, context_die, depth); + } + else + decls_for_scope (stmt, context_die, depth); +} + +/* Generate all of the decls declared within a given scope and (recursively) + all of its sub-blocks. */ + +static void +decls_for_scope (stmt, context_die, depth) + register tree stmt; + register dw_die_ref context_die; + int depth; +{ + register tree decl; + register tree subblocks; + + /* Ignore blocks never really used to make RTL. */ + if (stmt == NULL_TREE || ! TREE_USED (stmt)) + return; + + if (!BLOCK_ABSTRACT (stmt) && depth > 0) + next_block_number++; + + /* Output the DIEs to represent all of the data objects and typedefs + declared directly within this block but not within any nested + sub-blocks. Also, nested function and tag DIEs have been + generated with a parent of NULL; fix that up now. */ + for (decl = BLOCK_VARS (stmt); + decl != NULL; decl = TREE_CHAIN (decl)) + { + register dw_die_ref die; + + if (TREE_CODE (decl) == FUNCTION_DECL) + die = lookup_decl_die (decl); + else if (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl)) + die = lookup_type_die (TREE_TYPE (decl)); + else + die = NULL; + + if (die != NULL && die->die_parent == NULL) + add_child_die (context_die, die); + else + gen_decl_die (decl, context_die); + } + + /* Output the DIEs to represent all sub-blocks (and the items declared + therein) of this block. */ + for (subblocks = BLOCK_SUBBLOCKS (stmt); + subblocks != NULL; + subblocks = BLOCK_CHAIN (subblocks)) + gen_block_die (subblocks, context_die, depth + 1); +} + +/* Is this a typedef we can avoid emitting? */ + +static inline int +is_redundant_typedef (decl) + register 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; +} + +/* Generate Dwarf debug information for a decl described by DECL. */ + +static void +gen_decl_die (decl, context_die) + register tree decl; + register dw_die_ref context_die; +{ + register tree origin; + + /* 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 this ..._DECL node is marked to be ignored, then ignore it. But don't + ignore a function definition, since that would screw up our count of + blocks, and that in turn will completely screw up the labels we will + reference in subsequent DW_AT_low_pc and DW_AT_high_pc attributes (for + subsequent blocks). */ + if (DECL_IGNORED_P (decl) && TREE_CODE (decl) != FUNCTION_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: + /* Don't output any DIEs to represent mere function declarations, + unless they are class members or explicit block externs. */ + if (DECL_INITIAL (decl) == NULL_TREE && DECL_CONTEXT (decl) == NULL_TREE + && (current_function_decl == NULL_TREE || ! DECL_ARTIFICIAL (decl))) + break; + + if (debug_info_level > DINFO_LEVEL_TERSE) + { + /* Before we describe the FUNCTION_DECL itself, make sure that we + have described its return type. */ + gen_type_die (TREE_TYPE (TREE_TYPE (decl)), context_die); + + /* And its containing type. */ + origin = decl_class_context (decl); + if (origin != NULL_TREE) + gen_type_die (origin, context_die); + + /* And its virtual context. */ + if (DECL_VINDEX (decl) != NULL_TREE) + gen_type_die (DECL_CONTEXT (decl), context_die); + } + + /* Now output a DIE to represent the function itself. */ + gen_subprogram_die (decl, context_die); + break; + + case TYPE_DECL: + /* If we are in terse mode, don't generate any DIEs to represent any + actual typedefs. */ + if (debug_info_level <= DINFO_LEVEL_TERSE) + break; + + /* 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) + DW_TAG_structure_type, DW_TAG_union_type, or DW_TAG_enumeration_type + DIE here. */ + if (TYPE_DECL_IS_STUB (decl) && DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE) + { + gen_tagged_type_instantiation_die (TREE_TYPE (decl), context_die); + break; + } + + if (is_redundant_typedef (decl)) + gen_type_die (TREE_TYPE (decl), context_die); + else + /* Output a DIE to represent the typedef itself. */ + gen_typedef_die (decl, context_die); + break; + + case LABEL_DECL: + if (debug_info_level >= DINFO_LEVEL_NORMAL) + gen_label_die (decl, context_die); + break; + + case VAR_DECL: + /* 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. */ + gen_type_die (TREE_TYPE (decl), context_die); + + /* And its containing type. */ + origin = decl_class_context (decl); + if (origin != NULL_TREE) + gen_type_die (origin, context_die); + + /* 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. */ + origin = decl_ultimate_origin (decl); + if (origin != NULL_TREE && TREE_CODE (origin) == PARM_DECL) + gen_formal_parameter_die (decl, context_die); + else + gen_variable_die (decl, context_die); + break; + + case FIELD_DECL: + /* Ignore the nameless fields that are used to skip bits, but + handle C++ anonymous unions. */ + if (DECL_NAME (decl) != NULL_TREE + || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE) + { + gen_type_die (member_declared_type (decl), context_die); + gen_field_die (decl, context_die); + } + break; + + case PARM_DECL: + gen_type_die (TREE_TYPE (decl), context_die); + gen_formal_parameter_die (decl, context_die); + break; + + default: + abort (); + } +} + +/* Write the debugging output for DECL. */ + +void +dwarf2out_decl (decl) + register tree decl; +{ + register dw_die_ref context_die = comp_unit_die; + + if (TREE_CODE (decl) == ERROR_MARK) + return; + + /* If this ..._DECL node is marked to be ignored, then ignore it. We gotta + hope that the node in question doesn't represent a function definition. + If it does, then totally ignoring it is bound to screw up our count of + blocks, and that in turn will completely screw up the labels we will + reference in subsequent DW_AT_low_pc and DW_AT_high_pc attributes (for + subsequent blocks). (It's too bad that BLOCK nodes don't carry their + own sequence numbers with them!) */ + if (DECL_IGNORED_P (decl)) + { + if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_INITIAL (decl) != NULL) + abort (); + + 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 wil 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 we're a nested function, initially use a parent of NULL; if we're + a plain function, this will be fixed up in decls_for_scope. If + we're a method, it will be ignored, since we already have a DIE. */ + if (decl_function_context (decl)) + context_die = NULL; + + 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 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. */ + if (DECL_SOURCE_LINE (decl) == 0) + { + /* OK, we need to generate one for `bool' so GDB knows what type + comparisons have. */ + if ((get_AT_unsigned (comp_unit_die, DW_AT_language) + == DW_LANG_C_plus_plus) + && TREE_CODE (TREE_TYPE (decl)) == BOOLEAN_TYPE) + modified_type_die (TREE_TYPE (decl), 0, 0, NULL); + + return; + } + + /* If we are in terse mode, don't generate any DIEs for types. */ + if (debug_info_level <= DINFO_LEVEL_TERSE) + return; + + /* If we're a function-scope tag, initially use a parent of NULL; + this will be fixed up in decls_for_scope. */ + if (decl_function_context (decl)) + context_die = NULL; + + break; + + default: + return; + } + + gen_decl_die (decl, context_die); + output_pending_types_for_scope (comp_unit_die); +} + +/* Output a marker (i.e. a label) for the beginning of the generated code for + a lexical block. */ + +void +dwarf2out_begin_block (blocknum) + register unsigned blocknum; +{ + function_section (current_function_decl); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum); +} + +/* Output a marker (i.e. a label) for the end of the generated code for a + lexical block. */ + +void +dwarf2out_end_block (blocknum) + register unsigned blocknum; +{ + function_section (current_function_decl); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum); +} + +/* Output a marker (i.e. a label) at a point in the assembly code which + corresponds to a given source level label. */ + +void +dwarf2out_label (insn) + register rtx insn; +{ + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + if (debug_info_level >= DINFO_LEVEL_NORMAL) + { + function_section (current_function_decl); + sprintf (label, INSN_LABEL_FMT, current_funcdef_number); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, label, + (unsigned) INSN_UID (insn)); + } +} + +/* Lookup a filename (in the list of filenames that we know about here in + dwarf2out.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 + files numbers (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. + In order to speed up searches, we remember the index of the filename + was looked up last. This handles the majority of all searches. */ + +static unsigned +lookup_filename (file_name) + char *file_name; +{ + static unsigned last_file_lookup_index = 0; + register unsigned i; + + /* Check to see if the file name that was searched on the previous call + matches this file name. If so, return the index. */ + if (last_file_lookup_index != 0) + if (strcmp (file_name, file_table[last_file_lookup_index]) == 0) + return last_file_lookup_index; + + /* Didn't match the previous lookup, search the table */ + for (i = 1; i < file_table_in_use; ++i) + if (strcmp (file_name, file_table[i]) == 0) + { + last_file_lookup_index = i; + return i; + } + + /* 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 (file_table_in_use == file_table_allocated) + { + file_table_allocated += FILE_TABLE_INCREMENT; + file_table + = (char **) xrealloc (file_table, + file_table_allocated * sizeof (char *)); + } + + /* Add the new entry to the end of the filename table. */ + file_table[file_table_in_use] = xstrdup (file_name); + last_file_lookup_index = file_table_in_use++; + + return last_file_lookup_index; +} + +/* Output a label to mark the beginning of a source code line entry + and record information relating to this source line, in + 'line_info_table' for later output of the .debug_line section. */ + +void +dwarf2out_line (filename, line) + register char *filename; + register unsigned line; +{ + if (debug_info_level >= DINFO_LEVEL_NORMAL) + { + function_section (current_function_decl); + + if (DECL_SECTION_NAME (current_function_decl)) + { + register dw_separate_line_info_ref line_info; + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, SEPARATE_LINE_CODE_LABEL, + separate_line_info_table_in_use); + fputc ('\n', asm_out_file); + + /* expand the line info table if necessary */ + if (separate_line_info_table_in_use + == separate_line_info_table_allocated) + { + separate_line_info_table_allocated += LINE_INFO_TABLE_INCREMENT; + separate_line_info_table + = (dw_separate_line_info_ref) + xrealloc (separate_line_info_table, + separate_line_info_table_allocated + * sizeof (dw_separate_line_info_entry)); + } + + /* Add the new entry at the end of the line_info_table. */ + line_info + = &separate_line_info_table[separate_line_info_table_in_use++]; + line_info->dw_file_num = lookup_filename (filename); + line_info->dw_line_num = line; + line_info->function = current_funcdef_number; + } + else + { + register dw_line_info_ref line_info; + + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, LINE_CODE_LABEL, + line_info_table_in_use); + fputc ('\n', asm_out_file); + + /* Expand the line info table if necessary. */ + if (line_info_table_in_use == line_info_table_allocated) + { + line_info_table_allocated += LINE_INFO_TABLE_INCREMENT; + line_info_table + = (dw_line_info_ref) + xrealloc (line_info_table, + (line_info_table_allocated + * sizeof (dw_line_info_entry))); + } + + /* Add the new entry at the end of the line_info_table. */ + line_info = &line_info_table[line_info_table_in_use++]; + line_info->dw_file_num = lookup_filename (filename); + line_info->dw_line_num = line; + } + } +} + +/* Record the beginning of a new source file, for later output + of the .debug_macinfo section. At present, unimplemented. */ + +void +dwarf2out_start_source_file (filename) + register char *filename ATTRIBUTE_UNUSED; +{ +} + +/* Record the end of a source file, for later output + of the .debug_macinfo section. At present, unimplemented. */ + +void +dwarf2out_end_source_file () +{ +} + +/* 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. */ + +void +dwarf2out_define (lineno, buffer) + register unsigned lineno; + register char *buffer; +{ + static int initialized = 0; + if (!initialized) + { + dwarf2out_start_source_file (primary_filename); + initialized = 1; + } +} + +/* 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. */ + +void +dwarf2out_undef (lineno, buffer) + register unsigned lineno ATTRIBUTE_UNUSED; + register char *buffer ATTRIBUTE_UNUSED; +{ +} + +/* Set up for Dwarf output at the start of compilation. */ + +void +dwarf2out_init (asm_out_file, main_input_filename) + register FILE *asm_out_file; + register char *main_input_filename; +{ + /* Remember the name of the primary input file. */ + primary_filename = main_input_filename; + + /* Allocate the initial hunk of the file_table. */ + file_table = (char **) xmalloc (FILE_TABLE_INCREMENT * sizeof (char *)); + bzero ((char *) file_table, FILE_TABLE_INCREMENT * sizeof (char *)); + file_table_allocated = FILE_TABLE_INCREMENT; + + /* Skip the first entry - file numbers begin at 1. */ + file_table_in_use = 1; + + /* Allocate the initial hunk of the decl_die_table. */ + decl_die_table + = (dw_die_ref *) xmalloc (DECL_DIE_TABLE_INCREMENT * sizeof (dw_die_ref)); + bzero ((char *) decl_die_table, + DECL_DIE_TABLE_INCREMENT * sizeof (dw_die_ref)); + decl_die_table_allocated = DECL_DIE_TABLE_INCREMENT; + decl_die_table_in_use = 0; + + /* Allocate the initial hunk of the decl_scope_table. */ + decl_scope_table + = (decl_scope_node *) xmalloc (DECL_SCOPE_TABLE_INCREMENT + * sizeof (decl_scope_node)); + bzero ((char *) decl_scope_table, + DECL_SCOPE_TABLE_INCREMENT * sizeof (decl_scope_node)); + decl_scope_table_allocated = DECL_SCOPE_TABLE_INCREMENT; + decl_scope_depth = 0; + + /* Allocate the initial hunk of the abbrev_die_table. */ + abbrev_die_table + = (dw_die_ref *) xmalloc (ABBREV_DIE_TABLE_INCREMENT + * sizeof (dw_die_ref)); + bzero ((char *) abbrev_die_table, + ABBREV_DIE_TABLE_INCREMENT * sizeof (dw_die_ref)); + abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT; + /* Zero-th entry is allocated, but unused */ + abbrev_die_table_in_use = 1; + + /* Allocate the initial hunk of the line_info_table. */ + line_info_table + = (dw_line_info_ref) xmalloc (LINE_INFO_TABLE_INCREMENT + * sizeof (dw_line_info_entry)); + bzero ((char *) line_info_table, + LINE_INFO_TABLE_INCREMENT * sizeof (dw_line_info_entry)); + line_info_table_allocated = LINE_INFO_TABLE_INCREMENT; + /* Zero-th entry is allocated, but unused */ + line_info_table_in_use = 1; + + /* Generate the initial DIE for the .debug section. Note that the (string) + value given in the DW_AT_name attribute of the DW_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. */ + gen_compile_unit_die (main_input_filename); + + ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0); +} + +/* Output stuff that dwarf requires at the end of every file, + and generate the DWARF-2 debugging info. */ + +void +dwarf2out_finish () +{ + limbo_die_node *node, *next_node; + dw_die_ref die; + dw_attr_ref a; + + /* Traverse the limbo die list, and add parent/child links. The only + dies without parents that should be here are concrete instances of + inline functions, and the comp_unit_die. We can ignore the comp_unit_die. + For concrete instances, we can get the parent die from the abstract + instance. */ + for (node = limbo_die_list; node; node = next_node) + { + next_node = node->next; + die = node->die; + + if (die->die_parent == NULL) + { + a = get_AT (die, DW_AT_abstract_origin); + if (a) + add_child_die (a->dw_attr_val.v.val_die_ref->die_parent, die); + else if (die == comp_unit_die) + ; + else + abort (); + } + free (node); + } + + /* Traverse the DIE tree and add sibling attributes to those DIE's + that have children. */ + add_sibling_attributes (comp_unit_die); + + /* Output a terminator label for the .text section. */ + fputc ('\n', asm_out_file); + ASM_OUTPUT_SECTION (asm_out_file, TEXT_SECTION); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, TEXT_END_LABEL, 0); + +#if 0 + /* Output a terminator label for the .data section. */ + fputc ('\n', asm_out_file); + ASM_OUTPUT_SECTION (asm_out_file, DATA_SECTION); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, DATA_END_LABEL, 0); + + /* Output a terminator label for the .bss section. */ + fputc ('\n', asm_out_file); + ASM_OUTPUT_SECTION (asm_out_file, BSS_SECTION); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BSS_END_LABEL, 0); +#endif + + /* Output the source line correspondence table. */ + if (line_info_table_in_use > 1 || separate_line_info_table_in_use) + { + fputc ('\n', asm_out_file); + ASM_OUTPUT_SECTION (asm_out_file, DEBUG_LINE_SECTION); + output_line_info (); + + /* We can only use the low/high_pc attributes if all of the code + was in .text. */ + if (separate_line_info_table_in_use == 0) + { + add_AT_lbl_id (comp_unit_die, DW_AT_low_pc, + stripattributes (TEXT_SECTION)); + add_AT_lbl_id (comp_unit_die, DW_AT_high_pc, text_end_label); + } + + add_AT_section_offset (comp_unit_die, DW_AT_stmt_list, DEBUG_LINE_SECTION); + } + + /* Output the abbreviation table. */ + fputc ('\n', asm_out_file); + ASM_OUTPUT_SECTION (asm_out_file, ABBREV_SECTION); + build_abbrev_table (comp_unit_die); + output_abbrev_section (); + + /* Initialize the beginning DIE offset - and calculate sizes/offsets. */ + next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE; + calc_die_sizes (comp_unit_die); + + /* Output debugging information. */ + fputc ('\n', asm_out_file); + ASM_OUTPUT_SECTION (asm_out_file, DEBUG_INFO_SECTION); + output_compilation_unit_header (); + output_die (comp_unit_die); + + if (pubname_table_in_use) + { + /* Output public names table. */ + fputc ('\n', asm_out_file); + ASM_OUTPUT_SECTION (asm_out_file, PUBNAMES_SECTION); + output_pubnames (); + } + + if (fde_table_in_use) + { + /* Output the address range information. */ + fputc ('\n', asm_out_file); + ASM_OUTPUT_SECTION (asm_out_file, ARANGES_SECTION); + output_aranges (); + } +} +#endif /* DWARF2_DEBUGGING_INFO */ diff --git a/gcc_arm/dwarfout.c b/gcc_arm/dwarfout.c new file mode 100755 index 0000000..6b53979 --- /dev/null +++ b/gcc_arm/dwarfout.c @@ -0,0 +1,6030 @@ +/* Output Dwarf format symbol table information from the GNU C compiler. + Copyright (C) 1992, 1993, 95-97, 1998 Free Software Foundation, Inc. + Contributed by Ron Guilmette (rfg@monkeys.com) of Network Computing Devices. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" + +#ifdef DWARF_DEBUGGING_INFO +#include "system.h" +#include "dwarf.h" +#include "tree.h" +#include "flags.h" +#include "rtl.h" +#include "hard-reg-set.h" +#include "insn-config.h" +#include "reload.h" +#include "output.h" +#include "defaults.h" +#include "dwarfout.h" +#include "toplev.h" + +#if defined(DWARF_TIMESTAMPS) +#if !defined(POSIX) +extern time_t time PROTO ((time_t *)); /* FIXME: use NEED_DECLARATION_TIME */ +#endif /* !defined(POSIX) */ +#endif /* defined(DWARF_TIMESTAMPS) */ + +/* We cannot use in GCC source, since that would include + GCC's assert.h, which may not be compatible with the host compiler. */ +#undef assert +#ifdef NDEBUG +# define assert(e) +#else +# define assert(e) do { if (! (e)) abort (); } while (0) +#endif + +extern char *getpwd PROTO((void)); + +/* IMPORTANT NOTE: Please see the file README.DWARF for important details + regarding the GNU implementation of Dwarf. */ + +/* 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. */ + +#if !defined(__GNUC__) || (NDEBUG != 1) +#define inline +#endif + +/* 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 non-zero 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 non-zero for all incomplete tagged types. +*/ + +#define TYPE_USED_FOR_FUNCTION(tagged_type) (TYPE_SIZE (tagged_type) == 0) + +/* Define a macro which returns non-zero 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)))) + +extern int flag_traditional; +extern char *version_string; +extern char *language_string; + +/* Maximum size (in bytes) of an artificially generated label. */ + +#define MAX_ARTIFICIAL_LABEL_BYTES 30 + +/* Make sure we know the sizes of the various types dwarf can describe. + These are only defaults. If the sizes are different for your target, + you should override these values by defining the appropriate symbols + in your tm.h file. */ + +#ifndef CHAR_TYPE_SIZE +#define CHAR_TYPE_SIZE BITS_PER_UNIT +#endif + +#ifndef SHORT_TYPE_SIZE +#define SHORT_TYPE_SIZE (BITS_PER_UNIT * 2) +#endif + +#ifndef INT_TYPE_SIZE +#define INT_TYPE_SIZE BITS_PER_WORD +#endif + +#ifndef LONG_TYPE_SIZE +#define LONG_TYPE_SIZE BITS_PER_WORD +#endif + +#ifndef LONG_LONG_TYPE_SIZE +#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2) +#endif + +#ifndef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE INT_TYPE_SIZE +#endif + +#ifndef WCHAR_UNSIGNED +#define WCHAR_UNSIGNED 0 +#endif + +#ifndef FLOAT_TYPE_SIZE +#define FLOAT_TYPE_SIZE BITS_PER_WORD +#endif + +#ifndef DOUBLE_TYPE_SIZE +#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2) +#endif + +#ifndef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2) +#endif + +/* Structure to keep track of source filenames. */ + +struct filename_entry { + unsigned number; + 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 char *primary_filename; + +/* Pointer to the most recent filename for which we produced some line info. */ + +static char *last_filename; + +/* For Dwarf output, we must assign lexical-blocks id numbers + in the order in which their beginnings are encountered. + We output Dwarf debugging info that refers to the beginnings + and ends of the ranges of code for each lexical block with + assembler labels ..Bn and ..Bn.e, where n is the block number. + The labels themselves are generated in final.c, which assigns + numbers to the blocks in the same way. */ + +static unsigned next_block_number = 2; + +/* 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 + +/* Non-zero 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 + +/* 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; + +/* The number of the current function definition that we are generating + debugging information for. These numbers range from 1 up to the maximum + number of function definitions contained within the current compilation + unit. These numbers are used to create unique labels for various things + contained within various function definitions. */ + +static unsigned current_funcdef_number = 1; + +/* 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 char *dwarf_tag_name PROTO((unsigned)); +static char *dwarf_attr_name PROTO((unsigned)); +static char *dwarf_stack_op_name PROTO((unsigned)); +static char *dwarf_typemod_name PROTO((unsigned)); +static char *dwarf_fmt_byte_name PROTO((unsigned)); +static char *dwarf_fund_type_name PROTO((unsigned)); +static tree decl_ultimate_origin PROTO((tree)); +static tree block_ultimate_origin PROTO((tree)); +static tree decl_class_context PROTO((tree)); +#if 0 +static void output_unsigned_leb128 PROTO((unsigned long)); +static void output_signed_leb128 PROTO((long)); +#endif +static inline int is_body_block PROTO((tree)); +static int fundamental_type_code PROTO((tree)); +static tree root_type_1 PROTO((tree, int)); +static tree root_type PROTO((tree)); +static void write_modifier_bytes_1 PROTO((tree, int, int, int)); +static void write_modifier_bytes PROTO((tree, int, int)); +static inline int type_is_fundamental PROTO((tree)); +static void equate_decl_number_to_die_number PROTO((tree)); +static inline void equate_type_number_to_die_number PROTO((tree)); +static void output_reg_number PROTO((rtx)); +static void output_mem_loc_descriptor PROTO((rtx)); +static void output_loc_descriptor PROTO((rtx)); +static void output_bound_representation PROTO((tree, unsigned, int)); +static void output_enumeral_list PROTO((tree)); +static inline unsigned ceiling PROTO((unsigned, unsigned)); +static inline tree field_type PROTO((tree)); +static inline unsigned simple_type_align_in_bits PROTO((tree)); +static inline unsigned simple_type_size_in_bits PROTO((tree)); +static unsigned field_byte_offset PROTO((tree)); +static inline void sibling_attribute PROTO((void)); +static void location_attribute PROTO((rtx)); +static void data_member_location_attribute PROTO((tree)); +static void const_value_attribute PROTO((rtx)); +static void location_or_const_value_attribute PROTO((tree)); +static inline void name_attribute PROTO((char *)); +static inline void fund_type_attribute PROTO((unsigned)); +static void mod_fund_type_attribute PROTO((tree, int, int)); +static inline void user_def_type_attribute PROTO((tree)); +static void mod_u_d_type_attribute PROTO((tree, int, int)); +#ifdef USE_ORDERING_ATTRIBUTE +static inline void ordering_attribute PROTO((unsigned)); +#endif /* defined(USE_ORDERING_ATTRIBUTE) */ +static void subscript_data_attribute PROTO((tree)); +static void byte_size_attribute PROTO((tree)); +static inline void bit_offset_attribute PROTO((tree)); +static inline void bit_size_attribute PROTO((tree)); +static inline void element_list_attribute PROTO((tree)); +static inline void stmt_list_attribute PROTO((char *)); +static inline void low_pc_attribute PROTO((char *)); +static inline void high_pc_attribute PROTO((char *)); +static inline void body_begin_attribute PROTO((char *)); +static inline void body_end_attribute PROTO((char *)); +static inline void language_attribute PROTO((unsigned)); +static inline void member_attribute PROTO((tree)); +#if 0 +static inline void string_length_attribute PROTO((tree)); +#endif +static inline void comp_dir_attribute PROTO((char *)); +static inline void sf_names_attribute PROTO((char *)); +static inline void src_info_attribute PROTO((char *)); +static inline void mac_info_attribute PROTO((char *)); +static inline void prototyped_attribute PROTO((tree)); +static inline void producer_attribute PROTO((char *)); +static inline void inline_attribute PROTO((tree)); +static inline void containing_type_attribute PROTO((tree)); +static inline void abstract_origin_attribute PROTO((tree)); +#ifdef DWARF_DECL_COORDINATES +static inline void src_coords_attribute PROTO((unsigned, unsigned)); +#endif /* defined(DWARF_DECL_COORDINATES) */ +static inline void pure_or_virtual_attribute PROTO((tree)); +static void name_and_src_coords_attributes PROTO((tree)); +static void type_attribute PROTO((tree, int, int)); +static char *type_tag PROTO((tree)); +static inline void dienum_push PROTO((void)); +static inline void dienum_pop PROTO((void)); +static inline tree member_declared_type PROTO((tree)); +static char *function_start_label PROTO((tree)); +static void output_array_type_die PROTO((void *)); +static void output_set_type_die PROTO((void *)); +#if 0 +static void output_entry_point_die PROTO((void *)); +#endif +static void output_inlined_enumeration_type_die PROTO((void *)); +static void output_inlined_structure_type_die PROTO((void *)); +static void output_inlined_union_type_die PROTO((void *)); +static void output_enumeration_type_die PROTO((void *)); +static void output_formal_parameter_die PROTO((void *)); +static void output_global_subroutine_die PROTO((void *)); +static void output_global_variable_die PROTO((void *)); +static void output_label_die PROTO((void *)); +static void output_lexical_block_die PROTO((void *)); +static void output_inlined_subroutine_die PROTO((void *)); +static void output_local_variable_die PROTO((void *)); +static void output_member_die PROTO((void *)); +#if 0 +static void output_pointer_type_die PROTO((void *)); +static void output_reference_type_die PROTO((void *)); +#endif +static void output_ptr_to_mbr_type_die PROTO((void *)); +static void output_compile_unit_die PROTO((void *)); +static void output_string_type_die PROTO((void *)); +static void output_inheritance_die PROTO((void *)); +static void output_structure_type_die PROTO((void *)); +static void output_local_subroutine_die PROTO((void *)); +static void output_subroutine_type_die PROTO((void *)); +static void output_typedef_die PROTO((void *)); +static void output_union_type_die PROTO((void *)); +static void output_unspecified_parameters_die PROTO((void *)); +static void output_padded_null_die PROTO((void *)); +static void output_die PROTO((void (*) PROTO((void *)), void *)); +static void end_sibling_chain PROTO((void)); +static void output_formal_types PROTO((tree)); +static void pend_type PROTO((tree)); +static int type_ok_for_scope PROTO((tree, tree)); +static void output_pending_types_for_scope PROTO((tree)); +static void output_type PROTO((tree, tree)); +static void output_tagged_type_instantiation PROTO((tree)); +static void output_block PROTO((tree, int)); +static void output_decls_for_scope PROTO((tree, int)); +static void output_decl PROTO((tree, tree)); +static void shuffle_filename_entry PROTO((filename_entry *)); +static void generate_new_sfname_entry PROTO((void)); +static unsigned lookup_filename PROTO((char *)); +static void generate_srcinfo_entry PROTO((unsigned, unsigned)); +static void generate_macinfo_entry PROTO((char *, char *)); +static int is_pseudo_reg PROTO((rtx)); +static tree type_main_variant PROTO((tree)); +static int is_tagged_type PROTO((tree)); +static int is_redundant_typedef PROTO((tree)); + +/* 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 ".file" +#endif +#ifndef VERSION_ASM_OP +#define VERSION_ASM_OP ".version" +#endif +#ifndef UNALIGNED_SHORT_ASM_OP +#define UNALIGNED_SHORT_ASM_OP ".2byte" +#endif +#ifndef UNALIGNED_INT_ASM_OP +#define UNALIGNED_INT_ASM_OP ".4byte" +#endif +#ifndef ASM_BYTE_OP +#define ASM_BYTE_OP ".byte" +#endif +#ifndef SET_ASM_OP +#define SET_ASM_OP ".set" +#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 ".section" +#endif +#ifndef POPSECTION_ASM_OP +#define POPSECTION_ASM_OP ".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 "\t%s\t%s\n" +#endif + +#ifndef DEBUG_SECTION +#define DEBUG_SECTION ".debug" +#endif +#ifndef LINE_SECTION +#define LINE_SECTION ".line" +#endif +#ifndef SFNAMES_SECTION +#define SFNAMES_SECTION ".debug_sfnames" +#endif +#ifndef SRCINFO_SECTION +#define SRCINFO_SECTION ".debug_srcinfo" +#endif +#ifndef MACINFO_SECTION +#define MACINFO_SECTION ".debug_macinfo" +#endif +#ifndef PUBNAMES_SECTION +#define PUBNAMES_SECTION ".debug_pubnames" +#endif +#ifndef ARANGES_SECTION +#define ARANGES_SECTION ".debug_aranges" +#endif +#ifndef TEXT_SECTION +#define TEXT_SECTION ".text" +#endif +#ifndef DATA_SECTION +#define DATA_SECTION ".data" +#endif +#ifndef DATA1_SECTION +#define DATA1_SECTION ".data1" +#endif +#ifndef RODATA_SECTION +#define RODATA_SECTION ".rodata" +#endif +#ifndef RODATA1_SECTION +#define RODATA1_SECTION ".rodata1" +#endif +#ifndef BSS_SECTION +#define BSS_SECTION ".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 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 INSN_LABEL_FMT +#define INSN_LABEL_FMT "*.L_I%u_%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 DERIV_BEGIN_LABEL_FMT +#define DERIV_BEGIN_LABEL_FMT "*.L_d%u" +#endif +#ifndef DERIV_END_LABEL_FMT +#define DERIV_END_LABEL_FMT "*.L_d%u_e" +#endif +#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 +#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), "\t%s\n", POPSECTION_ASM_OP) +#endif + +#ifndef ASM_OUTPUT_DWARF_DELTA2 +#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2) \ + do { fprintf ((FILE), "\t%s\t", UNALIGNED_SHORT_ASM_OP); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, "-"); \ + assemble_name (FILE, LABEL2); \ + fprintf (FILE, "\n"); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_DELTA4 +#define ASM_OUTPUT_DWARF_DELTA4(FILE,LABEL1,LABEL2) \ + do { fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, "-"); \ + assemble_name (FILE, LABEL2); \ + fprintf (FILE, "\n"); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_TAG +#define ASM_OUTPUT_DWARF_TAG(FILE,TAG) \ + do { \ + fprintf ((FILE), "\t%s\t0x%x", \ + UNALIGNED_SHORT_ASM_OP, (unsigned) TAG); \ + if (flag_debug_asm) \ + fprintf ((FILE), "\t%s %s", \ + ASM_COMMENT_START, dwarf_tag_name (TAG)); \ + fputc ('\n', (FILE)); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_ATTRIBUTE +#define ASM_OUTPUT_DWARF_ATTRIBUTE(FILE,ATTR) \ + do { \ + fprintf ((FILE), "\t%s\t0x%x", \ + UNALIGNED_SHORT_ASM_OP, (unsigned) ATTR); \ + if (flag_debug_asm) \ + fprintf ((FILE), "\t%s %s", \ + ASM_COMMENT_START, dwarf_attr_name (ATTR)); \ + fputc ('\n', (FILE)); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_STACK_OP +#define ASM_OUTPUT_DWARF_STACK_OP(FILE,OP) \ + do { \ + fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) OP); \ + if (flag_debug_asm) \ + fprintf ((FILE), "\t%s %s", \ + ASM_COMMENT_START, dwarf_stack_op_name (OP)); \ + fputc ('\n', (FILE)); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_FUND_TYPE +#define ASM_OUTPUT_DWARF_FUND_TYPE(FILE,FT) \ + do { \ + fprintf ((FILE), "\t%s\t0x%x", \ + UNALIGNED_SHORT_ASM_OP, (unsigned) FT); \ + if (flag_debug_asm) \ + fprintf ((FILE), "\t%s %s", \ + ASM_COMMENT_START, dwarf_fund_type_name (FT)); \ + fputc ('\n', (FILE)); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_FMT_BYTE +#define ASM_OUTPUT_DWARF_FMT_BYTE(FILE,FMT) \ + do { \ + fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) FMT); \ + if (flag_debug_asm) \ + fprintf ((FILE), "\t%s %s", \ + ASM_COMMENT_START, dwarf_fmt_byte_name (FMT)); \ + fputc ('\n', (FILE)); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_TYPE_MODIFIER +#define ASM_OUTPUT_DWARF_TYPE_MODIFIER(FILE,MOD) \ + do { \ + fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) MOD); \ + if (flag_debug_asm) \ + fprintf ((FILE), "\t%s %s", \ + ASM_COMMENT_START, dwarf_typemod_name (MOD)); \ + fputc ('\n', (FILE)); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_ADDR +#define ASM_OUTPUT_DWARF_ADDR(FILE,LABEL) \ + do { fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP); \ + assemble_name (FILE, LABEL); \ + fprintf (FILE, "\n"); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_ADDR_CONST +#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,RTX) \ + do { \ + fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP); \ + output_addr_const ((FILE), (RTX)); \ + fputc ('\n', (FILE)); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_REF +#define ASM_OUTPUT_DWARF_REF(FILE,LABEL) \ + do { fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP); \ + assemble_name (FILE, LABEL); \ + fprintf (FILE, "\n"); \ + } while (0) +#endif + +#ifndef ASM_OUTPUT_DWARF_DATA1 +#define ASM_OUTPUT_DWARF_DATA1(FILE,VALUE) \ + fprintf ((FILE), "\t%s\t0x%x\n", ASM_BYTE_OP, VALUE) +#endif + +#ifndef ASM_OUTPUT_DWARF_DATA2 +#define ASM_OUTPUT_DWARF_DATA2(FILE,VALUE) \ + fprintf ((FILE), "\t%s\t0x%x\n", UNALIGNED_SHORT_ASM_OP, (unsigned short) VALUE) +#endif + +#ifndef ASM_OUTPUT_DWARF_DATA4 +#define ASM_OUTPUT_DWARF_DATA4(FILE,VALUE) \ + fprintf ((FILE), "\t%s\t0x%x\n", UNALIGNED_INT_ASM_OP, (unsigned) VALUE) +#endif + +#ifndef ASM_OUTPUT_DWARF_DATA8 +#define ASM_OUTPUT_DWARF_DATA8(FILE,HIGH_VALUE,LOW_VALUE) \ + do { \ + if (WORDS_BIG_ENDIAN) \ + { \ + fprintf ((FILE), "\t%s\t0x%x\n", UNALIGNED_INT_ASM_OP, HIGH_VALUE); \ + fprintf ((FILE), "\t%s\t0x%x\n", UNALIGNED_INT_ASM_OP, LOW_VALUE);\ + } \ + else \ + { \ + fprintf ((FILE), "\t%s\t0x%x\n", UNALIGNED_INT_ASM_OP, LOW_VALUE);\ + fprintf ((FILE), "\t%s\t0x%x\n", UNALIGNED_INT_ASM_OP, HIGH_VALUE); \ + } \ + } while (0) +#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 defintion 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 + + +/************************ general utility functions **************************/ + +inline static int +is_pseudo_reg (rtl) + register rtx rtl; +{ + return (((GET_CODE (rtl) == REG) && (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)) + || ((GET_CODE (rtl) == SUBREG) + && (REGNO (XEXP (rtl, 0)) >= FIRST_PSEUDO_REGISTER))); +} + +inline static tree +type_main_variant (type) + register 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 non-zero if the given type node represents a tagged type. */ + +inline static int +is_tagged_type (type) + register tree type; +{ + register enum tree_code code = TREE_CODE (type); + + return (code == RECORD_TYPE || code == UNION_TYPE + || code == QUAL_UNION_TYPE || code == ENUMERAL_TYPE); +} + +static char * +dwarf_tag_name (tag) + register 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_"; + } +} + +static char * +dwarf_attr_name (attr) + register 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_"; + } +} + +static char * +dwarf_stack_op_name (op) + register 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_"; + } +} + +static char * +dwarf_typemod_name (mod) + register 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_"; + } +} + +static char * +dwarf_fmt_byte_name (fmt) + register 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_"; + } +} + +static char * +dwarf_fund_type_name (ft) + register 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_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_"; + } +} + +/* 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) + register 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) + register tree block; +{ + register tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block); + + if (immediate_origin == NULL) + return NULL; + else + { + register tree ret_val; + register 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 && TREE_CODE_CLASS (TREE_CODE (context)) != 't') + context = NULL_TREE; + + return context; +} + +#if 0 +static void +output_unsigned_leb128 (value) + register unsigned long value; +{ + register unsigned long orig_value = value; + + do + { + register unsigned byte = (value & 0x7f); + + value >>= 7; + if (value != 0) /* more bytes to follow */ + byte |= 0x80; + fprintf (asm_out_file, "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) byte); + if (flag_debug_asm && value == 0) + fprintf (asm_out_file, "\t%s ULEB128 number - value = %lu", + ASM_COMMENT_START, orig_value); + fputc ('\n', asm_out_file); + } + while (value != 0); +} + +static void +output_signed_leb128 (value) + register long value; +{ + register long orig_value = value; + register int negative = (value < 0); + register int more; + + do + { + register 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; + } + fprintf (asm_out_file, "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) byte); + if (flag_debug_asm && more == 0) + fprintf (asm_out_file, "\t%s SLEB128 number - value = %ld", + ASM_COMMENT_START, orig_value); + fputc ('\n', asm_out_file); + } + while (more); +} +#endif + +/**************** utility functions for attribute functions ******************/ + +/* Given a pointer to a BLOCK node return non-zero if (and only if) the + node in question represents the outermost pair of curly braces (i.e. + the "body block") of a function or method. + + For any BLOCK node representing a "body block" of a function or method, + the BLOCK_SUPERCONTEXT of the node will point to another BLOCK node + which represents the outermost (function) scope for the function or + method (i.e. the one which includes the formal parameters). The + BLOCK_SUPERCONTEXT of *that* node in turn will point to the relevant + FUNCTION_DECL node. +*/ + +static inline int +is_body_block (stmt) + register tree stmt; +{ + if (TREE_CODE (stmt) == BLOCK) + { + register tree parent = BLOCK_SUPERCONTEXT (stmt); + + if (TREE_CODE (parent) == BLOCK) + { + register tree grandparent = BLOCK_SUPERCONTEXT (parent); + + if (TREE_CODE (grandparent) == FUNCTION_DECL) + return 1; + } + } + return 0; +} + +/* 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 enought 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) + register 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) + { + char *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); + + 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) + { + char *name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); + + /* Note that here we can run afowl 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 afowl 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) + register tree type; + register 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) + register 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) + register tree type; + register int decl_const; + register int decl_volatile; + register 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) + register tree type; + register int decl_const; + register int decl_volatile; +{ + write_modifier_bytes_1 (type, decl_const, decl_volatile, 0); +} + +/* Given a pointer to an arbitrary ..._TYPE tree node, return non-zero if the + given input type is a Dwarf "fundamental" type. Otherwise return zero. */ + +static inline int +type_is_fundamental (type) + register 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: + 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) + register 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) + register 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) + register rtx rtl; +{ + register unsigned regno = REGNO (rtl); + + if (regno >= FIRST_PSEUDO_REGISTER) + { + warning_with_decl (dwarf_last_decl, "internal regno botch: regno = %d\n", + regno); + regno = 0; + } + fprintf (asm_out_file, "\t%s\t0x%x", + UNALIGNED_INT_ASM_OP, 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) + register 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. */ + + 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 = XEXP (rtl, 0); + /* 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) + register 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 = XEXP (rtl, 0); + /* 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) + register tree bound; + register unsigned dim_num; /* For multi-dimensional arrays. */ + register 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: + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, + (unsigned) TREE_INT_CST_LOW (bound)); + 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) + 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) + register tree link; +{ + if (link) + { + output_enumeral_list (TREE_CHAIN (link)); + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, + (unsigned) TREE_INT_CST_LOW (TREE_VALUE (link))); + 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 unsigned +ceiling (value, boundary) + register unsigned value; + register unsigned 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) + register tree decl; +{ + register 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 +simple_type_align_in_bits (type) + register 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 +simple_type_size_in_bits (type) + register tree type; +{ + if (TREE_CODE (type) == ERROR_MARK) + return BITS_PER_WORD; + else + { + register tree type_size_tree = TYPE_SIZE (type); + + if (TREE_CODE (type_size_tree) != INTEGER_CST) + return TYPE_ALIGN (type); + + return (unsigned) TREE_INT_CST_LOW (type_size_tree); + } +} + +/* 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 unsigned +field_byte_offset (decl) + register tree decl; +{ + register unsigned type_align_in_bytes; + register unsigned type_align_in_bits; + register unsigned type_size_in_bits; + register unsigned object_offset_in_align_units; + register unsigned object_offset_in_bits; + register unsigned object_offset_in_bytes; + register tree type; + register tree bitpos_tree; + register tree field_size_tree; + register unsigned bitpos_int; + register unsigned deepest_bitpos; + register unsigned field_size_in_bits; + + if (TREE_CODE (decl) == ERROR_MARK) + return 0; + + if (TREE_CODE (decl) != FIELD_DECL) + abort (); + + type = field_type (decl); + + bitpos_tree = DECL_FIELD_BITPOS (decl); + field_size_tree = DECL_SIZE (decl); + + /* 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 (TREE_CODE (bitpos_tree) != INTEGER_CST) + return 0; + bitpos_int = (unsigned) TREE_INT_CST_LOW (bitpos_tree); + + if (TREE_CODE (field_size_tree) != INTEGER_CST) + return 0; + field_size_in_bits = (unsigned) TREE_INT_CST_LOW (field_size_tree); + + 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. */ + if (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) + register 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) + register tree t; +{ + register 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_INT_CST_LOW (BINFO_OFFSET (t)); + 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) + register 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 HOST_WIDE_INT) CONST_DOUBLE_HIGH (rtl), + (unsigned HOST_WIDE_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) + register tree decl; +{ + register 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. */ + register tree declared_type = type_main_variant (TREE_TYPE (decl)); + register 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) + 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 (leaf_function) + 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) + register 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) + register 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) + register tree type; + register int decl_const; + register 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) + register 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) + register tree type; + register int decl_const; + register 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) + register 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) + register tree type; +{ + register 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++) + { + register 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. */ + + register tree lower = TYPE_MIN_VALUE (domain); + register 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. */ + + output_bound_representation (upper, dimension_number, 'u'); + } + 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) + register tree tree_node; +{ + register 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) + register tree decl; +{ + register unsigned object_offset_in_bytes = field_byte_offset (decl); + register tree type = DECL_BIT_FIELD_TYPE (decl); + register tree bitpos_tree = DECL_FIELD_BITPOS (decl); + register unsigned bitpos_int; + register unsigned highest_order_object_bit_offset; + register unsigned highest_order_field_bit_offset; + register unsigned bit_offset; + + /* Must be a bit field. */ + if (!type + || TREE_CODE (decl) != FIELD_DECL) + abort (); + + /* We can't yet handle bit-fields whose offsets are variable, so if we + encounter such things, just return without generating any attribute + whatsoever. */ + + if (TREE_CODE (bitpos_tree) != INTEGER_CST) + return; + bitpos_int = (unsigned) TREE_INT_CST_LOW (bitpos_tree); + + /* 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 + += (unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl)); + + 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) + register tree decl; +{ + /* Must be a field and a bit field. */ + if (TREE_CODE (decl) != FIELD_DECL + || ! DECL_BIT_FIELD_TYPE (decl)) + abort (); + + ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_bit_size); + ASM_OUTPUT_DWARF_DATA4 (asm_out_file, + (unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl))); +} + +/* 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) + register 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) + register 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) + register 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) + register 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) + register 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) + register 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) + register 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) + register 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 +static inline void +string_length_attribute (upper_bound) + register 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) + register 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) + register 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) + register 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) + register 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) + register tree func_type; +{ + if ((strcmp (language_string, "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) + register 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) + register 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) + register 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) + register 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) + register unsigned src_fileno; + register 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) + register 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) + register tree decl; +{ + register 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) + register tree type; + register int decl_const; + register int decl_volatile; +{ + register enum tree_code code = TREE_CODE (type); + register 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 char * +type_tag (type) + register tree type; +{ + register char *name = 0; + + if (TYPE_NAME (type) != 0) + { + register 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) + register 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 char * +function_start_label (decl) + register tree decl; +{ + rtx x; + 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) + register void *arg; +{ + register 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) + register void *arg; +{ + register 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) + register void *arg; +{ + register tree decl = arg; + register 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) + register void *arg; +{ + register 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) + register void *arg; +{ + register 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) + register void *arg; +{ + register 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) + register void *arg; +{ + register 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 (TYPE_SIZE (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) + register void *arg; +{ + register 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) + register void *arg; +{ + register tree decl = arg; + register 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 + { + register 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_funcdef_number); + high_pc_attribute (label); + if (use_gnu_debug_info_extensions) + { + sprintf (label, BODY_BEGIN_LABEL_FMT, current_funcdef_number); + body_begin_attribute (label); + sprintf (label, BODY_END_LABEL_FMT, current_funcdef_number); + 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) + register void *arg; +{ + register tree decl = arg; + register 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) + register void *arg; +{ + register tree decl = arg; + register 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 + { + register rtx insn = DECL_RTL (decl); + + if (GET_CODE (insn) == CODE_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. */ + + sprintf (label, INSN_LABEL_FMT, current_funcdef_number, + (unsigned) INSN_UID (insn)); + low_pc_attribute (label); + } + } +} + +static void +output_lexical_block_die (arg) + register void *arg; +{ + register 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, next_block_number); + low_pc_attribute (begin_label); + sprintf (end_label, BLOCK_END_LABEL_FMT, next_block_number); + high_pc_attribute (end_label); + } +} + +static void +output_inlined_subroutine_die (arg) + register void *arg; +{ + register 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, next_block_number); + low_pc_attribute (begin_label); + sprintf (end_label, BLOCK_END_LABEL_FMT, next_block_number); + 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) + register void *arg; +{ + register tree decl = arg; + register 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) + register void *arg; +{ + register 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) + register void *arg; +{ + register 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) + register void *arg; +{ + register 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) + register void *arg; +{ + register 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) + register void *arg; +{ + register char *main_input_filename = arg; + + 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 (flag_traditional) + language_attribute (LANG_C); + 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); + last_filename = xstrdup (main_input_filename); + + { + 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) + register void *arg; +{ + register 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) + register void *arg; +{ + register 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) + register void *arg; +{ + register 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 (TYPE_SIZE (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) + register void *arg; +{ + register tree decl = arg; + register 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 + { + register 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_funcdef_number); + high_pc_attribute (label); + if (use_gnu_debug_info_extensions) + { + sprintf (label, BODY_BEGIN_LABEL_FMT, current_funcdef_number); + body_begin_attribute (label); + sprintf (label, BODY_END_LABEL_FMT, current_funcdef_number); + body_end_attribute (label); + } + } + } +} + +static void +output_subroutine_type_die (arg) + register void *arg; +{ + register tree type = arg; + register 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) + register void *arg; +{ + register tree decl = arg; + register 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) + register void *arg; +{ + register 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 (TYPE_SIZE (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) + register void *arg; +{ + register 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) + register 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) + register void (*die_specific_output_function) PROTO ((void *)); + register 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) + register tree function_or_method_type; +{ + register tree link; + register tree formal_type = NULL; + register 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) + register 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 non-zero 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) + register tree type; + register 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) + register tree containing_scope; +{ + register unsigned i; + + for (i = 0; i < pending_types; ) + { + register tree type = pending_types_list[i]; + + if (type_ok_for_scope (type, containing_scope)) + { + register tree *mover; + register 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++; + } +} + +static void +output_type (type, containing_scope) + register tree type; + register 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)) + { + register 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) + && TREE_CODE_CLASS (TREE_CODE (TYPE_CONTEXT (type))) == 't' + && ! 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 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 + { + register 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 (TYPE_SIZE (type) == 0 + && (TYPE_CONTEXT (type) == NULL + || (TREE_CODE_CLASS (TREE_CODE (TYPE_CONTEXT (type))) == 't' + && TREE_CODE (TYPE_CONTEXT (type)) != FUNCTION_TYPE + && TREE_CODE (TYPE_CONTEXT (type)) != METHOD_TYPE)) + && !finalizing) + 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 execpt 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 (TYPE_SIZE (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++) + output_die (output_inheritance_die, TREE_VEC_ELT (bases, i)); + } + + ++in_class; + + { + register 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); + } + + { + register 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)) + 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) + register 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) + register tree stmt; + int depth; +{ + register int must_output_die = 0; + register tree origin; + register enum tree_code origin_code; + + /* Ignore blocks never really used to make RTL. */ + + if (! stmt || ! TREE_USED (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 + { + register 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) + register tree stmt; + int depth; +{ + /* Ignore blocks never really used to make RTL. */ + + if (! stmt || ! TREE_USED (stmt)) + return; + + if (! BLOCK_ABSTRACT (stmt) && depth > 0) + next_block_number++; + + /* 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. */ + + { + register 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. */ + + { + register 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? */ + +inline static int +is_redundant_typedef (decl) + register 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) + register tree decl; + register 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. + But don't ignore a function definition, since that would screw + up our count of blocks, and that it turn will completely screw up the + labels we will reference in subsequent AT_low_pc and AT_high_pc + attributes (for subsequent blocks). */ + + if (DECL_IGNORED_P (decl) && TREE_CODE (decl) != FUNCTION_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 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 */ + + register tree arg_decls = DECL_ARGUMENTS (decl); + register 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 a 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. + */ + + { + register 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). */ + + { + register 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. */ + + { + register void (*func) PROTO((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 afowl 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; + + default: + abort (); + } +} + +void +dwarfout_file_scope_decl (decl, set_finalizing) + register tree decl; + register int set_finalizing; +{ + if (TREE_CODE (decl) == ERROR_MARK) + return; + + /* If this ..._DECL node is marked to be ignored, then ignore it. We + gotta hope that the node in question doesn't represent a function + definition. If it does, then totally ignoring it is bound to screw + up our count of blocks, and that it turn will completely screw up the + labels we will reference in subsequent AT_low_pc and AT_high_pc + attributes (for subsequent blocks). (It's too bad that BLOCK nodes + don't carry their own sequence numbers with them!) */ + + if (DECL_IGNORED_P (decl)) + { + if (TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl) != NULL) + abort (); + 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 wil 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, 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, 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, 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); + + if (TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl) != NULL) + current_funcdef_number++; +} + +/* Output a marker (i.e. a label) for the beginning of the generated code + for a lexical block. */ + +void +dwarfout_begin_block (blocknum) + register unsigned 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. */ + +void +dwarfout_end_block (blocknum) + register unsigned 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) at a point in the assembly code which + corresponds to a given source level label. */ + +void +dwarfout_label (insn) + register rtx insn; +{ + if (debug_info_level >= DINFO_LEVEL_NORMAL) + { + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + function_section (current_function_decl); + sprintf (label, INSN_LABEL_FMT, current_funcdef_number, + (unsigned) INSN_UID (insn)); + 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). */ + +void +dwarfout_begin_function () +{ + 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_funcdef_number); + 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). */ + +void +dwarfout_end_function () +{ + 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_funcdef_number); + 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. */ + +void +dwarfout_end_epilogue () +{ + 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_funcdef_number); + ASM_OUTPUT_LABEL (asm_out_file, label); +} + +static void +shuffle_filename_entry (new_zeroth) + register filename_entry *new_zeroth; +{ + filename_entry temp_entry; + register filename_entry *limit_p; + register 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, 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) + char *file_name; +{ + register filename_entry *search_p; + register 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, 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); +} + +void +dwarfout_line (filename, line) + register char *filename; + register unsigned line; +{ + 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; + register 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); + } + + { + register char *tail = rindex (filename, '/'); + + if (tail != NULL) + filename = tail; + } + + fprintf (asm_out_file, "\t%s\t%u\t%s %s:%u\n", + UNALIGNED_INT_ASM_OP, line, ASM_COMMENT_START, + 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_and_offset, string) + register char *type_and_offset; + register char *string; +{ + if (! use_gnu_debug_info_extensions) + return; + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, MACINFO_SECTION); + fprintf (asm_out_file, "\t%s\t%s\n", UNALIGNED_INT_ASM_OP, type_and_offset); + ASM_OUTPUT_DWARF_STRING_NEWLINE (asm_out_file, string); + ASM_OUTPUT_POP_SECTION (asm_out_file); +} + +void +dwarfout_start_new_source_file (filename) + register char *filename; +{ + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + char type_and_offset[MAX_ARTIFICIAL_LABEL_BYTES*3]; + + sprintf (label, SFNAMES_ENTRY_LABEL_FMT, lookup_filename (filename)); + sprintf (type_and_offset, "0x%08x+%s-%s", + ((unsigned) MACINFO_start << 24), + /* Hack: skip leading '*' . */ + (*label == '*') + label, + (*SFNAMES_BEGIN_LABEL == '*') + SFNAMES_BEGIN_LABEL); + generate_macinfo_entry (type_and_offset, ""); +} + +void +dwarfout_resume_previous_source_file (lineno) + register unsigned lineno; +{ + char type_and_offset[MAX_ARTIFICIAL_LABEL_BYTES*2]; + + sprintf (type_and_offset, "0x%08x+%u", + ((unsigned) MACINFO_resume << 24), lineno); + generate_macinfo_entry (type_and_offset, ""); +} + +/* 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. */ + +void +dwarfout_define (lineno, buffer) + register unsigned lineno; + register char *buffer; +{ + static int initialized = 0; + char type_and_offset[MAX_ARTIFICIAL_LABEL_BYTES*2]; + + if (!initialized) + { + dwarfout_start_new_source_file (primary_filename); + initialized = 1; + } + sprintf (type_and_offset, "0x%08x+%u", + ((unsigned) MACINFO_define << 24), lineno); + generate_macinfo_entry (type_and_offset, 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. */ + +void +dwarfout_undef (lineno, buffer) + register unsigned lineno; + register char *buffer; +{ + char type_and_offset[MAX_ARTIFICIAL_LABEL_BYTES*2]; + + sprintf (type_and_offset, "0x%08x+%u", + ((unsigned) MACINFO_undef << 24), lineno); + generate_macinfo_entry (type_and_offset, buffer); +} + +/* Set up for Dwarf output at the start of compilation. */ + +void +dwarfout_init (asm_out_file, main_input_filename) + register FILE *asm_out_file; + register char *main_input_filename; +{ + /* 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); + 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); + 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); + 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); + 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); + 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); + 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, SFNAMES_SECTION); + ASM_OUTPUT_LABEL (asm_out_file, SFNAMES_BEGIN_LABEL); + { + register char *pwd; + register unsigned len; + register char *dirname; + + pwd = getpwd (); + if (!pwd) + pfatal_with_name ("getpwd"); + len = strlen (pwd); + dirname = (char *) xmalloc (len + 2); + + strcpy (dirname, pwd); + strcpy (dirname + len, "/"); + 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, 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, 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, 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, ARANGES_SECTION); + 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, 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. */ + +void +dwarfout_finish () +{ + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, DEBUG_SECTION); + + /* 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); + 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); + 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); + 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); + 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); + 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); + 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, 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_resume_previous_source_file (0); + + fputc ('\n', asm_out_file); + ASM_OUTPUT_PUSH_SECTION (asm_out_file, 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, 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, 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_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/gcc_arm/dwarfout.h b/gcc_arm/dwarfout.h new file mode 100755 index 0000000..29c8dd3 --- /dev/null +++ b/gcc_arm/dwarfout.h @@ -0,0 +1,42 @@ +/* dwarfout.h - Various declarations for functions found in dwarfout.c + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +extern void dwarfout_init PROTO ((FILE *asm_out_file, + char *main_input_filename)); +extern void dwarfout_finish PROTO ((void)); + +extern void dwarfout_define PROTO ((unsigned, char *)); +extern void dwarfout_undef PROTO ((unsigned, char *)); +extern void dwarfout_file_scope_decl PROTO ((tree , int)); +extern void dwarfout_start_new_source_file PROTO ((char *)); +extern void dwarfout_resume_previous_source_file PROTO((unsigned)); + +extern void dwarfout_begin_function PROTO ((void)); +extern void dwarfout_end_function PROTO ((void)); +extern void dwarfout_begin_epilogue PROTO ((void)); +extern void dwarfout_end_epilogue PROTO ((void)); +extern void dwarfout_begin_block PROTO ((unsigned)); +extern void dwarfout_end_block PROTO ((unsigned)); + +#ifdef RTX_CODE +extern void dwarfout_label PROTO ((rtx)); +#endif +extern void dwarfout_line PROTO ((char *, unsigned)); + diff --git a/gcc_arm/dyn-string.c b/gcc_arm/dyn-string.c new file mode 100755 index 0000000..f00510f --- /dev/null +++ b/gcc_arm/dyn-string.c @@ -0,0 +1,97 @@ +/* An abstract string datatype. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Mark Mitchell (mark@markmitchell.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "dyn-string.h" + +/* Create a new dynamic string capable of holding at least SPACE + characters, including the terminating NUL. If SPACE is 0, it + will be silently increased to 1. */ + +dyn_string_t +dyn_string_new (space) + int space; +{ + dyn_string_t result = (dyn_string_t) xmalloc (sizeof (struct dyn_string)); + + if (space == 0) + /* We need at least one byte in which to store the terminating + NUL. */ + space = 1; + + result->allocated = space; + result->s = (char*) xmalloc (space); + result->length = 0; + result->s[0] = '\0'; + + return result; +} + +/* Free the memory used by DS. */ + +void +dyn_string_delete (ds) + dyn_string_t ds; +{ + free (ds->s); + free (ds); +} + +/* Append the NUL-terminated string S to DS, resizing DS if + necessary. */ + +dyn_string_t +dyn_string_append (ds, s) + dyn_string_t ds; + char *s; +{ + int len = strlen (s); + dyn_string_resize (ds, ds->length + len + 1 /* '\0' */); + strcpy (ds->s + ds->length, s); + ds->length += len; + + return ds; +} + +/* Increase the capacity of DS so that it can hold at least SPACE + characters, including the terminating NUL. This function will not + (at present) reduce the capacity of DS. */ + +dyn_string_t +dyn_string_resize (ds, space) + dyn_string_t ds; + int space; +{ + int new_allocated = ds->allocated; + + while (space > new_allocated) + new_allocated *= 2; + + if (new_allocated != ds->allocated) + { + /* We actually need more space. */ + ds->allocated = new_allocated; + ds->s = (char*) xrealloc (ds->s, ds->allocated); + } + + return ds; +} diff --git a/gcc_arm/dyn-string.h b/gcc_arm/dyn-string.h new file mode 100755 index 0000000..d6cd137 --- /dev/null +++ b/gcc_arm/dyn-string.h @@ -0,0 +1,32 @@ +/* An abstract string datatype. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Mark Mitchell (mark@markmitchell.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +typedef struct dyn_string +{ + int allocated; /* The amount of space allocated for the string. */ + int length; /* The actual length of the string. */ + char *s; /* The string itself, NUL-terminated. */ +}* dyn_string_t; + +extern dyn_string_t dyn_string_new PROTO((int)); +extern void dyn_string_delete PROTO((dyn_string_t)); +extern dyn_string_t dyn_string_append PROTO((dyn_string_t, char*)); +extern dyn_string_t dyn_string_resize PROTO((dyn_string_t, int)); diff --git a/gcc_arm/eh-common.h b/gcc_arm/eh-common.h new file mode 100755 index 0000000..c0ff7e7 --- /dev/null +++ b/gcc_arm/eh-common.h @@ -0,0 +1,142 @@ +/* EH stuff + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* This file contains the structures required for the language + independant exception handling model. Both the static compiler and + the runtime library share this file. */ + +/* The runtime flag flag_new_exceptions is used to determine whether the + compiler supports the new runtime typechecking mechanism or not. Under + the new model, runtime info is contained in the exception table, and + the __throw() library routine determines which handler to call based + on the results of a call to a matching function provided by the expcetion + thrower. Otherwise the old scheme of calling any handler which matches + an exception range is used, and the handler is responsible for all + checking of runtime conditions. If the handler wasn't suppose to + get the exception, it performs a re-throw. */ + + +/* The handler_label field MUST be the first field in this structure. The + __throw() library routine expects uses __eh_stub() from except.c, which + simply dereferences the context pointer to get the handler. + The routine get_dynamic_handler_chain() also has a dependancy on + the location of 'dynamic_handler_chain'. If its location is changed, + that routine must be modified as well. */ + +struct eh_context +{ + void *handler_label; + void **dynamic_handler_chain; + /* This is language dependent part of the eh context. */ + void *info; + /* This is used to remember where we threw for re-throws */ + void *table_index; /* address of exception table entry to rethrow from */ +}; + +#ifndef EH_TABLE_LOOKUP + +typedef struct old_exception_table +{ + void *start_region; + void *end_region; + void *exception_handler; +} old_exception_table; + +typedef struct exception_table +{ + void *start_region; + void *end_region; + void *exception_handler; + void *match_info; /* runtime type info */ +} exception_table; + + +/* The language identifying portion of an exception table */ + +typedef struct exception_lang_info +{ + short language; + short version; +} exception_lang_info; + +/* This value in the first field of the exception descriptor + identifies the descriptor as the new model format. This value would never + be present in this location under the old model */ + +#define NEW_EH_RUNTIME ((void *) -2) + +/* Each function has an exception_descriptor which contains the + language info, and a table of exception ranges and handlers */ + +typedef struct exception_descriptor +{ + void *runtime_id_field; + exception_lang_info lang; + exception_table table[1]; +} exception_descriptor; + + +/* A pointer to a matching function is initialized at runtime by the + specific language if run-time exceptions are supported. + The function takes 3 parameters + 1 - runtime exception that has been thrown info. (__eh_info *) + 2 - Match info pointer from the region being considered (void *) + 3 - exception table region is in (exception descriptor *) +*/ + +typedef void * (*__eh_matcher) PROTO ((void *, void *, void *)); + +/* This value is to be checked as a 'match all' case in the runtime field. */ + +#define CATCH_ALL_TYPE ((void *) -1) + +/* This is the runtime exception information. This forms the minimum required + information for an exception info pointer in an eh_context structure. */ + + +typedef struct __eh_info +{ + __eh_matcher match_function; + short language; + short version; +} __eh_info; + +/* Convienient language codes for ID the originating language. Similar + to the codes in dwarf2.h. */ + +enum exception_source_language + { + EH_LANG_C89 = 0x0001, + EH_LANG_C = 0x0002, + EH_LANG_Ada83 = 0x0003, + EH_LANG_C_plus_plus = 0x0004, + EH_LANG_Cobol74 = 0x0005, + EH_LANG_Cobol85 = 0x0006, + EH_LANG_Fortran77 = 0x0007, + EH_LANG_Fortran90 = 0x0008, + EH_LANG_Pascal83 = 0x0009, + EH_LANG_Modula2 = 0x000a, + EH_LANG_Java = 0x000b, + EH_LANG_Mips_Assembler = 0x8001 + }; + +#endif /* EH_TABLE_LOOKUP */ + + diff --git a/gcc_arm/emit-rtl.c b/gcc_arm/emit-rtl.c new file mode 100755 index 0000000..fcfc931 --- /dev/null +++ b/gcc_arm/emit-rtl.c @@ -0,0 +1,3666 @@ +/* Emit RTL for the GNU C-Compiler expander. + Copyright (C) 1987, 88, 92-97, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* Middle-to-low level generation of rtx code and 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 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" +#include "rtl.h" +#include "tree.h" +#include "flags.h" +#include "except.h" +#include "function.h" +#include "expr.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "insn-config.h" +#include "recog.h" +#include "real.h" +#include "obstack.h" +#include "bitmap.h" + +/* Commonly used modes. */ + +enum machine_mode byte_mode; /* Mode whose width is BITS_PER_UNIT. */ +enum machine_mode word_mode; /* Mode whose width is BITS_PER_WORD. */ +enum machine_mode double_mode; /* Mode whose width is DOUBLE_TYPE_SIZE. */ +enum machine_mode ptr_mode; /* Mode whose width is POINTER_SIZE. */ + +/* This is reset to LAST_VIRTUAL_REGISTER + 1 at the start of each function. + After rtl generation, it is 1 plus the largest register number used. */ + +int reg_rtx_no = LAST_VIRTUAL_REGISTER + 1; + +/* This is *not* reset after each function. It gives each CODE_LABEL + in the entire compilation a unique label number. */ + +static int label_num = 1; + +/* Lowest label number in current function. */ + +static int first_label_num; + +/* 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_first_and_last_label_number 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; + +/* Commonly used rtx's, so that we only need space for one copy. + These are initialized once for the entire compilation. + All of these except perhaps the floating-point CONST_DOUBLEs + are unique; no other rtx-object will be equal to any of these. */ + +/* Avoid warnings by initializing the `fld' field. Since its a union, + bypass problems with KNR compilers by only doing so when __GNUC__. */ +#ifdef __GNUC__ +#define FLDI , {{0}} +#else +#define FLDI +#endif + +struct _global_rtl global_rtl = +{ + {PC, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* pc_rtx */ + {CC0, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* cc0_rtx */ + {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* stack_pointer_rtx */ + {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* frame_pointer_rtx */ + {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* hard_frame_pointer_rtx */ + {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* arg_pointer_rtx */ + {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* virtual_incoming_args_rtx */ + {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* virtual_stack_vars_rtx */ + {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* virtual_stack_dynamic_rtx */ + {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* virtual_outgoing_args_rtx */ + {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* virtual_cfa_rtx */ +}; + +/* We record floating-point CONST_DOUBLEs in each floating-point mode for + the values of 0, 1, and 2. For the integer entries and VOIDmode, we + record a copy of const[012]_rtx. */ + +rtx const_tiny_rtx[3][(int) MAX_MACHINE_MODE]; + +rtx const_true_rtx; + +REAL_VALUE_TYPE dconst0; +REAL_VALUE_TYPE dconst1; +REAL_VALUE_TYPE dconst2; +REAL_VALUE_TYPE dconstm1; + +/* All references to the following fixed hard registers go through + these unique rtl objects. On machines where the frame-pointer and + arg-pointer are the same register, they use the same unique object. + + After register allocation, other rtl objects which used to be pseudo-regs + may be clobbered to refer to the frame-pointer register. + But references that were originally to the frame-pointer can be + distinguished from the others because they contain frame_pointer_rtx. + + When to use frame_pointer_rtx and hard_frame_pointer_rtx is a little + tricky: until register elimination has taken place hard_frame_pointer_rtx + should be used if it is being set, and frame_pointer_rtx otherwise. After + register elimination hard_frame_pointer_rtx should always be used. + On machines where the two registers are same (most) then these are the + same. + + In an inline procedure, the stack and frame pointer rtxs may not be + used for anything else. */ +rtx struct_value_rtx; /* (REG:Pmode STRUCT_VALUE_REGNUM) */ +rtx struct_value_incoming_rtx; /* (REG:Pmode STRUCT_VALUE_INCOMING_REGNUM) */ +rtx static_chain_rtx; /* (REG:Pmode STATIC_CHAIN_REGNUM) */ +rtx static_chain_incoming_rtx; /* (REG:Pmode STATIC_CHAIN_INCOMING_REGNUM) */ +rtx pic_offset_table_rtx; /* (REG:Pmode PIC_OFFSET_TABLE_REGNUM) */ + +/* This is used to implement __builtin_return_address for some machines. + See for instance the MIPS port. */ +rtx return_address_pointer_rtx; /* (REG:Pmode RETURN_ADDRESS_POINTER_REGNUM) */ + +/* We make one copy of (const_int C) where C is in + [- MAX_SAVED_CONST_INT, MAX_SAVED_CONST_INT] + to save space during the compilation and simplify comparisons of + integers. */ + +struct rtx_def const_int_rtx[MAX_SAVED_CONST_INT * 2 + 1]; + +/* The ends of the doubly-linked chain of rtl for the current function. + Both are reset to null at the start of rtl generation for the function. + + start_sequence saves both of these on `sequence_stack' along with + `sequence_rtl_expr' and then starts a new, nested sequence of insns. */ + +static rtx first_insn = NULL; +static rtx last_insn = NULL; + +/* RTL_EXPR within which the current sequence will be placed. Use to + prevent reuse of any temporaries within the sequence until after the + RTL_EXPR is emitted. */ + +tree sequence_rtl_expr = NULL; + +/* INSN_UID for next insn emitted. + Reset to 1 for each function compiled. */ + +static int cur_insn_uid = 1; + +/* Line number and source file of the last line-number NOTE emitted. + This is used to avoid generating duplicates. */ + +static int last_linenum = 0; +static char *last_filename = 0; + +/* A vector indexed by pseudo reg number. The allocated length + of this vector is regno_pointer_flag_length. Since this + vector is needed during the expansion phase when the total + number of registers in the function is not yet known, + it is copied and made bigger when necessary. */ + +char *regno_pointer_flag; +int regno_pointer_flag_length; + +/* Indexed by pseudo register number, if nonzero gives the known alignment + for that pseudo (if regno_pointer_flag is set). + Allocated in parallel with regno_pointer_flag. */ +char *regno_pointer_align; + +/* Indexed by pseudo register number, gives the rtx for that pseudo. + Allocated in parallel with regno_pointer_flag. */ + +rtx *regno_reg_rtx; + +/* Stack of pending (incomplete) sequences saved by `start_sequence'. + Each element describes one pending sequence. + The main insn-chain is saved in the last element of the chain, + unless the chain is empty. */ + +struct sequence_stack *sequence_stack; + +/* start_sequence and gen_sequence can make a lot of rtx expressions which are + shortly thrown away. We use two mechanisms to prevent this waste: + + First, we keep a list of the expressions used to represent the sequence + stack in sequence_element_free_list. + + Second, for sizes up to 5 elements, we keep a SEQUENCE and its associated + rtvec for use by gen_sequence. One entry for each size is sufficient + because most cases are calls to gen_sequence followed by immediately + emitting the SEQUENCE. Reuse is safe since emitting a sequence is + destructive on the insn in it anyway and hence can't be redone. + + We do not bother to save this cached data over nested function calls. + Instead, we just reinitialize them. */ + +#define SEQUENCE_RESULT_SIZE 5 + +static struct sequence_stack *sequence_element_free_list; +static rtx sequence_result[SEQUENCE_RESULT_SIZE]; + +/* During RTL generation, we also keep a list of free INSN rtl codes. */ +static rtx free_insn; + +extern int rtx_equal_function_value_matters; + +/* Filename and line number of last line-number note, + whether we actually emitted it or not. */ +extern char *emit_filename; +extern int emit_lineno; + +static rtx make_jump_insn_raw PROTO((rtx)); +static rtx make_call_insn_raw PROTO((rtx)); +static rtx find_line_note PROTO((rtx)); + +rtx +gen_rtx_CONST_INT (mode, arg) + enum machine_mode mode; + HOST_WIDE_INT arg; +{ + if (arg >= - MAX_SAVED_CONST_INT && arg <= MAX_SAVED_CONST_INT) + return &const_int_rtx[arg + MAX_SAVED_CONST_INT]; + +#if STORE_FLAG_VALUE != 1 && STORE_FLAG_VALUE != -1 + if (const_true_rtx && arg == STORE_FLAG_VALUE) + return const_true_rtx; +#endif + + return gen_rtx_raw_CONST_INT (mode, arg); +} + +rtx +gen_rtx_REG (mode, regno) + enum machine_mode mode; + int regno; +{ + /* In case the MD file explicitly references the frame pointer, have + all such references point to the same frame pointer. This is + used during frame pointer elimination to distinguish the explicit + references to these registers from pseudos that happened to be + assigned to them. + + If we have eliminated the frame pointer or arg pointer, we will + be using it as a normal register, for example as a spill + register. In such cases, we might be accessing it in a mode that + is not Pmode and therefore cannot use the pre-allocated rtx. + + Also don't do this when we are making new REGs in reload, since + we don't want to get confused with the real pointers. */ + + if (mode == Pmode && !reload_in_progress) + { + if (regno == FRAME_POINTER_REGNUM) + return frame_pointer_rtx; +#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM + if (regno == HARD_FRAME_POINTER_REGNUM) + return hard_frame_pointer_rtx; +#endif +#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM && HARD_FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM + if (regno == ARG_POINTER_REGNUM) + return arg_pointer_rtx; +#endif +#ifdef RETURN_ADDRESS_POINTER_REGNUM + if (regno == RETURN_ADDRESS_POINTER_REGNUM) + return return_address_pointer_rtx; +#endif + if (regno == STACK_POINTER_REGNUM) + return stack_pointer_rtx; + } + + return gen_rtx_raw_REG (mode, regno); +} + +rtx +gen_rtx_MEM (mode, addr) + enum machine_mode mode; + rtx addr; +{ + rtx rt = gen_rtx_raw_MEM (mode, addr); + + /* This field is not cleared by the mere allocation of the rtx, so + we clear it here. */ + MEM_ALIAS_SET (rt) = 0; + + return rt; +} + +/* rtx gen_rtx (code, mode, [element1, ..., elementn]) +** +** This routine generates an RTX of the size specified by +** , which is an RTX code. The RTX structure is initialized +** from the arguments through , which are +** interpreted according to the specific RTX type's format. The +** special machine mode associated with the rtx (if any) is specified +** in . +** +** 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)))), +*/ + +/*VARARGS2*/ +rtx +gen_rtx VPROTO((enum rtx_code code, enum machine_mode mode, ...)) +{ +#ifndef ANSI_PROTOTYPES + enum rtx_code code; + enum machine_mode mode; +#endif + va_list p; + register int i; /* Array indices... */ + register char *fmt; /* Current rtx's format... */ + register rtx rt_val; /* RTX to return to caller... */ + + VA_START (p, mode); + +#ifndef ANSI_PROTOTYPES + code = va_arg (p, enum rtx_code); + mode = va_arg (p, enum machine_mode); +#endif + + if (code == CONST_INT) + rt_val = gen_rtx_CONST_INT (mode, va_arg (p, HOST_WIDE_INT)); + else if (code == REG) + rt_val = gen_rtx_REG (mode, va_arg (p, int)); + else if (code == MEM) + rt_val = gen_rtx_MEM (mode, va_arg (p, rtx)); + else + { + rt_val = rtx_alloc (code); /* Allocate the storage space. */ + rt_val->mode = mode; /* Store the machine mode... */ + + fmt = GET_RTX_FORMAT (code); /* Find the right format... */ + for (i = 0; i < GET_RTX_LENGTH (code); i++) + { + switch (*fmt++) + { + case '0': /* Unused field. */ + break; + + case 'i': /* An integer? */ + XINT (rt_val, i) = va_arg (p, int); + break; + + case 'w': /* A wide integer? */ + XWINT (rt_val, i) = va_arg (p, HOST_WIDE_INT); + break; + + case 's': /* A string? */ + XSTR (rt_val, i) = va_arg (p, char *); + break; + + case 'e': /* An expression? */ + case 'u': /* An insn? Same except when printing. */ + XEXP (rt_val, i) = va_arg (p, rtx); + break; + + case 'E': /* An RTX vector? */ + XVEC (rt_val, i) = va_arg (p, rtvec); + break; + + case 'b': /* A bitmap? */ + XBITMAP (rt_val, i) = va_arg (p, bitmap); + break; + + case 't': /* A tree? */ + XTREE (rt_val, i) = va_arg (p, tree); + break; + + default: + abort (); + } + } + } + va_end (p); + return rt_val; /* Return the new RTX... */ +} + +/* gen_rtvec (n, [rt1, ..., rtn]) +** +** This routine creates an rtvec and stores within it the +** pointers to rtx's which are its arguments. +*/ + +/*VARARGS1*/ +rtvec +gen_rtvec VPROTO((int n, ...)) +{ +#ifndef ANSI_PROTOTYPES + int n; +#endif + int i; + va_list p; + rtx *vector; + + VA_START (p, n); + +#ifndef ANSI_PROTOTYPES + n = va_arg (p, int); +#endif + + if (n == 0) + return NULL_RTVEC; /* Don't allocate an empty rtvec... */ + + vector = (rtx *) alloca (n * sizeof (rtx)); + + for (i = 0; i < n; i++) + vector[i] = va_arg (p, rtx); + va_end (p); + + return gen_rtvec_v (n, vector); +} + +rtvec +gen_rtvec_v (n, argp) + int n; + rtx *argp; +{ + register int i; + register rtvec rt_val; + + if (n == 0) + return NULL_RTVEC; /* Don't allocate an empty rtvec... */ + + rt_val = rtvec_alloc (n); /* Allocate an rtvec... */ + + for (i = 0; i < n; i++) + rt_val->elem[i].rtx = *argp++; + + return rt_val; +} + +rtvec +gen_rtvec_vv (n, argp) + int n; + rtunion *argp; +{ + register int i; + register rtvec rt_val; + + if (n == 0) + return NULL_RTVEC; /* Don't allocate an empty rtvec... */ + + rt_val = rtvec_alloc (n); /* Allocate an rtvec... */ + + for (i = 0; i < n; i++) + rt_val->elem[i].rtx = (argp++)->rtx; + + return rt_val; +} + +/* Generate a REG rtx for a new pseudo register of mode MODE. + This pseudo is assigned the next sequential register number. */ + +rtx +gen_reg_rtx (mode) + enum machine_mode mode; +{ + register rtx val; + + /* Don't let anything called after initial flow analysis create new + registers. */ + if (no_new_pseudos) + abort (); + + if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT + || GET_MODE_CLASS (mode) == MODE_COMPLEX_INT) + { + /* For complex modes, don't make a single pseudo. + Instead, make a CONCAT of two pseudos. + This allows noncontiguous allocation of the real and imaginary parts, + which makes much better code. Besides, allocating DCmode + pseudos overstrains reload on some machines like the 386. */ + rtx realpart, imagpart; + int size = GET_MODE_UNIT_SIZE (mode); + enum machine_mode partmode + = mode_for_size (size * BITS_PER_UNIT, + (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT + ? MODE_FLOAT : MODE_INT), + 0); + + realpart = gen_reg_rtx (partmode); + imagpart = gen_reg_rtx (partmode); + return gen_rtx_CONCAT (mode, realpart, imagpart); + } + + /* Make sure regno_pointer_flag and regno_reg_rtx are large + enough to have an element for this pseudo reg number. */ + + if (reg_rtx_no == regno_pointer_flag_length) + { + rtx *new1; + char *new = + (char *) savealloc (regno_pointer_flag_length * 2); + bcopy (regno_pointer_flag, new, regno_pointer_flag_length); + bzero (&new[regno_pointer_flag_length], regno_pointer_flag_length); + regno_pointer_flag = new; + + new = (char *) savealloc (regno_pointer_flag_length * 2); + bcopy (regno_pointer_align, new, regno_pointer_flag_length); + bzero (&new[regno_pointer_flag_length], regno_pointer_flag_length); + regno_pointer_align = new; + + new1 = (rtx *) savealloc (regno_pointer_flag_length * 2 * sizeof (rtx)); + bcopy ((char *) regno_reg_rtx, (char *) new1, + regno_pointer_flag_length * sizeof (rtx)); + bzero ((char *) &new1[regno_pointer_flag_length], + regno_pointer_flag_length * sizeof (rtx)); + regno_reg_rtx = new1; + + regno_pointer_flag_length *= 2; + } + + val = gen_rtx_raw_REG (mode, reg_rtx_no); + regno_reg_rtx[reg_rtx_no++] = val; + return val; +} + +/* Identify REG (which may be a CONCAT) as a user register. */ + +void +mark_user_reg (reg) + rtx reg; +{ + if (GET_CODE (reg) == CONCAT) + { + 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 + abort (); +} + +/* Identify REG as a probable pointer register and show its alignment + as ALIGN, if nonzero. */ + +void +mark_reg_pointer (reg, align) + rtx reg; + int align; +{ + REGNO_POINTER_FLAG (REGNO (reg)) = 1; + + if (align) + REGNO_POINTER_ALIGN (REGNO (reg)) = align; +} + +/* Return 1 plus largest pseudo reg number used in the current function. */ + +int +max_reg_num () +{ + return reg_rtx_no; +} + +/* Return 1 + the largest label number used so far in the current function. */ + +int +max_label_num () +{ + if (last_label_num && label_num == base_label_num) + return last_label_num; + return label_num; +} + +/* Return first label number used in this function (if any were used). */ + +int +get_first_label_num () +{ + return first_label_num; +} + +/* 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 + representation is returned. + + This function handles the cases in common between gen_lowpart, below, + and two variants in cse.c and combine.c. These are the cases that can + be safely handled at all points in the compilation. + + If this is not a case we can handle, return 0. */ + +rtx +gen_lowpart_common (mode, x) + enum machine_mode mode; + register rtx x; +{ + int word = 0; + + if (GET_MODE (x) == mode) + return x; + + /* MODE must occupy no more words than the mode of X. */ + if (GET_MODE (x) != VOIDmode + && ((GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD + > ((GET_MODE_SIZE (GET_MODE (x)) + (UNITS_PER_WORD - 1)) + / UNITS_PER_WORD))) + return 0; + + if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) + word = ((GET_MODE_SIZE (GET_MODE (x)) + - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)) + / UNITS_PER_WORD); + + if ((GET_CODE (x) == ZERO_EXTEND || GET_CODE (x) == SIGN_EXTEND) + && (GET_MODE_CLASS (mode) == MODE_INT + || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)) + { + /* If we are getting the low-order part of something that has been + sign- or zero-extended, we can either just use the object being + extended or make a narrower extension. If we want an even smaller + piece than the size of the object being extended, call ourselves + recursively. + + This case is used mostly by combine and cse. */ + + if (GET_MODE (XEXP (x, 0)) == mode) + return XEXP (x, 0); + else if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (XEXP (x, 0)))) + return gen_lowpart_common (mode, XEXP (x, 0)); + else if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x))) + return gen_rtx_fmt_e (GET_CODE (x), mode, XEXP (x, 0)); + } + else if (GET_CODE (x) == SUBREG + && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD + || GET_MODE_SIZE (mode) == GET_MODE_UNIT_SIZE (GET_MODE (x)))) + return (GET_MODE (SUBREG_REG (x)) == mode && SUBREG_WORD (x) == 0 + ? SUBREG_REG (x) + : gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_WORD (x) + word)); + else if (GET_CODE (x) == REG) + { + /* Let the backend decide how many registers to skip. This is needed + in particular for Sparc64 where fp regs are smaller than a word. */ + /* ??? Note that subregs are now ambiguous, in that those against + pseudos are sized by the Word Size, while those against hard + regs are sized by the underlying register size. Better would be + to always interpret the subreg offset parameter as bytes or bits. */ + + if (WORDS_BIG_ENDIAN && REGNO (x) < FIRST_PSEUDO_REGISTER) + word = (HARD_REGNO_NREGS (REGNO (x), GET_MODE (x)) + - HARD_REGNO_NREGS (REGNO (x), mode)); + + /* If the register is not valid for MODE, return 0. If we don't + do this, there is no way to fix up the resulting REG later. + But we do do this if the current REG is not valid for its + mode. This latter is a kludge, but is required due to the + way that parameters are passed on some machines, most + notably Sparc. */ + if (REGNO (x) < FIRST_PSEUDO_REGISTER + && ! HARD_REGNO_MODE_OK (REGNO (x) + word, mode) + && HARD_REGNO_MODE_OK (REGNO (x), GET_MODE (x))) + return 0; + else if (REGNO (x) < FIRST_PSEUDO_REGISTER + /* integrate.c can't handle parts of a return value register. */ + && (! REG_FUNCTION_VALUE_P (x) + || ! rtx_equal_function_value_matters) +#ifdef CLASS_CANNOT_CHANGE_SIZE + && ! (GET_MODE_SIZE (mode) != GET_MODE_SIZE (GET_MODE (x)) + && GET_MODE_CLASS (GET_MODE (x)) != MODE_COMPLEX_INT + && GET_MODE_CLASS (GET_MODE (x)) != MODE_COMPLEX_FLOAT + && (TEST_HARD_REG_BIT + (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE], + REGNO (x)))) +#endif + /* We want to keep the stack, frame, and arg pointers + special. */ + && x != frame_pointer_rtx +#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM + && x != arg_pointer_rtx +#endif + && x != stack_pointer_rtx) + return gen_rtx_REG (mode, REGNO (x) + word); + else + return gen_rtx_SUBREG (mode, x, word); + } + /* If X is a CONST_INT or a CONST_DOUBLE, extract the appropriate bits + from the low-order part of the constant. */ + else if ((GET_MODE_CLASS (mode) == MODE_INT + || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT) + && GET_MODE (x) == VOIDmode + && (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)) + { + /* If MODE is twice the host word size, X is already the desired + representation. Otherwise, if MODE is wider than a word, we can't + do this. If MODE is exactly a word, return just one CONST_INT. + If MODE is smaller than a word, clear the bits that don't belong + in our 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. */ + + if (GET_MODE_BITSIZE (mode) >= 2 * HOST_BITS_PER_WIDE_INT) + return x; + else if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT) + return 0; + else if (GET_MODE_BITSIZE (mode) == HOST_BITS_PER_WIDE_INT) + return (GET_CODE (x) == CONST_INT ? x + : GEN_INT (CONST_DOUBLE_LOW (x))); + else + { + /* MODE must be narrower than HOST_BITS_PER_WIDE_INT. */ + int width = GET_MODE_BITSIZE (mode); + HOST_WIDE_INT val = (GET_CODE (x) == CONST_INT ? INTVAL (x) + : CONST_DOUBLE_LOW (x)); + + /* Sign extend to HOST_WIDE_INT. */ + val = val << (HOST_BITS_PER_WIDE_INT - width) >> (HOST_BITS_PER_WIDE_INT - width); + + return (GET_CODE (x) == CONST_INT && INTVAL (x) == val ? x + : GEN_INT (val)); + } + } + + /* If X is an integral constant but we want it in floating-point, it + must be the case that we have a union of an integer and a floating-point + value. If the machine-parameters allow it, simulate that union here + and return the result. The two-word and single-word cases are + different. */ + + else if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT + && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD) + || flag_pretend_float) + && GET_MODE_CLASS (mode) == MODE_FLOAT + && GET_MODE_SIZE (mode) == UNITS_PER_WORD + && GET_CODE (x) == CONST_INT + && sizeof (float) * HOST_BITS_PER_CHAR == HOST_BITS_PER_WIDE_INT) +#ifdef REAL_ARITHMETIC + { + REAL_VALUE_TYPE r; + HOST_WIDE_INT i; + + i = INTVAL (x); + r = REAL_VALUE_FROM_TARGET_SINGLE (i); + return CONST_DOUBLE_FROM_REAL_VALUE (r, mode); + } +#else + { + union {HOST_WIDE_INT i; float d; } u; + + u.i = INTVAL (x); + return CONST_DOUBLE_FROM_REAL_VALUE (u.d, mode); + } +#endif + else if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT + && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD) + || flag_pretend_float) + && GET_MODE_CLASS (mode) == MODE_FLOAT + && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD + && (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE) + && GET_MODE (x) == VOIDmode + && (sizeof (double) * HOST_BITS_PER_CHAR + == 2 * HOST_BITS_PER_WIDE_INT)) +#ifdef REAL_ARITHMETIC + { + REAL_VALUE_TYPE r; + HOST_WIDE_INT i[2]; + HOST_WIDE_INT low, high; + + if (GET_CODE (x) == CONST_INT) + low = INTVAL (x), high = low >> (HOST_BITS_PER_WIDE_INT -1); + else + low = CONST_DOUBLE_LOW (x), high = CONST_DOUBLE_HIGH (x); + + /* REAL_VALUE_TARGET_DOUBLE takes the addressing order of the + target machine. */ + if (WORDS_BIG_ENDIAN) + i[0] = high, i[1] = low; + else + i[0] = low, i[1] = high; + + r = REAL_VALUE_FROM_TARGET_DOUBLE (i); + return CONST_DOUBLE_FROM_REAL_VALUE (r, mode); + } +#else + { + union {HOST_WIDE_INT i[2]; double d; } u; + HOST_WIDE_INT low, high; + + if (GET_CODE (x) == CONST_INT) + low = INTVAL (x), high = low >> (HOST_BITS_PER_WIDE_INT -1); + else + low = CONST_DOUBLE_LOW (x), high = CONST_DOUBLE_HIGH (x); + +#ifdef HOST_WORDS_BIG_ENDIAN + u.i[0] = high, u.i[1] = low; +#else + u.i[0] = low, u.i[1] = high; +#endif + + return CONST_DOUBLE_FROM_REAL_VALUE (u.d, mode); + } +#endif + + /* We need an extra case for machines where HOST_BITS_PER_WIDE_INT is the + same as sizeof (double) or when sizeof (float) is larger than the + size of a word on the target machine. */ +#ifdef REAL_ARITHMETIC + else if (mode == SFmode && GET_CODE (x) == CONST_INT) + { + REAL_VALUE_TYPE r; + HOST_WIDE_INT i; + + i = INTVAL (x); + r = REAL_VALUE_FROM_TARGET_SINGLE (i); + return CONST_DOUBLE_FROM_REAL_VALUE (r, mode); + } +#endif + + /* Similarly, if this is converting a floating-point value into a + single-word integer. Only do this is the host and target parameters are + compatible. */ + + else if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT + && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD) + || flag_pretend_float) + && (GET_MODE_CLASS (mode) == MODE_INT + || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT) + && GET_CODE (x) == CONST_DOUBLE + && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT + && GET_MODE_BITSIZE (mode) == BITS_PER_WORD) + return operand_subword (x, word, 0, GET_MODE (x)); + + /* Similarly, if this is converting a floating-point value into a + two-word integer, we can do this one word at a time and make an + integer. Only do this is the host and target parameters are + compatible. */ + + else if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT + && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD) + || flag_pretend_float) + && (GET_MODE_CLASS (mode) == MODE_INT + || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT) + && GET_CODE (x) == CONST_DOUBLE + && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT + && GET_MODE_BITSIZE (mode) == 2 * BITS_PER_WORD) + { + rtx lowpart + = operand_subword (x, word + WORDS_BIG_ENDIAN, 0, GET_MODE (x)); + rtx highpart + = operand_subword (x, word + ! WORDS_BIG_ENDIAN, 0, GET_MODE (x)); + + if (lowpart && GET_CODE (lowpart) == CONST_INT + && highpart && GET_CODE (highpart) == CONST_INT) + return immed_double_const (INTVAL (lowpart), INTVAL (highpart), mode); + } + + /* Otherwise, we can't do this. */ + return 0; +} + +/* 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 (mode, x) + enum machine_mode mode; + register rtx x; +{ + if (GET_CODE (x) == CONCAT && GET_MODE (XEXP (x, 0)) == mode) + return XEXP (x, 0); + 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 (mode, x) + enum machine_mode mode; + register rtx x; +{ + if (GET_CODE (x) == CONCAT && GET_MODE (XEXP (x, 0)) == mode) + return XEXP (x, 1); + else if (WORDS_BIG_ENDIAN) + return gen_lowpart (mode, x); + 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 (x) + rtx x; +{ + if (GET_CODE (x) != SUBREG) + abort (); + + return SUBREG_WORD (x) * UNITS_PER_WORD < 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 (mode, x) + enum machine_mode mode; + register 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. */ + register int offset = 0; + 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 change_address (x, mode, plus_constant (XEXP (x, 0), 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 (mode, x) + enum machine_mode mode; + register 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. */ + if (GET_MODE_SIZE (mode) > UNITS_PER_WORD + && GET_MODE_SIZE (mode) != GET_MODE_UNIT_SIZE (GET_MODE (x))) + abort (); + if (GET_CODE (x) == CONST_DOUBLE +#if !(TARGET_FLOAT_FORMAT != HOST_FLOAT_FORMAT || defined (REAL_IS_NOT_DOUBLE)) + && GET_MODE_CLASS (GET_MODE (x)) != MODE_FLOAT +#endif + ) + return GEN_INT (CONST_DOUBLE_HIGH (x) & GET_MODE_MASK (mode)); + else if (GET_CODE (x) == CONST_INT) + { + if (HOST_BITS_PER_WIDE_INT <= BITS_PER_WORD) + return const0_rtx; + return GEN_INT (INTVAL (x) >> (HOST_BITS_PER_WIDE_INT - BITS_PER_WORD)); + } + else if (GET_CODE (x) == MEM) + { + register int offset = 0; + 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 + && GET_MODE_SIZE (mode) < UNITS_PER_WORD) + offset -= (GET_MODE_SIZE (mode) + - MIN (UNITS_PER_WORD, + GET_MODE_SIZE (GET_MODE (x)))); + + return change_address (x, mode, plus_constant (XEXP (x, 0), offset)); + } + else if (GET_CODE (x) == SUBREG) + { + /* The only time this should occur is when we are looking at a + multi-word item with a SUBREG whose mode is the same as that of the + item. It isn't clear what we would do if it wasn't. */ + if (SUBREG_WORD (x) != 0) + abort (); + return gen_highpart (mode, SUBREG_REG (x)); + } + else if (GET_CODE (x) == REG) + { + int word; + + /* Let the backend decide how many registers to skip. This is needed + in particular for sparc64 where fp regs are smaller than a word. */ + /* ??? Note that subregs are now ambiguous, in that those against + pseudos are sized by the word size, while those against hard + regs are sized by the underlying register size. Better would be + to always interpret the subreg offset parameter as bytes or bits. */ + + if (WORDS_BIG_ENDIAN) + word = 0; + else if (REGNO (x) < FIRST_PSEUDO_REGISTER) + word = (HARD_REGNO_NREGS (REGNO (x), GET_MODE (x)) + - HARD_REGNO_NREGS (REGNO (x), mode)); + else + word = ((GET_MODE_SIZE (GET_MODE (x)) + - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)) + / UNITS_PER_WORD); + + if (REGNO (x) < FIRST_PSEUDO_REGISTER + /* integrate.c can't handle parts of a return value register. */ + && (! REG_FUNCTION_VALUE_P (x) + || ! rtx_equal_function_value_matters) + /* We want to keep the stack, frame, and arg pointers special. */ + && x != frame_pointer_rtx +#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM + && x != arg_pointer_rtx +#endif + && x != stack_pointer_rtx) + return gen_rtx_REG (mode, REGNO (x) + word); + else + return gen_rtx_SUBREG (mode, x, word); + } + else + abort (); +} + +/* Return 1 iff X, assumed to be a SUBREG, + refers to the least significant part of its containing reg. + If X is not a SUBREG, always return 1 (it is its own low part!). */ + +int +subreg_lowpart_p (x) + rtx x; +{ + if (GET_CODE (x) != SUBREG) + return 1; + else if (GET_MODE (SUBREG_REG (x)) == VOIDmode) + return 0; + + if (WORDS_BIG_ENDIAN + && GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) > UNITS_PER_WORD) + return (SUBREG_WORD (x) + == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) + - MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)) + / UNITS_PER_WORD)); + + return SUBREG_WORD (x) == 0; +} + +/* Return subword I of operand OP. + The word number, I, is interpreted as the word number starting at the + low-order address. Word 0 is the low-order word if not WORDS_BIG_ENDIAN, + otherwise it is the high-order word. + + If we cannot extract the required word, we return zero. Otherwise, an + rtx corresponding to the requested word will be returned. + + VALIDATE_ADDRESS is nonzero if the address should be validated. Before + reload has completed, a valid address will always be returned. After + reload, if a valid address cannot be returned, we return zero. + + If VALIDATE_ADDRESS is zero, we simply form the required address; validating + it is the responsibility of the caller. + + MODE is the mode of OP in case it is a CONST_INT. */ + +rtx +operand_subword (op, i, validate_address, mode) + rtx op; + int i; + int validate_address; + enum machine_mode mode; +{ + HOST_WIDE_INT val; + int size_ratio = HOST_BITS_PER_WIDE_INT / BITS_PER_WORD; + int bits_per_word = BITS_PER_WORD; + + if (mode == VOIDmode) + mode = GET_MODE (op); + + if (mode == VOIDmode) + abort (); + + /* If OP is narrower than a word, fail. */ + if (mode != BLKmode + && (GET_MODE_SIZE (mode) < UNITS_PER_WORD)) + return 0; + + /* If we want a word outside OP, return zero. */ + if (mode != BLKmode + && (i + 1) * UNITS_PER_WORD > GET_MODE_SIZE (mode)) + return const0_rtx; + + /* If OP is already an integer word, return it. */ + if (GET_MODE_CLASS (mode) == MODE_INT + && GET_MODE_SIZE (mode) == UNITS_PER_WORD) + return op; + + /* If OP is a REG or SUBREG, we can handle it very simply. */ + if (GET_CODE (op) == REG) + { + /* If the register is not valid for MODE, return 0. If we don't + do this, there is no way to fix up the resulting REG later. */ + if (REGNO (op) < FIRST_PSEUDO_REGISTER + && ! HARD_REGNO_MODE_OK (REGNO (op) + i, word_mode)) + return 0; + else if (REGNO (op) >= FIRST_PSEUDO_REGISTER + || (REG_FUNCTION_VALUE_P (op) + && rtx_equal_function_value_matters) + /* We want to keep the stack, frame, and arg pointers + special. */ + || op == frame_pointer_rtx +#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM + || op == arg_pointer_rtx +#endif + || op == stack_pointer_rtx) + return gen_rtx_SUBREG (word_mode, op, i); + else + return gen_rtx_REG (word_mode, REGNO (op) + i); + } + else if (GET_CODE (op) == SUBREG) + return gen_rtx_SUBREG (word_mode, SUBREG_REG (op), i + SUBREG_WORD (op)); + else if (GET_CODE (op) == CONCAT) + { + int partwords = GET_MODE_UNIT_SIZE (GET_MODE (op)) / UNITS_PER_WORD; + if (i < partwords) + return operand_subword (XEXP (op, 0), i, validate_address, mode); + return operand_subword (XEXP (op, 1), i - partwords, + validate_address, mode); + } + + /* Form a new MEM at the requested address. */ + if (GET_CODE (op) == MEM) + { + rtx addr = plus_constant (XEXP (op, 0), i * UNITS_PER_WORD); + rtx new; + + if (validate_address) + { + if (reload_completed) + { + if (! strict_memory_address_p (word_mode, addr)) + return 0; + } + else + addr = memory_address (word_mode, addr); + } + + new = gen_rtx_MEM (word_mode, addr); + + MEM_COPY_ATTRIBUTES (new, op); + RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (op); + /* CYGNUS LOCAL unaligned-pointers */ + MEM_UNALIGNED_P (new) = MEM_UNALIGNED_P (op); + /* END CYGNUS LOCAL */ + + return new; + } + + /* The only remaining cases are when OP is a constant. If the host and + target floating formats are the same, handling two-word floating + constants are easy. Note that REAL_VALUE_TO_TARGET_{SINGLE,DOUBLE} + are defined as returning one or two 32 bit values, respectively, + and not values of BITS_PER_WORD bits. */ +#ifdef REAL_ARITHMETIC +/* The output is some bits, the width of the target machine's word. + A wider-word host can surely hold them in a CONST_INT. A narrower-word + host can't. */ + if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD + && GET_MODE_CLASS (mode) == MODE_FLOAT + && GET_MODE_BITSIZE (mode) == 64 + && GET_CODE (op) == CONST_DOUBLE) + { + long k[2]; + REAL_VALUE_TYPE rv; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, op); + REAL_VALUE_TO_TARGET_DOUBLE (rv, k); + + /* We handle 32-bit and >= 64-bit words here. Note that the order in + which the words are written depends on the word endianness. + + ??? This is a potential portability problem and should + be fixed at some point. */ + if (BITS_PER_WORD == 32) + return GEN_INT ((HOST_WIDE_INT) k[i]); +#if HOST_BITS_PER_WIDE_INT > 32 + else if (BITS_PER_WORD >= 64 && i == 0) + return GEN_INT ((((HOST_WIDE_INT) k[! WORDS_BIG_ENDIAN]) << 32) + | (HOST_WIDE_INT) k[WORDS_BIG_ENDIAN]); +#endif + else if (BITS_PER_WORD == 16) + { + long value; + value = k[i >> 1]; + if ((i & 0x1) == !WORDS_BIG_ENDIAN) + value >>= 16; + value &= 0xffff; + return GEN_INT ((HOST_WIDE_INT) value); + } + else + abort (); + } + else if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD + && GET_MODE_CLASS (mode) == MODE_FLOAT + && GET_MODE_BITSIZE (mode) > 64 + && GET_CODE (op) == CONST_DOUBLE) + { + long k[4]; + REAL_VALUE_TYPE rv; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, op); + REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k); + + if (BITS_PER_WORD == 32) + return GEN_INT ((HOST_WIDE_INT) k[i]); + } +#else /* no REAL_ARITHMETIC */ + if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT + && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD) + || flag_pretend_float) + && GET_MODE_CLASS (mode) == MODE_FLOAT + && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD + && GET_CODE (op) == CONST_DOUBLE) + { + /* The constant is stored in the host's word-ordering, + but we want to access it in the target's word-ordering. Some + compilers don't like a conditional inside macro args, so we have two + copies of the return. */ +#ifdef HOST_WORDS_BIG_ENDIAN + return GEN_INT (i == WORDS_BIG_ENDIAN + ? CONST_DOUBLE_HIGH (op) : CONST_DOUBLE_LOW (op)); +#else + return GEN_INT (i != WORDS_BIG_ENDIAN + ? CONST_DOUBLE_HIGH (op) : CONST_DOUBLE_LOW (op)); +#endif + } +#endif /* no REAL_ARITHMETIC */ + + /* Single word float is a little harder, since single- and double-word + values often do not have the same high-order bits. We have already + verified that we want the only defined word of the single-word value. */ +#ifdef REAL_ARITHMETIC + if (GET_MODE_CLASS (mode) == MODE_FLOAT + && GET_MODE_BITSIZE (mode) == 32 + && GET_CODE (op) == CONST_DOUBLE) + { + long l; + REAL_VALUE_TYPE rv; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, op); + REAL_VALUE_TO_TARGET_SINGLE (rv, l); + + if (BITS_PER_WORD == 16) + { + if ((i & 0x1) == !WORDS_BIG_ENDIAN) + l >>= 16; + l &= 0xffff; + } + return GEN_INT ((HOST_WIDE_INT) l); + } +#else + if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT + && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD) + || flag_pretend_float) + && sizeof (float) * 8 == HOST_BITS_PER_WIDE_INT + && GET_MODE_CLASS (mode) == MODE_FLOAT + && GET_MODE_SIZE (mode) == UNITS_PER_WORD + && GET_CODE (op) == CONST_DOUBLE) + { + double d; + union {float f; HOST_WIDE_INT i; } u; + + REAL_VALUE_FROM_CONST_DOUBLE (d, op); + + u.f = d; + return GEN_INT (u.i); + } + if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT + && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD) + || flag_pretend_float) + && sizeof (double) * 8 == HOST_BITS_PER_WIDE_INT + && GET_MODE_CLASS (mode) == MODE_FLOAT + && GET_MODE_SIZE (mode) == UNITS_PER_WORD + && GET_CODE (op) == CONST_DOUBLE) + { + double d; + union {double d; HOST_WIDE_INT i; } u; + + REAL_VALUE_FROM_CONST_DOUBLE (d, op); + + u.d = d; + return GEN_INT (u.i); + } +#endif /* no REAL_ARITHMETIC */ + + /* The only remaining cases that we can handle are integers. + Convert to proper endianness now since these cases need it. + At this point, i == 0 means the low-order word. + + We do not want to handle the case when BITS_PER_WORD <= HOST_BITS_PER_INT + in general. However, if OP is (const_int 0), we can just return + it for any word. */ + + if (op == const0_rtx) + return op; + + if (GET_MODE_CLASS (mode) != MODE_INT + || (GET_CODE (op) != CONST_INT && GET_CODE (op) != CONST_DOUBLE) + || BITS_PER_WORD > HOST_BITS_PER_WIDE_INT) + return 0; + + if (WORDS_BIG_ENDIAN) + i = GET_MODE_SIZE (mode) / UNITS_PER_WORD - 1 - i; + + /* Find out which word on the host machine this value is in and get + it from the constant. */ + val = (i / size_ratio == 0 + ? (GET_CODE (op) == CONST_INT ? INTVAL (op) : CONST_DOUBLE_LOW (op)) + : (GET_CODE (op) == CONST_INT + ? (INTVAL (op) < 0 ? ~0 : 0) : CONST_DOUBLE_HIGH (op))); + + /* Get the value we want into the low bits of val. */ + if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT) + val = ((val >> ((i % size_ratio) * BITS_PER_WORD))); + + /* Clear the bits that don't belong in our 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. */ + if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT + && ((val & ((HOST_WIDE_INT) (-1) << (bits_per_word - 1))) + != ((HOST_WIDE_INT) (-1) << (bits_per_word - 1)))) + val &= ((HOST_WIDE_INT) 1 << bits_per_word) - 1; + + /* 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 later confuses the sparc backend. */ + + if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT + && (val & ((HOST_WIDE_INT) 1 << (bits_per_word - 1)))) + val |= ((HOST_WIDE_INT) (-1) << bits_per_word); + + return GEN_INT (val); +} + +/* 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. It is not valid + to call this function after reload; it is mostly meant for RTL + generation. + + MODE is the mode of OP, in case it is CONST_INT. */ + +rtx +operand_subword_force (op, i, mode) + rtx op; + int i; + enum machine_mode mode; +{ + rtx result = operand_subword (op, i, 1, mode); + + if (result) + return result; + + if (mode != BLKmode && mode != VOIDmode) + { + /* If this is a register which can not be accessed by words, copy it + to a pseudo register. */ + if (GET_CODE (op) == REG) + op = copy_to_reg (op); + else + op = force_reg (mode, op); + } + + result = operand_subword (op, i, 1, mode); + 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 (insn) + 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; + } +} + +/* Return a memory reference like MEMREF, but with its mode changed + to MODE and its address changed to ADDR. + (VOIDmode means don't change the mode. + NULL for ADDR means don't change the address.) */ + +rtx +change_address (memref, mode, addr) + rtx memref; + enum machine_mode mode; + rtx addr; +{ + rtx new; + + if (GET_CODE (memref) != MEM) + abort (); + if (mode == VOIDmode) + mode = GET_MODE (memref); + if (addr == 0) + addr = XEXP (memref, 0); + + /* If reload is in progress or has completed, ADDR must be valid. + Otherwise, we can call memory_address to make it valid. */ + if (reload_completed || reload_in_progress) + { + if (! memory_address_p (mode, addr)) + abort (); + } + else + addr = memory_address (mode, addr); + + if (rtx_equal_p (addr, XEXP (memref, 0)) && mode == GET_MODE (memref)) + return memref; + + new = gen_rtx_MEM (mode, addr); + RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (memref); + MEM_COPY_ATTRIBUTES (new, memref); + /* CYGNUS LOCAL unaligned-pointers */ + MEM_UNALIGNED_P (new) = MEM_UNALIGNED_P (memref); + /* END CYGNUS LOCAL */ + return new; +} + +/* Return a newly created CODE_LABEL rtx with a unique label number. */ + +rtx +gen_label_rtx () +{ + register rtx label; + + label = gen_rtx_CODE_LABEL (VOIDmode, 0, NULL_RTX, + NULL_RTX, label_num++, NULL_PTR); + + LABEL_NUSES (label) = 0; + return label; +} + +/* For procedure integration. */ + +/* Return a newly created INLINE_HEADER rtx. Should allocate this + from a permanent obstack when the opportunity arises. */ + +rtx +gen_inline_header_rtx (first_insn, first_parm_insn, first_labelno, + last_labelno, max_parm_regnum, max_regnum, args_size, + pops_args, stack_slots, forced_labels, function_flags, + outgoing_args_size, original_arg_vector, + original_decl_initial, regno_rtx, regno_flag, + regno_align, parm_reg_stack_loc) + rtx first_insn, first_parm_insn; + int first_labelno, last_labelno, max_parm_regnum, max_regnum, args_size; + int pops_args; + rtx stack_slots; + rtx forced_labels; + int function_flags; + int outgoing_args_size; + rtvec original_arg_vector; + rtx original_decl_initial; + rtvec regno_rtx; + char *regno_flag; + char *regno_align; + rtvec parm_reg_stack_loc; +{ + rtx header = gen_rtx_INLINE_HEADER (VOIDmode, + cur_insn_uid++, NULL_RTX, + first_insn, first_parm_insn, + first_labelno, last_labelno, + max_parm_regnum, max_regnum, args_size, + pops_args, stack_slots, forced_labels, + function_flags, outgoing_args_size, + original_arg_vector, + original_decl_initial, + regno_rtx, regno_flag, regno_align, + parm_reg_stack_loc); + return header; +} + +/* Install new pointers to the first and last insns in the chain. + Also, set cur_insn_uid to one higher than the last in use. + Used for an inline-procedure after copying the insn chain. */ + +void +set_new_first_and_last_insn (first, last) + rtx first, last; +{ + rtx insn; + + first_insn = first; + last_insn = last; + cur_insn_uid = 0; + + for (insn = first; insn; insn = NEXT_INSN (insn)) + cur_insn_uid = MAX (cur_insn_uid, INSN_UID (insn)); + + cur_insn_uid++; +} + +/* Set the range of label numbers found in the current function. + This is used when belatedly compiling an inline function. */ + +void +set_new_first_and_last_label_num (first, last) + int first, last; +{ + base_label_num = label_num; + first_label_num = first; + last_label_num = last; +} + +/* Save all variables describing the current status into the structure *P. + This is used before starting a nested function. */ + +void +save_emit_status (p) + struct function *p; +{ + p->reg_rtx_no = reg_rtx_no; + p->first_label_num = first_label_num; + p->first_insn = first_insn; + p->last_insn = last_insn; + p->sequence_rtl_expr = sequence_rtl_expr; + p->sequence_stack = sequence_stack; + p->cur_insn_uid = cur_insn_uid; + p->last_linenum = last_linenum; + p->last_filename = last_filename; + p->regno_pointer_flag = regno_pointer_flag; + p->regno_pointer_align = regno_pointer_align; + p->regno_pointer_flag_length = regno_pointer_flag_length; + p->regno_reg_rtx = regno_reg_rtx; +} + +/* Restore all variables describing the current status from the structure *P. + This is used after a nested function. */ + +void +restore_emit_status (p) + struct function *p; +{ + int i; + + reg_rtx_no = p->reg_rtx_no; + first_label_num = p->first_label_num; + last_label_num = 0; + first_insn = p->first_insn; + last_insn = p->last_insn; + sequence_rtl_expr = p->sequence_rtl_expr; + sequence_stack = p->sequence_stack; + cur_insn_uid = p->cur_insn_uid; + last_linenum = p->last_linenum; + last_filename = p->last_filename; + regno_pointer_flag = p->regno_pointer_flag; + regno_pointer_align = p->regno_pointer_align; + regno_pointer_flag_length = p->regno_pointer_flag_length; + regno_reg_rtx = p->regno_reg_rtx; + + /* Clear our cache of rtx expressions for start_sequence and + gen_sequence. */ + sequence_element_free_list = 0; + for (i = 0; i < SEQUENCE_RESULT_SIZE; i++) + sequence_result[i] = 0; + + free_insn = 0; +} + +/* Go through all the RTL insn bodies and copy any invalid shared structure. + It does not work to do this twice, because the mark bits set here + are not cleared afterwards. */ + +void +unshare_all_rtl (insn) + register rtx insn; +{ + for (; insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN + || GET_CODE (insn) == CALL_INSN) + { + PATTERN (insn) = copy_rtx_if_shared (PATTERN (insn)); + REG_NOTES (insn) = copy_rtx_if_shared (REG_NOTES (insn)); + LOG_LINKS (insn) = copy_rtx_if_shared (LOG_LINKS (insn)); + } + + /* Make sure the addresses of stack slots found outside the insn chain + (such as, in DECL_RTL of a variable) are not shared + with the insn chain. + + This special care is necessary when the stack slot MEM does not + actually appear in the insn chain. If it does appear, its address + is unshared from all else at that point. */ + + copy_rtx_if_shared (stack_slot_list); +} + +/* Mark ORIG as in use, and return a copy of it if it was already in use. + Recursively does the same for subexpressions. */ + +rtx +copy_rtx_if_shared (orig) + rtx orig; +{ + register rtx x = orig; + register int i; + register enum rtx_code code; + register char *format_ptr; + int copied = 0; + + if (x == 0) + return 0; + + code = GET_CODE (x); + + /* These types may be freely shared. */ + + switch (code) + { + case REG: + case QUEUED: + case CONST_INT: + case CONST_DOUBLE: + case SYMBOL_REF: + case CODE_LABEL: + case PC: + case CC0: + case SCRATCH: + /* SCRATCH must be shared because they represent distinct values. */ + return x; + + case CONST: + /* CONST can be shared if it contains a SYMBOL_REF. If it contains + a LABEL_REF, it isn't sharable. */ + if (GET_CODE (XEXP (x, 0)) == PLUS + && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT) + return x; + break; + + case INSN: + case JUMP_INSN: + case CALL_INSN: + case NOTE: + case BARRIER: + /* The chain of insns is not being copied. */ + return x; + + case MEM: + /* A MEM is allowed to be shared if its address is constant + or is a constant plus one of the special registers. */ + if (CONSTANT_ADDRESS_P (XEXP (x, 0)) + || XEXP (x, 0) == virtual_stack_vars_rtx + || XEXP (x, 0) == virtual_incoming_args_rtx) + return x; + + if (GET_CODE (XEXP (x, 0)) == PLUS + && (XEXP (XEXP (x, 0), 0) == virtual_stack_vars_rtx + || XEXP (XEXP (x, 0), 0) == virtual_incoming_args_rtx) + && CONSTANT_ADDRESS_P (XEXP (XEXP (x, 0), 1))) + { + /* This MEM can appear in more than one place, + but its address better not be shared with anything else. */ + if (! x->used) + XEXP (x, 0) = copy_rtx_if_shared (XEXP (x, 0)); + x->used = 1; + return x; + } + break; + + default: + break; + } + + /* This rtx may not be shared. If it has already been seen, + replace it with a copy of itself. */ + + if (x->used) + { + register rtx copy; + + copy = rtx_alloc (code); + bcopy ((char *) x, (char *) copy, + (sizeof (*copy) - sizeof (copy->fld) + + sizeof (copy->fld[0]) * GET_RTX_LENGTH (code))); + x = copy; + copied = 1; + } + x->used = 1; + + /* Now scan the subexpressions recursively. + We can store any replaced subexpressions directly into X + since we know X is not shared! Any vectors in X + must be copied if X was copied. */ + + format_ptr = GET_RTX_FORMAT (code); + + for (i = 0; i < GET_RTX_LENGTH (code); i++) + { + switch (*format_ptr++) + { + case 'e': + XEXP (x, i) = copy_rtx_if_shared (XEXP (x, i)); + break; + + case 'E': + if (XVEC (x, i) != NULL) + { + register int j; + int len = XVECLEN (x, i); + + if (copied && len > 0) + XVEC (x, i) = gen_rtvec_vv (len, XVEC (x, i)->elem); + for (j = 0; j < len; j++) + XVECEXP (x, i, j) = copy_rtx_if_shared (XVECEXP (x, i, j)); + } + break; + } + } + return x; +} + +/* Clear all the USED bits in X to allow copy_rtx_if_shared to be used + to look for shared sub-parts. */ + +void +reset_used_flags (x) + rtx x; +{ + register int i, j; + register enum rtx_code code; + register char *format_ptr; + + if (x == 0) + return; + + code = GET_CODE (x); + + /* These types may be freely shared so we needn't do any resetting + for them. */ + + switch (code) + { + case REG: + case QUEUED: + case CONST_INT: + case CONST_DOUBLE: + case SYMBOL_REF: + case CODE_LABEL: + case PC: + case CC0: + return; + + case INSN: + case JUMP_INSN: + case CALL_INSN: + case NOTE: + case LABEL_REF: + case BARRIER: + /* The chain of insns is not being copied. */ + return; + + default: + break; + } + + x->used = 0; + + format_ptr = GET_RTX_FORMAT (code); + for (i = 0; i < GET_RTX_LENGTH (code); i++) + { + switch (*format_ptr++) + { + case 'e': + reset_used_flags (XEXP (x, i)); + break; + + case 'E': + for (j = 0; j < XVECLEN (x, i); j++) + reset_used_flags (XVECEXP (x, i, j)); + break; + } + } +} + +/* Copy X if necessary so that it won't be altered by changes in OTHER. + Return X or the rtx for the pseudo reg the value of X was copied into. + OTHER must be valid as a SET_DEST. */ + +rtx +make_safe_from (x, other) + rtx x, other; +{ + while (1) + switch (GET_CODE (other)) + { + case SUBREG: + other = SUBREG_REG (other); + break; + case STRICT_LOW_PART: + case SIGN_EXTEND: + case ZERO_EXTEND: + other = XEXP (other, 0); + break; + default: + goto done; + } + done: + if ((GET_CODE (other) == MEM + && ! CONSTANT_P (x) + && GET_CODE (x) != REG + && GET_CODE (x) != SUBREG) + || (GET_CODE (other) == REG + && (REGNO (other) < FIRST_PSEUDO_REGISTER + || reg_mentioned_p (other, x)))) + { + rtx temp = gen_reg_rtx (GET_MODE (x)); + emit_move_insn (temp, x); + return temp; + } + return x; +} + +/* Emission of insns (adding them to the doubly-linked list). */ + +/* Return the first insn of the current sequence or current function. */ + +rtx +get_insns () +{ + return first_insn; +} + +/* Return the last insn emitted in current sequence or current function. */ + +rtx +get_last_insn () +{ + return last_insn; +} + +/* Specify a new insn as the last in the chain. */ + +void +set_last_insn (insn) + rtx insn; +{ + if (NEXT_INSN (insn) != 0) + abort (); + last_insn = insn; +} + +/* Return the last insn emitted, even if it is in a sequence now pushed. */ + +rtx +get_last_insn_anywhere () +{ + struct sequence_stack *stack; + if (last_insn) + return last_insn; + for (stack = sequence_stack; stack; stack = stack->next) + if (stack->last != 0) + return stack->last; + return 0; +} + +/* Return a number larger than any instruction's uid in this function. */ + +int +get_max_uid () +{ + return cur_insn_uid; +} + +/* Return the next insn. If it is a SEQUENCE, return the first insn + of the sequence. */ + +rtx +next_insn (insn) + rtx insn; +{ + if (insn) + { + insn = NEXT_INSN (insn); + if (insn && GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == SEQUENCE) + insn = XVECEXP (PATTERN (insn), 0, 0); + } + + return insn; +} + +/* Return the previous insn. If it is a SEQUENCE, return the last insn + of the sequence. */ + +rtx +previous_insn (insn) + rtx insn; +{ + if (insn) + { + insn = PREV_INSN (insn); + if (insn && GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == SEQUENCE) + insn = XVECEXP (PATTERN (insn), 0, XVECLEN (PATTERN (insn), 0) - 1); + } + + return insn; +} + +/* Return the next insn after INSN that is not a NOTE. This routine does not + look inside SEQUENCEs. */ + +rtx +next_nonnote_insn (insn) + rtx insn; +{ + while (insn) + { + insn = NEXT_INSN (insn); + if (insn == 0 || GET_CODE (insn) != NOTE) + break; + } + + return insn; +} + +/* Return the previous insn before INSN that is not a NOTE. This routine does + not look inside SEQUENCEs. */ + +rtx +prev_nonnote_insn (insn) + rtx insn; +{ + while (insn) + { + insn = PREV_INSN (insn); + if (insn == 0 || GET_CODE (insn) != NOTE) + break; + } + + return insn; +} + +/* Return the next INSN, CALL_INSN or JUMP_INSN after INSN; + or 0, if there is none. This routine does not look inside + SEQUENCEs. */ + +rtx +next_real_insn (insn) + rtx insn; +{ + while (insn) + { + insn = NEXT_INSN (insn); + if (insn == 0 || GET_CODE (insn) == INSN + || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN) + break; + } + + return insn; +} + +/* Return the last INSN, CALL_INSN or JUMP_INSN before INSN; + or 0, if there is none. This routine does not look inside + SEQUENCEs. */ + +rtx +prev_real_insn (insn) + rtx insn; +{ + while (insn) + { + insn = PREV_INSN (insn); + if (insn == 0 || GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN + || GET_CODE (insn) == JUMP_INSN) + break; + } + + return insn; +} + +/* Find the next insn after INSN that really does something. This routine + does not look inside SEQUENCEs. Until reload has completed, this is the + same as next_real_insn. */ + +rtx +next_active_insn (insn) + rtx insn; +{ + while (insn) + { + insn = NEXT_INSN (insn); + if (insn == 0 + || 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)))) + break; + } + + return insn; +} + +/* Find the last insn before INSN that really does something. This routine + does not look inside SEQUENCEs. Until reload has completed, this is the + same as prev_real_insn. */ + +rtx +prev_active_insn (insn) + rtx insn; +{ + while (insn) + { + insn = PREV_INSN (insn); + if (insn == 0 + || 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)))) + break; + } + + return insn; +} + +/* Return the next CODE_LABEL after the insn INSN, or 0 if there is none. */ + +rtx +next_label (insn) + rtx insn; +{ + while (insn) + { + insn = NEXT_INSN (insn); + if (insn == 0 || GET_CODE (insn) == CODE_LABEL) + break; + } + + return insn; +} + +/* Return the last CODE_LABEL before the insn INSN, or 0 if there is none. */ + +rtx +prev_label (insn) + rtx insn; +{ + while (insn) + { + insn = PREV_INSN (insn); + if (insn == 0 || GET_CODE (insn) == CODE_LABEL) + break; + } + + return insn; +} + +#ifdef HAVE_cc0 +/* INSN uses CC0 and is being moved into a delay slot. Set up REG_CC_SETTER + and REG_CC_USER notes so we can find it. */ + +void +link_cc0_insns (insn) + rtx insn; +{ + rtx user = next_nonnote_insn (insn); + + 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, REG_NOTES (user)); + REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_CC_USER, user, REG_NOTES (insn)); +} + +/* Return the next insn that uses CC0 after INSN, which is assumed to + set it. This is the inverse of prev_cc0_setter (i.e., prev_cc0_setter + applied to the result of this function should yield INSN). + + Normally, this is simply the next insn. However, if a REG_CC_USER note + is present, it contains the insn that uses CC0. + + Return 0 if we can't find the insn. */ + +rtx +next_cc0_user (insn) + rtx insn; +{ + rtx note = find_reg_note (insn, REG_CC_USER, NULL_RTX); + + if (note) + return XEXP (note, 0); + + insn = next_nonnote_insn (insn); + if (insn && GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE) + insn = XVECEXP (PATTERN (insn), 0, 0); + + if (insn && GET_RTX_CLASS (GET_CODE (insn)) == 'i' + && reg_mentioned_p (cc0_rtx, PATTERN (insn))) + return insn; + + return 0; +} + +/* Find the insn that set CC0 for INSN. Unless INSN has a REG_CC_SETTER + note, it is the previous insn. */ + +rtx +prev_cc0_setter (insn) + rtx insn; +{ + rtx note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX); + + if (note) + return XEXP (note, 0); + + insn = prev_nonnote_insn (insn); + if (! sets_cc0_p (PATTERN (insn))) + abort (); + + return insn; +} +#endif + +/* Try splitting insns that can be split for better scheduling. + PAT is the pattern which might split. + TRIAL is the insn providing PAT. + LAST is non-zero if we should return the last insn of the sequence produced. + + If this routine succeeds in splitting, it returns the first or last + replacement insn depending on the value of LAST. Otherwise, it + returns TRIAL. If the insn to be returned can be split, it will be. */ + +rtx +try_split (pat, trial, last) + rtx pat, trial; + int last; +{ + rtx before = PREV_INSN (trial); + rtx after = NEXT_INSN (trial); + rtx seq = split_insns (pat, trial); + int has_barrier = 0; + rtx tem; + + /* If we are splitting a JUMP_INSN, it might be followed by a BARRIER. + We may need to handle this specially. */ + if (after && GET_CODE (after) == BARRIER) + { + has_barrier = 1; + after = NEXT_INSN (after); + } + + if (seq) + { + /* SEQ can either be a SEQUENCE or the pattern of a single insn. + The latter case will normally arise only when being done so that + it, in turn, will be split (SFmode on the 29k is an example). */ + if (GET_CODE (seq) == SEQUENCE) + { + /* If we are splitting a JUMP_INSN, look for the JUMP_INSN in + SEQ and copy our JUMP_LABEL to it. If JUMP_LABEL is non-zero, + increment the usage count so we don't delete the label. */ + int i; + + if (GET_CODE (trial) == JUMP_INSN) + for (i = XVECLEN (seq, 0) - 1; i >= 0; i--) + if (GET_CODE (XVECEXP (seq, 0, i)) == JUMP_INSN) + { + JUMP_LABEL (XVECEXP (seq, 0, i)) = JUMP_LABEL (trial); + + if (JUMP_LABEL (trial)) + LABEL_NUSES (JUMP_LABEL (trial))++; + } + + tem = emit_insn_after (seq, before); + + delete_insn (trial); + if (has_barrier) + emit_barrier_after (tem); + + /* Recursively call try_split for each new insn created; by the + time control returns here that insn will be fully split, so + set LAST and continue from the insn after the one returned. + We can't use next_active_insn here since AFTER may be a note. + Ignore deleted insns, which can be occur if not optimizing. */ + for (tem = NEXT_INSN (before); tem != after; + tem = NEXT_INSN (tem)) + if (! INSN_DELETED_P (tem) + && GET_RTX_CLASS (GET_CODE (tem)) == 'i') + tem = try_split (PATTERN (tem), tem, 1); + } + /* Avoid infinite loop if the result matches the original pattern. */ + else if (rtx_equal_p (seq, pat)) + return trial; + else + { + PATTERN (trial) = seq; + INSN_CODE (trial) = -1; + try_split (seq, trial, last); + } + + /* Return either the first or the last insn, depending on which was + requested. */ + return last ? prev_active_insn (after) : next_active_insn (before); + } + + return trial; +} + +/* Make and return an INSN rtx, initializing all its slots. + Store PATTERN in the pattern slots. */ + +rtx +make_insn_raw (pattern) + rtx pattern; +{ + register rtx insn; + + /* If in RTL generation phase, see if FREE_INSN can be used. */ + if (free_insn != 0 && rtx_equal_function_value_matters) + { + insn = free_insn; + free_insn = NEXT_INSN (free_insn); + PUT_CODE (insn, INSN); + } + else + insn = rtx_alloc (INSN); + + INSN_UID (insn) = cur_insn_uid++; + PATTERN (insn) = pattern; + INSN_CODE (insn) = -1; + LOG_LINKS (insn) = NULL; + REG_NOTES (insn) = NULL; + + return insn; +} + +/* Like `make_insn' but make a JUMP_INSN instead of an insn. */ + +static rtx +make_jump_insn_raw (pattern) + rtx pattern; +{ + register rtx insn; + + insn = rtx_alloc (JUMP_INSN); + INSN_UID (insn) = cur_insn_uid++; + + PATTERN (insn) = pattern; + INSN_CODE (insn) = -1; + LOG_LINKS (insn) = NULL; + REG_NOTES (insn) = NULL; + JUMP_LABEL (insn) = NULL; + + return insn; +} + +/* Like `make_insn' but make a CALL_INSN instead of an insn. */ + +static rtx +make_call_insn_raw (pattern) + rtx pattern; +{ + register rtx insn; + + insn = rtx_alloc (CALL_INSN); + INSN_UID (insn) = cur_insn_uid++; + + PATTERN (insn) = pattern; + INSN_CODE (insn) = -1; + LOG_LINKS (insn) = NULL; + REG_NOTES (insn) = NULL; + CALL_INSN_FUNCTION_USAGE (insn) = NULL; + + return insn; +} + +/* Add INSN to the end of the doubly-linked list. + INSN may be an INSN, JUMP_INSN, CALL_INSN, CODE_LABEL, BARRIER or NOTE. */ + +void +add_insn (insn) + register rtx insn; +{ + PREV_INSN (insn) = last_insn; + NEXT_INSN (insn) = 0; + + if (NULL != last_insn) + NEXT_INSN (last_insn) = insn; + + if (NULL == first_insn) + first_insn = insn; + + last_insn = insn; +} + +/* Add INSN into the doubly-linked list after insn AFTER. This and + the next should be the only functions called to insert an insn once + delay slots have been filled since only they know how to update a + SEQUENCE. */ + +void +add_insn_after (insn, after) + rtx insn, after; +{ + rtx next = NEXT_INSN (after); + + if (optimize && INSN_DELETED_P (after)) + abort (); + + NEXT_INSN (insn) = next; + PREV_INSN (insn) = after; + + if (next) + { + PREV_INSN (next) = insn; + if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == SEQUENCE) + PREV_INSN (XVECEXP (PATTERN (next), 0, 0)) = insn; + } + else if (last_insn == after) + last_insn = insn; + else + { + struct sequence_stack *stack = sequence_stack; + /* Scan all pending sequences too. */ + for (; stack; stack = stack->next) + if (after == stack->last) + { + stack->last = insn; + break; + } + + if (stack == 0) + abort (); + } + + NEXT_INSN (after) = insn; + if (GET_CODE (after) == INSN && GET_CODE (PATTERN (after)) == SEQUENCE) + { + rtx sequence = PATTERN (after); + NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = insn; + } +} + +/* Add INSN into the doubly-linked list before insn BEFORE. This and + the previous should be the only functions called to insert an insn once + delay slots have been filled since only they know how to update a + SEQUENCE. */ + +void +add_insn_before (insn, before) + rtx insn, before; +{ + rtx prev = PREV_INSN (before); + + if (optimize && INSN_DELETED_P (before)) + abort (); + + PREV_INSN (insn) = prev; + NEXT_INSN (insn) = before; + + if (prev) + { + NEXT_INSN (prev) = insn; + if (GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SEQUENCE) + { + rtx sequence = PATTERN (prev); + NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = insn; + } + } + else if (first_insn == before) + first_insn = insn; + else + { + struct sequence_stack *stack = sequence_stack; + /* Scan all pending sequences too. */ + for (; stack; stack = stack->next) + if (before == stack->first) + { + stack->first = insn; + break; + } + + if (stack == 0) + abort (); + } + + PREV_INSN (before) = insn; + if (GET_CODE (before) == INSN && GET_CODE (PATTERN (before)) == SEQUENCE) + PREV_INSN (XVECEXP (PATTERN (before), 0, 0)) = insn; +} + +/* Remove an insn from its doubly-linked list. This function knows how + to handle sequences. */ +void +remove_insn (insn) + rtx insn; +{ + rtx next = NEXT_INSN (insn); + rtx prev = PREV_INSN (insn); + if (prev) + { + NEXT_INSN (prev) = next; + if (GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SEQUENCE) + { + rtx sequence = PATTERN (prev); + NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = next; + } + } + else if (first_insn == insn) + first_insn = next; + else + { + struct sequence_stack *stack = sequence_stack; + /* Scan all pending sequences too. */ + for (; stack; stack = stack->next) + if (insn == stack->first) + { + stack->first = next; + break; + } + + if (stack == 0) + abort (); + } + + if (next) + { + PREV_INSN (next) = prev; + if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == SEQUENCE) + PREV_INSN (XVECEXP (PATTERN (next), 0, 0)) = prev; + } + else if (last_insn == insn) + last_insn = prev; + else + { + struct sequence_stack *stack = sequence_stack; + /* Scan all pending sequences too. */ + for (; stack; stack = stack->next) + if (insn == stack->last) + { + stack->last = prev; + break; + } + + if (stack == 0) + abort (); + } +} + +/* Delete all insns made since FROM. + FROM becomes the new last instruction. */ + +void +delete_insns_since (from) + rtx from; +{ + if (from == 0) + first_insn = 0; + else + NEXT_INSN (from) = 0; + last_insn = from; +} + +/* This function is deprecated, please use sequences instead. + + Move a consecutive bunch of insns to a different place in the chain. + The insns to be moved are those between FROM and TO. + They are moved to a new position after the insn AFTER. + AFTER must not be FROM or TO or any insn in between. + + This function does not know about SEQUENCEs and hence should not be + called after delay-slot filling has been done. */ + +void +reorder_insns (from, to, after) + rtx from, to, after; +{ + /* Splice this bunch out of where it is now. */ + if (PREV_INSN (from)) + NEXT_INSN (PREV_INSN (from)) = NEXT_INSN (to); + if (NEXT_INSN (to)) + PREV_INSN (NEXT_INSN (to)) = PREV_INSN (from); + if (last_insn == to) + last_insn = PREV_INSN (from); + if (first_insn == from) + first_insn = NEXT_INSN (to); + + /* Make the new neighbors point to it and it to them. */ + if (NEXT_INSN (after)) + PREV_INSN (NEXT_INSN (after)) = to; + + NEXT_INSN (to) = NEXT_INSN (after); + PREV_INSN (from) = after; + NEXT_INSN (after) = from; + if (after == last_insn) + last_insn = to; +} + +/* Return the line note insn preceding INSN. */ + +static rtx +find_line_note (insn) + rtx insn; +{ + if (no_line_numbers) + return 0; + + for (; insn; insn = PREV_INSN (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 (from, to, after) + rtx from, to, 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_line_note_after (NOTE_SOURCE_FILE (from_line), + NOTE_LINE_NUMBER (from_line), + after); + if (after_line) + emit_line_note_after (NOTE_SOURCE_FILE (after_line), + NOTE_LINE_NUMBER (after_line), + to); +} + +/* Emit an insn of given code and pattern + at a specified place within the doubly-linked list. */ + +/* Make an instruction with body PATTERN + and output it before the instruction BEFORE. */ + +rtx +emit_insn_before (pattern, before) + register rtx pattern, before; +{ + register rtx insn = before; + + if (GET_CODE (pattern) == SEQUENCE) + { + register int i; + + for (i = 0; i < XVECLEN (pattern, 0); i++) + { + insn = XVECEXP (pattern, 0, i); + add_insn_before (insn, before); + } + if (XVECLEN (pattern, 0) < SEQUENCE_RESULT_SIZE) + sequence_result[XVECLEN (pattern, 0)] = pattern; + } + else + { + insn = make_insn_raw (pattern); + add_insn_before (insn, before); + } + + return insn; +} + +/* Make an instruction with body PATTERN and code JUMP_INSN + and output it before the instruction BEFORE. */ + +rtx +emit_jump_insn_before (pattern, before) + register rtx pattern, before; +{ + register rtx insn; + + if (GET_CODE (pattern) == SEQUENCE) + insn = emit_insn_before (pattern, before); + else + { + insn = make_jump_insn_raw (pattern); + add_insn_before (insn, before); + } + + return insn; +} + +/* Make an instruction with body PATTERN and code CALL_INSN + and output it before the instruction BEFORE. */ + +rtx +emit_call_insn_before (pattern, before) + register rtx pattern, before; +{ + register rtx insn; + + if (GET_CODE (pattern) == SEQUENCE) + insn = emit_insn_before (pattern, before); + else + { + insn = make_call_insn_raw (pattern); + add_insn_before (insn, before); + PUT_CODE (insn, CALL_INSN); + } + + return insn; +} + +/* Make an insn of code BARRIER + and output it before the insn AFTER. */ + +rtx +emit_barrier_before (before) + register rtx before; +{ + register rtx insn = rtx_alloc (BARRIER); + + INSN_UID (insn) = cur_insn_uid++; + + add_insn_before (insn, before); + return insn; +} + +/* Emit a note of subtype SUBTYPE before the insn BEFORE. */ + +rtx +emit_note_before (subtype, before) + int subtype; + rtx before; +{ + register rtx note = rtx_alloc (NOTE); + INSN_UID (note) = cur_insn_uid++; + NOTE_SOURCE_FILE (note) = 0; + NOTE_LINE_NUMBER (note) = subtype; + + add_insn_before (note, before); + return note; +} + +/* Make an insn of code INSN with body PATTERN + and output it after the insn AFTER. */ + +rtx +emit_insn_after (pattern, after) + register rtx pattern, after; +{ + register rtx insn = after; + + if (GET_CODE (pattern) == SEQUENCE) + { + register int i; + + for (i = 0; i < XVECLEN (pattern, 0); i++) + { + insn = XVECEXP (pattern, 0, i); + add_insn_after (insn, after); + after = insn; + } + if (XVECLEN (pattern, 0) < SEQUENCE_RESULT_SIZE) + sequence_result[XVECLEN (pattern, 0)] = pattern; + } + else + { + insn = make_insn_raw (pattern); + add_insn_after (insn, after); + } + + return insn; +} + +/* Similar to emit_insn_after, except that line notes are to be inserted so + as to act as if this insn were at FROM. */ + +void +emit_insn_after_with_line_notes (pattern, after, from) + rtx pattern, after, from; +{ + rtx from_line = find_line_note (from); + rtx after_line = find_line_note (after); + rtx insn = emit_insn_after (pattern, after); + + if (from_line) + emit_line_note_after (NOTE_SOURCE_FILE (from_line), + NOTE_LINE_NUMBER (from_line), + after); + + if (after_line) + emit_line_note_after (NOTE_SOURCE_FILE (after_line), + NOTE_LINE_NUMBER (after_line), + insn); +} + +/* Make an insn of code JUMP_INSN with body PATTERN + and output it after the insn AFTER. */ + +rtx +emit_jump_insn_after (pattern, after) + register rtx pattern, after; +{ + register rtx insn; + + if (GET_CODE (pattern) == SEQUENCE) + insn = emit_insn_after (pattern, after); + else + { + insn = make_jump_insn_raw (pattern); + add_insn_after (insn, after); + } + + return insn; +} + +/* Make an insn of code BARRIER + and output it after the insn AFTER. */ + +rtx +emit_barrier_after (after) + register rtx after; +{ + register rtx insn = rtx_alloc (BARRIER); + + INSN_UID (insn) = cur_insn_uid++; + + add_insn_after (insn, after); + return insn; +} + +/* Emit the label LABEL after the insn AFTER. */ + +rtx +emit_label_after (label, after) + rtx label, after; +{ + /* This can be called twice for the same label + as a result of the confusion that follows a syntax error! + So make it harmless. */ + if (INSN_UID (label) == 0) + { + INSN_UID (label) = cur_insn_uid++; + add_insn_after (label, after); + } + + return label; +} + +/* Emit a note of subtype SUBTYPE after the insn AFTER. */ + +rtx +emit_note_after (subtype, after) + int subtype; + rtx after; +{ + register rtx note = rtx_alloc (NOTE); + INSN_UID (note) = cur_insn_uid++; + NOTE_SOURCE_FILE (note) = 0; + NOTE_LINE_NUMBER (note) = subtype; + add_insn_after (note, after); + return note; +} + +/* Emit a line note for FILE and LINE after the insn AFTER. */ + +rtx +emit_line_note_after (file, line, after) + char *file; + int line; + rtx after; +{ + register rtx note; + + if (no_line_numbers && line > 0) + { + cur_insn_uid++; + return 0; + } + + note = rtx_alloc (NOTE); + INSN_UID (note) = cur_insn_uid++; + NOTE_SOURCE_FILE (note) = file; + NOTE_LINE_NUMBER (note) = line; + add_insn_after (note, after); + return note; +} + +/* Make an insn of code INSN with pattern PATTERN + and add it to the end of the doubly-linked list. + If PATTERN is a SEQUENCE, take the elements of it + and emit an insn for each element. + + Returns the last insn emitted. */ + +rtx +emit_insn (pattern) + rtx pattern; +{ + rtx insn = last_insn; + + if (GET_CODE (pattern) == SEQUENCE) + { + register int i; + + for (i = 0; i < XVECLEN (pattern, 0); i++) + { + insn = XVECEXP (pattern, 0, i); + add_insn (insn); + } + if (XVECLEN (pattern, 0) < SEQUENCE_RESULT_SIZE) + sequence_result[XVECLEN (pattern, 0)] = pattern; + } + else + { + insn = make_insn_raw (pattern); + add_insn (insn); + } + + return insn; +} + +/* Emit the insns in a chain starting with INSN. + Return the last insn emitted. */ + +rtx +emit_insns (insn) + rtx insn; +{ + rtx last = 0; + + while (insn) + { + rtx next = NEXT_INSN (insn); + add_insn (insn); + last = insn; + insn = next; + } + + return last; +} + +/* Emit the insns in a chain starting with INSN and place them in front of + the insn BEFORE. Return the last insn emitted. */ + +rtx +emit_insns_before (insn, before) + rtx insn; + rtx before; +{ + rtx last = 0; + + while (insn) + { + rtx next = NEXT_INSN (insn); + add_insn_before (insn, before); + last = insn; + insn = next; + } + + return last; +} + +/* Emit the insns in a chain starting with FIRST and place them in back of + the insn AFTER. Return the last insn emitted. */ + +rtx +emit_insns_after (first, after) + register rtx first; + register rtx after; +{ + register rtx last; + register rtx after_after; + + if (!after) + abort (); + + if (!first) + return first; + + for (last = first; NEXT_INSN (last); last = NEXT_INSN (last)) + continue; + + after_after = NEXT_INSN (after); + + NEXT_INSN (after) = first; + PREV_INSN (first) = after; + NEXT_INSN (last) = after_after; + if (after_after) + PREV_INSN (after_after) = last; + + if (after == last_insn) + last_insn = last; + return last; +} + +/* Make an insn of code JUMP_INSN with pattern PATTERN + and add it to the end of the doubly-linked list. */ + +rtx +emit_jump_insn (pattern) + rtx pattern; +{ + if (GET_CODE (pattern) == SEQUENCE) + return emit_insn (pattern); + else + { + register rtx insn = make_jump_insn_raw (pattern); + add_insn (insn); + return insn; + } +} + +/* Make an insn of code CALL_INSN with pattern PATTERN + and add it to the end of the doubly-linked list. */ + +rtx +emit_call_insn (pattern) + rtx pattern; +{ + if (GET_CODE (pattern) == SEQUENCE) + return emit_insn (pattern); + else + { + register rtx insn = make_call_insn_raw (pattern); + add_insn (insn); + PUT_CODE (insn, CALL_INSN); + return insn; + } +} + +/* Add the label LABEL to the end of the doubly-linked list. */ + +rtx +emit_label (label) + rtx label; +{ + /* This can be called twice for the same label + as a result of the confusion that follows a syntax error! + So make it harmless. */ + if (INSN_UID (label) == 0) + { + INSN_UID (label) = cur_insn_uid++; + add_insn (label); + } + return label; +} + +/* Make an insn of code BARRIER + and add it to the end of the doubly-linked list. */ + +rtx +emit_barrier () +{ + register rtx barrier = rtx_alloc (BARRIER); + INSN_UID (barrier) = cur_insn_uid++; + add_insn (barrier); + return barrier; +} + +/* Make an insn of code NOTE + with data-fields specified by FILE and LINE + and add it to the end of the doubly-linked list, + but only if line-numbers are desired for debugging info. */ + +rtx +emit_line_note (file, line) + char *file; + int line; +{ + emit_filename = file; + emit_lineno = line; + +#if 0 + if (no_line_numbers) + return 0; +#endif + + return emit_note (file, line); +} + +/* Make an insn of code NOTE + with data-fields specified by FILE and LINE + and add it to the end of the doubly-linked list. + If it is a line-number NOTE, omit it if it matches the previous one. */ + +rtx +emit_note (file, line) + char *file; + int line; +{ + register rtx note; + + if (line > 0) + { + if (file && last_filename && !strcmp (file, last_filename) + && line == last_linenum) + return 0; + last_filename = file; + last_linenum = line; + } + + if (no_line_numbers && line > 0) + { + cur_insn_uid++; + return 0; + } + + note = rtx_alloc (NOTE); + INSN_UID (note) = cur_insn_uid++; + NOTE_SOURCE_FILE (note) = file; + NOTE_LINE_NUMBER (note) = line; + add_insn (note); + return note; +} + +/* Emit a NOTE, and don't omit it even if LINE is the previous note. */ + +rtx +emit_line_note_force (file, line) + char *file; + int line; +{ + last_linenum = -1; + return emit_line_note (file, line); +} + +/* Cause next statement to emit a line note even if the line number + has not changed. This is used at the beginning of a function. */ + +void +force_next_line_note () +{ + last_linenum = -1; +} + +/* 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. */ + +enum rtx_code +classify_insn (x) + rtx x; +{ + if (GET_CODE (x) == CODE_LABEL) + return CODE_LABEL; + if (GET_CODE (x) == CALL) + return CALL_INSN; + if (GET_CODE (x) == RETURN) + return JUMP_INSN; + if (GET_CODE (x) == SET) + { + if (SET_DEST (x) == pc_rtx) + return JUMP_INSN; + else if (GET_CODE (SET_SRC (x)) == CALL) + return CALL_INSN; + else + return INSN; + } + if (GET_CODE (x) == PARALLEL) + { + register int j; + for (j = XVECLEN (x, 0) - 1; j >= 0; j--) + if (GET_CODE (XVECEXP (x, 0, j)) == CALL) + return CALL_INSN; + else if (GET_CODE (XVECEXP (x, 0, j)) == SET + && SET_DEST (XVECEXP (x, 0, j)) == pc_rtx) + return JUMP_INSN; + else if (GET_CODE (XVECEXP (x, 0, j)) == SET + && GET_CODE (SET_SRC (XVECEXP (x, 0, j))) == CALL) + return CALL_INSN; + } + return INSN; +} + +/* Emit the rtl pattern X as an appropriate kind of insn. + If X is a label, it is simply added into the insn chain. */ + +rtx +emit (x) + rtx x; +{ + enum rtx_code code = classify_insn (x); + + if (code == CODE_LABEL) + return emit_label (x); + else if (code == INSN) + return emit_insn (x); + else if (code == JUMP_INSN) + { + register rtx insn = emit_jump_insn (x); + if (simplejump_p (insn) || GET_CODE (x) == RETURN) + return emit_barrier (); + return insn; + } + else if (code == CALL_INSN) + return emit_call_insn (x); + else + abort (); +} + +/* Begin emitting insns to a sequence which can be packaged in an RTL_EXPR. */ + +void +start_sequence () +{ + struct sequence_stack *tem; + + if (sequence_element_free_list) + { + /* Reuse a previously-saved struct sequence_stack. */ + tem = sequence_element_free_list; + sequence_element_free_list = tem->next; + } + else + tem = (struct sequence_stack *) permalloc (sizeof (struct sequence_stack)); + + tem->next = sequence_stack; + tem->first = first_insn; + tem->last = last_insn; + tem->sequence_rtl_expr = sequence_rtl_expr; + + sequence_stack = tem; + + first_insn = 0; + last_insn = 0; +} + +/* Similarly, but indicate that this sequence will be placed in + T, an RTL_EXPR. */ + +void +start_sequence_for_rtl_expr (t) + tree t; +{ + start_sequence (); + + sequence_rtl_expr = t; +} + +/* Set up the insn chain starting with FIRST + as the current sequence, saving the previously current one. */ + +void +push_to_sequence (first) + rtx first; +{ + rtx last; + + start_sequence (); + + for (last = first; last && NEXT_INSN (last); last = NEXT_INSN (last)); + + first_insn = first; + last_insn = last; +} + +/* Set up the outer-level insn chain + as the current sequence, saving the previously current one. */ + +void +push_topmost_sequence () +{ + struct sequence_stack *stack, *top = NULL; + + start_sequence (); + + for (stack = sequence_stack; stack; stack = stack->next) + top = stack; + + first_insn = top->first; + last_insn = top->last; + sequence_rtl_expr = top->sequence_rtl_expr; +} + +/* After emitting to the outer-level insn chain, update the outer-level + insn chain, and restore the previous saved state. */ + +void +pop_topmost_sequence () +{ + struct sequence_stack *stack, *top = NULL; + + for (stack = sequence_stack; stack; stack = stack->next) + top = stack; + + top->first = first_insn; + top->last = last_insn; + /* ??? Why don't we save sequence_rtl_expr here? */ + + end_sequence (); +} + +/* After emitting to a sequence, restore previous saved state. + + To get the contents of the sequence just made, + you must call `gen_sequence' *before* calling here. */ + +void +end_sequence () +{ + struct sequence_stack *tem = sequence_stack; + + first_insn = tem->first; + last_insn = tem->last; + sequence_rtl_expr = tem->sequence_rtl_expr; + sequence_stack = tem->next; + + tem->next = sequence_element_free_list; + sequence_element_free_list = tem; +} + +/* Return 1 if currently emitting into a sequence. */ + +int +in_sequence_p () +{ + return sequence_stack != 0; +} + +/* Generate a SEQUENCE rtx containing the insns already emitted + to the current sequence. + + This is how the gen_... function from a DEFINE_EXPAND + constructs the SEQUENCE that it returns. */ + +rtx +gen_sequence () +{ + rtx result; + rtx tem; + int i; + int len; + + /* Count the insns in the chain. */ + len = 0; + for (tem = first_insn; tem; tem = NEXT_INSN (tem)) + len++; + + /* If only one insn, return its pattern rather than a SEQUENCE. + (Now that we cache SEQUENCE expressions, it isn't worth special-casing + the case of an empty list.) */ + if (len == 1 + && ! RTX_FRAME_RELATED_P (first_insn) + && (GET_CODE (first_insn) == INSN + || GET_CODE (first_insn) == JUMP_INSN + /* Don't discard the call usage field. */ + || (GET_CODE (first_insn) == CALL_INSN + && CALL_INSN_FUNCTION_USAGE (first_insn) == NULL_RTX))) + { + NEXT_INSN (first_insn) = free_insn; + free_insn = first_insn; + return PATTERN (first_insn); + } + + /* Put them in a vector. See if we already have a SEQUENCE of the + appropriate length around. */ + if (len < SEQUENCE_RESULT_SIZE && (result = sequence_result[len]) != 0) + sequence_result[len] = 0; + else + { + /* Ensure that this rtl goes in saveable_obstack, since we may + cache it. */ + push_obstacks_nochange (); + rtl_in_saveable_obstack (); + result = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (len)); + pop_obstacks (); + } + + for (i = 0, tem = first_insn; tem; tem = NEXT_INSN (tem), i++) + XVECEXP (result, 0, i) = tem; + + return result; +} + +/* Put the various virtual registers into REGNO_REG_RTX. */ + +void +init_virtual_regs () +{ + regno_reg_rtx[VIRTUAL_INCOMING_ARGS_REGNUM] = virtual_incoming_args_rtx; + regno_reg_rtx[VIRTUAL_STACK_VARS_REGNUM] = virtual_stack_vars_rtx; + regno_reg_rtx[VIRTUAL_STACK_DYNAMIC_REGNUM] = virtual_stack_dynamic_rtx; + regno_reg_rtx[VIRTUAL_OUTGOING_ARGS_REGNUM] = virtual_outgoing_args_rtx; + regno_reg_rtx[VIRTUAL_CFA_REGNUM] = virtual_cfa_rtx; +} + +/* Initialize data structures and variables in this file + before generating rtl for each function. */ + +void +init_emit () +{ + int i; + + first_insn = NULL; + last_insn = NULL; + sequence_rtl_expr = NULL; + cur_insn_uid = 1; + reg_rtx_no = LAST_VIRTUAL_REGISTER + 1; + last_linenum = 0; + last_filename = 0; + first_label_num = label_num; + last_label_num = 0; + sequence_stack = NULL; + + /* Clear the start_sequence/gen_sequence cache. */ + sequence_element_free_list = 0; + for (i = 0; i < SEQUENCE_RESULT_SIZE; i++) + sequence_result[i] = 0; + free_insn = 0; + + /* Init the tables that describe all the pseudo regs. */ + + regno_pointer_flag_length = LAST_VIRTUAL_REGISTER + 101; + + regno_pointer_flag + = (char *) savealloc (regno_pointer_flag_length); + bzero (regno_pointer_flag, regno_pointer_flag_length); + + regno_pointer_align + = (char *) savealloc (regno_pointer_flag_length); + bzero (regno_pointer_align, regno_pointer_flag_length); + + regno_reg_rtx + = (rtx *) savealloc (regno_pointer_flag_length * sizeof (rtx)); + bzero ((char *) regno_reg_rtx, regno_pointer_flag_length * sizeof (rtx)); + + /* Put copies of all the virtual register rtx into regno_reg_rtx. */ + init_virtual_regs (); + + /* Indicate that the virtual registers and stack locations are + all pointers. */ + REGNO_POINTER_FLAG (STACK_POINTER_REGNUM) = 1; + REGNO_POINTER_FLAG (FRAME_POINTER_REGNUM) = 1; + REGNO_POINTER_FLAG (HARD_FRAME_POINTER_REGNUM) = 1; + REGNO_POINTER_FLAG (ARG_POINTER_REGNUM) = 1; + + REGNO_POINTER_FLAG (VIRTUAL_INCOMING_ARGS_REGNUM) = 1; + REGNO_POINTER_FLAG (VIRTUAL_STACK_VARS_REGNUM) = 1; + REGNO_POINTER_FLAG (VIRTUAL_STACK_DYNAMIC_REGNUM) = 1; + REGNO_POINTER_FLAG (VIRTUAL_OUTGOING_ARGS_REGNUM) = 1; + REGNO_POINTER_FLAG (VIRTUAL_CFA_REGNUM) = 1; + +#ifdef STACK_BOUNDARY + REGNO_POINTER_ALIGN (STACK_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT; + REGNO_POINTER_ALIGN (FRAME_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT; + REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) + = STACK_BOUNDARY / BITS_PER_UNIT; + REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT; + + REGNO_POINTER_ALIGN (VIRTUAL_INCOMING_ARGS_REGNUM) + = STACK_BOUNDARY / BITS_PER_UNIT; + REGNO_POINTER_ALIGN (VIRTUAL_STACK_VARS_REGNUM) + = STACK_BOUNDARY / BITS_PER_UNIT; + REGNO_POINTER_ALIGN (VIRTUAL_STACK_DYNAMIC_REGNUM) + = STACK_BOUNDARY / BITS_PER_UNIT; + REGNO_POINTER_ALIGN (VIRTUAL_OUTGOING_ARGS_REGNUM) + = STACK_BOUNDARY / BITS_PER_UNIT; + REGNO_POINTER_ALIGN (VIRTUAL_CFA_REGNUM) = UNITS_PER_WORD; +#endif + +#ifdef INIT_EXPANDERS + INIT_EXPANDERS; +#endif +} + +/* Create some permanent unique rtl objects shared between all functions. + LINE_NUMBERS is nonzero if line numbers are to be generated. */ + +void +init_emit_once (line_numbers) + int line_numbers; +{ + int i; + enum machine_mode mode; + enum machine_mode double_mode; + + no_line_numbers = ! line_numbers; + + sequence_stack = NULL; + + /* Compute the word and byte modes. */ + + byte_mode = VOIDmode; + word_mode = VOIDmode; + double_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 + && byte_mode == VOIDmode) + byte_mode = mode; + + if (GET_MODE_BITSIZE (mode) == BITS_PER_WORD + && word_mode == VOIDmode) + word_mode = mode; + } + +#ifndef DOUBLE_TYPE_SIZE +#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2) +#endif + + for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + { + if (GET_MODE_BITSIZE (mode) == DOUBLE_TYPE_SIZE + && double_mode == VOIDmode) + double_mode = mode; + } + + ptr_mode = mode_for_size (POINTER_SIZE, GET_MODE_CLASS (Pmode), 0); + + /* Create the unique rtx's for certain rtx codes and operand values. */ + + for (i = - MAX_SAVED_CONST_INT; i <= MAX_SAVED_CONST_INT; i++) + { + PUT_CODE (&const_int_rtx[i + MAX_SAVED_CONST_INT], CONST_INT); + PUT_MODE (&const_int_rtx[i + MAX_SAVED_CONST_INT], VOIDmode); + INTVAL (&const_int_rtx[i + MAX_SAVED_CONST_INT]) = i; + } + + if (STORE_FLAG_VALUE >= - MAX_SAVED_CONST_INT + && STORE_FLAG_VALUE <= MAX_SAVED_CONST_INT) + const_true_rtx = &const_int_rtx[STORE_FLAG_VALUE + MAX_SAVED_CONST_INT]; + else + const_true_rtx = gen_rtx_CONST_INT (VOIDmode, STORE_FLAG_VALUE); + + dconst0 = REAL_VALUE_ATOF ("0", double_mode); + dconst1 = REAL_VALUE_ATOF ("1", double_mode); + dconst2 = REAL_VALUE_ATOF ("2", double_mode); + dconstm1 = REAL_VALUE_ATOF ("-1", double_mode); + + for (i = 0; i <= 2; i++) + { + for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + { + rtx tem = rtx_alloc (CONST_DOUBLE); + union real_extract u; + + bzero ((char *) &u, sizeof u); /* Zero any holes in a structure. */ + u.d = i == 0 ? dconst0 : i == 1 ? dconst1 : dconst2; + + bcopy ((char *) &u, (char *) &CONST_DOUBLE_LOW (tem), sizeof u); + CONST_DOUBLE_MEM (tem) = cc0_rtx; + PUT_MODE (tem, mode); + + const_tiny_rtx[i][(int) mode] = tem; + } + + const_tiny_rtx[i][(int) VOIDmode] = GEN_INT (i); + + 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); + + for (mode = GET_CLASS_NARROWEST_MODE (MODE_PARTIAL_INT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + const_tiny_rtx[i][(int) mode] = GEN_INT (i); + } + + for (mode = GET_CLASS_NARROWEST_MODE (MODE_CC); mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + const_tiny_rtx[0][(int) mode] = const0_rtx; + + + /* Assign register numbers to the globally defined register rtx. + This must be done at runtime because the register number field + is in a union and some compilers can't initialize unions. */ + + REGNO (stack_pointer_rtx) = STACK_POINTER_REGNUM; + PUT_MODE (stack_pointer_rtx, Pmode); + REGNO (frame_pointer_rtx) = FRAME_POINTER_REGNUM; + PUT_MODE (frame_pointer_rtx, Pmode); +#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM + REGNO (hard_frame_pointer_rtx) = HARD_FRAME_POINTER_REGNUM; + PUT_MODE (hard_frame_pointer_rtx, Pmode); +#endif +#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM && HARD_FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM + REGNO (arg_pointer_rtx) = ARG_POINTER_REGNUM; + PUT_MODE (arg_pointer_rtx, Pmode); +#endif + + REGNO (virtual_incoming_args_rtx) = VIRTUAL_INCOMING_ARGS_REGNUM; + PUT_MODE (virtual_incoming_args_rtx, Pmode); + REGNO (virtual_stack_vars_rtx) = VIRTUAL_STACK_VARS_REGNUM; + PUT_MODE (virtual_stack_vars_rtx, Pmode); + REGNO (virtual_stack_dynamic_rtx) = VIRTUAL_STACK_DYNAMIC_REGNUM; + PUT_MODE (virtual_stack_dynamic_rtx, Pmode); + REGNO (virtual_outgoing_args_rtx) = VIRTUAL_OUTGOING_ARGS_REGNUM; + PUT_MODE (virtual_outgoing_args_rtx, Pmode); + REGNO (virtual_cfa_rtx) = VIRTUAL_CFA_REGNUM; + PUT_MODE (virtual_cfa_rtx, Pmode); + +#ifdef RETURN_ADDRESS_POINTER_REGNUM + return_address_pointer_rtx + = gen_rtx_raw_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM); +#endif + +#ifdef STRUCT_VALUE + struct_value_rtx = STRUCT_VALUE; +#else + struct_value_rtx = gen_rtx_REG (Pmode, STRUCT_VALUE_REGNUM); +#endif + +#ifdef STRUCT_VALUE_INCOMING + struct_value_incoming_rtx = STRUCT_VALUE_INCOMING; +#else +#ifdef STRUCT_VALUE_INCOMING_REGNUM + struct_value_incoming_rtx + = gen_rtx_REG (Pmode, STRUCT_VALUE_INCOMING_REGNUM); +#else + struct_value_incoming_rtx = struct_value_rtx; +#endif +#endif + +#ifdef STATIC_CHAIN_REGNUM + static_chain_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM); + +#ifdef STATIC_CHAIN_INCOMING_REGNUM + if (STATIC_CHAIN_INCOMING_REGNUM != STATIC_CHAIN_REGNUM) + static_chain_incoming_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_INCOMING_REGNUM); + else +#endif + static_chain_incoming_rtx = static_chain_rtx; +#endif + +#ifdef STATIC_CHAIN + static_chain_rtx = STATIC_CHAIN; + +#ifdef STATIC_CHAIN_INCOMING + static_chain_incoming_rtx = STATIC_CHAIN_INCOMING; +#else + static_chain_incoming_rtx = static_chain_rtx; +#endif +#endif + +#ifdef PIC_OFFSET_TABLE_REGNUM + pic_offset_table_rtx = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM); +#endif + +#ifdef INIT_EXPANDERS + /* This is to initialize save_machine_status and restore_machine_status before + the first call to push_function_context_to. This is needed by the Chill + front end which calls push_function_context_to before the first cal to + init_function_start. */ + INIT_EXPANDERS; +#endif +} + +/* 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 () +{ + int old = no_line_numbers; + + no_line_numbers = 0; + if (old) + force_next_line_note (); + return old; +} + +void +restore_line_number_status (old_value) + int old_value; +{ + no_line_numbers = old_value; +} diff --git a/gcc_arm/enquire.c b/gcc_arm/enquire.c new file mode 100755 index 0000000..bb5ea0b --- /dev/null +++ b/gcc_arm/enquire.c @@ -0,0 +1,2887 @@ +/* Everything you wanted to know about your machine and C compiler, + but didn't know who to ask. */ + +#ifndef VERSION +#define VERSION "4.3" +#endif + +/* Author: Steven Pemberton, CWI, Amsterdam; steven@cwi.nl + Bugfixes and upgrades gratefully received. + + Copyright (c) 1988, 1989, 1990 Steven Pemberton, CWI, Amsterdam. + All rights reserved. + + Changes by Richard Stallman: + Undef CHAR_BIT, etc., if defined in stdio.h, Richard Stallman, Aug 90. + In EPROP, avoid a <= old if bad is set, Richard Stallman, May 91. + Use gstddef.h, not stddef.h, Richard Stallman, Nov 91. + Don't declare malloc, instead cast the value, Richard Stallman, Nov 91. + Include sys/types.h before signal.h, Apr 92. + Support NO_LONG_DOUBLE_IO in f_define and f_rep; new fn fake_f_rep, Apr 92. + Enclose -f output in #ifndef _FLOAT_H___, Richard Stallman, May 92. + + Change by Jim Wilson: + Add #undef before every #define, Dec 92. + Use stddef.h not gstddef.h, Mar 94. + + Changes by Paul Eggert, installed Feb 93: + (fake_f_rep): Clear all of u, initially. Make the ints in u unsigned. + (f_define): Use ordinary constants for long double + if it's same width as double. Make __convert_long_double_i unsigned. + Richard Stallman, May 93: + In F_check, check NO_LONG_DOUBLE_IO. + + Changes by Stephen Moshier, installed Sep 93: + (FPROP): Recognize 80387 or 68881 XFmode format. + + Change by Manfred Hollstein, installed Mar 98: + (bitpattern): Change type of variable i to unsigned int. + + + COMPILING + With luck and a following wind, just the following will work: + cc enquire.c -o enquire + You may get some messages about unreachable code, which you can ignore. + + If your compiler doesn't support: add flag: + signed char (eg pcc) -DNO_SC + unsigned char -DNO_UC + unsigned short and long -DNO_UI + void -DNO_VOID + signal(), or setjmp/longjmp() -DNO_SIG + %Lf in printf -DNO_LONG_DOUBLE_IO + + Try to compile first with no flags, and see if you get any errors - + you might be surprised. (Most non-ANSI compilers need -DNO_SC, though.) + Some compilers need a -f flag for floating point. + + Don't use any optimisation flags: the program may not work if you do. + Though "while (a+1.0-a-1.0 == 0.0)" may look like "while(1)" to an + optimiser, to a floating-point unit there's a world of difference. + + Some compilers offer various flags for different floating point + modes; it's worth trying all possible combinations of these. + + Add -DID=\"name\" if you want the machine/flags identified in the output. + + FAULTY COMPILERS + Because of bugs and/or inadequacies, some compilers need the following + defines: + + If your C preprocessor doesn't have the predefined __FILE__ macro, and + you don't want to call this file enquire.c but, say, tell.c, add the + flag -DFILENAME=\"tell.c\" . + + Some compilers won't accept the line "#include FILENAME". + Add flag -DNO_FILE. In that case, this file *must* be called enquire.c. + + Some compilers can't cope with "#ifdef __FILE__". Use -DFILENAME= + or -DNO_FILE as above. + + Some naughty compilers define __STDC__, but don't really support it. + Some define it as 0, in which case we treat it as undefined. + But if your compiler defines it, and isn't really ANSI C, + add flag -DNO_STDC. (To those compiler writers: for shame). + + Some naughty compilers define __STDC__, but don't have the stddef.h + include file. Add flag -DNO_STDDEF. + + Summary of naughty-compiler flags: + If your compiler doesn't support: add flag: + __FILE__ (and you changed the filename) -DFILENAME=\"name.c\" + #ifdef __FILE__ -DNO_FILE or -DFILENAME=... + #include FILENAME -DNO_FILE + __STDC__ (properly) -DNO_STDC + stddef.h -DNO_STDDEF + + Some systems crash when you try to malloc all store. To save users of + such defective systems too much grief, they may compile with -DNO_MEM, + which ignores that bit of the code. + + While it is not our policy to support defective compilers, pity has been + taken on people with compilers that can't produce object files bigger than + 32k (especially since it was an easy addition). Compile the program + into separate parts like this: + cc -DSEP -DPASS0 -o p0.o enquire.c + cc -DSEP -DPASS1 -o p1.o enquire.c + cc -DSEP -DPASS2 -o p2.o enquire.c + cc -DSEP -DPASS3 -o p3.o enquire.c + cc -o enquire p0.o p1.o p2.o p3.o + + SYSTEM DEPENDENCIES + You may possibly need to add some calls to signal() for other sorts of + exception on your machine than SIGFPE, and SIGOVER. See lines beginning + #ifdef SIGxxx in main() (and communicate the differences to me!). + + OUTPUT + Run without argument to get the information as English text. If run + with argument -l (e.g. enquire -l), output is a series of #define's for + the ANSI standard limits.h include file, excluding MB_MAX_CHAR. If run + with argument -f, output is a series of #define's for the ANSI standard + float.h include file (according to ANSI C Draft of Dec 7, 1988). + Flag -v gives verbose output: output includes the English text above + as C comments. The program exit(0)'s if everything went ok, otherwise + it exits with a positive number, telling how many problems there were. + + VERIFYING THE COMPILER + If, having produced the float.h and limits.h header files, you want to + verify that the compiler reads them back correctly (there are a lot of + boundary cases, of course, like minimum and maximum numbers), you can + recompile enquire.c with -DVERIFY set (plus the other flags that you used + when compiling the version that produced the header files). This then + recompiles the program so that it #includes "limits.h" and "float.h", + and checks that the constants it finds there are the same as the + constants it produces. Run the resulting program with enquire -fl. + Very few compilers have passed without error. + NB: You *must* recompile with the same compiler and flags, otherwise + you may get odd results. + + You can also use this option if your compiler already has both files, + and you want to confirm that this program produces the right results. + + TROUBLESHOOTING. + This program is now quite trustworthy, and suspicious and wrong output + may well be caused by bugs in the compiler, not in the program (however + of course, this is not guaranteed, and no responsibility can be + accepted, etc.) + + The program only works if overflows are ignored by the C system or + are catchable with signal(). + + If the program fails to run to completion (often with the error message + "Unexpected signal at point x"), this often turns out to be a bug in the + C compiler's run-time system. Check what was about to be printed, and + try to narrow the problem down. + + Another possible problem is that you have compiled the program to produce + loss-of-precision arithmetic traps. The program cannot cope with these, + and you should re-compile without them. (They should never be the default). + + Make sure you compiled with optimisation turned off. + + Output preceded by *** WARNING: identifies behaviour of the C system + deemed incorrect by the program. Likely problems are that printf or + scanf don't cope properly with certain boundary numbers: this program + goes to a lot of trouble to calculate its values, and these values + are mostly boundary numbers. Experience has shown that often printf + cannot cope with these values, and so in an attempt to increase + confidence in the output, for each float and double that is printed, + the printed value is checked by using sscanf to read it back. + Care is taken that numbers are printed with enough digits to uniquely + identify them, and therefore that they can be read back identically. + If the number read back is different, then there is probably a bug in + printf or sscanf, and the program prints the warning message. + If the two numbers in the warning look identical, then printf is more + than likely rounding the last digit(s) incorrectly. To put you at ease + that the two really are different, the bit patterns of the two numbers + are also printed. The difference is very likely in the last bit. + Many scanf's read the minimum double back as 0.0, and similarly cause + overflow when reading the maximum double. This program quite ruthlessly + declares all these behaviours faulty. The point is that if you get + one of these warnings, the output may be wrong, so you should check + the result carefully if you intend to use the results. Of course, printf + and sscanf may both be wrong, and cancel each other out, so you should + check the output carefully anyway. + + The warning that "a cast didn't work" refers to cases like this: + + float f; + #define C 1.234567890123456789 + f= C; + if (f != (float) C) printf ("Wrong!"); + + A faulty compiler will widen f to double and ignore the cast to float, + and because there is more accuracy in a double than a float, fail to + recognise that they are the same. In the actual case in point, f and C + are passed as parameters to a function that discovers they are not equal, + so it's just possible that the error was in the parameter passing, + not in the cast (see function Validate()). + For ANSI C, which has float constants, the error message is "constant has + wrong precision". + + REPORTING PROBLEMS + If the program doesn't work for you for any reason that can't be + narrowed down to a problem in the C compiler, or it has to be changed in + order to get it to compile, or it produces suspicious output (like a very + low maximum float, for instance), please mail the problem and an example + of the incorrect output to steven@cwi.nl or ..!hp4nl!cwi.nl!steven, so that + improvements can be worked into future versions; cwi.nl is the European + backbone, and is connected to uunet and other fine hosts. + + The program tries to catch and diagnose bugs in the compiler/run-time + system. I would be especially pleased to have reports of failures so + that I can improve this service. + + I apologise unreservedly for the contorted use of the preprocessor... + + THE SMALL PRINT + You may copy and distribute verbatim copies of this source file. + + You may modify this source file, and copy and distribute such + modified versions, provided that you leave the copyright notice + at the top of the file and also cause the modified file to carry + prominent notices stating that you changed the files and the date + of any change; and cause the whole of any work that you distribute + or publish, that in whole or in part contains or is a derivative of + this program or any part thereof, to be licensed at no charge to + all third parties on terms identical to those here. + + If you do have a fix to any problem, please send it to me, so that + other people can have the benefits. + + While every effort has been taken to make this program as reliable as + possible, no responsibility can be taken for the correctness of the + output, nor suitability for any particular use. + + This program is an offshoot of a project funded by public funds. + If you use this program for research or commercial use (i.e. more + than just for the fun of knowing about your compiler) mailing a short + note of acknowledgement may help keep enquire.c supported. + + ACKNOWLEDGEMENTS + Many people have given time and ideas to making this program what it is. + To all of them thanks, and apologies for not mentioning them by name. + + HISTORY + Originally started as a program to generate configuration constants + for a large piece of software we were writing, which later took on + a life of its own... + 1.0 Length 6658!; end 1984? + Unix only. Only printed a dozen maximum int/double values. + 2.0 Length 10535; Spring 1985 + Prints values as #defines (about 20 of them) + More extensive floating point, using Cody and Waite + Handles signals better + Programs around optimisations + Handles Cybers + 3.0 Length 12648; Aug 1987; prints about 42 values + Added PASS stuff, so treats float as well as double + 4.0 Length 33891; Feb 1989; prints around 85 values + First GNU version (for gcc, where they call it hard-params.c) + Generates float.h and limits.h files + Handles long double + Generates warnings for dubious output + 4.1 Length 47738; April 1989 + Added VERIFY and TEST + 4.2 Length 63442; Feb 1990 + Added SEP + Fixed eps/epsneg + Added check for pseudo-unsigned chars + Added description for each #define output + Added check for absence of defines during verify + Added prototypes + Added NO_STDC and NO_FILE + Fixed alignments output + 4.3 Length 75000; Oct 1990; around 114 lines of output + Function xmalloc defined, Richard Stallman, June 89. + Alignments computed from member offsets rather than structure sizes, + Richard Stallman, Oct 89. + Print whether char* and int* pointers have the same format; + also char * and function *. + Update to Draft C version Dec 7, 1988 + - types of constants produced in limits.h + (whether to put a U after unsigned shorts and chars and + whether to output -1024 as (-1023-1)) + - values of SCHAR_MIN/MAX + - values of *_EPSILON (not the smallest but the effective smallest) + Added FILENAME, since standard C doesn't allow #define __FILE__ + Renamed from config.c to enquire.c + Added size_t and ptrdiff_t enquiries + Added promotion enquiries + Added type checks of #defines + Added NO_STDDEF + Changed endian to allow for cases where not all bits are used + Sanity check for max integrals + Fixed definition of setjmp for -DNO_SIG + Moved #define ... 0.0L inside #ifdef STDC, in case some cpp's tokenize + Added NO_MEM +*/ + +/* Set FILENAME to the name of this file */ +#ifndef FILENAME +#ifdef NO_FILE +#define FILENAME "enquire.c" +#else +#ifdef __FILE__ /* It's a compiler bug if this fails. Compile with -DNO_FILE */ +#define FILENAME __FILE__ +#else +#define FILENAME "enquire.c" +#endif /* __FILE__ */ +#endif /* NO_FILE */ +#endif /* FILENAME */ + +/* If PASS isn't defined, then this is the first pass over this file. */ +#ifndef PASS +#ifndef SEP +#define PASS 1 +#define PASS0 1 +#define PASS1 1 +#endif /* SEP */ + +/* A description of the ANSI constants */ +#define D_CHAR_BIT "Number of bits in a storage unit" +#define D_CHAR_MAX "Maximum char" +#define D_CHAR_MIN "Minimum char" +#define D_SCHAR_MAX "Maximum signed char" +#define D_SCHAR_MIN "Minimum signed char" +#define D_UCHAR_MAX "Maximum unsigned char (minimum is always 0)" + +#define D_INT_MAX "Maximum %s" +#define D_INT_MIN "Minimum %s" +#define D_UINT_MAX "Maximum unsigned %s (minimum is always 0)" + +#define D_FLT_ROUNDS "Addition rounds to 0: zero, 1: nearest, 2: +inf, 3: -inf, -1: unknown" +#define D_FLT_RADIX "Radix of exponent representation" +#define D_MANT_DIG "Number of base-FLT_RADIX digits in the significand of a %s" +#define D_DIG "Number of decimal digits of precision in a %s" +#define D_MIN_EXP "Minimum int x such that FLT_RADIX**(x-1) is a normalised %s" +#define D_MIN_10_EXP "Minimum int x such that 10**x is a normalised %s" +#define D_MAX_EXP "Maximum int x such that FLT_RADIX**(x-1) is a representable %s" +#define D_MAX_10_EXP "Maximum int x such that 10**x is a representable %s" +#define D_MAX "Maximum %s" +#define D_EPSILON "Difference between 1.0 and the minimum %s greater than 1.0" +#define D_MIN "Minimum normalised %s" + +/* Procedure just marks the functions that don't return a result */ +#ifdef NO_VOID +#define Procedure int +#else +#define Procedure void +#endif + +/* Some bad compilers define __STDC__, when they don't support it. + Compile with -DNO_STDC to get round this. +*/ +#ifndef NO_STDC +#ifdef __STDC__ +#if __STDC__ /* If __STDC__ is 0, assume it isn't supported */ +#define STDC +#endif +#endif +#endif + +/* Stuff different for ANSI C, and old C: + ARGS and NOARGS are used for function prototypes. + Volatile is used to reduce the chance of optimisation, + and to prevent variables being put in registers (when setjmp/longjmp + wouldn't work as we want) + Long_double is the longest floating point type available. + stdc is used in tests like "if (stdc)", which is less ugly than #ifdef. + U is output after unsigned constants. + */ +#ifdef STDC + +#define ARGS(x) x +#define NOARGS (void) +#define Volatile volatile +#define Long_double long double +#define stdc 1 +#define U "U" + +#else /* Old style C */ + +#define ARGS(x) () +#define NOARGS () +#define Volatile static +#define Long_double double +#define stdc 0 +#define U "" + +#endif /* STDC */ + +/* include files */ +/* Stdio.h might include limits.h, and limits.h might include float.h, and + float.h is probably the float.h put together by the gcc makefile to + cause errors. We use our special define to assure float.h that we don't + really need it. */ +#define __GCC_FLOAT_NOT_NEEDED +#include + +#ifdef STDC +#ifndef NO_STDDEF +#include /* for size_t: if this fails, define NO_STDDEF */ +#endif +#endif + +#ifdef NO_SIG +#define jmp_buf int +#else +#include +#include +#include +#endif + +/* Kludge around the possibility that includes */ +#ifdef CHAR_BIT +#undef CHAR_BIT +#undef CHAR_MAX +#undef CHAR_MIN +#undef SCHAR_MAX +#undef SCHAR_MIN +#undef UCHAR_MAX +#undef UCHAR_MIN +#endif + +#ifdef VERIFY +#include "limits.h" +#endif + +#ifndef SYS_FLOAT_H_WRAP +#define SYS_FLOAT_H_WRAP 0 +#endif + +#if SYS_FLOAT_H_WRAP || defined VERIFY +#include "float.h" +#endif + +#define Vprintf if (V) printf +#define Unexpected(place) if (setjmp(lab)!=0) croak(place) +#define fabs(x) (((x)<0.0)?(-x):(x)) + +#endif /* PASS */ + +#ifdef PASS0 + +/* Prototypes for what's to come: */ + +int false NOARGS; + +#ifdef NO_STDDEF +char *malloc (); /* Old style prototype */ +#else +char *malloc ARGS((size_t size)); +#endif + +Procedure exit ARGS((int status)); + +char *f_rep ARGS((int precision, Long_double val)); +char *fake_f_rep ARGS((char *type, Long_double val)); + +int maximum_int NOARGS; +int cprop NOARGS; +int basic NOARGS; +Procedure sprop NOARGS; +Procedure iprop NOARGS; +Procedure lprop NOARGS; +Procedure usprop NOARGS; +Procedure uiprop NOARGS; +Procedure ulprop NOARGS; +int fprop ARGS((int bits_per_byte)); +int dprop ARGS((int bits_per_byte)); +int ldprop ARGS((int bits_per_byte)); +Procedure efprop ARGS((int fprec, int dprec, int lprec)); +Procedure edprop ARGS((int fprec, int dprec, int lprec)); +Procedure eldprop ARGS((int fprec, int dprec, int lprec)); + +int setmode ARGS((char *s)); +Procedure farewell ARGS((int bugs)); +Procedure describe ARGS((char *description, char *extra)); +Procedure missing ARGS((char *s)); +Procedure fmissing ARGS((char *s)); +Procedure check_defines NOARGS; +Procedure bitpattern ARGS((char *p, unsigned int size)); +int ceil_log ARGS((int base, Long_double x)); +Procedure croak ARGS((int place)); +Procedure eek_a_bug ARGS((char *problem)); +Procedure endian ARGS((int bits_per_byte)); +int exponent ARGS((Long_double x, double *fract, int *exp)); +int floor_log ARGS((int base, Long_double x)); +Procedure f_define ARGS((char *desc, char *extra, char *sort, char *name, + int prec, Long_double val, Long_double req, + char *mark)); +Procedure i_define ARGS((char *desc, char *extra, char *sort, char *name, + long val, long lim, long req, char *mark)); +Procedure u_define ARGS((char *desc, char *extra, char *sort, char *name, + unsigned long val, unsigned long req, char *mark)); + +#ifdef NO_SIG /* There's no signal(), or setjmp/longjmp() */ + + /* Dummy routines instead */ + + int setjmp ARGS((int lab)); + + int lab=1; + int setjmp(lab) int lab; { return(0); } + Procedure signal(i, p) int i, (*p)(); {} + +#else + jmp_buf lab; + Procedure overflow(sig) int sig; { /* what to do on over/underflow */ + signal(sig, overflow); + longjmp(lab, 1); + } + +#endif /*NO_SIG*/ + +int V= 0, /* verbose */ + L= 0, /* produce limits.h */ + F= 0, /* produce float.h */ + bugs=0; /* The number of (possible) bugs in the output */ + +char co[4], oc[4]; /* Comment starter and ender symbols */ + +int bits_per_byte; /* the number of bits per unit returned by sizeof() */ +int flt_rounds; /* The calculated value of FLT_ROUNDS */ +int flt_radix; /* The calculated value of FLT_RADIX */ + +#ifdef TEST +/* Set the fp modes on a SUN with 68881 chip, to check that different + rounding modes etc. get properly detected. + Compile with -f68881 for cc, -m68881 for gcc, and with additional flag + -DTEST. Run with additional parameter +hex-number, to set the 68881 mode + register to hex-number +*/ + +/* Bits 0x30 = rounding mode */ +#define ROUND_BITS 0x30 +#define TO_NEAREST 0x00 +#define TO_ZERO 0x10 +#define TO_MINUS_INF 0x20 +#define TO_PLUS_INF 0x30 /* The SUN FP user's guide seems to be wrong here */ + +/* Bits 0xc0 = extended rounding */ +#define EXT_BITS 0xc0 +#define ROUND_EXTENDED 0x00 +#define ROUND_SINGLE 0x40 +#define ROUND_DOUBLE 0x80 + +/* Enabled traps */ +#define EXE_INEX1 0x100 +#define EXE_INEX2 0x200 +#define EXE_DZ 0x400 +#define EXE_UNFL 0x800 +#define EXE_OVFL 0x1000 +#define EXE_OPERR 0x2000 +#define EXE_SNAN 0x4000 +#define EXE_BSUN 0x8000 + +/* Only used for testing, on a Sun with 68881 chip */ +/* Print the FP mode */ +printmode(new) unsigned new; { + fpmode_(&new); + printf("New fp mode:\n"); + printf(" Round toward "); + switch (new & ROUND_BITS) { + case TO_NEAREST: printf("nearest"); break; + case TO_ZERO: printf("zero"); break; + case TO_MINUS_INF: printf("minus infinity"); break; + case TO_PLUS_INF: printf("plus infinity"); break; + default: printf("???"); break; + } + + printf("\n Extended rounding precision: "); + + switch (new & EXT_BITS) { + case ROUND_EXTENDED: printf("extended"); break; + case ROUND_SINGLE: printf("single"); break; + case ROUND_DOUBLE: printf("double"); break; + default: printf("???"); break; + } + + printf("\n Enabled exceptions:"); + if (new & (unsigned) EXE_INEX1) printf(" inex1"); + if (new & (unsigned) EXE_INEX2) printf(" inex2"); + if (new & (unsigned) EXE_DZ) printf(" dz"); + if (new & (unsigned) EXE_UNFL) printf(" unfl"); + if (new & (unsigned) EXE_OVFL) printf(" ovfl"); + if (new & (unsigned) EXE_OPERR) printf(" operr"); + if (new & (unsigned) EXE_SNAN) printf(" snan"); + if (new & (unsigned) EXE_BSUN) printf(" bsun"); + printf("\n"); +} + +/* Only used for testing, on a Sun with 68881 chip */ +/* Set the FP mode */ +int setmode(s) char *s; { + unsigned mode=0, dig; + char c; + + while (*s) { + c= *s++; + if (c>='0' && c<='9') dig= c-'0'; + else if (c>='a' && c<='f') dig= c-'a'+10; + else if (c>='A' && c<='F') dig= c-'A'+10; + else return 1; + mode= mode<<4 | dig; + } + printmode(mode); + return 0; +} +#else +/* ARGSUSED */ +int setmode(s) char *s; { + fprintf(stderr, "Can't set mode: not compiled with TEST\n"); + return(1); +} +#endif + +Procedure farewell(bugs) int bugs; { + if (bugs == 0) exit(0); + printf("\n%sFor hints on dealing with the ", co); + if (bugs == 1) printf("problem"); + else printf("%d problems", bugs); + printf(" above\n see the section 'TROUBLESHOOTING' in the file "); + printf("%s%s\n", FILENAME, oc); + exit(bugs); +} + +/* The program has received a signal where it wasn't expecting one */ +Procedure croak(place) int place; { + printf("*** Unexpected signal at point %d\n", place); + farewell(bugs+1); /* An exit isn't essential here, but avoids loops */ +} + +/* This is here in case alloca.c is used, which calls this. */ +char *xmalloc(size) unsigned size; { + char *value = (char *)malloc(size); + if (value == 0) { + fprintf(stderr, "Virtual memory exceeded\n"); + exit(bugs+1); + } + return value; +} + +int maxint; + +int maximum_int() { + /* Find the maximum integer */ + Volatile int newi, int_max, two=2; + + /* Calculate maxint ***********************************/ + /* Calculate 2**n-1 until overflow - then use the previous value */ + + newi=1; int_max=0; + + if (setjmp(lab)==0) { /* Yields int_max */ + while(newi>int_max) { + int_max=newi; + newi=newi*two+1; + } + } + Unexpected(0); + return int_max; +} + +int main(argc, argv) int argc; char *argv[]; { + int dprec, fprec, lprec; + int i; char *s; int bad; + +#ifdef SIGFPE + signal(SIGFPE, overflow); +#endif +#ifdef SIGOVER + signal(SIGOVER, overflow); +#endif +/* Add more calls as necessary */ + + Unexpected(1); + + bad=0; + for (i=1; i < argc; i++) { + s= argv[i]; + if (*s == '-') { + s++; + while (*s) { + switch (*(s++)) { + case 'v': V=1; break; + case 'l': L=1; break; + case 'f': F=1; break; + default: bad=1; break; + } + } + } else if (*s == '+') { + s++; + bad= setmode(s); + } else bad= 1; + } + if (bad) { + fprintf(stderr, + "Usage: %s [-vlf]\n v=Verbose l=Limits.h f=Float.h\n", + argv[0]); + exit(1); + } + if (L || F) { + co[0]= '/'; oc[0]= ' '; + co[1]= '*'; oc[1]= '*'; + co[2]= ' '; oc[2]= '/'; + co[3]= '\0'; oc[3]= '\0'; + } else { + co[0]= '\0'; oc[0]= '\0'; + V=1; + } + + if (L) printf("%slimits.h%s\n", co, oc); + if (F) printf("%sfloat.h%s\n", co, oc); + if (F) { + printf ("#ifndef _FLOAT_H___\n"); + printf ("#define _FLOAT_H___\n"); + if (SYS_FLOAT_H_WRAP) + printf ("#include_next \n"); + } +#ifdef ID + printf("%sProduced on %s by enquire version %s, CWI, Amsterdam%s\n", + co, ID, VERSION, oc); +#else + printf("%sProduced by enquire version %s, CWI, Amsterdam%s\n", + co, VERSION, oc); +#endif + +#ifdef VERIFY + printf("%sVerification phase%s\n", co, oc); +#endif + +#ifdef NO_SIG + Vprintf("%sCompiled without signal(): %s%s\n", + co, + "there's nothing that can be done if overflow occurs", + oc); +#endif +#ifdef NO_SC + Vprintf("%sCompiled without signed char%s\n", co, oc); +#endif +#ifdef NO_UC + Vprintf("%Compiled without unsigned char%s\n", co, oc); +#endif +#ifdef NO_UI + Vprintf("%Compiled without unsigned short or long%s\n", co, oc); +#endif +#ifdef __STDC__ + Vprintf("%sCompiler claims to be ANSI C level %d%s\n", + co, __STDC__, oc); +#else + Vprintf("%sCompiler does not claim to be ANSI C%s\n", co, oc); +#endif + printf("\n"); + check_defines(); + + maxint= maximum_int(); + bits_per_byte= basic(); + Vprintf("\n"); + if (F||V) { + fprec= fprop(bits_per_byte); + dprec= dprop(bits_per_byte); + lprec= ldprop(bits_per_byte); + efprop(fprec, dprec, lprec); + edprop(fprec, dprec, lprec); + eldprop(fprec, dprec, lprec); + } +#ifndef NO_MEM + if (V) { + unsigned int size; + long total; + /* An extra goody: the approximate amount of data-space */ + /* Allocate store until no more available */ + /* Different implementations have a different argument type + to malloc. Here we assume that it's the same type as + that which sizeof() returns */ + size=1<<((bits_per_byte*sizeof(int))-2); + total=0; + while (size!=0) { + while ( malloc((false()?sizeof(int):size)) != + (char *)NULL + ) { + total+=(size/2); + } + size/=2; + } + + Vprintf("%sMemory allocable ~= %ld Kbytes%s\n", + co, (total+511)/512, oc); + } +#endif + if (F) { + printf ("#endif %s _FLOAT_H___%s\n", co, oc); + } + farewell(bugs); + return bugs; /* To keep compilers and lint happy */ +} + +Procedure eek_a_bug(problem) char *problem; { + /* The program has discovered a problem */ + printf("\n%s*** WARNING: %s%s\n", co, problem, oc); + bugs++; +} + +Procedure describe(description, extra) char *description, *extra; { + /* Produce the description for a #define */ + printf(" %s", co); + printf(description, extra); + printf("%s\n", oc); +} + +Procedure i_define(desc, extra, sort, name, val, lim, req, mark) + char *desc, *extra, *sort, *name; long val, lim, req; char *mark; { + if (SYS_FLOAT_H_WRAP && F && val == req) + return; + /* Produce a #define for a signed int type */ + describe(desc, extra); + printf("#undef %s%s\n", sort, name); + if (val >= 0) { + printf("#define %s%s %ld%s\n", sort, name, val, mark); + } else if (val + lim < 0) { + /* We may not produce a constant like -1024 if the max + allowable value is 1023. It has then to be output as + -1023-1. lim is the max allowable value. */ + printf("#define %s%s (%ld%s%ld%s)\n", + sort, name, -lim, mark, val+lim, mark); + } else { + printf("#define %s%s (%ld%s)\n", sort, name, val, mark); + } +#ifdef VERIFY + if (val != req) { + printf("%s*** Verify failed for above #define!\n", co); + printf(" Compiler has %ld for value%s\n\n", req, oc); + bugs++; + } +#endif + Vprintf("\n"); +} + +Procedure u_define(desc, extra, sort, name, val, req, mark) + char *desc, *extra, *sort, *name; unsigned long val, req; char *mark; { + /* Produce a #define for an unsigned value */ + describe(desc, extra); + printf("#undef %s%s\n", sort, name); + printf("#define %s%s %lu%s%s\n", sort, name, val, U, mark); +#ifdef VERIFY + if (val != req) { + printf("%s*** Verify failed for above #define!\n", co); + printf(" Compiler has %lu for value%s\n\n", req, oc); + bugs++; + } +#endif + Vprintf("\n"); +} + +Procedure f_define(desc, extra, sort, name, precision, val, req, mark) + char *desc, *extra, *sort, *name; int precision; + Long_double val, req; char *mark; { + if (SYS_FLOAT_H_WRAP && F && val == req) + return; + /* Produce a #define for a float/double/long double */ + describe(desc, extra); + printf ("#undef %s%s\n", sort, name); + if (stdc) { +#ifdef NO_LONG_DOUBLE_IO + static int union_defined = 0; + if (sizeof(double) != sizeof(Long_double) + && !strcmp(sort, "LDBL")) { + if (!union_defined) { + printf("#ifndef __LDBL_UNION__\n"); + printf("#define __LDBL_UNION__\n"); + printf("union __convert_long_double {\n"); + printf(" unsigned __convert_long_double_i[4];\n"); + printf(" long double __convert_long_double_d;\n"); + printf("};\n"); + printf("#endif\n"); + union_defined = 1; + } + printf("#define %s%s %s\n", + sort, name, fake_f_rep("long double", val)); + } else { + printf("#define %s%s %s%s\n", + sort, name, f_rep(precision, val), mark); + } +#else + printf("#define %s%s %s%s\n", + sort, name, f_rep(precision, val), mark); +#endif + } else if (*mark == 'F') { + /* non-ANSI C has no float constants, so cast the constant */ + printf("#define %s%s ((float)%s)\n", + sort, name, f_rep(precision, val)); + } else { + printf("#define %s%s %s\n", sort, name, f_rep(precision, val)); + } + Vprintf("\n"); +} + +int floor_log(base, x) int base; Long_double x; { + /* return floor(log base(x)) */ + int r=0; + while (x>=base) { r++; x/=base; } + return r; +} + +int ceil_log(base, x) int base; Long_double x; { + int r=0; + while (x>1.0) { r++; x/=base; } + return r; +} + +int exponent(x, fract, exp) Long_double x; double *fract; int *exp; { + /* Split x into a fraction and a power of ten; + returns 0 if x is unusable, 1 otherwise. + Only used for error messages about faulty output. + */ + int r=0, neg=0; + Long_double old; + *fract=0.0; *exp=0; + if (x<0.0) { + x= -x; + neg= 1; + } + if (x==0.0) return 1; + if (x>=10.0) { + while (x>=10.0) { + old=x; r++; x/=10.0; + if (old==x) return 0; + } + } else { + while (x<1.0) { + old=x; r--; x*=10.0; + if (old==x) return 0; + } + } + if (neg) *fract= (double) -x; + else *fract=(double) x; + *exp=r; + return 1; +} + +/* Print a value of type TYPE with value VAL, + assuming that sprintf can't handle this type properly (without truncation). + We create an expression that uses type casting to create the value from + a bit pattern. */ + +char *fake_f_rep(type, val) char *type; Long_double val; { + static char buf[1024]; + union { unsigned int i[4]; Long_double ld;} u; + u.i[0] = u.i[1] = u.i[2] = u.i[3] = 0; + u.ld = val; + sprintf(buf, "(__extension__ ((union __convert_long_double) {__convert_long_double_i: {0x%x, 0x%x, 0x%x, 0x%x}}).__convert_long_double_d)", + u.i[0], u.i[1], u.i[2], u.i[3]); + return buf; +} + +char *f_rep(precision, val) int precision; Long_double val; { + /* Return the floating representation of val */ + static char buf[1024]; +#ifdef NO_LONG_DOUBLE_IO + if (1) +#else + if (sizeof(double) == sizeof(Long_double)) +#endif + { + double d = val; + /* Assume they're the same, and use non-stdc format */ + /* This is for stdc compilers using non-stdc libraries */ + sprintf(buf, "%.*e", precision, d); + } else { + /* It had better support Le then */ + sprintf(buf, "%.*Le", precision, val); + } + return buf; +} + +Procedure bitpattern(p, size) char *p; unsigned int size; { + /* Printf the bit-pattern of p */ + char c; + unsigned int i; + int j; + + for (i=1; i<=size; i++) { + c= *p; + p++; + for (j=bits_per_byte-1; j>=0; j--) + printf("%c", (c>>j)&1 ? '1' : '0'); + if (i!=size) printf(" "); + } +} + +#define Order(x, px, mode)\ + printf("%s%s ", co, mode); for (i=0; i>(bits_per_byte*(sizeof(x)-i)))&mask);\ + putchar(c==0 ? '?' : (char)c); }\ + printf("%s\n", oc); + +Procedure endian(bits_per_byte) int bits_per_byte; { + /* Printf the byte-order used on this machine */ + /*unsigned*/ short s=0; + /*unsigned*/ int j=0; + /*unsigned*/ long l=0; + + char *ps= (char *) &s, + *pj= (char *) &j, + *pl= (char *) &l, + *ab= "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + unsigned int mask, i, c; + + mask=0; + for (i=1; i<=(unsigned)bits_per_byte; i++) mask= (mask<<1)|1; + + if (V) { + printf("%sCHARACTER ORDER%s\n", co, oc); + Order(s, ps, "short:"); + Order(j, pj, "int: "); + Order(l, pl, "long: "); + } +} + +Procedure missing(s) char *s; { + printf("%s*** #define %s missing from limits.h%s\n", co, s, oc); + bugs++; +} + +Procedure fmissing(s) char *s; { + printf("%s*** #define %s missing from float.h%s\n", co, s, oc); + bugs++; +} + +/* To try and fool optimisers */ +int false() { return 0; } + +#define Promoted(x) (false()?(x):(-1)) +#define is_signed(x) (Promoted(x) < 0) +#define sign_of(x) ((x)?"signed":"unsigned") +#define Signed 1 +#define Unsigned 0 +#define sgn(x) ((is_signed(x))?Signed:Unsigned) + +#define showtype(t, x) Vprintf("%s%s %s %s%s\n", co, t, sign_of(is_signed(x)), type_of(sizeof(x)), oc) + +char *type_of(x) int x; { + if (x == sizeof(char)) { + if (sizeof(char) == sizeof(int)) return "char/short/int"; + if (sizeof(char) == sizeof(short)) return "char/short"; + return "char"; + } + if (x == sizeof(short)) { + if (sizeof(short) == sizeof(int)) return "short/int"; + return "short"; + } + if (x == sizeof(int)) { + if (sizeof(int) == sizeof(long)) return "int/long"; + return "int"; + } + if (x == sizeof(long)) return "long"; + return "unknown-type"; +} + +char *ftype_of(x) int x; { + if (x == sizeof(float)) { + return "float"; + } + if (x == sizeof(double)) { + if (sizeof(double) == sizeof(Long_double)) + return "(long)double"; + return "double"; + } + if (x == sizeof(Long_double)) { + return "long double"; + } + return "unknown-type"; +} + +Procedure typerr(name, esign, esize, sign, size) + char *name; int esign, esize, sign, size; +{ + Vprintf("*** %s has wrong type: expected %s %s, found %s %s\n", + name, sign_of(esign), type_of(esize), + sign_of(sign), type_of(size)); +} + +Procedure ftyperr(name, esize, size) char *name; int esize, size; { + Vprintf("*** %s has wrong type: expected %s, found %s\n", + name, ftype_of(esize), ftype_of(size)); +} + +int promotions() { + int si = 0; long sl = 0; + unsigned int ui; unsigned long ul; + short ss; unsigned short us; + + Vprintf("\n%sPROMOTIONS%s\n", co, oc); + + if ( + /* Possible warnings here; no problem */ + (sizeof(Promoted(si)) != sizeof(int)) || + (sizeof(Promoted(sl)) != sizeof(long)) || + (sizeof(Promoted(ss)) != sizeof(int)) || + (sizeof(Promoted(ui)) != sizeof(int)) || + (sizeof(Promoted(ul)) != sizeof(long)) || + (sizeof(Promoted(us)) != sizeof(int)) || + is_signed(ui) || is_signed(ul) || + !is_signed(si) || !is_signed(sl) + ) + { + eek_a_bug("promotions don't work properly in conditional expressions\n"); + } + + showtype("unsigned short promotes to", Promoted((unsigned short) 0)); + showtype("long+unsigned gives", sl+ui); + return 0; +} + +#define checktype(x, n, s, t) if((sgn(x)!=s)||(sizeof(x)!=sizeof(t))) typerr(n, s, sizeof(t), sign_of(x), sizeof(x)); + +#define fchecktype(x, n, t) if (sizeof(x) != sizeof(t)) ftyperr(n, sizeof(x), sizeof(t)); + +Procedure check_defines() { + /* ensure that all #defines are present and have the correct type */ +#ifdef VERIFY + int usign; + +#ifdef NO_UI + usign= Signed; +#else + /* Implementations promote unsigned short differently */ + usign= is_signed((unsigned short) 0); +#endif + + if (L) { +#ifdef CHAR_BIT + checktype(CHAR_BIT, "CHAR_BIT", Signed, int); +#else + missing("CHAR_BIT"); +#endif +#ifdef CHAR_MAX + checktype(CHAR_MAX, "CHAR_MAX", Signed, int); +#else + missing("CHAR_MAX"); +#endif +#ifdef CHAR_MIN + checktype(CHAR_MIN, "CHAR_MIN", Signed, int); +#else + missing("CHAR_MIN"); +#endif +#ifdef SCHAR_MAX + checktype(SCHAR_MAX, "SCHAR_MAX", Signed, int); +#else + missing("SCHAR_MAX"); +#endif +#ifdef SCHAR_MIN + checktype(SCHAR_MIN, "SCHAR_MIN", Signed, int); +#else + missing("SCHAR_MIN"); +#endif +#ifdef UCHAR_MAX + checktype(UCHAR_MAX, "UCHAR_MAX", Signed, int); +#else + missing("UCHAR_MAX"); +#endif +#ifdef SHRT_MAX + checktype(SHRT_MAX, "SHRT_MAX", Signed, int); +#else + missing("SHRT_MAX"); +#endif +#ifdef SHRT_MIN + checktype(SHRT_MIN, "SHRT_MIN", Signed, int); +#else + missing("SHRT_MIN"); +#endif +#ifdef INT_MAX + checktype(INT_MAX, "INT_MAX", Signed, int); +#else + missing("INT_MAX"); +#endif +#ifdef INT_MIN + checktype(INT_MIN, "INT_MIN", Signed, int); +#else + missing("INT_MIN"); +#endif +#ifdef LONG_MAX + checktype(LONG_MAX, "LONG_MAX", Signed, long); +#else + missing("LONG_MAX"); +#endif +#ifdef LONG_MIN + checktype(LONG_MIN, "LONG_MIN", Signed, long); +#else + missing("LONG_MIN"); +#endif +#ifdef USHRT_MAX + checktype(USHRT_MAX, "USHRT_MAX", usign, int); +#else + missing("USHRT_MAX"); +#endif +#ifdef UINT_MAX + checktype(UINT_MAX, "UINT_MAX", Unsigned, int); +#else + missing("UINT_MAX"); +#endif +#ifdef ULONG_MAX + checktype(ULONG_MAX, "ULONG_MAX", Unsigned, long); +#else + missing("ULONG_MAX"); +#endif + } /* if (L) */ + + if (F) { +#ifdef FLT_RADIX + checktype(FLT_RADIX, "FLT_RADIX", Signed, int); +#else + fmissing("FLT_RADIX"); +#endif +#ifdef FLT_MANT_DIG + checktype(FLT_MANT_DIG, "FLT_MANT_DIG", Signed, int); +#else + fmissing("FLT_MANT_DIG"); +#endif +#ifdef FLT_DIG + checktype(FLT_DIG, "FLT_DIG", Signed, int); +#else + fmissing("FLT_DIG"); +#endif +#ifdef FLT_ROUNDS + checktype(FLT_ROUNDS, "FLT_ROUNDS", Signed, int); +#else + fmissing("FLT_ROUNDS"); +#endif +#ifdef FLT_EPSILON + fchecktype(FLT_EPSILON, "FLT_EPSILON", float); +#else + fmissing("FLT_EPSILON"); +#endif +#ifdef FLT_MIN_EXP + checktype(FLT_MIN_EXP, "FLT_MIN_EXP", Signed, int); +#else + fmissing("FLT_MIN_EXP"); +#endif +#ifdef FLT_MIN + fchecktype(FLT_MIN, "FLT_MIN", float); +#else + fmissing("FLT_MIN"); +#endif +#ifdef FLT_MIN_10_EXP + checktype(FLT_MIN_10_EXP, "FLT_MIN_10_EXP", Signed, int); +#else + fmissing("FLT_MIN_10_EXP"); +#endif +#ifdef FLT_MAX_EXP + checktype(FLT_MAX_EXP, "FLT_MAX_EXP", Signed, int); +#else + fmissing("FLT_MAX_EXP"); +#endif +#ifdef FLT_MAX + fchecktype(FLT_MAX, "FLT_MAX", float); +#else + fmissing("FLT_MAX"); +#endif +#ifdef FLT_MAX_10_EXP + checktype(FLT_MAX_10_EXP, "FLT_MAX_10_EXP", Signed, int); +#else + fmissing("FLT_MAX_10_EXP"); +#endif +#ifdef DBL_MANT_DIG + checktype(DBL_MANT_DIG, "DBL_MANT_DIG", Signed, int); +#else + fmissing("DBL_MANT_DIG"); +#endif +#ifdef DBL_DIG + checktype(DBL_DIG, "DBL_DIG", Signed, int); +#else + fmissing("DBL_DIG"); +#endif +#ifdef DBL_EPSILON + fchecktype(DBL_EPSILON, "DBL_EPSILON", double); +#else + fmissing("DBL_EPSILON"); +#endif +#ifdef DBL_MIN_EXP + checktype(DBL_MIN_EXP, "DBL_MIN_EXP", Signed, int); +#else + fmissing("DBL_MIN_EXP"); +#endif +#ifdef DBL_MIN + fchecktype(DBL_MIN, "DBL_MIN", double); +#else + fmissing("DBL_MIN"); +#endif +#ifdef DBL_MIN_10_EXP + checktype(DBL_MIN_10_EXP, "DBL_MIN_10_EXP", Signed, int); +#else + fmissing("DBL_MIN_10_EXP"); +#endif +#ifdef DBL_MAX_EXP + checktype(DBL_MAX_EXP, "DBL_MAX_EXP", Signed, int); +#else + fmissing("DBL_MAX_EXP"); +#endif +#ifdef DBL_MAX + fchecktype(DBL_MAX, "DBL_MAX", double); +#else + fmissing("DBL_MAX"); +#endif +#ifdef DBL_MAX_10_EXP + checktype(DBL_MAX_10_EXP, "DBL_MAX_10_EXP", Signed, int); +#else + fmissing("DBL_MAX_10_EXP"); +#endif +#ifdef STDC +#ifdef LDBL_MANT_DIG + checktype(LDBL_MANT_DIG, "LDBL_MANT_DIG", Signed, int); +#else + fmissing("LDBL_MANT_DIG"); +#endif +#ifdef LDBL_DIG + checktype(LDBL_DIG, "LDBL_DIG", Signed, int); +#else + fmissing("LDBL_DIG"); +#endif +#ifdef LDBL_EPSILON + fchecktype(LDBL_EPSILON, "LDBL_EPSILON", long double); +#else + fmissing("LDBL_EPSILON"); +#endif +#ifdef LDBL_MIN_EXP + checktype(LDBL_MIN_EXP, "LDBL_MIN_EXP", Signed, int); +#else + fmissing("LDBL_MIN_EXP"); +#endif +#ifdef LDBL_MIN + fchecktype(LDBL_MIN, "LDBL_MIN", long double); +#else + fmissing("LDBL_MIN"); +#endif +#ifdef LDBL_MIN_10_EXP + checktype(LDBL_MIN_10_EXP, "LDBL_MIN_10_EXP", Signed, int); +#else + fmissing("LDBL_MIN_10_EXP"); +#endif +#ifdef LDBL_MAX_EXP + checktype(LDBL_MAX_EXP, "LDBL_MAX_EXP", Signed, int); +#else + fmissing("LDBL_MAX_EXP"); +#endif +#ifdef LDBL_MAX + fchecktype(LDBL_MAX, "LDBL_MAX", long double); +#else + fmissing("LDBL_MAX"); +#endif +#ifdef LDBL_MAX_10_EXP + checktype(LDBL_MAX_10_EXP, "LDBL_MAX_10_EXP", Signed, int); +#else + fmissing("LDBL_MAX_10_EXP"); +#endif +#endif /* STDC */ + } /* if (F) */ +#endif /* VERIFY */ +} + +#ifdef VERIFY +#ifndef SCHAR_MAX +#define SCHAR_MAX char_max +#endif +#ifndef SCHAR_MIN +#define SCHAR_MIN char_min +#endif +#ifndef UCHAR_MAX +#define UCHAR_MAX char_max +#endif +#endif /* VERIFY */ + +#ifndef CHAR_BIT +#define CHAR_BIT char_bit +#endif +#ifndef CHAR_MAX +#define CHAR_MAX char_max +#endif +#ifndef CHAR_MIN +#define CHAR_MIN char_min +#endif +#ifndef SCHAR_MAX +#define SCHAR_MAX char_max +#endif +#ifndef SCHAR_MIN +#define SCHAR_MIN char_min +#endif +#ifndef UCHAR_MAX +#define UCHAR_MAX char_max +#endif + +int cprop() { + /* Properties of type char */ + Volatile char c, char_max, char_min; + Volatile int bits_per_byte, c_signed; + long char_bit; + + Unexpected(2); + + /* Calculate number of bits per character *************************/ + c=1; bits_per_byte=0; + do { c=c<<1; bits_per_byte++; } while(c!=0); + c= (char)(-1); + if (((int)c)<0) c_signed=1; + else c_signed=0; + Vprintf("%schar = %d bits, %ssigned%s\n", + co, (int)sizeof(c)*bits_per_byte, (c_signed?"":"un"), oc); + char_bit=(long)(sizeof(c)*bits_per_byte); + if (L) i_define(D_CHAR_BIT, "", "CHAR", "_BIT", + char_bit, 0L, (long) CHAR_BIT, ""); + + c=0; char_max=0; + c++; + if (bits_per_byte <= 16) { + if (setjmp(lab)==0) { /* Yields char_max */ + while (c>char_max) { + char_max=c; + c++; + } + } else { + Vprintf("%sCharacter overflow generates a trap!%s\n", + co, oc); + } + c=0; char_min=0; + c--; + if (setjmp(lab)==0) { /* Yields char_min */ + while (c char_max) + char_max = ~0; + c = 0; + char_min = 0; + c--; + if (c < char_min) { + c = (1 << (bits_per_byte - 1)) - 1; + c = -c; + char_min = c; + c--; + if (c < char_min) + char_min = c; + } + } + if (c_signed && char_min == 0) { + Vprintf("%sBEWARE! Chars are pseudo-unsigned:%s\n", co, oc); + Vprintf("%s %s%s%s\n", + "They contain only nonnegative values, ", + "but sign extend when used as integers.", co, oc); + } + Unexpected(3); + + if (L) { + /* Because of the integer promotions, you must use a U after + the MAX_CHARS in the following cases */ + if ((sizeof(char) == sizeof(int)) && !c_signed) { + u_define(D_CHAR_MAX, "", "CHAR", "_MAX", + (long) char_max, + (long) CHAR_MAX, ""); + } else { + i_define(D_CHAR_MAX, "", "CHAR", "_MAX", + (long) char_max, 0L, + (long) CHAR_MAX, ""); + } + i_define(D_CHAR_MIN, "", "CHAR", "_MIN", + (long) char_min, (long) maxint, + (long) CHAR_MIN, ""); + if (c_signed) { + i_define(D_SCHAR_MAX, "", "SCHAR", "_MAX", + (long) char_max, 0L, + (long) SCHAR_MAX, ""); + i_define(D_SCHAR_MIN, "", "SCHAR", "_MIN", + (long) char_min, (long) maxint, + (long) SCHAR_MIN, ""); + } else { + if (sizeof(char) == sizeof(int)) { + u_define(D_UCHAR_MAX, "", "UCHAR", "_MAX", + (long) char_max, + (long) UCHAR_MAX, ""); + } else { + i_define(D_UCHAR_MAX, "", "UCHAR", "_MAX", + (long) char_max, 0L, + (long) UCHAR_MAX, ""); + } + } + + if (c_signed) { +#ifndef NO_UC + Volatile unsigned char c, char_max; + c=0; char_max=0; + c++; + if (setjmp(lab)==0) { /* Yields char_max */ + while (c>char_max) { + char_max=c; + c++; + } + } + Unexpected(4); + if (sizeof(char) == sizeof(int)) { + u_define(D_UCHAR_MAX, "", "UCHAR", "_MAX", + (long) char_max, + (long) UCHAR_MAX, ""); + } else { + i_define(D_UCHAR_MAX, "", "UCHAR", "_MAX", + (long) char_max, 0L, + (long) UCHAR_MAX, ""); + } +#endif + } else { +#ifndef NO_SC +/* Define NO_SC if this gives a syntax error */ Volatile signed char c, char_max, char_min; + c=0; char_max=0; + c++; + if (setjmp(lab)==0) { /* Yields char_max */ + while (c>char_max) { + char_max=c; + c++; + } + } + c=0; char_min=0; + c--; + if (setjmp(lab)==0) { /* Yields char_min */ + while (csizeof(int)?" BEWARE! larger than int!":"", + oc); + Vprintf("%sint* =%d bits%s%s\n", + co, (int)sizeof(int *)*bits_per_byte, + sizeof(int *)>sizeof(int)?" BEWARE! larger than int!":"", + oc); + Vprintf("%sfunc*=%d bits%s%s\n", + co, (int)sizeof(function *)*bits_per_byte, + sizeof(function *)>sizeof(int)?" BEWARE! larger than int!":"", + oc); +if (V) printf ("%s%s %s %s%s\n", co, "Type size_t is", + ((((false()?( sizeof(int)):(-1)) < 0) )? + "signed":"unsigned") , + type_of(sizeof( + sizeof(int)+0 + ) + ), + oc); + showtype("Type size_t is", sizeof(0)); + + /* Alignment constants ********************************************/ + +#define alignment(TYPE) \ + ((long)((char *)&((struct{char c; TYPE d;}*)0)->d - (char *) 0)) + + Vprintf("\n%sALIGNMENTS%s\n", co, oc); + + Vprintf("%schar=%ld short=%ld int=%ld long=%ld%s\n", + co, + alignment(char), alignment(short), + alignment(int), alignment(long), + oc); + + Vprintf("%sfloat=%ld double=%ld%s\n", + co, + alignment(float), alignment(double), + oc); + + if (stdc) { + Vprintf("%slong double=%ld%s\n", + co, + alignment(Long_double), + oc); + } + Vprintf("%schar*=%ld int*=%ld func*=%ld%s\n", + co, + alignment(char *), alignment(int *), alignment(function *), + oc); + + Vprintf("\n"); + + /* Ten little endians *********************************************/ + + endian(bits_per_byte); + + /* Pointers *******************************************************/ + + Vprintf("\n%sPROPERTIES OF POINTERS%s\n", co, oc); + + if ((long) (char *) &variable == (long) (int *) &variable) { + Vprintf("%sChar and int pointer formats seem identical%s\n", + co, oc); + } else { + Vprintf("%sChar and int pointer formats are different%s\n", + co, oc); + } + if ((long) (char *) &variable == (long) (function *) &variable) { + Vprintf("%sChar and function pointer formats seem identical%s\n", + co, oc); + } else { + Vprintf("%sChar and function pointer formats are different%s\n", + co, oc); + } + + if (V) { + if ("abcd"=="abcd") + printf("%sStrings are shared%s\n", co, oc); + else printf("%sStrings are not shared%s\n", co, oc); + } + + p=0; q=0; + showtype("Type ptrdiff_t is", p-q); + + Vprintf("\n%sPROPERTIES OF INTEGRAL TYPES%s\n", co, oc); + + sprop(); + iprop(); + lprop(); + usprop(); + uiprop(); + ulprop(); + + promotions(); + + Unexpected(6); + + return bits_per_byte; +} + +#else /* not PASS0 */ + +#ifdef SEP +extern jmp_buf lab; +extern int V, L, F, bugs, bits_per_byte; +extern char co[], oc[]; +extern char *f_rep(); +#endif /* SEP */ +#endif /* ifdef PASS0 */ + +/* As I said, I apologise for the contortions below. The functions are + expanded by the preprocessor twice or three times (for float and double, + and maybe for long double, and for short, int and long). That way, + I never make a change to one that I forget to make to the other. + You can look on it as C's fault for not supporting multi-line macro's. + This whole file is read 3 times by the preprocessor, with PASSn set for + n=1, 2 or 3, to decide which parts to reprocess. +*/ + +/* #undef on an already undefined thing is (wrongly) flagged as an error + by some compilers, therefore the #ifdef that follows: +*/ +#ifdef Number +#undef Number +#undef THING +#undef Thing +#undef thing +#undef FPROP +#undef Fname +#undef Store +#undef Sum +#undef Diff +#undef Mul +#undef Div +#undef ZERO +#undef HALF +#undef ONE +#undef TWO +#undef THREE +#undef FOUR +#undef Self +#undef F_check +#undef Validate +#undef EPROP +#undef MARK + +/* These are the float.h constants */ +#undef F_RADIX +#undef F_MANT_DIG +#undef F_DIG +#undef F_ROUNDS +#undef F_EPSILON +#undef F_MIN_EXP +#undef F_MIN +#undef F_MIN_10_EXP +#undef F_MAX_EXP +#undef F_MAX +#undef F_MAX_10_EXP +#endif + +#ifdef Integer +#undef Integer +#undef INT +#undef IPROP +#undef Iname +#undef UPROP +#undef Uname +#undef OK_UI +#undef IMARK + +#undef I_MAX +#undef I_MIN +#undef U_MAX +#endif + +#ifdef PASS1 + +/* Define the things we're going to use this pass */ + +#define Number float +#define THING "FLOAT" +#define Thing "Float" +#define thing "float" +#define Fname "FLT" +#define FPROP fprop +#define Store fStore +#define Sum fSum +#define Diff fDiff +#define Mul fMul +#define Div fDiv +#define ZERO 0.0 +#define HALF 0.5 +#define ONE 1.0 +#define TWO 2.0 +#define THREE 3.0 +#define FOUR 4.0 +#define Self fSelf +#define F_check fCheck +#define MARK "F" +#ifdef VERIFY +#define Validate(prec, val, req, same) fValidate(prec, val, req, same) +#endif + +#define EPROP efprop + +#define Integer short +#define INT "short" +#define IPROP sprop +#define Iname "SHRT" +#ifndef NO_UI +#define OK_UI 1 +#endif +#define IMARK "" + +#define UPROP usprop +#define Uname "USHRT" + +#ifdef SHRT_MAX +#define I_MAX SHRT_MAX +#endif +#ifdef SHRT_MIN +#define I_MIN SHRT_MIN +#endif +#ifdef USHRT_MAX +#define U_MAX USHRT_MAX +#endif + +#ifdef FLT_RADIX +#define F_RADIX FLT_RADIX +#endif +#ifdef FLT_MANT_DIG +#define F_MANT_DIG FLT_MANT_DIG +#endif +#ifdef FLT_DIG +#define F_DIG FLT_DIG +#endif +#ifdef FLT_ROUNDS +#define F_ROUNDS FLT_ROUNDS +#endif +#ifdef FLT_EPSILON +#define F_EPSILON FLT_EPSILON +#endif +#ifdef FLT_MIN_EXP +#define F_MIN_EXP FLT_MIN_EXP +#endif +#ifdef FLT_MIN +#define F_MIN FLT_MIN +#endif +#ifdef FLT_MIN_10_EXP +#define F_MIN_10_EXP FLT_MIN_10_EXP +#endif +#ifdef FLT_MAX_EXP +#define F_MAX_EXP FLT_MAX_EXP +#endif +#ifdef FLT_MAX +#define F_MAX FLT_MAX +#endif +#ifdef FLT_MAX_10_EXP +#define F_MAX_10_EXP FLT_MAX_10_EXP +#endif + +#endif /* PASS1 */ + +#ifdef PASS2 + +#define Number double +#define THING "DOUBLE" +#define Thing "Double" +#define thing "double" +#define Fname "DBL" +#define FPROP dprop +#define Store dStore +#define Sum dSum +#define Diff dDiff +#define Mul dMul +#define Div dDiv +#define ZERO 0.0 +#define HALF 0.5 +#define ONE 1.0 +#define TWO 2.0 +#define THREE 3.0 +#define FOUR 4.0 +#define Self dSelf +#define F_check dCheck +#define MARK "" +#ifdef VERIFY +#define Validate(prec, val, req, same) dValidate(prec, val, req, same) +#endif + +#define EPROP edprop + +#define Integer int +#define INT "int" +#define IPROP iprop +#define Iname "INT" +#define OK_UI 1 /* Unsigned int is always possible */ +#define IMARK "" + +#define UPROP uiprop +#define Uname "UINT" + +#ifdef INT_MAX +#define I_MAX INT_MAX +#endif +#ifdef INT_MIN +#define I_MIN INT_MIN +#endif +#ifdef UINT_MAX +#define U_MAX UINT_MAX +#endif + +#ifdef DBL_MANT_DIG +#define F_MANT_DIG DBL_MANT_DIG +#endif +#ifdef DBL_DIG +#define F_DIG DBL_DIG +#endif +#ifdef DBL_EPSILON +#define F_EPSILON DBL_EPSILON +#endif +#ifdef DBL_MIN_EXP +#define F_MIN_EXP DBL_MIN_EXP +#endif +#ifdef DBL_MIN +#define F_MIN DBL_MIN +#endif +#ifdef DBL_MIN_10_EXP +#define F_MIN_10_EXP DBL_MIN_10_EXP +#endif +#ifdef DBL_MAX_EXP +#define F_MAX_EXP DBL_MAX_EXP +#endif +#ifdef DBL_MAX +#define F_MAX DBL_MAX +#endif +#ifdef DBL_MAX_10_EXP +#define F_MAX_10_EXP DBL_MAX_10_EXP +#endif + +#endif /* PASS2 */ + +#ifdef PASS3 + +#ifdef STDC +#define Number long double + +#define ZERO 0.0L +#define HALF 0.5L +#define ONE 1.0L +#define TWO 2.0L +#define THREE 3.0L +#define FOUR 4.0L +#endif + +#define THING "LONG DOUBLE" +#define Thing "Long double" +#define thing "long double" +#define Fname "LDBL" +#define FPROP ldprop +#define Store ldStore +#define Sum ldSum +#define Diff ldDiff +#define Mul ldMul +#define Div ldDiv +#define Self ldSelf +#define F_check ldCheck +#define MARK "L" +#ifdef VERIFY +#define Validate(prec, val, req, same) ldValidate(prec, val, req, same) +#endif + +#define EPROP eldprop + +#define Integer long +#define INT "long" +#define IPROP lprop +#define Iname "LONG" +#ifndef NO_UI +#define OK_UI 1 +#endif +#define IMARK "L" + +#define UPROP ulprop +#define Uname "ULONG" + +#ifdef LONG_MAX +#define I_MAX LONG_MAX +#endif +#ifdef LONG_MIN +#define I_MIN LONG_MIN +#endif +#ifdef ULONG_MAX +#define U_MAX ULONG_MAX +#endif + +#ifdef LDBL_MANT_DIG +#define F_MANT_DIG LDBL_MANT_DIG +#endif +#ifdef LDBL_DIG +#define F_DIG LDBL_DIG +#endif +#ifdef LDBL_EPSILON +#define F_EPSILON LDBL_EPSILON +#endif +#ifdef LDBL_MIN_EXP +#define F_MIN_EXP LDBL_MIN_EXP +#endif +#ifdef LDBL_MIN +#define F_MIN LDBL_MIN +#endif +#ifdef LDBL_MIN_10_EXP +#define F_MIN_10_EXP LDBL_MIN_10_EXP +#endif +#ifdef LDBL_MAX_EXP +#define F_MAX_EXP LDBL_MAX_EXP +#endif +#ifdef LDBL_MAX +#define F_MAX LDBL_MAX +#endif +#ifdef LDBL_MAX_10_EXP +#define F_MAX_10_EXP LDBL_MAX_10_EXP +#endif + +#endif /* PASS3 */ + +#define UNDEFINED (-2) + +#ifndef I_MAX +#define I_MAX ((unsigned long) UNDEFINED) +#endif +#ifndef I_MIN +#define I_MIN ((unsigned long) UNDEFINED) +#endif +#ifndef U_MAX +#define U_MAX ((unsigned long) UNDEFINED) +#endif + +#ifndef F_RADIX +#define F_RADIX UNDEFINED +#endif +#ifndef F_MANT_DIG +#define F_MANT_DIG UNDEFINED +#endif +#ifndef F_DIG +#define F_DIG UNDEFINED +#endif +#ifndef F_ROUNDS +#define F_ROUNDS UNDEFINED +#endif +#ifndef F_EPSILON +#define F_EPSILON ((Number) UNDEFINED) +#endif +#ifndef F_MIN_EXP +#define F_MIN_EXP UNDEFINED +#endif +#ifndef F_MIN +#define F_MIN ((Number) UNDEFINED) +#endif +#ifndef F_MIN_10_EXP +#define F_MIN_10_EXP UNDEFINED +#endif +#ifndef F_MAX_EXP +#define F_MAX_EXP UNDEFINED +#endif +#ifndef F_MAX +#define F_MAX ((Number) UNDEFINED) +#endif +#ifndef F_MAX_10_EXP +#define F_MAX_10_EXP UNDEFINED +#endif + +#ifndef VERIFY +#define Validate(prec, val, req, same) {;} +#endif + +#ifdef Integer + +Procedure IPROP() { + /* the properties of short, int, and long */ + Volatile Integer newi, int_max, maxeri, int_min, minneri; + Volatile int ibits, ipower, two=2; + + /* Calculate max short/int/long ***********************************/ + /* Calculate 2**n-1 until overflow - then use the previous value */ + + newi=1; int_max=0; + + if (setjmp(lab)==0) { /* Yields int_max */ + for(ipower=0; newi>int_max; ipower++) { + int_max=newi; + newi=newi*two+1; + } + Vprintf("%sOverflow of a%s %s does not generate a trap%s\n", + co, INT[0]=='i'?"n":"", INT, oc); + } else { + Vprintf("%sOverflow of a%s %s generates a trap%s\n", + co, INT[0]=='i'?"n":"", INT, oc); + } + Unexpected(7); + + /* Minimum value: assume either two's or one's complement *********/ + int_min= -int_max; + if (setjmp(lab)==0) { /* Yields int_min */ + if (int_min-1 < int_min) int_min--; + } + Unexpected(8); + + /* Now for those daft Cybers */ + + maxeri=0; newi=int_max; + + if (setjmp(lab)==0) { /* Yields maxeri */ + for(ibits=ipower; newi>maxeri; ibits++) { + maxeri=newi; + newi=newi+newi+1; + } + } + Unexpected(9); + + minneri= -maxeri; + if (setjmp(lab)==0) { /* Yields minneri */ + if (minneri-1 < minneri) minneri--; + } + Unexpected(10); + + Vprintf("%sMaximum %s = %ld (= 2**%d-1)%s\n", + co, INT, (long)int_max, ipower, oc); + Vprintf("%sMinimum %s = %ld%s\n", co, INT, (long)int_min, oc); + + if (L) i_define(D_INT_MAX, INT, Iname, "_MAX", + (long) int_max, 0L, + (long) I_MAX, IMARK); + if (L) i_define(D_INT_MIN, INT, Iname, "_MIN", + (long) int_min, (long) (PASS==1?maxint:int_max), + (long) I_MIN, IMARK); + + if(int_max < 0) { /* It has happened */ + eek_a_bug("signed integral comparison faulty?"); + } + + if (maxeri>int_max) { + Vprintf("%sThere is a larger %s, %ld (= 2**%d-1), %s %s%s\n", + co, INT, (long)maxeri, ibits, + "but only for addition, not multiplication", + "(I smell a Cyber!)", + oc); + } + + if (minneriu_max) { + u_max=newi; + newi=newi*two+1; + } + } + Unexpected(11); + Vprintf("%sMaximum unsigned %s = %lu%s\n", + co, INT, (unsigned long) u_max, oc); + + /* Oh woe: new standard C defines value preserving promotions */ + if (L) { + if (PASS == 1 && sizeof(short) < sizeof(int)) { + /* Special only for short */ + i_define(D_UINT_MAX, INT, Uname, "_MAX", + (unsigned long) u_max, 0L, + (unsigned long) U_MAX, IMARK); + } else { + u_define(D_UINT_MAX, INT, Uname, "_MAX", + (unsigned long) u_max, + (unsigned long) U_MAX, IMARK); + } + } +#endif +} + +#endif /* Integer */ + +#ifdef Number + +/* The following routines are intended to defeat any attempt at optimisation + or use of extended precision, and to defeat faulty narrowing casts. + The weird prototypes are because of widening incompatibilities. +*/ +#ifdef STDC +#define ARGS1(atype, a) (atype a) +#define ARGS2(atype, a, btype, b) (atype a, btype b) +#else +#define ARGS1(atype, a) (a) atype a; +#define ARGS2(atype, a, btype, b) (a, b) atype a; btype b; +#endif + +Procedure Store ARGS2(Number, a, Number *, b) { *b=a; } +Number Sum ARGS2(Number, a, Number, b) {Number r; Store(a+b, &r); return (r); } +Number Diff ARGS2(Number, a, Number, b){Number r; Store(a-b, &r); return (r); } +Number Mul ARGS2(Number, a, Number, b) {Number r; Store(a*b, &r); return (r); } +Number Div ARGS2(Number, a, Number, b) {Number r; Store(a/b, &r); return (r); } +Number Self ARGS1(Number, a) {Number r; Store(a, &r); return (r); } + +Procedure F_check ARGS((int precision, Long_double val1)); + +Procedure F_check(precision, val1) int precision; Long_double val1; { + /* You don't think I'm going to go to all the trouble of writing + a program that works out what all sorts of values are, only to + have printf go and print the wrong values out, do you? + No, you're right, so this function tries to see if printf + has written the right value, by reading it back again. + This introduces a new problem of course: suppose printf writes + the correct value, and scanf reads it back wrong... oh well. + But I'm adamant about this: the precision given is enough + to uniquely identify the printed number, therefore I insist + that sscanf read the number back identically. Harsh yes, but + sometimes you've got to be cruel to be kind. + */ + Number val, new, diff; + double rem; + int e; + char *rep; + char *f2; + +#ifdef NO_LONG_DOUBLE_IO + double new1; + /* On the Sun 3, sscanf clobbers 4 words, + which leads to a crash when this function tries to return. */ + f2= "%le"; /* Input */ + /* It is no use checking long doubles if we can't + read and write them. */ + if (sizeof (Number) > sizeof(double)) + return; +#else + Long_double new1; + if (sizeof(double) == sizeof(Long_double)) { + /* Assume they're the same, and use non-stdc format */ + /* This is for stdc compilers using non-stdc libraries */ + f2= "%le"; /* Input */ + } else { + /* It had better support Le then */ + f2= "%Le"; + } +#endif + val= val1; + rep= f_rep(precision, (Long_double) val); + if (setjmp(lab)==0) { + sscanf(rep, f2, &new1); + } else { + eek_a_bug("sscanf caused a trap"); + printf("%s scanning: %s format: %s%s\n\n", co, rep, f2, oc); + Unexpected(12); + return; + } + + if (setjmp(lab)==0) { /* See if new is usable */ + new= new1; + if (new != 0.0) { + diff= val/new - 1.0; + if (diff < 0.1) diff= 1.0; + /* That should be enough to generate a trap */ + } + } else { + eek_a_bug("sscanf returned an unusable number"); + printf("%s scanning: %s with format: %s%s\n\n", + co, rep, f2, oc); + Unexpected(13); + return; + } + + Unexpected(14); + if (new != val) { + eek_a_bug("Possibly bad output from printf above"); + if (!exponent((Long_double)val, &rem, &e)) { + printf("%s but value was an unusable number%s\n\n", + co, oc); + return; + } + printf("%s expected value around %.*fe%d, bit pattern:\n ", + co, precision, rem, e); + bitpattern((char *) &val, (unsigned)sizeof(val)); + printf ("%s\n", oc); + printf("%s sscanf gave %s, bit pattern:\n ", + co, f_rep(precision, (Long_double) new)); + bitpattern((char *) &new, (unsigned)sizeof(new)); + printf ("%s\n", oc); + if (setjmp(lab) == 0) { + diff= val-new; + printf("%s difference= %s%s\n\n", + co, f_rep(precision, (Long_double) diff), oc); + } /* else forget it */ + Unexpected(15); + } +} + +#ifdef VERIFY +Procedure Validate(prec, val, req, same) int prec, same; Long_double val, req; { + /* Check that the compiler has read a #define value correctly */ + Unexpected(16); + if (!same) { + printf("%s*** Verify failed for above #define!\n", co); + if (setjmp(lab) == 0) { /* for the case that req == nan */ + printf(" Compiler has %s for value%s\n", + f_rep(prec, req), oc); + } else { + printf(" Compiler has %s for value%s\n", + "an unusable number", oc); + } + if (setjmp(lab) == 0) { + F_check(prec, (Long_double) req); + } /*else forget it*/ + if (setjmp(lab) == 0) { + if (req > 0.0 && val > 0.0) { + printf("%s difference= %s%s\n", + co, f_rep(prec, val-req), oc); + } + } /*else forget it*/ + Unexpected(17); + printf("\n"); + bugs++; + } else if (val != req) { + if (stdc) eek_a_bug("constant has the wrong precision"); + else eek_a_bug("the cast didn't work"); + printf("\n"); + } +} +#endif /* VERIFY */ + +int FPROP(bits_per_byte) int bits_per_byte; { + /* Properties of floating types, using algorithms by Cody and Waite + from MA Malcolm, as modified by WM Gentleman and SB Marovich. + Further extended by S Pemberton. + + Returns the number of digits in the fraction. + */ + + Volatile int + i, f_radix, iexp, irnd, mrnd, f_rounds, f_mant_dig, + iz, k, inf, machep, f_max_exp, f_min_exp, mx, negeps, + mantbits, digs, f_dig, trap, + hidden, normal, f_min_10_exp, f_max_10_exp; + Volatile Number + a, b, base, basein, basem1, f_epsilon, epsneg, + eps, epsp1, etop, ebot, + f_max, newxmax, f_min, xminner, y, y1, z, z1, z2; + + Unexpected(18); + + Vprintf("%sPROPERTIES OF %s%s\n", co, THING, oc); + + /* Base and size of significand **************************************/ + /* First repeatedly double until adding 1 has no effect. */ + /* For instance, if base is 10, with 3 significant digits */ + /* it will try 1, 2, 4, 8, ... 512, 1024, and stop there, */ + /* since 1024 is only representable as 1020. */ + a=1.0; + if (setjmp(lab)==0) { /* inexact trap? */ + do { a=Sum(a, a); } + while (Diff(Diff(Sum(a, ONE), a), ONE) == ZERO); + } else { + fprintf(stderr, "*** Program got loss-of-precision trap!\n"); + /* And supporting those is just TOO much trouble! */ + farewell(bugs+1); + } + Unexpected(19); + /* Now double until you find a number that can be added to the */ + /* above number. For 1020 this is 8 or 16, depending whether the */ + /* result is rounded or truncated. */ + /* In either case the result is 1030. 1030-1020= the base, 10. */ + b=1.0; + do { b=Sum(b, b); } while ((base=Diff(Sum(a, b), a)) == ZERO); + f_radix=base; + Vprintf("%sBase = %d%s\n", co, f_radix, oc); + + /* Sanity check; if base<2, I can't guarantee the rest will work */ + if (f_radix < 2) { + eek_a_bug("Function return or parameter passing faulty? (This is a guess.)"); + printf("\n"); + return(0); + } + + if (PASS == 1) { /* only for FLT */ + flt_radix= f_radix; + if (F) i_define(D_FLT_RADIX, "", "FLT", "_RADIX", + (long) f_radix, 0L, (long) F_RADIX, ""); + } else if (f_radix != flt_radix) { + printf("\n%s*** WARNING: %s %s (%d) %s%s\n", + co, thing, "arithmetic has a different radix", + f_radix, "from float", oc); + bugs++; + } + + /* Now the number of digits precision */ + f_mant_dig=0; b=1.0; + do { f_mant_dig++; b=Mul(b, base); } + while (Diff(Diff(Sum(b, ONE), b), ONE) == ZERO); + f_dig=floor_log(10, (Long_double)(b/base)) + (base==10?1:0); + Vprintf("%sSignificant base digits = %d %s %d %s%s\n", + co, f_mant_dig, "(= at least", f_dig, "decimal digits)", oc); + if (F) i_define(D_MANT_DIG, thing, Fname, "_MANT_DIG", + (long) f_mant_dig, 0L, (long) F_MANT_DIG, ""); + if (F) i_define(D_DIG, thing, Fname, "_DIG", + (long) f_dig, 0L, (long) F_DIG, ""); + digs= ceil_log(10, (Long_double)b); /* the number of digits to printf */ + + /* Rounding *******************************************************/ + basem1=Diff(base, HALF); + if (Diff(Sum(a, basem1), a) != ZERO) { + if (f_radix == 2) basem1=0.375; + else basem1=1.0; + if (Diff(Sum(a, basem1), a) != ZERO) irnd=2; /* away from 0 */ + else irnd=1; /* to nearest */ + } else irnd=0; /* towards 0 */ + + basem1=Diff(base, HALF); + + if (Diff(Diff(-a, basem1), -a) != ZERO) { + if (f_radix == 2) basem1=0.375; + else basem1=1.0; + if (Diff(Diff(-a, basem1), -a) != ZERO) mrnd=2; /* away from 0*/ + else mrnd=1; /* to nearest */ + } else mrnd=0; /* towards 0 */ + + f_rounds= -1; /* Unknown rounding */ + if (irnd==0 && mrnd==0) f_rounds=0; /* zero = chops */ + if (irnd==1 && mrnd==1) f_rounds=1; /* nearest */ + if (irnd==2 && mrnd==0) f_rounds=2; /* +inf */ + if (irnd==0 && mrnd==2) f_rounds=3; /* -inf */ + + if (f_rounds != -1) { + Vprintf("%sArithmetic rounds towards ", co); + switch (f_rounds) { + case 0: Vprintf("zero (i.e. it chops)"); break; + case 1: Vprintf("nearest"); break; + case 2: Vprintf("+infinity"); break; + case 3: Vprintf("-infinity"); break; + default: Vprintf("???"); break; + } + Vprintf("%s\n", oc); + } else { /* Hmm, try to give some help here */ + Vprintf("%sArithmetic rounds oddly: %s\n", co, oc); + Vprintf("%s Negative numbers %s%s\n", + co, mrnd==0 ? "towards zero" : + mrnd==1 ? "to nearest" : + "away from zero", + oc); + Vprintf("%s Positive numbers %s%s\n", + co, irnd==0 ? "towards zero" : + irnd==1 ? "to nearest" : + "away from zero", + oc); + } + /* An extra goody */ + if (f_radix == 2 && f_rounds == 1) { + if (Diff(Sum(a, ONE), a) != ZERO) { + Vprintf("%s Tie breaking rounds up%s\n", co, oc); + } else if (Diff(Sum(a, THREE), a) == FOUR) { + Vprintf("%s Tie breaking rounds to even%s\n", co, oc); + } else { + Vprintf("%s Tie breaking rounds down%s\n", co, oc); + } + } + if (PASS == 1) { /* only for FLT */ + flt_rounds= f_rounds; + /* Prefer system float.h definition of F_ROUNDS, + since it's more likely to be right than our "1". */ + if (F && (!SYS_FLOAT_H_WRAP || F_ROUNDS == UNDEFINED)) + i_define(D_FLT_ROUNDS, "", "FLT", "_ROUNDS", + (long) f_rounds, 1L, (long) F_ROUNDS, ""); + } else if (f_rounds != flt_rounds) { + printf("\n%s*** WARNING: %s %s (%d) %s%s\n", + co, thing, "arithmetic rounds differently", + f_rounds, "from float", oc); + bugs++; + } + + /* Various flavours of epsilon ************************************/ + negeps=f_mant_dig+f_mant_dig; + basein=1.0/base; + a=1.0; + for(i=1; i<=negeps; i++) a*=basein; + + b=a; + while (Diff(Diff(ONE, a), ONE) == ZERO) { + a*=base; + negeps--; + } + negeps= -negeps; + Vprintf("%sSmallest x such that 1.0-base**x != 1.0 = %d%s\n", + co, negeps, oc); + + etop = ONE; + ebot = ZERO; + eps = Sum(ebot, Div(Diff(etop, ebot), TWO)); + /* find the smallest epsneg (1-epsneg != 1) by binary search. + ebot and etop are the current bounds */ + while (eps != ebot && eps != etop) { + epsp1 = Diff(ONE, eps); + if (epsp1 < ONE) etop = eps; + else ebot = eps; + eps = Sum(ebot, Div(Diff(etop, ebot), TWO)); + } + eps= etop; + /* Sanity check */ + if (Diff(ONE, etop) >= ONE || Diff(ONE, ebot) != ONE) { + eek_a_bug("internal error calculating epsneg"); + } + Vprintf("%sSmallest x such that 1.0-x != 1.0 = %s%s\n", + co, f_rep(digs, (Long_double) eps), oc); + if (V) F_check(digs, (Long_double) eps); + + epsneg=a; + if ((f_radix!=2) && irnd) { + /* a=(a*(1.0+a))/(1.0+1.0); => */ + a=Div(Mul(a, Sum(ONE, a)), Sum(ONE, ONE)); + /* if ((1.0-a)-1.0 != 0.0) epsneg=a; => */ + if (Diff(Diff(ONE, a), ONE) != ZERO) epsneg=a; + } + /* epsneg is used later */ + Unexpected(20); + + machep= -f_mant_dig-f_mant_dig; + a=b; + while (Diff(Sum(ONE, a), ONE) == ZERO) { a*=base; machep++; } + Vprintf("%sSmallest x such that 1.0+base**x != 1.0 = %d%s\n", + co, machep, oc); + + etop = ONE; + ebot = ZERO; + eps = Sum(ebot, Div(Diff(etop, ebot), TWO)); + /* find the smallest eps (1+eps != 1) by binary search. + ebot and etop are the current bounds */ + while (eps != ebot && eps != etop) { + epsp1 = Sum(ONE, eps); + if (epsp1 > ONE) etop = eps; + else ebot = eps; + eps = Sum(ebot, Div(Diff(etop, ebot), TWO)); + } + /* Sanity check */ + if (Sum(ONE, etop) <= ONE || Sum(ONE, ebot) != ONE) { + eek_a_bug("internal error calculating eps"); + } + f_epsilon=etop; + + Vprintf("%sSmallest x such that 1.0+x != 1.0 = %s%s\n", + co, f_rep(digs, (Long_double) f_epsilon), oc); + + f_epsilon= Diff(Sum(ONE, f_epsilon), ONE); /* New C standard defn */ + Vprintf("%s(Above number + 1.0) - 1.0 = %s%s\n", + co, f_rep(digs, (Long_double) (f_epsilon)), oc); + + /* Possible loss of precision warnings here from non-stdc compilers */ + if (F) f_define(D_EPSILON, thing, + Fname, "_EPSILON", digs, + (Long_double) f_epsilon, + (Long_double) F_EPSILON, MARK); + if (V || F) F_check(digs, (Long_double) f_epsilon); + Unexpected(21); + if (F) Validate(digs, (Long_double) f_epsilon, (Long_double) F_EPSILON, + f_epsilon == Self(F_EPSILON)); + Unexpected(22); + + /* Extra chop info *************************************************/ + if (f_rounds == 0) { + if (Diff(Mul(Sum(ONE,f_epsilon),ONE),ONE) != ZERO) { + Vprintf("%sAlthough arithmetic chops, it uses guard digits%s\n", co, oc); + } + } + + /* Size of and minimum normalised exponent ************************/ + y=0; i=0; k=1; z=basein; z1=(1.0+f_epsilon)/base; + + /* Coarse search for the largest power of two */ + if (setjmp(lab)==0) { /* for underflow trap */ /* Yields i, k, y, y1 */ + do { + y=z; y1=z1; + z=Mul(y,y); z1=Mul(z1, y); + a=Mul(z,ONE); + z2=Div(z1,y); + if (z2 != y1) break; + if ((Sum(a,a) == ZERO) || (fabs(z) >= y)) break; + i++; + k+=k; + } while(1); + } else { + Vprintf("%s%s underflow generates a trap%s\n", co, Thing, oc); + } + Unexpected(23); + + if (f_radix != 10) { + iexp=i+1; /* for the sign */ + mx=k+k; + } else { + iexp=2; + iz=f_radix; + while (k >= iz) { iz*=f_radix; iexp++; } + mx=iz+iz-1; + } + + /* Fine tune starting with y and y1 */ + if (setjmp(lab)==0) { /* for underflow trap */ /* Yields k, f_min */ + do { + f_min=y; z1=y1; + y=Div(y,base); y1=Div(y1,base); + a=Mul(y,ONE); + z2=Mul(y1,base); + if (z2 != z1) break; + if ((Sum(a,a) == ZERO) || (fabs(y) >= f_min)) break; + k++; + } while (1); + } + Unexpected(24); + + f_min_exp=(-k)+1; + + if ((mx <= k+k-3) && (f_radix != 10)) { mx+=mx; iexp+=1; } + Vprintf("%sNumber of bits used for exponent = %d%s\n", co, iexp, oc); + Vprintf("%sMinimum normalised exponent = %d%s\n", co, f_min_exp-1, oc); + if (F) + i_define(D_MIN_EXP, thing, Fname, "_MIN_EXP", + (long) f_min_exp, (long) maxint, (long) F_MIN_EXP, ""); + + if (setjmp(lab)==0) { + Vprintf("%sMinimum normalised positive number = %s%s\n", + co, f_rep(digs, (Long_double) f_min), oc); + } else { + eek_a_bug("printf can't print the smallest normalised number"); + printf("\n"); + } + Unexpected(25); + /* Possible loss of precision warnings here from non-stdc compilers */ + if (setjmp(lab) == 0) { + if (F) f_define(D_MIN, thing, + Fname, "_MIN", digs, + (Long_double) f_min, + (Long_double) F_MIN, MARK); + if (V || F) F_check(digs, (Long_double) f_min); + } else { + eek_a_bug("xxx_MIN caused a trap"); + printf("\n"); + } + + if (setjmp(lab) == 0) { + if (F) Validate(digs, (Long_double) f_min, (Long_double) F_MIN, + f_min == Self(F_MIN)); + } else { + printf("%s*** Verify failed for above #define!\n %s %s\n\n", + co, "Compiler has an unusable number for value", oc); + bugs++; + } + Unexpected(26); + + a=1.0; f_min_10_exp=0; + while (a > f_min*10.0) { a/=10.0; f_min_10_exp--; } + if (F) i_define(D_MIN_10_EXP, thing, Fname, "_MIN_10_EXP", + (long) f_min_10_exp, (long) maxint, + (long) F_MIN_10_EXP, ""); + + /* Minimum exponent ************************************************/ + if (setjmp(lab)==0) { /* for underflow trap */ /* Yields xminner */ + do { + xminner=y; + y=Div(y,base); + a=Mul(y,ONE); + if ((Sum(a,a) == ZERO) || (fabs(y) >= xminner)) break; + } while (1); + } + Unexpected(27); + + if (xminner != 0.0 && xminner != f_min) { + normal= 0; + Vprintf("%sThe smallest numbers are not kept normalised%s\n", + co, oc); + if (setjmp(lab)==0) { + Vprintf("%sSmallest unnormalised positive number = %s%s\n", + co, f_rep(digs, (Long_double) xminner), oc); + if (V) F_check(digs, (Long_double) xminner); + } else { + eek_a_bug("printf can't print the smallest unnormalised number."); + printf("\n"); + } + Unexpected(28); + } else { + normal= 1; + Vprintf("%sThe smallest numbers are normalised%s\n", co, oc); + } + + /* Maximum exponent ************************************************/ + f_max_exp=2; f_max=1.0; newxmax=base+1.0; + inf=0; trap=0; + while (f_max